[file-roller: 1/123] make FrArchive more abstract and FrCommand a subclass of it



commit 4b64c5ece7a4e209799b72845b1587d4b9323940
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Mon Jul 16 20:53:20 2012 +0200

    make FrArchive more abstract and FrCommand a subclass of it
    
    this will allow to handle some archive types using a library instead of
    executing external utilities.

 src/Makefile.am             |    2 -
 src/actions.c               |   14 +-
 src/dlg-batch-add.c         |   12 +-
 src/dlg-new.c               |   14 +-
 src/dlg-package-installer.c |   46 +-
 src/dlg-prop.c              |    6 +-
 src/fr-archive.c            | 4142 +++++++++++++------------------------------
 src/fr-archive.h            |  616 +++++--
 src/fr-command-7z.c         |  364 ++--
 src/fr-command-ace.c        |   40 +-
 src/fr-command-ace.h        |    2 -
 src/fr-command-alz.c        |   50 +-
 src/fr-command-ar.c         |   36 +-
 src/fr-command-arj.c        |   58 +-
 src/fr-command-cfile.c      |  113 +-
 src/fr-command-cfile.h      |    2 +-
 src/fr-command-cpio.c       |   40 +-
 src/fr-command-dpkg.c       |   35 +-
 src/fr-command-iso.c        |   39 +-
 src/fr-command-jar.c        |   23 +-
 src/fr-command-lha.c        |   32 +-
 src/fr-command-lrzip.c      |   32 +-
 src/fr-command-rar.c        |   95 +-
 src/fr-command-rpm.c        |   32 +-
 src/fr-command-tar.c        |  207 ++-
 src/fr-command-unarchiver.c |   54 +-
 src/fr-command-unstuff.c    |   38 +-
 src/fr-command-zip.c        |   69 +-
 src/fr-command-zoo.c        |   32 +-
 src/fr-command.c            | 3716 +++++++++++++++++++++++++++++++++------
 src/fr-command.h            |  300 +---
 src/fr-error.c              |   75 +-
 src/fr-error.h              |   36 +-
 src/fr-init.c               |  178 +-
 src/fr-init.h               |   12 +-
 src/fr-proc-error.c         |   55 -
 src/fr-proc-error.h         |   31 -
 src/fr-process.c            |  680 ++++----
 src/fr-process.h            |  112 +-
 src/fr-window.c             | 1721 +++++++++++-------
 src/fr-window.h             |  385 ++--
 src/glib-utils.c            |   23 +
 src/glib-utils.h            |    5 +
 src/main.c                  |    8 +-
 src/rar-utils.c             |    2 +-
 src/typedefs.h              |   54 +-
 46 files changed, 7627 insertions(+), 6011 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 7c6804f..3dbd816 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -136,8 +136,6 @@ COMMON_SOURCES = 			\
 	fr-list-model.h			\
 	fr-stock.c			\
 	fr-stock.h			\
-	fr-proc-error.c			\
-	fr-proc-error.h			\
 	fr-process.c			\
 	fr-process.h			\
 	fr-window.c			\
diff --git a/src/actions.c b/src/actions.c
index ab21347..2142439 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -267,13 +267,15 @@ new_file_response_cb (GtkWidget  *w,
 		      int         response,
 		      DlgNewData *data)
 {
-	char *path;
+	char *uri;
 
 	if ((response == GTK_RESPONSE_CANCEL) || (response == GTK_RESPONSE_DELETE_EVENT)) {
-		fr_archive_action_completed (data->window->archive,
+		/* FIXME: libarchive
+		 fr_archive_action_completed (data->window->archive,
 					     FR_ACTION_CREATING_NEW_ARCHIVE,
 					     FR_PROC_ERROR_STOPPED,
 					     NULL);
+					     */
 		gtk_widget_destroy (data->dialog);
 		return;
 	}
@@ -283,10 +285,10 @@ new_file_response_cb (GtkWidget  *w,
 		return;
 	}
 
-	path = get_archive_filename_from_selector (data);
-	if (path != NULL) {
-		new_archive (data, path);
-		g_free (path);
+	uri = get_archive_filename_from_selector (data);
+	if (uri != NULL) {
+		new_archive (data, uri);
+		g_free (uri);
 	}
 }
 
diff --git a/src/dlg-batch-add.c b/src/dlg-batch-add.c
index 4e73295..1b787c0 100644
--- a/src/dlg-batch-add.c
+++ b/src/dlg-batch-add.c
@@ -93,20 +93,20 @@ set_archive_options (DialogData *data)
 	int idx;
 
 	idx = gtk_combo_box_get_active (GTK_COMBO_BOX (data->archive_type_combo_box));
-	if (mime_type_desc[data->supported_types[idx]].capabilities & FR_COMMAND_CAN_ENCRYPT) {
+	if (mime_type_desc[data->supported_types[idx]].capabilities & FR_ARCHIVE_CAN_ENCRYPT) {
 		const char *pwd;
 
 		pwd = gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("a_password_entry")));
 		if (pwd != NULL) {
 			if (strcmp (pwd, "") != 0) {
 				fr_window_set_password (data->window, pwd);
-				if (mime_type_desc[data->supported_types[idx]].capabilities & FR_COMMAND_CAN_ENCRYPT_HEADER)
+				if (mime_type_desc[data->supported_types[idx]].capabilities & FR_ARCHIVE_CAN_ENCRYPT_HEADER)
 					fr_window_set_encrypt_header (data->window, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("a_encrypt_header_checkbutton"))));
 			}
 		}
 	}
 
-	if ((mime_type_desc[data->supported_types[idx]].capabilities & FR_COMMAND_CAN_CREATE_VOLUMES)
+	if ((mime_type_desc[data->supported_types[idx]].capabilities & FR_ARCHIVE_CAN_CREATE_VOLUMES)
 	    && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("a_volume_checkbutton"))))
 	{
 		double value;
@@ -364,15 +364,15 @@ update_sensitivity_for_mime_type (DialogData *data,
 		if (strcmp (mime_type_desc[i].mime_type, mime_type) == 0) {
 			gboolean sensitive;
 
-			sensitive = mime_type_desc[i].capabilities & FR_COMMAND_CAN_ENCRYPT;
+			sensitive = mime_type_desc[i].capabilities & FR_ARCHIVE_CAN_ENCRYPT;
 			gtk_widget_set_sensitive (GET_WIDGET ("a_password_entry"), sensitive);
 			gtk_widget_set_sensitive (GET_WIDGET ("a_password_label"), sensitive);
 
-			sensitive = mime_type_desc[i].capabilities & FR_COMMAND_CAN_ENCRYPT_HEADER;
+			sensitive = mime_type_desc[i].capabilities & FR_ARCHIVE_CAN_ENCRYPT_HEADER;
 			gtk_widget_set_sensitive (GET_WIDGET ("a_encrypt_header_checkbutton"), sensitive);
 			gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (GET_WIDGET ("a_encrypt_header_checkbutton")), ! sensitive);
 
-			sensitive = mime_type_desc[i].capabilities & FR_COMMAND_CAN_CREATE_VOLUMES;
+			sensitive = mime_type_desc[i].capabilities & FR_ARCHIVE_CAN_CREATE_VOLUMES;
 			gtk_widget_set_sensitive (GET_WIDGET ("a_volume_box"), sensitive);
 
 			break;
diff --git a/src/dlg-new.c b/src/dlg-new.c
index d64fae6..5469a30 100644
--- a/src/dlg-new.c
+++ b/src/dlg-new.c
@@ -81,14 +81,14 @@ update_sensitivity_for_ext (DlgNewData *data,
 
 	for (i = 0; mime_type_desc[i].mime_type != NULL; i++) {
 		if (strcmp (mime_type_desc[i].mime_type, mime_type) == 0) {
-			data->can_encrypt = mime_type_desc[i].capabilities & FR_COMMAND_CAN_ENCRYPT;
+			data->can_encrypt = mime_type_desc[i].capabilities & FR_ARCHIVE_CAN_ENCRYPT;
 			gtk_widget_set_sensitive (data->n_password_entry, data->can_encrypt);
 			gtk_widget_set_sensitive (data->n_password_label, data->can_encrypt);
 
-			data->can_encrypt_header = mime_type_desc[i].capabilities & FR_COMMAND_CAN_ENCRYPT_HEADER;
+			data->can_encrypt_header = mime_type_desc[i].capabilities & FR_ARCHIVE_CAN_ENCRYPT_HEADER;
 			gtk_widget_set_sensitive (data->n_encrypt_header_checkbutton, data->can_encrypt_header);
 
-			data->can_create_volumes = mime_type_desc[i].capabilities & FR_COMMAND_CAN_CREATE_VOLUMES;
+			data->can_create_volumes = mime_type_desc[i].capabilities & FR_ARCHIVE_CAN_CREATE_VOLUMES;
 			gtk_widget_set_sensitive (data->n_volume_box, data->can_create_volumes);
 
 			break;
@@ -454,7 +454,7 @@ dlg_new_data_get_password (DlgNewData *data)
 	if (idx < 0)
 		return NULL;
 
-	if (mime_type_desc[idx].capabilities & FR_COMMAND_CAN_ENCRYPT)
+	if (mime_type_desc[idx].capabilities & FR_ARCHIVE_CAN_ENCRYPT)
 		password = (char*) gtk_entry_get_text (GTK_ENTRY (data->n_password_entry));
 
 	return password;
@@ -471,11 +471,11 @@ dlg_new_data_get_encrypt_header (DlgNewData *data)
 	if (idx < 0)
 		return FALSE;
 
-	if (mime_type_desc[idx].capabilities & FR_COMMAND_CAN_ENCRYPT) {
+	if (mime_type_desc[idx].capabilities & FR_ARCHIVE_CAN_ENCRYPT) {
 		const char *password = gtk_entry_get_text (GTK_ENTRY (data->n_password_entry));
 		if (password != NULL) {
 			if (strcmp (password, "") != 0) {
-				if (mime_type_desc[idx].capabilities & FR_COMMAND_CAN_ENCRYPT_HEADER)
+				if (mime_type_desc[idx].capabilities & FR_ARCHIVE_CAN_ENCRYPT_HEADER)
 					encrypt_header = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->n_encrypt_header_checkbutton));
 			}
 		}
@@ -495,7 +495,7 @@ dlg_new_data_get_volume_size (DlgNewData *data)
 	if (idx < 0)
 		return 0;
 
-	if ((mime_type_desc[idx].capabilities & FR_COMMAND_CAN_CREATE_VOLUMES)
+	if ((mime_type_desc[idx].capabilities & FR_ARCHIVE_CAN_CREATE_VOLUMES)
 	    && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (data->n_volume_checkbutton)))
 	{
 		double value;
diff --git a/src/dlg-package-installer.c b/src/dlg-package-installer.c
index ecc4f55..b109544 100644
--- a/src/dlg-package-installer.c
+++ b/src/dlg-package-installer.c
@@ -47,9 +47,9 @@ installer_data_free (InstallerData *idata)
 
 
 static void
-package_installer_terminated (InstallerData   *idata,
-			      FrProcErrorType  error_type,
-			      const char      *error_message)
+package_installer_terminated (InstallerData *idata,
+			      FrErrorType    error_type,
+			      const char    *error_message)
 {
 	GdkWindow *window;
 
@@ -57,14 +57,16 @@ package_installer_terminated (InstallerData   *idata,
 	if (window != NULL)
 		gdk_window_set_cursor (window, NULL);
 
-	if (error_type != FR_PROC_ERROR_NONE) {
+	if (error_type != FR_ERROR_NONE) {
+		/* FIXME: libarchive
 		fr_archive_action_completed (idata->archive,
 					     idata->action,
 					     error_type,
 					     error_message);
+		*/
 	}
 	else {
-		update_registered_commands_capabilities ();
+		update_registered_archives_capabilities ();
 		if (fr_window_is_batch_mode (idata->window))
 			fr_window_resume_batch (idata->window);
 		else
@@ -87,7 +89,7 @@ packagekit_install_package_names_ready_cb (GObject      *source_object,
 	GDBusProxy      *proxy;
 	GVariant        *values;
 	GError          *error = NULL;
-	FrProcErrorType  error_type = FR_PROC_ERROR_NONE;
+	FrErrorType  error_type = FR_ERROR_NONE;
 	char            *error_message = NULL;
 
 	proxy = G_DBUS_PROXY (source_object);
@@ -98,11 +100,11 @@ packagekit_install_package_names_ready_cb (GObject      *source_object,
 			&& (error->message != NULL)
 			&& (strstr (error->message, "org.freedesktop.Packagekit.Modify.Cancelled") != NULL)))
 		{
-			error_type = FR_PROC_ERROR_STOPPED;
+			error_type = FR_ERROR_STOPPED;
 			error_message = NULL;
 		}
 		else {
-			error_type = FR_PROC_ERROR_GENERIC;
+			error_type = FR_ERROR_GENERIC;
 			error_message = g_strdup_printf ("%s\n%s",
 							 _("There was an internal error trying to search for applications:"),
 							 error->message);
@@ -219,7 +221,7 @@ install_packages (InstallerData *idata)
 		message = g_strdup_printf ("%s\n%s",
 					   _("There was an internal error trying to search for applications:"),
 					   error->message);
-		package_installer_terminated (idata, FR_PROC_ERROR_GENERIC, message);
+		package_installer_terminated (idata, FR_ERROR_GENERIC, message);
 
 		g_clear_error (&error);
 	}
@@ -254,28 +256,28 @@ dlg_package_installer (FrWindow  *window,
 		       FrAction   action)
 {
 	InstallerData   *idata;
-	GType            command_type;
-	FrCommand       *command;
+	GType            archive_type;
+	FrArchive       *preferred_archive;
 
 	idata = g_new0 (InstallerData, 1);
 	idata->window = g_object_ref (window);
 	idata->archive = g_object_ref (archive);
 	idata->action = action;
 
-	command_type = get_preferred_command_for_mime_type (idata->archive->content_type, FR_COMMAND_CAN_READ_WRITE);
-	if (command_type == 0)
-		command_type = get_preferred_command_for_mime_type (idata->archive->content_type, FR_COMMAND_CAN_READ);
-	if (command_type == 0) {
-		package_installer_terminated (idata, FR_PROC_ERROR_GENERIC, _("Archive type not supported."));
+	archive_type = get_preferred_archive_for_mime_type (idata->archive->mime_type, FR_ARCHIVE_CAN_READ_WRITE);
+	if (archive_type == 0)
+		archive_type = get_preferred_archive_for_mime_type (idata->archive->mime_type, FR_ARCHIVE_CAN_READ);
+	if (archive_type == 0) {
+		package_installer_terminated (idata, FR_ERROR_GENERIC, _("Archive type not supported."));
 		return;
 	}
 
-	command = g_object_new (command_type, 0);
-	idata->packages = fr_command_get_packages (command, idata->archive->content_type);
-	g_object_unref (command);
+	preferred_archive = g_object_new (archive_type, 0);
+	idata->packages = fr_archive_get_packages (preferred_archive, idata->archive->mime_type);
+	g_object_unref (preferred_archive);
 
 	if (idata->packages == NULL) {
-		package_installer_terminated (idata, FR_PROC_ERROR_GENERIC, _("Archive type not supported."));
+		package_installer_terminated (idata, FR_ERROR_GENERIC, _("Archive type not supported."));
 		return;
 	}
 
@@ -286,7 +288,7 @@ dlg_package_installer (FrWindow  *window,
 		GtkWidget *dialog;
 
 		secondary_text = g_strdup_printf (_("There is no command installed for %s files.\nDo you want to search for a command to open this file?"),
-						  g_content_type_get_description (idata->archive->content_type));
+						  g_content_type_get_description (idata->archive->mime_type));
 		dialog = _gtk_message_dialog_new (GTK_WINDOW (idata->window),
 						  GTK_DIALOG_MODAL,
 						  GTK_STOCK_DIALOG_ERROR,
@@ -303,7 +305,7 @@ dlg_package_installer (FrWindow  *window,
 
 #else /* ! ENABLE_PACKAGEKIT */
 
-	package_installer_terminated (idata, FR_PROC_ERROR_GENERIC, _("Archive type not supported."));
+	package_installer_terminated (idata, FR_ERROR_GENERIC, _("Archive type not supported."));
 
 #endif /* ENABLE_PACKAGEKIT */
 }
diff --git a/src/dlg-prop.c b/src/dlg-prop.c
index addc2d2..64e33dc 100644
--- a/src/dlg-prop.c
+++ b/src/dlg-prop.c
@@ -112,8 +112,8 @@ dlg_prop (FrWindow *window)
 	if (fr_window_archive_is_present (window)) {
 		int i;
 
-		for (i = 0; i < window->archive->command->files->len; i++) {
-			FileData *fd = g_ptr_array_index (window->archive->command->files, i);
+		for (i = 0; i < window->archive->files->len; i++) {
+			FileData *fd = g_ptr_array_index (window->archive->files, i);
 			uncompressed_size += fd->size;
 		}
 	}
@@ -138,7 +138,7 @@ dlg_prop (FrWindow *window)
 	/**/
 
 	label = _gtk_builder_get_widget (data->builder, "p_files_label");
-	s = g_strdup_printf ("%d", window->archive->command->n_regular_files);
+	s = g_strdup_printf ("%d", window->archive->n_regular_files);
 	gtk_label_set_text (GTK_LABEL (label), s);
 	g_free (s);
 
diff --git a/src/fr-archive.c b/src/fr-archive.c
index 68bc771..9d3541a 100644
--- a/src/fr-archive.c
+++ b/src/fr-archive.c
@@ -25,7 +25,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/param.h>
-
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gio/gio.h>
@@ -35,9 +34,9 @@
 #include "file-data.h"
 #include "fr-archive.h"
 #include "fr-command.h"
+#include "fr-enum-types.h"
 #include "fr-error.h"
 #include "fr-marshal.h"
-#include "fr-proc-error.h"
 #include "fr-process.h"
 #include "fr-init.h"
 
@@ -45,121 +44,42 @@
 #include <magic.h>
 #endif
 
-#ifndef NCARGS
-#define NCARGS _POSIX_ARG_MAX
-#endif
 
+#define FILES_ARRAY_INITIAL_SIZE 256
 
-/* -- DroppedItemsData -- */
 
+char *action_names[] = { "NONE",
+			 "CREATING_NEW_ARCHIVE",
+			 "LOADING_ARCHIVE",
+			 "LISTING_CONTENT",
+			 "DELETING_FILES",
+			 "TESTING_ARCHIVE",
+			 "GETTING_FILE_LIST",
+			 "COPYING_FILES_FROM_REMOTE",
+			 "ADDING_FILES",
+			 "EXTRACTING_FILES",
+			 "COPYING_FILES_TO_REMOTE",
+			 "CREATING_ARCHIVE",
+			 "SAVING_REMOTE_ARCHIVE" };
 
-typedef struct {
-	FrArchive     *archive;
-	GList         *item_list;
-	char          *base_dir;
-	char          *dest_dir;
-	gboolean       update;
-	char          *password;
-	gboolean       encrypt_header;
-	FrCompression  compression;
-	guint          volume_size;
-} DroppedItemsData;
-
-
-static DroppedItemsData *
-dropped_items_data_new (FrArchive     *archive,
-			GList         *item_list,
-			const char    *base_dir,
-			const char    *dest_dir,
-			gboolean       update,
-			const char    *password,
-			gboolean       encrypt_header,
-			FrCompression  compression,
-			guint          volume_size)
-{
-	DroppedItemsData *data;
-
-	data = g_new0 (DroppedItemsData, 1);
-	data->archive = archive;
-	data->item_list = _g_string_list_dup (item_list);
-	if (base_dir != NULL)
-		data->base_dir = g_strdup (base_dir);
-	if (dest_dir != NULL)
-		data->dest_dir = g_strdup (dest_dir);
-	data->update = update;
-	if (password != NULL)
-		data->password = g_strdup (password);
-	data->encrypt_header = encrypt_header;
-	data->compression = compression;
-	data->volume_size = volume_size;
-
-	return data;
-}
 
+struct _FrArchivePrivate {
+	/* propeties */
 
-static void
-dropped_items_data_free (DroppedItemsData *data)
-{
-	if (data == NULL)
-		return;
-	_g_string_list_free (data->item_list);
-	g_free (data->base_dir);
-	g_free (data->dest_dir);
-	g_free (data->password);
-	g_free (data);
-}
+	GFile         *file;
+	FrArchiveCaps  capabilities;
 
+	/* internal */
 
-struct _FrArchivePrivData {
-	FakeLoadFunc         fake_load_func;                /* If returns TRUE, archives are not read when
-							     * fr_archive_load is invoked, used
-							     * in batch mode. */
-	gpointer             fake_load_data;
-	GCancellable        *cancellable;
-	char                *temp_dir;
-	gboolean             continue_adding_dropped_items;
-	DroppedItemsData    *dropped_items_data;
-
-	char                *temp_extraction_dir;
-	char                *extraction_destination;
-	gboolean             remote_extraction;
-	gboolean             extract_here;
+	GCancellable  *cancellable;
+	gboolean       creating_archive;
+	char          *extraction_destination;
+	gboolean       have_write_permissions;     /* true if we have the
+						    * permissions to write the
+						    * file. */
 };
 
 
-typedef struct {
-	FrArchive      *archive;
-	char           *uri;
-	FrAction        action;
-	GList          *file_list;
-	char           *base_uri;
-	char           *dest_dir;
-	gboolean        update;
-	char           *tmp_dir;
-	guint           source_id;
-	char           *password;
-	gboolean        encrypt_header;
-	FrCompression   compression;
-	guint           volume_size;
-} XferData;
-
-
-static void
-xfer_data_free (XferData *data)
-{
-	if (data == NULL)
-		return;
-
-	g_free (data->uri);
-	g_free (data->password);
-	_g_string_list_free (data->file_list);
-	g_free (data->base_uri);
-	g_free (data->dest_dir);
-	g_free (data->tmp_dir);
-	g_free (data);
-}
-
-
 #define MAX_CHUNK_LEN (NCARGS * 2 / 3) /* Max command line length */
 #define UNKNOWN_TYPE "application/octet-stream"
 #define SAME_FS (FALSE)
@@ -167,11 +87,11 @@ xfer_data_free (XferData *data)
 #define NO_DOT_FILES (FALSE)
 #define IGNORE_CASE (FALSE)
 #define LIST_LENGTH_TO_USE_FILE 10 /* FIXME: find a good value */
+#define FILE_ARRAY_INITIAL_SIZE 256
 
 
 enum {
 	START,
-	DONE,
 	PROGRESS,
 	MESSAGE,
 	STOPPABLE,
@@ -186,84 +106,117 @@ static guint fr_archive_signals[LAST_SIGNAL] = { 0 };
 G_DEFINE_TYPE (FrArchive, fr_archive, G_TYPE_OBJECT)
 
 
-static GFile *
-get_local_copy_for_file (GFile *remote_file)
-{
-	char  *temp_dir;
-	GFile *local_copy = NULL;
-
-	temp_dir = _g_path_get_temp_work_dir (NULL);
-	if (temp_dir != NULL) {
-		char  *archive_name;
-		char  *local_path;
+/* Properties */
+enum {
+        PROP_0,
+        PROP_FILE,
+        PROP_MIME_TYPE,
+        PROP_PASSWORD,
+        PROP_ENCRYPT_HEADER,
+        PROP_COMPRESSION,
+        PROP_VOLUME_SIZE
+};
 
-		archive_name = g_file_get_basename (remote_file);
-		local_path = g_build_filename (temp_dir, archive_name, NULL);
-		local_copy = g_file_new_for_path (local_path);
 
-		g_free (local_path);
-		g_free (archive_name);
+static void
+_fr_archive_set_file (FrArchive *self,
+		      GFile     *file)
+{
+	if (self->priv->file != NULL) {
+		g_object_unref (self->priv->file);
+		self->priv->file = NULL;
 	}
-	g_free (temp_dir);
+	if (file != NULL)
+		self->priv->file = g_object_ref (file);
 
-	return local_copy;
+	self->mime_type = NULL;
+
+	g_object_notify (G_OBJECT (self), "file");
 }
 
 
 static void
-fr_archive_set_uri (FrArchive  *archive,
-		    const char *uri)
+_fr_archive_set_uri (FrArchive  *self,
+		     const char *uri)
 {
-	if ((archive->local_copy != NULL) && archive->is_remote) {
-		GFile  *temp_folder;
-		GError *err = NULL;
-
-		g_file_delete (archive->local_copy, NULL, &err);
-		if (err != NULL) {
-			g_warning ("Failed to delete the local copy: %s", err->message);
-			g_clear_error (&err);
-		}
+	GFile *file;
 
-		temp_folder = g_file_get_parent (archive->local_copy);
-		g_file_delete (temp_folder, NULL, &err);
-		if (err != NULL) {
-			g_warning ("Failed to delete temp folder: %s", err->message);
-			g_clear_error (&err);
-		}
+	file = (uri != NULL) ? g_file_new_for_uri (uri) : NULL;
+	_fr_archive_set_file (self, file);
 
-		g_object_unref (temp_folder);
-	}
+	_g_object_unref (file);
+}
 
-	if (archive->file != NULL) {
-		g_object_unref (archive->file);
-		archive->file = NULL;
-	}
-	if (archive->local_copy != NULL) {
-		g_object_unref (archive->local_copy);
-		archive->local_copy = NULL;
-	}
-	archive->content_type = NULL;
 
-	if (uri == NULL)
-		return;
+static void
+fr_archive_set_property (GObject      *object,
+			 guint         property_id,
+			 const GValue *value,
+			 GParamSpec   *pspec)
+{
+        FrArchive *self;
 
-	archive->file = g_file_new_for_uri (uri);
-	archive->is_remote = ! g_file_has_uri_scheme (archive->file, "file");
-	if (archive->is_remote)
-		archive->local_copy = get_local_copy_for_file (archive->file);
-	else
-		archive->local_copy = g_file_dup (archive->file);
+        self = FR_ARCHIVE (object);
+
+        switch (property_id) {
+        case PROP_FILE:
+        	_fr_archive_set_file (self, g_value_get_object (value));
+        	break;
+	case PROP_MIME_TYPE:
+		fr_archive_set_mime_type (self, g_value_get_string (value));
+		break;
+	case PROP_PASSWORD:
+		g_free (self->password);
+		self->password = g_strdup (g_value_get_string (value));
+		break;
+	case PROP_ENCRYPT_HEADER:
+		self->encrypt_header = g_value_get_boolean (value);
+		break;
+	case PROP_COMPRESSION:
+		self->compression = g_value_get_enum (value);
+		break;
+	case PROP_VOLUME_SIZE:
+		self->volume_size = g_value_get_uint (value);
+		break;
+        default:
+                break;
+        }
 }
 
 
 static void
-fr_archive_remove_temp_work_dir (FrArchive *archive)
+fr_archive_get_property (GObject    *object,
+			 guint       property_id,
+			 GValue     *value,
+			 GParamSpec *pspec)
 {
-	if (archive->priv->temp_dir == NULL)
-		return;
-	_g_path_remove_directory (archive->priv->temp_dir);
-	g_free (archive->priv->temp_dir);
-	archive->priv->temp_dir = NULL;
+        FrArchive *self;
+
+        self = FR_ARCHIVE (object);
+
+        switch (property_id) {
+        case PROP_FILE:
+                g_value_set_object (value, self->priv->file);
+                break;
+	case PROP_MIME_TYPE:
+		g_value_set_static_string (value, self->mime_type);
+		break;
+	case PROP_PASSWORD:
+		g_value_set_string (value, self->password);
+		break;
+	case PROP_ENCRYPT_HEADER:
+		g_value_set_boolean (value, self->encrypt_header);
+		break;
+	case PROP_COMPRESSION:
+		g_value_set_enum (value, self->compression);
+		break;
+	case PROP_VOLUME_SIZE:
+		g_value_set_uint (value, self->volume_size);
+		break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
 }
 
 
@@ -277,18 +230,8 @@ fr_archive_finalize (GObject *object)
 
 	archive = FR_ARCHIVE (object);
 
-	fr_archive_set_uri (archive, NULL);
-	fr_archive_remove_temp_work_dir (archive);
-	if (archive->command != NULL)
-		g_object_unref (archive->command);
-	g_object_unref (archive->process);
-	if (archive->priv->dropped_items_data != NULL) {
-		dropped_items_data_free (archive->priv->dropped_items_data);
-		archive->priv->dropped_items_data = NULL;
-	}
-	g_free (archive->priv->temp_extraction_dir);
-	g_free (archive->priv->extraction_destination);
-	g_free (archive->priv);
+	_fr_archive_set_uri (archive, NULL);
+	g_object_unref (archive->priv->cancellable);
 
 	/* Chain up */
 
@@ -297,46 +240,137 @@ fr_archive_finalize (GObject *object)
 }
 
 
+const char **void_mime_types = { NULL };
+
+
+static const char **
+fr_archive_base_get_mime_types (FrArchive *self)
+{
+	return void_mime_types;
+}
+
+
+static FrArchiveCap
+fr_archive_base_get_capabilities (FrArchive  *self,
+			          const char *mime_type,
+			          gboolean    check_command)
+{
+	return FR_ARCHIVE_CAN_DO_NOTHING;
+}
+
+
+static void
+fr_archive_base_set_mime_type (FrArchive  *self,
+			       const char *mime_type)
+{
+	self->mime_type = _g_str_get_static (mime_type);
+	fr_archive_update_capabilities (self);
+}
+
+
+static const char *
+fr_archive_base_get_packages (FrArchive  *self,
+			      const char *mime_type)
+{
+	return NULL;
+}
+
+
 static void
-fr_archive_class_init (FrArchiveClass *class)
+fr_archive_class_init (FrArchiveClass *klass)
 {
 	GObjectClass *gobject_class;
 
-	fr_archive_parent_class = g_type_class_peek_parent (class);
+	fr_archive_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (FrArchivePrivate));
 
-	gobject_class = G_OBJECT_CLASS (class);
+	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_archive_finalize;
-
-	class->start = NULL;
-	class->done = NULL;
-	class->progress = NULL;
-	class->message = NULL;
-	class->working_archive = NULL;
+	gobject_class->set_property = fr_archive_set_property;
+	gobject_class->get_property = fr_archive_get_property;
+
+	klass->start = NULL;
+	klass->progress = NULL;
+	klass->message = NULL;
+	klass->stoppable = NULL;
+	klass->working_archive = NULL;
+
+	klass->get_mime_types = fr_archive_base_get_mime_types;
+	klass->get_capabilities = fr_archive_base_get_capabilities;
+	klass->set_mime_type = fr_archive_base_set_mime_type;
+	klass->get_packages = fr_archive_base_get_packages;
+	klass->load = NULL;
+	klass->add_files = NULL;
+	klass->extract_files = NULL;
+	klass->remove_files = NULL;
+	klass->test_integrity = NULL;
+	klass->rename = NULL;
+	klass->paste_clipboard = NULL;
+	klass->add_dropped_items = NULL;
+	klass->update_open_files = NULL;
+
+	/* properties */
+
+	g_object_class_install_property (gobject_class,
+					 PROP_FILE,
+					 g_param_spec_object ("file",
+							      "File",
+							      "The archive file",
+							      G_TYPE_FILE,
+							      G_PARAM_READWRITE));
+	g_object_class_install_property (gobject_class,
+					 PROP_MIME_TYPE,
+					 g_param_spec_string ("mime-type",
+							      "Content type",
+							      "A mime-type that describes the content type",
+							      NULL,
+							      G_PARAM_READWRITE));
+	g_object_class_install_property (gobject_class,
+					 PROP_PASSWORD,
+					 g_param_spec_string ("password",
+							      "Password",
+							      "The archive password",
+							      NULL,
+							      G_PARAM_READWRITE));
+	g_object_class_install_property (gobject_class,
+					 PROP_ENCRYPT_HEADER,
+					 g_param_spec_boolean ("encrypt-header",
+							       "Encrypt header",
+							       "Whether to encrypt the archive header when creating the archive",
+							       FALSE,
+							       G_PARAM_READWRITE));
+	g_object_class_install_property (gobject_class,
+					 PROP_COMPRESSION,
+					 g_param_spec_enum ("compression",
+							    "Compression type",
+							    "The compression type to use when creating the archive",
+							    FR_TYPE_COMPRESSION,
+							    FR_COMPRESSION_NORMAL,
+							    G_PARAM_READWRITE));
+	g_object_class_install_property (gobject_class,
+					 PROP_VOLUME_SIZE,
+					 g_param_spec_uint ("volume-size",
+							    "Volume size",
+							    "The size of each volume or 0 to not use volumes",
+							    0L,
+							    G_MAXUINT,
+							    0,
+							    G_PARAM_READWRITE));
 
 	/* signals */
 
 	fr_archive_signals[START] =
 		g_signal_new ("start",
-			      G_TYPE_FROM_CLASS (class),
+			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (FrArchiveClass, start),
 			      NULL, NULL,
 			      fr_marshal_VOID__INT,
 			      G_TYPE_NONE,
 			      1, G_TYPE_INT);
-	fr_archive_signals[DONE] =
-		g_signal_new ("done",
-			      G_TYPE_FROM_CLASS (class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (FrArchiveClass, done),
-			      NULL, NULL,
-			      fr_marshal_VOID__INT_BOXED,
-			      G_TYPE_NONE, 2,
-			      G_TYPE_INT,
-			      FR_TYPE_PROC_ERROR);
 	fr_archive_signals[PROGRESS] =
 		g_signal_new ("progress",
-			      G_TYPE_FROM_CLASS (class),
+			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (FrArchiveClass, progress),
 			      NULL, NULL,
@@ -345,7 +379,7 @@ fr_archive_class_init (FrArchiveClass *class)
 			      G_TYPE_DOUBLE);
 	fr_archive_signals[MESSAGE] =
 		g_signal_new ("message",
-			      G_TYPE_FROM_CLASS (class),
+			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (FrArchiveClass, message),
 			      NULL, NULL,
@@ -354,7 +388,7 @@ fr_archive_class_init (FrArchiveClass *class)
 			      G_TYPE_STRING);
 	fr_archive_signals[STOPPABLE] =
 		g_signal_new ("stoppable",
-			      G_TYPE_FROM_CLASS (class),
+			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (FrArchiveClass, stoppable),
 			      NULL, NULL,
@@ -363,7 +397,7 @@ fr_archive_class_init (FrArchiveClass *class)
 			      1, G_TYPE_BOOLEAN);
 	fr_archive_signals[WORKING_ARCHIVE] =
 		g_signal_new ("working_archive",
-			      G_TYPE_FROM_CLASS (class),
+			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (FrArchiveClass, working_archive),
 			      NULL, NULL,
@@ -373,152 +407,238 @@ fr_archive_class_init (FrArchiveClass *class)
 }
 
 
+static void
+fr_archive_init (FrArchive *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, FR_TYPE_ARCHIVE, FrArchivePrivate);
+
+	self->mime_type = NULL;
+	self->files = g_ptr_array_sized_new (FILES_ARRAY_INITIAL_SIZE);
+	self->n_regular_files = 0;
+        self->password = NULL;
+        self->encrypt_header = FALSE;
+        self->compression = FR_COMPRESSION_NORMAL;
+        self->multi_volume = FALSE;
+        self->volume_size = 0;
+	self->read_only = FALSE;
+	self->action = FR_ACTION_NONE;
+        self->extract_here = FALSE;
+        self->n_file = 0;
+        self->n_files = 0;
+
+        self->propAddCanUpdate = FALSE;
+        self->propAddCanReplace = FALSE;
+        self->propAddCanStoreFolders = FALSE;
+        self->propExtractCanAvoidOverwrite = FALSE;
+        self->propExtractCanSkipOlder = FALSE;
+        self->propExtractCanJunkPaths = FALSE;
+        self->propPassword = FALSE;
+        self->propTest = FALSE;
+        self->propCanExtractAll = TRUE;
+        self->propCanDeleteNonEmptyFolders = TRUE;
+        self->propCanExtractNonEmptyFolders = TRUE;
+        self->propListFromFile = FALSE;
+
+	self->priv->file = NULL;
+	self->priv->cancellable = g_cancellable_new ();
+	self->priv->creating_archive = FALSE;
+	self->priv->extraction_destination = NULL;
+	self->priv->have_write_permissions = FALSE;
+}
+
+
+GFile *
+fr_archive_get_file (FrArchive *self)
+{
+	return self->priv->file;
+}
+
+
+gboolean
+fr_archive_is_capable_of (FrArchive     *self,
+			  FrArchiveCaps  requested_capabilities)
+{
+	return (((self->priv->capabilities ^ requested_capabilities) & requested_capabilities) == 0);
+}
+
+
+const char **
+fr_archive_get_mime_types (FrArchive *self)
+{
+	return FR_ARCHIVE_GET_CLASS (G_OBJECT (self))->get_mime_types (self);
+}
+
+
 void
-fr_archive_stoppable (FrArchive *archive,
-		      gboolean   stoppable)
+fr_archive_update_capabilities (FrArchive *self)
 {
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[STOPPABLE],
-		       0,
-		       stoppable);
+	self->priv->capabilities = fr_archive_get_capabilities (self, self->mime_type, TRUE);
+	/* FIXME: check if this is correct */
+	self->read_only = ! fr_archive_is_capable_of (self, FR_ARCHIVE_CAN_WRITE);
+}
+
+
+FrArchiveCap
+fr_archive_get_capabilities (FrArchive  *self,
+			     const char *mime_type,
+			     gboolean    check_command)
+{
+	return FR_ARCHIVE_GET_CLASS (G_OBJECT (self))->get_capabilities (self, mime_type, check_command);
 }
 
 
 void
-fr_archive_stop (FrArchive *archive)
+fr_archive_set_mime_type (FrArchive  *self,
+			  const char *mime_type)
 {
-	if (archive->process != NULL) {
-		fr_process_stop (archive->process);
-		return;
-	}
+	FR_ARCHIVE_GET_CLASS (G_OBJECT (self))->set_mime_type (self, mime_type);
+}
+
 
-	if (! g_cancellable_is_cancelled (archive->priv->cancellable))
-		g_cancellable_cancel (archive->priv->cancellable);
+const char *
+fr_archive_get_packages (FrArchive  *self,
+			 const char *mime_type)
+{
+	return FR_ARCHIVE_GET_CLASS (G_OBJECT (self))->get_packages (self, mime_type);
 }
 
 
 void
-fr_archive_action_completed (FrArchive       *archive,
-			     FrAction         action,
-			     FrProcErrorType  error_type,
-			     const char      *error_details)
+fr_archive_set_stoppable (FrArchive *archive,
+			  gboolean   stoppable)
 {
-	archive->error.type = error_type;
-	archive->error.status = 0;
-	g_clear_error (&archive->error.gerror);
-	if (error_details != NULL)
-		archive->error.gerror = g_error_new_literal (fr_error_quark (),
-							     0,
-							     error_details);
 	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[DONE],
+		       fr_archive_signals[STOPPABLE],
 		       0,
-		       action,
-		       &archive->error);
+		       stoppable);
 }
 
 
-static gboolean
-archive_sticky_only_cb (FrProcess *process,
-			FrArchive *archive)
+/* -- fr_archive_new_for_creating -- */
+
+
+static const char *
+get_mime_type_from_filename (GFile *file)
 {
-	fr_archive_stoppable (archive, FALSE);
-	return TRUE;
+	const char *mime_type = NULL;
+	char       *uri;
+
+	if (file == NULL)
+		return NULL;
+
+	uri = g_file_get_uri (file);
+	mime_type = get_mime_type_from_extension (_g_filename_get_extension (uri));
+
+	g_free (uri);
+
+	return mime_type;
 }
 
 
-static void
-fr_archive_init (FrArchive *archive)
+static FrArchive *
+create_archive_for_mime_type (GType          archive_type,
+			      GFile         *file,
+			      const char    *mime_type,
+			      FrArchiveCaps  requested_capabilities)
 {
-	archive->file = NULL;
-	archive->local_copy = NULL;
-	archive->is_remote = FALSE;
-	archive->command = NULL;
-	archive->is_compressed_file = FALSE;
-	archive->can_create_compressed_file = FALSE;
+	FrArchive *archive;
 
-	archive->priv = g_new0 (FrArchivePrivData, 1);
-	archive->priv->fake_load_func = NULL;
-	archive->priv->fake_load_data = NULL;
+	if (archive_type == 0)
+		return NULL;
 
-	archive->priv->extraction_destination = NULL;
-	archive->priv->temp_extraction_dir = NULL;
-	archive->priv->cancellable = g_cancellable_new ();
-
-	archive->process = fr_process_new ();
-	g_signal_connect (G_OBJECT (archive->process),
-			  "sticky_only",
-			  G_CALLBACK (archive_sticky_only_cb),
-			  archive);
+	archive = g_object_new (archive_type,
+				"file", file,
+				"mime-type", mime_type,
+				NULL);
+
+	if (! fr_archive_is_capable_of (archive, requested_capabilities)) {
+		g_object_unref (archive);
+		return NULL;
+	}
+
+	return archive;
 }
 
 
 FrArchive *
-fr_archive_new (void)
+fr_archive_create (GFile *file)
 {
-	return FR_ARCHIVE (g_object_new (FR_TYPE_ARCHIVE, NULL));
-}
+	const char *mime_type;
+	GType       archive_type;
+	FrArchive  *archive;
+	GFile      *parent;
 
+	mime_type = get_mime_type_from_filename (file);
+	archive_type = get_archive_type_from_mime_type (mime_type, FR_ARCHIVE_CAN_WRITE);
 
-static const char *
-get_mime_type_from_content (GFile *file)
-{
-	GFileInfo  *info;
-	GError     *err = NULL;
- 	const char *content_type = NULL;
-
-	info = g_file_query_info (file,
-				  G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
-				  0, NULL, &err);
-	if (info == NULL) {
-		g_warning ("could not get content type: %s", err->message);
-		g_clear_error (&err);
-	}
-	else {
-		content_type = _g_str_get_static (g_file_info_get_content_type (info));
-		g_object_unref (info);
-	}
+	archive = create_archive_for_mime_type (archive_type,
+						file,
+						mime_type,
+						FR_ARCHIVE_CAN_WRITE);
 
-	return content_type;
+	parent = g_file_get_parent (file);
+	archive->priv->have_write_permissions = _g_file_check_permissions (parent, W_OK);
+	archive->read_only = ! fr_archive_is_capable_of (archive, FR_ARCHIVE_CAN_WRITE) || ! archive->priv->have_write_permissions;
+
+	g_object_unref (parent);
+
+	return archive;
 }
 
 
-static const char *
-get_mime_type_from_magic_numbers (GFile *file)
+/* -- fr_archive_open -- */
+
+
+#define BUFFER_SIZE_FOR_PRELOAD 32
+
+
+typedef struct {
+	GFile              *file;
+	GCancellable       *cancellable;
+	GSimpleAsyncResult *result;
+	char               *buffer;
+        gsize               buffer_size;
+	FrArchive          *archive;
+} OpenData;
+
+
+static void
+load_data_free (OpenData *open_data)
 {
-#if ENABLE_MAGIC
-	static magic_t magic = NULL;
+	g_object_unref (open_data->file);
+	_g_object_unref (open_data->cancellable);
+	_g_object_unref (open_data->result);
+	_g_object_unref (open_data->archive);
+	g_free (open_data->buffer);
+	g_free (open_data);
+}
 
-	if (! magic) {
-		magic = magic_open (MAGIC_MIME_TYPE);
-		if (magic)
-			magic_load (magic, NULL);
-		else
-			g_warning ("unable to open magic database");
-	}
 
-	if (magic) {
-		const char * mime_type = NULL;
-		char * filepath = g_file_get_path (file);
+static void
+load_data_complete_with_error (OpenData *load_data,
+			       GError   *error)
+{
+	GSimpleAsyncResult *result;
 
-		if (filepath) {
-			mime_type = magic_file (magic, filepath);
-			g_free (filepath);
-		}
+	result = g_object_ref (load_data->result);
+	g_simple_async_result_set_from_error (result, error);
+	g_simple_async_result_complete_in_idle (result);
+
+	g_object_unref (result);
+}
 
-		if (mime_type)
-			return mime_type;
 
-		g_warning ("unable to detect filetype from magic: %s",
-			   magic_error (magic));
-	}
-#else
+static const char *
+get_mime_type_from_magic_numbers (char  *buffer,
+				  gsize  buffer_size)
+{
 	static const struct magic {
 		const unsigned int off;
 		const unsigned int len;
 		const char * const id;
 		const char * const mime_type;
-	} magic_ids [] = {
+	}
+	magic_ids [] = {
 		/* magic ids taken from magic/Magdir/archive from the file-4.21 tarball */
 		{ 0,  6, "7z\274\257\047\034",                   "application/x-7z-compressed" },
 		{ 7,  7, "**ACE**",                              "application/x-ace"           },
@@ -536,76 +656,27 @@ get_mime_type_from_magic_numbers (GFile *file)
 		{ 0,  4, "LRZI",                                 "application/x-lrzip"         },
 	};
 
-	char buffer[32];
 	int  i;
 
-	if (! g_load_file_in_buffer (file, buffer, sizeof (buffer), NULL))
-		return NULL;
-
 	for (i = 0; i < G_N_ELEMENTS (magic_ids); i++) {
 		const struct magic * const magic = &magic_ids[i];
 
-		if (sizeof (buffer) < (magic->off + magic->len))
-			g_warning ("buffer underrun for mime type '%s' magic",
-				   magic->mime_type);
+		if ((magic->off + magic->len) > buffer_size)
+			g_warning ("buffer underrun for mime-type '%s' magic", magic->mime_type);
 		else if (! memcmp (buffer + magic->off, magic->id, magic->len))
 			return magic->mime_type;
 	}
-#endif
 
 	return NULL;
 }
 
 
-static const char *
-get_mime_type_from_filename (GFile *file)
-{
-	const char *mime_type = NULL;
-	char       *filename;
-
-	if (file == NULL)
-		return NULL;
-
-	filename = g_file_get_path (file);
-	mime_type = get_mime_type_from_extension (_g_filename_get_extension (filename));
-	g_free (filename);
-
-	return mime_type;
-}
-
-
-static gboolean
-create_command_from_type (FrArchive     *archive,
-			  const char    *mime_type,
-		          GType          command_type,
-		          FrCommandCaps  requested_capabilities)
-{
-	if (command_type == 0)
-		return FALSE;
-
-	archive->command = FR_COMMAND (g_object_new (command_type,
-					             "process", archive->process,
-					             "mime-type", mime_type,
-					             NULL));
-
-	if (! fr_command_is_capable_of (archive->command, requested_capabilities)) {
-		g_object_unref (archive->command);
-		archive->command = NULL;
-		archive->is_compressed_file = FALSE;
-	}
-	else
-		archive->is_compressed_file = ! fr_command_is_capable_of (archive->command, FR_COMMAND_CAN_ARCHIVE_MANY_FILES);
-
-	return (archive->command != NULL);
-}
-
-
-static gboolean
-create_command_to_load_archive (FrArchive  *archive,
+static FrArchive *
+create_archive_to_load_archive (GFile      *file,
 			        const char *mime_type)
 {
-	FrCommandCaps requested_capabilities = FR_COMMAND_CAN_DO_NOTHING;
-	GType         command_type;
+	FrArchiveCaps requested_capabilities = FR_ARCHIVE_CAN_DO_NOTHING;
+	GType         archive_type;
 
 	if (mime_type == NULL)
 		return FALSE;
@@ -614,2631 +685,613 @@ create_command_to_load_archive (FrArchive  *archive,
 	 * priority to the commands that can read and write over commands
 	 * that can only read a specific file format. */
 
-	requested_capabilities |= FR_COMMAND_CAN_READ_WRITE;
-	command_type = get_command_type_from_mime_type (mime_type, requested_capabilities);
+	requested_capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
+	archive_type = get_archive_type_from_mime_type (mime_type, requested_capabilities);
 
 	/* if no command was found, remove the write capability and try again */
 
-	if (command_type == 0) {
-		requested_capabilities ^= FR_COMMAND_CAN_WRITE;
-		command_type = get_command_type_from_mime_type (mime_type, requested_capabilities);
+	if (archive_type == 0) {
+		requested_capabilities ^= FR_ARCHIVE_CAN_WRITE;
+		archive_type = get_archive_type_from_mime_type (mime_type, requested_capabilities);
 	}
 
-	return create_command_from_type (archive,
-					 mime_type,
-					 command_type,
-					 requested_capabilities);
+	return create_archive_for_mime_type (archive_type,
+					     file,
+					     mime_type,
+					     requested_capabilities);
 }
 
 
-static gboolean
-create_command_to_create_archive (FrArchive  *archive,
-			          const char *mime_type)
-{
-	FrCommandCaps requested_capabilities = FR_COMMAND_CAN_DO_NOTHING;
-	GType         command_type;
+static void
+open_archive_stream_ready_cb (GObject      *source_object,
+			      GAsyncResult *result,
+			      gpointer      user_data)
+{
+	OpenData         *open_data = user_data;
+	GFileInputStream *istream = G_FILE_INPUT_STREAM (source_object);
+	GError           *error = NULL;
+	gssize            bytes_read;
+	const char       *mime_type;
+	gboolean          result_uncertain;
+	FrArchive        *archive;
+	char             *local_mime_type, *uri;
+
+	bytes_read = g_input_stream_read_finish (G_INPUT_STREAM (istream), result, &error);
+	if (bytes_read == -1) {
+		g_object_unref (istream);
+		load_data_complete_with_error (open_data, error);
+		return;
+	}
 
-	if (mime_type == NULL)
-		return FALSE;
+	open_data->buffer_size = bytes_read;
+	g_object_unref (istream);
+
+	archive = NULL;
+	uri = g_file_get_uri (open_data->file);
+	local_mime_type = g_content_type_guess (uri, (guchar *) open_data->buffer, open_data->buffer_size, &result_uncertain);
+	if (! result_uncertain) {
+		mime_type = _g_str_get_static (local_mime_type);
+		archive = create_archive_to_load_archive (open_data->file, mime_type);
+	}
+	if (archive == NULL) {
+		mime_type = get_mime_type_from_magic_numbers (open_data->buffer, open_data->buffer_size);
+		archive = create_archive_to_load_archive (open_data->file, mime_type);
+		if (archive == NULL) {
+			mime_type = get_mime_type_from_filename (open_data->file);
+			archive = create_archive_to_load_archive (open_data->file, mime_type);
+			if (archive == NULL) {
+				error = g_error_new (FR_ERROR,
+						     FR_ERROR_UNSUPPORTED_FORMAT,
+						     "%s",
+						     _("Archive type not supported."));
+				load_data_complete_with_error (open_data, error);
+				return;
+			}
+		}
+	}
+
+	archive->priv->have_write_permissions = _g_file_check_permissions (fr_archive_get_file (archive), W_OK);
+	archive->read_only = ! fr_archive_is_capable_of (archive, FR_ARCHIVE_CAN_WRITE) || ! archive->priv->have_write_permissions;
+	open_data->archive = archive;
 
-	requested_capabilities |= FR_COMMAND_CAN_WRITE;
-	command_type = get_command_type_from_mime_type (mime_type, requested_capabilities);
+        g_simple_async_result_complete_in_idle (open_data->result);
 
-	return create_command_from_type (archive,
-					 mime_type,
-					 command_type,
-					 requested_capabilities);
+        g_free (local_mime_type);
+        g_free (uri);
 }
 
 
 static void
-action_started (FrCommand *command,
-		FrAction   action,
-		FrArchive *archive)
+open_archive_read_ready_cb (GObject      *source_object,
+			    GAsyncResult *result,
+			    gpointer      user_data)
 {
-#ifdef DEBUG
-	debug (DEBUG_INFO, "%s [START] (FR::Archive)\n", action_names[action]);
-#endif
-
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[START],
-		       0,
-		       action);
-}
-
+	OpenData         *open_data = user_data;
+	GFileInputStream *istream;
+	GError           *error = NULL;
 
-/* -- copy_to_remote_location -- */
+	istream = g_file_read_finish (G_FILE (source_object), result, &error);
+	if (istream == NULL) {
+		load_data_complete_with_error (open_data, error);
+		return;
+	}
 
+	g_input_stream_read_async (G_INPUT_STREAM (istream),
+				   open_data->buffer,
+				   open_data->buffer_size,
+				   G_PRIORITY_DEFAULT,
+				   open_data->cancellable,
+				   open_archive_stream_ready_cb,
+				   open_data);
+}
 
-static void
-fr_archive_copy_done (FrArchive *archive,
-		      FrAction   action,
-		      GError    *error)
-{
-	FrProcErrorType  error_type = FR_PROC_ERROR_NONE;
-	const char      *error_details = NULL;
 
-	if (error != NULL) {
-		error_type = (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ? FR_PROC_ERROR_STOPPED : FR_PROC_ERROR_GENERIC);
-		error_details = error->message;
-	}
-	fr_archive_action_completed (archive, action, error_type, error_details);
+void
+fr_archive_open (GFile               *file,
+		 GCancellable        *cancellable,
+		 GAsyncReadyCallback  callback,
+		 gpointer             user_data)
+{
+	OpenData *open_data;
+
+	g_return_if_fail (file != NULL);
+
+	open_data = g_new0 (OpenData, 1);
+	open_data->file = g_object_ref (file);
+	open_data->cancellable = _g_object_ref (cancellable);
+	open_data->result = g_simple_async_result_new (G_OBJECT (file),
+						       callback,
+						       user_data,
+						       fr_archive_open);
+	open_data->buffer_size = BUFFER_SIZE_FOR_PRELOAD;
+	open_data->buffer = g_new (char, open_data->buffer_size);
+        g_simple_async_result_set_op_res_gpointer (open_data->result,
+        					   open_data,
+                                                   (GDestroyNotify) load_data_free);
+
+        /* FIXME: libarchive
+         fr_archive_action_started (archive, FR_ACTION_LOADING_ARCHIVE); */
+
+        /* load a few bytes to guess the archive type */
+
+	g_file_read_async (open_data->file,
+			   G_PRIORITY_DEFAULT,
+			   open_data->cancellable,
+			   open_archive_read_ready_cb,
+			   open_data);
 }
 
 
-static void
-copy_to_remote_location_done (GError   *error,
-			      gpointer  user_data)
+FrArchive *
+fr_archive_open_finish (GFile         *file,
+			GAsyncResult  *result,
+			GError       **error)
 {
-	XferData *xfer_data = user_data;
+	GSimpleAsyncResult *simple;
+	OpenData           *open_data;
 
-	fr_archive_copy_done (xfer_data->archive, xfer_data->action, error);
-	xfer_data_free (xfer_data);
-}
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (file), fr_archive_open), NULL);
 
+	simple = G_SIMPLE_ASYNC_RESULT (result);
 
-static void
-copy_to_remote_location_progress (goffset   current_file,
-                                  goffset   total_files,
-                                  GFile    *source,
-                                  GFile    *destination,
-                                  goffset   current_num_bytes,
-                                  goffset   total_num_bytes,
-                                  gpointer  user_data)
-{
-	XferData *xfer_data = user_data;
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
 
-	g_signal_emit (G_OBJECT (xfer_data->archive),
-		       fr_archive_signals[PROGRESS],
-		       0,
-		       (double) current_num_bytes / total_num_bytes);
+	open_data = g_simple_async_result_get_op_res_gpointer (simple);
+	return _g_object_ref (open_data->archive);
 }
 
 
-static void
-copy_to_remote_location (FrArchive  *archive,
-			 FrAction    action)
+void
+fr_archive_load (FrArchive           *archive,
+		 const char          *password,
+		 GCancellable        *cancellable,
+		 GAsyncReadyCallback  callback,
+		 gpointer             user_data)
 {
-	XferData *xfer_data;
+	g_return_if_fail (archive != NULL);
 
-	xfer_data = g_new0 (XferData, 1);
-	xfer_data->archive = archive;
-	xfer_data->action = action;
+	if (archive->files != NULL) {
+		_g_ptr_array_free_full (archive->files, (GFunc) file_data_free, NULL);
+		archive->files = g_ptr_array_sized_new (FILE_ARRAY_INITIAL_SIZE);
+	}
 
-	g_copy_file_async (archive->local_copy,
-			   archive->file,
-			   G_FILE_COPY_OVERWRITE,
-			   G_PRIORITY_DEFAULT,
-			   archive->priv->cancellable,
-			   copy_to_remote_location_progress,
-			   xfer_data,
-			   copy_to_remote_location_done,
-			   xfer_data);
+	fr_archive_action_started (archive, FR_ACTION_LISTING_CONTENT);
+	FR_ARCHIVE_GET_CLASS (archive)->load (archive, password, cancellable, callback, user_data);
 }
 
 
-/* -- copy_extracted_files_to_destination -- */
+gboolean
+fr_archive_operation_finish (FrArchive     *archive,
+			     GAsyncResult  *result,
+			     GError       **error)
+{
+	return ! g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+}
 
 
-static void
-move_here (FrArchive *archive)
+void
+fr_archive_add_files (FrArchive           *archive,
+		      GList               *file_list,
+		      const char          *base_dir,
+		      const char          *dest_dir,
+		      gboolean             update,
+		      gboolean             recursive,
+		      const char          *password,
+		      gboolean             encrypt_header,
+		      FrCompression        compression,
+		      guint                volume_size,
+		      GCancellable        *cancellable,
+		      GAsyncReadyCallback  callback,
+		      gpointer             user_data)
 {
-	char   *content_uri;
-	char   *parent;
-	char   *parent_parent;
-	char   *new_content_uri;
-	GFile  *source, *destination, *parent_file;
-	GError *error = NULL;
-
-	content_uri = _g_uri_get_dir_content_if_unique (archive->priv->extraction_destination);
-	if (content_uri == NULL)
-		return;
+	g_return_if_fail (! archive->read_only);
 
-	parent = _g_path_remove_level (content_uri);
+	g_signal_emit (G_OBJECT (archive),
+		       fr_archive_signals[START],
+		       0,
+		       FR_ACTION_ADDING_FILES);
 
-	if (_g_uri_cmp (parent, archive->priv->extraction_destination) == 0) {
-		char *new_uri;
+	FR_ARCHIVE_GET_CLASS (archive)->add_files (archive,
+						   file_list,
+						   base_dir,
+						   dest_dir,
+						   update,
+						   recursive,
+						   password,
+						   encrypt_header,
+						   compression,
+						   volume_size,
+						   cancellable,
+						   callback,
+						   user_data);
+}
 
-		new_uri = _g_uri_create_alternative_for_uri (archive->priv->extraction_destination);
 
-		source = g_file_new_for_uri (archive->priv->extraction_destination);
-		destination = g_file_new_for_uri (new_uri);
-		if (! g_file_move (source, destination, 0, NULL, NULL, NULL, &error)) {
-			g_warning ("could not rename %s to %s: %s", archive->priv->extraction_destination, new_uri, error->message);
-			g_clear_error (&error);
-		}
-		g_object_unref (source);
-		g_object_unref (destination);
+/* -- add with wildcard -- */
 
-		g_free (archive->priv->extraction_destination);
-		archive->priv->extraction_destination = new_uri;
 
-		g_free (parent);
-
-		content_uri = _g_uri_get_dir_content_if_unique (archive->priv->extraction_destination);
-		if (content_uri == NULL)
-			return;
-
-		parent = _g_path_remove_level (content_uri);
-	}
-
-	parent_parent = _g_path_remove_level (parent);
-	new_content_uri = _g_uri_create_alternative (parent_parent, _g_path_get_file_name (content_uri));
-
-	source = g_file_new_for_uri (content_uri);
-	destination = g_file_new_for_uri (new_content_uri);
-	if (! g_file_move (source, destination, 0, NULL, NULL, NULL, &error)) {
-		g_warning ("could not rename %s to %s: %s", content_uri, new_content_uri, error->message);
-		g_clear_error (&error);
-	}
-
-	parent_file = g_file_new_for_uri (parent);
-	if (! g_file_delete (parent_file, NULL, &error)) {
-		g_warning ("could not remove directory %s: %s", parent, error->message);
-		g_clear_error (&error);
-	}
-	g_object_unref (parent_file);
-
-	g_free (archive->priv->extraction_destination);
-	archive->priv->extraction_destination = new_content_uri;
-
-	g_free (parent_parent);
-	g_free (parent);
-	g_free (content_uri);
-}
-
-
-static void
-copy_extracted_files_done (GError   *error,
-			   gpointer  user_data)
-{
-	FrArchive *archive = user_data;
-
-	_g_path_remove_directory (archive->priv->temp_extraction_dir);
-	g_free (archive->priv->temp_extraction_dir);
-	archive->priv->temp_extraction_dir = NULL;
-
-	fr_archive_action_completed (archive,
-				     FR_ACTION_COPYING_FILES_TO_REMOTE,
-				     FR_PROC_ERROR_NONE,
-				     NULL);
-
-	if ((error == NULL) && (archive->priv->extract_here))
-		move_here (archive);
-
-	fr_archive_copy_done (archive, FR_ACTION_EXTRACTING_FILES, error);
-}
-
-
-static void
-copy_extracted_files_progress (goffset   current_file,
-                               goffset   total_files,
-                               GFile    *source,
-                               GFile    *destination,
-                               goffset   current_num_bytes,
-                               goffset   total_num_bytes,
-                               gpointer  user_data)
-{
-	FrArchive *archive = user_data;
-
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[PROGRESS],
-		       0,
-		       (double) current_file / (total_files + 1));
-}
-
-
-static void
-copy_extracted_files_to_destination (FrArchive *archive)
-{
-	g_directory_copy_async (archive->priv->temp_extraction_dir,
-				archive->priv->extraction_destination,
-				G_FILE_COPY_OVERWRITE,
-				G_PRIORITY_DEFAULT,
-				archive->priv->cancellable,
-				copy_extracted_files_progress,
-				archive,
-				copy_extracted_files_done,
-				archive);
-}
-
-
-static void add_dropped_items (DroppedItemsData *data);
-
-
-static void
-fr_archive_change_name (FrArchive  *archive,
-		        const char *filename)
-{
-	const char *name;
-	GFile      *parent;
-
-	name = _g_path_get_file_name (filename);
-
-	parent = g_file_get_parent (archive->file);
-	g_object_unref (archive->file);
-	archive->file = g_file_get_child (parent, name);
-	g_object_unref (parent);
-
-	parent = g_file_get_parent (archive->local_copy);
-	g_object_unref (archive->local_copy);
-	archive->local_copy = g_file_get_child (parent, name);
-	g_object_unref (parent);
-}
-
-
-static void
-action_performed (FrCommand   *command,
-		  FrAction     action,
-		  FrProcError *error,
-		  FrArchive   *archive)
-{
-#ifdef DEBUG
-	debug (DEBUG_INFO, "%s [DONE] (FR::Archive)\n", action_names[action]);
-#endif
-
-	switch (action) {
-	case FR_ACTION_DELETING_FILES:
-		if (error->type == FR_PROC_ERROR_NONE) {
-			if (! g_file_has_uri_scheme (archive->file, "file")) {
-				copy_to_remote_location (archive, action);
-				return;
-			}
-		}
-		break;
-
-	case FR_ACTION_ADDING_FILES:
-		if (error->type == FR_PROC_ERROR_NONE) {
-			fr_archive_remove_temp_work_dir (archive);
-			if (archive->priv->continue_adding_dropped_items) {
-				add_dropped_items (archive->priv->dropped_items_data);
-				return;
-			}
-			if (archive->priv->dropped_items_data != NULL) {
-				dropped_items_data_free (archive->priv->dropped_items_data);
-				archive->priv->dropped_items_data = NULL;
-			}
-			/* the name of the volumes are different from the
-			 * original name */
-			if (archive->command->multi_volume)
-				fr_archive_change_name (archive, archive->command->filename);
-			if (! g_file_has_uri_scheme (archive->file, "file")) {
-				copy_to_remote_location (archive, action);
-				return;
-			}
-		}
-		break;
-
-	case FR_ACTION_EXTRACTING_FILES:
-		if (error->type == FR_PROC_ERROR_NONE) {
-			if (archive->priv->remote_extraction) {
-				copy_extracted_files_to_destination (archive);
-				return;
-			}
-			else if (archive->priv->extract_here)
-				move_here (archive);
-		}
-		else {
-			/* if an error occurred during extraction remove the
-			 * temp extraction dir, if used. */
-			g_print ("action_performed: ERROR!\n");
-
-			if ((archive->priv->remote_extraction) && (archive->priv->temp_extraction_dir != NULL)) {
-				_g_path_remove_directory (archive->priv->temp_extraction_dir);
-				g_free (archive->priv->temp_extraction_dir);
-				archive->priv->temp_extraction_dir = NULL;
-			}
-
-			if (archive->priv->extract_here)
-				_g_uri_remove_directory (archive->priv->extraction_destination);
-		}
-		break;
-
-	case FR_ACTION_LISTING_CONTENT:
-		/* the name of the volumes are different from the
-		 * original name */
-		if (archive->command->multi_volume)
-			fr_archive_change_name (archive, archive->command->filename);
-		fr_command_update_capabilities (archive->command);
-		if (! fr_command_is_capable_of (archive->command, FR_COMMAND_CAN_WRITE))
-			archive->read_only = TRUE;
-		break;
-
-	default:
-		/* nothing */
-		break;
-	}
-
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[DONE],
-		       0,
-		       action,
-		       error);
-}
-
-
-static gboolean
-archive_progress_cb (FrCommand *command,
-		     double     fraction,
-		     FrArchive *archive)
-{
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[PROGRESS],
-		       0,
-		       fraction);
-	return TRUE;
-}
-
-
-static gboolean
-archive_message_cb  (FrCommand  *command,
-		     const char *msg,
-		     FrArchive  *archive)
-{
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[MESSAGE],
-		       0,
-		       msg);
-	return TRUE;
-}
-
-
-static gboolean
-archive_working_archive_cb  (FrCommand  *command,
-			     const char *archive_filename,
-			     FrArchive  *archive)
-{
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[WORKING_ARCHIVE],
-		       0,
-		       archive_filename);
-	return TRUE;
-}
-
-
-static void
-fr_archive_connect_to_command (FrArchive *archive)
-{
-	g_signal_connect (G_OBJECT (archive->command),
-			  "start",
-			  G_CALLBACK (action_started),
-			  archive);
-	g_signal_connect (G_OBJECT (archive->command),
-			  "done",
-			  G_CALLBACK (action_performed),
-			  archive);
-	g_signal_connect (G_OBJECT (archive->command),
-			  "progress",
-			  G_CALLBACK (archive_progress_cb),
-			  archive);
-	g_signal_connect (G_OBJECT (archive->command),
-			  "message",
-			  G_CALLBACK (archive_message_cb),
-			  archive);
-	g_signal_connect (G_OBJECT (archive->command),
-			  "working_archive",
-			  G_CALLBACK (archive_working_archive_cb),
-			  archive);
-}
-
-
-gboolean
-fr_archive_create (FrArchive  *archive,
-		   const char *uri)
-{
-	FrCommand  *tmp_command;
-	const char *mime_type;
-
-	if (uri == NULL)
-		return FALSE;
-
-	fr_archive_set_uri (archive, uri);
-
-	tmp_command = archive->command;
-
-	mime_type = get_mime_type_from_filename (archive->local_copy);
-	if (! create_command_to_create_archive (archive, mime_type)) {
-		archive->command = tmp_command;
-		return FALSE;
-	}
-
-	if (tmp_command != NULL) {
-		g_signal_handlers_disconnect_by_data (tmp_command, archive);
-		g_object_unref (G_OBJECT (tmp_command));
-	}
-
-	fr_archive_connect_to_command (archive);
-	archive->read_only = FALSE;
-
-	return TRUE;
-}
-
-
-void
-fr_archive_set_fake_load_func (FrArchive    *archive,
-			       FakeLoadFunc  func,
-			       gpointer      data)
-{
-	archive->priv->fake_load_func = func;
-	archive->priv->fake_load_data = data;
-}
-
-
-gboolean
-fr_archive_fake_load (FrArchive *archive)
-{
-	if (archive->priv->fake_load_func != NULL)
-		return (*archive->priv->fake_load_func) (archive, archive->priv->fake_load_data);
-	else
-		return FALSE;
-}
-
-
-/* -- fr_archive_load -- */
-
-
-static void
-load_local_archive (FrArchive  *archive,
-		    const char *password)
-{
-	FrCommand  *old_command;
-	const char *mime_type;
-
-	if (! g_file_query_exists (archive->file, archive->priv->cancellable)) {
-		fr_archive_action_completed (archive,
-					     FR_ACTION_LOADING_ARCHIVE,
-					     FR_PROC_ERROR_GENERIC,
-					     _("File not found."));
-		return;
-	}
-
-	archive->have_permissions = _g_file_check_permissions (archive->file, W_OK);
-	archive->read_only = ! archive->have_permissions;
-
-	old_command = archive->command;
-
-	mime_type = get_mime_type_from_filename (archive->local_copy);
-	if (! create_command_to_load_archive (archive, mime_type)) {
-		mime_type = get_mime_type_from_content (archive->local_copy);
-		if (! create_command_to_load_archive (archive, mime_type)) {
-			mime_type = get_mime_type_from_magic_numbers (archive->local_copy);
-			if (! create_command_to_load_archive (archive, mime_type)) {
-				archive->command = old_command;
-				archive->content_type = mime_type;
-				fr_archive_action_completed (archive,
-							     FR_ACTION_LOADING_ARCHIVE,
-							     FR_PROC_ERROR_UNSUPPORTED_FORMAT,
-							     _("Archive type not supported."));
-				return;
-			}
-		}
-	}
-
-	if (old_command != NULL) {
-		g_signal_handlers_disconnect_by_data (old_command, archive);
-		g_object_unref (old_command);
-	}
-
-	fr_archive_connect_to_command (archive);
-	archive->content_type = mime_type;
-	if (! fr_command_is_capable_of (archive->command, FR_COMMAND_CAN_WRITE))
-		archive->read_only = TRUE;
-	fr_archive_stoppable (archive, TRUE);
-	archive->command->fake_load = fr_archive_fake_load (archive);
-
-	fr_archive_action_completed (archive,
-				     FR_ACTION_LOADING_ARCHIVE,
-				     FR_PROC_ERROR_NONE,
-				     NULL);
-
-	/**/
-
-	fr_process_clear (archive->process);
-	g_object_set (archive->command,
-		      "file", archive->local_copy,
-		      "password", password,
-		      NULL);
-	fr_command_list (archive->command);
-}
-
-
-static void
-copy_remote_file_done (GError   *error,
-		       gpointer  user_data)
-{
-	XferData *xfer_data = user_data;
-
-	if (error != NULL)
-		fr_archive_copy_done (xfer_data->archive, FR_ACTION_LOADING_ARCHIVE, error);
-	else
-		load_local_archive (xfer_data->archive, xfer_data->password);
-	xfer_data_free (xfer_data);
-}
-
-
-static void
-copy_remote_file_progress (goffset   current_file,
-                           goffset   total_files,
-                           GFile    *source,
-                           GFile    *destination,
-                           goffset   current_num_bytes,
-                           goffset   total_num_bytes,
-                           gpointer  user_data)
-{
-	XferData *xfer_data = user_data;
-
-	g_signal_emit (G_OBJECT (xfer_data->archive),
-		       fr_archive_signals[PROGRESS],
-		       0,
-		       (double) current_num_bytes / total_num_bytes);
-}
-
-
-static gboolean
-copy_remote_file_done_cb (gpointer user_data)
-{
-	XferData *xfer_data = user_data;
-
-	g_source_remove (xfer_data->source_id);
-	copy_remote_file_done (NULL, xfer_data);
-	return FALSE;
-}
-
-
-static void
-copy_remote_file (FrArchive  *archive,
-		  const char *password)
-{
-	XferData *xfer_data;
-
-	if (! g_file_query_exists (archive->file, archive->priv->cancellable)) {
-		GError *error;
-
-		error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Archive not found"));
-		fr_archive_copy_done (archive, FR_ACTION_LOADING_ARCHIVE, error);
-		g_error_free (error);
-
-		return;
-	}
-
-	xfer_data = g_new0 (XferData, 1);
-	xfer_data->archive = archive;
-	xfer_data->uri = g_file_get_uri (archive->file);
-	if (password != NULL)
-		xfer_data->password = g_strdup (password);
-
-	if (! archive->is_remote) {
-		xfer_data->source_id = g_idle_add (copy_remote_file_done_cb, xfer_data);
-		return;
-	}
-
-	g_copy_file_async (archive->file,
-			   archive->local_copy,
-			   G_FILE_COPY_OVERWRITE,
-			   G_PRIORITY_DEFAULT,
-			   archive->priv->cancellable,
-			   copy_remote_file_progress,
-			   xfer_data,
-			   copy_remote_file_done,
-			   xfer_data);
-}
-
-
-gboolean
-fr_archive_load (FrArchive  *archive,
-		 const char *uri,
-		 const char *password)
-{
-	g_return_val_if_fail (archive != NULL, FALSE);
-
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[START],
-		       0,
-		       FR_ACTION_LOADING_ARCHIVE);
-
-	fr_archive_set_uri (archive, uri);
-	copy_remote_file (archive, password);
-
-	return TRUE;
-}
-
-
-void
-fr_archive_reload (FrArchive  *archive,
-		   const char *password)
-{
-	char *uri;
-
-	g_return_if_fail (archive != NULL);
-	g_return_if_fail (archive->file != NULL);
-
-	fr_archive_stoppable (archive, TRUE);
-	archive->command->fake_load = fr_archive_fake_load (archive);
-
-	uri = g_file_get_uri (archive->file);
-	fr_archive_load (archive, uri, password);
-	g_free (uri);
-}
-
-
-/* -- add -- */
-
-
-static char *
-create_tmp_base_dir (const char *base_dir,
-		     const char *dest_path)
-{
-	char *dest_dir;
-	char *temp_dir;
-	char *tmp;
-	char *parent_dir;
-	char *dir;
-
-	if ((dest_path == NULL)
-	    || (*dest_path == '\0')
-	    || (strcmp (dest_path, "/") == 0))
-	{
-		return g_strdup (base_dir);
-	}
-
-	dest_dir = g_strdup (dest_path);
-	if (dest_dir[strlen (dest_dir) - 1] == G_DIR_SEPARATOR)
-		dest_dir[strlen (dest_dir) - 1] = 0;
-
-	debug (DEBUG_INFO, "base_dir: %s\n", base_dir);
-	debug (DEBUG_INFO, "dest_dir: %s\n", dest_dir);
-
-	temp_dir = _g_path_get_temp_work_dir (NULL);
-	tmp = _g_path_remove_level (dest_dir);
-	parent_dir =  g_build_filename (temp_dir, tmp, NULL);
-	g_free (tmp);
-
-	debug (DEBUG_INFO, "mkdir %s\n", parent_dir);
-	_g_path_make_directory_tree (parent_dir, 0700, NULL);
-	g_free (parent_dir);
-
-	dir = g_build_filename (temp_dir, "/", dest_dir, NULL);
-	debug (DEBUG_INFO, "symlink %s --> %s\n", dir, base_dir);
-	if (! symlink (base_dir, dir)) {
-		/* void */
-	}
-
-	g_free (dir);
-	g_free (dest_dir);
-
-	return temp_dir;
-}
-
-
-static FileData *
-find_file_in_archive (FrArchive *archive,
-		      char      *path)
-{
-	int i;
-
-	g_return_val_if_fail (path != NULL, NULL);
-
-	i = find_path_in_file_data_array (archive->command->files, path);
-	if (i >= 0)
-		return (FileData *) g_ptr_array_index (archive->command->files, i);
-	else
-		return NULL;
-}
-
-
-static void delete_from_archive (FrArchive *archive, GList *file_list);
-
-
-static GList *
-newer_files_only (FrArchive  *archive,
-		  GList      *file_list,
-		  const char *base_dir)
-{
-	GList *newer_files = NULL;
-	GList *scan;
-
-	for (scan = file_list; scan; scan = scan->next) {
-		char     *filename = scan->data;
-		char     *fullpath;
-		char     *uri;
-		FileData *fdata;
-
-		fdata = find_file_in_archive (archive, filename);
-
-		if (fdata == NULL) {
-			newer_files = g_list_prepend (newer_files, g_strdup (scan->data));
-			continue;
-		}
-
-		fullpath = g_strconcat (base_dir, "/", filename, NULL);
-		uri = g_filename_to_uri (fullpath, NULL, NULL);
-
-		if (fdata->modified >= _g_uri_get_file_mtime (uri)) {
-			g_free (fullpath);
-			g_free (uri);
-			continue;
-		}
-		g_free (fullpath);
-		g_free (uri);
-
-		newer_files = g_list_prepend (newer_files, g_strdup (scan->data));
-	}
-
-	return newer_files;
-}
-
-
-static gboolean
-save_list_to_temp_file (GList   *file_list,
-		        char   **list_dir,
-		        char   **list_filename,
-		        GError **error)
-{
-	gboolean           error_occurred = FALSE;
-	GFile             *list_file;
-	GFileOutputStream *ostream;
-
-	if (error != NULL)
-		*error = NULL;
-	*list_dir = _g_path_get_temp_work_dir (NULL);
-	*list_filename = g_build_filename (*list_dir, "file-list", NULL);
-	list_file = g_file_new_for_path (*list_filename);
-	ostream = g_file_create (list_file, G_FILE_CREATE_PRIVATE, NULL, error);
-
-	if (ostream != NULL) {
-		GList *scan;
-
-		for (scan = file_list; scan != NULL; scan = scan->next) {
-			char *filename = scan->data;
-
-			filename = _g_str_substitute (filename, "\n", "\\n");
-			if ((g_output_stream_write (G_OUTPUT_STREAM (ostream), filename, strlen (filename), NULL, error) < 0)
-			    || (g_output_stream_write (G_OUTPUT_STREAM (ostream), "\n", 1, NULL, error) < 0))
-			{
-				error_occurred = TRUE;
-			}
-
-			g_free (filename);
-
-			if (error_occurred)
-				break;
-		}
-		if (! error_occurred && ! g_output_stream_close (G_OUTPUT_STREAM (ostream), NULL, error))
-			error_occurred = TRUE;
-		g_object_unref (ostream);
-	}
-	else
-		error_occurred = TRUE;
-
-	if (error_occurred) {
-		_g_path_remove_directory (*list_dir);
-		g_free (*list_dir);
-		g_free (*list_filename);
-		*list_dir = NULL;
-		*list_filename = NULL;
-	}
-
-	g_object_unref (list_file);
-
-	return ! error_occurred;
-}
-
-
-static GList *
-split_in_chunks (GList *file_list)
-{
-	GList *chunks = NULL;
-	GList *new_file_list;
-	GList *scan;
-
-	new_file_list = g_list_copy (file_list);
-	for (scan = new_file_list; scan != NULL; /* void */) {
-		GList *prev = scan->prev;
-		GList *chunk;
-		int    l;
-
-		chunk = scan;
-		l = 0;
-		while ((scan != NULL) && (l < MAX_CHUNK_LEN)) {
-			if (l == 0)
-				l = strlen (scan->data);
-			prev = scan;
-			scan = scan->next;
-			if (scan != NULL)
-				l += strlen (scan->data);
-		}
-		if (prev != NULL) {
-			if (prev->next != NULL)
-				prev->next->prev = NULL;
-			prev->next = NULL;
-		}
-		chunks = g_list_append (chunks, chunk);
-	}
-
-	return chunks;
-}
-
-
-void
-fr_archive_add (FrArchive     *archive,
-		GList         *file_list,
-		const char    *base_dir,
-		const char    *dest_dir,
-		gboolean       update,
-		gboolean       recursive,
-		const char    *password,
-		gboolean       encrypt_header,
-		FrCompression  compression,
-		guint          volume_size)
-{
-	GList    *new_file_list = NULL;
-	gboolean  base_dir_created = FALSE;
-	GList    *scan;
-	char     *tmp_base_dir = NULL;
-	char     *tmp_archive_dir = NULL;
-	char     *archive_filename = NULL;
-	char     *tmp_archive_filename = NULL;
-	gboolean  error_occurred = FALSE;
-
-	if (file_list == NULL)
-		return;
-
-	if (archive->read_only)
-		return;
-
-	g_object_set (archive->command,
-		      "password", password,
-		      "encrypt_header", encrypt_header,
-		      "compression", compression,
-		      "volume_size", volume_size,
-		      NULL);
-
-	fr_archive_stoppable (archive, TRUE);
-
-	/* dest_dir is the destination folder inside the archive */
-
-	if ((dest_dir != NULL) && (*dest_dir != '\0') && (strcmp (dest_dir, "/") != 0)) {
-		const char *rel_dest_dir = dest_dir;
-
-		tmp_base_dir = create_tmp_base_dir (base_dir, dest_dir);
-		base_dir_created = TRUE;
-
-		if (dest_dir[0] == G_DIR_SEPARATOR)
-			rel_dest_dir = dest_dir + 1;
-
-		new_file_list = NULL;
-		for (scan = file_list; scan != NULL; scan = scan->next) {
-			char *filename = scan->data;
-			new_file_list = g_list_prepend (new_file_list, g_build_filename (rel_dest_dir, filename, NULL));
-		}
-	}
-	else {
-		tmp_base_dir = g_strdup (base_dir);
-		new_file_list = _g_string_list_dup (file_list);
-	}
-
-	/* if the command cannot update,  get the list of files that are
-	 * newer than the ones in the archive. */
-
-	if (update && ! archive->command->propAddCanUpdate) {
-		GList *tmp_file_list;
-
-		tmp_file_list = new_file_list;
-		new_file_list = newer_files_only (archive, tmp_file_list, tmp_base_dir);
-		_g_string_list_free (tmp_file_list);
-	}
-
-	if (new_file_list == NULL) {
-		debug (DEBUG_INFO, "nothing to update.\n");
-
-		if (base_dir_created)
-			_g_path_remove_directory (tmp_base_dir);
-		g_free (tmp_base_dir);
-
-		archive->process->error.type = FR_PROC_ERROR_NONE;
-		g_signal_emit_by_name (G_OBJECT (archive->process),
-				       "done",
-				       &archive->process->error);
-		return;
-	}
-
-	archive->command->creating_archive = ! g_file_query_exists (archive->local_copy, archive->priv->cancellable);
-
-	/* create the new archive in a temporary sub-directory, this allows
-	 * to cancel the operation without losing the original archive and
-	 * removing possible temporary files created by the command. */
-
-	{
-		GFile *local_copy_parent;
-		char  *archive_dir;
-		GFile *tmp_file;
-
-		/* create the new archive in a sub-folder of the original
-		 * archive this way the 'mv' command is fast. */
-
-		local_copy_parent = g_file_get_parent (archive->local_copy);
-		archive_dir = g_file_get_path (local_copy_parent);
-		tmp_archive_dir = _g_path_get_temp_work_dir (archive_dir);
-		archive_filename = g_file_get_path (archive->local_copy);
-		tmp_archive_filename = g_build_filename (tmp_archive_dir, _g_path_get_file_name (archive_filename), NULL);
-		tmp_file = g_file_new_for_path (tmp_archive_filename);
-		g_object_set (archive->command, "file", tmp_file, NULL);
-
-		if (! archive->command->creating_archive) {
-			/* copy the original archive to the new position */
-
-			fr_process_begin_command (archive->process, "cp");
-			fr_process_add_arg (archive->process, "-f");
-			fr_process_add_arg (archive->process, archive_filename);
-			fr_process_add_arg (archive->process, tmp_archive_filename);
-			fr_process_end_command (archive->process);
-		}
-
-		g_object_unref (tmp_file);
-		g_free (archive_dir);
-		g_object_unref (local_copy_parent);
-	}
-
-	fr_command_uncompress (archive->command);
-
-	/* when files are already present in a tar archive and are added
-	 * again, they are not replaced, so we have to delete them first. */
-
-	/* if we are adding (== ! update) and 'add' cannot replace or
-	 * if we are updating and 'add' cannot update,
-	 * delete the files first. */
-
-	if ((! update && ! archive->command->propAddCanReplace)
-	    || (update && ! archive->command->propAddCanUpdate))
-	{
-		GList *del_list = NULL;
-
-		for (scan = new_file_list; scan != NULL; scan = scan->next) {
-			char *filename = scan->data;
-			if (find_file_in_archive (archive, filename))
-				del_list = g_list_prepend (del_list, filename);
-		}
-
-		/* delete */
-
-		if (del_list != NULL) {
-			delete_from_archive (archive, del_list);
-			fr_process_set_ignore_error (archive->process, TRUE);
-			g_list_free (del_list);
-		}
-	}
-
-	/* add now. */
-
-	fr_command_set_n_files (archive->command, g_list_length (new_file_list));
-
-	if (archive->command->propListFromFile
-	    && (archive->command->n_files > LIST_LENGTH_TO_USE_FILE))
-	{
-		char   *list_dir;
-		char   *list_filename;
-		GError *error = NULL;
-
-		if (! save_list_to_temp_file (new_file_list, &list_dir, &list_filename, &error)) {
-			archive->process->error.type = FR_PROC_ERROR_GENERIC;
-			archive->process->error.status = 0;
-			archive->process->error.gerror = g_error_copy (error);
-			g_signal_emit_by_name (G_OBJECT (archive->process),
-					       "done",
-					       &archive->process->error);
-			g_clear_error (&error);
-			error_occurred = TRUE;
-		}
-		else {
-			fr_command_add (archive->command,
-					list_filename,
-					new_file_list,
-					tmp_base_dir,
-					update,
-					recursive);
-
-			/* remove the temp dir */
-
-			fr_process_begin_command (archive->process, "rm");
-			fr_process_set_working_dir (archive->process, g_get_tmp_dir());
-			fr_process_set_sticky (archive->process, TRUE);
-			fr_process_add_arg (archive->process, "-rf");
-			fr_process_add_arg (archive->process, list_dir);
-			fr_process_end_command (archive->process);
-		}
-
-		g_free (list_filename);
-		g_free (list_dir);
-	}
-	else {
-		GList *chunks = NULL;
-
-		/* specify the file list on the command line, splitting
-		 * in more commands to avoid to overflow the command line
-		 * length limit. */
-
-		chunks = split_in_chunks (new_file_list);
-		for (scan = chunks; scan != NULL; scan = scan->next) {
-			GList *chunk = scan->data;
-
-			fr_command_add (archive->command,
-					NULL,
-					chunk,
-					tmp_base_dir,
-					update,
-					recursive);
-			g_list_free (chunk);
-		}
-
-		g_list_free (chunks);
-	}
-
-	_g_string_list_free (new_file_list);
-
-	if (! error_occurred) {
-		fr_command_recompress (archive->command);
-
-		/* move the new archive to the original position */
-
-		fr_process_begin_command (archive->process, "mv");
-		fr_process_add_arg (archive->process, "-f");
-		fr_process_add_arg (archive->process, tmp_archive_filename);
-		fr_process_add_arg (archive->process, archive_filename);
-		fr_process_end_command (archive->process);
-
-		/* remove the temp sub-directory */
-
-		fr_process_begin_command (archive->process, "rm");
-		fr_process_set_working_dir (archive->process, g_get_tmp_dir());
-		fr_process_set_sticky (archive->process, TRUE);
-		fr_process_add_arg (archive->process, "-rf");
-		fr_process_add_arg (archive->process, tmp_archive_dir);
-		fr_process_end_command (archive->process);
-
-		/* remove the base dir */
-
-		if (base_dir_created) {
-			fr_process_begin_command (archive->process, "rm");
-			fr_process_set_working_dir (archive->process, g_get_tmp_dir());
-			fr_process_set_sticky (archive->process, TRUE);
-			fr_process_add_arg (archive->process, "-rf");
-			fr_process_add_arg (archive->process, tmp_base_dir);
-			fr_process_end_command (archive->process);
-		}
-	}
-
-	g_free (tmp_archive_filename);
-	g_free (archive_filename);
-	g_free (tmp_archive_dir);
-	g_free (tmp_base_dir);
-}
-
-
-static void
-fr_archive_add_local_files (FrArchive     *archive,
-			    GList         *file_list,
-			    const char    *base_dir,
-			    const char    *dest_dir,
-			    gboolean       update,
-			    const char    *password,
-			    gboolean       encrypt_header,
-			    FrCompression  compression,
-			    guint          volume_size)
-{
-	fr_process_clear (archive->process);
-	fr_archive_add (archive,
-			file_list,
-			base_dir,
-			dest_dir,
-			update,
-			FALSE,
-			password,
-			encrypt_header,
-			compression,
-			volume_size);
-	fr_process_start (archive->process);
-}
-
-
-static void
-copy_remote_files_done (GError   *error,
-			gpointer  user_data)
-{
-	XferData *xfer_data = user_data;
-
-	fr_archive_copy_done (xfer_data->archive, FR_ACTION_COPYING_FILES_FROM_REMOTE, error);
-
-	if (error == NULL)
-		fr_archive_add_local_files (xfer_data->archive,
-					    xfer_data->file_list,
-					    xfer_data->tmp_dir,
-					    xfer_data->dest_dir,
-					    FALSE,
-					    xfer_data->password,
-					    xfer_data->encrypt_header,
-					    xfer_data->compression,
-					    xfer_data->volume_size);
-	xfer_data_free (xfer_data);
-}
-
-
-static void
-copy_remote_files_progress (goffset   current_file,
-                            goffset   total_files,
-                            GFile    *source,
-                            GFile    *destination,
-                            goffset   current_num_bytes,
-                            goffset   total_num_bytes,
-                            gpointer  user_data)
-{
-	XferData *xfer_data = user_data;
-
-	g_signal_emit (G_OBJECT (xfer_data->archive),
-		       fr_archive_signals[PROGRESS],
-		       0,
-		       (double) current_file / (total_files + 1));
-}
-
-
-static void
-copy_remote_files (FrArchive     *archive,
-		   GList         *file_list,
-		   const char    *base_uri,
-		   const char    *dest_dir,
-		   gboolean       update,
-		   const char    *password,
-		   gboolean       encrypt_header,
-		   FrCompression  compression,
-		   guint          volume_size,
-		   const char    *tmp_dir)
-{
-	GList      *sources = NULL, *destinations = NULL;
-	GHashTable *created_folders;
-	GList      *scan;
-	XferData   *xfer_data;
-
-	created_folders = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
-	for (scan = file_list; scan; scan = scan->next) {
-		char  *partial_filename = scan->data;
-		char  *local_uri;
-		char  *local_folder_uri;
-		char  *remote_uri;
-
-		local_uri = g_strconcat ("file://", tmp_dir, "/", partial_filename, NULL);
-		local_folder_uri = _g_path_remove_level (local_uri);
-		if (g_hash_table_lookup (created_folders, local_folder_uri) == NULL) {
-			GError *error = NULL;
-			if (! _g_uri_ensure_dir_exists (local_folder_uri, 0755, &error)) {
-				g_free (local_folder_uri);
-				g_free (local_uri);
-				_g_file_list_free (sources);
-				_g_file_list_free (destinations);
-				g_hash_table_destroy (created_folders);
-
-				fr_archive_action_completed (archive,
-							     FR_ACTION_COPYING_FILES_FROM_REMOTE,
-							     FR_PROC_ERROR_GENERIC,
-							     error->message);
-				g_clear_error (&error);
-				return;
-			}
-
-			g_hash_table_insert (created_folders, local_folder_uri, GINT_TO_POINTER (1));
-		}
-		else
-			g_free (local_folder_uri);
-
-		remote_uri = g_strconcat (base_uri, "/", partial_filename, NULL);
-		sources = g_list_append (sources, g_file_new_for_uri (remote_uri));
-		g_free (remote_uri);
-
-		destinations = g_list_append (destinations, g_file_new_for_uri (local_uri));
-		g_free (local_uri);
-	}
-	g_hash_table_destroy (created_folders);
-
-	xfer_data = g_new0 (XferData, 1);
-	xfer_data->archive = archive;
-	xfer_data->file_list = _g_string_list_dup (file_list);
-	xfer_data->base_uri = g_strdup (base_uri);
-	xfer_data->dest_dir = g_strdup (dest_dir);
-	xfer_data->update = update;
-	xfer_data->dest_dir = g_strdup (dest_dir);
-	xfer_data->password = g_strdup (password);
-	xfer_data->encrypt_header = encrypt_header;
-	xfer_data->compression = compression;
-	xfer_data->volume_size = volume_size;
-	xfer_data->tmp_dir = g_strdup (tmp_dir);
-
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[START],
-		       0,
-		       FR_ACTION_COPYING_FILES_FROM_REMOTE);
-
-	g_copy_files_async (sources,
-			    destinations,
-			    G_FILE_COPY_OVERWRITE,
-			    G_PRIORITY_DEFAULT,
-			    archive->priv->cancellable,
-			    copy_remote_files_progress,
-			    xfer_data,
-			    copy_remote_files_done,
-			    xfer_data);
-
-	_g_file_list_free (sources);
-	_g_file_list_free (destinations);
-}
-
-
-static char *
-fr_archive_get_temp_work_dir (FrArchive *archive)
-{
-	fr_archive_remove_temp_work_dir (archive);
-	archive->priv->temp_dir = _g_path_get_temp_work_dir (NULL);
-	return archive->priv->temp_dir;
-}
-
-
-void
-fr_archive_add_files (FrArchive     *archive,
-		      GList         *file_list,
-		      const char    *base_dir,
-		      const char    *dest_dir,
-		      gboolean       update,
-		      const char    *password,
-		      gboolean       encrypt_header,
-		      FrCompression  compression,
-		      guint          volume_size)
-{
-	if (_g_uri_is_local (base_dir)) {
-		char *local_dir = g_filename_from_uri (base_dir, NULL, NULL);
-		fr_archive_add_local_files (archive,
-					    file_list,
-					    local_dir,
-					    dest_dir,
-					    update,
-					    password,
-					    encrypt_header,
-					    compression,
-					    volume_size);
-		g_free (local_dir);
-	}
-	else
-		copy_remote_files (archive,
-				   file_list,
-				   base_dir,
-				   dest_dir,
-				   update,
-				   password,
-				   encrypt_header,
-				   compression,
-				   volume_size,
-				   fr_archive_get_temp_work_dir (archive));
-}
-
-
-/* -- add with wildcard -- */
-
-
-typedef struct {
-	FrArchive     *archive;
-	char          *source_dir;
-	char          *dest_dir;
-	gboolean       update;
-	char          *password;
-	gboolean       encrypt_header;
-	FrCompression  compression;
-	guint          volume_size;
-} AddWithWildcardData;
-
-
-static void
-add_with_wildcard_data_free (AddWithWildcardData *aww_data)
-{
-	g_free (aww_data->source_dir);
-	g_free (aww_data->dest_dir);
-	g_free (aww_data->password);
-	g_free (aww_data);
-}
-
-
-static void
-add_with_wildcard__step2 (GList    *file_list,
-			  GList    *dirs_list,
-			  GError   *error,
-			  gpointer  data)
-{
-	AddWithWildcardData *aww_data = data;
-	FrArchive           *archive = aww_data->archive;
-
-	if (error != NULL) {
-		fr_archive_action_completed (archive,
-					     FR_ACTION_GETTING_FILE_LIST,
-					     (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ? FR_PROC_ERROR_STOPPED : FR_PROC_ERROR_GENERIC),
-					     error->message);
-		return;
-	}
-
-	fr_archive_action_completed (archive,
-				     FR_ACTION_GETTING_FILE_LIST,
-				     FR_PROC_ERROR_NONE,
-				     NULL);
-
-	if (file_list != NULL)
-		fr_archive_add_files (aww_data->archive,
-				      file_list,
-				      aww_data->source_dir,
-				      aww_data->dest_dir,
-				      aww_data->update,
-				      aww_data->password,
-				      aww_data->encrypt_header,
-				      aww_data->compression,
-				      aww_data->volume_size);
-
-	_g_string_list_free (file_list);
-	_g_string_list_free (dirs_list);
-	add_with_wildcard_data_free (aww_data);
-}
-
-
-void
-fr_archive_add_with_wildcard (FrArchive     *archive,
-			      const char    *include_files,
-			      const char    *exclude_files,
-			      const char    *exclude_folders,
-			      const char    *source_dir,
-			      const char    *dest_dir,
-			      gboolean       update,
-			      gboolean       follow_links,
-			      const char    *password,
-			      gboolean       encrypt_header,
-			      FrCompression  compression,
-			      guint          volume_size)
-{
-	AddWithWildcardData *aww_data;
-
-	g_return_if_fail (! archive->read_only);
-
-	aww_data = g_new0 (AddWithWildcardData, 1);
-	aww_data->archive = archive;
-	aww_data->source_dir = g_strdup (source_dir);
-	aww_data->dest_dir = g_strdup (dest_dir);
-	aww_data->update = update;
-	aww_data->password = g_strdup (password);
-	aww_data->encrypt_header = encrypt_header;
-	aww_data->compression = compression;
-	aww_data->volume_size = volume_size;
-
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[START],
-		       0,
-		       FR_ACTION_GETTING_FILE_LIST);
-
-	g_directory_list_async (source_dir,
-				source_dir,
-				TRUE,
-				follow_links,
-				NO_BACKUP_FILES,
-				NO_DOT_FILES,
-				include_files,
-				exclude_files,
-				exclude_folders,
-				IGNORE_CASE,
-				archive->priv->cancellable,
-				add_with_wildcard__step2,
-				aww_data);
-}
-
-
-/* -- fr_archive_add_directory -- */
-
-
-typedef struct {
-	FrArchive     *archive;
-	char          *base_dir;
-	char          *dest_dir;
-	gboolean       update;
-	char          *password;
-	gboolean       encrypt_header;
-	FrCompression  compression;
-	guint          volume_size;
-} AddDirectoryData;
-
-
-static void
-add_directory_data_free (AddDirectoryData *ad_data)
-{
-	g_free (ad_data->base_dir);
-	g_free (ad_data->dest_dir);
-	g_free (ad_data->password);
-	g_free (ad_data);
-}
-
-
-static void
-add_directory__step2 (GList    *file_list,
-		      GList    *dir_list,
-		      GError   *error,
-		      gpointer  data)
-{
-	AddDirectoryData *ad_data = data;
-	FrArchive        *archive = ad_data->archive;
-
-	if (error != NULL) {
-		fr_archive_action_completed (archive,
-					     FR_ACTION_GETTING_FILE_LIST,
-					     (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ? FR_PROC_ERROR_STOPPED : FR_PROC_ERROR_GENERIC),
-					     error->message);
-		return;
-	}
-
-	fr_archive_action_completed (archive,
-				     FR_ACTION_GETTING_FILE_LIST,
-				     FR_PROC_ERROR_NONE,
-				     NULL);
-
-	if (archive->command->propAddCanStoreFolders)
-		file_list = g_list_concat (file_list, dir_list);
-	else
-		_g_string_list_free (dir_list);
-
-	if (file_list != NULL) {
-		fr_archive_add_files (ad_data->archive,
-				      file_list,
-				      ad_data->base_dir,
-				      ad_data->dest_dir,
-				      ad_data->update,
-				      ad_data->password,
-				      ad_data->encrypt_header,
-				      ad_data->compression,
-				      ad_data->volume_size);
-		_g_string_list_free (file_list);
-	}
-
-	add_directory_data_free (ad_data);
-}
-
-
-void
-fr_archive_add_directory (FrArchive     *archive,
-			  const char    *directory,
-			  const char    *base_dir,
-			  const char    *dest_dir,
-			  gboolean       update,
-			  const char    *password,
-			  gboolean       encrypt_header,
-			  FrCompression  compression,
-			  guint          volume_size)
-
-{
-	AddDirectoryData *ad_data;
-
-	g_return_if_fail (! archive->read_only);
-
-	ad_data = g_new0 (AddDirectoryData, 1);
-	ad_data->archive = archive;
-	ad_data->base_dir = g_strdup (base_dir);
-	ad_data->dest_dir = g_strdup (dest_dir);
-	ad_data->update = update;
-	ad_data->password = g_strdup (password);
-	ad_data->encrypt_header = encrypt_header;
-	ad_data->compression = compression;
-	ad_data->volume_size = volume_size;
-
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[START],
-		       0,
-		       FR_ACTION_GETTING_FILE_LIST);
-
-	g_directory_list_all_async (directory,
-				    base_dir,
-				    TRUE,
-				    archive->priv->cancellable,
-				    add_directory__step2,
-				    ad_data);
-}
-
-
-void
-fr_archive_add_items (FrArchive     *archive,
-		      GList         *item_list,
-		      const char    *base_dir,
-		      const char    *dest_dir,
-		      gboolean       update,
-		      const char    *password,
-		      gboolean       encrypt_header,
-		      FrCompression  compression,
-		      guint          volume_size)
-
-{
-	AddDirectoryData *ad_data;
-
-	g_return_if_fail (! archive->read_only);
-
-	ad_data = g_new0 (AddDirectoryData, 1);
-	ad_data->archive = archive;
-	ad_data->base_dir = g_strdup (base_dir);
-	ad_data->dest_dir = g_strdup (dest_dir);
-	ad_data->update = update;
-	ad_data->password = g_strdup (password);
-	ad_data->encrypt_header = encrypt_header;
-	ad_data->compression = compression;
-	ad_data->volume_size = volume_size;
-
-	g_signal_emit (G_OBJECT (archive),
-		       fr_archive_signals[START],
-		       0,
-		       FR_ACTION_GETTING_FILE_LIST);
-
-	g_list_items_async (item_list,
-			    base_dir,
-			    archive->priv->cancellable,
-			    add_directory__step2,
-			    ad_data);
-}
-
-
-/* -- fr_archive_add_dropped_items -- */
-
-
-static gboolean
-all_files_in_same_dir (GList *list)
-{
-	gboolean  same_dir = TRUE;
-	char     *first_basedir;
-	GList    *scan;
-
-	if (list == NULL)
-		return FALSE;
-
-	first_basedir = _g_path_remove_level (list->data);
-	if (first_basedir == NULL)
-		return TRUE;
-
-	for (scan = list->next; scan; scan = scan->next) {
-		char *path = scan->data;
-		char *basedir;
-
-		basedir = _g_path_remove_level (path);
-		if (basedir == NULL) {
-			same_dir = FALSE;
-			break;
-		}
-
-		if (strcmp (first_basedir, basedir) != 0) {
-			same_dir = FALSE;
-			g_free (basedir);
-			break;
-		}
-		g_free (basedir);
-	}
-	g_free (first_basedir);
-
-	return same_dir;
-}
-
-
-static void
-add_dropped_items (DroppedItemsData *data)
-{
-	FrArchive *archive = data->archive;
-	GList     *list = data->item_list;
-	GList     *scan;
-
-	if (list == NULL) {
-		dropped_items_data_free (archive->priv->dropped_items_data);
-		archive->priv->dropped_items_data = NULL;
-		fr_archive_action_completed (archive,
-					     FR_ACTION_ADDING_FILES,
-					     FR_PROC_ERROR_NONE,
-					     NULL);
-		return;
-	}
-
-	/* if all files/dirs are in the same directory call fr_archive_add_items... */
-
-	if (all_files_in_same_dir (list)) {
-		char *first_base_dir;
-
-		first_base_dir = _g_path_remove_level (list->data);
-		fr_archive_add_items (data->archive,
-				      list,
-				      first_base_dir,
-				      data->dest_dir,
-				      data->update,
-				      data->password,
-				      data->encrypt_header,
-				      data->compression,
-				      data->volume_size);
-		g_free (first_base_dir);
-
-		dropped_items_data_free (archive->priv->dropped_items_data);
-		archive->priv->dropped_items_data = NULL;
-
-		return;
-	}
-
-	/* ...else add a directory at a time. */
-
-	for (scan = list; scan; scan = scan->next) {
-		char *path = scan->data;
-		char *base_dir;
-
-		if (! _g_uri_query_is_dir (path))
-			continue;
-
-		data->item_list = g_list_remove_link (list, scan);
-		if (data->item_list != NULL)
-			archive->priv->continue_adding_dropped_items = TRUE;
-		base_dir = _g_path_remove_level (path);
-
-		fr_archive_add_directory (archive,
-					  _g_path_get_file_name (path),
-					  base_dir,
-					  data->dest_dir,
-					  data->update,
-					  data->password,
-					  data->encrypt_header,
-					  data->compression,
-					  data->volume_size);
-
-		g_free (base_dir);
-		g_free (path);
-
-		return;
-	}
-
-	/* if all files are in the same directory call fr_archive_add_files. */
-
-	if (all_files_in_same_dir (list)) {
-		char  *first_basedir;
-		GList *only_names_list = NULL;
-
-		first_basedir = _g_path_remove_level (list->data);
-
-		for (scan = list; scan; scan = scan->next) {
-			char *name;
-
-			name = g_uri_unescape_string (_g_path_get_file_name (scan->data), NULL);
-			only_names_list = g_list_prepend (only_names_list, name);
-		}
-
-		fr_archive_add_files (archive,
-				      only_names_list,
-				      first_basedir,
-				      data->dest_dir,
-				      data->update,
-				      data->password,
-				      data->encrypt_header,
-				      data->compression,
-				      data->volume_size);
-
-		_g_string_list_free (only_names_list);
-		g_free (first_basedir);
-
-		return;
-	}
-
-	/* ...else call fr_command_add for each file.  This is needed to add
-	 * files without path info. FIXME: doesn't work with remote files. */
-
-	fr_archive_stoppable (archive, FALSE);
-	archive->command->creating_archive = ! g_file_query_exists (archive->local_copy, archive->priv->cancellable);
-	g_object_set (archive->command,
-		      "file", archive->local_copy,
-		      "password", data->password,
-		      "encrypt_header", data->encrypt_header,
-		      "compression", data->compression,
-		      "volume_size", data->volume_size,
-		      NULL);
-	fr_process_clear (archive->process);
-	fr_command_uncompress (archive->command);
-	for (scan = list; scan; scan = scan->next) {
-		char  *fullpath = scan->data;
-		char  *basedir;
-		GList *singleton;
-
-		basedir = _g_path_remove_level (fullpath);
-		singleton = g_list_prepend (NULL, (char*)_g_path_get_file_name (fullpath));
-		fr_command_add (archive->command,
-				NULL,
-				singleton,
-				basedir,
-				data->update,
-				FALSE);
-		g_list_free (singleton);
-		g_free (basedir);
-	}
-	fr_command_recompress (archive->command);
-	fr_process_start (archive->process);
-
-	_g_string_list_free (data->item_list);
-	data->item_list = NULL;
-}
-
-
-void
-fr_archive_add_dropped_items (FrArchive     *archive,
-			      GList         *item_list,
-			      const char    *base_dir,
-			      const char    *dest_dir,
-			      gboolean       update,
-			      const char    *password,
-			      gboolean       encrypt_header,
-			      FrCompression  compression,
-			      guint          volume_size)
-{
-	GList *scan;
-	char  *archive_uri;
-
-	if (archive->read_only) {
-		fr_archive_action_completed (archive,
-					     FR_ACTION_ADDING_FILES,
-					     FR_PROC_ERROR_GENERIC,
-					     ! archive->have_permissions ? _("You don't have the right permissions.") : _("This archive type cannot be modified"));
-		return;
-	}
-
-	/* FIXME: make this check for all the add actions */
-	archive_uri = g_file_get_uri (archive->file);
-	for (scan = item_list; scan; scan = scan->next) {
-		if (_g_uri_cmp (scan->data, archive_uri) == 0) {
-			g_free (archive_uri);
-			fr_archive_action_completed (archive,
-						     FR_ACTION_ADDING_FILES,
-						     FR_PROC_ERROR_GENERIC,
-						     _("You can't add an archive to itself."));
-			return;
-		}
-	}
-	g_free (archive_uri);
-
-	if (archive->priv->dropped_items_data != NULL)
-		dropped_items_data_free (archive->priv->dropped_items_data);
-	archive->priv->dropped_items_data = dropped_items_data_new (
-						archive,
-				       		item_list,
-				       		base_dir,
-				       		dest_dir,
-				       		update,
-				       		password,
-				       		encrypt_header,
-				       		compression,
-				       		volume_size);
-	add_dropped_items (archive->priv->dropped_items_data);
-}
-
-
-/* -- remove -- */
-
-
-static gboolean
-file_is_in_subfolder_of (const char *filename,
-		         GList      *folder_list)
-{
-	GList *scan;
-
-	if (filename == NULL)
-		return FALSE;
-
-	for (scan = folder_list; scan; scan = scan->next) {
-		char *folder_in_list = (char*) scan->data;
-
-		if (_g_path_is_parent_of (folder_in_list, filename))
-			return TRUE;
-	}
-
-	return FALSE;
-}
-
-static gboolean
-archive_type_has_issues_deleting_non_empty_folders (FrArchive *archive)
-{
-       return ! archive->command->propCanDeleteNonEmptyFolders;
-}
-
-
-static void
-delete_from_archive (FrArchive *archive,
-		     GList     *file_list)
-{
-	gboolean  file_list_created = FALSE;
-	GList    *tmp_file_list = NULL;
-	gboolean  tmp_file_list_created = FALSE;
-	GList    *scan;
-
-	/* file_list == NULL means delete all the files in the archive. */
-
-	if (file_list == NULL) {
-		int i;
-
-		for (i = 0; i < archive->command->files->len; i++) {
-			FileData *fdata = g_ptr_array_index (archive->command->files, i);
-			file_list = g_list_prepend (file_list, fdata->original_path);
-		}
-
-		file_list_created = TRUE;
-	}
-
-	if (archive_type_has_issues_deleting_non_empty_folders (archive)) {
-		GList *folders_to_remove;
-
-		/* remove from the list the files contained in folders to be
-		 * removed. */
-
-		folders_to_remove = NULL;
-		for (scan = file_list; scan != NULL; scan = scan->next) {
-			char *path = scan->data;
-
-			if (path[strlen (path) - 1] == '/')
-				folders_to_remove = g_list_prepend (folders_to_remove, path);
-		}
-
-		if (folders_to_remove != NULL) {
-			tmp_file_list = NULL;
-			for (scan = file_list; scan != NULL; scan = scan->next) {
-				char *path = scan->data;
-
-				if (! file_is_in_subfolder_of (path, folders_to_remove))
-					tmp_file_list = g_list_prepend (tmp_file_list, path);
-			}
-			tmp_file_list_created = TRUE;
-			g_list_free (folders_to_remove);
-		}
-	}
-
-	if (! tmp_file_list_created)
-		tmp_file_list = g_list_copy (file_list);
-
-	if (file_list_created)
-		g_list_free (file_list);
-
-	fr_command_set_n_files (archive->command, g_list_length (tmp_file_list));
-
-	if (archive->command->propListFromFile
-	    && (archive->command->n_files > LIST_LENGTH_TO_USE_FILE))
-	{
-		char *list_dir;
-		char *list_filename;
-
-		if (save_list_to_temp_file (tmp_file_list, &list_dir, &list_filename, NULL)) {
-			fr_command_delete (archive->command,
-					   list_filename,
-					   tmp_file_list);
-
-			/* remove the temp dir */
-
-			fr_process_begin_command (archive->process, "rm");
-			fr_process_set_working_dir (archive->process, g_get_tmp_dir());
-			fr_process_set_sticky (archive->process, TRUE);
-			fr_process_add_arg (archive->process, "-rf");
-			fr_process_add_arg (archive->process, list_dir);
-			fr_process_end_command (archive->process);
-		}
-
-		g_free (list_filename);
-		g_free (list_dir);
-	}
-	else {
-		for (scan = tmp_file_list; scan != NULL; ) {
-			GList *prev = scan->prev;
-			GList *chunk_list;
-			int    l;
-
-			chunk_list = scan;
-			l = 0;
-			while ((scan != NULL) && (l < MAX_CHUNK_LEN)) {
-				if (l == 0)
-					l = strlen (scan->data);
-				prev = scan;
-				scan = scan->next;
-				if (scan != NULL)
-					l += strlen (scan->data);
-			}
-
-			prev->next = NULL;
-			fr_command_delete (archive->command, NULL, chunk_list);
-			prev->next = scan;
-		}
-	}
-
-	g_list_free (tmp_file_list);
-}
-
-
-void
-fr_archive_remove (FrArchive     *archive,
-		   GList         *file_list,
-		   FrCompression  compression)
-{
-	char *tmp_archive_dir = NULL;
-	char *archive_filename = NULL;
-	char *tmp_archive_filename = NULL;
-
-	g_return_if_fail (archive != NULL);
-
-	if (archive->read_only)
-		return;
-
-	fr_archive_stoppable (archive, TRUE);
-	archive->command->creating_archive = FALSE;
-	g_object_set (archive->command, "compression", compression, NULL);
-
-	/* create the new archive in a temporary sub-directory, this allows
-	 * to cancel the operation without losing the original archive and
-	 * removing possible temporary files created by the command. */
-
-	{
-		GFile *local_copy_parent;
-		char  *archive_dir;
-		GFile *tmp_file;
-
-		/* create the new archive in a sub-folder of the original
-		 * archive this way the 'mv' command is fast. */
-
-		local_copy_parent = g_file_get_parent (archive->local_copy);
-		archive_dir = g_file_get_path (local_copy_parent);
-		tmp_archive_dir = _g_path_get_temp_work_dir (archive_dir);
-		archive_filename = g_file_get_path (archive->local_copy);
-		tmp_archive_filename = g_build_filename (tmp_archive_dir, _g_path_get_file_name (archive_filename), NULL);
-		tmp_file = g_file_new_for_path (tmp_archive_filename);
-		g_object_set (archive->command, "file", tmp_file, NULL);
-
-		if (! archive->command->creating_archive) {
-			/* copy the original archive to the new position */
-
-			fr_process_begin_command (archive->process, "cp");
-			fr_process_add_arg (archive->process, "-f");
-			fr_process_add_arg (archive->process, archive_filename);
-			fr_process_add_arg (archive->process, tmp_archive_filename);
-			fr_process_end_command (archive->process);
-		}
-
-		g_object_unref (tmp_file);
-		g_free (archive_dir);
-		g_object_unref (local_copy_parent);
-	}
-
-	/* uncompress, delete and recompress */
-
-	fr_command_uncompress (archive->command);
-	delete_from_archive (archive, file_list);
-	fr_command_recompress (archive->command);
-
-	/* move the new archive to the original position */
-
-	fr_process_begin_command (archive->process, "mv");
-	fr_process_add_arg (archive->process, "-f");
-	fr_process_add_arg (archive->process, tmp_archive_filename);
-	fr_process_add_arg (archive->process, archive_filename);
-	fr_process_end_command (archive->process);
-
-	/* remove the temp sub-directory */
-
-	fr_process_begin_command (archive->process, "rm");
-	fr_process_set_working_dir (archive->process, g_get_tmp_dir());
-	fr_process_set_sticky (archive->process, TRUE);
-	fr_process_add_arg (archive->process, "-rf");
-	fr_process_add_arg (archive->process, tmp_archive_dir);
-	fr_process_end_command (archive->process);
-
-	g_free (tmp_archive_filename);
-	g_free (archive_filename);
-	g_free (tmp_archive_dir);
-}
-
-
-/* -- extract -- */
-
-
-static void
-move_files_to_dir (FrArchive  *archive,
-		   GList      *file_list,
-		   const char *source_dir,
-		   const char *dest_dir,
-		   gboolean    overwrite)
-{
-	GList *list;
-	GList *scan;
-
-	/* we prefer mv instead of cp for performance reasons,
-	 * but if the destination folder already exists mv
-	 * doesn't work correctly. (bug #590027) */
-
-	list = g_list_copy (file_list);
-	for (scan = list; scan; /* void */) {
-		GList *next = scan->next;
-		char  *filename = scan->data;
-		char  *basename;
-		char  *destname;
-
-		basename = g_path_get_basename (filename);
-		destname = g_build_filename (dest_dir, basename, NULL);
-		if (g_file_test (destname, G_FILE_TEST_IS_DIR)) {
-			fr_process_begin_command (archive->process, "cp");
-			fr_process_add_arg (archive->process, "-R");
-			if (overwrite)
-				fr_process_add_arg (archive->process, "-f");
-			else
-				fr_process_add_arg (archive->process, "-n");
-			if (filename[0] == '/')
-				fr_process_add_arg_concat (archive->process, source_dir, filename, NULL);
-			else
-				fr_process_add_arg_concat (archive->process, source_dir, "/", filename, NULL);
-			fr_process_add_arg (archive->process, dest_dir);
-			fr_process_end_command (archive->process);
-
-			list = g_list_remove_link (list, scan);
-			g_list_free (scan);
-		}
-
-		g_free (destname);
-		g_free (basename);
-
-		scan = next;
-	}
-
-	if (list == NULL)
-		return;
-
-	/* 'list' now contains the files that can be moved without problems */
-
-	fr_process_begin_command (archive->process, "mv");
-	if (overwrite)
-		fr_process_add_arg (archive->process, "-f");
-	else
-		fr_process_add_arg (archive->process, "-n");
-	for (scan = list; scan; scan = scan->next) {
-		char *filename = scan->data;
-
-		if (filename[0] == '/')
-			fr_process_add_arg_concat (archive->process, source_dir, filename, NULL);
-		else
-			fr_process_add_arg_concat (archive->process, source_dir, "/", filename, NULL);
-	}
-	fr_process_add_arg (archive->process, dest_dir);
-	fr_process_end_command (archive->process);
-
-	g_list_free (list);
-}
+typedef struct {
+	FrArchive           *archive;
+	char                *source_dir;
+	char                *dest_dir;
+	gboolean             update;
+	char                *password;
+	gboolean             encrypt_header;
+	FrCompression        compression;
+	guint                volume_size;
+	GCancellable        *cancellable;
+	GAsyncReadyCallback  callback;
+	gpointer             user_data;
+} AddWithWildcardData;
 
 
 static void
-move_files_in_chunks (FrArchive  *archive,
-		      GList      *file_list,
-		      const char *temp_dir,
-		      const char *dest_dir,
-		      gboolean    overwrite)
+add_with_wildcard_data_free (AddWithWildcardData *aww_data)
 {
-	GList *scan;
-	int    temp_dir_l;
-
-	temp_dir_l = strlen (temp_dir);
-
-	for (scan = file_list; scan != NULL; ) {
-		GList *prev = scan->prev;
-		GList *chunk_list;
-		int    l;
-
-		chunk_list = scan;
-		l = 0;
-		while ((scan != NULL) && (l < MAX_CHUNK_LEN)) {
-			if (l == 0)
-				l = temp_dir_l + 1 + strlen (scan->data);
-			prev = scan;
-			scan = scan->next;
-			if (scan != NULL)
-				l += temp_dir_l + 1 + strlen (scan->data);
-		}
-
-		prev->next = NULL;
-		move_files_to_dir (archive, chunk_list, temp_dir, dest_dir, overwrite);
-		prev->next = scan;
-	}
+	g_free (aww_data->source_dir);
+	g_free (aww_data->dest_dir);
+	g_free (aww_data->password);
+	_g_object_unref (aww_data->cancellable);
+	g_free (aww_data);
 }
 
 
 static void
-extract_from_archive (FrArchive  *archive,
-		      GList      *file_list,
-		      const char *dest_dir,
-		      gboolean    overwrite,
-		      gboolean    skip_older,
-		      gboolean    junk_paths,
-		      const char *password)
-{
-	FrCommand *command = archive->command;
-	GList     *scan;
-
-	g_object_set (command, "password", password, NULL);
-
-	if (file_list == NULL) {
-		fr_command_extract (command,
-				    NULL,
-				    file_list,
-				    dest_dir,
-				    overwrite,
-				    skip_older,
-				    junk_paths);
-		return;
-	}
-
-	if (command->propListFromFile
-	    && (g_list_length (file_list) > LIST_LENGTH_TO_USE_FILE))
-	{
-		char *list_dir;
-		char *list_filename;
-
-		if (save_list_to_temp_file (file_list, &list_dir, &list_filename, NULL)) {
-			fr_command_extract (command,
-					    list_filename,
-					    file_list,
-					    dest_dir,
-					    overwrite,
-					    skip_older,
-					    junk_paths);
-
-			/* remove the temp dir */
-
-			fr_process_begin_command (archive->process, "rm");
-			fr_process_set_working_dir (archive->process, g_get_tmp_dir());
-			fr_process_set_sticky (archive->process, TRUE);
-			fr_process_add_arg (archive->process, "-rf");
-			fr_process_add_arg (archive->process, list_dir);
-			fr_process_end_command (archive->process);
-		}
-
-		g_free (list_filename);
-		g_free (list_dir);
-	}
-	else {
-		for (scan = file_list; scan != NULL; ) {
-			GList *prev = scan->prev;
-			GList *chunk_list;
-			int    l;
-
-			chunk_list = scan;
-			l = 0;
-			while ((scan != NULL) && (l < MAX_CHUNK_LEN)) {
-				if (l == 0)
-					l = strlen (scan->data);
-				prev = scan;
-				scan = scan->next;
-				if (scan != NULL)
-					l += strlen (scan->data);
-			}
-
-			prev->next = NULL;
-			fr_command_extract (command,
-					    NULL,
-					    chunk_list,
-					    dest_dir,
-					    overwrite,
-					    skip_older,
-					    junk_paths);
-			prev->next = scan;
-		}
-	}
-}
-
-
-static char*
-compute_base_path (const char *base_dir,
-		   const char *path,
-		   gboolean    junk_paths,
-		   gboolean    can_junk_paths)
+add_with_wildcard__step2 (GList    *file_list,
+			  GList    *dirs_list,
+			  GError   *error,
+			  gpointer  data)
 {
-	int         base_dir_len = strlen (base_dir);
-	int         path_len = strlen (path);
-	const char *base_path;
-	char       *name_end;
-	char       *new_path;
-
-	if (junk_paths) {
-		if (can_junk_paths)
-			new_path = g_strdup (_g_path_get_file_name (path));
-		else
-			new_path = g_strdup (path);
+	AddWithWildcardData *aww_data = data;
+	FrArchive           *archive = aww_data->archive;
+	GSimpleAsyncResult  *result;
 
-		/*debug (DEBUG_INFO, "%s, %s --> %s\n", base_dir, path, new_path);*/
+	result = g_simple_async_result_new (G_OBJECT (archive),
+					    aww_data->callback,
+					    aww_data->user_data,
+					    fr_archive_add_with_wildcard);
 
-		return new_path;
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (result, error);
+		g_simple_async_result_complete_in_idle (result);
 	}
-
-	if (path_len <= base_dir_len)
-		return NULL;
-
-	base_path = path + base_dir_len;
-	if (path[0] != '/')
-		base_path -= 1;
-	name_end = strchr (base_path, '/');
-
-	if (name_end == NULL)
-		new_path = g_strdup (path);
 	else {
-		int name_len = name_end - path;
-		new_path = g_strndup (path, name_len);
-	}
-
-	/*debug (DEBUG_INFO, "%s, %s --> %s\n", base_dir, path, new_path);*/
-
-	return new_path;
-}
-
-
-static GList*
-compute_list_base_path (const char *base_dir,
-			GList      *filtered,
-			gboolean    junk_paths,
-			gboolean    can_junk_paths)
-{
-	GList *scan;
-	GList *list = NULL, *list_unique = NULL;
-	GList *last_inserted;
-
-	if (filtered == NULL)
-		return NULL;
-
-	for (scan = filtered; scan; scan = scan->next) {
-		const char *path = scan->data;
-		char       *new_path;
-
-		new_path = compute_base_path (base_dir, path, junk_paths, can_junk_paths);
-		if (new_path != NULL)
-			list = g_list_prepend (list, new_path);
-	}
-
-	/* The above operation can create duplicates, we remove them here. */
-	list = g_list_sort (list, (GCompareFunc)strcmp);
-
-	last_inserted = NULL;
-	for (scan = list; scan; scan = scan->next) {
-		const char *path = scan->data;
-
-		if (last_inserted != NULL) {
-			const char *last_path = (const char*)last_inserted->data;
-			if (strcmp (last_path, path) == 0) {
-				g_free (scan->data);
-				continue;
-			}
-		}
-
-		last_inserted = scan;
-		list_unique = g_list_prepend (list_unique, scan->data);
-	}
-
-	g_list_free (list);
-
-	return list_unique;
-}
-
-
-static gboolean
-archive_type_has_issues_extracting_non_empty_folders (FrArchive *archive)
-{
-	/*if ((archive->command->files == NULL) || (archive->command->files->len == 0))
-		return FALSE;  FIXME: test with extract_here */
-	return ! archive->command->propCanExtractNonEmptyFolders;
-}
-
-
-static gboolean
-file_list_contains_files_in_this_dir (GList      *file_list,
-				      const char *dirname)
-{
-	GList *scan;
-
-	for (scan = file_list; scan; scan = scan->next) {
-		char *filename = scan->data;
-
-		if (_g_path_is_parent_of (dirname, filename))
-			return TRUE;
-	}
-
-	return FALSE;
-}
-
-
-static GList*
-remove_files_contained_in_this_dir (GList *file_list,
-				    GList *dir_pointer)
-{
-	char  *dirname = dir_pointer->data;
-	int    dirname_l = strlen (dirname);
-	GList *scan;
-
-	for (scan = dir_pointer->next; scan; /* empty */) {
-		char *filename = scan->data;
-
-		if (strncmp (dirname, filename, dirname_l) != 0)
-			break;
-
-		if (_g_path_is_parent_of (dirname, filename)) {
-			GList *next = scan->next;
-
-			file_list = g_list_remove_link (file_list, scan);
-			g_list_free (scan);
-
-			scan = next;
-		}
+		if (file_list == NULL)
+			g_simple_async_result_complete_in_idle (result);
 		else
-			scan = scan->next;
-	}
-
-	return file_list;
+			fr_archive_add_files (aww_data->archive,
+					      file_list,
+					      aww_data->source_dir,
+					      aww_data->dest_dir,
+					      aww_data->update,
+					      FALSE,
+					      aww_data->password,
+					      aww_data->encrypt_header,
+					      aww_data->compression,
+					      aww_data->volume_size,
+					      aww_data->cancellable,
+					      aww_data->callback,
+					      aww_data->user_data);
+	}
+
+	g_object_unref (result);
+	_g_string_list_free (file_list);
+	_g_string_list_free (dirs_list);
+	add_with_wildcard_data_free (aww_data);
 }
 
 
 void
-fr_archive_extract_to_local (FrArchive  *archive,
-			     GList      *file_list,
-			     const char *destination,
-			     const char *base_dir,
-			     gboolean    skip_older,
-			     gboolean    overwrite,
-			     gboolean    junk_paths,
-			     const char *password)
+fr_archive_add_with_wildcard (FrArchive           *archive,
+			      const char          *include_files,
+			      const char          *exclude_files,
+			      const char          *exclude_folders,
+			      const char          *source_dir,
+			      const char          *dest_dir,
+			      gboolean             update,
+			      gboolean             follow_links,
+			      const char          *password,
+			      gboolean             encrypt_header,
+			      FrCompression        compression,
+			      guint                volume_size,
+			      GCancellable        *cancellable,
+			      GAsyncReadyCallback  callback,
+			      gpointer             user_data)
 {
-	GList    *filtered;
-	GList    *scan;
-	gboolean  extract_all;
-	gboolean  use_base_dir;
-	gboolean  all_options_supported;
-	gboolean  move_to_dest_dir;
-	gboolean  file_list_created = FALSE;
+	AddWithWildcardData *aww_data;
 
-	g_return_if_fail (archive != NULL);
+	g_return_if_fail (! archive->read_only);
 
-	fr_archive_stoppable (archive, TRUE);
-	g_object_set (archive->command, "file", archive->local_copy, NULL);
+	aww_data = g_new0 (AddWithWildcardData, 1);
+	aww_data->archive = archive;
+	aww_data->source_dir = g_strdup (source_dir);
+	aww_data->dest_dir = g_strdup (dest_dir);
+	aww_data->update = update;
+	aww_data->password = g_strdup (password);
+	aww_data->encrypt_header = encrypt_header;
+	aww_data->compression = compression;
+	aww_data->volume_size = volume_size;
+	aww_data->cancellable = _g_object_ref (cancellable);
+	aww_data->callback = callback;
+	aww_data->user_data = user_data;
 
-	/* if a command supports all the requested options use
-	 * fr_command_extract directly. */
+	g_signal_emit (G_OBJECT (archive),
+		       fr_archive_signals[START],
+		       0,
+		       FR_ACTION_GETTING_FILE_LIST);
 
-	use_base_dir = ! ((base_dir == NULL)
-			  || (strcmp (base_dir, "") == 0)
-			  || (strcmp (base_dir, "/") == 0));
+	g_directory_list_async (source_dir,
+				source_dir,
+				TRUE,
+				follow_links,
+				NO_BACKUP_FILES,
+				NO_DOT_FILES,
+				include_files,
+				exclude_files,
+				exclude_folders,
+				IGNORE_CASE,
+				aww_data->cancellable,
+				add_with_wildcard__step2,
+				aww_data);
+}
 
-	all_options_supported = (! use_base_dir
-				 && ! (! overwrite && ! archive->command->propExtractCanAvoidOverwrite)
-				 && ! (skip_older && ! archive->command->propExtractCanSkipOlder)
-				 && ! (junk_paths && ! archive->command->propExtractCanJunkPaths));
 
-	extract_all = (file_list == NULL);
-	if (extract_all && (! all_options_supported || ! archive->command->propCanExtractAll)) {
-		int i;
+/* -- fr_archive_add_directory -- */
 
-		file_list = NULL;
-		for (i = 0; i < archive->command->files->len; i++) {
-			FileData *fdata = g_ptr_array_index (archive->command->files, i);
-			file_list = g_list_prepend (file_list, g_strdup (fdata->original_path));
-		}
-		file_list_created = TRUE;
-	}
 
-	if (extract_all && (file_list == NULL))
-		fr_command_set_n_files (archive->command, archive->command->n_regular_files);
-	else
-		fr_command_set_n_files (archive->command, g_list_length (file_list));
+typedef struct {
+	FrArchive           *archive;
+	char                *base_dir;
+	char                *dest_dir;
+	gboolean             update;
+	char                *password;
+	gboolean             encrypt_header;
+	FrCompression        compression;
+	guint                volume_size;
+	GCancellable        *cancellable;
+	GAsyncReadyCallback  callback;
+	gpointer             user_data;
+} AddDirectoryData;
 
-	if (all_options_supported) {
-		gboolean created_filtered_list = FALSE;
 
-		if (! extract_all && archive_type_has_issues_extracting_non_empty_folders (archive)) {
-			created_filtered_list = TRUE;
-			filtered = g_list_copy (file_list);
-			filtered = g_list_sort (filtered, (GCompareFunc) strcmp);
-			for (scan = filtered; scan; scan = scan->next)
-				filtered = remove_files_contained_in_this_dir (filtered, scan);
-		}
-		else
-			filtered = file_list;
+static void
+add_directory_data_free (AddDirectoryData *ad_data)
+{
+	g_free (ad_data->base_dir);
+	g_free (ad_data->dest_dir);
+	g_free (ad_data->password);
+	_g_object_unref (ad_data->cancellable);
+	g_free (ad_data);
+}
 
-		if (! (created_filtered_list && (filtered == NULL)))
-			extract_from_archive (archive,
-					      filtered,
-					      destination,
-					      overwrite,
-					      skip_older,
-					      junk_paths,
-					      password);
 
-		if (created_filtered_list && (filtered != NULL))
-			g_list_free (filtered);
+static void
+add_directory__step2 (GList    *file_list,
+		      GList    *dir_list,
+		      GError   *error,
+		      gpointer  user_data)
+{
+	AddDirectoryData   *ad_data = user_data;
+	FrArchive          *archive = ad_data->archive;
+	GSimpleAsyncResult *result;
 
-		if (file_list_created)
-			_g_string_list_free (file_list);
+	result = g_simple_async_result_new (G_OBJECT (archive),
+					    ad_data->callback,
+					    ad_data->user_data,
+					    fr_archive_add_directory);
 
-		return;
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (result, error);
+		g_simple_async_result_complete_in_idle (result);
 	}
+	else {
+		if (archive->propAddCanStoreFolders)
+			file_list = g_list_concat (file_list, dir_list);
+		else
+			_g_string_list_free (dir_list);
 
-	/* .. else we have to implement the unsupported options. */
+		if (file_list == NULL)
+			g_simple_async_result_complete_in_idle (result);
+		else
+			fr_archive_add_files (ad_data->archive,
+					      file_list,
+					      ad_data->base_dir,
+					      ad_data->dest_dir,
+					      ad_data->update,
+					      FALSE,
+					      ad_data->password,
+					      ad_data->encrypt_header,
+					      ad_data->compression,
+					      ad_data->volume_size,
+					      ad_data->cancellable,
+					      ad_data->callback,
+					      ad_data->user_data);
+	}
+
+	g_object_unref (result);
+	_g_string_list_free (file_list);
+	_g_string_list_free (dir_list);
+	add_directory_data_free (ad_data);
+}
 
-	move_to_dest_dir = (use_base_dir
-			    || ((junk_paths
-				 && ! archive->command->propExtractCanJunkPaths)));
 
-	if (extract_all && ! file_list_created) {
-		int i;
+void
+fr_archive_add_directory (FrArchive           *archive,
+			  const char          *directory,
+			  const char          *base_dir,
+			  const char          *dest_dir,
+			  gboolean             update,
+			  const char          *password,
+			  gboolean             encrypt_header,
+			  FrCompression        compression,
+			  guint                volume_size,
+			  GCancellable        *cancellable,
+			  GAsyncReadyCallback  callback,
+			  gpointer             user_data)
 
-		file_list = NULL;
-		for (i = 0; i < archive->command->files->len; i++) {
-			FileData *fdata = g_ptr_array_index (archive->command->files, i);
-			file_list = g_list_prepend (file_list, g_strdup (fdata->original_path));
-		}
+{
+	AddDirectoryData *ad_data;
 
-		file_list_created = TRUE;
-	}
+	g_return_if_fail (! archive->read_only);
 
-	filtered = NULL;
-	for (scan = file_list; scan; scan = scan->next) {
-		FileData   *fdata;
-		char       *archive_list_filename = scan->data;
-		char        dest_filename[4096];
-		const char *filename;
+	ad_data = g_new0 (AddDirectoryData, 1);
+	ad_data->archive = archive;
+	ad_data->base_dir = g_strdup (base_dir);
+	ad_data->dest_dir = g_strdup (dest_dir);
+	ad_data->update = update;
+	ad_data->password = g_strdup (password);
+	ad_data->encrypt_header = encrypt_header;
+	ad_data->compression = compression;
+	ad_data->volume_size = volume_size;
+	ad_data->cancellable = _g_object_ref (cancellable);
+	ad_data->callback = callback;
+	ad_data->user_data = user_data;
 
-		fdata = find_file_in_archive (archive, archive_list_filename);
+	g_signal_emit (G_OBJECT (archive),
+		       fr_archive_signals[START],
+		       0,
+		       FR_ACTION_GETTING_FILE_LIST);
 
-		if (fdata == NULL)
-			continue;
+	g_directory_list_all_async (directory,
+				    base_dir,
+				    TRUE,
+				    cancellable,
+				    add_directory__step2,
+				    ad_data);
+}
 
-		if (archive_type_has_issues_extracting_non_empty_folders (archive)
-		    && fdata->dir
-		    && file_list_contains_files_in_this_dir (file_list, archive_list_filename))
-			continue;
 
-		/* get the destination file path. */
+void
+fr_archive_add_items (FrArchive           *archive,
+		      GList               *item_list,
+		      const char          *base_dir,
+		      const char          *dest_dir,
+		      gboolean             update,
+		      const char          *password,
+		      gboolean             encrypt_header,
+		      FrCompression        compression,
+		      guint                volume_size,
+		      GCancellable        *cancellable,
+		      GAsyncReadyCallback  callback,
+		      gpointer             user_data)
 
-		if (! junk_paths)
-			filename = archive_list_filename;
-		else
-			filename = _g_path_get_file_name (archive_list_filename);
+{
+	AddDirectoryData *ad_data;
 
-		if ((destination[strlen (destination) - 1] == '/')
-		    || (filename[0] == '/'))
-			sprintf (dest_filename, "%s%s", destination, filename);
-		else
-			sprintf (dest_filename, "%s/%s", destination, filename);
+	g_return_if_fail (! archive->read_only);
 
-		/*debug (DEBUG_INFO, "-> %s\n", dest_filename);*/
+	ad_data = g_new0 (AddDirectoryData, 1);
+	ad_data->archive = archive;
+	ad_data->base_dir = g_strdup (base_dir);
+	ad_data->dest_dir = g_strdup (dest_dir);
+	ad_data->update = update;
+	ad_data->password = g_strdup (password);
+	ad_data->encrypt_header = encrypt_header;
+	ad_data->compression = compression;
+	ad_data->volume_size = volume_size;
+	ad_data->cancellable = _g_object_ref (cancellable);
+	ad_data->callback = callback;
+	ad_data->user_data = user_data;
 
-		/**/
+	g_signal_emit (G_OBJECT (archive),
+		       fr_archive_signals[START],
+		       0,
+		       FR_ACTION_GETTING_FILE_LIST);
 
-		if (! archive->command->propExtractCanSkipOlder
-		    && skip_older
-		    && g_file_test (dest_filename, G_FILE_TEST_EXISTS)
-		    && (fdata->modified < _g_path_get_file_mtime (dest_filename)))
-			continue;
+	g_list_items_async (item_list,
+			    base_dir,
+			    cancellable,
+			    add_directory__step2,
+			    ad_data);
+}
 
-		if (! archive->command->propExtractCanAvoidOverwrite
-		    && ! overwrite
-		    && g_file_test (dest_filename, G_FILE_TEST_EXISTS))
-			continue;
 
-		filtered = g_list_prepend (filtered, fdata->original_path);
-	}
+void
+fr_archive_remove (FrArchive           *archive,
+		   GList               *file_list,
+		   FrCompression        compression,
+		   GCancellable        *cancellable,
+		   GAsyncReadyCallback  callback,
+		   gpointer             user_data)
+{
+	g_return_if_fail (! archive->read_only);
 
-	if (filtered == NULL) {
-		/* all files got filtered, do nothing. */
-		debug (DEBUG_INFO, "All files got filtered, nothing to do.\n");
+	FR_ARCHIVE_GET_CLASS (archive)->remove_files (archive,
+						      file_list,
+						      compression,
+						      cancellable,
+						      callback,
+						      user_data);
+}
 
-		if (extract_all)
-			_g_string_list_free (file_list);
-		return;
-	}
 
-	if (move_to_dest_dir) {
-		char *temp_dir;
-
-		temp_dir = _g_path_get_temp_work_dir (destination);
-		extract_from_archive (archive,
-				      filtered,
-				      temp_dir,
-				      overwrite,
-				      skip_older,
-				      junk_paths,
-				      password);
-
-		if (use_base_dir) {
-			GList *tmp_list = compute_list_base_path (base_dir, filtered, junk_paths, archive->command->propExtractCanJunkPaths);
-			g_list_free (filtered);
-			filtered = tmp_list;
-		}
+void
+fr_archive_extract (FrArchive           *self,
+		    GList               *file_list,
+		    const char          *destination,
+		    const char          *base_dir,
+		    gboolean             skip_older,
+		    gboolean             overwrite,
+		    gboolean             junk_paths,
+		    const char          *password,
+		    GCancellable        *cancellable,
+		    GAsyncReadyCallback  callback,
+		    gpointer             user_data)
+{
+	g_free (self->priv->extraction_destination);
+	self->priv->extraction_destination = g_strdup (destination);
+
+	FR_ARCHIVE_GET_CLASS (self)->extract_files (self,
+						    file_list,
+						    destination,
+						    base_dir,
+						    skip_older,
+						    overwrite,
+						    junk_paths,
+						    password,
+						    cancellable,
+						    callback,
+						    user_data);
+}
 
-		move_files_in_chunks (archive,
-				      filtered,
-				      temp_dir,
-				      destination,
-				      overwrite);
 
-		/* remove the temp dir. */
+void
+fr_archive_extract_to_local (FrArchive           *self,
+			     GList               *file_list,
+			     const char          *destination_path,
+			     const char          *base_dir,
+			     gboolean             skip_older,
+			     gboolean             overwrite,
+			     gboolean             junk_paths,
+			     const char          *password,
+			     GCancellable        *cancellable,
+			     GAsyncReadyCallback  callback,
+			     gpointer             user_data)
+{
+	char *destination_uri;
+
+	destination_uri = g_filename_to_uri (destination_path, NULL, NULL);
+	if (destination_uri == NULL)
+		return;
 
-		fr_process_begin_command (archive->process, "rm");
-		fr_process_add_arg (archive->process, "-rf");
-		fr_process_add_arg (archive->process, temp_dir);
-		fr_process_end_command (archive->process);
+	fr_archive_extract (self,
+			    file_list,
+			    destination_uri,
+			    base_dir,
+			    skip_older,
+			    overwrite,
+			    junk_paths,
+			    password,
+			    cancellable,
+			    callback,
+			    user_data);
 
-		g_free (temp_dir);
-	}
-	else
-		extract_from_archive (archive,
-				      filtered,
-				      destination,
-				      overwrite,
-				      skip_older,
-				      junk_paths,
-				      password);
-
-	if (filtered != NULL)
-		g_list_free (filtered);
-	if (file_list_created)
-		_g_string_list_free (file_list);
+	g_free (destination_uri);
 }
 
 
-void
-fr_archive_extract (FrArchive  *archive,
-		    GList      *file_list,
-		    const char *destination,
-		    const char *base_dir,
-		    gboolean    skip_older,
-		    gboolean    overwrite,
-		    gboolean    junk_paths,
-		    const char *password)
-{
-	g_free (archive->priv->extraction_destination);
-	archive->priv->extraction_destination = g_strdup (destination);
-
-	g_free (archive->priv->temp_extraction_dir);
-	archive->priv->temp_extraction_dir = NULL;
-
-	archive->priv->remote_extraction = ! _g_uri_is_local (destination);
-	if (archive->priv->remote_extraction) {
-		archive->priv->temp_extraction_dir = _g_path_get_temp_work_dir (NULL);
-		fr_archive_extract_to_local (archive,
-					     file_list,
-					     archive->priv->temp_extraction_dir,
-					     base_dir,
-					     skip_older,
-					     overwrite,
-					     junk_paths,
-					     password);
-	}
-	else {
-		char *local_destination;
-
-		local_destination = g_filename_from_uri (destination, NULL, NULL);
-		fr_archive_extract_to_local (archive,
-					     file_list,
-					     local_destination,
-					     base_dir,
-					     skip_older,
-					     overwrite,
-					     junk_paths,
-					     password);
-		g_free (local_destination);
-	}
-}
+/* -- fr_archive_extract_here -- */
 
 
 static char *
@@ -3301,7 +1354,8 @@ get_extract_here_destination (GFile   *file,
 		g_object_unref (directory);
 
 		n++;
-	} while (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_EXISTS));
+	}
+	while (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_EXISTS));
 
 	g_free (desired_destination);
 
@@ -3316,26 +1370,35 @@ get_extract_here_destination (GFile   *file,
 
 
 gboolean
-fr_archive_extract_here (FrArchive  *archive,
-			 gboolean    skip_older,
-			 gboolean    overwrite,
-			 gboolean    junk_path,
-			 const char *password)
+fr_archive_extract_here (FrArchive           *archive,
+			 gboolean             skip_older,
+			 gboolean             overwrite,
+			 gboolean             junk_path,
+			 const char          *password,
+			 GCancellable        *cancellable,
+			 GAsyncReadyCallback  callback,
+			 gpointer             user_data)
 {
 	char   *destination;
 	GError *error = NULL;
 
-	destination = get_extract_here_destination (archive->file, &error);
+	destination = get_extract_here_destination (archive->priv->file, &error);
 	if (error != NULL) {
-		fr_archive_action_completed (archive,
-					     FR_ACTION_EXTRACTING_FILES,
-					     FR_PROC_ERROR_GENERIC,
-					     error->message);
-		g_clear_error (&error);
+		GSimpleAsyncResult *result;
+
+		result = g_simple_async_result_new (G_OBJECT (archive),
+						    callback,
+						    user_data,
+						    fr_archive_extract_here);
+		g_simple_async_result_set_from_error (result, error);
+		g_simple_async_result_complete_in_idle (result);
+
+		g_error_free (error);
+
 		return FALSE;
 	}
 
-	archive->priv->extract_here = TRUE;
+	archive->extract_here = TRUE;
 	fr_archive_extract (archive,
 			    NULL,
 			    destination,
@@ -3343,7 +1406,10 @@ fr_archive_extract_here (FrArchive  *archive,
 			    skip_older,
 			    overwrite,
 			    junk_path,
-			    password);
+			    password,
+			    cancellable,
+			    callback,
+			    user_data);
 
 	g_free (destination);
 
@@ -3351,6 +1417,20 @@ fr_archive_extract_here (FrArchive  *archive,
 }
 
 
+void
+fr_archive_set_last_extraction_destination (FrArchive  *archive,
+					    const char *uri)
+{
+	if (uri == archive->priv->extraction_destination)
+		return;
+
+	g_free (archive->priv->extraction_destination);
+	archive->priv->extraction_destination = NULL;
+	if (uri != NULL)
+		archive->priv->extraction_destination = g_strdup (uri);
+}
+
+
 const char *
 fr_archive_get_last_extraction_destination (FrArchive *archive)
 {
@@ -3359,33 +1439,287 @@ fr_archive_get_last_extraction_destination (FrArchive *archive)
 
 
 void
-fr_archive_test (FrArchive  *archive,
-		 const char *password)
+fr_archive_test (FrArchive           *archive,
+		 const char          *password,
+		 GCancellable        *cancellable,
+		 GAsyncReadyCallback  callback,
+		 gpointer             user_data)
+{
+	FR_ARCHIVE_GET_CLASS (archive)->test_integrity (archive,
+							password,
+							cancellable,
+							callback,
+							user_data);
+}
+
+
+void
+fr_archive_rename (FrArchive           *archive,
+		   GList               *file_list,
+		   const char          *old_name,
+		   const char          *new_name,
+		   const char          *current_dir,
+		   gboolean             is_dir,
+		   gboolean             dir_in_archive,
+		   const char          *original_path,
+		   GCancellable        *cancellable,
+		   GAsyncReadyCallback  callback,
+		   gpointer             user_data)
+{
+	FR_ARCHIVE_GET_CLASS (archive)->rename (archive,
+						file_list,
+						old_name,
+						new_name,
+						current_dir,
+						is_dir,
+						dir_in_archive,
+						original_path,
+						cancellable,
+						callback,
+						user_data);
+}
+
+
+void
+fr_archive_paste_clipboard (FrArchive           *archive,
+			    char                *archive_uri,
+			    char                *password,
+			    gboolean             encrypt_header,
+			    FrCompression        compression,
+			    guint                volume_size,
+			    FrClipboardOp        op,
+			    char                *base_dir,
+			    GList               *files,
+			    char                *tmp_dir,
+			    char                *current_dir,
+			    GCancellable        *cancellable,
+			    GAsyncReadyCallback  callback,
+			    gpointer             user_data)
+{
+	FR_ARCHIVE_GET_CLASS (archive)->paste_clipboard (archive,
+							 archive_uri,
+							 password,
+							 encrypt_header,
+							 compression,
+							 volume_size,
+							 op,
+							 base_dir,
+							 files,
+							 tmp_dir,
+							 current_dir,
+							 cancellable,
+							 callback,
+							 user_data);
+}
+
+
+void
+fr_archive_add_dropped_items (FrArchive           *archive,
+			      GList               *item_list,
+			      const char          *base_dir,
+			      const char          *dest_dir,
+			      gboolean             update,
+			      const char          *password,
+			      gboolean             encrypt_header,
+			      FrCompression        compression,
+			      guint                volume_size,
+			      GCancellable        *cancellable,
+			      GAsyncReadyCallback  callback,
+			      gpointer             user_data)
+{
+	GSimpleAsyncResult *result;
+	GList              *scan;
+	char               *archive_uri;
+
+	result = g_simple_async_result_new (G_OBJECT (archive),
+					    callback,
+					    user_data,
+					    fr_archive_add_dropped_items);
+
+	if (archive->read_only) {
+		GError *error;
+
+		error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, ! archive->priv->have_write_permissions ? _("You don't have the right permissions.") : _("This archive type cannot be modified"));
+		g_simple_async_result_set_from_error (result, error);
+		g_simple_async_result_complete_in_idle (result);
+
+		g_error_free (error);
+		return;
+	}
+
+	/* FIXME: make this check for all the add actions */
+	archive_uri = g_file_get_uri (archive->priv->file);
+	for (scan = item_list; scan; scan = scan->next) {
+		if (_g_uri_cmp (scan->data, archive_uri) == 0) {
+			GError *error;
+
+			error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, _("You can't add an archive to itself."));
+			g_simple_async_result_set_from_error (result, error);
+			g_simple_async_result_complete_in_idle (result);
+
+			g_error_free (error);
+			g_free (archive_uri);
+			return;
+		}
+	}
+	g_free (archive_uri);
+
+	FR_ARCHIVE_GET_CLASS (archive)->add_dropped_items (archive,
+							   item_list,
+							   base_dir,
+							   dest_dir,
+							   update,
+							   password,
+							   encrypt_header,
+							   compression,
+							   volume_size,
+							   cancellable,
+							   callback,
+							   user_data);
+}
+
+
+void
+fr_archive_update_open_files (FrArchive           *archive,
+			      GList               *file_list,
+			      GList               *dir_list,
+			      const char          *password,
+			      gboolean             encrypt_header,
+			      FrCompression        compression,
+			      guint                volume_size,
+			      GCancellable        *cancellable,
+			      GAsyncReadyCallback  callback,
+			      gpointer             user_data)
+{
+	FR_ARCHIVE_GET_CLASS (archive)->update_open_files (archive,
+							   file_list,
+							   dir_list,
+							   password,
+							   encrypt_header,
+							   compression,
+							   volume_size,
+							   cancellable,
+							   callback,
+							   user_data);
+}
+
+
+void
+fr_archive_set_multi_volume (FrArchive *self,
+			     GFile     *file)
+{
+	self->multi_volume = TRUE;
+	_fr_archive_set_file (self, file);
+}
+
+
+void
+fr_archive_change_name (FrArchive  *archive,
+		        const char *filename)
+{
+	const char *name;
+	GFile      *parent;
+	GFile      *file;
+
+	name = _g_path_get_file_name (filename);
+
+	parent = g_file_get_parent (archive->priv->file);
+	file = g_file_get_child (parent, name);;
+	_fr_archive_set_file (archive, file);
+
+	g_object_unref (parent);
+	g_object_unref (file);
+}
+
+
+GCancellable *
+fr_archive_get_cancellable (FrArchive *self)
+{
+	return self->priv->cancellable;
+}
+
+
+void
+fr_archive_action_started (FrArchive *self,
+			   FrAction   action)
+{
+	g_signal_emit (self,
+		       fr_archive_signals[START],
+		       0,
+		       action);
+}
+
+
+/* fraction == -1 means : I don't known how much time the current operation
+ *                        will take, the dialog will display this info pulsing
+ *                        the progress bar.
+ * fraction in [0.0, 1.0] means the amount of work, in percentage,
+ *                        accomplished.
+ */
+void
+fr_archive_progress (FrArchive *self,
+		     double     fraction)
+{
+	g_signal_emit (self,
+		       fr_archive_signals[PROGRESS],
+		       0,
+		       fraction);
+}
+
+
+void
+fr_archive_message (FrArchive  *self,
+		    const char *msg)
+{
+	g_signal_emit (self,
+		       fr_archive_signals[MESSAGE],
+		       0,
+		       msg);
+}
+
+
+void
+fr_archive_working_archive (FrArchive  *self,
+		            const char *archive_name)
+{
+	g_signal_emit (self,
+		       fr_archive_signals[WORKING_ARCHIVE],
+		       0,
+		       archive_name);
+}
+
+
+void
+fr_archive_set_n_files (FrArchive *self,
+			int        n_files)
 {
-	fr_archive_stoppable (archive, TRUE);
-
-	g_object_set (archive->command,
-		      "file", archive->local_copy,
-		      "password", password,
-		      NULL);
-	fr_process_clear (archive->process);
-	fr_command_set_n_files (archive->command, 0);
-	fr_command_test (archive->command);
-	fr_process_start (archive->process);
+	self->n_files = n_files;
+	self->n_file = 0;
 }
 
 
+void
+fr_archive_add_file (FrArchive *self,
+		     FileData  *file_data)
+{
+	file_data_update_content_type (file_data);
+	g_ptr_array_add (self->files, file_data);
+	if (! file_data->dir)
+		self->n_regular_files++;
+}
+
+
+/* FIXME: use sniffer as in fr_archive_open */
 gboolean
 _g_uri_is_archive (const char *uri)
 {
 	GFile      *file;
-	const char *mime_type;
+	const char *mime_type = NULL;
 	gboolean    is_archive = FALSE;
 
 	file = g_file_new_for_uri (uri);
-	mime_type = get_mime_type_from_magic_numbers (file);
-	if (mime_type == NULL)
-		mime_type = get_mime_type_from_content (file);
+	/* FIXME: libarchive
+	mime_type = get_mime_type_from_magic_numbers (file); */
 	if (mime_type == NULL)
 		mime_type = get_mime_type_from_filename (file);
 
diff --git a/src/fr-archive.h b/src/fr-archive.h
index 604977e..af7c256 100644
--- a/src/fr-archive.h
+++ b/src/fr-archive.h
@@ -3,7 +3,7 @@
 /*
  *  File-Roller
  *
- *  Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+ *  Copyright (C) 2001, 2003, 2012 Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -23,8 +23,32 @@
 #define FR_ARCHIVE_H
 
 #include <glib.h>
-#include "fr-process.h"
-#include "fr-command.h"
+#include "file-data.h"
+#include "typedefs.h"
+
+typedef enum {
+	FR_ACTION_NONE,
+	FR_ACTION_CREATING_NEW_ARCHIVE,
+	FR_ACTION_LOADING_ARCHIVE,            /* loading the archive from a remote location */
+	FR_ACTION_LISTING_CONTENT,            /* listing the content of the archive */
+	FR_ACTION_DELETING_FILES,             /* deleting files from the archive */
+	FR_ACTION_TESTING_ARCHIVE,            /* testing the archive integrity */
+	FR_ACTION_GETTING_FILE_LIST,          /* getting the file list (when fr_archive_add_with_wildcard or
+						 fr_archive_add_directory are used, we need to scan a directory
+						 and collect the files to add to the archive, this
+						 may require some time to complete, so the operation
+						 is asynchronous) */
+	FR_ACTION_COPYING_FILES_FROM_REMOTE,  /* copying files to be added to the archive from a remote location */
+	FR_ACTION_ADDING_FILES,               /* adding files to an archive */
+	FR_ACTION_EXTRACTING_FILES,           /* extracting files */
+	FR_ACTION_COPYING_FILES_TO_REMOTE,    /* copying extracted files to a remote location */
+	FR_ACTION_CREATING_ARCHIVE,           /* creating a local archive */
+	FR_ACTION_SAVING_REMOTE_ARCHIVE       /* copying the archive to a remote location */
+} FrAction;
+
+#ifdef DEBUG
+extern char *action_names[];
+#endif
 
 #define FR_TYPE_ARCHIVE            (fr_archive_get_type ())
 #define FR_ARCHIVE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), FR_TYPE_ARCHIVE, FrArchive))
@@ -35,176 +59,452 @@
 
 typedef struct _FrArchive         FrArchive;
 typedef struct _FrArchiveClass    FrArchiveClass;
-typedef struct _FrArchivePrivData FrArchivePrivData;
+typedef struct _FrArchivePrivate  FrArchivePrivate;
 
 typedef gboolean (*FakeLoadFunc) (FrArchive *archive, gpointer data);
 
 struct _FrArchive {
 	GObject  __parent;
+	FrArchivePrivate *priv;
+
+	/*<public, read only>*/
+
+	const char    *mime_type;
+	GPtrArray     *files;                      /* Array of FileData* */
+	int            n_regular_files;
+
+	/*<public>*/
+
+	char          *password;
+	gboolean       encrypt_header : 1;
+	FrCompression  compression;
+	gboolean       multi_volume;
+	guint          volume_size;
+	gboolean       read_only;                  /* Whether archive is
+						    * read-only for whatever
+						    * reason. */
+
+	/*<protected>*/
+
+	/* FIXME: remove this two attributes */
+	FrAction       action;        /* current action. */
+	gboolean       extract_here;
+
+	/* progress data */
+
+	int            n_file;
+	int            n_files;
+
+	/* features. */
+
+	/* propAddCanReplace:
+	 *
+	 * TRUE if the command can overwrite a file in the archive.
+	 */
+	guint          propAddCanReplace : 1;
+
+	/* propAddCanReplace:
+	 *
+	 * TRUE if the command can overwrite a file in the archive if older
+	 * then the file on disk.
+	 */
+	guint          propAddCanUpdate : 1;
+
+	/* propAddCanStoreFolders:
+	 *
+	 * TRUE if the command can store folder entries inside the archive.
+	 */
+	guint          propAddCanStoreFolders : 1;
 
-	GFile       *file;
-	GFile       *local_copy;
-	gboolean     is_remote;
-	const char  *content_type;
-	FrCommand   *command;
-	FrProcess   *process;
-	FrProcError  error;
-	gboolean     can_create_compressed_file;
-	gboolean     is_compressed_file;         /* Whether the file is not an
-						  * archive that can contain
-						  * many files but simply a
-						  * compressed file, for
-						  * example foo.txt.gz is a
-						  * compressed file, foo.zip
-						  * is not. */
-	gboolean     read_only;                  /* Whether archive is
-						  * read-only for whatever
-						  * reason. */
-	gboolean     have_permissions;           /* true if we have the
-						  * permissions to write the
-						  * file. */
-
-	FrArchivePrivData *priv;
+	/* propExtractCanAvoidOverwrite:
+	 *
+	 * TRUE if the command can avoid to overwrite the files on disk.
+	 */
+	guint          propExtractCanAvoidOverwrite : 1;
+
+	/* propExtractCanSkipOlder:
+	 *
+	 * TRUE if the command can avoid to overwrite a file on disk when it is
+	 * newer than the file in the archive.
+	 */
+	guint          propExtractCanSkipOlder : 1;
+
+	/* propExtractCanJunkPaths:
+	 *
+	 * TRUE if the command can extract the files in the current folder
+	 * without recreating the directory structure.
+	 */
+	guint          propExtractCanJunkPaths : 1;
+
+	/* propPassword:
+	 *
+	 * TRUE if the command can use passwords for adding or extracting files.
+	 */
+	guint          propPassword : 1;
+
+	/* propTest:
+	 *
+	 * TRUE if the command can test the archive integrity.
+	 */
+	guint          propTest : 1;
+
+	/* propCanExtractAll:
+	 *
+	 * TRUE if the command extract all the files when no file is specified.
+	 */
+	guint          propCanExtractAll : 1;
+
+	/* propCanDeleteNonEmptyFolders:
+	 *
+	 * is used to overcome an issue with tar, that deletes only the folder
+	 * entry in the archive instead of deleting the folder content
+	 * recursively.
+	 */
+	guint          propCanDeleteNonEmptyFolders : 1;
+
+	/* propCanExtractNonEmptyFolders:
+	 *
+	 * is used to overcome an issue with tar.  For example if
+	 * the content of a tar archive is
+	 *
+	 * readme.txt
+	 * doc/
+	 * doc/page1.html
+	 * doc/page2.html
+	 *
+	 * and we want to extract the content of the doc folder, the command:
+	 *
+	 * tar -xf archive.tar doc doc/page1.html doc/page2.html
+	 *
+	 * gives an error.
+	 * To fix the issue we have to remove the files inside the doc
+	 * folder from the command line, getting the following command:
+	 *
+	 * tar -xf archive.tar doc
+	 */
+	guint          propCanExtractNonEmptyFolders : 1;
+
+	/* propListFromFile:
+	 *
+	 * if TRUE the command has an option to read the file list from a file
+	 */
+	guint          propListFromFile : 1;
 };
 
 struct _FrArchiveClass {
 	GObjectClass __parent_class;
 
-	/* -- Signals -- */
-
-	void (*start)            (FrArchive   *archive,
-			          FrAction     action);
-	void (*done)             (FrArchive   *archive,
-			          FrAction     action,
-			          FrProcError *error);
-	void (*progress)         (FrArchive   *archive,
-			          double       fraction);
-	void (*message)          (FrArchive   *archive,
-			          const char  *msg);
-	void (*stoppable)        (FrArchive   *archive,
-			          gboolean     value);
-	void (*working_archive)  (FrCommand   *comm,
-			          const char  *filename);
+	/*< signals >*/
+
+	void          (*start)             (FrArchive           *archive,
+					    FrAction             action);
+	void          (*progress)          (FrArchive           *archive,
+			           	    double               fraction);
+	void          (*message)           (FrArchive           *archive,
+			           	    const char          *msg);
+	void          (*stoppable)         (FrArchive           *archive,
+			           	    gboolean             value);
+	void          (*working_archive)   (FrArchive           *archive,
+			           	    const char          *filename);
+
+	/*< virtual functions >*/
+
+	const char ** (*get_mime_types)    (FrArchive           *archive);
+	FrArchiveCap  (*get_capabilities)  (FrArchive           *archive,
+					    const char          *mime_type,
+					    gboolean             check_command);
+	void          (*set_mime_type)     (FrArchive           *archive,
+				            const char          *mime_type);
+	const char *  (*get_packages)      (FrArchive           *archive,
+					    const char          *mime_type);
+	void          (*load)              (FrArchive           *archive,
+					    const char          *password,
+					    GCancellable        *cancellable,
+					    GAsyncReadyCallback  callback,
+					    gpointer             user_data);
+	void          (*add_files)         (FrArchive           *archive,
+					    GList               *file_list,
+					    const char          *base_dir,
+					    const char          *dest_dir,
+					    gboolean             update,
+					    gboolean             recursive,
+					    const char          *password,
+					    gboolean             encrypt_header,
+					    FrCompression        compression,
+					    guint                volume_size,
+					    GCancellable        *cancellable,
+					    GAsyncReadyCallback  callback,
+					    gpointer             user_data);
+	void          (*extract_files)     (FrArchive           *archive,
+	    				    GList               *file_list,
+	    				    const char          *destination,
+	    				    const char          *base_dir,
+	    				    gboolean             skip_older,
+	    				    gboolean             overwrite,
+	    				    gboolean             junk_paths,
+	    				    const char          *password,
+					    GCancellable        *cancellable,
+					    GAsyncReadyCallback  callback,
+					    gpointer             user_data);
+	void          (*remove_files)      (FrArchive           *archive,
+				   	    GList               *file_list,
+				   	    FrCompression        compression,
+				   	    GCancellable        *cancellable,
+				   	    GAsyncReadyCallback  callback,
+				   	    gpointer             user_data);
+	void          (*test_integrity)    (FrArchive           *archive,
+			 	   	    const char          *password,
+			 	   	    GCancellable        *cancellable,
+			 	   	    GAsyncReadyCallback  callback,
+			 	   	    gpointer             user_data);
+	void          (*rename)            (FrArchive           *archive,
+					    GList               *file_list,
+				   	    const char          *old_name,
+				   	    const char          *new_name,
+				   	    const char          *current_dir,
+				   	    gboolean             is_dir,
+				   	    gboolean             dir_in_archive,
+				   	    const char          *original_path,
+					    GCancellable        *cancellable,
+					    GAsyncReadyCallback  callback,
+					    gpointer             user_data);
+	void          (*paste_clipboard)   (FrArchive           *archive,
+					    char                *archive_uri,
+					    char                *password,
+					    gboolean             encrypt_header,
+					    FrCompression        compression,
+					    guint                volume_size,
+					    FrClipboardOp        op,
+					    char                *base_dir,
+					    GList               *files,
+					    char                *tmp_dir,
+					    char                *current_dir,
+					    GCancellable        *cancellable,
+					    GAsyncReadyCallback  callback,
+					    gpointer             user_data);
+	void          (*add_dropped_items) (FrArchive           *archive,
+				   	    GList               *item_list,
+				   	    const char          *base_dir,
+				   	    const char          *dest_dir,
+				   	    gboolean             update,
+				   	    const char          *password,
+				   	    gboolean             encrypt_header,
+				   	    FrCompression        compression,
+				   	    guint                volume_size,
+					    GCancellable        *cancellable,
+					    GAsyncReadyCallback  callback,
+					    gpointer             user_data);
+	void          (*update_open_files) (FrArchive           *archive,
+					    GList               *file_list,
+					    GList               *dir_list,
+					    const char          *password,
+					    gboolean             encrypt_header,
+					    FrCompression        compression,
+					    guint                volume_size,
+					    GCancellable        *cancellable,
+					    GAsyncReadyCallback  callback,
+					    gpointer             user_data);
 };
 
-GType       fr_archive_get_type                  (void);
-FrArchive * fr_archive_new                       (void);
-void        fr_archive_set_fake_load_func        (FrArchive       *archive,
-						  FakeLoadFunc     func,
-						  gpointer         data);
-gboolean    fr_archive_fake_load                 (FrArchive       *archive);
-void        fr_archive_stoppable                 (FrArchive       *archive,
-						  gboolean         stoppable);
-void        fr_archive_stop	                 (FrArchive       *archive);
-void        fr_archive_action_completed          (FrArchive       *archive,
-						  FrAction         action,
-						  FrProcErrorType  error_type,
-						  const char      *error_details);
-
-/**/
-
-gboolean    fr_archive_create                    (FrArchive       *archive,
-						  const char      *uri);
-gboolean    fr_archive_load                      (FrArchive       *archive,
-						  const char      *uri,
-						  const char      *password);
-void        fr_archive_reload                    (FrArchive       *archive,
-						  const char      *password);
-
-/**/
-
-void        fr_archive_add                       (FrArchive       *archive,
-						  GList           *file_list,
-						  const char      *base_dir,
-						  const char      *dest_dir,
-						  gboolean         update,
-						  gboolean         recursive,
-						  const char      *password,
-						  gboolean         encrypt_header,
-						  FrCompression    compression,
-						  guint            volume_size);
-void        fr_archive_remove                    (FrArchive       *archive,
-						  GList           *file_list,
-						  FrCompression    compression);
-void        fr_archive_extract                   (FrArchive       *archive,
-						  GList           *file_list,
-						  const char      *dest_uri,
-						  const char      *base_dir,
-						  gboolean         skip_older,
-						  gboolean         overwrite,
-						  gboolean         junk_path,
-						  const char      *password);
-void        fr_archive_extract_to_local          (FrArchive       *archive,
-						  GList           *file_list,
-						  const char      *dest_path,
-						  const char      *base_dir,
-						  gboolean         skip_older,
-						  gboolean         overwrite,
-						  gboolean         junk_path,
-						  const char      *password);
-gboolean    fr_archive_extract_here              (FrArchive       *archive,
-						  gboolean         skip_older,
-						  gboolean         overwrite,
-						  gboolean         junk_path,
-						  const char      *password);
-const char *fr_archive_get_last_extraction_destination
-						 (FrArchive       *archive);
-
-/**/
-
-void        fr_archive_add_files                 (FrArchive       *archive,
-						  GList           *file_list,
-						  const char      *base_dir,
-						  const char      *dest_dir,
-						  gboolean         update,
-						  const char      *password,
-						  gboolean         encrypt_header,
-						  FrCompression    compression,
-						  guint            volume_size);
-void        fr_archive_add_with_wildcard         (FrArchive       *archive,
-						  const char      *include_files,
-						  const char      *exclude_files,
-						  const char      *exclude_folders,
-						  const char      *base_dir,
-						  const char      *dest_dir,
-						  gboolean         update,
-						  gboolean         follow_links,
-						  const char      *password,
-						  gboolean         encrypt_header,
-						  FrCompression    compression,
-						  guint            volume_size);
-void        fr_archive_add_directory             (FrArchive       *archive,
-						  const char      *directory,
-						  const char      *base_dir,
-						  const char      *dest_dir,
-						  gboolean         update,
-						  const char      *password,
-						  gboolean         encrypt_header,
-						  FrCompression    compression,
-						  guint            volume_size);
-void        fr_archive_add_items                 (FrArchive       *archive,
-						  GList           *item_list,
-						  const char      *base_dir,
-						  const char      *dest_dir,
-						  gboolean         update,
-						  const char      *password,
-						  gboolean         encrypt_header,
-						  FrCompression    compression,
-						  guint            volume_size);
-void        fr_archive_add_dropped_items         (FrArchive       *archive,
-						  GList           *item_list,
-						  const char      *base_dir,
-						  const char      *dest_dir,
-						  gboolean         update,
-						  const char      *password,
-						  gboolean         encrypt_header,
-						  FrCompression    compression,
-						  guint            volume_size);
-void        fr_archive_test                      (FrArchive       *archive,
-						  const char      *password);
+GType         fr_archive_get_type                (void);
+GFile *       fr_archive_get_file                (FrArchive           *archive);
+gboolean      fr_archive_is_capable_of           (FrArchive           *archive,
+						  FrArchiveCaps        capabilities);
+const char ** fr_archive_get_mime_types          (FrArchive           *archive);
+void          fr_archive_update_capabilities     (FrArchive           *archive);
+FrArchiveCap  fr_archive_get_capabilities        (FrArchive           *archive,
+						  const char          *mime_type,
+						  gboolean             check_command);
+void          fr_archive_set_mime_type           (FrArchive           *archive,
+						  const char          *mime_type);
+const char *  fr_archive_get_packages            (FrArchive           *archive,
+						  const char          *mime_type);
+void          fr_archive_set_stoppable           (FrArchive           *archive,
+						  gboolean             stoppable);
+FrArchive *   fr_archive_create                  (GFile               *file);
+void          fr_archive_open                    (GFile               *file,
+		       	       	       	          GCancellable        *cancellable,
+		       	       	       	          GAsyncReadyCallback  callback,
+		       	       	       	          gpointer             user_data);
+FrArchive *   fr_archive_open_finish             (GFile               *file,
+						  GAsyncResult        *result,
+						  GError             **error);
+void          fr_archive_load                    (FrArchive           *archive,
+						  const char          *password,
+						  GCancellable        *cancellable,
+		       	       	       	          GAsyncReadyCallback  callback,
+		       	       	       	          gpointer             user_data);
+gboolean      fr_archive_operation_finish        (FrArchive           *archive,
+						  GAsyncResult        *result,
+						  GError             **error);
+void          fr_archive_add_files               (FrArchive           *archive,
+						  GList               *file_list,
+						  const char          *base_dir,
+						  const char          *dest_dir,
+						  gboolean             update,
+						  gboolean             recursive,
+						  const char          *password,
+						  gboolean             encrypt_header,
+						  FrCompression        compression,
+						  guint                volume_size,
+						  GCancellable        *cancellable,
+						  GAsyncReadyCallback  callback,
+						  gpointer             user_data);
+void          fr_archive_add_with_wildcard       (FrArchive           *archive,
+						  const char          *include_files,
+						  const char          *exclude_files,
+						  const char          *exclude_folders,
+						  const char          *base_dir,
+						  const char          *dest_dir,
+						  gboolean             update,
+						  gboolean             follow_links,
+						  const char          *password,
+						  gboolean             encrypt_header,
+						  FrCompression        compression,
+						  guint                volume_size,
+						  GCancellable        *cancellable,
+						  GAsyncReadyCallback  callback,
+						  gpointer             user_data);
+void          fr_archive_add_directory           (FrArchive           *archive,
+						  const char          *directory,
+						  const char          *base_dir,
+						  const char          *dest_dir,
+						  gboolean             update,
+						  const char          *password,
+						  gboolean             encrypt_header,
+						  FrCompression        compression,
+						  guint                volume_size,
+						  GCancellable        *cancellable,
+						  GAsyncReadyCallback  callback,
+						  gpointer             user_data);
+void          fr_archive_add_items               (FrArchive           *archive,
+						  GList               *item_list,
+						  const char          *base_dir,
+						  const char          *dest_dir,
+						  gboolean             update,
+						  const char          *password,
+						  gboolean             encrypt_header,
+						  FrCompression        compression,
+						  guint                volume_size,
+						  GCancellable        *cancellable,
+						  GAsyncReadyCallback  callback,
+						  gpointer             user_data);
+void          fr_archive_remove                  (FrArchive           *archive,
+						  GList               *file_list,
+						  FrCompression        compression,
+						  GCancellable        *cancellable,
+						  GAsyncReadyCallback  callback,
+						  gpointer             user_data);
+void          fr_archive_extract                 (FrArchive           *archive,
+						  GList               *file_list,
+						  const char          *dest_uri,
+						  const char          *base_dir,
+						  gboolean             skip_older,
+						  gboolean             overwrite,
+						  gboolean             junk_path,
+						  const char          *password,
+		       	       	       	          GCancellable        *cancellable,
+		       	       	       	          GAsyncReadyCallback  callback,
+		       	       	       	          gpointer             user_data);
+void          fr_archive_extract_to_local        (FrArchive           *archive,
+						  GList               *file_list,
+						  const char          *dest_path,
+						  const char          *base_dir,
+						  gboolean             skip_older,
+						  gboolean             overwrite,
+						  gboolean             junk_path,
+						  const char          *password,
+		       	       	       	          GCancellable        *cancellable,
+		       	       	       	          GAsyncReadyCallback  callback,
+		       	       	       	          gpointer             user_data);
+gboolean      fr_archive_extract_here            (FrArchive           *archive,
+						  gboolean             skip_older,
+						  gboolean             overwrite,
+						  gboolean             junk_path,
+						  const char          *password,
+		       	       	       	          GCancellable        *cancellable,
+		       	       	       	          GAsyncReadyCallback  callback,
+		       	       	       	          gpointer             user_data);
+void          fr_archive_set_last_extraction_destination
+						 (FrArchive           *archive,
+						  const char          *uri);
+const char *  fr_archive_get_last_extraction_destination
+						 (FrArchive           *archive);
+void          fr_archive_test                    (FrArchive           *archive,
+						  const char          *password,
+		       	       	       	          GCancellable        *cancellable,
+		       	       	       	          GAsyncReadyCallback  callback,
+		       	       	       	          gpointer             user_data);
+void          fr_archive_rename                  (FrArchive           *archive,
+						  GList               *file_list,
+						  const char          *old_name,
+						  const char          *new_name,
+						  const char          *current_dir,
+						  gboolean             is_dir,
+						  gboolean             dir_in_archive,
+						  const char          *original_path,
+						  GCancellable        *cancellable,
+						  GAsyncReadyCallback  callback,
+						  gpointer             user_data);
+void          fr_archive_paste_clipboard         (FrArchive           *archive,
+						  char                *archive_uri,
+						  char                *password,
+						  gboolean             encrypt_header,
+						  FrCompression        compression,
+						  guint                volume_size,
+						  FrClipboardOp        op,
+						  char                *base_dir,
+						  GList               *files,
+						  char                *tmp_dir,
+						  char                *current_dir,
+		       	       	       	          GCancellable        *cancellable,
+		       	       	       	          GAsyncReadyCallback  callback,
+		       	       	       	          gpointer             user_data);
+void          fr_archive_add_dropped_items       (FrArchive           *archive,
+						  GList               *item_list,
+						  const char          *base_dir,
+						  const char          *dest_dir,
+						  gboolean             update,
+						  const char          *password,
+						  gboolean             encrypt_header,
+						  FrCompression        compression,
+						  guint                volume_size,
+						  GCancellable        *cancellable,
+						  GAsyncReadyCallback  callback,
+						  gpointer             user_data);
+void          fr_archive_update_open_files       (FrArchive           *archive,
+						  GList               *file_list,
+						  GList               *dir_list,
+						  const char          *password,
+						  gboolean             encrypt_header,
+						  FrCompression        compression,
+						  guint                volume_size,
+						  GCancellable        *cancellable,
+						  GAsyncReadyCallback  callback,
+						  gpointer             user_data);
+
+/* protected */
+
+void          fr_archive_set_multi_volume        (FrArchive           *archive,
+					          GFile               *file);
+void          fr_archive_change_name             (FrArchive           *archive,
+						  const char          *filename);
+GCancellable *fr_archive_get_cancellable         (FrArchive           *archive);
+void          fr_archive_action_started          (FrArchive           *archive,
+						  FrAction             action);
+void          fr_archive_progress                (FrArchive           *archive,
+						  double               fraction);
+void          fr_archive_message                 (FrArchive           *archive,
+						  const char          *msg);
+void          fr_archive_working_archive         (FrArchive           *archive,
+						  const char          *archive_name);
+void          fr_archive_set_n_files             (FrArchive           *archive,
+						  int                  n_files);
+void          fr_archive_add_file                (FrArchive           *archive,
+						  FileData            *file_data);
 
 /* utilities */
 
-gboolean    _g_uri_is_archive                    (const char      *uri);
+gboolean      _g_uri_is_archive                  (const char          *uri);
 
 #endif /* FR_ARCHIVE_H */
diff --git a/src/fr-command-7z.c b/src/fr-command-7z.c
index f35c2b6..6287d23 100644
--- a/src/fr-command-7z.c
+++ b/src/fr-command-7z.c
@@ -80,14 +80,14 @@ static void
 list__process_line (char     *line,
 		    gpointer  data)
 {
-	FrCommand    *comm = FR_COMMAND (data);
-	FrCommand7z  *p7z_comm = FR_COMMAND_7Z (comm);
+	FrCommand7z  *self = FR_COMMAND_7Z (data);
+	FrArchive    *archive = FR_ARCHIVE (data);
 	char        **fields;
 	FileData     *fdata;
 
 	g_return_if_fail (line != NULL);
 
-	if (! p7z_comm->list_started) {
+	if (! self->list_started) {
 		if (strncmp (line, "p7zip Version ", 14) == 0) {
 			const char *ver_start;
 			int         ver_len;
@@ -99,44 +99,44 @@ list__process_line (char     *line,
 			version[ver_len] = 0;
 
 			if (strcmp (version, "4.55") < 0)
-				p7z_comm->old_style = TRUE;
+				self->old_style = TRUE;
 			else
-				p7z_comm->old_style = FALSE;
+				self->old_style = FALSE;
 		}
-		else if (p7z_comm->old_style && (strncmp (line, "Listing archive: ", 17) == 0))
-			p7z_comm->list_started = TRUE;
-		else if (! p7z_comm->old_style && (strcmp (line, "----------") == 0))
-			p7z_comm->list_started = TRUE;
+		else if (self->old_style && (strncmp (line, "Listing archive: ", 17) == 0))
+			self->list_started = TRUE;
+		else if (! self->old_style && (strcmp (line, "----------") == 0))
+			self->list_started = TRUE;
 		else if (strncmp (line, "Multivolume = ", 14) == 0) {
 			fields = g_strsplit (line, " = ", 2);
-			comm->multi_volume = (strcmp (fields[1], "+") == 0);
+			archive->multi_volume = (strcmp (fields[1], "+") == 0);
 			g_strfreev (fields);
 		}
 		return;
 	}
 
 	if (strcmp (line, "") == 0) {
-		if (p7z_comm->fdata != NULL) {
-			if (p7z_comm->fdata->original_path == NULL) {
-				file_data_free (p7z_comm->fdata);
-				p7z_comm->fdata = NULL;
+		if (self->fdata != NULL) {
+			if (self->fdata->original_path == NULL) {
+				file_data_free (self->fdata);
+				self->fdata = NULL;
 			}
 			else {
-				fdata = p7z_comm->fdata;
+				fdata = self->fdata;
 				if (fdata->dir)
 					fdata->name = _g_path_get_dir_name (fdata->full_path);
 				else
 					fdata->name = g_strdup (_g_path_get_file_name (fdata->full_path));
 				fdata->path = _g_path_remove_level (fdata->full_path);
-				fr_command_add_file (comm, fdata);
-				p7z_comm->fdata = NULL;
+				fr_archive_add_file (archive, fdata);
+				self->fdata = NULL;
 			}
 		}
 		return;
 	}
 
-	if (p7z_comm->fdata == NULL)
-		p7z_comm->fdata = file_data_new ();
+	if (self->fdata == NULL)
+		self->fdata = file_data_new ();
 
 	fields = g_strsplit (line, " = ", 2);
 
@@ -145,7 +145,7 @@ list__process_line (char     *line,
 		return;
 	}
 
-	fdata = p7z_comm->fdata;
+	fdata = self->fdata;
 
 	if (strcmp (fields[0], "Path") == 0) {
 		fdata->free_original_path = TRUE;
@@ -198,15 +198,15 @@ fr_command_7z_begin_command (FrCommand *comm)
 
 
 static void
-add_password_arg (FrCommand     *comm,
-		  const char    *password,
-		  gboolean       always_specify)
+add_password_arg (FrCommand  *command,
+		  const char *password,
+		  gboolean    always_specify)
 {
 	if (always_specify || ((password != NULL) && (*password != 0))) {
 		char *arg;
 
 		arg = g_strconcat ("-p", password, NULL);
-		fr_process_add_arg (comm->process, arg);
+		fr_process_add_arg (command->process, arg);
 		g_free (arg);
 	}
 }
@@ -225,30 +225,30 @@ list__begin (gpointer data)
 }
 
 
-static void
-fr_command_7z_list (FrCommand  *comm)
+static gboolean
+fr_command_7z_list (FrCommand *command)
 {
-	rar_check_multi_volume (comm);
-
-	fr_process_set_out_line_func (comm->process, list__process_line, comm);
-
-	fr_command_7z_begin_command (comm);
-	fr_process_set_begin_func (comm->process, list__begin, comm);
-	fr_process_add_arg (comm->process, "l");
-	fr_process_add_arg (comm->process, "-slt");
-	fr_process_add_arg (comm->process, "-bd");
-	fr_process_add_arg (comm->process, "-y");
-	add_password_arg (comm, comm->password, FALSE);
-	fr_process_add_arg (comm->process, "--");
-	fr_process_add_arg (comm->process, comm->filename);
-	fr_process_end_command (comm->process);
-
-	fr_process_start (comm->process);
+	rar_check_multi_volume (command);
+
+	fr_process_set_out_line_func (command->process, list__process_line, command);
+
+	fr_command_7z_begin_command (command);
+	fr_process_set_begin_func (command->process, list__begin, command);
+	fr_process_add_arg (command->process, "l");
+	fr_process_add_arg (command->process, "-slt");
+	fr_process_add_arg (command->process, "-bd");
+	fr_process_add_arg (command->process, "-y");
+	add_password_arg (command, FR_ARCHIVE (command)->password, FALSE);
+	fr_process_add_arg (command->process, "--");
+	fr_process_add_arg (command->process, command->filename);
+	fr_process_end_command (command->process);
+
+	return TRUE;
 }
 
 
 static void
-parse_progress_line (FrCommand  *comm,
+parse_progress_line (FrArchive  *archive,
 		     const char *prefix,
 		     const char *message_format,
 		     const char *line)
@@ -257,8 +257,8 @@ parse_progress_line (FrCommand  *comm,
 
 	prefix_len = strlen (prefix);
 	if (strncmp (line, prefix, prefix_len) == 0) {
-		if (comm->n_files > 1) {
-			fr_command_progress (comm, (double) ++comm->n_file / (comm->n_files + 1));
+		if (archive->n_files > 1) {
+			fr_archive_progress (archive, (double) ++archive->n_file / (archive->n_files + 1));
 		}
 		else {
 			char  filename[4196];
@@ -266,7 +266,7 @@ parse_progress_line (FrCommand  *comm,
 
 			strcpy (filename, line + prefix_len);
 			msg = g_strdup_printf (message_format, filename, NULL);
-			fr_command_message (comm, msg);
+			fr_archive_message (archive, msg);
 
 			g_free (msg);
 		}
@@ -278,132 +278,134 @@ static void
 process_line__add (char     *line,
 		   gpointer  data)
 {
-	FrCommand *comm = FR_COMMAND (data);
+	FrCommand *command = FR_COMMAND (data);
+	FrArchive *archive = FR_ARCHIVE (data);
 
-	if ((comm->volume_size > 0) && (strncmp (line, "Creating archive ", 17) == 0)) {
+	if ((archive->volume_size > 0) && (strncmp (line, "Creating archive ", 17) == 0)) {
 		char  *volume_filename;
 		GFile *volume_file;
 
-		volume_filename = g_strconcat (comm->filename, ".001", NULL);
+		volume_filename = g_strconcat (command->filename, ".001", NULL);
 		volume_file = g_file_new_for_path (volume_filename);
-		fr_command_set_multi_volume (comm, volume_file);
+		fr_archive_set_multi_volume (archive, volume_file);
 
 		g_object_unref (volume_file);
 		g_free (volume_filename);
 	}
 
-	if (comm->n_files != 0)
-		parse_progress_line (comm, "Compressing  ", _("Adding \"%s\""), line);
+	if (archive->n_files != 0)
+		parse_progress_line (archive, "Compressing  ", _("Adding \"%s\""), line);
 }
 
 
 static void
-fr_command_7z_add (FrCommand     *comm,
-		   const char    *from_file,
-		   GList         *file_list,
-		   const char    *base_dir,
-		   gboolean       update,
-		   gboolean       recursive)
+fr_command_7z_add (FrCommand  *command,
+		   const char *from_file,
+		   GList      *file_list,
+		   const char *base_dir,
+		   gboolean    update,
+		   gboolean    recursive)
 {
-	GList *scan;
+	FrArchive *archive = FR_ARCHIVE (command);
+	GList     *scan;
 
-	fr_process_use_standard_locale (comm->process, TRUE);
-	fr_process_set_out_line_func (comm->process,
+	fr_process_use_standard_locale (command->process, TRUE);
+	fr_process_set_out_line_func (command->process,
 				      process_line__add,
-				      comm);
+				      command);
 
-	fr_command_7z_begin_command (comm);
+	fr_command_7z_begin_command (command);
 
 	if (update)
-		fr_process_add_arg (comm->process, "u");
+		fr_process_add_arg (command->process, "u");
 	else
-		fr_process_add_arg (comm->process, "a");
+		fr_process_add_arg (command->process, "a");
 
 	if (base_dir != NULL) {
-		fr_process_set_working_dir (comm->process, base_dir);
-		fr_process_add_arg_concat (comm->process, "-w", base_dir, NULL);
+		fr_process_set_working_dir (command->process, base_dir);
+		fr_process_add_arg_concat (command->process, "-w", base_dir, NULL);
 	}
 
-	if (_g_mime_type_matches (comm->mime_type, "application/zip")
-	    || _g_mime_type_matches (comm->mime_type, "application/x-cbz"))
+	if (_g_mime_type_matches (archive->mime_type, "application/zip")
+	    || _g_mime_type_matches (archive->mime_type, "application/x-cbz"))
 	{
-		fr_process_add_arg (comm->process, "-tzip");
-		fr_process_add_arg (comm->process, "-mem=AES128");
+		fr_process_add_arg (command->process, "-tzip");
+		fr_process_add_arg (command->process, "-mem=AES128");
 	}
 
-	fr_process_add_arg (comm->process, "-bd");
-	fr_process_add_arg (comm->process, "-y");
-	fr_process_add_arg (comm->process, "-l");
-	add_password_arg (comm, comm->password, FALSE);
-	if ((comm->password != NULL)
-	    && (*comm->password != 0)
-	    && comm->encrypt_header
-	    && fr_command_is_capable_of (comm, FR_COMMAND_CAN_ENCRYPT_HEADER))
+	fr_process_add_arg (command->process, "-bd");
+	fr_process_add_arg (command->process, "-y");
+	fr_process_add_arg (command->process, "-l");
+	add_password_arg (command, archive->password, FALSE);
+	if ((archive->password != NULL)
+	    && (*archive->password != 0)
+	    && archive->encrypt_header
+	    && fr_archive_is_capable_of (archive, FR_ARCHIVE_CAN_ENCRYPT_HEADER))
 	{
-		fr_process_add_arg (comm->process, "-mhe=on");
+		fr_process_add_arg (command->process, "-mhe=on");
 	}
 
-	/* fr_process_add_arg (comm->process, "-ms=off"); FIXME: solid mode off? */
+	/* fr_process_add_arg (command->process, "-ms=off"); FIXME: solid mode off? */
 
-	switch (comm->compression) {
+	switch (archive->compression) {
 	case FR_COMPRESSION_VERY_FAST:
-		fr_process_add_arg (comm->process, "-mx=1");
+		fr_process_add_arg (command->process, "-mx=1");
 		break;
 	case FR_COMPRESSION_FAST:
-		fr_process_add_arg (comm->process, "-mx=5");
+		fr_process_add_arg (command->process, "-mx=5");
 		break;
 	case FR_COMPRESSION_NORMAL:
-		fr_process_add_arg (comm->process, "-mx=7");
+		fr_process_add_arg (command->process, "-mx=7");
 		break;
 	case FR_COMPRESSION_MAXIMUM:
-		fr_process_add_arg (comm->process, "-mx=9");
-		fr_process_add_arg (comm->process, "-m0=lzma2");;
+		fr_process_add_arg (command->process, "-mx=9");
+		fr_process_add_arg (command->process, "-m0=lzma2");;
 		break;
 	}
 
-	if (_g_mime_type_matches (comm->mime_type, "application/x-ms-dos-executable"))
-		fr_process_add_arg (comm->process, "-sfx");
+	if (_g_mime_type_matches (archive->mime_type, "application/x-ms-dos-executable"))
+		fr_process_add_arg (command->process, "-sfx");
 
-	if (comm->volume_size > 0)
-		fr_process_add_arg_printf (comm->process, "-v%ub", comm->volume_size);
+	if (archive->volume_size > 0)
+		fr_process_add_arg_printf (command->process, "-v%ub", archive->volume_size);
 
 	if (from_file != NULL)
-		fr_process_add_arg_concat (comm->process, "-i@", from_file, NULL);
+		fr_process_add_arg_concat (command->process, "-i@", from_file, NULL);
 
-	fr_process_add_arg (comm->process, "--");
-	fr_process_add_arg (comm->process, comm->filename);
+	fr_process_add_arg (command->process, "--");
+	fr_process_add_arg (command->process, command->filename);
 	if (from_file == NULL)
 		for (scan = file_list; scan; scan = scan->next)
-			fr_process_add_arg (comm->process, scan->data);
+			fr_process_add_arg (command->process, scan->data);
 
-	fr_process_end_command (comm->process);
+	fr_process_end_command (command->process);
 }
 
 
 static void
-fr_command_7z_delete (FrCommand  *comm,
+fr_command_7z_delete (FrCommand  *command,
 		      const char *from_file,
 		      GList      *file_list)
 {
 	GList *scan;
 
-	fr_command_7z_begin_command (comm);
-	fr_process_add_arg (comm->process, "d");
-	fr_process_add_arg (comm->process, "-bd");
-	fr_process_add_arg (comm->process, "-y");
-	if (_g_mime_type_matches (comm->mime_type, "application/x-ms-dos-executable"))
-		fr_process_add_arg (comm->process, "-sfx");
+	fr_command_7z_begin_command (command);
+	fr_process_add_arg (command->process, "d");
+	fr_process_add_arg (command->process, "-bd");
+	fr_process_add_arg (command->process, "-y");
+	if (_g_mime_type_matches (FR_ARCHIVE (command)->mime_type, "application/x-ms-dos-executable"))
+		fr_process_add_arg (command->process, "-sfx");
 
 	if (from_file != NULL)
-		fr_process_add_arg_concat (comm->process, "-i@", from_file, NULL);
+		fr_process_add_arg_concat (command->process, "-i@", from_file, NULL);
 
-	fr_process_add_arg (comm->process, "--");
-	fr_process_add_arg (comm->process, comm->filename);
+	fr_process_add_arg (command->process, "--");
+	fr_process_add_arg (command->process, command->filename);
 	if (from_file == NULL)
 		for (scan = file_list; scan; scan = scan->next)
-			fr_process_add_arg (comm->process, scan->data);
+			fr_process_add_arg (command->process, scan->data);
 
-	fr_process_end_command (comm->process);
+	fr_process_end_command (command->process);
 }
 
 
@@ -411,15 +413,15 @@ static void
 process_line__extract (char     *line,
 		       gpointer  data)
 {
-	FrCommand *comm = FR_COMMAND (data);
+	FrArchive *archive = FR_ARCHIVE (data);
 
-	if (comm->n_files != 0)
-		parse_progress_line (comm, "Extracting  ", _("Extracting \"%s\""), line);
+	if (archive->n_files != 0)
+		parse_progress_line (archive, "Extracting  ", _("Extracting \"%s\""), line);
 }
 
 
 static void
-fr_command_7z_extract (FrCommand  *comm,
+fr_command_7z_extract (FrCommand  *command,
 		       const char *from_file,
 		       GList      *file_list,
 		       const char *dest_dir,
@@ -427,76 +429,81 @@ fr_command_7z_extract (FrCommand  *comm,
 		       gboolean    skip_older,
 		       gboolean    junk_paths)
 {
-	GList *scan;
+	FrArchive *archive = FR_ARCHIVE (command);
+	GList     *scan;
 
-	fr_process_use_standard_locale (comm->process, TRUE);
-	fr_process_set_out_line_func (comm->process,
+	fr_process_use_standard_locale (command->process, TRUE);
+	fr_process_set_out_line_func (command->process,
 				      process_line__extract,
-				      comm);
-	fr_command_7z_begin_command (comm);
+				      command);
+	fr_command_7z_begin_command (command);
 
 	if (junk_paths)
-		fr_process_add_arg (comm->process, "e");
+		fr_process_add_arg (command->process, "e");
 	else
-		fr_process_add_arg (comm->process, "x");
+		fr_process_add_arg (command->process, "x");
 
-	fr_process_add_arg (comm->process, "-bd");
-	fr_process_add_arg (comm->process, "-y");
-	add_password_arg (comm, comm->password, FALSE);
+	fr_process_add_arg (command->process, "-bd");
+	fr_process_add_arg (command->process, "-y");
+	add_password_arg (command, archive->password, FALSE);
 
 	if (dest_dir != NULL)
-		fr_process_add_arg_concat (comm->process, "-o", dest_dir, NULL);
+		fr_process_add_arg_concat (command->process, "-o", dest_dir, NULL);
 
 	if (from_file != NULL)
-		fr_process_add_arg_concat (comm->process, "-i@", from_file, NULL);
+		fr_process_add_arg_concat (command->process, "-i@", from_file, NULL);
 
-	fr_process_add_arg (comm->process, "--");
-	fr_process_add_arg (comm->process, comm->filename);
+	fr_process_add_arg (command->process, "--");
+	fr_process_add_arg (command->process, command->filename);
 	if (from_file == NULL)
 		for (scan = file_list; scan; scan = scan->next)
-			fr_process_add_arg (comm->process, scan->data);
+			fr_process_add_arg (command->process, scan->data);
 
-	fr_process_end_command (comm->process);
+	fr_process_end_command (command->process);
 }
 
 
 static void
-fr_command_7z_test (FrCommand   *comm)
+fr_command_7z_test (FrCommand *command)
 {
-	fr_command_7z_begin_command (comm);
-	fr_process_add_arg (comm->process, "t");
-	fr_process_add_arg (comm->process, "-bd");
-	fr_process_add_arg (comm->process, "-y");
-	add_password_arg (comm, comm->password, FALSE);
-	fr_process_add_arg (comm->process, "--");
-	fr_process_add_arg (comm->process, comm->filename);
-	fr_process_end_command (comm->process);
+	FrArchive *archive = FR_ARCHIVE (command);
+
+	fr_command_7z_begin_command (command);
+	fr_process_add_arg (command->process, "t");
+	fr_process_add_arg (command->process, "-bd");
+	fr_process_add_arg (command->process, "-y");
+	add_password_arg (command, archive->password, FALSE);
+	fr_process_add_arg (command->process, "--");
+	fr_process_add_arg (command->process, command->filename);
+	fr_process_end_command (command->process);
 }
 
 
 static void
-fr_command_7z_handle_error (FrCommand   *comm,
-			    FrProcError *error)
+fr_command_7z_handle_error (FrCommand   *command,
+			    FrError *error)
 {
-	if (error->type == FR_PROC_ERROR_NONE) {
+	FrArchive *archive = FR_ARCHIVE (command);
+
+	if (error->type == FR_ERROR_NONE) {
 		FileData *first;
 		char     *basename;
 		char     *testname;
 
 		/* This is a way to fix bug #582712. */
 
-		if (comm->files->len != 1)
+		if (archive->files->len != 1)
 			return;
 
-		if (! g_str_has_suffix (comm->filename, ".001"))
+		if (! g_str_has_suffix (command->filename, ".001"))
 			return;
 
-		first = g_ptr_array_index (comm->files, 0);
-		basename = g_path_get_basename (comm->filename);
+		first = g_ptr_array_index (archive->files, 0);
+		basename = g_path_get_basename (command->filename);
 		testname = g_strconcat (first->original_path, ".001", NULL);
 
 		if (strcmp (basename, testname) == 0)
-			error->type = FR_PROC_ERROR_ASK_PASSWORD;
+			error->type = FR_ERROR_ASK_PASSWORD;
 
 		g_free (testname);
 		g_free (basename);
@@ -505,18 +512,18 @@ fr_command_7z_handle_error (FrCommand   *comm,
 	}
 
 	if (error->status <= 1) {
-		error->type = FR_PROC_ERROR_NONE;
+		error->type = FR_ERROR_NONE;
 	}
 	else {
 		GList *scan;
 
-		for (scan = g_list_last (comm->process->out.raw); scan; scan = scan->prev) {
+		for (scan = g_list_last (command->process->out.raw); scan; scan = scan->prev) {
 			char *line = scan->data;
 
 			if ((strstr (line, "Wrong password?") != NULL)
 			    || (strstr (line, "Enter password") != NULL))
 			{
-				error->type = FR_PROC_ERROR_ASK_PASSWORD;
+				error->type = FR_ERROR_ASK_PASSWORD;
 				break;
 			}
 		}
@@ -538,71 +545,71 @@ const char *sevenz_mime_types[] = { "application/x-7z-compressed",
 
 
 static const char **
-fr_command_7z_get_mime_types (FrCommand *comm)
+fr_command_7z_get_mime_types (FrArchive *archive)
 {
 	return sevenz_mime_types;
 }
 
 
-static FrCommandCap
-fr_command_7z_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_7z_get_capabilities (FrArchive  *archive,
 				const char *mime_type,
 				gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (! _g_program_is_available ("7za", check_command) && ! _g_program_is_available ("7zr", check_command) && ! _g_program_is_available ("7z", check_command))
 		return capabilities;
 
 	if (_g_mime_type_matches (mime_type, "application/x-7z-compressed")) {
-		capabilities |= FR_COMMAND_CAN_READ_WRITE | FR_COMMAND_CAN_CREATE_VOLUMES;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE | FR_ARCHIVE_CAN_CREATE_VOLUMES;
 		if (_g_program_is_available ("7z", check_command))
-			capabilities |= FR_COMMAND_CAN_ENCRYPT | FR_COMMAND_CAN_ENCRYPT_HEADER;
+			capabilities |= FR_ARCHIVE_CAN_ENCRYPT | FR_ARCHIVE_CAN_ENCRYPT_HEADER;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-7z-compressed-tar")) {
-		capabilities |= FR_COMMAND_CAN_READ_WRITE;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 		if (_g_program_is_available ("7z", check_command))
-			capabilities |= FR_COMMAND_CAN_ENCRYPT | FR_COMMAND_CAN_ENCRYPT_HEADER;
+			capabilities |= FR_ARCHIVE_CAN_ENCRYPT | FR_ARCHIVE_CAN_ENCRYPT_HEADER;
 	}
 	else if (_g_program_is_available ("7z", check_command)) {
 		if (_g_mime_type_matches (mime_type, "application/x-rar")
 		    || _g_mime_type_matches (mime_type, "application/x-cbr"))
 		{
 			if (! check_command || g_file_test ("/usr/lib/p7zip/Codecs/Rar29.so", G_FILE_TEST_EXISTS))
-				capabilities |= FR_COMMAND_CAN_READ;
+				capabilities |= FR_ARCHIVE_CAN_READ;
 		}
 		else
-			capabilities |= FR_COMMAND_CAN_READ;
+			capabilities |= FR_ARCHIVE_CAN_READ;
 
 		if (_g_mime_type_matches (mime_type, "application/x-cbz")
 		    || _g_mime_type_matches (mime_type, "application/x-ms-dos-executable")
 		    || _g_mime_type_matches (mime_type, "application/zip"))
 		{
-			capabilities |= FR_COMMAND_CAN_WRITE | FR_COMMAND_CAN_ENCRYPT;
+			capabilities |= FR_ARCHIVE_CAN_WRITE | FR_ARCHIVE_CAN_ENCRYPT;
 		}
 	}
 	else if (_g_program_is_available ("7za", check_command)) {
 		if (_g_mime_type_matches (mime_type, "application/vnd.ms-cab-compressed")
 		    || _g_mime_type_matches (mime_type, "application/zip"))
 		{
-			capabilities |= FR_COMMAND_CAN_READ;
+			capabilities |= FR_ARCHIVE_CAN_READ;
 		}
 
 		if (_g_mime_type_matches (mime_type, "application/zip"))
-			capabilities |= FR_COMMAND_CAN_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_WRITE;
 	}
 
 	/* multi-volumes are read-only */
-	if ((comm->files->len > 0) && comm->multi_volume && (capabilities & FR_COMMAND_CAN_WRITE))
-		capabilities ^= FR_COMMAND_CAN_WRITE;
+	if ((archive->files->len > 0) && archive->multi_volume && (capabilities & FR_ARCHIVE_CAN_WRITE))
+		capabilities ^= FR_ARCHIVE_CAN_WRITE;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_7z_get_packages (FrCommand  *comm,
+fr_command_7z_get_packages (FrArchive  *archive,
 			    const char *mime_type)
 {
 	if (_g_mime_type_matches (mime_type, "application/x-rar"))
@@ -630,30 +637,33 @@ static void
 fr_command_7z_class_init (FrCommand7zClass *class)
 {
 	GObjectClass   *gobject_class;
-	FrCommandClass *afc;
+	FrArchiveClass *archive_class;
+	FrCommandClass *command_class;
 
 	fr_command_7z_parent_class = g_type_class_peek_parent (class);
-	afc = (FrCommandClass*) class;
 
 	gobject_class = G_OBJECT_CLASS (class);
 	gobject_class->finalize = fr_command_7z_finalize;
 
-	afc->list             = fr_command_7z_list;
-	afc->add              = fr_command_7z_add;
-	afc->delete           = fr_command_7z_delete;
-	afc->extract          = fr_command_7z_extract;
-	afc->test             = fr_command_7z_test;
-	afc->handle_error     = fr_command_7z_handle_error;
-	afc->get_mime_types   = fr_command_7z_get_mime_types;
-	afc->get_capabilities = fr_command_7z_get_capabilities;
-	afc->get_packages     = fr_command_7z_get_packages;
+	archive_class = FR_ARCHIVE_CLASS (class);
+	archive_class->get_mime_types   = fr_command_7z_get_mime_types;
+	archive_class->get_capabilities = fr_command_7z_get_capabilities;
+	archive_class->get_packages     = fr_command_7z_get_packages;
+
+	command_class = FR_COMMAND_CLASS (class);
+	command_class->list             = fr_command_7z_list;
+	command_class->add              = fr_command_7z_add;
+	command_class->delete           = fr_command_7z_delete;
+	command_class->extract          = fr_command_7z_extract;
+	command_class->test             = fr_command_7z_test;
+	command_class->handle_error     = fr_command_7z_handle_error;
 }
 
 
 static void
 fr_command_7z_init (FrCommand7z *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-ace.c b/src/fr-command-ace.c
index 1ddb5a8..528b5c1 100644
--- a/src/fr-command-ace.c
+++ b/src/fr-command-ace.c
@@ -148,7 +148,7 @@ process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
@@ -162,7 +162,7 @@ list__begin (gpointer data)
 }
 
 
-static void
+static gboolean
 fr_command_ace_list (FrCommand  *comm)
 {
 	fr_process_set_out_line_func (comm->process, process_line, comm);
@@ -173,7 +173,8 @@ fr_command_ace_list (FrCommand  *comm)
 	fr_process_add_arg (comm->process, "-y");
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -220,7 +221,7 @@ fr_command_ace_test (FrCommand   *comm)
 
 static void
 fr_command_ace_handle_error (FrCommand   *comm,
-			     FrProcError *error)
+			     FrError *error)
 {
 	/* FIXME */
 }
@@ -230,29 +231,29 @@ const char *ace_mime_type[] = { "application/x-ace", NULL };
 
 
 static const char **
-fr_command_ace_get_mime_types (FrCommand *comm)
+fr_command_ace_get_mime_types (FrArchive *archive)
 {
 	return ace_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_ace_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_ace_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("unace", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_ace_get_packages (FrCommand  *comm,
+fr_command_ace_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("unace");
@@ -273,29 +274,32 @@ fr_command_ace_finalize (GObject *object)
 static void
 fr_command_ace_class_init (FrCommandAceClass *klass)
 {
-        GObjectClass   *gobject_class;
-        FrCommandClass *command_class;
+	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
+	FrCommandClass *command_class;
 
-        fr_command_ace_parent_class = g_type_class_peek_parent (klass);
+	fr_command_ace_parent_class = g_type_class_peek_parent (klass);
 
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_ace_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_ace_get_mime_types;
+	archive_class->get_capabilities = fr_command_ace_get_capabilities;
+	archive_class->get_packages     = fr_command_ace_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_ace_list;
 	command_class->extract          = fr_command_ace_extract;
 	command_class->test             = fr_command_ace_test;
 	command_class->handle_error     = fr_command_ace_handle_error;
-	command_class->get_mime_types   = fr_command_ace_get_mime_types;
-	command_class->get_capabilities = fr_command_ace_get_capabilities;
-	command_class->get_packages     = fr_command_ace_get_packages;
 }
 
 
 static void
 fr_command_ace_init (FrCommandAce *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-ace.h b/src/fr-command-ace.h
index 369366b..563a444 100644
--- a/src/fr-command-ace.h
+++ b/src/fr-command-ace.h
@@ -23,9 +23,7 @@
 #define FR_COMMAND_ACE_H
 
 #include <glib.h>
-#include "file-data.h"
 #include "fr-command.h"
-#include "fr-process.h"
 
 #define FR_TYPE_COMMAND_ACE            (fr_command_ace_get_type ())
 #define FR_COMMAND_ACE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), FR_TYPE_COMMAND_ACE, FrCommandAce))
diff --git a/src/fr-command-alz.c b/src/fr-command-alz.c
index 232cce2..4cd0252 100644
--- a/src/fr-command-alz.c
+++ b/src/fr-command-alz.c
@@ -142,7 +142,7 @@ process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 
 	g_free (name_field);
 	g_strfreev (fields);
@@ -201,7 +201,7 @@ list__begin (gpointer data)
 }
 
 
-static void
+static gboolean
 fr_command_alz_list (FrCommand  *comm)
 {
 	fr_process_set_out_line_func (FR_COMMAND (comm)->process, process_line, comm);
@@ -213,7 +213,8 @@ fr_command_alz_list (FrCommand  *comm)
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
 	fr_process_use_standard_locale (comm->process, TRUE);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -223,8 +224,8 @@ static void
 process_extract_line (char     *line,
 		      gpointer  data)
 {
-	FrCommand     *comm = FR_COMMAND (data);
-	FrCommandAlz  *alz_comm = FR_COMMAND_ALZ (comm);
+	FrCommand    *comm = FR_COMMAND (data);
+	FrCommandAlz *alz_comm = FR_COMMAND_ALZ (comm);
 
 	g_return_if_fail (line != NULL);
 
@@ -232,7 +233,7 @@ process_extract_line (char     *line,
 
 	if (strncmp (line, "err code(28) (invalid password)", 31) == 0) {
 		alz_comm->invalid_password = TRUE;
-		fr_process_stop (comm->process);
+		fr_process_cancel (comm->process);
 		return;
 	}
 
@@ -240,7 +241,7 @@ process_extract_line (char     *line,
 		alz_comm->extract_none = FALSE;
 	}
 	else if ((strncmp (line, "done..", 6) == 0) && alz_comm->extract_none) {
-		fr_process_stop (comm->process);
+		fr_process_cancel (comm->process);
 		return;
 	}
 }
@@ -269,7 +270,7 @@ fr_command_alz_extract (FrCommand  *comm,
 		fr_process_add_arg (comm->process, dest_dir);
 	}
 	add_codepage_arg (comm);
-	add_password_arg (comm, comm->password, TRUE);
+	add_password_arg (comm, FR_ARCHIVE (comm)->password, TRUE);
 	fr_process_add_arg (comm->process, comm->filename);
 	for (scan = file_list; scan; scan = scan->next)
 		fr_process_add_arg (comm->process, scan->data);
@@ -279,12 +280,12 @@ fr_command_alz_extract (FrCommand  *comm,
 
 static void
 fr_command_alz_handle_error (FrCommand   *comm,
-			     FrProcError *error)
+			     FrError *error)
 {
-	if ((error->type == FR_PROC_ERROR_STOPPED)) {
+	if ((error->type == FR_ERROR_STOPPED)) {
 		if  (FR_COMMAND_ALZ (comm)->extract_none ||
-		     FR_COMMAND_ALZ (comm)->invalid_password ) {
-			error->type = FR_PROC_ERROR_ASK_PASSWORD;
+		     FR_COMMAND_ALZ (comm)->invalid_password) {
+			error->type = FR_ERROR_ASK_PASSWORD;
 		}
 	}
 }
@@ -294,29 +295,29 @@ const char *alz_mime_type[] = { "application/x-alz", NULL };
 
 
 static const char **
-fr_command_alz_get_mime_types (FrCommand *comm)
+fr_command_alz_get_mime_types (FrArchive *archive)
 {
 	return alz_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_alz_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_alz_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("unalz", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_alz_get_packages (FrCommand  *comm,
+fr_command_alz_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("unalz");
@@ -338,6 +339,7 @@ static void
 fr_command_alz_class_init (FrCommandAlzClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
         fr_command_alz_parent_class = g_type_class_peek_parent (klass);
@@ -345,22 +347,24 @@ fr_command_alz_class_init (FrCommandAlzClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_alz_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_alz_get_mime_types;
+	archive_class->get_capabilities = fr_command_alz_get_capabilities;
+	archive_class->get_packages     = fr_command_alz_get_packages;
+
 	command_class = (FrCommandClass*) klass;
         command_class->list             = fr_command_alz_list;
 	command_class->add              = NULL;
 	command_class->delete           = NULL;
 	command_class->extract          = fr_command_alz_extract;
 	command_class->handle_error     = fr_command_alz_handle_error;
-	command_class->get_mime_types   = fr_command_alz_get_mime_types;
-	command_class->get_capabilities = fr_command_alz_get_capabilities;
-	command_class->get_packages     = fr_command_alz_get_packages;
 }
 
 
 static void
 fr_command_alz_init (FrCommandAlz *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-ar.c b/src/fr-command-ar.c
index 2eb4e7f..9a4dbad 100644
--- a/src/fr-command-ar.c
+++ b/src/fr-command-ar.c
@@ -176,11 +176,11 @@ process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
-static void
+static gboolean
 fr_command_ar_list (FrCommand *comm)
 {
 	fr_process_set_out_line_func (comm->process, process_line, comm);
@@ -189,7 +189,8 @@ fr_command_ar_list (FrCommand *comm)
 	fr_process_add_arg (comm->process, "tv");
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -264,7 +265,7 @@ fr_command_ar_extract (FrCommand  *comm,
 
 static void
 fr_command_ar_handle_error (FrCommand   *comm,
-			    FrProcError *error)
+			    FrError *error)
 {
 	/* FIXME */
 }
@@ -276,25 +277,25 @@ const char *ar_mime_type[] = { "application/x-ar",
 
 
 static const char **
-fr_command_ar_get_mime_types (FrCommand *comm)
+fr_command_ar_get_mime_types (FrArchive *archive)
 {
 	return ar_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_ar_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_ar_get_capabilities (FrArchive  *archive,
 			        const char *mime_type,
 				gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("ar", check_command)) {
 		if (_g_mime_type_matches (mime_type, "application/x-deb"))
-			capabilities |= FR_COMMAND_CAN_READ;
+			capabilities |= FR_ARCHIVE_CAN_READ;
 		else if (_g_mime_type_matches (mime_type, "application/x-ar"))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 
 	return capabilities;
@@ -302,7 +303,7 @@ fr_command_ar_get_capabilities (FrCommand  *comm,
 
 
 static const char *
-fr_command_ar_get_packages (FrCommand  *comm,
+fr_command_ar_get_packages (FrArchive  *archive,
 			    const char *mime_type)
 {
 	return PACKAGES ("binutils");
@@ -324,6 +325,7 @@ static void
 fr_command_ar_class_init (FrCommandArClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
         fr_command_ar_parent_class = g_type_class_peek_parent (klass);
@@ -331,22 +333,24 @@ fr_command_ar_class_init (FrCommandArClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_ar_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_ar_get_mime_types;
+	archive_class->get_capabilities = fr_command_ar_get_capabilities;
+	archive_class->get_packages     = fr_command_ar_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_ar_list;
 	command_class->add              = fr_command_ar_add;
 	command_class->delete           = fr_command_ar_delete;
 	command_class->extract          = fr_command_ar_extract;
 	command_class->handle_error     = fr_command_ar_handle_error;
-	command_class->get_mime_types   = fr_command_ar_get_mime_types;
-	command_class->get_capabilities = fr_command_ar_get_capabilities;
-	command_class->get_packages     = fr_command_ar_get_packages;
 }
 
 
 static void
 fr_command_ar_init (FrCommandAr *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-arj.c b/src/fr-command-arj.c
index b8e68bc..31a85b6 100644
--- a/src/fr-command-arj.c
+++ b/src/fr-command-arj.c
@@ -143,7 +143,7 @@ list__process_line (char     *line,
 		if (*fdata->name == 0)
 			file_data_free (fdata);
 		else
-			fr_command_add_file (comm, fdata);
+			fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 		arj_comm->fdata = NULL;
 	}
 
@@ -151,7 +151,7 @@ list__process_line (char     *line,
 }
 
 
-static void
+static gboolean
 fr_command_arj_list (FrCommand *comm)
 {
 	fr_process_set_out_line_func (comm->process, list__process_line, comm);
@@ -162,7 +162,8 @@ fr_command_arj_list (FrCommand *comm)
 	fr_process_add_arg (comm->process, "-");
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -186,10 +187,10 @@ fr_command_arj_add (FrCommand     *comm,
 	if (update)
 		fr_process_add_arg (comm->process, "-u");
 
-	if (comm->password != NULL)
-		fr_process_add_arg_concat (comm->process, "-g/", comm->password, NULL);
+	if (FR_ARCHIVE (comm)->password != NULL)
+		fr_process_add_arg_concat (comm->process, "-g/", FR_ARCHIVE (comm)->password, NULL);
 
-	switch (comm->compression) {
+	switch (FR_ARCHIVE (comm)->compression) {
 	case FR_COMPRESSION_VERY_FAST:
 		fr_process_add_arg (comm->process, "-m3"); break;
 	case FR_COMPRESSION_FAST:
@@ -262,8 +263,8 @@ fr_command_arj_extract (FrCommand  *comm,
 	if (skip_older)
 		fr_process_add_arg (comm->process, "-u");
 
-	if (comm->password != NULL)
-		fr_process_add_arg_concat (comm->process, "-g/", comm->password, NULL);
+	if (FR_ARCHIVE (comm)->password != NULL)
+		fr_process_add_arg_concat (comm->process, "-g/", FR_ARCHIVE (comm)->password, NULL);
 	else
  		fr_process_add_arg (comm->process, "-g/");
 
@@ -281,12 +282,12 @@ fr_command_arj_extract (FrCommand  *comm,
 
 
 static void
-fr_command_arj_test (FrCommand   *comm)
+fr_command_arj_test (FrCommand *comm)
 {
 	fr_process_begin_command (comm->process, "arj");
 	fr_process_add_arg (comm->process, "t");
-	if (comm->password != NULL)
-		fr_process_add_arg_concat (comm->process, "-g/", comm->password, NULL);
+	if (FR_ARCHIVE (comm)->password != NULL)
+		fr_process_add_arg_concat (comm->process, "-g/", FR_ARCHIVE (comm)->password, NULL);
 	fr_process_add_arg (comm->process, "-i");
 	fr_process_add_arg (comm->process, "-y");
 	fr_process_add_arg (comm->process, "-");
@@ -296,14 +297,14 @@ fr_command_arj_test (FrCommand   *comm)
 
 
 static void
-fr_command_arj_handle_error (FrCommand   *comm,
-			     FrProcError *error)
+fr_command_arj_handle_error (FrCommand *comm,
+			     FrError   *error)
 {
-	if (error->type != FR_PROC_ERROR_NONE) {
+	if (error->type != FR_ERROR_NONE) {
  		if (error->status <= 1)
- 			error->type = FR_PROC_ERROR_NONE;
+ 			error->type = FR_ERROR_NONE;
 		else if (error->status == 3)
- 			error->type = FR_PROC_ERROR_ASK_PASSWORD;
+ 			error->type = FR_ERROR_ASK_PASSWORD;
  	}
 }
 
@@ -312,29 +313,29 @@ const char *arj_mime_type[] = { "application/x-arj", NULL };
 
 
 static const char **
-fr_command_arj_get_mime_types (FrCommand *comm)
+fr_command_arj_get_mime_types (FrArchive *archive)
 {
 	return arj_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_arj_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_arj_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES | FR_COMMAND_CAN_ENCRYPT;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES | FR_ARCHIVE_CAN_ENCRYPT;
 	if (_g_program_is_available ("arj", check_command))
-		capabilities |= FR_COMMAND_CAN_READ_WRITE;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_arj_get_packages (FrCommand  *comm,
+fr_command_arj_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("arj");
@@ -361,6 +362,7 @@ static void
 fr_command_arj_class_init (FrCommandArjClass *klass)
 {
 	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
 	FrCommandClass *command_class;
 
 	fr_command_arj_parent_class = g_type_class_peek_parent (klass);
@@ -368,6 +370,11 @@ fr_command_arj_class_init (FrCommandArjClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_arj_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_arj_get_mime_types;
+	archive_class->get_capabilities = fr_command_arj_get_capabilities;
+	archive_class->get_packages     = fr_command_arj_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
 	command_class->list             = fr_command_arj_list;
 	command_class->add              = fr_command_arj_add;
@@ -375,16 +382,13 @@ fr_command_arj_class_init (FrCommandArjClass *klass)
 	command_class->extract          = fr_command_arj_extract;
 	command_class->test             = fr_command_arj_test;
 	command_class->handle_error     = fr_command_arj_handle_error;
-	command_class->get_mime_types   = fr_command_arj_get_mime_types;
-	command_class->get_capabilities = fr_command_arj_get_capabilities;
-	command_class->get_packages     = fr_command_arj_get_packages;
 }
 
 
 static void
 fr_command_arj_init (FrCommandArj *self)
 {
-	FrCommand *base = FR_COMMAND (self);;
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-cfile.c b/src/fr-command-cfile.c
index 32812ca..15cd91c 100644
--- a/src/fr-command-cfile.c
+++ b/src/fr-command-cfile.c
@@ -44,7 +44,7 @@ get_uncompressed_name_from_archive (FrCommand  *comm,
 	GInputStream *stream;
 	char         *filename = NULL;
 
-	if (! _g_mime_type_matches (comm->mime_type, "application/x-gzip"))
+	if (! _g_mime_type_matches (FR_ARCHIVE (comm)->mime_type, "application/x-gzip"))
 		return NULL;
 
 	file = g_file_new_for_path (archive);
@@ -126,19 +126,17 @@ list__process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
-static void
-fr_command_cfile_list (FrCommand  *comm)
+static gboolean
+fr_command_cfile_list (FrCommand *comm)
 {
-	FrCommandCFile *comm_cfile = FR_COMMAND_CFILE (comm);
-
-	if (_g_mime_type_matches (comm->mime_type, "application/x-gzip")) {
+	if (_g_mime_type_matches (FR_ARCHIVE (comm)->mime_type, "application/x-gzip")) {
 		/* gzip let us known the uncompressed size */
 
-		fr_process_set_out_line_func (FR_COMMAND (comm)->process,
+		fr_process_set_out_line_func (comm->process,
 					      list__process_line,
 					      comm);
 
@@ -147,7 +145,6 @@ fr_command_cfile_list (FrCommand  *comm)
 		fr_process_add_arg (comm->process, "-q");
 		fr_process_add_arg (comm->process, comm->filename);
 		fr_process_end_command (comm->process);
-		fr_process_start (comm->process);
 	}
 	else {
 		/* ... other compressors do not support this feature so
@@ -176,15 +173,12 @@ fr_command_cfile_list (FrCommand  *comm)
 		if (*fdata->name == 0)
 			file_data_free (fdata);
 		else
-			fr_command_add_file (comm, fdata);
-
-		comm_cfile->error.type = FR_PROC_ERROR_NONE;
-		comm_cfile->error.status = 0;
-		g_signal_emit_by_name (G_OBJECT (comm),
-				       "done",
-				       comm->action,
-				       &comm_cfile->error);
+			fr_archive_add_file (FR_ARCHIVE (comm), fdata);
+
+		return FALSE;
 	}
+
+	return TRUE;
 }
 
 
@@ -196,6 +190,7 @@ fr_command_cfile_add (FrCommand     *comm,
 		      gboolean       update,
 		      gboolean       recursive)
 {
+	FrArchive  *archive = FR_ARCHIVE (comm);
 	const char *filename;
 	char       *temp_dir;
 	char       *temp_file;
@@ -220,7 +215,7 @@ fr_command_cfile_add (FrCommand     *comm,
 
 	/**/
 
-	if (_g_mime_type_matches (comm->mime_type, "application/x-gzip")) {
+	if (_g_mime_type_matches (archive->mime_type, "application/x-gzip")) {
 		fr_process_begin_command (comm->process, "gzip");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, "--");
@@ -228,7 +223,7 @@ fr_command_cfile_add (FrCommand     *comm,
 		fr_process_end_command (comm->process);
 		compressed_filename = g_strconcat (filename, ".gz", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-bzip")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-bzip")) {
 		fr_process_begin_command (comm->process, "bzip2");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, "--");
@@ -236,7 +231,7 @@ fr_command_cfile_add (FrCommand     *comm,
 		fr_process_end_command (comm->process);
 		compressed_filename = g_strconcat (filename, ".bz2", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-compress")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-compress")) {
 		fr_process_begin_command (comm->process, "compress");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, "-f");
@@ -244,7 +239,7 @@ fr_command_cfile_add (FrCommand     *comm,
 		fr_process_end_command (comm->process);
 		compressed_filename = g_strconcat (filename, ".Z", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzip")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzip")) {
 		fr_process_begin_command (comm->process, "lzip");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, "--");
@@ -252,7 +247,7 @@ fr_command_cfile_add (FrCommand     *comm,
 		fr_process_end_command (comm->process);
 		compressed_filename = g_strconcat (filename, ".lz", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzma")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzma")) {
 		fr_process_begin_command (comm->process, "lzma");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, "--");
@@ -260,7 +255,7 @@ fr_command_cfile_add (FrCommand     *comm,
 		fr_process_end_command (comm->process);
 		compressed_filename = g_strconcat (filename, ".lzma", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-xz")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-xz")) {
 		fr_process_begin_command (comm->process, "xz");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, "--");
@@ -268,7 +263,7 @@ fr_command_cfile_add (FrCommand     *comm,
 		fr_process_end_command (comm->process);
 		compressed_filename = g_strconcat (filename, ".xz", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzop")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzop")) {
 		fr_process_begin_command (comm->process, "lzop");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, "-fU");
@@ -278,7 +273,7 @@ fr_command_cfile_add (FrCommand     *comm,
 		fr_process_end_command (comm->process);
 		compressed_filename = g_strconcat (filename, ".lzo", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-rzip")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-rzip")) {
 		fr_process_begin_command (comm->process, "rzip");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, filename);
@@ -329,11 +324,12 @@ fr_command_cfile_extract (FrCommand  *comm,
 			  gboolean    skip_older,
 			  gboolean    junk_paths)
 {
-	char *temp_dir;
-	char *dest_file;
-	char *temp_file;
-	char *uncompr_file;
-	char *compr_file;
+	FrArchive *archive = FR_ARCHIVE (comm);
+	char      *temp_dir;
+	char      *dest_file;
+	char      *temp_file;
+	char      *uncompr_file;
+	char      *compr_file;
 
 	/* copy file to the temp dir, remove the already existing file first */
 
@@ -351,7 +347,7 @@ fr_command_cfile_extract (FrCommand  *comm,
 
 	/* uncompress the file */
 
-	if (_g_mime_type_matches (comm->mime_type, "application/x-gzip")) {
+	if (_g_mime_type_matches (archive->mime_type, "application/x-gzip")) {
 		fr_process_begin_command (comm->process, "gzip");
 		fr_process_add_arg (comm->process, "-f");
 		fr_process_add_arg (comm->process, "-d");
@@ -359,14 +355,14 @@ fr_command_cfile_extract (FrCommand  *comm,
 		fr_process_add_arg (comm->process, temp_file);
 		fr_process_end_command (comm->process);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-bzip")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-bzip")) {
 		fr_process_begin_command (comm->process, "bzip2");
 		fr_process_add_arg (comm->process, "-f");
 		fr_process_add_arg (comm->process, "-d");
 		fr_process_add_arg (comm->process, temp_file);
 		fr_process_end_command (comm->process);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-compress")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-compress")) {
 		if (_g_program_is_in_path ("gzip")) {
 			fr_process_begin_command (comm->process, "gzip");
 			fr_process_add_arg (comm->process, "-d");
@@ -378,28 +374,28 @@ fr_command_cfile_extract (FrCommand  *comm,
 		fr_process_add_arg (comm->process, temp_file);
 		fr_process_end_command (comm->process);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzip")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzip")) {
 		fr_process_begin_command (comm->process, "lzip");
 		fr_process_add_arg (comm->process, "-f");
 		fr_process_add_arg (comm->process, "-d");
 		fr_process_add_arg (comm->process, temp_file);
 		fr_process_end_command (comm->process);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzma")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzma")) {
 		fr_process_begin_command (comm->process, "lzma");
 		fr_process_add_arg (comm->process, "-f");
 		fr_process_add_arg (comm->process, "-d");
 		fr_process_add_arg (comm->process, temp_file);
 		fr_process_end_command (comm->process);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-xz")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-xz")) {
 		fr_process_begin_command (comm->process, "xz");
 		fr_process_add_arg (comm->process, "-f");
 		fr_process_add_arg (comm->process, "-d");
 		fr_process_add_arg (comm->process, temp_file);
 		fr_process_end_command (comm->process);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzop")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzop")) {
 		fr_process_begin_command (comm->process, "lzop");
 		fr_process_set_working_dir (comm->process, temp_dir);
 		fr_process_add_arg (comm->process, "-d");
@@ -408,7 +404,7 @@ fr_command_cfile_extract (FrCommand  *comm,
 		fr_process_add_arg (comm->process, temp_file);
 		fr_process_end_command (comm->process);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-rzip")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-rzip")) {
 		fr_process_begin_command (comm->process, "rzip");
 		fr_process_add_arg (comm->process, "-f");
 		fr_process_add_arg (comm->process, "-d");
@@ -462,53 +458,53 @@ const char *cfile_mime_type[] = { "application/x-gzip",
 
 
 static const char **
-fr_command_cfile_get_mime_types (FrCommand *comm)
+fr_command_cfile_get_mime_types (FrArchive *archive)
 {
 	return cfile_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_cfile_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_cfile_get_capabilities (FrArchive  *archive,
 			           const char *mime_type,
 				   gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_DO_NOTHING;
+	capabilities = FR_ARCHIVE_CAN_DO_NOTHING;
 	if (_g_mime_type_matches (mime_type, "application/x-gzip")) {
 		if (_g_program_is_available ("gzip", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-bzip")) {
 		if (_g_program_is_available ("bzip2", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-compress")) {
 		if (_g_program_is_available ("compress", check_command))
-			capabilities |= FR_COMMAND_CAN_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_WRITE;
 		if (_g_program_is_available ("uncompress", check_command) || _g_program_is_available ("gzip", check_command))
-			capabilities |= FR_COMMAND_CAN_READ;
+			capabilities |= FR_ARCHIVE_CAN_READ;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-lzip")) {
 		if (_g_program_is_available ("lzip", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-lzma")) {
 		if (_g_program_is_available ("lzma", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-xz")) {
 		if (_g_program_is_available ("xz", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-lzop")) {
 		if (_g_program_is_available ("lzop", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-rzip")) {
 		if (_g_program_is_available ("rzip", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 
 	return capabilities;
@@ -516,7 +512,7 @@ fr_command_cfile_get_capabilities (FrCommand  *comm,
 
 
 static const char *
-fr_command_cfile_get_packages (FrCommand  *comm,
+fr_command_cfile_get_packages (FrArchive  *archive,
 			       const char *mime_type)
 {
 	if (_g_mime_type_matches (mime_type, "application/x-gzip"))
@@ -556,6 +552,7 @@ static void
 fr_command_cfile_class_init (FrCommandCFileClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
         fr_command_cfile_parent_class = g_type_class_peek_parent (klass);
@@ -563,21 +560,23 @@ fr_command_cfile_class_init (FrCommandCFileClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
         gobject_class->finalize = fr_command_cfile_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_cfile_get_mime_types;
+	archive_class->get_capabilities = fr_command_cfile_get_capabilities;
+	archive_class->get_packages     = fr_command_cfile_get_packages;
+
         command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_cfile_list;
 	command_class->add              = fr_command_cfile_add;
 	command_class->delete           = fr_command_cfile_delete;
 	command_class->extract          = fr_command_cfile_extract;
-	command_class->get_mime_types   = fr_command_cfile_get_mime_types;
-	command_class->get_capabilities = fr_command_cfile_get_capabilities;
-	command_class->get_packages     = fr_command_cfile_get_packages;
 }
 
 
 static void
 fr_command_cfile_init (FrCommandCFile *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-cfile.h b/src/fr-command-cfile.h
index a8e3e6b..ded2eac 100644
--- a/src/fr-command-cfile.h
+++ b/src/fr-command-cfile.h
@@ -42,7 +42,7 @@ struct _FrCommandCFile
 
 	/*<private>*/
 
-	FrProcError error;
+	FrError error;
 };
 
 struct _FrCommandCFileClass
diff --git a/src/fr-command-cpio.c b/src/fr-command-cpio.c
index 40201c7..266968a 100644
--- a/src/fr-command-cpio.c
+++ b/src/fr-command-cpio.c
@@ -157,11 +157,11 @@ list__process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
-static void
+static gboolean
 fr_command_cpio_list (FrCommand  *comm)
 {
 	fr_process_set_out_line_func (comm->process, list__process_line, comm);
@@ -170,7 +170,8 @@ fr_command_cpio_list (FrCommand  *comm)
 	fr_process_add_arg (comm->process, "-c");
 	fr_process_add_arg_concat (comm->process, "cpio -itv < ", comm->e_filename, NULL);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -218,29 +219,29 @@ const char *cpio_mime_type[] = { "application/x-cpio", NULL };
 
 
 static const char **
-fr_command_cpio_get_mime_types (FrCommand *comm)
+fr_command_cpio_get_mime_types (FrArchive *archive)
 {
 	return cpio_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_cpio_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_cpio_get_capabilities (FrArchive  *archive,
 			          const char *mime_type,
 				  gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("cpio", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_cpio_get_packages (FrCommand  *comm,
+fr_command_cpio_get_packages (FrArchive  *archive,
 			      const char *mime_type)
 {
 	return PACKAGES ("cpio");
@@ -259,29 +260,32 @@ fr_command_cpio_finalize (GObject *object)
 
 
 static void
-fr_command_cpio_class_init (FrCommandCpioClass *class)
+fr_command_cpio_class_init (FrCommandCpioClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
-        fr_command_cpio_parent_class = g_type_class_peek_parent (class);
+        fr_command_cpio_parent_class = g_type_class_peek_parent (klass);
 
-	gobject_class = G_OBJECT_CLASS (class);
+	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_cpio_finalize;
 
-	command_class = FR_COMMAND_CLASS (class);
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_cpio_get_mime_types;
+	archive_class->get_capabilities = fr_command_cpio_get_capabilities;
+	archive_class->get_packages     = fr_command_cpio_get_packages;
+
+	command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_cpio_list;
 	command_class->extract          = fr_command_cpio_extract;
-	command_class->get_mime_types   = fr_command_cpio_get_mime_types;
-	command_class->get_capabilities = fr_command_cpio_get_capabilities;
-	command_class->get_packages     = fr_command_cpio_get_packages;
 }
 
 
 static void
 fr_command_cpio_init (FrCommandCpio *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = FALSE;
 	base->propAddCanReplace            = FALSE;
diff --git a/src/fr-command-dpkg.c b/src/fr-command-dpkg.c
index 309995c..7325a71 100644
--- a/src/fr-command-dpkg.c
+++ b/src/fr-command-dpkg.c
@@ -68,7 +68,7 @@ process_metadata_line (char      *line,
 
         fdata->name = g_strdup (name);
         fdata->path = g_strdup ("DEBIAN");
-        fr_command_add_file (comm, fdata);
+        fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 static void
@@ -146,11 +146,11 @@ process_data_line (char     *line,
         if (*fdata->name == 0)
                 file_data_free (fdata);
         else
-                fr_command_add_file (comm, fdata);
+                fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
-static void
+static gboolean
 fr_command_dpkg_list (FrCommand *comm)
 {
         fr_process_set_out_line_func (comm->process, process_data_line, comm);
@@ -159,13 +159,13 @@ fr_command_dpkg_list (FrCommand *comm)
         fr_process_add_arg (comm->process, "-I");
         fr_process_add_arg (comm->process, comm->filename);
         fr_process_end_command (comm->process);
-        fr_process_start (comm->process);
 
         fr_process_begin_command (comm->process, "dpkg-deb");
         fr_process_add_arg (comm->process, "-c");
         fr_process_add_arg (comm->process, comm->filename);
         fr_process_end_command (comm->process);
-        fr_process_start (comm->process);
+
+        return TRUE;
 }
 
 
@@ -204,29 +204,29 @@ const char *dpkg_mime_type[] = { "application/x-deb", NULL };
 
 
 static const char **
-fr_command_dpkg_get_mime_types (FrCommand *comm)
+fr_command_dpkg_get_mime_types (FrArchive *archive)
 {
         return dpkg_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_dpkg_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_dpkg_get_capabilities (FrArchive  *archive,
                                   const char *mime_type,
                                   gboolean    check_command)
 {
-        FrCommandCap capabilities;
+        FrArchiveCap capabilities;
 
-        capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+        capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
         if (_g_program_is_available ("dpkg-deb", check_command))
-                capabilities |= FR_COMMAND_CAN_READ;
+                capabilities |= FR_ARCHIVE_CAN_READ;
 
         return capabilities;
 }
 
 
 static const char *
-fr_command_dpkg_get_packages (FrCommand  *comm,
+fr_command_dpkg_get_packages (FrArchive  *archive,
                               const char *mime_type)
 {
         return PACKAGES ("dpkg");
@@ -248,6 +248,7 @@ static void
 fr_command_dpkg_class_init (FrCommandDpkgClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
         fr_command_dpkg_parent_class = g_type_class_peek_parent (klass);
@@ -255,19 +256,21 @@ fr_command_dpkg_class_init (FrCommandDpkgClass *klass)
         gobject_class = G_OBJECT_CLASS (klass);
         gobject_class->finalize = fr_command_dpkg_finalize;
 
+        archive_class = FR_ARCHIVE_CLASS (klass);
+        archive_class->get_mime_types   = fr_command_dpkg_get_mime_types;
+        archive_class->get_capabilities = fr_command_dpkg_get_capabilities;
+        archive_class->get_packages     = fr_command_dpkg_get_packages;
+
         command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_dpkg_list;
         command_class->extract          = fr_command_dpkg_extract;
-        command_class->get_mime_types   = fr_command_dpkg_get_mime_types;
-        command_class->get_capabilities = fr_command_dpkg_get_capabilities;
-        command_class->get_packages     = fr_command_dpkg_get_packages;
 }
 
 
 static void
 fr_command_dpkg_init (FrCommandDpkg *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
         base->propAddCanUpdate             = FALSE;
         base->propAddCanReplace            = FALSE;
diff --git a/src/fr-command-iso.c b/src/fr-command-iso.c
index f925002..9a19863 100644
--- a/src/fr-command-iso.c
+++ b/src/fr-command-iso.c
@@ -114,7 +114,7 @@ list__process_line (char     *line,
 		fdata->name = g_strdup (_g_path_get_file_name (fdata->full_path));
 		fdata->path = _g_path_remove_level (fdata->full_path);
 
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 	}
 }
 
@@ -129,7 +129,7 @@ list__begin (gpointer data)
 }
 
 
-static void
+static gboolean
 fr_command_iso_list (FrCommand *comm)
 {
 	fr_process_set_out_line_func (comm->process, list__process_line, comm);
@@ -142,7 +142,7 @@ fr_command_iso_list (FrCommand *comm)
 	fr_process_add_arg (comm->process, "-l");
 	fr_process_end_command (comm->process);
 
-	fr_process_start (comm->process);
+	return TRUE;
 }
 
 
@@ -195,29 +195,29 @@ const char *iso_mime_type[] = { "application/x-cd-image", NULL };
 
 
 static const char **
-fr_command_iso_get_mime_types (FrCommand *comm)
+fr_command_iso_get_mime_types (FrArchive *archive)
 {
 	return iso_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_iso_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_iso_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("isoinfo", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_iso_get_packages (FrCommand  *comm,
+fr_command_iso_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("genisoimage");
@@ -241,29 +241,32 @@ fr_command_iso_finalize (GObject *object)
 
 
 static void
-fr_command_iso_class_init (FrCommandIsoClass *class)
+fr_command_iso_class_init (FrCommandIsoClass *klass)
 {
 	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
 	FrCommandClass *command_class;
 
-	fr_command_iso_parent_class = g_type_class_peek_parent (class);
+	fr_command_iso_parent_class = g_type_class_peek_parent (klass);
 
-	gobject_class = G_OBJECT_CLASS (class);
+	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_iso_finalize;
 
-	command_class = FR_COMMAND_CLASS (class);
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_iso_get_mime_types;
+	archive_class->get_capabilities = fr_command_iso_get_capabilities;
+	archive_class->get_packages     = fr_command_iso_get_packages;
+
+	command_class = FR_COMMAND_CLASS (klass);
 	command_class->list             = fr_command_iso_list;
 	command_class->extract          = fr_command_iso_extract;
-	command_class->get_mime_types   = fr_command_iso_get_mime_types;
-	command_class->get_capabilities = fr_command_iso_get_capabilities;
-	command_class->get_packages     = fr_command_iso_get_packages;
 }
 
 
 static void
 fr_command_iso_init (FrCommandIso *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = FALSE;
 	base->propAddCanReplace            = FALSE;
diff --git a/src/fr-command-jar.c b/src/fr-command-jar.c
index f7f0ef2..a72bb56 100644
--- a/src/fr-command-jar.c
+++ b/src/fr-command-jar.c
@@ -145,29 +145,29 @@ const char *jar_mime_type[] = { "application/x-java-archive",
 
 
 static const char **
-fr_command_jar_get_mime_types (FrCommand *comm)
+fr_command_jar_get_mime_types (FrArchive *archive)
 {
 	return jar_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_jar_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_jar_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("zip", check_command))
-		capabilities |= FR_COMMAND_CAN_READ_WRITE;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_jar_get_packages (FrCommand  *comm,
+fr_command_jar_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("zip,unzip");
@@ -189,6 +189,7 @@ static void
 fr_command_jar_class_init (FrCommandJarClass *klass)
 {
 	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
 	FrCommandClass *command_class;
 
 	fr_command_jar_parent_class = g_type_class_peek_parent (klass);
@@ -196,11 +197,13 @@ fr_command_jar_class_init (FrCommandJarClass *klass)
 	gobject_class = G_OBJECT_CLASS(klass);
 	gobject_class->finalize = fr_command_jar_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_jar_get_mime_types;
+	archive_class->get_capabilities = fr_command_jar_get_capabilities;
+	archive_class->get_packages     = fr_command_jar_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
 	command_class->add              = fr_command_jar_add;
-	command_class->get_mime_types   = fr_command_jar_get_mime_types;
-	command_class->get_capabilities = fr_command_jar_get_capabilities;
-	command_class->get_packages     = fr_command_jar_get_packages;
 }
 
 
diff --git a/src/fr-command-lha.c b/src/fr-command-lha.c
index dff2e54..32301ed 100644
--- a/src/fr-command-lha.c
+++ b/src/fr-command-lha.c
@@ -197,11 +197,11 @@ process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
-static void
+static gboolean
 fr_command_lha_list (FrCommand  *comm)
 {
 	fr_process_set_out_line_func (comm->process, process_line, comm);
@@ -210,7 +210,8 @@ fr_command_lha_list (FrCommand  *comm)
 	fr_process_add_arg (comm->process, "lq");
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -297,29 +298,29 @@ const char *lha_mime_type[] = { "application/x-lha", NULL };
 
 
 static const char **
-fr_command_lha_get_mime_types (FrCommand *comm)
+fr_command_lha_get_mime_types (FrArchive *archive)
 {
 	return lha_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_lha_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_lha_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("lha", check_command))
-		capabilities |= FR_COMMAND_CAN_READ_WRITE;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_lha_get_packages (FrCommand  *comm,
+fr_command_lha_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("lha");
@@ -341,6 +342,7 @@ static void
 fr_command_lha_class_init (FrCommandLhaClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
         fr_command_lha_parent_class = g_type_class_peek_parent (klass);
@@ -348,21 +350,23 @@ fr_command_lha_class_init (FrCommandLhaClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_lha_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_lha_get_mime_types;
+	archive_class->get_capabilities = fr_command_lha_get_capabilities;
+	archive_class->get_packages     = fr_command_lha_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_lha_list;
 	command_class->add              = fr_command_lha_add;
 	command_class->delete           = fr_command_lha_delete;
 	command_class->extract          = fr_command_lha_extract;
-	command_class->get_mime_types   = fr_command_lha_get_mime_types;
-	command_class->get_capabilities = fr_command_lha_get_capabilities;
-	command_class->get_packages     = fr_command_lha_get_packages;
 }
 
 
 static void
 fr_command_lha_init (FrCommandLha *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-lrzip.c b/src/fr-command-lrzip.c
index 7eb48ce..2e542e4 100644
--- a/src/fr-command-lrzip.c
+++ b/src/fr-command-lrzip.c
@@ -71,11 +71,11 @@ list__process_line (char     *line,
 	if (fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
-static void
+static gboolean
 fr_command_lrzip_list (FrCommand  *comm)
 {
 	fr_process_set_err_line_func (comm->process, list__process_line, comm);
@@ -84,7 +84,8 @@ fr_command_lrzip_list (FrCommand  *comm)
 	fr_process_add_arg (comm->process, "-i");
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -103,7 +104,7 @@ fr_command_lrzip_add (FrCommand  *comm,
 
 	/* preserve links. */
 
-	switch (comm->compression) {
+	switch (FR_ARCHIVE (comm)->compression) {
 	case FR_COMPRESSION_VERY_FAST:
 		fr_process_add_arg (comm->process, "-l"); break;
 	case FR_COMPRESSION_FAST:
@@ -161,28 +162,28 @@ const char *lrzip_mime_type[] = { "application/x-lrzip", NULL };
 
 
 static const char **
-fr_command_lrzip_get_mime_types (FrCommand *comm)
+fr_command_lrzip_get_mime_types (FrArchive *archive)
 {
 	return lrzip_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_lrzip_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_lrzip_get_capabilities (FrArchive  *archive,
 				   const char *mime_type,
 				   gboolean    check_command)
 {
-	FrCommandCap capabilities = FR_COMMAND_CAN_DO_NOTHING;
+	FrArchiveCap capabilities = FR_ARCHIVE_CAN_DO_NOTHING;
 
 	if (_g_program_is_available ("lrzip", check_command))
-		capabilities |= FR_COMMAND_CAN_READ_WRITE;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_lrzip_get_packages (FrCommand  *comm,
+fr_command_lrzip_get_packages (FrArchive  *archive,
 			       const char *mime_type)
 {
 	return PACKAGES ("lrzip");
@@ -204,6 +205,7 @@ static void
 fr_command_lrzip_class_init (FrCommandLrzipClass *klass)
 {
 	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
 	FrCommandClass *command_class;
 
 	fr_command_lrzip_parent_class = g_type_class_peek_parent (klass);
@@ -211,20 +213,22 @@ fr_command_lrzip_class_init (FrCommandLrzipClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_lrzip_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_lrzip_get_mime_types;
+	archive_class->get_capabilities = fr_command_lrzip_get_capabilities;
+	archive_class->get_packages     = fr_command_lrzip_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
 	command_class->list             = fr_command_lrzip_list;
 	command_class->add              = fr_command_lrzip_add;
 	command_class->extract          = fr_command_lrzip_extract;
-	command_class->get_mime_types   = fr_command_lrzip_get_mime_types;
-	command_class->get_capabilities = fr_command_lrzip_get_capabilities;
-	command_class->get_packages     = fr_command_lrzip_get_packages;
 }
 
 
 static void
 fr_command_lrzip_init (FrCommandLrzip *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = FALSE;
 	base->propAddCanReplace            = FALSE;
diff --git a/src/fr-command-rar.c b/src/fr-command-rar.c
index cd70e59..bf9aea9 100644
--- a/src/fr-command-rar.c
+++ b/src/fr-command-rar.c
@@ -101,7 +101,7 @@ process_line (char     *line,
 			rar_comm->odd_line = TRUE;
 		}
 		else if (strncmp (line, "Volume ", 7) == 0)
-			comm->multi_volume = TRUE;
+			FR_ARCHIVE (comm)->multi_volume = TRUE;
 		return;
 	}
 
@@ -155,7 +155,7 @@ process_line (char     *line,
 				else
 					fdata->name = g_strdup (_g_path_get_file_name (fdata->full_path));
 
-				fr_command_add_file (comm, fdata);
+				fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 				rar_comm->fdata = NULL;
 			}
 
@@ -200,7 +200,7 @@ add_password_arg (FrCommand  *comm,
 		  gboolean    disable_query)
 {
 	if ((password != NULL) && (password[0] != '\0')) {
-		if (comm->encrypt_header)
+		if (FR_ARCHIVE (comm)->encrypt_header)
 			fr_process_add_arg_concat (comm->process, "-hp", password, NULL);
 		else
 			fr_process_add_arg_concat (comm->process, "-p", password, NULL);
@@ -219,7 +219,7 @@ list__begin (gpointer data)
 }
 
 
-static void
+static gboolean
 fr_command_rar_list (FrCommand  *comm)
 {
 	rar_check_multi_volume (comm);
@@ -235,7 +235,7 @@ fr_command_rar_list (FrCommand  *comm)
 	fr_process_add_arg (comm->process, "-c-");
 	fr_process_add_arg (comm->process, "-v");
 
-	add_password_arg (comm, comm->password, TRUE);
+	add_password_arg (comm, FR_ARCHIVE (comm)->password, TRUE);
 
 	/* stop switches scanning */
 	fr_process_add_arg (comm->process, "--");
@@ -243,7 +243,7 @@ fr_command_rar_list (FrCommand  *comm)
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
 
-	fr_process_start (comm->process);
+	return TRUE;
 }
 
 
@@ -253,12 +253,13 @@ parse_progress_line (FrCommand  *comm,
 		     const char *message_format,
 		     const char *line)
 {
-	int prefix_len;
+	FrArchive *archive = FR_ARCHIVE (comm);
+	int        prefix_len;
 
 	prefix_len = strlen (prefix);
 	if (strncmp (line, prefix, prefix_len) == 0) {
-		if (comm->n_files > 1) {
-			fr_command_progress (comm, (double) ++comm->n_file / (comm->n_files + 1));
+		if (archive->n_files > 1) {
+			fr_archive_progress (archive, (double) ++archive->n_file / (archive->n_files + 1));
 		}
 		else {
 			char  filename[4096];
@@ -280,7 +281,7 @@ parse_progress_line (FrCommand  *comm,
 				filename[len - 5] = 0;
 
 			msg = g_strdup_printf (message_format, _g_path_get_file_name (filename), NULL);
-			fr_command_message (comm, msg);
+			fr_archive_message (archive, msg);
 
 			g_free (msg);
 		}
@@ -293,13 +294,14 @@ process_line__add (char     *line,
 		   gpointer  data)
 {
 	FrCommand *comm = FR_COMMAND (data);
+	FrArchive *archive = FR_ARCHIVE (comm);
 
 	if (strncmp (line, "Creating archive ", 17) == 0) {
 		const char *archive_filename = line + 17;
 		char *uri;
 
 		uri = g_filename_to_uri (archive_filename, NULL, NULL);
-		if ((comm->volume_size > 0)
+		if ((archive->volume_size > 0)
 		    && g_regex_match_simple ("^.*\\.part(0)*2\\.rar$", uri, G_REGEX_CASELESS, 0))
 		{
 			char  *volume_filename;
@@ -308,18 +310,18 @@ process_line__add (char     *line,
 			volume_filename = g_strdup (archive_filename);
 			volume_filename[strlen (volume_filename) - 5] = '1';
 			volume_file = g_file_new_for_path (volume_filename);
-			fr_command_set_multi_volume (comm, volume_file);
+			fr_archive_set_multi_volume (archive, volume_file);
 
 			g_object_unref (volume_file);
 			g_free (volume_filename);
 		}
-		fr_command_working_archive (comm, uri);
+		fr_archive_working_archive (archive, uri);
 
 		g_free (uri);
 		return;
 	}
 
-	if (comm->n_files != 0)
+	if (archive->n_files != 0)
 		parse_progress_line (comm, "Adding    ", _("Adding \"%s\""), line);
 }
 
@@ -349,7 +351,7 @@ fr_command_rar_add (FrCommand     *comm,
 	else
 		fr_process_add_arg (comm->process, "a");
 
-	switch (comm->compression) {
+	switch (FR_ARCHIVE (comm)->compression) {
 	case FR_COMPRESSION_VERY_FAST:
 		fr_process_add_arg (comm->process, "-m1"); break;
 	case FR_COMPRESSION_FAST:
@@ -360,10 +362,10 @@ fr_command_rar_add (FrCommand     *comm,
 		fr_process_add_arg (comm->process, "-m5"); break;
 	}
 
-	add_password_arg (comm, comm->password, FALSE);
+	add_password_arg (comm, FR_ARCHIVE (comm)->password, FALSE);
 
-	if (comm->volume_size > 0)
-		fr_process_add_arg_printf (comm->process, "-v%ub", comm->volume_size);
+	if (FR_ARCHIVE (comm)->volume_size > 0)
+		fr_process_add_arg_printf (comm->process, "-v%ub", FR_ARCHIVE (comm)->volume_size);
 
 	/* disable percentage indicator */
 	fr_process_add_arg (comm->process, "-Idp");
@@ -391,13 +393,13 @@ process_line__delete (char     *line,
 		char *uri;
 
 		uri = g_filename_to_uri (line + 14, NULL, NULL);
-		fr_command_working_archive (comm, uri);
+		fr_archive_working_archive (FR_ARCHIVE (comm), uri);
 		g_free (uri);
 
 		return;
 	}
 
-	if (comm->n_files != 0)
+	if (FR_ARCHIVE (comm)->n_files != 0)
 		parse_progress_line (comm, "Deleting ", _("Removing \"%s\""), line);
 }
 
@@ -440,13 +442,13 @@ process_line__extract (char     *line,
 		char *uri;
 
 		uri = g_filename_to_uri (line + 16, NULL, NULL);
-		fr_command_working_archive (comm, uri);
+		fr_archive_working_archive (FR_ARCHIVE (comm), uri);
 		g_free (uri);
 
 		return;
 	}
 
-	if (comm->n_files != 0)
+	if (FR_ARCHIVE (comm)->n_files != 0)
 		parse_progress_line (comm, "Extracting  ", _("Extracting \"%s\""), line);
 }
 
@@ -488,7 +490,7 @@ fr_command_rar_extract (FrCommand  *comm,
 	if (junk_paths)
 		fr_process_add_arg (comm->process, "-ep");
 
-	add_password_arg (comm, comm->password, TRUE);
+	add_password_arg (comm, FR_ARCHIVE (comm)->password, TRUE);
 
 	/* disable percentage indicator */
 	fr_process_add_arg (comm->process, "-Idp");
@@ -519,7 +521,7 @@ fr_command_rar_test (FrCommand   *comm)
 
 	fr_process_add_arg (comm->process, "t");
 
-	add_password_arg (comm, comm->password, TRUE);
+	add_password_arg (comm, FR_ARCHIVE (comm)->password, TRUE);
 
 	/* disable percentage indicator */
 	fr_process_add_arg (comm->process, "-Idp");
@@ -534,7 +536,7 @@ fr_command_rar_test (FrCommand   *comm)
 
 static void
 fr_command_rar_handle_error (FrCommand   *comm,
-			     FrProcError *error)
+			     FrError *error)
 {
 	GList *scan;
 
@@ -547,25 +549,25 @@ fr_command_rar_handle_error (FrCommand   *comm,
 	}
 #endif
 
-	if (error->type == FR_PROC_ERROR_NONE)
+	if (error->type == FR_ERROR_NONE)
 		return;
 
 	/*if (error->status == 3)
-		error->type = FR_PROC_ERROR_ASK_PASSWORD;
+		error->type = FR_ERROR_ASK_PASSWORD;
 	else */
 	if (error->status <= 1)
-		error->type = FR_PROC_ERROR_NONE;
+		error->type = FR_ERROR_NONE;
 
 	for (scan = g_list_last (comm->process->err.raw); scan; scan = scan->prev) {
 		char *line = scan->data;
 
 		if (strstr (line, "password incorrect") != NULL) {
-			error->type = FR_PROC_ERROR_ASK_PASSWORD;
+			error->type = FR_ERROR_ASK_PASSWORD;
 			break;
 		}
 
 		if (strstr (line, "wrong password") != NULL) {
-			error->type = FR_PROC_ERROR_ASK_PASSWORD;
+			error->type = FR_ERROR_ASK_PASSWORD;
 			break;
 		}
 
@@ -578,7 +580,7 @@ fr_command_rar_handle_error (FrCommand   *comm,
 
 			g_clear_error (&error->gerror);
 
-			error->type = FR_PROC_ERROR_MISSING_VOLUME;
+			error->type = FR_ERROR_MISSING_VOLUME;
 			volume_filename = g_path_get_basename (line + strlen ("Cannot find volume "));
 			error->gerror = g_error_new (FR_ERROR, error->status, _("Could not find the volume: %s"), volume_filename);
 			g_free (volume_filename);
@@ -594,35 +596,35 @@ const char *rar_mime_type[] = { "application/x-cbr",
 
 
 static const char **
-fr_command_rar_get_mime_types (FrCommand *comm)
+fr_command_rar_get_mime_types (FrArchive *archive)
 {
 	return rar_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_rar_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_rar_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES | FR_COMMAND_CAN_ENCRYPT | FR_COMMAND_CAN_ENCRYPT_HEADER;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES | FR_ARCHIVE_CAN_ENCRYPT | FR_ARCHIVE_CAN_ENCRYPT_HEADER;
 	if (_g_program_is_available ("rar", check_command))
-		capabilities |= FR_COMMAND_CAN_READ_WRITE | FR_COMMAND_CAN_CREATE_VOLUMES;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE | FR_ARCHIVE_CAN_CREATE_VOLUMES;
 	else if (_g_program_is_available ("unrar", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	/* multi-volumes are read-only */
-	if ((comm->files->len > 0) && comm->multi_volume && (capabilities & FR_COMMAND_CAN_WRITE))
-		capabilities ^= FR_COMMAND_CAN_WRITE;
+	if ((archive->files->len > 0) && archive->multi_volume && (capabilities & FR_ARCHIVE_CAN_WRITE))
+		capabilities ^= FR_ARCHIVE_CAN_WRITE;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_rar_get_packages (FrCommand  *comm,
+fr_command_rar_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("rar,unrar");
@@ -644,6 +646,7 @@ static void
 fr_command_rar_class_init (FrCommandRarClass *klass)
 {
 	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
 	FrCommandClass *command_class;
 
 	fr_command_rar_parent_class = g_type_class_peek_parent (klass);
@@ -651,6 +654,11 @@ fr_command_rar_class_init (FrCommandRarClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_rar_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_rar_get_mime_types;
+	archive_class->get_capabilities = fr_command_rar_get_capabilities;
+	archive_class->get_packages     = fr_command_rar_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
 	command_class->list             = fr_command_rar_list;
 	command_class->add              = fr_command_rar_add;
@@ -658,16 +666,13 @@ fr_command_rar_class_init (FrCommandRarClass *klass)
 	command_class->extract          = fr_command_rar_extract;
 	command_class->test             = fr_command_rar_test;
 	command_class->handle_error     = fr_command_rar_handle_error;
-	command_class->get_mime_types   = fr_command_rar_get_mime_types;
-	command_class->get_capabilities = fr_command_rar_get_capabilities;
-	command_class->get_packages     = fr_command_rar_get_packages;
 }
 
 
 static void
 fr_command_rar_init (FrCommandRar *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-rpm.c b/src/fr-command-rpm.c
index 39bb3a1..88b42c7 100644
--- a/src/fr-command-rpm.c
+++ b/src/fr-command-rpm.c
@@ -165,11 +165,11 @@ list__process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
-static void
+static gboolean
 fr_command_rpm_list (FrCommand *comm)
 {
 	fr_process_set_out_line_func (comm->process, list__process_line, comm);
@@ -178,7 +178,8 @@ fr_command_rpm_list (FrCommand *comm)
 	fr_process_add_arg (comm->process, "-c");
 	fr_process_add_arg_concat (comm->process, PRIVEXECDIR "rpm2cpio ", comm->e_filename, " -itv", NULL);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -219,29 +220,29 @@ const char *rpm_mime_type[] = { "application/x-rpm", NULL };
 
 
 static const char **
-fr_command_rpm_get_mime_types (FrCommand *comm)
+fr_command_rpm_get_mime_types (FrArchive *archive)
 {
 	return rpm_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_rpm_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_rpm_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("cpio", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_rpm_get_packages (FrCommand  *comm,
+fr_command_rpm_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("cpio,rpm");
@@ -264,6 +265,7 @@ static void
 fr_command_rpm_class_init (FrCommandRpmClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
         fr_command_rpm_parent_class = g_type_class_peek_parent (klass);
@@ -271,19 +273,21 @@ fr_command_rpm_class_init (FrCommandRpmClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_rpm_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_rpm_get_mime_types;
+	archive_class->get_capabilities = fr_command_rpm_get_capabilities;
+	archive_class->get_packages     = fr_command_rpm_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_rpm_list;
 	command_class->extract          = fr_command_rpm_extract;
-	command_class->get_mime_types   = fr_command_rpm_get_mime_types;
-	command_class->get_capabilities = fr_command_rpm_get_capabilities;
-	command_class->get_packages     = fr_command_rpm_get_packages;
 }
 
 
 static void
 fr_command_rpm_init (FrCommandRpm *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = FALSE;
 	base->propAddCanReplace            = FALSE;
diff --git a/src/fr-command-tar.c b/src/fr-command-tar.c
index 6cc3d85..7082a04 100644
--- a/src/fr-command-tar.c
+++ b/src/fr-command-tar.c
@@ -181,41 +181,43 @@ process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
 static void
 add_compress_arg (FrCommand *comm)
 {
-	if (_g_mime_type_matches (comm->mime_type, "application/x-compressed-tar"))
+	FrArchive *archive = FR_ARCHIVE (comm);
+
+	if (_g_mime_type_matches (archive->mime_type, "application/x-compressed-tar"))
 		fr_process_add_arg (comm->process, "-z");
 
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-bzip-compressed-tar"))
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-bzip-compressed-tar"))
 		fr_process_add_arg (comm->process, "--use-compress-program=bzip2");
 
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-tarz")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-tarz")) {
 		if (_g_program_is_in_path ("gzip"))
 			fr_process_add_arg (comm->process, "-z");
 		else
 			fr_process_add_arg (comm->process, "-Z");
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lrzip-compressed-tar"))
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lrzip-compressed-tar"))
 		fr_process_add_arg (comm->process, "--use-compress-program=lrzip");
 
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzip-compressed-tar"))
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzip-compressed-tar"))
 		fr_process_add_arg (comm->process, "--use-compress-program=lzip");
 
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzma-compressed-tar"))
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzma-compressed-tar"))
 		fr_process_add_arg (comm->process, "--use-compress-program=lzma");
 
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-xz-compressed-tar"))
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-xz-compressed-tar"))
 		fr_process_add_arg (comm->process, "--use-compress-program=xz");
 
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzop-compressed-tar"))
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzop-compressed-tar"))
 		fr_process_add_arg (comm->process, "--use-compress-program=lzop");
 
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-7z-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-7z-compressed-tar")) {
 		FrCommandTar *comm_tar = (FrCommandTar*) comm;
 		char         *option;
 
@@ -246,7 +248,7 @@ begin_tar_command (FrCommand *comm)
 }
 
 
-static void
+static gboolean
 fr_command_tar_list (FrCommand *comm)
 {
 	fr_process_set_out_line_func (comm->process, process_line, comm);
@@ -258,14 +260,15 @@ fr_command_tar_list (FrCommand *comm)
 	fr_process_add_arg (comm->process, comm->filename);
 	add_compress_arg (comm);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
 static gboolean
 can_create_a_compressed_archive (FrCommand *comm)
 {
-	return comm->creating_archive && ! _g_mime_type_matches (comm->mime_type, "application/x-7z-compressed-tar");
+	return comm->creating_archive && ! _g_mime_type_matches (FR_ARCHIVE (comm)->mime_type, "application/x-7z-compressed-tar");
 }
 
 
@@ -275,6 +278,7 @@ process_line__generic (char     *line,
 		       char     *message_format)
 {
 	FrCommand *comm = FR_COMMAND (data);
+	FrArchive *archive = FR_ARCHIVE (comm);
 
 	if (line == NULL)
 		return;
@@ -282,13 +286,13 @@ process_line__generic (char     *line,
 	if (line[strlen (line) - 1] == '/') /* ignore directories */
 		return;
 
-	if (comm->n_files > 1) {
-		double fraction = (double) ++comm->n_file / (comm->n_files + 1);
-		fr_command_progress (comm, fraction);
+	if (archive->n_files > 1) {
+		double fraction = (double) ++archive->n_file / (archive->n_files + 1);
+		fr_archive_progress (archive, fraction);
 	}
 	else {
 		char *msg = g_strdup_printf (message_format, _g_path_get_file_name (line), NULL);
-		fr_command_message (comm, msg);
+		fr_archive_message (archive, msg);
 		g_free (msg);
 	}
 }
@@ -371,9 +375,10 @@ process_line__delete (char     *line,
 static void
 begin_func__delete (gpointer data)
 {
-	FrCommand *comm = data;
-	fr_command_progress (comm, -1.0);
-	fr_command_message (comm, _("Deleting files from archive"));
+	FrArchive *archive = data;
+
+	fr_archive_progress (archive, -1.0);
+	fr_archive_message (archive, _("Deleting files from archive"));
 }
 
 
@@ -475,26 +480,23 @@ fr_command_tar_extract (FrCommand  *comm,
 static void
 begin_func__recompress (gpointer data)
 {
-	FrCommand *comm = data;
-	fr_command_progress (comm, -1.0);
-	fr_command_message (comm, _("Recompressing archive"));
+	FrArchive *archive = data;
+
+	fr_archive_progress (archive, -1.0);
+	fr_archive_message (archive, _("Recompressing archive"));
 }
 
 
 static gboolean
-gzip_continue_func (gpointer user_data)
+gzip_continue_func (FrError  **error,
+		    gpointer   user_data)
 {
-	FrCommand *comm = user_data;
-
 	/* ignore gzip warnings */
 
-	if (comm->process->error.status == 2) {
-		comm->process->error.type = FR_PROC_ERROR_NONE;
-		comm->process->error.status = 0;
-		g_clear_error (&comm->process->error.gerror);
-	}
+	if ((*error != NULL) && ((*error)->status == 2))
+		fr_clear_error (error);
 
-	return comm->process->error.status == 0;
+	return *error == NULL;
 }
 
 
@@ -502,16 +504,17 @@ static void
 fr_command_tar_recompress (FrCommand *comm)
 {
 	FrCommandTar *c_tar = FR_COMMAND_TAR (comm);
+	FrArchive    *archive = FR_ARCHIVE (comm);
 	char         *new_name = NULL;
 
 	if (can_create_a_compressed_archive (comm))
 		return;
 
-	if (_g_mime_type_matches (comm->mime_type, "application/x-compressed-tar")) {
+	if (_g_mime_type_matches (archive->mime_type, "application/x-compressed-tar")) {
 		fr_process_begin_command (comm->process, "gzip");
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
 		fr_process_set_continue_func (comm->process, gzip_continue_func, comm);
-		switch (comm->compression) {
+		switch (archive->compression) {
 		case FR_COMPRESSION_VERY_FAST:
 			fr_process_add_arg (comm->process, "-1"); break;
 		case FR_COMPRESSION_FAST:
@@ -527,10 +530,10 @@ fr_command_tar_recompress (FrCommand *comm)
 
 		new_name = g_strconcat (c_tar->uncomp_filename, ".gz", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-bzip-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-bzip-compressed-tar")) {
 		fr_process_begin_command (comm->process, "bzip2");
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
-		switch (comm->compression) {
+		switch (archive->compression) {
 		case FR_COMPRESSION_VERY_FAST:
 			fr_process_add_arg (comm->process, "-1"); break;
 		case FR_COMPRESSION_FAST:
@@ -546,7 +549,7 @@ fr_command_tar_recompress (FrCommand *comm)
 
 		new_name = g_strconcat (c_tar->uncomp_filename, ".bz2", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-tarz")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-tarz")) {
 		fr_process_begin_command (comm->process, "compress");
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
 		fr_process_add_arg (comm->process, "-f");
@@ -555,10 +558,10 @@ fr_command_tar_recompress (FrCommand *comm)
 
 		new_name = g_strconcat (c_tar->uncomp_filename, ".Z", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lrzip-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lrzip-compressed-tar")) {
 		fr_process_begin_command (comm->process, "lrzip");
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
-		switch (comm->compression) {
+		switch (archive->compression) {
 		case FR_COMPRESSION_VERY_FAST:
 			fr_process_add_arg (comm->process, "-l"); break;
 		case FR_COMPRESSION_FAST:
@@ -574,10 +577,10 @@ fr_command_tar_recompress (FrCommand *comm)
 
 		new_name = g_strconcat (c_tar->uncomp_filename, ".lrz", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzip-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzip-compressed-tar")) {
 		fr_process_begin_command (comm->process, "lzip");
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
-		switch (comm->compression) {
+		switch (archive->compression) {
 		case FR_COMPRESSION_VERY_FAST:
 			fr_process_add_arg (comm->process, "-1"); break;
 		case FR_COMPRESSION_FAST:
@@ -593,10 +596,10 @@ fr_command_tar_recompress (FrCommand *comm)
 
 		new_name = g_strconcat (c_tar->uncomp_filename, ".lz", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzma-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzma-compressed-tar")) {
 		fr_process_begin_command (comm->process, "lzma");
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
-		switch (comm->compression) {
+		switch (archive->compression) {
 		case FR_COMPRESSION_VERY_FAST:
 			fr_process_add_arg (comm->process, "-1"); break;
 		case FR_COMPRESSION_FAST:
@@ -612,10 +615,10 @@ fr_command_tar_recompress (FrCommand *comm)
 
 		new_name = g_strconcat (c_tar->uncomp_filename, ".lzma", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-xz-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-xz-compressed-tar")) {
 		fr_process_begin_command (comm->process, "xz");
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
-		switch (comm->compression) {
+		switch (archive->compression) {
 		case FR_COMPRESSION_VERY_FAST:
 			fr_process_add_arg (comm->process, "-1"); break;
 		case FR_COMPRESSION_FAST:
@@ -631,10 +634,10 @@ fr_command_tar_recompress (FrCommand *comm)
 
 		new_name = g_strconcat (c_tar->uncomp_filename, ".xz", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzop-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzop-compressed-tar")) {
 		fr_process_begin_command (comm->process, "lzop");
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
-		switch (comm->compression) {
+		switch (archive->compression) {
 		case FR_COMPRESSION_VERY_FAST:
 			fr_process_add_arg (comm->process, "-1"); break;
 		case FR_COMPRESSION_FAST:
@@ -651,12 +654,12 @@ fr_command_tar_recompress (FrCommand *comm)
 
 		new_name = g_strconcat (c_tar->uncomp_filename, ".lzo", NULL);
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-7z-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-7z-compressed-tar")) {
 		FrCommandTar *comm_tar = (FrCommandTar*) comm;
 
 		fr_process_begin_command (comm->process, comm_tar->compress_command);
 		fr_process_set_begin_func (comm->process, begin_func__recompress, comm);
-		switch (comm->compression) {
+		switch (archive->compression) {
 		case FR_COMPRESSION_VERY_FAST:
 			fr_process_add_arg (comm->process, "-mx=1"); break;
 		case FR_COMPRESSION_FAST:
@@ -716,9 +719,10 @@ fr_command_tar_recompress (FrCommand *comm)
 static void
 begin_func__uncompress (gpointer data)
 {
-	FrCommand *comm = data;
-	fr_command_progress (comm, -1.0);
-	fr_command_message (comm, _("Decompressing archive"));
+	FrArchive *archive = data;
+
+	fr_archive_progress (archive, -1.0);
+	fr_archive_message (archive, _("Decompressing archive"));
 }
 
 
@@ -727,10 +731,11 @@ get_uncompressed_name (FrCommandTar *c_tar,
 		       const char   *e_filename)
 {
 	FrCommand *comm = FR_COMMAND (c_tar);
+	FrArchive *archive = FR_ARCHIVE (comm);
 	char      *new_name = g_strdup (e_filename);
 	int        l = strlen (new_name);
 
-	if (_g_mime_type_matches (comm->mime_type, "application/x-compressed-tar")) {
+	if (_g_mime_type_matches (archive->mime_type, "application/x-compressed-tar")) {
 		/* X.tgz     -->  X.tar
 		 * X.tar.gz  -->  X.tar */
 		if (_g_filename_has_extension (e_filename, ".tgz")) {
@@ -740,7 +745,7 @@ get_uncompressed_name (FrCommandTar *c_tar,
 		else if (_g_filename_has_extension (e_filename, ".tar.gz"))
 			new_name[l - 3] = 0;
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-bzip-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-bzip-compressed-tar")) {
 		/* X.tbz2    -->  X.tar
 		 * X.tar.bz2 -->  X.tar */
 		if (_g_filename_has_extension (e_filename, ".tbz2")) {
@@ -751,7 +756,7 @@ get_uncompressed_name (FrCommandTar *c_tar,
 		else if (_g_filename_has_extension (e_filename, ".tar.bz2"))
 			new_name[l - 4] = 0;
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-tarz")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-tarz")) {
 		/* X.taz   -->  X.tar
 		 * X.tar.Z -->  X.tar */
 		if (_g_filename_has_extension (e_filename, ".taz"))
@@ -759,7 +764,7 @@ get_uncompressed_name (FrCommandTar *c_tar,
 		else if (_g_filename_has_extension (e_filename, ".tar.Z"))
 			new_name[l - 2] = 0;
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lrzip-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lrzip-compressed-tar")) {
 		/* X.tlrz     -->  X.tar
 		 * X.tar.lrz  -->  X.tar */
 		if (_g_filename_has_extension (e_filename, ".tlrz")) {
@@ -770,7 +775,7 @@ get_uncompressed_name (FrCommandTar *c_tar,
 		else if (_g_filename_has_extension (e_filename, ".tar.lrz"))
 			new_name[l - 4] = 0;
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzip-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzip-compressed-tar")) {
 		/* X.tlz     -->  X.tar
 		 * X.tar.lz  -->  X.tar */
 		if (_g_filename_has_extension (e_filename, ".tlz")) {
@@ -780,19 +785,19 @@ get_uncompressed_name (FrCommandTar *c_tar,
 		else if (_g_filename_has_extension (e_filename, ".tar.lz"))
 			new_name[l - 3] = 0;
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzma-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzma-compressed-tar")) {
 		/* X.tar.lzma --> X.tar
 		 * (There doesn't seem to be a shorthand suffix) */
 		if (_g_filename_has_extension (e_filename, ".tar.lzma"))
 			new_name[l - 5] = 0;
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-xz-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-xz-compressed-tar")) {
 		/* X.tar.xz --> X.tar
 		 * (There doesn't seem to be a shorthand suffix) */
 		if (_g_filename_has_extension (e_filename, ".tar.xz"))
 			new_name[l - 3] = 0;
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-lzop-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-lzop-compressed-tar")) {
 		/* X.tzo     -->  X.tar
 		 * X.tar.lzo -->  X.tar */
 		if (_g_filename_has_extension (e_filename, ".tzo")) {
@@ -802,7 +807,7 @@ get_uncompressed_name (FrCommandTar *c_tar,
 		else if (_g_filename_has_extension (e_filename, ".tar.lzo"))
 			new_name[l - 4] = 0;
 	}
-	else if (_g_mime_type_matches (comm->mime_type, "application/x-7z-compressed-tar")) {
+	else if (_g_mime_type_matches (archive->mime_type, "application/x-7z-compressed-tar")) {
 		/* X.tar.7z -->  X.tar */
 		if (_g_filename_has_extension (e_filename, ".tar.7z"))
 			new_name[l - 3] = 0;
@@ -837,6 +842,7 @@ static void
 fr_command_tar_uncompress (FrCommand *comm)
 {
 	FrCommandTar *c_tar = FR_COMMAND_TAR (comm);
+	FrArchive    *archive = FR_ARCHIVE (comm);
 	char         *tmp_name;
 	gboolean      archive_exists;
 
@@ -850,7 +856,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 
 	archive_exists = ! comm->creating_archive;
 
-	c_tar->name_modified = ! _g_mime_type_matches (comm->mime_type, "application/x-tar");
+	c_tar->name_modified = ! _g_mime_type_matches (archive->mime_type, "application/x-tar");
 	if (c_tar->name_modified) {
 		tmp_name = get_temp_name (c_tar, comm->filename);
 		if (archive_exists) {
@@ -865,7 +871,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 		tmp_name = g_strdup (comm->filename);
 
 	if (archive_exists) {
-		if (_g_mime_type_matches (comm->mime_type, "application/x-compressed-tar")) {
+		if (_g_mime_type_matches (archive->mime_type, "application/x-compressed-tar")) {
 			fr_process_begin_command (comm->process, "gzip");
 			fr_process_set_begin_func (comm->process, begin_func__uncompress, comm);
 			fr_process_set_continue_func (comm->process, gzip_continue_func, comm);
@@ -874,7 +880,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 			fr_process_add_arg (comm->process, tmp_name);
 			fr_process_end_command (comm->process);
 		}
-		else if (_g_mime_type_matches (comm->mime_type, "application/x-bzip-compressed-tar")) {
+		else if (_g_mime_type_matches (archive->mime_type, "application/x-bzip-compressed-tar")) {
 			fr_process_begin_command (comm->process, "bzip2");
 			fr_process_set_begin_func (comm->process, begin_func__uncompress, comm);
 			fr_process_add_arg (comm->process, "-f");
@@ -882,7 +888,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 			fr_process_add_arg (comm->process, tmp_name);
 			fr_process_end_command (comm->process);
 		}
-		else if (_g_mime_type_matches (comm->mime_type, "application/x-tarz")) {
+		else if (_g_mime_type_matches (archive->mime_type, "application/x-tarz")) {
 			if (_g_program_is_in_path ("gzip")) {
 				fr_process_begin_command (comm->process, "gzip");
 				fr_process_set_continue_func (comm->process, gzip_continue_func, comm);
@@ -894,7 +900,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 			fr_process_add_arg (comm->process, tmp_name);
 			fr_process_end_command (comm->process);
 		}
-		else if (_g_mime_type_matches (comm->mime_type, "application/x-lrzip-compressed-tar")) {
+		else if (_g_mime_type_matches (archive->mime_type, "application/x-lrzip-compressed-tar")) {
 			fr_process_begin_command (comm->process, "lrzip");
 			fr_process_set_begin_func (comm->process, begin_func__uncompress, comm);
 			fr_process_add_arg (comm->process, "-f");
@@ -902,7 +908,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 			fr_process_add_arg (comm->process, tmp_name);
 			fr_process_end_command (comm->process);
 		}
-		else if (_g_mime_type_matches (comm->mime_type, "application/x-lzip-compressed-tar")) {
+		else if (_g_mime_type_matches (archive->mime_type, "application/x-lzip-compressed-tar")) {
 			fr_process_begin_command (comm->process, "lzip");
 			fr_process_set_begin_func (comm->process, begin_func__uncompress, comm);
 			fr_process_add_arg (comm->process, "-f");
@@ -910,7 +916,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 			fr_process_add_arg (comm->process, tmp_name);
 			fr_process_end_command (comm->process);
 		}
-		else if (_g_mime_type_matches (comm->mime_type, "application/x-lzma-compressed-tar")) {
+		else if (_g_mime_type_matches (archive->mime_type, "application/x-lzma-compressed-tar")) {
 			fr_process_begin_command (comm->process, "lzma");
 			fr_process_set_begin_func (comm->process, begin_func__uncompress, comm);
 			fr_process_add_arg (comm->process, "-f");
@@ -918,7 +924,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 			fr_process_add_arg (comm->process, tmp_name);
 			fr_process_end_command (comm->process);
 		}
-		else if (_g_mime_type_matches (comm->mime_type, "application/x-xz-compressed-tar")) {
+		else if (_g_mime_type_matches (archive->mime_type, "application/x-xz-compressed-tar")) {
 			fr_process_begin_command (comm->process, "xz");
 			fr_process_set_begin_func (comm->process, begin_func__uncompress, comm);
 			fr_process_add_arg (comm->process, "-f");
@@ -926,7 +932,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 			fr_process_add_arg (comm->process, tmp_name);
 			fr_process_end_command (comm->process);
 		}
-		else if (_g_mime_type_matches (comm->mime_type, "application/x-lzop-compressed-tar")) {
+		else if (_g_mime_type_matches (archive->mime_type, "application/x-lzop-compressed-tar")) {
 			fr_process_begin_command (comm->process, "lzop");
 			fr_process_set_begin_func (comm->process, begin_func__uncompress, comm);
 			fr_process_add_arg (comm->process, "-dfU");
@@ -934,7 +940,7 @@ fr_command_tar_uncompress (FrCommand *comm)
 			fr_process_add_arg (comm->process, tmp_name);
 			fr_process_end_command (comm->process);
 		}
-		else if (_g_mime_type_matches (comm->mime_type, "application/x-7z-compressed-tar")) {
+		else if (_g_mime_type_matches (archive->mime_type, "application/x-7z-compressed-tar")) {
 			FrCommandTar *comm_tar = (FrCommandTar*) comm;
 
 			fr_process_begin_command (comm->process, comm_tar->compress_command);
@@ -961,11 +967,11 @@ fr_command_tar_uncompress (FrCommand *comm)
 
 static void
 fr_command_tar_handle_error (FrCommand   *comm,
-			     FrProcError *error)
+			     FrError *error)
 {
-	if (error->type != FR_PROC_ERROR_NONE) {
+	if (error->type != FR_ERROR_NONE) {
 		if (error->status <= 1)
-			error->type = FR_PROC_ERROR_NONE;
+			error->type = FR_ERROR_NONE;
 	}
 }
 
@@ -984,61 +990,61 @@ const char *tar_mime_types[] = { "application/x-compressed-tar",
 
 
 static const char **
-fr_command_tar_get_mime_types (FrCommand *comm)
+fr_command_tar_get_mime_types (FrArchive *archive)
 {
 	return tar_mime_types;
 }
 
 
-static FrCommandCap
-fr_command_tar_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_tar_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 
 	/* In solaris gtar is present under /usr/sfw/bin */
 	if (! _g_program_is_available ("tar", check_command) && ! _g_program_is_available ("/usr/sfw/bin/gtar", check_command))
 		return capabilities;
 
 	if (_g_mime_type_matches (mime_type, "application/x-tar")) {
-		capabilities |= FR_COMMAND_CAN_READ_WRITE;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-compressed-tar")) {
 		if (_g_program_is_available ("gzip", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-bzip-compressed-tar")) {
 		if (_g_program_is_available ("bzip2", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-tarz")) {
 		if (_g_program_is_available ("compress", check_command) && _g_program_is_available ("uncompress", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 		else if (_g_program_is_available ("gzip", check_command))
-			capabilities |= FR_COMMAND_CAN_READ;
+			capabilities |= FR_ARCHIVE_CAN_READ;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-lrzip-compressed-tar")) {
 		if (_g_program_is_available ("lrzip", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-lzip-compressed-tar")) {
 		if (_g_program_is_available ("lzip", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-lzma-compressed-tar")) {
 		if (_g_program_is_available ("lzma", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-xz-compressed-tar")) {
 		if (_g_program_is_available ("xz", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-lzop-compressed-tar")) {
 		if (_g_program_is_available ("lzop", check_command))
-			capabilities |= FR_COMMAND_CAN_READ_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 	}
 	else if (_g_mime_type_matches (mime_type, "application/x-7z-compressed-tar")) {
 		char *try_command[3] = { "7za", "7zr", "7z" };
@@ -1046,7 +1052,7 @@ fr_command_tar_get_capabilities (FrCommand  *comm,
 
 		for (i = 0; i < G_N_ELEMENTS (try_command); i++) {
 			if (_g_program_is_available (try_command[i], check_command)) {
-				capabilities |= FR_COMMAND_CAN_WRITE;
+				capabilities |= FR_ARCHIVE_CAN_WRITE;
 				break;
 			}
 		}
@@ -1057,12 +1063,12 @@ fr_command_tar_get_capabilities (FrCommand  *comm,
 
 
 static void
-fr_command_tar_set_mime_type (FrCommand  *comm,
+fr_command_tar_set_mime_type (FrArchive  *archive,
 		 	      const char *mime_type)
 {
-	FrCommandTar *comm_tar = FR_COMMAND_TAR (comm);
+	FrCommandTar *comm_tar = FR_COMMAND_TAR (archive);
 
-	FR_COMMAND_CLASS (fr_command_tar_parent_class)->set_mime_type (comm, mime_type);
+	FR_ARCHIVE_CLASS (fr_command_tar_parent_class)->set_mime_type (archive, mime_type);
 
 	if (_g_mime_type_matches (mime_type, "application/x-7z-compressed-tar")) {
 		char *try_command[3] = { "7za", "7zr", "7z" };
@@ -1079,7 +1085,7 @@ fr_command_tar_set_mime_type (FrCommand  *comm,
 
 
 static const char *
-fr_command_tar_get_packages (FrCommand  *comm,
+fr_command_tar_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	if (_g_mime_type_matches (mime_type, "application/x-tar"))
@@ -1142,6 +1148,7 @@ static void
 fr_command_tar_class_init (FrCommandTarClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
         fr_command_tar_parent_class = g_type_class_peek_parent (klass);
@@ -1149,25 +1156,27 @@ fr_command_tar_class_init (FrCommandTarClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_tar_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_tar_get_mime_types;
+	archive_class->get_capabilities = fr_command_tar_get_capabilities;
+	archive_class->set_mime_type    = fr_command_tar_set_mime_type;
+	archive_class->get_packages     = fr_command_tar_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_tar_list;
 	command_class->add              = fr_command_tar_add;
 	command_class->delete           = fr_command_tar_delete;
 	command_class->extract          = fr_command_tar_extract;
 	command_class->handle_error     = fr_command_tar_handle_error;
-	command_class->get_mime_types   = fr_command_tar_get_mime_types;
-	command_class->get_capabilities = fr_command_tar_get_capabilities;
-	command_class->set_mime_type    = fr_command_tar_set_mime_type;
 	command_class->recompress       = fr_command_tar_recompress;
 	command_class->uncompress       = fr_command_tar_uncompress;
-	command_class->get_packages     = fr_command_tar_get_packages;
 }
 
 
 static void
 fr_command_tar_init (FrCommandTar *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate              = FALSE;
 	base->propAddCanReplace             = FALSE;
diff --git a/src/fr-command-unarchiver.c b/src/fr-command-unarchiver.c
index 0a7e97f..2cad7f7 100644
--- a/src/fr-command-unarchiver.c
+++ b/src/fr-command-unarchiver.c
@@ -112,7 +112,7 @@ list_command_completed (gpointer data)
 					fdata->name = g_strdup (_g_path_get_file_name (fdata->full_path));
 				fdata->path = _g_path_remove_level (fdata->full_path);
 
-				fr_command_add_file (FR_COMMAND (unar_comm), fdata);
+				fr_archive_add_file (FR_ARCHIVE (unar_comm), fdata);
 			}
 		}
 	}
@@ -121,7 +121,7 @@ list_command_completed (gpointer data)
 }
 
 
-static void
+static gboolean
 fr_command_unarchiver_list (FrCommand  *comm)
 {
 	FrCommandUnarchiver *unar_comm = FR_COMMAND_UNARCHIVER (comm);
@@ -134,12 +134,12 @@ fr_command_unarchiver_list (FrCommand  *comm)
 	fr_process_begin_command (comm->process, "lsar");
 	fr_process_set_end_func (comm->process, list_command_completed, comm);
 	fr_process_add_arg (comm->process, "-j");
-	if ((comm->password != NULL) && (comm->password[0] != '\0'))
-		fr_process_add_arg_concat (comm->process, "-password=", comm->password, NULL);
+	if ((FR_ARCHIVE (comm)->password != NULL) && (FR_ARCHIVE (comm)->password[0] != '\0'))
+		fr_process_add_arg_concat (comm->process, "-password=", FR_ARCHIVE (comm)->password, NULL);
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
 
-	fr_process_start (comm->process);
+	return TRUE;
 }
 
 
@@ -148,6 +148,7 @@ process_line__extract (char     *line,
 		       gpointer  data)
 {
 	FrCommand           *comm = FR_COMMAND (data);
+	FrArchive           *archive = FR_ARCHIVE (comm);
 	FrCommandUnarchiver *unar_comm = FR_COMMAND_UNARCHIVER (comm);
 
 	if (line == NULL)
@@ -159,12 +160,12 @@ process_line__extract (char     *line,
 	if (unar_comm->n_line == 1)
 		return;
 
-	if (comm->n_files > 1) {
-		double fraction = (double) ++comm->n_file / (comm->n_files + 1);
-		fr_command_progress (comm, CLAMP (fraction, 0.0, 1.0));
+	if (archive->n_files > 1) {
+		double fraction = (double) ++archive->n_file / (archive->n_files + 1);
+		fr_archive_progress (archive, CLAMP (fraction, 0.0, 1.0));
 	}
 	else
-		fr_command_message (comm, line);
+		fr_archive_message (archive, line);
 }
 
 
@@ -197,8 +198,8 @@ fr_command_unarchiver_extract (FrCommand  *comm,
 	if (junk_paths)
 		fr_process_add_arg (comm->process, "-D");
 
-	if ((comm->password != NULL) && (comm->password[0] != '\0'))
-		fr_process_add_arg_concat (comm->process, "-password=", comm->password, NULL);
+	if ((FR_ARCHIVE (comm)->password != NULL) && (FR_ARCHIVE (comm)->password[0] != '\0'))
+		fr_process_add_arg_concat (comm->process, "-password=", FR_ARCHIVE (comm)->password, NULL);
 
 	if (dest_dir != NULL)
 		fr_process_add_arg_concat (comm->process, "-output-directory=", dest_dir, NULL);
@@ -214,7 +215,7 @@ fr_command_unarchiver_extract (FrCommand  *comm,
 
 static void
 fr_command_unarchiver_handle_error (FrCommand   *comm,
-				    FrProcError *error)
+				    FrError *error)
 {
 	GList *scan;
 
@@ -225,14 +226,14 @@ fr_command_unarchiver_handle_error (FrCommand   *comm,
 	}
 #endif
 
-	if (error->type == FR_PROC_ERROR_NONE)
+	if (error->type == FR_ERROR_NONE)
 		return;
 
 	for (scan = g_list_last (comm->process->err.raw); scan; scan = scan->prev) {
 		char *line = scan->data;
 
 		if (strstr (line, "password") != NULL) {
-			error->type = FR_PROC_ERROR_ASK_PASSWORD;
+			error->type = FR_ERROR_ASK_PASSWORD;
 			break;
 		}
 	}
@@ -245,29 +246,29 @@ const char *unarchiver_mime_type[] = { "application/x-cbr",
 
 
 static const char **
-fr_command_unarchiver_get_mime_types (FrCommand *comm)
+fr_command_unarchiver_get_mime_types (FrArchive *archive)
 {
 	return unarchiver_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_unarchiver_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_unarchiver_get_capabilities (FrArchive  *archive,
 					const char *mime_type,
 					gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_DO_NOTHING;
+	capabilities = FR_ARCHIVE_CAN_DO_NOTHING;
 	if (_g_program_is_available ("lsar", check_command) && _g_program_is_available ("unar", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_unarchiver_get_packages (FrCommand  *comm,
+fr_command_unarchiver_get_packages (FrArchive  *archive,
 				    const char *mime_type)
 {
 	return PACKAGES ("unarchiver");
@@ -294,6 +295,7 @@ static void
 fr_command_unarchiver_class_init (FrCommandUnarchiverClass *klass)
 {
 	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
 	FrCommandClass *command_class;
 
 	fr_command_unarchiver_parent_class = g_type_class_peek_parent (klass);
@@ -301,20 +303,22 @@ fr_command_unarchiver_class_init (FrCommandUnarchiverClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_unarchiver_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_unarchiver_get_mime_types;
+	archive_class->get_capabilities = fr_command_unarchiver_get_capabilities;
+	archive_class->get_packages     = fr_command_unarchiver_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
 	command_class->list             = fr_command_unarchiver_list;
 	command_class->extract          = fr_command_unarchiver_extract;
 	command_class->handle_error     = fr_command_unarchiver_handle_error;
-	command_class->get_mime_types   = fr_command_unarchiver_get_mime_types;
-	command_class->get_capabilities = fr_command_unarchiver_get_capabilities;
-	command_class->get_packages     = fr_command_unarchiver_get_packages;
 }
 
 
 static void
 fr_command_unarchiver_init (FrCommandUnarchiver *self)
 {
-	FrCommand *base = FR_COMMAND (self);;
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propExtractCanAvoidOverwrite = TRUE;
 	base->propExtractCanSkipOlder      = FALSE;
diff --git a/src/fr-command-unstuff.c b/src/fr-command-unstuff.c
index f696fc6..84b3999 100644
--- a/src/fr-command-unstuff.c
+++ b/src/fr-command-unstuff.c
@@ -166,7 +166,7 @@ process_line (char     *line,
 	fdata->modified = time (NULL);
 
 	unstuff_comm->fdata = fdata;
-	fr_command_add_file (comm, fdata);
+	fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 
 	unlink (real_filename);
 	g_free (real_filename);
@@ -182,7 +182,7 @@ list__begin (gpointer data)
 }
 
 
-static void
+static gboolean
 fr_command_unstuff_list (FrCommand *comm)
 {
 	char *arg, *path;
@@ -209,7 +209,8 @@ fr_command_unstuff_list (FrCommand *comm)
 	fr_process_add_arg (comm->process, filename);
 	g_free (filename);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -260,12 +261,12 @@ fr_command_unstuff_extract (FrCommand  *comm,
 
 static void
 fr_command_unstuff_handle_error (FrCommand   *comm,
-				 FrProcError *error)
+				 FrError *error)
 {
-	if ((error->type != FR_PROC_ERROR_NONE)
+	if ((error->type != FR_ERROR_NONE)
 	    && (error->status <= 1))
 	{
-		error->type = FR_PROC_ERROR_NONE;
+		error->type = FR_ERROR_NONE;
 	}
 }
 
@@ -274,29 +275,29 @@ const char *unstuff_mime_type[] = { "application/x-stuffit", NULL };
 
 
 static const char **
-fr_command_unstuff_get_mime_types (FrCommand *comm)
+fr_command_unstuff_get_mime_types (FrArchive *archive)
 {
 	return unstuff_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_unstuff_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_unstuff_get_capabilities (FrArchive  *archive,
 			             const char *mime_type,
 				     gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("unstuff", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_unstuff_get_packages (FrCommand  *comm,
+fr_command_unstuff_get_packages (FrArchive  *archive,
 			         const char *mime_type)
 {
 	return PACKAGES ("unstaff");
@@ -327,6 +328,7 @@ static void
 fr_command_unstuff_class_init (FrCommandUnstuffClass *klass)
 {
 	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
 	FrCommandClass *command_class;
 
 	fr_command_unstuff_parent_class = g_type_class_peek_parent (klass);
@@ -334,20 +336,22 @@ fr_command_unstuff_class_init (FrCommandUnstuffClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_unstuff_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_unstuff_get_mime_types;
+	archive_class->get_capabilities = fr_command_unstuff_get_capabilities;
+	archive_class->get_packages     = fr_command_unstuff_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
 	command_class->list             = fr_command_unstuff_list;
 	command_class->extract          = fr_command_unstuff_extract;
 	command_class->handle_error     = fr_command_unstuff_handle_error;
-	command_class->get_mime_types   = fr_command_unstuff_get_mime_types;
-	command_class->get_capabilities = fr_command_unstuff_get_capabilities;
-	command_class->get_packages     = fr_command_unstuff_get_packages;
 }
 
 
 static void
 fr_command_unstuff_init (FrCommandUnstuff *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = FALSE;
 	base->propAddCanReplace            = FALSE;
diff --git a/src/fr-command-zip.c b/src/fr-command-zip.c
index 189aff4..efc9578 100644
--- a/src/fr-command-zip.c
+++ b/src/fr-command-zip.c
@@ -150,7 +150,7 @@ list__process_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (comm), fdata);
 }
 
 
@@ -174,7 +174,7 @@ list__begin (gpointer data)
 }
 
 
-static void
+static gboolean
 fr_command_zip_list (FrCommand  *comm)
 {
 	fr_process_set_out_line_func (comm->process, list__process_line, comm);
@@ -185,7 +185,8 @@ fr_command_zip_list (FrCommand  *comm)
 	fr_process_add_arg (comm->process, "--");
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
-	fr_process_start (comm->process);
+
+	return TRUE;
 }
 
 
@@ -193,17 +194,18 @@ static void
 process_line__common (char     *line,
 		      gpointer  data)
 {
-	FrCommand  *comm = FR_COMMAND (data);
+	FrCommand *comm = FR_COMMAND (data);
+	FrArchive *archive = FR_ARCHIVE (comm);
 
 	if (line == NULL)
 		return;
 
-	if (comm->n_files > 1) {
-		double fraction = (double) ++comm->n_file / (comm->n_files + 1);
-		fr_command_progress (comm, fraction);
+	if (archive->n_files > 1) {
+		double fraction = (double) ++archive->n_file / (archive->n_files + 1);
+		fr_archive_progress (archive, fraction);
 	}
 	else
-		fr_command_message (comm, line);
+		fr_archive_message (archive, line);
 }
 
 
@@ -232,9 +234,9 @@ fr_command_zip_add (FrCommand     *comm,
 	if (update)
 		fr_process_add_arg (comm->process, "-u");
 
-	add_password_arg (comm, comm->password);
+	add_password_arg (comm, FR_ARCHIVE (comm)->password);
 
-	switch (comm->compression) {
+	switch (FR_ARCHIVE (comm)->compression) {
 	case FR_COMPRESSION_VERY_FAST:
 		fr_process_add_arg (comm->process, "-1"); break;
 	case FR_COMPRESSION_FAST:
@@ -313,7 +315,7 @@ fr_command_zip_extract (FrCommand  *comm,
 		fr_process_add_arg (comm->process, "-u");
 	if (junk_paths)
 		fr_process_add_arg (comm->process, "-j");
-	add_password_arg (comm, comm->password);
+	add_password_arg (comm, FR_ARCHIVE (comm)->password);
 
 	fr_process_add_arg (comm->process, "--");
 	fr_process_add_arg (comm->process, comm->filename);
@@ -335,7 +337,7 @@ fr_command_zip_test (FrCommand   *comm)
 {
 	fr_process_begin_command (comm->process, "unzip");
 	fr_process_add_arg (comm->process, "-t");
-	add_password_arg (comm, comm->password);
+	add_password_arg (comm, FR_ARCHIVE (comm)->password);
 	fr_process_add_arg (comm->process, "--");
 	fr_process_add_arg (comm->process, comm->filename);
 	fr_process_end_command (comm->process);
@@ -343,19 +345,19 @@ fr_command_zip_test (FrCommand   *comm)
 
 
 static void
-fr_command_zip_handle_error (FrCommand   *comm,
-			     FrProcError *error)
+fr_command_zip_handle_error (FrCommand *comm,
+			     FrError   *error)
 {
-	if (error->type != FR_PROC_ERROR_NONE) {
+	if (error->type != FR_ERROR_NONE) {
 		if (error->status <= 1)
-			error->type = FR_PROC_ERROR_NONE;
+			error->type = FR_ERROR_NONE;
 		else if ((error->status == 82) || (error->status == 5))
-			error->type = FR_PROC_ERROR_ASK_PASSWORD;
+			error->type = FR_ERROR_ASK_PASSWORD;
 		else {
 			GList *output;
 			GList *scan;
 
-			if (comm->action == FR_ACTION_TESTING_ARCHIVE)
+			if (FR_ARCHIVE (comm)->action == FR_ACTION_TESTING_ARCHIVE)
 				output = comm->process->out.raw;
 			else
 				output = comm->process->err.raw;
@@ -364,7 +366,7 @@ fr_command_zip_handle_error (FrCommand   *comm,
 				char *line = scan->data;
 
 				if (strstr (line, "incorrect password") != NULL) {
-					error->type = FR_PROC_ERROR_ASK_PASSWORD;
+					error->type = FR_ERROR_ASK_PASSWORD;
 					break;
 				}
 			}
@@ -380,35 +382,35 @@ const char *zip_mime_type[] = { "application/x-cbz",
 
 
 static const char **
-fr_command_zip_get_mime_types (FrCommand *comm)
+fr_command_zip_get_mime_types (FrArchive *archive)
 {
 	return zip_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_zip_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_zip_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES | FR_COMMAND_CAN_ENCRYPT;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES | FR_ARCHIVE_CAN_ENCRYPT;
 	if (_g_program_is_available ("zip", check_command)) {
 		if (strcmp (mime_type, "application/x-ms-dos-executable") == 0)
-			capabilities |= FR_COMMAND_CAN_READ;
+			capabilities |= FR_ARCHIVE_CAN_READ;
 		else
-			capabilities |= FR_COMMAND_CAN_WRITE;
+			capabilities |= FR_ARCHIVE_CAN_WRITE;
 	}
 	if (_g_program_is_available ("unzip", check_command))
-		capabilities |= FR_COMMAND_CAN_READ;
+		capabilities |= FR_ARCHIVE_CAN_READ;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_zip_get_packages (FrCommand  *comm,
+fr_command_zip_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("zip,unzip");
@@ -430,6 +432,7 @@ static void
 fr_command_zip_class_init (FrCommandZipClass *klass)
 {
 	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
 	FrCommandClass *command_class;
 
 	fr_command_zip_parent_class = g_type_class_peek_parent (klass);
@@ -437,6 +440,11 @@ fr_command_zip_class_init (FrCommandZipClass *klass)
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_zip_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_zip_get_mime_types;
+	archive_class->get_capabilities = fr_command_zip_get_capabilities;
+	archive_class->get_packages     = fr_command_zip_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
 	command_class->list             = fr_command_zip_list;
 	command_class->add              = fr_command_zip_add;
@@ -444,16 +452,13 @@ fr_command_zip_class_init (FrCommandZipClass *klass)
 	command_class->extract          = fr_command_zip_extract;
 	command_class->test             = fr_command_zip_test;
 	command_class->handle_error     = fr_command_zip_handle_error;
-	command_class->get_mime_types   = fr_command_zip_get_mime_types;
-	command_class->get_capabilities = fr_command_zip_get_capabilities;
-	command_class->get_packages     = fr_command_zip_get_packages;
 }
 
 
 static void
 fr_command_zip_init (FrCommandZip *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = TRUE;
diff --git a/src/fr-command-zoo.c b/src/fr-command-zoo.c
index 955a61a..13245e0 100644
--- a/src/fr-command-zoo.c
+++ b/src/fr-command-zoo.c
@@ -207,11 +207,11 @@ process_zoo_line (char     *line,
 	if (*fdata->name == 0)
 		file_data_free (fdata);
 	else
-		fr_command_add_file (zoo_comm, fdata);
+		fr_archive_add_file (FR_ARCHIVE (zoo_comm), fdata);
 }
 
 
-static void
+static gboolean
 fr_command_zoo_list (FrCommand  *zoo_comm)
 {
 	fr_process_set_out_line_func (zoo_comm->process, process_zoo_line, zoo_comm);
@@ -220,7 +220,8 @@ fr_command_zoo_list (FrCommand  *zoo_comm)
 	fr_process_add_arg (zoo_comm->process, "lq");
 	fr_process_add_arg (zoo_comm->process, zoo_comm->filename);
 	fr_process_end_command (zoo_comm->process);
-	fr_process_start (zoo_comm->process);
+
+	return TRUE;
 }
 
 
@@ -316,29 +317,29 @@ const char *zoo_mime_type[] = { "application/x-zoo", NULL };
 
 
 static const char **
-fr_command_zoo_get_mime_types (FrCommand *comm)
+fr_command_zoo_get_mime_types (FrArchive *archive)
 {
 	return zoo_mime_type;
 }
 
 
-static FrCommandCap
-fr_command_zoo_get_capabilities (FrCommand  *comm,
+static FrArchiveCap
+fr_command_zoo_get_capabilities (FrArchive  *archive,
 			         const char *mime_type,
 				 gboolean    check_command)
 {
-	FrCommandCap capabilities;
+	FrArchiveCap capabilities;
 
-	capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES;
+	capabilities = FR_ARCHIVE_CAN_STORE_MANY_FILES;
 	if (_g_program_is_available ("zoo", check_command))
-		capabilities |= FR_COMMAND_CAN_READ_WRITE;
+		capabilities |= FR_ARCHIVE_CAN_READ_WRITE;
 
 	return capabilities;
 }
 
 
 static const char *
-fr_command_zoo_get_packages (FrCommand  *comm,
+fr_command_zoo_get_packages (FrArchive  *archive,
 			     const char *mime_type)
 {
 	return PACKAGES ("zoo");
@@ -360,6 +361,7 @@ static void
 fr_command_zoo_class_init (FrCommandZooClass *klass)
 {
         GObjectClass   *gobject_class;
+        FrArchiveClass *archive_class;
         FrCommandClass *command_class;
 
         fr_command_zoo_parent_class = g_type_class_peek_parent (klass);
@@ -367,22 +369,24 @@ fr_command_zoo_class_init (FrCommandZooClass *klass)
         gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_command_zoo_finalize;
 
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->get_mime_types   = fr_command_zoo_get_mime_types;
+	archive_class->get_capabilities = fr_command_zoo_get_capabilities;
+	archive_class->get_packages     = fr_command_zoo_get_packages;
+
 	command_class = FR_COMMAND_CLASS (klass);
         command_class->list             = fr_command_zoo_list;
 	command_class->add              = fr_command_zoo_add;
 	command_class->delete           = fr_command_zoo_delete;
 	command_class->extract          = fr_command_zoo_extract;
 	command_class->test             = fr_command_zoo_test;
-	command_class->get_mime_types   = fr_command_zoo_get_mime_types;
-	command_class->get_capabilities = fr_command_zoo_get_capabilities;
-	command_class->get_packages     = fr_command_zoo_get_packages;
 }
 
 
 static void
 fr_command_zoo_init (FrCommandZoo *self)
 {
-	FrCommand *base = FR_COMMAND (self);
+	FrArchive *base = FR_ARCHIVE (self);
 
 	base->propAddCanUpdate             = TRUE;
 	base->propAddCanReplace            = FALSE;
diff --git a/src/fr-command.c b/src/fr-command.c
index 7baf4c3..621498a 100644
--- a/src/fr-command.c
+++ b/src/fr-command.c
@@ -3,7 +3,7 @@
 /*
  *  File-Roller
  *
- *  Copyright (C) 2001 The Free Software Foundation, Inc.
+ *  Copyright (C) 2001, 2003, 2007, 2008 Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -19,234 +19,701 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <string.h>
+#include <config.h>
 #include <unistd.h>
-#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
 #include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
 #include "file-data.h"
 #include "file-utils.h"
 #include "fr-command.h"
-#include "fr-enum-types.h"
-#include "fr-marshal.h"
-#include "fr-proc-error.h"
+#include "fr-error.h"
 #include "fr-process.h"
+#include "gio-utils.h"
 #include "glib-utils.h"
 
-#define INITIAL_SIZE 256
 
+#define MAX_CHUNK_LEN (NCARGS * 2 / 3) /* Max command line length */
+#define LIST_LENGTH_TO_USE_FILE 10     /* FIXME: find a good value */
+#ifndef NCARGS
+#define NCARGS _POSIX_ARG_MAX
+#endif
+
+
+/* -- DroppedItemsData -- */
+
+
+typedef struct {
+	FrCommand           *command;
+	GList               *item_list;
+	char                *base_dir;
+	char                *dest_dir;
+	gboolean             update;
+	char                *password;
+	gboolean             encrypt_header;
+	FrCompression        compression;
+	guint                volume_size;
+	GCancellable        *cancellable;
+	GAsyncReadyCallback  callback;
+	gpointer             user_data;
+} DroppedItemsData;
+
+
+static DroppedItemsData *
+dropped_items_data_new (FrCommand           *command,
+			GList               *item_list,
+			const char          *base_dir,
+			const char          *dest_dir,
+			gboolean             update,
+			const char          *password,
+			gboolean             encrypt_header,
+			FrCompression        compression,
+			guint                volume_size,
+			GCancellable        *cancellable,
+			GAsyncReadyCallback  callback,
+			gpointer             user_data)
+{
+	DroppedItemsData *data;
+
+	data = g_new0 (DroppedItemsData, 1);
+	data->command = command;
+	data->item_list = _g_string_list_dup (item_list);
+	if (base_dir != NULL)
+		data->base_dir = g_strdup (base_dir);
+	if (dest_dir != NULL)
+		data->dest_dir = g_strdup (dest_dir);
+	data->update = update;
+	if (password != NULL)
+		data->password = g_strdup (password);
+	data->encrypt_header = encrypt_header;
+	data->compression = compression;
+	data->volume_size = volume_size;
+	data->cancellable = _g_object_ref (cancellable);
+	data->callback = callback;
+	data->user_data = user_data;
+
+	return data;
+}
+
+
+static void
+dropped_items_data_free (DroppedItemsData *data)
+{
+	if (data == NULL)
+		return;
+	_g_string_list_free (data->item_list);
+	g_free (data->base_dir);
+	g_free (data->dest_dir);
+	g_free (data->password);
+	_g_object_unref (data->cancellable);
+	g_free (data);
+}
+
+
+/* -- XferData -- */
 
-G_DEFINE_TYPE (FrCommand, fr_command, G_TYPE_OBJECT)
 
+typedef struct {
+	FrArchive          *archive;
+	char               *uri;
+	FrAction            action;
+	GList              *file_list;
+	char               *base_uri;
+	char               *dest_dir;
+	gboolean            update;
+	gboolean            recursive;
+	char               *tmp_dir;
+	guint               source_id;
+	char               *password;
+	gboolean            encrypt_header;
+	FrCompression       compression;
+	guint               volume_size;
+	GCancellable       *cancellable;
+	GSimpleAsyncResult *result;
+} XferData;
+
+
+static void
+xfer_data_free (XferData *data)
+{
+	if (data == NULL)
+		return;
+
+	g_free (data->uri);
+	g_free (data->password);
+	_g_string_list_free (data->file_list);
+	g_free (data->base_uri);
+	g_free (data->dest_dir);
+	g_free (data->tmp_dir);
+	_g_object_unref (data->cancellable);
+	_g_object_unref (data->result);
+	g_free (data);
+}
+
+
+/* -- FrCommand -- */
+
+
+G_DEFINE_TYPE (FrCommand, fr_command, FR_TYPE_ARCHIVE)
 
-/* Signals */
-enum {
-	START,
-	DONE,
-	PROGRESS,
-	MESSAGE,
-	WORKING_ARCHIVE,
-	LAST_SIGNAL
-};
 
 /* Properties */
 enum {
         PROP_0,
-        PROP_FILE,
-        PROP_MIME_TYPE,
         PROP_PROCESS,
-        PROP_PASSWORD,
-        PROP_ENCRYPT_HEADER,
-        PROP_COMPRESSION,
-        PROP_VOLUME_SIZE
+        PROP_FILENAME
+};
+
+
+struct _FrCommandPrivate {
+	GFile            *local_copy;
+	gboolean          is_remote;
+	char             *temp_dir;
+	gboolean          continue_adding_dropped_items;
+	DroppedItemsData *dropped_items_data;
+	char             *temp_extraction_dir;
+	gboolean          remote_extraction;
 };
 
 
-static guint fr_command_signals[LAST_SIGNAL] = { 0 };
+static void
+_fr_command_remove_temp_work_dir (FrCommand *self)
+{
+	if (self->priv->temp_dir == NULL)
+		return;
+	_g_path_remove_directory (self->priv->temp_dir);
+	g_free (self->priv->temp_dir);
+	self->priv->temp_dir = NULL;
+}
+
+
+static const char *
+_fr_command_get_temp_work_dir (FrCommand *self)
+{
+	_fr_command_remove_temp_work_dir (self);
+	self->priv->temp_dir = _g_path_get_temp_work_dir (NULL);
+	return self->priv->temp_dir;
+}
+
+
+/* -- copy_archive_to_remote_location -- */
+
 
+static void
+copy_archive_to_remote_location_done (GError   *error,
+				      gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
 
-char *action_names[] = { "NONE",
-			 "CREATING_NEW_ARCHIVE",
-			 "LOADING_ARCHIVE",
-			 "LISTING_CONTENT",
-			 "DELETING_FILES",
-			 "TESTING_ARCHIVE",
-			 "GETTING_FILE_LIST",
-			 "COPYING_FILES_FROM_REMOTE",
-			 "ADDING_FILES",
-			 "EXTRACTING_FILES",
-			 "COPYING_FILES_TO_REMOTE",
-			 "CREATING_ARCHIVE",
-			 "SAVING_REMOTE_ARCHIVE" };
+	if (error != NULL)
+		g_simple_async_result_set_from_error (xfer_data->result, error);
+	g_simple_async_result_complete_in_idle (xfer_data->result);
+
+	xfer_data_free (xfer_data);
+}
 
 
 static void
-base_fr_command_list (FrCommand  *comm)
+copy_archive_to_remote_location_progress (goffset   current_file,
+					  goffset   total_files,
+					  GFile    *source,
+					  GFile    *destination,
+					  goffset   current_num_bytes,
+					  goffset   total_num_bytes,
+					  gpointer  user_data)
 {
+	XferData *xfer_data = user_data;
+
+	g_signal_emit_by_name (xfer_data->archive,
+			       "progress",
+			       (double) current_num_bytes / total_num_bytes);
 }
 
 
 static void
-base_fr_command_add (FrCommand     *comm,
-		     const char    *from_file,
-		     GList         *file_list,
-		     const char    *base_dir,
-		     gboolean       update,
-		     gboolean       recursive)
+copy_archive_to_remote_location (FrArchive          *archive,
+				 GSimpleAsyncResult *result,
+				 GCancellable       *cancellable)
 {
+	XferData *xfer_data;
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = _g_object_ref (archive);
+	xfer_data->result = _g_object_ref (result);
+	xfer_data->cancellable = _g_object_ref (cancellable);
+
+	g_copy_file_async (FR_COMMAND (xfer_data->archive)->priv->local_copy,
+			   fr_archive_get_file (xfer_data->archive),
+			   G_FILE_COPY_OVERWRITE,
+			   G_PRIORITY_DEFAULT,
+			   xfer_data->cancellable,
+			   copy_archive_to_remote_location_progress,
+			   xfer_data,
+			   copy_archive_to_remote_location_done,
+			   xfer_data);
 }
 
 
+/* -- copy_extracted_files_to_destination -- */
+
+
 static void
-base_fr_command_delete (FrCommand  *comm,
-		        const char *from_file,
-			GList       *file_list)
+move_here (FrArchive    *archive,
+	   GCancellable *cancellable)
 {
+	const char *extraction_destination;
+	char       *content_uri;
+	char       *parent;
+	char       *parent_parent;
+	char       *new_content_uri;
+	GFile      *source, *destination, *parent_file;
+	GError     *error = NULL;
+
+	extraction_destination = fr_archive_get_last_extraction_destination (archive);
+	content_uri = _g_uri_get_dir_content_if_unique (extraction_destination);
+	if (content_uri == NULL)
+		return;
+
+	parent = _g_path_remove_level (content_uri);
+
+	if (_g_uri_cmp (parent, extraction_destination) == 0) {
+		char *new_uri;
+
+		new_uri = _g_uri_create_alternative_for_uri (extraction_destination);
+
+		source = g_file_new_for_uri (extraction_destination);
+		destination = g_file_new_for_uri (new_uri);
+		if (! g_file_move (source, destination, 0, NULL, NULL, NULL, &error)) {
+			g_warning ("could not rename %s to %s: %s", extraction_destination, new_uri, error->message);
+			g_clear_error (&error);
+		}
+		g_object_unref (source);
+		g_object_unref (destination);
+
+		fr_archive_set_last_extraction_destination (archive, new_uri);
+
+		g_free (parent);
+
+		content_uri = _g_uri_get_dir_content_if_unique (new_uri);
+		if (content_uri == NULL)
+			return;
+
+		parent = _g_path_remove_level (content_uri);
+	}
+
+	parent_parent = _g_path_remove_level (parent);
+	new_content_uri = _g_uri_create_alternative (parent_parent, _g_path_get_file_name (content_uri));
+
+	source = g_file_new_for_uri (content_uri);
+	destination = g_file_new_for_uri (new_content_uri);
+	if (! g_file_move (source, destination, 0, NULL, NULL, NULL, &error)) {
+		g_warning ("could not rename %s to %s: %s", content_uri, new_content_uri, error->message);
+		g_clear_error (&error);
+	}
+
+	parent_file = g_file_new_for_uri (parent);
+	if (! g_file_delete (parent_file, cancellable, &error)) {
+		g_warning ("could not remove directory %s: %s", parent, error->message);
+		g_clear_error (&error);
+	}
+	g_object_unref (parent_file);
+
+	fr_archive_set_last_extraction_destination (archive, new_content_uri);
+
+	g_free (parent_parent);
+	g_free (parent);
+	g_free (content_uri);
 }
 
 
 static void
-base_fr_command_extract (FrCommand  *comm,
-		         const char *from_file,
-			 GList      *file_list,
-			 const char *dest_dir,
-			 gboolean    overwrite,
-			 gboolean    skip_older,
-			 gboolean    junk_paths)
+copy_extracted_files_done (GError   *error,
+			   gpointer  user_data)
 {
+	XferData  *xfer_data = user_data;
+	FrCommand *self = FR_COMMAND (xfer_data->archive);
+
+	if (error != NULL)
+		g_simple_async_result_set_from_error (xfer_data->result, error);
+
+	_g_path_remove_directory (self->priv->temp_extraction_dir);
+	g_free (self->priv->temp_extraction_dir);
+	self->priv->temp_extraction_dir = NULL;
+
+	if ((error == NULL) && (xfer_data->archive->extract_here))
+		move_here (xfer_data->archive, xfer_data->cancellable);
+
+	g_simple_async_result_complete_in_idle (xfer_data->result);
+
+	xfer_data_free (xfer_data);
 }
 
 
 static void
-base_fr_command_test (FrCommand *comm)
+copy_extracted_files_progress (goffset   current_file,
+                               goffset   total_files,
+                               GFile    *source,
+                               GFile    *destination,
+                               goffset   current_num_bytes,
+                               goffset   total_num_bytes,
+                               gpointer  user_data)
 {
+	FrArchive *archive = user_data;
+
+	g_signal_emit_by_name (archive,
+			       "progress",
+			       (double) current_file / (total_files + 1));
 }
 
 
 static void
-base_fr_command_uncompress (FrCommand *comm)
+copy_extracted_files_to_destination (FrArchive          *archive,
+				     GSimpleAsyncResult *result,
+				     GCancellable       *cancellable)
 {
+	FrCommand *self = FR_COMMAND (archive);
+	XferData  *xfer_data;
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = _g_object_ref (archive);
+	xfer_data->result = _g_object_ref (result);
+	xfer_data->cancellable = _g_object_ref (cancellable);
+
+	g_directory_copy_async (self->priv->temp_extraction_dir,
+				fr_archive_get_last_extraction_destination (archive),
+				G_FILE_COPY_OVERWRITE,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				copy_extracted_files_progress,
+				archive,
+				copy_extracted_files_done,
+				xfer_data);
 }
 
 
+/* -- virtual functions  -- */
+
+
 static void
-base_fr_command_recompress (FrCommand *comm)
+fr_command_add (FrCommand  *self,
+		const char *from_file,
+		GList      *file_list,
+		const char *base_dir,
+		gboolean    update,
+		gboolean    recursive)
 {
+	FrArchive *archive = FR_ARCHIVE (self);
+
+	archive->action = FR_ACTION_ADDING_FILES;
+	fr_process_set_out_line_func (self->process, NULL, NULL);
+	fr_process_set_err_line_func (self->process, NULL, NULL);
+
+	FR_COMMAND_GET_CLASS (G_OBJECT (self))->add (self,
+						     from_file,
+						     file_list,
+						     base_dir,
+						     update,
+						     recursive);
 }
 
 
 static void
-base_fr_command_handle_error (FrCommand   *comm,
-			      FrProcError *error)
+fr_command_delete (FrCommand  *self,
+		   const char *from_file,
+		   GList      *file_list)
 {
+	FrArchive *archive = FR_ARCHIVE (self);
+
+	archive->action = FR_ACTION_DELETING_FILES;
+	fr_process_set_out_line_func (self->process, NULL, NULL);
+	fr_process_set_err_line_func (self->process, NULL, NULL);
+
+	FR_COMMAND_GET_CLASS (G_OBJECT (self))->delete (self, from_file, file_list);
 }
 
 
-const char **void_mime_types = { NULL };
+static void
+fr_command_extract (FrCommand  *self,
+		    const char *from_file,
+		    GList      *file_list,
+		    const char *dest_dir,
+		    gboolean    overwrite,
+		    gboolean    skip_older,
+		    gboolean    junk_paths)
+{
+	FrArchive *archive = FR_ARCHIVE (self);
+
+	archive->action = FR_ACTION_EXTRACTING_FILES;
+	fr_process_set_out_line_func (self->process, NULL, NULL);
+	fr_process_set_err_line_func (self->process, NULL, NULL);
+
+	FR_COMMAND_GET_CLASS (G_OBJECT (self))->extract (self,
+							 from_file,
+							 file_list,
+							 dest_dir,
+							 overwrite,
+							 skip_older,
+							 junk_paths);
+}
 
 
-static const char **
-base_fr_command_get_mime_types (FrCommand *comm)
+static void
+fr_command_test (FrCommand *self)
 {
-	return void_mime_types;
+	FrArchive *archive = FR_ARCHIVE (self);
+
+	archive->action = FR_ACTION_TESTING_ARCHIVE;
+	fr_process_set_out_line_func (self->process, NULL, NULL);
+	fr_process_set_err_line_func (self->process, NULL, NULL);
+
+	FR_COMMAND_GET_CLASS (G_OBJECT (self))->test (self);
 }
 
 
-static FrCommandCap
-base_fr_command_get_capabilities (FrCommand  *comm,
-			          const char *mime_type,
-			          gboolean    check_command)
+static void
+fr_command_uncompress (FrCommand *self)
 {
-	return FR_COMMAND_CAN_DO_NOTHING;
+	FR_COMMAND_GET_CLASS (G_OBJECT (self))->uncompress (self);
 }
 
 
 static void
-base_fr_command_set_mime_type (FrCommand  *comm,
-			       const char *mime_type)
+fr_command_recompress (FrCommand *self)
 {
-	comm->mime_type = _g_str_get_static (mime_type);
-	fr_command_update_capabilities (comm);
+	FR_COMMAND_GET_CLASS (G_OBJECT (self))->recompress (self);
 }
 
 
-static const char *
-base_fr_command_get_packages (FrCommand  *comm,
-			      const char *mime_type)
+static gboolean
+fr_command_handle_process_error (FrCommand     *self,
+				 GAsyncResult  *result,
+				 FrError      **error)
 {
-	return NULL;
+	self->process->restart = FALSE;
+
+	if (! fr_process_execute_finish (self->process, result, error)) {
+		if (g_error_matches ((*error)->gerror, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			(*error)->type = FR_ERROR_STOPPED;
+
+		if ((*error)->type != FR_ERROR_STOPPED)
+			FR_COMMAND_GET_CLASS (G_OBJECT (self))->handle_error (self, (*error));
+
+		if (self->process->restart) {
+			fr_process_restart (self->process);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
 }
 
 
+/* -- command signals -- */
+
+
+#if 0
+
+
 static void
-fr_command_start (FrProcess *process,
-		  gpointer   data)
+process_start_cb (FrProcess *process,
+		  gpointer   user_data)
 {
-	FrCommand *comm = FR_COMMAND (data);
+	FrCommand *self = user_data;
+	FrArchive *archive = FR_ARCHIVE (self);
 
-	g_signal_emit (G_OBJECT (comm),
-		       fr_command_signals[START],
-		       0,
-		       comm->action);
+	fr_archive_action_started (archive, archive->action);
 }
 
 
 static void
-fr_command_done (FrProcess   *process,
-		 FrProcError *error,
-		 gpointer     data)
+process_done_cb (FrProcess *process,
+		 FrError   *error,
+		 gpointer   user_data)
 {
-	FrCommand *comm = FR_COMMAND (data);
+	FrCommand *self = user_data;
+	FrArchive *archive = FR_ARCHIVE (self);
+
+        process->restart = FALSE;
+        if (error->type != FR_ERROR_STOPPED)
+                fr_command_handle_error (self, error);
+
+        if (process->restart) {
+                fr_process_start (process);
+                return;
+        }
+
+	switch (archive->action) {
+	case FR_ACTION_DELETING_FILES:
+		if (error->type == FR_ERROR_NONE) {
+			if (! g_file_has_uri_scheme (fr_archive_get_file (archive), "file")) {
+				copy_archive_to_remote_location (self, action);
+				return;
+			}
+		}
+		break;
 
-	comm->process->restart = FALSE;
-	if (error->type != FR_PROC_ERROR_STOPPED)
-		fr_command_handle_error (comm, error);
+	case FR_ACTION_ADDING_FILES:
+		if (error->type == FR_ERROR_NONE) {
+			fr_archive_remove_temp_work_dir (archive);
+			if (self->priv->continue_adding_dropped_items) {
+				add_dropped_items (self->priv->dropped_items_data);
+				return;
+			}
+			if (self->priv->dropped_items_data != NULL) {
+				dropped_items_data_free (self->priv->dropped_items_data);
+				self->priv->dropped_items_data = NULL;
+			}
+			/* the name of the volumes are different from the
+			 * original name */
+			if (archive->multi_volume)
+				fr_archive_change_name (archive, self->filename);
+			if (! g_file_has_uri_scheme (fr_archive_get_file (archive), "file")) {
+				copy_archive_to_remote_location (self, action);
+				return;
+			}
+		}
+		break;
 
-	if (comm->process->restart) {
-		fr_process_start (comm->process);
-		return;
-	}
+	case FR_ACTION_EXTRACTING_FILES:
+		if (error->type == FR_ERROR_NONE) {
+			if (self->priv->remote_extraction) {
+				copy_extracted_files_to_destination (archive);
+				return;
+			}
+			else if (archive->extract_here)
+				move_here (self);
+		}
+		else {
+			/* if an error occurred during extraction remove the
+			 * temp extraction dir, if used. */
+			g_print ("action_performed: ERROR!\n");
+
+			if ((self->priv->remote_extraction) && (self->priv->temp_extraction_dir != NULL)) {
+				_g_path_remove_directory (self->priv->temp_extraction_dir);
+				g_free (self->priv->temp_extraction_dir);
+				self->priv->temp_extraction_dir = NULL;
+			}
+
+			if (archive->extract_here)
+				_g_uri_remove_directory (fr_archive_get_last_extraction_destination (archive));
+		}
+		break;
+
+	case FR_ACTION_LISTING_CONTENT:
+                /* order the list by name to speed up search */
+                g_ptr_array_sort (archive->files, file_data_compare_by_path);
 
-	if (comm->action == FR_ACTION_LISTING_CONTENT) {
-		/* order the list by name to speed up search */
-		g_ptr_array_sort (comm->files, file_data_compare_by_path);
+		/* the name of the volumes are different from the
+		 * original name */
+		if (archive->multi_volume)
+			fr_archive_change_name (archive, self->filename);
+		fr_archive_update_capabilities (archive);
+		break;
+
+	default:
+		/* nothing */
+		break;
 	}
 
-	g_signal_emit (G_OBJECT (comm),
-		       fr_command_signals[DONE],
-		       0,
-		       comm->action,
-		       error);
+        g_signal_emit_by_name (self,
+        		       "done",
+        		       archive->action,
+        		       error);
+}
+
+
+#endif
+
+
+static gboolean
+process_sticky_only_cb (FrProcess *process,
+                        gpointer   user_data)
+{
+	FrArchive *archive = user_data;
+
+	fr_archive_set_stoppable (archive, FALSE);
+        return TRUE;
 }
 
 
 static void
-fr_command_set_process (FrCommand *comm,
-		        FrProcess *process)
+_fr_command_set_process (FrCommand *self,
+			 FrProcess *process)
 {
-	if (comm->process != NULL) {
-		g_signal_handlers_disconnect_matched (G_OBJECT (comm->process),
-					      G_SIGNAL_MATCH_DATA,
-					      0,
-					      0, NULL,
-					      0,
-					      comm);
-		g_object_unref (G_OBJECT (comm->process));
-		comm->process = NULL;
+	if (self->process != NULL) {
+		g_signal_handlers_disconnect_matched (G_OBJECT (self->process),
+						      G_SIGNAL_MATCH_DATA,
+						      0,
+						      0, NULL,
+						      0,
+						      self);
+		g_object_unref (G_OBJECT (self->process));
+		self->process = NULL;
 	}
 
 	if (process == NULL)
 		return;
 
-	g_object_ref (G_OBJECT (process));
-	comm->process = process;
-	g_signal_connect (G_OBJECT (comm->process),
-			  "start",
-			  G_CALLBACK (fr_command_start),
-			  comm);
-	g_signal_connect (G_OBJECT (comm->process),
-			  "done",
-			  G_CALLBACK (fr_command_done),
-			  comm);
+	self->process = g_object_ref (process);
+	g_signal_connect (G_OBJECT (self->process),
+			  "sticky_only",
+			  G_CALLBACK (process_sticky_only_cb),
+			  self);
+}
+
+
+static void
+_fr_command_set_filename (FrCommand  *self,
+			  const char *filename)
+{
+	if (self->filename != NULL) {
+		g_free (self->filename);
+		self->filename = NULL;
+	}
+
+	if (self->e_filename != NULL) {
+		g_free (self->e_filename);
+		self->e_filename = NULL;
+	}
+
+	if (filename != NULL) {
+		if (! g_path_is_absolute (filename)) {
+			char *current_dir;
+
+			current_dir = g_get_current_dir ();
+			self->filename = g_strconcat (current_dir,
+						      "/",
+						      filename,
+						      NULL);
+			g_free (current_dir);
+		}
+		else
+			self->filename = g_strdup (filename);
+
+		self->e_filename = g_shell_quote (self->filename);
+
+		debug (DEBUG_INFO, "filename : %s\n", self->filename);
+		debug (DEBUG_INFO, "e_filename : %s\n", self->e_filename);
+	}
+
+	g_signal_emit_by_name (self, "working-archive", self->filename);
+}
+
+
+static void
+_fr_command_set_filename_from_file (FrCommand *self,
+				    GFile     *file)
+{
+	char *filename;
+
+	filename = g_file_get_path (file);
+	_fr_command_set_filename (self, filename);
+
+	g_free (filename);
 }
 
 
@@ -256,32 +723,16 @@ fr_command_set_property (GObject      *object,
 			 const GValue *value,
 			 GParamSpec   *pspec)
 {
-	FrCommand *comm;
+	FrCommand *self;
 
-	comm = FR_COMMAND (object);
+	self = FR_COMMAND (object);
 
 	switch (prop_id) {
 	case PROP_PROCESS:
-		fr_command_set_process (comm, g_value_get_object (value));
-		break;
-	case PROP_FILE:
-		fr_command_set_file (comm, g_value_get_object (value));
-		break;
-	case PROP_MIME_TYPE:
-		fr_command_set_mime_type (comm, g_value_get_string (value));
-		break;
-	case PROP_PASSWORD:
-		g_free (comm->password);
-		comm->password = g_strdup (g_value_get_string (value));
+		_fr_command_set_process (self, g_value_get_object (value));
 		break;
-	case PROP_ENCRYPT_HEADER:
-		comm->encrypt_header = g_value_get_boolean (value);
-		break;
-	case PROP_COMPRESSION:
-		comm->compression = g_value_get_enum (value);
-		break;
-	case PROP_VOLUME_SIZE:
-		comm->volume_size = g_value_get_uint (value);
+	case PROP_FILENAME:
+		_fr_command_set_filename_from_file (self, g_value_get_object (value));
 		break;
 	default:
 		break;
@@ -295,31 +746,18 @@ fr_command_get_property (GObject    *object,
 			 GValue     *value,
 			 GParamSpec *pspec)
 {
-	FrCommand *comm;
+	FrCommand *self;
+	GFile     *file;
 
-	comm = FR_COMMAND (object);
+	self = FR_COMMAND (object);
 
 	switch (prop_id) {
 	case PROP_PROCESS:
-		g_value_set_object (value, comm->process);
-		break;
-	case PROP_FILE:
-		g_value_take_object (value, g_file_new_for_path (comm->filename));
-		break;
-	case PROP_MIME_TYPE:
-		g_value_set_static_string (value, comm->mime_type);
+		g_value_set_object (value, self->process);
 		break;
-	case PROP_PASSWORD:
-		g_value_set_string (value, comm->password);
-		break;
-	case PROP_ENCRYPT_HEADER:
-		g_value_set_boolean (value, comm->encrypt_header);
-		break;
-	case PROP_COMPRESSION:
-		g_value_set_enum (value, comm->compression);
-		break;
-	case PROP_VOLUME_SIZE:
-		g_value_set_uint (value, comm->volume_size);
+	case PROP_FILENAME:
+		file = g_file_new_for_path (self->filename);
+		g_value_take_object (value, file);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -331,483 +769,2733 @@ fr_command_get_property (GObject    *object,
 static void
 fr_command_finalize (GObject *object)
 {
-	FrCommand* comm;
+	FrCommand *self;
 
 	g_return_if_fail (object != NULL);
 	g_return_if_fail (FR_IS_COMMAND (object));
 
-	comm = FR_COMMAND (object);
+	self = FR_COMMAND (object);
 
-	g_free (comm->filename);
-	g_free (comm->e_filename);
-	g_free (comm->password);
-	if (comm->files != NULL)
-		_g_ptr_array_free_full (comm->files, (GFunc) file_data_free, NULL);
-	fr_command_set_process (comm, NULL);
+	_g_object_unref (self->process);
+	_fr_command_remove_temp_work_dir (self);
+	if (self->priv->dropped_items_data != NULL) {
+		dropped_items_data_free (self->priv->dropped_items_data);
+		self->priv->dropped_items_data = NULL;
+	}
+	g_free (self->priv->temp_extraction_dir);
 
-	/* Chain up */
 	if (G_OBJECT_CLASS (fr_command_parent_class)->finalize)
 		G_OBJECT_CLASS (fr_command_parent_class)->finalize (object);
 }
 
 
-static void
-fr_command_class_init (FrCommandClass *klass)
-{
-	GObjectClass *gobject_class;
-
-	fr_command_parent_class = g_type_class_peek_parent (klass);
-
-	/* virtual functions */
+/* -- load -- */
 
-	gobject_class = G_OBJECT_CLASS (klass);
-	gobject_class->finalize = fr_command_finalize;
-	gobject_class->set_property = fr_command_set_property;
-	gobject_class->get_property = fr_command_get_property;
 
-	klass->list             = base_fr_command_list;
-	klass->add              = base_fr_command_add;
-	klass->delete           = base_fr_command_delete;
-	klass->extract          = base_fr_command_extract;
-	klass->test             = base_fr_command_test;
-	klass->uncompress       = base_fr_command_uncompress;
-	klass->recompress       = base_fr_command_recompress;
-	klass->handle_error     = base_fr_command_handle_error;
-	klass->get_mime_types   = base_fr_command_get_mime_types;
-	klass->get_capabilities = base_fr_command_get_capabilities;
-	klass->set_mime_type    = base_fr_command_set_mime_type;
-	klass->get_packages     = base_fr_command_get_packages;
-	klass->start            = NULL;
-	klass->done             = NULL;
-	klass->progress         = NULL;
-	klass->message          = NULL;
-
-	/* signals */
-
-	fr_command_signals[START] =
-		g_signal_new ("start",
-			      G_TYPE_FROM_CLASS (klass),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (FrCommandClass, start),
-			      NULL, NULL,
-			      fr_marshal_VOID__INT,
-			      G_TYPE_NONE,
-			      1, G_TYPE_INT);
-	fr_command_signals[DONE] =
-		g_signal_new ("done",
-			      G_TYPE_FROM_CLASS (klass),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (FrCommandClass, done),
-			      NULL, NULL,
-			      fr_marshal_VOID__INT_BOXED,
-			      G_TYPE_NONE, 2,
-			      G_TYPE_INT,
-			      FR_TYPE_PROC_ERROR);
-	fr_command_signals[PROGRESS] =
-		g_signal_new ("progress",
-			      G_TYPE_FROM_CLASS (klass),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (FrCommandClass, progress),
-			      NULL, NULL,
-			      fr_marshal_VOID__DOUBLE,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_DOUBLE);
-	fr_command_signals[MESSAGE] =
-		g_signal_new ("message",
-			      G_TYPE_FROM_CLASS (klass),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (FrCommandClass, message),
-			      NULL, NULL,
-			      fr_marshal_VOID__STRING,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_STRING);
-	fr_command_signals[WORKING_ARCHIVE] =
-			g_signal_new ("working_archive",
-				      G_TYPE_FROM_CLASS (klass),
-				      G_SIGNAL_RUN_LAST,
-				      G_STRUCT_OFFSET (FrCommandClass, working_archive),
-				      NULL, NULL,
-				      fr_marshal_VOID__STRING,
-				      G_TYPE_NONE, 1,
-				      G_TYPE_STRING);
+typedef struct {
+	FrArchive          *archive;
+	char               *password;
+	GCancellable       *cancellable;
+	GSimpleAsyncResult *result;
+} LoadData;
 
-	/* properties */
 
-	g_object_class_install_property (gobject_class,
-					 PROP_PROCESS,
-					 g_param_spec_object ("process",
-							      "Process",
-							      "The process object used by the command",
-							      FR_TYPE_PROCESS,
-							      G_PARAM_READWRITE));
-	g_object_class_install_property (gobject_class,
-					 PROP_FILE,
-					 g_param_spec_object ("file",
-							      "File",
-							      "The archive local file",
-							      G_TYPE_FILE,
-							      G_PARAM_READWRITE));
-	g_object_class_install_property (gobject_class,
-					 PROP_MIME_TYPE,
-					 g_param_spec_string ("mime-type",
-							      "Mime type",
-							      "The file mime-type",
-							      NULL,
-							      G_PARAM_READWRITE));
-	g_object_class_install_property (gobject_class,
-					 PROP_PASSWORD,
-					 g_param_spec_string ("password",
-							      "Password",
-							      "The archive password",
-							      NULL,
-							      G_PARAM_READWRITE));
-	g_object_class_install_property (gobject_class,
-					 PROP_ENCRYPT_HEADER,
-					 g_param_spec_boolean ("encrypt-header",
-							       "Encrypt header",
-							       "Whether to encrypt the archive header when creating the archive",
-							       FALSE,
-							       G_PARAM_READWRITE));
-	g_object_class_install_property (gobject_class,
-					 PROP_COMPRESSION,
-					 g_param_spec_enum ("compression",
-							    "Compression type",
-							    "The compression type to use when creating the archive",
-							    FR_TYPE_COMPRESSION,
-							    FR_COMPRESSION_NORMAL,
-							    G_PARAM_READWRITE));
-	g_object_class_install_property (gobject_class,
-					 PROP_VOLUME_SIZE,
-					 g_param_spec_uint ("volume-size",
-							    "Volume size",
-							    "The size of each volume or 0 to not use volumes",
-							    0L,
-							    G_MAXUINT,
-							    0,
-							    G_PARAM_READWRITE));
+static void
+load_data_free (LoadData *add_data)
+{
+	_g_object_unref (add_data->archive);
+	g_free (add_data->password);
+	_g_object_unref (add_data->cancellable);
+	_g_object_unref (add_data->result);
+	g_free (add_data);
 }
 
 
 static void
-fr_command_init (FrCommand *self)
+_fr_command_load_complete_with_error (LoadData *add_data,
+				      GError   *error)
 {
-	self->files = g_ptr_array_sized_new (INITIAL_SIZE);
+	g_return_if_fail (error != NULL);
 
-	self->password = NULL;
-	self->encrypt_header = FALSE;
-	self->compression = FR_COMPRESSION_NORMAL;
-	self->volume_size = 0;
-	self->filename = NULL;
-	self->e_filename = NULL;
-	self->fake_load = FALSE;
+	g_simple_async_result_set_from_error (add_data->result, error);
+	g_simple_async_result_complete_in_idle (add_data->result);
 
-	self->propAddCanUpdate = FALSE;
-	self->propAddCanReplace = FALSE;
-	self->propAddCanStoreFolders = FALSE;
-	self->propExtractCanAvoidOverwrite = FALSE;
-	self->propExtractCanSkipOlder = FALSE;
-	self->propExtractCanJunkPaths = FALSE;
-	self->propPassword = FALSE;
-	self->propTest = FALSE;
-	self->propCanExtractAll = TRUE;
-	self->propCanDeleteNonEmptyFolders = TRUE;
-	self->propCanExtractNonEmptyFolders = TRUE;
-	self->propListFromFile = FALSE;
+	load_data_free (add_data);
 }
 
 
 static void
-fr_command_set_filename (FrCommand  *comm,
-			 const char *filename)
+_fr_command_load_complete (LoadData *load_data)
 {
-	g_return_if_fail (FR_IS_COMMAND (comm));
-
-	if (comm->filename != NULL) {
-		g_free (comm->filename);
-		comm->filename = NULL;
-	}
-
-	if (comm->e_filename != NULL) {
-		g_free (comm->e_filename);
-		comm->e_filename = NULL;
-	}
+	FrArchive *archive;
 
-	if (filename != NULL) {
-		if (! g_path_is_absolute (filename)) {
-			char *current_dir;
+	archive = load_data->archive;
 
-			current_dir = g_get_current_dir ();
-			comm->filename = g_strconcat (current_dir,
-						      "/",
-						      filename,
-						      NULL);
-			g_free (current_dir);
-		}
-		else
-			comm->filename = g_strdup (filename);
+	/* order the list by name to speed up search */
+	g_ptr_array_sort (archive->files, file_data_compare_by_path);
 
-		comm->e_filename = g_shell_quote (comm->filename);
+	/* the name of the volumes are different from the
+	 * original name */
+	if (archive->multi_volume)
+		fr_archive_change_name (archive, FR_COMMAND (archive)->filename);
+	fr_archive_update_capabilities (archive);
 
-		debug (DEBUG_INFO, "filename : %s\n", comm->filename);
-		debug (DEBUG_INFO, "e_filename : %s\n", comm->e_filename);
-	}
+	g_simple_async_result_complete_in_idle (load_data->result);
 
-	fr_command_working_archive (comm, comm->filename);
+	load_data_free (load_data);
 }
 
 
-void
-fr_command_set_file (FrCommand *comm,
-		     GFile     *file)
+static void
+load_local_archive_list_ready_cb (GObject      *source_object,
+				  GAsyncResult *result,
+				  gpointer      user_data)
 {
-	char *filename;
+	LoadData *load_data = user_data;
+	FrError  *error = NULL;
 
-	filename = g_file_get_path (file);
-	fr_command_set_filename (comm, filename);
+	if (! fr_command_handle_process_error (FR_COMMAND (load_data->archive), result, &error))
+		return;
 
-	g_free (filename);
+	if (error != NULL) {
+		_fr_command_load_complete_with_error (load_data, error->gerror);
+		fr_error_free (error);
+		return;
+	}
+
+	_fr_command_load_complete (load_data);
+
+	fr_error_free (error);
 }
 
 
-void
-fr_command_set_multi_volume (FrCommand *comm,
-			     GFile     *file)
+static void
+load_local_archive (LoadData *load_data)
 {
-	comm->multi_volume = TRUE;
-	fr_command_set_file (comm, file);
+	FrCommand *self = FR_COMMAND (load_data->archive);
+
+	load_data->archive->action = FR_ACTION_LISTING_CONTENT;
+	fr_process_set_out_line_func (self->process, NULL, NULL);
+	fr_process_set_err_line_func (self->process, NULL, NULL);
+	fr_process_use_standard_locale (self->process, TRUE);
+	load_data->archive->multi_volume = FALSE;
+
+        g_object_set (self,
+                      "filename", self->priv->local_copy,
+                      "password", load_data->password,
+                      NULL);
+
+        fr_process_clear (self->process);
+	if (FR_COMMAND_GET_CLASS (G_OBJECT (self))->list (self))
+		fr_process_execute (self->process,
+				    load_data->cancellable,
+				    load_local_archive_list_ready_cb,
+				    load_data);
+	else
+		_fr_command_load_complete (load_data);
 }
 
 
-void
-fr_command_list (FrCommand *comm)
+static void
+copy_remote_file_done (GError   *error,
+		       gpointer  user_data)
 {
-	g_return_if_fail (FR_IS_COMMAND (comm));
+	LoadData *load_data = user_data;
 
-	fr_command_progress (comm, -1.0);
+	if (error != NULL)
+		_fr_command_load_complete_with_error (load_data, error);
+	else
+		load_local_archive (load_data);
+}
 
-	if (comm->files != NULL) {
-		_g_ptr_array_free_full (comm->files, (GFunc) file_data_free, NULL);
-		comm->files = g_ptr_array_sized_new (INITIAL_SIZE);
-	}
 
-	comm->action = FR_ACTION_LISTING_CONTENT;
-	fr_process_set_out_line_func (comm->process, NULL, NULL);
-	fr_process_set_err_line_func (comm->process, NULL, NULL);
-	fr_process_use_standard_locale (comm->process, TRUE);
-	comm->multi_volume = FALSE;
+static void
+copy_remote_file_progress (goffset   current_file,
+                           goffset   total_files,
+                           GFile    *source,
+                           GFile    *destination,
+                           goffset   current_num_bytes,
+                           goffset   total_num_bytes,
+                           gpointer  user_data)
+{
+	LoadData *load_data = user_data;
 
-	if (! comm->fake_load)
-		FR_COMMAND_GET_CLASS (G_OBJECT (comm))->list (comm);
-	else
-		g_signal_emit (G_OBJECT (comm),
-			       fr_command_signals[DONE],
-			       0,
-			       comm->action,
-			       &comm->process->error);
+	g_signal_emit_by_name (load_data->archive,
+			       "progress",
+			       (double) current_num_bytes / total_num_bytes);
 }
 
 
-void
-fr_command_add (FrCommand     *comm,
-		const char    *from_file,
-		GList         *file_list,
-		const char    *base_dir,
-		gboolean       update,
-		gboolean       recursive)
+static gboolean
+copy_remote_file_done_cb (gpointer user_data)
 {
-	fr_command_progress (comm, -1.0);
+	LoadData *load_data = user_data;
 
-	comm->action = FR_ACTION_ADDING_FILES;
-	fr_process_set_out_line_func (FR_COMMAND (comm)->process, NULL, NULL);
-	fr_process_set_err_line_func (FR_COMMAND (comm)->process, NULL, NULL);
+	copy_remote_file_done (NULL, load_data);
 
-	FR_COMMAND_GET_CLASS (G_OBJECT (comm))->add (comm,
-						     from_file,
-						     file_list,
-						     base_dir,
-						     update,
-						     recursive);
+	return FALSE;
 }
 
 
-void
-fr_command_delete (FrCommand   *comm,
-		   const char  *from_file,
-		   GList       *file_list)
+static void
+copy_remote_file (LoadData *load_data)
 {
-	fr_command_progress (comm, -1.0);
+	FrCommand *self = FR_COMMAND (load_data->archive);
 
-	comm->action = FR_ACTION_DELETING_FILES;
-	fr_process_set_out_line_func (FR_COMMAND (comm)->process, NULL, NULL);
-	fr_process_set_err_line_func (FR_COMMAND (comm)->process, NULL, NULL);
+	if (! g_file_query_exists (fr_archive_get_file (FR_ARCHIVE (self)),
+				   load_data->cancellable))
+	{
+		GError *error;
 
-	FR_COMMAND_GET_CLASS (G_OBJECT (comm))->delete (comm, from_file, file_list);
-}
+		error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Archive not found"));
+		_fr_command_load_complete_with_error (load_data, error);
+		g_error_free (error);
 
+		return;
+	}
 
-void
-fr_command_extract (FrCommand  *comm,
-		    const char *from_file,
-		    GList      *file_list,
-		    const char *dest_dir,
-		    gboolean    overwrite,
-		    gboolean    skip_older,
-		    gboolean    junk_paths)
+	if (self->priv->is_remote)
+		g_copy_file_async (fr_archive_get_file (FR_ARCHIVE (self)),
+				   self->priv->local_copy,
+				   G_FILE_COPY_OVERWRITE,
+				   G_PRIORITY_DEFAULT,
+				   load_data->cancellable,
+				   copy_remote_file_progress,
+				   load_data,
+				   copy_remote_file_done,
+				   load_data);
+	else
+		g_idle_add (copy_remote_file_done_cb, load_data);
+}
+
+
+static void
+fr_command_load (FrArchive           *archive,
+		 const char          *password,
+		 GCancellable        *cancellable,
+		 GAsyncReadyCallback  callback,
+		 gpointer             user_data)
+{
+	LoadData *load_data;
+
+	load_data = g_new0 (LoadData, 1);
+	load_data->archive = g_object_ref (archive);
+	load_data->password = g_strdup (password);
+	load_data->cancellable = _g_object_ref (cancellable);
+	load_data->result = g_simple_async_result_new (G_OBJECT (archive),
+						       callback,
+						       user_data,
+						       fr_archive_load);
+
+	copy_remote_file (load_data);
+}
+
+
+/* -- add -- */
+
+
+static char *
+create_tmp_base_dir (const char *base_dir,
+		     const char *dest_path)
+{
+	char *dest_dir;
+	char *temp_dir;
+	char *tmp;
+	char *parent_dir;
+	char *dir;
+
+	if ((dest_path == NULL)
+	    || (*dest_path == '\0')
+	    || (strcmp (dest_path, "/") == 0))
+	{
+		return g_strdup (base_dir);
+	}
+
+	dest_dir = g_strdup (dest_path);
+	if (dest_dir[strlen (dest_dir) - 1] == G_DIR_SEPARATOR)
+		dest_dir[strlen (dest_dir) - 1] = 0;
+
+	debug (DEBUG_INFO, "base_dir: %s\n", base_dir);
+	debug (DEBUG_INFO, "dest_dir: %s\n", dest_dir);
+
+	temp_dir = _g_path_get_temp_work_dir (NULL);
+	tmp = _g_path_remove_level (dest_dir);
+	parent_dir =  g_build_filename (temp_dir, tmp, NULL);
+	g_free (tmp);
+
+	debug (DEBUG_INFO, "mkdir %s\n", parent_dir);
+	_g_path_make_directory_tree (parent_dir, 0700, NULL);
+	g_free (parent_dir);
+
+	dir = g_build_filename (temp_dir, "/", dest_dir, NULL);
+	debug (DEBUG_INFO, "symlink %s --> %s\n", dir, base_dir);
+	if (! symlink (base_dir, dir)) {
+		/* void */
+	}
+
+	g_free (dir);
+	g_free (dest_dir);
+
+	return temp_dir;
+}
+
+
+static FileData *
+find_file_in_archive (FrArchive *archive,
+		      char      *path)
+{
+	int i;
+
+	g_return_val_if_fail (path != NULL, NULL);
+
+	i = find_path_in_file_data_array (archive->files, path);
+	if (i >= 0)
+		return (FileData *) g_ptr_array_index (archive->files, i);
+	else
+		return NULL;
+}
+
+
+static void delete_from_archive (FrCommand *self,
+				 GList     *file_list);
+
+
+static GList *
+newer_files_only (FrArchive  *archive,
+		  GList      *file_list,
+		  const char *base_dir)
+{
+	GList *newer_files = NULL;
+	GList *scan;
+
+	for (scan = file_list; scan; scan = scan->next) {
+		char     *filename = scan->data;
+		char     *fullpath;
+		char     *uri;
+		FileData *fdata;
+
+		fdata = find_file_in_archive (archive, filename);
+
+		if (fdata == NULL) {
+			newer_files = g_list_prepend (newer_files, g_strdup (scan->data));
+			continue;
+		}
+
+		fullpath = g_strconcat (base_dir, "/", filename, NULL);
+		uri = g_filename_to_uri (fullpath, NULL, NULL);
+
+		if (fdata->modified >= _g_uri_get_file_mtime (uri)) {
+			g_free (fullpath);
+			g_free (uri);
+			continue;
+		}
+		g_free (fullpath);
+		g_free (uri);
+
+		newer_files = g_list_prepend (newer_files, g_strdup (scan->data));
+	}
+
+	return newer_files;
+}
+
+
+static gboolean
+save_list_to_temp_file (GList   *file_list,
+		        char   **list_dir,
+		        char   **list_filename,
+		        GError **error)
+{
+	gboolean           error_occurred = FALSE;
+	GFile             *list_file;
+	GFileOutputStream *ostream;
+
+	if (error != NULL)
+		*error = NULL;
+	*list_dir = _g_path_get_temp_work_dir (NULL);
+	*list_filename = g_build_filename (*list_dir, "file-list", NULL);
+	list_file = g_file_new_for_path (*list_filename);
+	ostream = g_file_create (list_file, G_FILE_CREATE_PRIVATE, NULL, error);
+
+	if (ostream != NULL) {
+		GList *scan;
+
+		for (scan = file_list; scan != NULL; scan = scan->next) {
+			char *filename = scan->data;
+
+			filename = _g_str_substitute (filename, "\n", "\\n");
+			if ((g_output_stream_write (G_OUTPUT_STREAM (ostream), filename, strlen (filename), NULL, error) < 0)
+			    || (g_output_stream_write (G_OUTPUT_STREAM (ostream), "\n", 1, NULL, error) < 0))
+			{
+				error_occurred = TRUE;
+			}
+
+			g_free (filename);
+
+			if (error_occurred)
+				break;
+		}
+		if (! error_occurred && ! g_output_stream_close (G_OUTPUT_STREAM (ostream), NULL, error))
+			error_occurred = TRUE;
+		g_object_unref (ostream);
+	}
+	else
+		error_occurred = TRUE;
+
+	if (error_occurred) {
+		_g_path_remove_directory (*list_dir);
+		g_free (*list_dir);
+		g_free (*list_filename);
+		*list_dir = NULL;
+		*list_filename = NULL;
+	}
+
+	g_object_unref (list_file);
+
+	return ! error_occurred;
+}
+
+
+static GList *
+split_in_chunks (GList *file_list)
+{
+	GList *chunks = NULL;
+	GList *new_file_list;
+	GList *scan;
+
+	new_file_list = g_list_copy (file_list);
+	for (scan = new_file_list; scan != NULL; /* void */) {
+		GList *prev = scan->prev;
+		GList *chunk;
+		int    l;
+
+		chunk = scan;
+		l = 0;
+		while ((scan != NULL) && (l < MAX_CHUNK_LEN)) {
+			if (l == 0)
+				l = strlen (scan->data);
+			prev = scan;
+			scan = scan->next;
+			if (scan != NULL)
+				l += strlen (scan->data);
+		}
+		if (prev != NULL) {
+			if (prev->next != NULL)
+				prev->next->prev = NULL;
+			prev->next = NULL;
+		}
+		chunks = g_list_append (chunks, chunk);
+	}
+
+	return chunks;
+}
+
+
+static gboolean
+_fr_command_add (FrCommand      *self,
+		 GList          *file_list,
+		 const char     *base_dir,
+		 const char     *dest_dir,
+		 gboolean        update,
+		 gboolean        recursive,
+		 const char     *password,
+		 gboolean        encrypt_header,
+		 FrCompression   compression,
+		 guint           volume_size,
+		 GError        **error)
+{
+	FrArchive *archive = FR_ARCHIVE (self);
+	GList     *new_file_list = NULL;
+	gboolean   base_dir_created = FALSE;
+	GList     *scan;
+	char      *tmp_base_dir = NULL;
+	char      *tmp_archive_dir = NULL;
+	char      *archive_filename = NULL;
+	char      *tmp_archive_filename = NULL;
+	gboolean   error_occurred = FALSE;
+
+	if (file_list == NULL)
+		return FALSE;
+
+	g_object_set (self,
+		      "filename", self->priv->local_copy,
+		      "password", password,
+		      "encrypt_header", encrypt_header,
+		      "compression", compression,
+		      "volume_size", volume_size,
+		      NULL);
+
+	fr_archive_set_stoppable (archive, TRUE);
+
+	/* dest_dir is the destination folder inside the archive */
+
+	if ((dest_dir != NULL) && (*dest_dir != '\0') && (strcmp (dest_dir, "/") != 0)) {
+		const char *rel_dest_dir = dest_dir;
+
+		tmp_base_dir = create_tmp_base_dir (base_dir, dest_dir);
+		base_dir_created = TRUE;
+
+		if (dest_dir[0] == G_DIR_SEPARATOR)
+			rel_dest_dir = dest_dir + 1;
+
+		new_file_list = NULL;
+		for (scan = file_list; scan != NULL; scan = scan->next) {
+			char *filename = scan->data;
+			new_file_list = g_list_prepend (new_file_list, g_build_filename (rel_dest_dir, filename, NULL));
+		}
+	}
+	else {
+		tmp_base_dir = g_strdup (base_dir);
+		new_file_list = _g_string_list_dup (file_list);
+	}
+
+	/* if the command cannot update,  get the list of files that are
+	 * newer than the ones in the archive. */
+
+	if (update && ! archive->propAddCanUpdate) {
+		GList *tmp_file_list;
+
+		tmp_file_list = new_file_list;
+		new_file_list = newer_files_only (archive, tmp_file_list, tmp_base_dir);
+		_g_string_list_free (tmp_file_list);
+	}
+
+	if (new_file_list == NULL) {
+		debug (DEBUG_INFO, "nothing to update.\n");
+
+		if (base_dir_created)
+			_g_path_remove_directory (tmp_base_dir);
+		g_free (tmp_base_dir);
+
+		return FALSE;
+	}
+
+	self->creating_archive = ! g_file_query_exists (self->priv->local_copy, fr_archive_get_cancellable (FR_ARCHIVE (self)));
+
+	/* create the new archive in a temporary sub-directory, this allows
+	 * to cancel the operation without losing the original archive and
+	 * removing possible temporary files created by the command. */
+
+	{
+		GFile *local_copy_parent;
+		char  *archive_dir;
+		GFile *tmp_file;
+
+		/* create the new archive in a sub-folder of the original
+		 * archive this way the 'mv' command is fast. */
+
+		local_copy_parent = g_file_get_parent (self->priv->local_copy);
+		archive_dir = g_file_get_path (local_copy_parent);
+		tmp_archive_dir = _g_path_get_temp_work_dir (archive_dir);
+		archive_filename = g_file_get_path (self->priv->local_copy);
+		tmp_archive_filename = g_build_filename (tmp_archive_dir,
+							 _g_path_get_file_name (archive_filename),
+							 NULL);
+		tmp_file = g_file_new_for_path (tmp_archive_filename);
+		g_object_set (self, "filename", tmp_file, NULL);
+
+		if (! self->creating_archive) {
+			/* copy the original archive to the new position */
+
+			fr_process_begin_command (self->process, "cp");
+			fr_process_add_arg (self->process, "-f");
+			fr_process_add_arg (self->process, archive_filename);
+			fr_process_add_arg (self->process, tmp_archive_filename);
+			fr_process_end_command (self->process);
+		}
+
+		g_object_unref (tmp_file);
+		g_free (archive_dir);
+		g_object_unref (local_copy_parent);
+	}
+
+	fr_command_uncompress (self);
+
+	/* when files are already present in a tar archive and are added
+	 * again, they are not replaced, so we have to delete them first. */
+
+	/* if we are adding (== ! update) and 'add' cannot replace or
+	 * if we are updating and 'add' cannot update,
+	 * delete the files first. */
+
+	if ((! update && ! archive->propAddCanReplace)
+	    || (update && ! archive->propAddCanUpdate))
+	{
+		GList *del_list = NULL;
+
+		for (scan = new_file_list; scan != NULL; scan = scan->next) {
+			char *filename = scan->data;
+			if (find_file_in_archive (archive, filename))
+				del_list = g_list_prepend (del_list, filename);
+		}
+
+		/* delete */
+
+		if (del_list != NULL) {
+			delete_from_archive (self, del_list);
+			fr_process_set_ignore_error (self->process, TRUE);
+			g_list_free (del_list);
+		}
+	}
+
+	/* add now. */
+
+	fr_archive_set_n_files (archive, g_list_length (new_file_list));
+
+	if (archive->propListFromFile && (archive->n_files > LIST_LENGTH_TO_USE_FILE)) {
+		char   *list_dir;
+		char   *list_filename;
+
+		if (! save_list_to_temp_file (new_file_list, &list_dir, &list_filename, error)) {
+			error_occurred = TRUE;
+		}
+		else {
+			fr_command_add (self,
+					list_filename,
+					new_file_list,
+					tmp_base_dir,
+					update,
+					recursive);
+
+			/* remove the temp dir */
+
+			fr_process_begin_command (self->process, "rm");
+			fr_process_set_working_dir (self->process, g_get_tmp_dir());
+			fr_process_set_sticky (self->process, TRUE);
+			fr_process_add_arg (self->process, "-rf");
+			fr_process_add_arg (self->process, list_dir);
+			fr_process_end_command (self->process);
+		}
+
+		g_free (list_filename);
+		g_free (list_dir);
+	}
+	else {
+		GList *chunks = NULL;
+
+		/* specify the file list on the command line, splitting
+		 * in more commands to avoid to overflow the command line
+		 * length limit. */
+
+		chunks = split_in_chunks (new_file_list);
+		for (scan = chunks; scan != NULL; scan = scan->next) {
+			GList *chunk = scan->data;
+
+			fr_command_add (self,
+					NULL,
+					chunk,
+					tmp_base_dir,
+					update,
+					recursive);
+			g_list_free (chunk);
+		}
+
+		g_list_free (chunks);
+	}
+
+	_g_string_list_free (new_file_list);
+
+	if (! error_occurred) {
+		fr_command_recompress (self);
+
+		/* move the new archive to the original position */
+
+		fr_process_begin_command (self->process, "mv");
+		fr_process_add_arg (self->process, "-f");
+		fr_process_add_arg (self->process, tmp_archive_filename);
+		fr_process_add_arg (self->process, archive_filename);
+		fr_process_end_command (self->process);
+
+		/* remove the temp sub-directory */
+
+		fr_process_begin_command (self->process, "rm");
+		fr_process_set_working_dir (self->process, g_get_tmp_dir ());
+		fr_process_set_sticky (self->process, TRUE);
+		fr_process_add_arg (self->process, "-rf");
+		fr_process_add_arg (self->process, tmp_archive_dir);
+		fr_process_end_command (self->process);
+
+		/* remove the archive dir */
+
+		if (base_dir_created) {
+			fr_process_begin_command (self->process, "rm");
+			fr_process_set_working_dir (self->process, g_get_tmp_dir ());
+			fr_process_set_sticky (self->process, TRUE);
+			fr_process_add_arg (self->process, "-rf");
+			fr_process_add_arg (self->process, tmp_base_dir);
+			fr_process_end_command (self->process);
+		}
+	}
+
+	g_free (tmp_archive_filename);
+	g_free (archive_filename);
+	g_free (tmp_archive_dir);
+	g_free (tmp_base_dir);
+
+	return ! error_occurred;
+}
+
+
+/* -- fr_command_add_files -- */
+
+
+typedef struct {
+	FrArchive          *archive;
+	GCancellable       *cancellable;
+	GSimpleAsyncResult *result;
+} AddData;
+
+
+static void
+add_data_free (AddData *add_data)
+{
+	_g_object_unref (add_data->archive);
+	_g_object_unref (add_data->cancellable);
+	_g_object_unref (add_data->result);
+	g_free (add_data);
+}
+
+
+static void add_dropped_items (DroppedItemsData *data);
+
+
+static void
+process_ready_for_add_files_cb (GObject      *source_object,
+				GAsyncResult *result,
+				gpointer      user_data)
+{
+	AddData *add_data = user_data;
+	FrError *error = NULL;
+
+	if (! fr_process_execute_finish (FR_PROCESS (source_object), result, &error)) {
+		g_simple_async_result_set_from_error (add_data->result, error->gerror);
+	}
+	else {
+		FrArchive *archive = add_data->archive;
+		FrCommand *self = FR_COMMAND (archive);
+
+		_fr_command_remove_temp_work_dir (self);
+
+		if (self->priv->continue_adding_dropped_items) {
+			add_dropped_items (self->priv->dropped_items_data);
+			return;
+		}
+
+		if (self->priv->dropped_items_data != NULL) {
+			dropped_items_data_free (self->priv->dropped_items_data);
+			self->priv->dropped_items_data = NULL;
+		}
+
+		/* the name of the volumes are different from the
+		 * original name */
+		if (archive->multi_volume)
+			fr_archive_change_name (archive, self->filename);
+
+		if (! g_file_has_uri_scheme (fr_archive_get_file (archive), "file")) {
+			copy_archive_to_remote_location (add_data->archive,
+							 add_data->result,
+							 add_data->cancellable);
+
+			add_data_free (add_data);
+			return;
+		}
+	}
+
+	g_simple_async_result_complete_in_idle (add_data->result);
+
+	fr_error_free (error);
+	add_data_free (add_data);
+}
+
+
+static void
+_fr_command_add_local_files (FrCommand           *self,
+			     GList               *file_list,
+			     const char          *base_dir,
+			     const char          *dest_dir,
+			     gboolean             update,
+			     gboolean             recursive,
+			     const char          *password,
+			     gboolean             encrypt_header,
+			     FrCompression        compression,
+			     guint                volume_size,
+			     GCancellable        *cancellable,
+			     GSimpleAsyncResult  *command_result)
+{
+	AddData *add_data;
+	GError  *error = NULL;
+
+	g_object_set (self, "filename", self->priv->local_copy, NULL);
+	fr_process_clear (self->process);
+	if (! _fr_command_add (self,
+			       file_list,
+			       base_dir,
+			       dest_dir,
+			       update,
+			       recursive,
+			       password,
+			       encrypt_header,
+			       compression,
+			       volume_size,
+			       &error))
+	{
+		if (error != NULL) {
+			g_simple_async_result_set_from_error (command_result, error);
+			g_error_free (error);
+		}
+		g_simple_async_result_complete_in_idle (command_result);
+		return;
+	}
+
+	add_data = g_new0 (AddData, 1);
+	add_data->archive = _g_object_ref (self);
+	add_data->cancellable = _g_object_ref (cancellable);
+	add_data->result = _g_object_ref (command_result);
+
+	fr_process_execute (self->process,
+			    add_data->cancellable,
+			    process_ready_for_add_files_cb,
+			    add_data);
+}
+
+
+static void
+copy_remote_files_done (GError   *error,
+			gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (xfer_data->result, error);
+		g_simple_async_result_complete_in_idle (xfer_data->result);
+
+	}
+	else
+		_fr_command_add_local_files (FR_COMMAND (xfer_data->archive),
+					     xfer_data->file_list,
+					     xfer_data->tmp_dir,
+					     xfer_data->dest_dir,
+					     FALSE,
+					     xfer_data->recursive,
+					     xfer_data->password,
+					     xfer_data->encrypt_header,
+					     xfer_data->compression,
+					     xfer_data->volume_size,
+					     xfer_data->cancellable,
+					     g_object_ref (xfer_data->result));
+
+	xfer_data_free (xfer_data);
+}
+
+
+static void
+copy_remote_files_progress (goffset   current_file,
+                            goffset   total_files,
+                            GFile    *source,
+                            GFile    *destination,
+                            goffset   current_num_bytes,
+                            goffset   total_num_bytes,
+                            gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
+
+	g_signal_emit_by_name (xfer_data->archive,
+			       "progress",
+			       (double) current_file / (total_files + 1));
+}
+
+
+static void
+copy_remote_files (FrCommand           *self,
+		   GList               *file_list,
+		   const char          *base_uri,
+		   const char          *dest_dir,
+		   gboolean             update,
+		   gboolean             recursive,
+		   const char          *password,
+		   gboolean             encrypt_header,
+		   FrCompression        compression,
+		   guint                volume_size,
+		   const char          *tmp_dir,
+		   GCancellable        *cancellable,
+		   GSimpleAsyncResult  *result)
+{
+	GList        *sources = NULL;
+	GList        *destinations = NULL;
+	GHashTable   *created_folders;
+	GList        *scan;
+	XferData     *xfer_data;
+
+	sources = NULL;
+	destinations = NULL;
+	created_folders = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+	for (scan = file_list; scan; scan = scan->next) {
+		char *partial_filename = scan->data;
+		char *local_uri;
+		char *local_folder_uri;
+		char *remote_uri;
+
+		local_uri = g_strconcat ("file://", tmp_dir, "/", partial_filename, NULL);
+		local_folder_uri = _g_path_remove_level (local_uri);
+		if (g_hash_table_lookup (created_folders, local_folder_uri) == NULL) {
+			GError *error = NULL;
+			if (! _g_uri_ensure_dir_exists (local_folder_uri, 0755, &error)) {
+				g_simple_async_result_set_from_error (result, error);
+				g_simple_async_result_complete_in_idle (result);
+
+				g_clear_error (&error);
+				g_object_unref (result);
+				g_free (local_folder_uri);
+				g_free (local_uri);
+				_g_file_list_free (sources);
+				_g_file_list_free (destinations);
+				g_hash_table_destroy (created_folders);
+
+				return;
+			}
+
+			g_hash_table_insert (created_folders, local_folder_uri, GINT_TO_POINTER (1));
+		}
+		else
+			g_free (local_folder_uri);
+
+		remote_uri = g_strconcat (base_uri, "/", partial_filename, NULL);
+		sources = g_list_append (sources, g_file_new_for_uri (remote_uri));
+		g_free (remote_uri);
+
+		destinations = g_list_append (destinations, g_file_new_for_uri (local_uri));
+		g_free (local_uri);
+	}
+	g_hash_table_destroy (created_folders);
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = FR_ARCHIVE (self);
+	xfer_data->file_list = _g_string_list_dup (file_list);
+	xfer_data->base_uri = g_strdup (base_uri);
+	xfer_data->dest_dir = g_strdup (dest_dir);
+	xfer_data->update = update;
+	xfer_data->recursive = recursive;
+	xfer_data->dest_dir = g_strdup (dest_dir);
+	xfer_data->password = g_strdup (password);
+	xfer_data->encrypt_header = encrypt_header;
+	xfer_data->compression = compression;
+	xfer_data->volume_size = volume_size;
+	xfer_data->tmp_dir = g_strdup (tmp_dir);
+	xfer_data->cancellable = _g_object_ref (cancellable);
+	xfer_data->result = result;
+
+	g_signal_emit_by_name (self, "start", FR_ACTION_COPYING_FILES_FROM_REMOTE);
+
+	g_copy_files_async (sources,
+			    destinations,
+			    G_FILE_COPY_OVERWRITE,
+			    G_PRIORITY_DEFAULT,
+			    cancellable,
+			    copy_remote_files_progress,
+			    xfer_data,
+			    copy_remote_files_done,
+			    xfer_data);
+
+	_g_file_list_free (sources);
+	_g_file_list_free (destinations);
+}
+
+
+static void
+fr_command_add_files (FrArchive           *base,
+		      GList               *file_list,
+		      const char          *base_dir,
+		      const char          *dest_dir,
+		      gboolean             update,
+		      gboolean             recursive,
+		      const char          *password,
+		      gboolean             encrypt_header,
+		      FrCompression        compression,
+		      guint                volume_size,
+		      GCancellable        *cancellable,
+		      GAsyncReadyCallback  callback,
+		      gpointer             user_data)
+{
+	FrCommand          *self = FR_COMMAND (base);
+	GSimpleAsyncResult *result;
+
+	result = g_simple_async_result_new (G_OBJECT (self),
+					    callback,
+					    user_data,
+					    fr_archive_add_files);
+
+	if (_g_uri_is_local (base_dir)) {
+		char *local_dir;
+
+		local_dir = g_filename_from_uri (base_dir, NULL, NULL);
+		_fr_command_add_local_files (self,
+					     file_list,
+					     local_dir,
+					     dest_dir,
+					     update,
+					     recursive,
+					     password,
+					     encrypt_header,
+					     compression,
+					     volume_size,
+					     cancellable,
+					     result);
+
+		g_free (local_dir);
+	}
+	else
+		copy_remote_files (self,
+				   file_list,
+				   base_dir,
+				   dest_dir,
+				   update,
+				   recursive,
+				   password,
+				   encrypt_header,
+				   compression,
+				   volume_size,
+				   _fr_command_get_temp_work_dir (self),
+				   cancellable,
+				   result);
+}
+
+
+/* -- remove -- */
+
+
+static gboolean
+file_is_in_subfolder_of (const char *filename,
+		         GList      *folder_list)
+{
+	GList *scan;
+
+	if (filename == NULL)
+		return FALSE;
+
+	for (scan = folder_list; scan; scan = scan->next) {
+		char *folder_in_list = (char*) scan->data;
+
+		if (_g_path_is_parent_of (folder_in_list, filename))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void
+delete_from_archive (FrCommand *self,
+		     GList     *file_list)
+{
+	FrArchive *archive = FR_ARCHIVE (self);
+	gboolean   file_list_created = FALSE;
+	GList     *tmp_file_list = NULL;
+	gboolean   tmp_file_list_created = FALSE;
+	GList     *scan;
+
+	/* file_list == NULL means delete all the files in the archive. */
+
+	if (file_list == NULL) {
+		int i;
+
+		for (i = 0; i < archive->files->len; i++) {
+			FileData *fdata = g_ptr_array_index (archive->files, i);
+			file_list = g_list_prepend (file_list, fdata->original_path);
+		}
+
+		file_list_created = TRUE;
+	}
+
+	if (! archive->propCanDeleteNonEmptyFolders) {
+		GList *folders_to_remove;
+
+		/* remove from the list the files contained in folders to be
+		 * removed. */
+
+		folders_to_remove = NULL;
+		for (scan = file_list; scan != NULL; scan = scan->next) {
+			char *path = scan->data;
+
+			if (path[strlen (path) - 1] == '/')
+				folders_to_remove = g_list_prepend (folders_to_remove, path);
+		}
+
+		if (folders_to_remove != NULL) {
+			tmp_file_list = NULL;
+			for (scan = file_list; scan != NULL; scan = scan->next) {
+				char *path = scan->data;
+
+				if (! file_is_in_subfolder_of (path, folders_to_remove))
+					tmp_file_list = g_list_prepend (tmp_file_list, path);
+			}
+			tmp_file_list_created = TRUE;
+			g_list_free (folders_to_remove);
+		}
+	}
+
+	if (! tmp_file_list_created)
+		tmp_file_list = g_list_copy (file_list);
+
+	if (file_list_created)
+		g_list_free (file_list);
+
+	fr_archive_set_n_files (archive, g_list_length (tmp_file_list));
+
+	if (archive->propListFromFile && (archive->n_files > LIST_LENGTH_TO_USE_FILE)) {
+		char *list_dir;
+		char *list_filename;
+
+		if (save_list_to_temp_file (tmp_file_list, &list_dir, &list_filename, NULL)) {
+			fr_command_delete (self,
+					   list_filename,
+					   tmp_file_list);
+
+			/* remove the temp dir */
+
+			fr_process_begin_command (self->process, "rm");
+			fr_process_set_working_dir (self->process, g_get_tmp_dir());
+			fr_process_set_sticky (self->process, TRUE);
+			fr_process_add_arg (self->process, "-rf");
+			fr_process_add_arg (self->process, list_dir);
+			fr_process_end_command (self->process);
+		}
+
+		g_free (list_filename);
+		g_free (list_dir);
+	}
+	else {
+		for (scan = tmp_file_list; scan != NULL; ) {
+			GList *prev = scan->prev;
+			GList *chunk_list;
+			int    l;
+
+			chunk_list = scan;
+			l = 0;
+			while ((scan != NULL) && (l < MAX_CHUNK_LEN)) {
+				if (l == 0)
+					l = strlen (scan->data);
+				prev = scan;
+				scan = scan->next;
+				if (scan != NULL)
+					l += strlen (scan->data);
+			}
+
+			prev->next = NULL;
+			fr_command_delete (self, NULL, chunk_list);
+			prev->next = scan;
+		}
+	}
+
+	g_list_free (tmp_file_list);
+}
+
+
+static void
+_fr_command_remove (FrCommand     *self,
+		    GList         *file_list,
+		    FrCompression  compression)
+{
+	FrArchive *archive = FR_ARCHIVE (self);
+	char      *tmp_archive_dir = NULL;
+	char      *archive_filename = NULL;
+	char      *tmp_archive_filename = NULL;
+
+	g_return_if_fail (self != NULL);
+
+	fr_archive_set_stoppable (archive, TRUE);
+	self->creating_archive = FALSE;
+	g_object_set (self, "compression", compression, NULL);
+
+	/* create the new archive in a temporary sub-directory, this allows
+	 * to cancel the operation without losing the original archive and
+	 * removing possible temporary files created by the command. */
+
+	{
+		GFile *local_copy_parent;
+		char  *archive_dir;
+		GFile *tmp_file;
+
+		/* create the new archive in a sub-folder of the original
+		 * archive this way the 'mv' command is fast. */
+
+		local_copy_parent = g_file_get_parent (self->priv->local_copy);
+		archive_dir = g_file_get_path (local_copy_parent);
+		tmp_archive_dir = _g_path_get_temp_work_dir (archive_dir);
+		archive_filename = g_file_get_path (self->priv->local_copy);
+		tmp_archive_filename = g_build_filename (tmp_archive_dir, _g_path_get_file_name (archive_filename), NULL);
+		tmp_file = g_file_new_for_path (tmp_archive_filename);
+		g_object_set (self, "file", tmp_file, NULL);
+
+		if (! self->creating_archive) {
+			/* copy the original self to the new position */
+
+			fr_process_begin_command (self->process, "cp");
+			fr_process_add_arg (self->process, "-f");
+			fr_process_add_arg (self->process, archive_filename);
+			fr_process_add_arg (self->process, tmp_archive_filename);
+			fr_process_end_command (self->process);
+		}
+
+		g_object_unref (tmp_file);
+		g_free (archive_dir);
+		g_object_unref (local_copy_parent);
+	}
+
+	/* uncompress, delete and recompress */
+
+	fr_command_uncompress (self);
+	delete_from_archive (self, file_list);
+	fr_command_recompress (self);
+
+	/* move the new self to the original position */
+
+	fr_process_begin_command (self->process, "mv");
+	fr_process_add_arg (self->process, "-f");
+	fr_process_add_arg (self->process, tmp_archive_filename);
+	fr_process_add_arg (self->process, archive_filename);
+	fr_process_end_command (self->process);
+
+	/* remove the temp sub-directory */
+
+	fr_process_begin_command (self->process, "rm");
+	fr_process_set_working_dir (self->process, g_get_tmp_dir ());
+	fr_process_set_sticky (self->process, TRUE);
+	fr_process_add_arg (self->process, "-rf");
+	fr_process_add_arg (self->process, tmp_archive_dir);
+	fr_process_end_command (self->process);
+
+	g_free (tmp_archive_filename);
+	g_free (archive_filename);
+	g_free (tmp_archive_dir);
+}
+
+
+static void
+process_ready_for_remove_files_cb (GObject      *source_object,
+				   GAsyncResult *result,
+				   gpointer      user_data)
+{
+	XferData *xfer_data = user_data;
+	FrError  *error = NULL;
+
+	if (! fr_process_execute_finish (FR_PROCESS (source_object), result, &error)) {
+		g_simple_async_result_set_from_error (xfer_data->result, error->gerror);
+		fr_error_free (error);
+	}
+	else {
+		if (! g_file_has_uri_scheme (fr_archive_get_file (xfer_data->archive), "file")) {
+			copy_archive_to_remote_location (xfer_data->archive,
+							 xfer_data->result,
+							 xfer_data->cancellable);
+
+			xfer_data_free (xfer_data);
+			return;
+		}
+	}
+
+	g_simple_async_result_complete_in_idle (xfer_data->result);
+
+	xfer_data_free (xfer_data);
+}
+
+
+static void
+fr_command_remove_files (FrArchive           *archive,
+		  	 GList               *file_list,
+		  	 FrCompression        compression,
+		  	 GCancellable        *cancellable,
+		  	 GAsyncReadyCallback  callback,
+		  	 gpointer             user_data)
+{
+	FrCommand *self = FR_COMMAND (archive);
+	XferData  *xfer_data;
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = _g_object_ref (archive);
+	xfer_data->cancellable = _g_object_ref (cancellable);
+	xfer_data->result = g_simple_async_result_new (G_OBJECT (self),
+						       callback,
+						       user_data,
+						       fr_archive_remove);
+
+	g_object_set (self, "filename", self->priv->local_copy, NULL);
+	fr_process_clear (self->process);
+	_fr_command_remove (self, file_list, compression);
+
+	fr_process_execute (self->process,
+			    cancellable,
+			    process_ready_for_remove_files_cb,
+			    xfer_data);
+}
+
+
+/* -- extract -- */
+
+
+static void
+move_files_to_dir (FrCommand *self,
+		   GList            *file_list,
+		   const char       *source_dir,
+		   const char       *dest_dir,
+		   gboolean          overwrite)
+{
+	GList *list;
+	GList *scan;
+
+	/* we prefer mv instead of cp for performance reasons,
+	 * but if the destination folder already exists mv
+	 * doesn't work correctly. (bug #590027) */
+
+	list = g_list_copy (file_list);
+	for (scan = list; scan; /* void */) {
+		GList *next = scan->next;
+		char  *filename = scan->data;
+		char  *basename;
+		char  *destname;
+
+		basename = g_path_get_basename (filename);
+		destname = g_build_filename (dest_dir, basename, NULL);
+		if (g_file_test (destname, G_FILE_TEST_IS_DIR)) {
+			fr_process_begin_command (self->process, "cp");
+			fr_process_add_arg (self->process, "-R");
+			if (overwrite)
+				fr_process_add_arg (self->process, "-f");
+			else
+				fr_process_add_arg (self->process, "-n");
+			if (filename[0] == '/')
+				fr_process_add_arg_concat (self->process, source_dir, filename, NULL);
+			else
+				fr_process_add_arg_concat (self->process, source_dir, "/", filename, NULL);
+			fr_process_add_arg (self->process, dest_dir);
+			fr_process_end_command (self->process);
+
+			list = g_list_remove_link (list, scan);
+			g_list_free (scan);
+		}
+
+		g_free (destname);
+		g_free (basename);
+
+		scan = next;
+	}
+
+	if (list == NULL)
+		return;
+
+	/* 'list' now contains the files that can be moved without problems */
+
+	fr_process_begin_command (self->process, "mv");
+	if (overwrite)
+		fr_process_add_arg (self->process, "-f");
+	else
+		fr_process_add_arg (self->process, "-n");
+	for (scan = list; scan; scan = scan->next) {
+		char *filename = scan->data;
+
+		if (filename[0] == '/')
+			fr_process_add_arg_concat (self->process, source_dir, filename, NULL);
+		else
+			fr_process_add_arg_concat (self->process, source_dir, "/", filename, NULL);
+	}
+	fr_process_add_arg (self->process, dest_dir);
+	fr_process_end_command (self->process);
+
+	g_list_free (list);
+}
+
+
+static void
+move_files_in_chunks (FrCommand *self,
+		      GList            *file_list,
+		      const char       *temp_dir,
+		      const char       *dest_dir,
+		      gboolean          overwrite)
+{
+	GList *scan;
+	int    temp_dir_l;
+
+	temp_dir_l = strlen (temp_dir);
+
+	for (scan = file_list; scan != NULL; ) {
+		GList *prev = scan->prev;
+		GList *chunk_list;
+		int    l;
+
+		chunk_list = scan;
+		l = 0;
+		while ((scan != NULL) && (l < MAX_CHUNK_LEN)) {
+			if (l == 0)
+				l = temp_dir_l + 1 + strlen (scan->data);
+			prev = scan;
+			scan = scan->next;
+			if (scan != NULL)
+				l += temp_dir_l + 1 + strlen (scan->data);
+		}
+
+		prev->next = NULL;
+		move_files_to_dir (self, chunk_list, temp_dir, dest_dir, overwrite);
+		prev->next = scan;
+	}
+}
+
+
+static void
+extract_from_archive (FrCommand  *self,
+		      GList      *file_list,
+		      const char *dest_dir,
+		      gboolean    overwrite,
+		      gboolean    skip_older,
+		      gboolean    junk_paths,
+		      const char *password)
+{
+	GList *scan;
+
+	g_object_set (self, "password", password, NULL);
+
+	if (file_list == NULL) {
+		fr_command_extract (self,
+				    NULL,
+				    file_list,
+				    dest_dir,
+				    overwrite,
+				    skip_older,
+				    junk_paths);
+		return;
+	}
+
+	if (FR_ARCHIVE (self)->propListFromFile
+	    && (g_list_length (file_list) > LIST_LENGTH_TO_USE_FILE))
+	{
+		char *list_dir;
+		char *list_filename;
+
+		if (save_list_to_temp_file (file_list, &list_dir, &list_filename, NULL)) {
+			fr_command_extract (self,
+					    list_filename,
+					    file_list,
+					    dest_dir,
+					    overwrite,
+					    skip_older,
+					    junk_paths);
+
+			/* remove the temp dir */
+
+			fr_process_begin_command (self->process, "rm");
+			fr_process_set_working_dir (self->process, g_get_tmp_dir());
+			fr_process_set_sticky (self->process, TRUE);
+			fr_process_add_arg (self->process, "-rf");
+			fr_process_add_arg (self->process, list_dir);
+			fr_process_end_command (self->process);
+		}
+
+		g_free (list_filename);
+		g_free (list_dir);
+	}
+	else {
+		for (scan = file_list; scan != NULL; ) {
+			GList *prev = scan->prev;
+			GList *chunk_list;
+			int    l;
+
+			chunk_list = scan;
+			l = 0;
+			while ((scan != NULL) && (l < MAX_CHUNK_LEN)) {
+				if (l == 0)
+					l = strlen (scan->data);
+				prev = scan;
+				scan = scan->next;
+				if (scan != NULL)
+					l += strlen (scan->data);
+			}
+
+			prev->next = NULL;
+			fr_command_extract (self,
+					    NULL,
+					    chunk_list,
+					    dest_dir,
+					    overwrite,
+					    skip_older,
+					    junk_paths);
+			prev->next = scan;
+		}
+	}
+}
+
+
+static char*
+compute_base_path (const char *base_dir,
+		   const char *path,
+		   gboolean    junk_paths,
+		   gboolean    can_junk_paths)
+{
+	int         base_dir_len = strlen (base_dir);
+	int         path_len = strlen (path);
+	const char *base_path;
+	char       *name_end;
+	char       *new_path;
+
+	if (junk_paths) {
+		if (can_junk_paths)
+			new_path = g_strdup (_g_path_get_file_name (path));
+		else
+			new_path = g_strdup (path);
+
+		/*debug (DEBUG_INFO, "%s, %s --> %s\n", base_dir, path, new_path);*/
+
+		return new_path;
+	}
+
+	if (path_len <= base_dir_len)
+		return NULL;
+
+	base_path = path + base_dir_len;
+	if (path[0] != '/')
+		base_path -= 1;
+	name_end = strchr (base_path, '/');
+
+	if (name_end == NULL)
+		new_path = g_strdup (path);
+	else {
+		int name_len = name_end - path;
+		new_path = g_strndup (path, name_len);
+	}
+
+	/*debug (DEBUG_INFO, "%s, %s --> %s\n", base_dir, path, new_path);*/
+
+	return new_path;
+}
+
+
+static GList*
+compute_list_base_path (const char *base_dir,
+			GList      *filtered,
+			gboolean    junk_paths,
+			gboolean    can_junk_paths)
+{
+	GList *scan;
+	GList *list = NULL, *list_unique = NULL;
+	GList *last_inserted;
+
+	if (filtered == NULL)
+		return NULL;
+
+	for (scan = filtered; scan; scan = scan->next) {
+		const char *path = scan->data;
+		char       *new_path;
+
+		new_path = compute_base_path (base_dir, path, junk_paths, can_junk_paths);
+		if (new_path != NULL)
+			list = g_list_prepend (list, new_path);
+	}
+
+	/* The above operation can create duplicates, we remove them here. */
+	list = g_list_sort (list, (GCompareFunc)strcmp);
+
+	last_inserted = NULL;
+	for (scan = list; scan; scan = scan->next) {
+		const char *path = scan->data;
+
+		if (last_inserted != NULL) {
+			const char *last_path = (const char*)last_inserted->data;
+			if (strcmp (last_path, path) == 0) {
+				g_free (scan->data);
+				continue;
+			}
+		}
+
+		last_inserted = scan;
+		list_unique = g_list_prepend (list_unique, scan->data);
+	}
+
+	g_list_free (list);
+
+	return list_unique;
+}
+
+
+static gboolean
+file_list_contains_files_in_this_dir (GList      *file_list,
+				      const char *dirname)
+{
+	GList *scan;
+
+	for (scan = file_list; scan; scan = scan->next) {
+		char *filename = scan->data;
+
+		if (_g_path_is_parent_of (dirname, filename))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static GList*
+remove_files_contained_in_this_dir (GList *file_list,
+				    GList *dir_pointer)
 {
-	fr_command_progress (comm, -1.0);
+	char  *dirname = dir_pointer->data;
+	int    dirname_l = strlen (dirname);
+	GList *scan;
 
-	comm->action = FR_ACTION_EXTRACTING_FILES;
-	fr_process_set_out_line_func (FR_COMMAND (comm)->process, NULL, NULL);
-	fr_process_set_err_line_func (FR_COMMAND (comm)->process, NULL, NULL);
+	for (scan = dir_pointer->next; scan; /* empty */) {
+		char *filename = scan->data;
 
-	FR_COMMAND_GET_CLASS (G_OBJECT (comm))->extract (comm,
-							 from_file,
-							 file_list,
-							 dest_dir,
-							 overwrite,
-							 skip_older,
-							 junk_paths);
+		if (strncmp (dirname, filename, dirname_l) != 0)
+			break;
+
+		if (_g_path_is_parent_of (dirname, filename)) {
+			GList *next = scan->next;
+
+			file_list = g_list_remove_link (file_list, scan);
+			g_list_free (scan);
+
+			scan = next;
+		}
+		else
+			scan = scan->next;
+	}
+
+	return file_list;
 }
 
 
-void
-fr_command_test (FrCommand *comm)
+static void
+_fr_command_extract (FrCommand  *self,
+		     GList      *file_list,
+		     const char *destination,
+		     const char *base_dir,
+		     gboolean    skip_older,
+		     gboolean    overwrite,
+		     gboolean    junk_paths,
+		     const char *password)
 {
-	fr_command_progress (comm, -1.0);
+	FrArchive *archive = FR_ARCHIVE (self);
+	GList     *filtered;
+	GList     *scan;
+	gboolean   extract_all;
+	gboolean   use_base_dir;
+	gboolean   all_options_supported;
+	gboolean   move_to_dest_dir;
+	gboolean   file_list_created = FALSE;
+
+	g_return_if_fail (archive != NULL);
+
+	fr_archive_set_stoppable (archive, TRUE);
+	g_object_set (self, "filename", self->priv->local_copy, NULL);
+
+	/* if a command supports all the requested options use
+	 * fr_command_extract_files directly. */
+
+	use_base_dir = ! ((base_dir == NULL)
+			  || (strcmp (base_dir, "") == 0)
+			  || (strcmp (base_dir, "/") == 0));
+
+	all_options_supported = (! use_base_dir
+				 && ! (! overwrite && ! archive->propExtractCanAvoidOverwrite)
+				 && ! (skip_older && ! archive->propExtractCanSkipOlder)
+				 && ! (junk_paths && ! archive->propExtractCanJunkPaths));
+
+	extract_all = (file_list == NULL);
+	if (extract_all && (! all_options_supported || ! archive->propCanExtractAll)) {
+		int i;
+
+		file_list = NULL;
+		for (i = 0; i < archive->files->len; i++) {
+			FileData *fdata = g_ptr_array_index (archive->files, i);
+			file_list = g_list_prepend (file_list, g_strdup (fdata->original_path));
+		}
+		file_list_created = TRUE;
+	}
+
+	if (extract_all && (file_list == NULL))
+		fr_archive_set_n_files (archive, archive->files->len);
+	else
+		fr_archive_set_n_files (archive, g_list_length (file_list));
+
+	if (all_options_supported) {
+		gboolean created_filtered_list = FALSE;
+
+		if (! extract_all && ! archive->propCanExtractNonEmptyFolders) {
+			created_filtered_list = TRUE;
+			filtered = g_list_copy (file_list);
+			filtered = g_list_sort (filtered, (GCompareFunc) strcmp);
+			for (scan = filtered; scan; scan = scan->next)
+				filtered = remove_files_contained_in_this_dir (filtered, scan);
+		}
+		else
+			filtered = file_list;
+
+		if (! (created_filtered_list && (filtered == NULL)))
+			extract_from_archive (self,
+					      filtered,
+					      destination,
+					      overwrite,
+					      skip_older,
+					      junk_paths,
+					      password);
+
+		if (created_filtered_list && (filtered != NULL))
+			g_list_free (filtered);
+
+		if (file_list_created)
+			_g_string_list_free (file_list);
+
+		return;
+	}
+
+	/* .. else we have to implement the unsupported options. */
+
+	move_to_dest_dir = (use_base_dir
+			    || ((junk_paths
+				 && ! archive->propExtractCanJunkPaths)));
 
-	comm->action = FR_ACTION_TESTING_ARCHIVE;
-	fr_process_set_out_line_func (FR_COMMAND (comm)->process, NULL, NULL);
-	fr_process_set_err_line_func (FR_COMMAND (comm)->process, NULL, NULL);
+	if (extract_all && ! file_list_created) {
+		int i;
 
-	FR_COMMAND_GET_CLASS (G_OBJECT (comm))->test (comm);
+		file_list = NULL;
+		for (i = 0; i < archive->files->len; i++) {
+			FileData *fdata = g_ptr_array_index (archive->files, i);
+			file_list = g_list_prepend (file_list, g_strdup (fdata->original_path));
+		}
+
+		file_list_created = TRUE;
+	}
+
+	filtered = NULL;
+	for (scan = file_list; scan; scan = scan->next) {
+		FileData   *fdata;
+		char       *archive_list_filename = scan->data;
+		char        dest_filename[4096];
+		const char *filename;
+
+		fdata = find_file_in_archive (archive, archive_list_filename);
+
+		if (fdata == NULL)
+			continue;
+
+		if (! archive->propCanExtractNonEmptyFolders
+		    && fdata->dir
+		    && file_list_contains_files_in_this_dir (file_list, archive_list_filename))
+			continue;
+
+		/* get the destination file path. */
+
+		if (! junk_paths)
+			filename = archive_list_filename;
+		else
+			filename = _g_path_get_file_name (archive_list_filename);
+
+		if ((destination[strlen (destination) - 1] == '/')
+		    || (filename[0] == '/'))
+			sprintf (dest_filename, "%s%s", destination, filename);
+		else
+			sprintf (dest_filename, "%s/%s", destination, filename);
+
+		/*debug (DEBUG_INFO, "-> %s\n", dest_filename);*/
+
+		/**/
+
+		if (! archive->propExtractCanSkipOlder
+		    && skip_older
+		    && g_file_test (dest_filename, G_FILE_TEST_EXISTS)
+		    && (fdata->modified < _g_path_get_file_mtime (dest_filename)))
+			continue;
+
+		if (! archive->propExtractCanAvoidOverwrite
+		    && ! overwrite
+		    && g_file_test (dest_filename, G_FILE_TEST_EXISTS))
+			continue;
+
+		filtered = g_list_prepend (filtered, fdata->original_path);
+	}
+
+	if (filtered == NULL) {
+		/* all files got filtered, do nothing. */
+		debug (DEBUG_INFO, "All files got filtered, nothing to do.\n");
+
+		if (extract_all)
+			_g_string_list_free (file_list);
+		return;
+	}
+
+	if (move_to_dest_dir) {
+		char *temp_dir;
+
+		temp_dir = _g_path_get_temp_work_dir (destination);
+		extract_from_archive (self,
+				      filtered,
+				      temp_dir,
+				      overwrite,
+				      skip_older,
+				      junk_paths,
+				      password);
+
+		if (use_base_dir) {
+			GList *tmp_list = compute_list_base_path (base_dir, filtered, junk_paths, archive->propExtractCanJunkPaths);
+			g_list_free (filtered);
+			filtered = tmp_list;
+		}
+
+		move_files_in_chunks (self,
+				      filtered,
+				      temp_dir,
+				      destination,
+				      overwrite);
+
+		/* remove the temp dir. */
+
+		fr_process_begin_command (self->process, "rm");
+		fr_process_add_arg (self->process, "-rf");
+		fr_process_add_arg (self->process, temp_dir);
+		fr_process_end_command (self->process);
+
+		g_free (temp_dir);
+	}
+	else
+		extract_from_archive (self,
+				      filtered,
+				      destination,
+				      overwrite,
+				      skip_older,
+				      junk_paths,
+				      password);
+
+	if (filtered != NULL)
+		g_list_free (filtered);
+	if (file_list_created)
+		_g_string_list_free (file_list);
 }
 
 
-void
-fr_command_uncompress (FrCommand *comm)
+/* -- _fr_command_extract_to_local -- */
+
+
+static void
+process_ready_for_extract_to_local_cb (GObject      *source_object,
+				       GAsyncResult *result,
+				       gpointer      user_data)
 {
-	fr_command_progress (comm, -1.0);
-	FR_COMMAND_GET_CLASS (G_OBJECT (comm))->uncompress (comm);
+	XferData  *xfer_data = user_data;
+	FrError   *error = NULL;
+	FrCommand *self = FR_COMMAND (xfer_data->archive);
+
+	if (! fr_process_execute_finish (FR_PROCESS (source_object), result, &error))
+		g_simple_async_result_set_from_error (xfer_data->result, error->gerror);
+
+	if (error == NULL) {
+		if (self->priv->remote_extraction) {
+			copy_extracted_files_to_destination (xfer_data->archive,
+							     xfer_data->result,
+							     xfer_data->cancellable);
+			xfer_data_free (xfer_data);
+			return;
+		}
+		else if (xfer_data->archive->extract_here)
+			move_here (xfer_data->archive, xfer_data->cancellable);
+	}
+	else {
+		/* if an error occurred during extraction remove the
+		 * temp extraction dir, if used. */
+		g_print ("action_performed: ERROR!\n");
+
+		if ((self->priv->remote_extraction) && (self->priv->temp_extraction_dir != NULL)) {
+			_g_path_remove_directory (self->priv->temp_extraction_dir);
+			g_free (self->priv->temp_extraction_dir);
+			self->priv->temp_extraction_dir = NULL;
+		}
+
+		if (xfer_data->archive->extract_here)
+			_g_uri_remove_directory (fr_archive_get_last_extraction_destination (xfer_data->archive));
+	}
+
+	g_simple_async_result_complete_in_idle (xfer_data->result);
+
+	fr_error_free (error);
+	xfer_data_free (xfer_data);
 }
 
 
-void
-fr_command_recompress (FrCommand *comm)
+static void
+_fr_command_extract_to_local (FrCommand           *self,
+			      GList               *file_list,
+			      const char          *destination,
+			      const char          *base_dir,
+			      gboolean             skip_older,
+			      gboolean             overwrite,
+			      gboolean             junk_paths,
+			      const char          *password,
+			      GCancellable        *cancellable,
+			      GAsyncReadyCallback  callback,
+			      gpointer             user_data)
 {
-	fr_command_progress (comm, -1.0);
-	FR_COMMAND_GET_CLASS (G_OBJECT (comm))->recompress (comm);
+	XferData *xfer_data;
+
+	fr_process_clear (self->process);
+	_fr_command_extract (self,
+			     file_list,
+			     destination,
+			     base_dir,
+			     skip_older,
+			     overwrite,
+			     junk_paths,
+			     password);
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = _g_object_ref (self);
+	xfer_data->cancellable = _g_object_ref (cancellable);
+	xfer_data->result = g_simple_async_result_new (G_OBJECT (self),
+						       callback,
+						       user_data,
+						       fr_archive_extract);
+	fr_process_execute (self->process,
+			    cancellable,
+			    process_ready_for_extract_to_local_cb,
+			    xfer_data);
 }
 
 
-const char **
-fr_command_get_mime_types (FrCommand *comm)
+static void
+fr_command_extract_files (FrArchive           *base,
+			  GList               *file_list,
+			  const char          *destination,
+			  const char          *base_dir,
+			  gboolean             skip_older,
+			  gboolean             overwrite,
+			  gboolean             junk_paths,
+			  const char          *password,
+			  GCancellable        *cancellable,
+			  GAsyncReadyCallback  callback,
+			  gpointer             user_data)
 {
-	return FR_COMMAND_GET_CLASS (G_OBJECT (comm))->get_mime_types (comm);
+	FrCommand *self = FR_COMMAND (base);
+
+	g_free (self->priv->temp_extraction_dir);
+	self->priv->temp_extraction_dir = NULL;
+
+	self->priv->remote_extraction = ! _g_uri_is_local (destination);
+	if (self->priv->remote_extraction) {
+		self->priv->temp_extraction_dir = _g_path_get_temp_work_dir (NULL);
+		_fr_command_extract_to_local (self,
+					     file_list,
+					     self->priv->temp_extraction_dir,
+					     base_dir,
+					     skip_older,
+					     overwrite,
+					     junk_paths,
+					     password,
+					     cancellable,
+					     callback,
+					     user_data);
+	}
+	else {
+		char *local_destination;
+
+		local_destination = g_filename_from_uri (destination, NULL, NULL);
+		_fr_command_extract_to_local (self,
+					     file_list,
+					     local_destination,
+					     base_dir,
+					     skip_older,
+					     overwrite,
+					     junk_paths,
+					     password,
+					     cancellable,
+					     callback,
+					     user_data);
+		g_free (local_destination);
+	}
 }
 
 
-void
-fr_command_update_capabilities (FrCommand *comm)
+/* -- fr_command_test_integrity -- */
+
+
+static void
+process_ready_for_test_integrity (GObject      *source_object,
+				  GAsyncResult *result,
+				  gpointer      user_data)
 {
-	comm->capabilities = fr_command_get_capabilities (comm, comm->mime_type, TRUE);
+	XferData  *xfer_data = user_data;
+	FrError   *error = NULL;
+
+	if (! fr_process_execute_finish (FR_PROCESS (source_object), result, &error))
+		g_simple_async_result_set_from_error (xfer_data->result, error->gerror);
+
+	g_simple_async_result_complete_in_idle (xfer_data->result);
+
+	fr_error_free (error);
+	xfer_data_free (xfer_data);
 }
 
 
-FrCommandCap
-fr_command_get_capabilities (FrCommand  *comm,
-			     const char *mime_type,
-			     gboolean    check_command)
+static void
+fr_command_test_integrity (FrArchive           *archive,
+			   const char          *password,
+			   GCancellable        *cancellable,
+			   GAsyncReadyCallback  callback,
+			   gpointer             user_data)
 {
-	return FR_COMMAND_GET_CLASS (G_OBJECT (comm))->get_capabilities (comm, mime_type, check_command);
+	FrCommand *self = FR_COMMAND (archive);
+	XferData  *xfer_data;
+
+	fr_archive_set_stoppable (archive, TRUE);
+	g_object_set (self,
+		      "filename", self->priv->local_copy,
+		      "password", password,
+		      NULL);
+	fr_archive_set_n_files (archive, 0);
+
+	fr_process_clear (self->process);
+	fr_command_test (self);
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = _g_object_ref (self);
+	xfer_data->cancellable = _g_object_ref (cancellable);
+	xfer_data->result = g_simple_async_result_new (G_OBJECT (self),
+						       callback,
+						       user_data,
+						       fr_archive_test);
+
+	fr_process_execute (self->process,
+			    cancellable,
+			    process_ready_for_test_integrity,
+			    xfer_data);
 }
 
 
-gboolean
-fr_command_is_capable_of (FrCommand     *comm,
-			  FrCommandCaps  requested_capabilities)
+/* -- fr_command_rename -- */
+
+
+static void
+fr_command_rename (FrArchive           *archive,
+		   GList               *file_list,
+		   const char          *old_name,
+		   const char          *new_name,
+		   const char          *current_dir,
+		   gboolean             is_dir,
+		   gboolean             dir_in_archive,
+		   const char          *original_path,
+		   GCancellable        *cancellable,
+		   GAsyncReadyCallback  callback,
+		   gpointer             user_data)
 {
-	return (((comm->capabilities ^ requested_capabilities) & requested_capabilities) == 0);
+	/* FIXME: libarchive */
+#if 0
+	FrCommand *self = FR_COMMAND (archive);
+	char      *tmp_dir;
+	gboolean   added_dir;
+	char      *new_dirname;
+	GList     *new_file_list;
+	GList     *scan;
+	GError    *error = NULL;
+
+	g_object_set (self, "filename", self->priv->local_copy, NULL);
+	tmp_dir = _g_path_get_temp_work_dir (NULL);
+
+	fr_process_clear (self->process);
+
+	_fr_command_extract (self,
+			     file_list,
+			     tmp_dir,
+			     NULL,
+			     FALSE,
+			     TRUE,
+			     FALSE,
+			     archive->password);
+
+	/* temporarily add the dir to rename to the list if it's stored in the
+	 * archive, this way it will be removed from the archive... */
+	added_dir = FALSE;
+	if (is_dir && dir_in_archive && ! g_list_find_custom (file_list, original_path, (GCompareFunc) strcmp)) {
+		file_list = g_list_prepend (file_list, g_strdup (original_path));
+		added_dir = TRUE;
+	}
+
+	_fr_command_remove (self, file_list, archive->compression);
+
+	/* ...and remove it from the list again */
+	if (added_dir) {
+		GList *tmp;
+
+		tmp = file_list;
+		file_list = g_list_remove_link (file_list, tmp);
+
+		g_free (tmp->data);
+		g_list_free (tmp);
+	}
+
+	/* rename the files. */
+
+	new_dirname = g_build_filename (current_dir + 1, new_name, "/", NULL);
+	new_file_list = NULL;
+	if (rdata->is_dir) {
+		char *old_path;
+		char *new_path;
+
+		old_path = g_build_filename (tmp_dir, current_dir, old_name, NULL);
+		new_path = g_build_filename (tmp_dir, current_dir, new_name, NULL);
+
+		fr_process_begin_command (self->process, "mv");
+		fr_process_add_arg (self->process, "-f");
+		fr_process_add_arg (self->process, old_path);
+		fr_process_add_arg (self->process, new_path);
+		fr_process_end_command (self->process);
+
+		g_free (old_path);
+		g_free (new_path);
+	}
+
+	for (scan = file_list; scan; scan = scan->next) {
+		const char *current_dir_relative = current_dir + 1;
+		const char *filename = (char*) scan->data;
+		char       *old_path = NULL, *common = NULL, *new_path = NULL;
+		char       *new_filename;
+
+		old_path = g_build_filename (tmp_dir, filename, NULL);
+
+		if (strlen (filename) > (strlen (current_dir) + strlen (old_name)))
+			common = g_strdup (filename + strlen (current_dir) + strlen (old_name));
+		new_path = g_build_filename (tmp_dir, current_dir, new_name, common, NULL);
+
+		if (! rdata->is_dir) {
+			fr_process_begin_command (self->process, "mv");
+			fr_process_add_arg (self->process, "-f");
+			fr_process_add_arg (self->process, old_path);
+			fr_process_add_arg (self->process, new_path);
+			fr_process_end_command (self->process);
+		}
+
+		new_filename = g_build_filename (current_dir_relative, new_name, common, NULL);
+		new_file_list = g_list_prepend (new_file_list, new_filename);
+
+		g_free (old_path);
+		g_free (common);
+		g_free (new_path);
+	}
+	new_file_list = g_list_reverse (new_file_list);
+
+	/* FIXME: this is broken for tar archives.
+	if (is_dir && dir_in_archive && ! g_list_find_custom (new_file_list, new_dirname, (GCompareFunc) strcmp))
+		new_file_list = g_list_prepend (new_file_list, g_build_filename (rdata->current_dir + 1, rdata->new_name, NULL));
+	*/
+
+	if (! _fr_command_add (self,
+			       new_file_list,
+			       tmp_dir,
+			       NULL,
+			       FALSE,
+			       FALSE,
+			       archive->password,
+			       archive->encrypt_header,
+			       archive->compression,
+			       archive->volume_size,
+			       &error))
+	{
+		/* FIXME */
+	}
+
+	g_free (new_dirname);
+	_g_string_list_free (new_file_list);
+
+	/* remove the tmp dir */
+
+	fr_process_begin_command (self->process, "rm");
+	fr_process_set_working_dir (self->process, g_get_tmp_dir ());
+	fr_process_set_sticky (self->process, TRUE);
+	fr_process_add_arg (self->process, "-rf");
+	fr_process_add_arg (self->process, tmp_dir);
+	fr_process_end_command (self->process);
+
+	fr_process_start (self->process);
+
+	g_free (tmp_dir);
+#endif
 }
 
 
-const char *
-fr_command_get_packages (FrCommand  *comm,
-			 const char *mime_type)
+/* -- fr_command_paste_clipboard -- */
+
+
+static void
+process_ready_for_paste_clipboard (GObject      *source_object,
+				   GAsyncResult *result,
+				   gpointer      user_data)
 {
-	return FR_COMMAND_GET_CLASS (G_OBJECT (comm))->get_packages (comm, mime_type);
+	XferData  *xfer_data = user_data;
+	FrError   *error = NULL;
+
+	if (! fr_process_execute_finish (FR_PROCESS (source_object), result, &error))
+		g_simple_async_result_set_from_error (xfer_data->result, error->gerror);
+
+	g_simple_async_result_complete_in_idle (xfer_data->result);
+
+	fr_error_free (error);
+	xfer_data_free (xfer_data);
 }
 
 
-/* fraction == -1 means : I don't known how much time the current operation
- *                        will take, the dialog will display this info pulsing
- *                        the progress bar.
- * fraction in [0.0, 1.0] means the amount of work, in percentage,
- *                        accomplished.
- */
-void
-fr_command_progress (FrCommand *comm,
-		     double     fraction)
+static void
+fr_command_paste_clipboard (FrArchive           *archive,
+		    	    char                *archive_uri,
+		    	    char                *password,
+		    	    gboolean             encrypt_header,
+		    	    FrCompression        compression,
+		    	    guint                volume_size,
+		    	    FrClipboardOp        op,
+		    	    char                *base_dir,
+		    	    GList               *files,
+		    	    char                *tmp_dir,
+		    	    char                *current_dir,
+		    	    GCancellable        *cancellable,
+		    	    GAsyncReadyCallback  callback,
+		    	    gpointer             user_data)
+{
+	FrCommand  *command = FR_COMMAND (archive);
+	const char *current_dir_relative = current_dir + 1;
+	GList      *scan;
+	GList      *new_file_list = NULL;
+	GError     *error = NULL;
+	XferData   *xfer_data;
+
+	fr_process_clear (command->process);
+
+	for (scan = files; scan; scan = scan->next) {
+		const char *old_name = (char*) scan->data;
+		char       *new_name = g_build_filename (current_dir_relative, old_name + strlen (base_dir) - 1, NULL);
+
+		/* skip folders */
+
+		if ((strcmp (old_name, new_name) != 0)
+		    && (old_name[strlen (old_name) - 1] != '/'))
+		{
+			fr_process_begin_command (command->process, "mv");
+			fr_process_set_working_dir (command->process, tmp_dir);
+			fr_process_add_arg (command->process, "-f");
+			if (old_name[0] == '/')
+				old_name = old_name + 1;
+			fr_process_add_arg (command->process, old_name);
+			fr_process_add_arg (command->process, new_name);
+			fr_process_end_command (command->process);
+		}
+
+		new_file_list = g_list_prepend (new_file_list, new_name);
+	}
+
+	if (! _fr_command_add (command,
+			       new_file_list,
+			       tmp_dir,
+			       NULL,
+			       FALSE,
+			       FALSE,
+			       password,
+			       encrypt_header,
+			       compression,
+			       volume_size,
+			       &error))
+	{
+		GSimpleAsyncResult *result;
+
+		result = g_simple_async_result_new (G_OBJECT (command),
+						    callback,
+						    user_data,
+						    fr_archive_paste_clipboard);
+
+		if (error != NULL) {
+			g_simple_async_result_set_from_error (result, error);
+			g_error_free (error);
+		}
+
+		g_simple_async_result_complete_in_idle (result);
+
+		g_object_unref (result);
+		return;
+	}
+
+	_g_string_list_free (new_file_list);
+
+	/* remove the tmp dir */
+
+	fr_process_begin_command (command->process, "rm");
+	fr_process_set_working_dir (command->process, g_get_tmp_dir ());
+	fr_process_set_sticky (command->process, TRUE);
+	fr_process_add_arg (command->process, "-rf");
+	fr_process_add_arg (command->process, tmp_dir);
+	fr_process_end_command (command->process);
+
+	/**/
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = _g_object_ref (command);
+	xfer_data->cancellable = _g_object_ref (cancellable);
+	xfer_data->result = g_simple_async_result_new (G_OBJECT (command),
+						       callback,
+						       user_data,
+						       fr_archive_paste_clipboard);
+
+	fr_process_execute (command->process,
+			    cancellable,
+			    process_ready_for_paste_clipboard,
+			    xfer_data);
+}
+
+
+/* -- fr_command_add_dropped_items -- */
+
+
+static gboolean
+all_files_in_same_dir (GList *list)
+{
+	gboolean  same_dir = TRUE;
+	char     *first_basedir;
+	GList    *scan;
+
+	if (list == NULL)
+		return FALSE;
+
+	first_basedir = _g_path_remove_level (list->data);
+	if (first_basedir == NULL)
+		return TRUE;
+
+	for (scan = list->next; scan; scan = scan->next) {
+		char *path = scan->data;
+		char *basedir;
+
+		basedir = _g_path_remove_level (path);
+		if (basedir == NULL) {
+			same_dir = FALSE;
+			break;
+		}
+
+		if (strcmp (first_basedir, basedir) != 0) {
+			same_dir = FALSE;
+			g_free (basedir);
+			break;
+		}
+		g_free (basedir);
+	}
+	g_free (first_basedir);
+
+	return same_dir;
+}
+
+
+static void
+add_dropped_items (DroppedItemsData *data)
+{
+	FrCommand *self = data->command;
+	GList     *list = data->item_list;
+	GList     *scan;
+
+	if (list == NULL) {
+		GSimpleAsyncResult *result;
+
+		result = g_simple_async_result_new (G_OBJECT (data->command),
+						    data->callback,
+						    data->user_data,
+						    fr_archive_add_dropped_items);
+		g_simple_async_result_complete_in_idle (result);
+
+		dropped_items_data_free (self->priv->dropped_items_data);
+		self->priv->dropped_items_data = NULL;
+		return;
+	}
+
+	/* if all files/dirs are in the same directory call fr_archive_add_items... */
+
+	if (all_files_in_same_dir (list)) {
+		char *first_base_dir;
+
+		first_base_dir = _g_path_remove_level (list->data);
+		fr_archive_add_items (FR_ARCHIVE (self),
+				      list,
+				      first_base_dir,
+				      data->dest_dir,
+				      data->update,
+				      data->password,
+				      data->encrypt_header,
+				      data->compression,
+				      data->volume_size,
+				      data->cancellable,
+				      data->callback,
+				      data->user_data);
+
+		g_free (first_base_dir);
+		dropped_items_data_free (self->priv->dropped_items_data);
+		self->priv->dropped_items_data = NULL;
+
+		return;
+	}
+
+	/* ...else add a directory at a time. */
+
+	for (scan = list; scan; scan = scan->next) {
+		char *path = scan->data;
+		char *base_dir;
+
+		if (! _g_uri_query_is_dir (path))
+			continue;
+
+		data->item_list = g_list_remove_link (list, scan);
+		if (data->item_list != NULL)
+			self->priv->continue_adding_dropped_items = TRUE;
+		base_dir = _g_path_remove_level (path);
+
+		fr_archive_add_directory (FR_ARCHIVE (self),
+					  _g_path_get_file_name (path),
+					  base_dir,
+					  data->dest_dir,
+					  data->update,
+					  data->password,
+					  data->encrypt_header,
+					  data->compression,
+					  data->volume_size,
+					  data->cancellable,
+					  data->callback,
+					  data->user_data);
+
+		g_free (base_dir);
+		g_free (path);
+
+		return;
+	}
+
+	/* if all files are in the same directory call fr_archive_add_files. */
+
+	if (all_files_in_same_dir (list)) {
+		char  *first_basedir;
+		GList *only_names_list = NULL;
+
+		first_basedir = _g_path_remove_level (list->data);
+
+		for (scan = list; scan; scan = scan->next) {
+			char *name;
+
+			name = g_uri_unescape_string (_g_path_get_file_name (scan->data), NULL);
+			only_names_list = g_list_prepend (only_names_list, name);
+		}
+
+		fr_archive_add_files (FR_ARCHIVE (self),
+				      only_names_list,
+				      first_basedir,
+				      data->dest_dir,
+				      data->update,
+				      FALSE,
+				      data->password,
+				      data->encrypt_header,
+				      data->compression,
+				      data->volume_size,
+				      data->cancellable,
+				      data->callback,
+				      data->user_data);
+
+		_g_string_list_free (only_names_list);
+		g_free (first_basedir);
+
+		return;
+	}
+
+	/* ...else call fr_command_add for each file.  This is needed to add
+	 * files without path info. FIXME: doesn't work with remote files. */
+
+	fr_archive_set_stoppable (FR_ARCHIVE (self), TRUE);
+	self->creating_archive = ! g_file_query_exists (self->priv->local_copy, data->cancellable);
+	g_object_set (self,
+		      "filename", self->priv->local_copy,
+		      "password", data->password,
+		      "encrypt_header", data->encrypt_header,
+		      "compression", data->compression,
+		      "volume_size", data->volume_size,
+		      NULL);
+
+	fr_process_clear (self->process);
+	fr_command_uncompress (self);
+	for (scan = list; scan; scan = scan->next) {
+		char  *fullpath = scan->data;
+		char  *basedir;
+		GList *singleton;
+
+		basedir = _g_path_remove_level (fullpath);
+		singleton = g_list_prepend (NULL, (char*)_g_path_get_file_name (fullpath));
+		fr_command_add (self,
+				NULL,
+				singleton,
+				basedir,
+				data->update,
+				FALSE);
+		g_list_free (singleton);
+		g_free (basedir);
+	}
+	fr_command_recompress (self);
+	fr_process_execute (self->process,
+			    data->cancellable,
+			    data->callback,
+			    data->user_data);
+
+	_g_string_list_free (data->item_list);
+	data->item_list = NULL;
+}
+
+
+static void
+fr_command_add_dropped_items (FrArchive           *archive,
+		   	      GList               *item_list,
+		   	      const char          *base_dir,
+		   	      const char          *dest_dir,
+		   	      gboolean             update,
+		   	      const char          *password,
+		   	      gboolean             encrypt_header,
+		   	      FrCompression        compression,
+		   	      guint                volume_size,
+		   	      GCancellable        *cancellable,
+		   	      GAsyncReadyCallback  callback,
+		   	      gpointer             user_data)
+{
+	FrCommand *self = FR_COMMAND (archive);
+
+	if (self->priv->dropped_items_data != NULL)
+		dropped_items_data_free (self->priv->dropped_items_data);
+	self->priv->dropped_items_data = dropped_items_data_new (self,
+								 item_list,
+								 base_dir,
+								 dest_dir,
+								 update,
+								 password,
+								 encrypt_header,
+								 compression,
+								 volume_size,
+								 cancellable,
+								 callback,
+								 user_data);
+	add_dropped_items (self->priv->dropped_items_data);
+}
+
+
+/* -- fr_command_update_open_files -- */
+
+
+static void
+process_ready_for_update_open_files (GObject      *source_object,
+				     GAsyncResult *result,
+				     gpointer      user_data)
 {
-	g_signal_emit (G_OBJECT (comm),
-		       fr_command_signals[PROGRESS],
-		       0,
-		       fraction);
+	XferData *xfer_data = user_data;
+	FrError  *error = NULL;
+
+	if (! fr_process_execute_finish (FR_PROCESS (source_object), result, &error))
+		g_simple_async_result_set_from_error (xfer_data->result, error->gerror);
+
+	g_simple_async_result_complete_in_idle (xfer_data->result);
+
+	fr_error_free (error);
+	xfer_data_free (xfer_data);
 }
 
 
-void
-fr_command_message (FrCommand  *comm,
-		    const char *msg)
+static void
+fr_command_update_open_files (FrArchive           *archive,
+			      GList               *file_list,
+			      GList               *dir_list,
+			      const char          *password,
+			      gboolean             encrypt_header,
+			      FrCompression        compression,
+			      guint                volume_size,
+		   	      GCancellable        *cancellable,
+		   	      GAsyncReadyCallback  callback,
+		   	      gpointer             user_data)
 {
-	g_signal_emit (G_OBJECT (comm),
-		       fr_command_signals[MESSAGE],
-		       0,
-		       msg);
+	FrCommand *self = FR_COMMAND (archive);
+	GList     *scan_file, *scan_dir;
+	XferData  *xfer_data;
+
+	fr_process_clear (self->process);
+
+	for (scan_file = file_list, scan_dir = dir_list;
+	     scan_file && scan_dir;
+	     scan_file = scan_file->next, scan_dir = scan_dir->next)
+	{
+		char  *filepath = scan_file->data;
+		char  *dirpath = scan_dir->data;
+		GList *local_file_list;
+
+		local_file_list = g_list_append (NULL, filepath);
+		_fr_command_add (self,
+				 local_file_list,
+				 dirpath,
+				 "/",
+				 FALSE,
+				 FALSE,
+				 password,
+				 encrypt_header,
+				 compression,
+				 volume_size,
+				 NULL);
+
+		g_list_free (local_file_list);
+	}
+
+	/**/
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = _g_object_ref (self);
+	xfer_data->cancellable = _g_object_ref (cancellable);
+	xfer_data->result = g_simple_async_result_new (G_OBJECT (self),
+						       callback,
+						       user_data,
+						       fr_archive_update_open_files);
+
+	fr_process_execute (self->process,
+			    cancellable,
+			    process_ready_for_update_open_files,
+			    xfer_data);
 }
 
 
-void
-fr_command_working_archive (FrCommand  *comm,
-		            const char *archive_name)
+static void
+fr_command_class_init (FrCommandClass *klass)
 {
-	g_signal_emit (G_OBJECT (comm),
-		       fr_command_signals[WORKING_ARCHIVE],
-		       0,
-		       archive_name);
+	GObjectClass   *gobject_class;
+	FrArchiveClass *archive_class;
+
+	fr_command_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (FrCommandPrivate));
+
+	gobject_class = G_OBJECT_CLASS (klass);
+	gobject_class->set_property = fr_command_set_property;
+	gobject_class->get_property = fr_command_get_property;
+	gobject_class->finalize = fr_command_finalize;
+
+	archive_class = FR_ARCHIVE_CLASS (klass);
+	archive_class->load = fr_command_load;
+	archive_class->add_files = fr_command_add_files;
+	archive_class->remove_files = fr_command_remove_files;
+	archive_class->extract_files = fr_command_extract_files;
+	archive_class->test_integrity = fr_command_test_integrity;
+	archive_class->rename = fr_command_rename;
+	archive_class->paste_clipboard = fr_command_paste_clipboard;
+	archive_class->add_dropped_items = fr_command_add_dropped_items;
+	archive_class->update_open_files = fr_command_update_open_files;
+
+	/* properties */
+
+	g_object_class_install_property (gobject_class,
+					 PROP_PROCESS,
+					 g_param_spec_object ("process",
+							      "Process",
+							      "The process object used by the command",
+							      FR_TYPE_PROCESS,
+							      G_PARAM_READWRITE));
+	g_object_class_install_property (gobject_class,
+					 PROP_FILENAME,
+					 g_param_spec_object ("filename",
+							      "Filename",
+							      "The path of the archive the command will use (can be different from local_copy)",
+							      G_TYPE_FILE,
+							      G_PARAM_READWRITE));
 }
 
 
-void
-fr_command_set_n_files (FrCommand *comm,
-			int        n_files)
+static GFile *
+get_local_copy_for_file (GFile *remote_file)
 {
-	comm->n_files = n_files;
-	comm->n_file = 0;
+	char  *temp_dir;
+	GFile *local_copy = NULL;
+
+	temp_dir = _g_path_get_temp_work_dir (NULL);
+	if (temp_dir != NULL) {
+		char  *archive_name;
+		char  *local_path;
+
+		archive_name = g_file_get_basename (remote_file);
+		local_path = g_build_filename (temp_dir, archive_name, NULL);
+		local_copy = g_file_new_for_path (local_path);
+
+		g_free (local_path);
+		g_free (archive_name);
+	}
+	g_free (temp_dir);
+
+	return local_copy;
 }
 
 
-void
-fr_command_add_file (FrCommand *comm,
-		     FileData  *fdata)
+static void
+archive_file_changed_cb (GObject    *object,
+			 GParamSpec *spec,
+			 gpointer    user_data)
 {
-	file_data_update_content_type (fdata);
-	g_ptr_array_add (comm->files, fdata);
-	if (! fdata->dir)
-		comm->n_regular_files++;
+	FrCommand *self = user_data;
+	GFile            *file;
+
+	/* FIXME: if multi_volume... */
+
+	if ((self->priv->local_copy != NULL) && self->priv->is_remote) {
+		GFile  *temp_folder;
+		GError *err = NULL;
+
+		g_file_delete (self->priv->local_copy, NULL, &err);
+		if (err != NULL) {
+			g_warning ("Failed to delete the local copy: %s", err->message);
+			g_clear_error (&err);
+		}
+
+		temp_folder = g_file_get_parent (self->priv->local_copy);
+		g_file_delete (temp_folder, NULL, &err);
+		if (err != NULL) {
+			g_warning ("Failed to delete temp folder: %s", err->message);
+			g_clear_error (&err);
+		}
+
+		g_object_unref (temp_folder);
+	}
+
+	if (self->priv->local_copy != NULL) {
+		g_object_unref (self->priv->local_copy);
+		self->priv->local_copy = NULL;
+	}
+
+	file = fr_archive_get_file (FR_ARCHIVE (object));
+	self->priv->is_remote = ! g_file_has_uri_scheme (file, "file");
+	if (self->priv->is_remote)
+		self->priv->local_copy = get_local_copy_for_file (file);
+	else
+		self->priv->local_copy = g_file_dup (file);
+
+	_fr_command_set_filename_from_file (self, self->priv->local_copy);
 }
 
 
-void
-fr_command_set_mime_type (FrCommand  *comm,
-			  const char *mime_type)
+static void
+fr_command_init (FrCommand *self)
 {
-	FR_COMMAND_GET_CLASS (G_OBJECT (comm))->set_mime_type (comm, mime_type);
+	FrProcess *process;
+
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, FR_TYPE_COMMAND, FrCommandPrivate);
+
+	self->priv->local_copy = NULL;
+	self->priv->is_remote = FALSE;
+	self->priv->temp_dir = NULL;
+	self->priv->continue_adding_dropped_items = FALSE;
+	self->priv->dropped_items_data = NULL;
+	self->priv->temp_extraction_dir = NULL;
+	self->priv->remote_extraction = FALSE;
+
+	self->filename = NULL;
+	self->e_filename = NULL;
+	self->creating_archive = FALSE;
+
+	process = fr_process_new ();
+	_fr_command_set_process (self, process);
+	g_object_unref (process);
+
+	g_signal_connect (self,
+			  "notify::file",
+			  G_CALLBACK (archive_file_changed_cb),
+			  self);
 }
 
 
-void
-fr_command_handle_error (FrCommand   *comm,
-			 FrProcError *error)
+GList  *
+fr_command_get_last_output (FrCommand *self)
 {
-	FR_COMMAND_GET_CLASS (G_OBJECT (comm))->handle_error (comm, error);
+	return (self->process->err.raw != NULL) ? self->process->err.raw : self->process->out.raw;
 }
diff --git a/src/fr-command.h b/src/fr-command.h
index 4c2c511..9ba01e9 100644
--- a/src/fr-command.h
+++ b/src/fr-command.h
@@ -3,7 +3,7 @@
 /*
  *  File-Roller
  *
- *  Copyright (C) 2001 The Free Software Foundation, Inc.
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@
 #define FR_COMMAND_H
 
 #include <glib.h>
-#include "file-data.h"
+#include "fr-archive.h"
 #include "fr-process.h"
 
 #define PACKAGES(x) (x)
@@ -35,273 +35,53 @@
 #define FR_IS_COMMAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FR_TYPE_COMMAND))
 #define FR_COMMAND_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), FR_TYPE_COMMAND, FrCommandClass))
 
-typedef struct _FrCommand         FrCommand;
-typedef struct _FrCommandClass    FrCommandClass;
+typedef struct _FrCommand        FrCommand;
+typedef struct _FrCommandClass   FrCommandClass;
+typedef struct _FrCommandPrivate FrCommandPrivate;
 
-typedef enum {
-	FR_ACTION_NONE,
-	FR_ACTION_CREATING_NEW_ARCHIVE,
-	FR_ACTION_LOADING_ARCHIVE,            /* loading the archive from a remote location */
-	FR_ACTION_LISTING_CONTENT,            /* listing the content of the archive */
-	FR_ACTION_DELETING_FILES,             /* deleting files from the archive */
-	FR_ACTION_TESTING_ARCHIVE,            /* testing the archive integrity */
-	FR_ACTION_GETTING_FILE_LIST,          /* getting the file list (when fr_archive_add_with_wildcard or
-						 fr_archive_add_directory are used, we need to scan a directory
-						 and collect the files to add to the archive, this
-						 may require some time to complete, so the operation
-						 is asynchronous) */
-	FR_ACTION_COPYING_FILES_FROM_REMOTE,  /* copying files to be added to the archive from a remote location */
-	FR_ACTION_ADDING_FILES,               /* adding files to an archive */
-	FR_ACTION_EXTRACTING_FILES,           /* extracting files */
-	FR_ACTION_COPYING_FILES_TO_REMOTE,    /* copying extracted files to a remote location */
-	FR_ACTION_CREATING_ARCHIVE,           /* creating a local archive */
-	FR_ACTION_SAVING_REMOTE_ARCHIVE       /* copying the archive to a remote location */
-} FrAction;
+struct _FrCommand {
+	FrArchive  __parent;
+	FrCommandPrivate *priv;
 
-#ifdef DEBUG
-extern char *action_names[];
-#endif
+	/*<protected, read only>*/
 
-struct _FrCommand
-{
-	GObject  __parent;
-
-	/*<public, read only>*/
-
-	GPtrArray     *files;           /* Array of FileData* */
-	int            n_regular_files;
-	FrProcess     *process;         /* the process object used to execute
-				         * commands. */
-	char          *filename;        /* archive file path. */
-	char          *e_filename;      /* escaped archive filename. */
-	const char    *mime_type;
-	gboolean       multi_volume;
-
-	/*<protected>*/
-
-	/* options */
-
-	char          *password;
-	gboolean       encrypt_header : 1;
-	FrCompression  compression;
-	guint          volume_size;
-	gboolean       creating_archive;
-
-	/* command features. */
-
-	/* propAddCanReplace:
-	 *
-	 * TRUE if the command can overwrite a file in the archive.
-	 */
-	guint          propAddCanReplace : 1;
-
-	/* propAddCanReplace:
-	 *
-	 * TRUE if the command can overwrite a file in the archive if older
-	 * then the file on disk.
-	 */
-	guint          propAddCanUpdate : 1;
-
-	/* propAddCanStoreFolders:
-	 *
-	 * TRUE if the command can store folder entries inside the archive.
-	 */
-	guint          propAddCanStoreFolders : 1;
-
-	/* propExtractCanAvoidOverwrite:
-	 *
-	 * TRUE if the command can avoid to overwrite the files on disk.
-	 */
-	guint          propExtractCanAvoidOverwrite : 1;
-
-	/* propExtractCanSkipOlder:
-	 *
-	 * TRUE if the command can avoid to overwrite a file on disk when it is
-	 * newer than the file in the archive.
-	 */
-	guint          propExtractCanSkipOlder : 1;
-
-	/* propExtractCanJunkPaths:
-	 *
-	 * TRUE if the command can extract the files in the current folder
-	 * without recreating the directory structure.
-	 */
-	guint          propExtractCanJunkPaths : 1;
-
-	/* propPassword:
-	 *
-	 * TRUE if the command can use passwords for adding or extracting files.
-	 */
-	guint          propPassword : 1;
-
-	/* propTest:
-	 *
-	 * TRUE if the command can test the archive integrity.
-	 */
-	guint          propTest : 1;
-
-	/* propCanExtractAll:
-	 *
-	 * TRUE if the command extract all the files when no file is specified.
-	 */
-	guint          propCanExtractAll : 1;
-
-	/* propCanDeleteNonEmptyFolders:
-	 *
-	 * is used to overcome an issue with tar, that deletes only the folder
-	 * entry in the archive instead of deleting the folder content
-	 * recursively.
-	 */
-	guint          propCanDeleteNonEmptyFolders : 1;
-
-	/* propCanExtractNonEmptyFolders:
-	 *
-	 * is used to overcome an issue with tar.  For example if
-	 * the content of a tar archive is
-	 *
-	 * readme.txt
-	 * doc/
-	 * doc/page1.html
-	 * doc/page2.html
-	 *
-	 * and we want to extract the content of the doc folder, the command:
-	 *
-	 * tar -xf archive.tar doc doc/page1.html doc/page2.html
-	 *
-	 * gives an error.
-	 * To fix the issue we have to remove the files inside the doc
-	 * folder from the command line, getting the following command:
-	 *
-	 * tar -xf archive.tar doc
-	 */
-	guint          propCanExtractNonEmptyFolders : 1;
-
-	/* propListFromFile:
-	 *
-	 * if TRUE the command has an option to read the file list from a file
-	 */
-	guint          propListFromFile : 1;
-
-	/*<private>*/
-
-	FrCommandCaps  capabilities;
-	FrAction       action;        /* current action. */
-	gboolean       fake_load;     /* if TRUE does nothing when the list
-				       * operation is invoked. */
-
-	/* progress data */
-
-	int            n_file;
-	int            n_files;
+	FrProcess *process;         /* the process object used to execute
+				     * commands. */
+	char      *filename;        /* local archive file path. */
+	char      *e_filename;      /* escaped filename. */
+	gboolean   creating_archive;
 };
 
-struct _FrCommandClass
-{
-	GObjectClass __parent_class;
+struct _FrCommandClass {
+	FrArchiveClass __parent_class;
 
 	/*<virtual functions>*/
 
-	void          (*list)             (FrCommand     *comm);
-	void          (*add)              (FrCommand     *comm,
-					   const char    *from_file,
-				           GList         *file_list,
-				           const char    *base_dir,
-				           gboolean       update,
-				           gboolean       recursive);
-	void          (*delete)           (FrCommand     *comm,
-			                   const char    *from_file,
-				           GList         *file_list);
-	void          (*extract)          (FrCommand     *comm,
-			                   const char    *from_file,
-				           GList         *file_list,
-				           const char    *dest_dir,
-				           gboolean       overwrite,
-				           gboolean       skip_older,
-				           gboolean       junk_paths);
-	void          (*test)             (FrCommand     *comm);
-	void          (*uncompress)       (FrCommand     *comm);
-	void          (*recompress)       (FrCommand     *comm);
-	void          (*handle_error)     (FrCommand     *comm,
-				           FrProcError   *error);
-	const char ** (*get_mime_types)   (FrCommand     *comm);
-	FrCommandCap  (*get_capabilities) (FrCommand     *comm,
-					   const char    *mime_type,
-					   gboolean       check_command);
-	void          (*set_mime_type)    (FrCommand     *comm,
-				           const char    *mime_type);
-	const char *  (*get_packages)     (FrCommand     *comm,
-					   const char    *mime_type);
-
-	/*<signals>*/
-
-	void          (*start)            (FrCommand   *comm,
-			 	           FrAction     action);
-	void          (*done)             (FrCommand   *comm,
-				           FrAction     action,
-				           FrProcError *error);
-	void          (*progress)         (FrCommand   *comm,
-				           double       fraction);
-	void          (*message)          (FrCommand   *comm,
-				           const char  *msg);
-	void          (*working_archive)  (FrCommand   *comm,
-					   const char  *filename);
+	gboolean  (*list)           (FrCommand   *comm);
+	void      (*add)            (FrCommand   *comm,
+				     const char  *from_file,
+				     GList       *file_list,
+				     const char  *base_dir,
+				     gboolean     update,
+				     gboolean     recursive);
+	void      (*delete)         (FrCommand   *comm,
+		                     const char  *from_file,
+		                     GList       *file_list);
+	void      (*extract)        (FrCommand   *comm,
+		                     const char  *from_file,
+		                     GList       *file_list,
+		                     const char  *dest_dir,
+		                     gboolean     overwrite,
+		                     gboolean     skip_older,
+		                     gboolean     junk_paths);
+	void      (*test)           (FrCommand   *comm);
+	void      (*uncompress)     (FrCommand   *comm);
+	void      (*recompress)     (FrCommand   *comm);
+	void      (*handle_error)   (FrCommand   *comm,
+			             FrError     *error);
 };
 
-GType          fr_command_get_type            (void);
-void           fr_command_set_file            (FrCommand     *comm,
-					       GFile         *file);
-void           fr_command_set_multi_volume    (FrCommand     *comm,
-					       GFile         *file);
-void           fr_command_list                (FrCommand     *comm);
-void           fr_command_add                 (FrCommand     *comm,
-					       const char    *from_file,
-					       GList         *file_list,
-					       const char    *base_dir,
-					       gboolean       update,
-					       gboolean       recursive);
-void           fr_command_delete              (FrCommand     *comm,
-					       const char    *from_file,
-					       GList         *file_list);
-void           fr_command_extract             (FrCommand     *comm,
-					       const char    *from_file,
-					       GList         *file_list,
-					       const char    *dest_dir,
-					       gboolean       overwrite,
-					       gboolean       skip_older,
-					       gboolean       junk_paths);
-void           fr_command_test                (FrCommand     *comm);
-void           fr_command_uncompress          (FrCommand     *comm);
-void           fr_command_recompress          (FrCommand     *comm);
-gboolean       fr_command_is_capable_of       (FrCommand     *comm,
-					       FrCommandCaps  capabilities);
-const char **  fr_command_get_mime_types      (FrCommand     *comm);
-void           fr_command_update_capabilities (FrCommand     *comm);
-FrCommandCap   fr_command_get_capabilities    (FrCommand     *comm,
-					       const char    *mime_type,
-					       gboolean       check_command);
-void           fr_command_set_mime_type       (FrCommand     *comm,
-					       const char    *mime_type);
-gboolean       fr_command_is_capable_of       (FrCommand     *comm,
-					       FrCommandCaps  capabilities);
-const char *   fr_command_get_packages        (FrCommand     *comm,
-					       const char    *mime_type);
-
-/* protected functions */
-
-void           fr_command_progress            (FrCommand     *comm,
-					       double         fraction);
-void           fr_command_message             (FrCommand     *comm,
-					       const char    *msg);
-void           fr_command_working_archive     (FrCommand     *comm,
-		                               const char    *archive_name);
-void           fr_command_set_n_files         (FrCommand     *comm,
-					       int            n_files);
-void           fr_command_add_file            (FrCommand     *comm,
-					       FileData      *fdata);
-
-/* private functions */
-
-void           fr_command_handle_error        (FrCommand     *comm,
-					       FrProcError   *error);
+GType    fr_command_get_type         (void);
+GList *  fr_command_get_last_output  (FrCommand *command);
 
 #endif /* FR_COMMAND_H */
diff --git a/src/fr-error.c b/src/fr-error.c
index 6c4d0f5..530f3e5 100644
--- a/src/fr-error.c
+++ b/src/fr-error.c
@@ -23,13 +23,80 @@
 #include "fr-error.h"
 
 
-GQuark 
+GQuark
 fr_error_quark (void)
 {
 	static GQuark quark;
-        
+
         if (!quark)
-                quark = g_quark_from_static_string ("file-roller-error");
-	
+                quark = g_quark_from_static_string ("FrError");
+
         return quark;
 }
+
+
+G_DEFINE_BOXED_TYPE (FrError,
+		     fr_error,
+		     fr_error_copy,
+		     fr_error_free);
+
+
+FrError *
+fr_error_new (FrErrorType  type,
+	      int          status,
+	      GError      *gerror)
+{
+	FrError *error;
+
+	error = g_new0 (FrError, 1);
+	fr_error_set (error, type, status, gerror);
+
+	return error;
+}
+
+
+FrError *
+fr_error_copy (FrError *error)
+{
+	if (error != NULL)
+		return fr_error_new (error->type, error->status, error->gerror);
+	else
+		return NULL;
+}
+
+
+void
+fr_error_free (FrError *error)
+{
+	if (error == NULL)
+		return;
+	g_clear_error (&error->gerror);
+	g_free (error);
+}
+
+
+void
+fr_error_set (FrError     *error,
+	      FrErrorType  type,
+	      int          status,
+	      GError      *gerror)
+{
+	error->type = type;
+	error->status = status;
+	if (gerror != error->gerror) {
+		g_clear_error (&error->gerror);
+		if (gerror != NULL)
+			error->gerror = g_error_copy (gerror);
+	}
+}
+
+
+void
+fr_clear_error (FrError **error)
+{
+	if ((error == NULL) || (*error == NULL))
+		return;
+
+	fr_error_free (*error);
+	*error = NULL;
+}
diff --git a/src/fr-error.h b/src/fr-error.h
index 1614954..39dc2ed 100644
--- a/src/fr-error.h
+++ b/src/fr-error.h
@@ -23,9 +23,43 @@
 #define __FR_ERROR_H__
 
 #include <glib.h>
+#include <glib-object.h>
 
 #define FR_ERROR fr_error_quark ()
-GQuark fr_error_quark (void);
+#define FR_TYPE_ERROR (fr_error_get_type ())
 
+typedef enum { /*< skip >*/
+	FR_ERROR_NONE,
+	FR_ERROR_GENERIC,
+	FR_ERROR_COMMAND_ERROR,
+	FR_ERROR_COMMAND_NOT_FOUND,
+	FR_ERROR_EXITED_ABNORMALLY,
+	FR_ERROR_SPAWN,
+	FR_ERROR_STOPPED,
+	FR_ERROR_ASK_PASSWORD,
+	FR_ERROR_MISSING_VOLUME,
+	FR_ERROR_IO_CHANNEL,
+	FR_ERROR_BAD_CHARSET,
+	FR_ERROR_UNSUPPORTED_FORMAT
+} FrErrorType;
+
+typedef struct {
+	GError      *gerror;
+	FrErrorType  type;
+	int          status;
+} FrError;
+
+GQuark     fr_error_quark      (void);
+GType      fr_error_get_type   (void);
+FrError *  fr_error_new        (FrErrorType   type,
+				int           status,
+				GError       *gerror);
+FrError *  fr_error_copy       (FrError      *error);
+void       fr_error_free       (FrError      *error);
+void       fr_error_set        (FrError      *error,
+				FrErrorType   type,
+				int           status,
+				GError       *gerror);
+void       fr_clear_error      (FrError     **error);
 
 #endif /* __FR_ERROR_H__ */
diff --git a/src/fr-init.c b/src/fr-init.c
index 08a33ee..1dfd3d1 100644
--- a/src/fr-init.c
+++ b/src/fr-init.c
@@ -167,7 +167,7 @@ FrExtensionType file_ext_type[] = {
 GList        *CommandList;
 gint          ForceDirectoryCreation;
 GHashTable   *ProgramsCache;
-GPtrArray    *Registered_Commands;
+GPtrArray    *Registered_Archives;
 int           single_file_save_type[64];
 int           save_type[64];
 int           open_type[64];
@@ -200,25 +200,25 @@ migrate_options_directory (void)
 }
 
 
-/* -- FrRegisteredCommand -- */
+/* -- FrRegisteredArchive -- */
 
 
-static FrRegisteredCommand *
-fr_registered_command_new (GType command_type)
+static FrRegisteredArchive *
+fr_registered_archive_new (GType command_type)
 {
-	FrRegisteredCommand  *reg_com;
-	FrCommand            *command;
+	FrRegisteredArchive  *reg_com;
+	FrArchive            *archive;
 	const char          **mime_types;
 	int                   i;
 
-	reg_com = g_new0 (FrRegisteredCommand, 1);
+	reg_com = g_new0 (FrRegisteredArchive, 1);
 	reg_com->ref = 1;
 	reg_com->type = command_type;
 	reg_com->caps = g_ptr_array_new ();
 	reg_com->packages = g_ptr_array_new ();
 
-	command = (FrCommand*) g_object_new (reg_com->type, NULL);
-	mime_types = fr_command_get_mime_types (command);
+	archive = (FrArchive*) g_object_new (reg_com->type, NULL);
+	mime_types = fr_archive_get_mime_types (archive);
 	for (i = 0; mime_types[i] != NULL; i++) {
 		const char         *mime_type;
 		FrMimeTypeCap      *cap;
@@ -228,31 +228,31 @@ fr_registered_command_new (GType command_type)
 
 		cap = g_new0 (FrMimeTypeCap, 1);
 		cap->mime_type = mime_type;
-		cap->current_capabilities = fr_command_get_capabilities (command, mime_type, TRUE);
-		cap->potential_capabilities = fr_command_get_capabilities (command, mime_type, FALSE);
+		cap->current_capabilities = fr_archive_get_capabilities (archive, mime_type, TRUE);
+		cap->potential_capabilities = fr_archive_get_capabilities (archive, mime_type, FALSE);
 		g_ptr_array_add (reg_com->caps, cap);
 
 		packages = g_new0 (FrMimeTypePackages, 1);
 		packages->mime_type = mime_type;
-		packages->packages = fr_command_get_packages (command, mime_type);
+		packages->packages = fr_archive_get_packages (archive, mime_type);
 		g_ptr_array_add (reg_com->packages, packages);
 	}
 
-	g_object_unref (command);
+	g_object_unref (archive);
 
 	return reg_com;
 }
 
 
 G_GNUC_UNUSED static void
-fr_registered_command_ref (FrRegisteredCommand *reg_com)
+fr_registered_command_ref (FrRegisteredArchive *reg_com)
 {
 	reg_com->ref++;
 }
 
 
 static void
-fr_registered_command_unref (FrRegisteredCommand *reg_com)
+fr_registered_archive_unref (FrRegisteredArchive *reg_com)
 {
 	if (--(reg_com->ref) != 0)
 		return;
@@ -263,8 +263,8 @@ fr_registered_command_unref (FrRegisteredCommand *reg_com)
 }
 
 
-static FrCommandCaps
-fr_registered_command_get_capabilities (FrRegisteredCommand *reg_com,
+static FrArchiveCaps
+fr_registered_archive_get_capabilities (FrRegisteredArchive *reg_com,
 				        const char          *mime_type)
 {
 	int i;
@@ -277,18 +277,18 @@ fr_registered_command_get_capabilities (FrRegisteredCommand *reg_com,
 			return cap->current_capabilities;
 	}
 
-	return FR_COMMAND_CAN_DO_NOTHING;
+	return FR_ARCHIVE_CAN_DO_NOTHING;
 }
 
 
-static FrCommandCaps
-fr_registered_command_get_potential_capabilities (FrRegisteredCommand *reg_com,
+static FrArchiveCaps
+fr_registered_archive_get_potential_capabilities (FrRegisteredArchive *reg_com,
 						  const char          *mime_type)
 {
 	int i;
 
 	if (mime_type == NULL)
-		return FR_COMMAND_CAN_DO_NOTHING;
+		return FR_ARCHIVE_CAN_DO_NOTHING;
 
 	for (i = 0; i < reg_com->caps->len; i++) {
 		FrMimeTypeCap *cap;
@@ -298,31 +298,31 @@ fr_registered_command_get_potential_capabilities (FrRegisteredCommand *reg_com,
 			return cap->potential_capabilities;
 	}
 
-	return FR_COMMAND_CAN_DO_NOTHING;
+	return FR_ARCHIVE_CAN_DO_NOTHING;
 }
 
 
 static void
-register_command (GType command_type)
+register_archive (GType command_type)
 {
-	if (Registered_Commands == NULL)
-		Registered_Commands = g_ptr_array_sized_new (5);
-	g_ptr_array_add (Registered_Commands, fr_registered_command_new (command_type));
+	if (Registered_Archives == NULL)
+		Registered_Archives = g_ptr_array_sized_new (5);
+	g_ptr_array_add (Registered_Archives, fr_registered_archive_new (command_type));
 }
 
 
 G_GNUC_UNUSED static gboolean
-unregister_command (GType command_type)
+unregister_archive (GType command_type)
 {
 	int i;
 
-	for (i = 0; i < Registered_Commands->len; i++) {
-		FrRegisteredCommand *command;
+	for (i = 0; i < Registered_Archives->len; i++) {
+		FrRegisteredArchive *archive;
 
-		command = g_ptr_array_index (Registered_Commands, i);
-		if (command->type == command_type) {
-			g_ptr_array_remove_index (Registered_Commands, i);
-			fr_registered_command_unref (command);
+		archive = g_ptr_array_index (Registered_Archives, i);
+		if (archive->type == command_type) {
+			g_ptr_array_remove_index (Registered_Archives, i);
+			fr_registered_archive_unref (archive);
 			return TRUE;
 		}
 	}
@@ -332,53 +332,57 @@ unregister_command (GType command_type)
 
 
 static void
-register_commands (void)
+register_archives (void)
 {
 	/* The order here is important. Commands registered earlier have higher
 	 * priority.  However commands that can read and write a file format
 	 * have higher priority over commands that can only read the same
 	 * format, regardless of the registration order. */
 
-	register_command (FR_TYPE_COMMAND_TAR);
-	register_command (FR_TYPE_COMMAND_CFILE);
-	register_command (FR_TYPE_COMMAND_7Z);
-	register_command (FR_TYPE_COMMAND_DPKG);
-
-	register_command (FR_TYPE_COMMAND_ACE);
-	register_command (FR_TYPE_COMMAND_ALZ);
-	register_command (FR_TYPE_COMMAND_AR);
-	register_command (FR_TYPE_COMMAND_ARJ);
-	register_command (FR_TYPE_COMMAND_CPIO);
-	register_command (FR_TYPE_COMMAND_ISO);
-	register_command (FR_TYPE_COMMAND_JAR);
-	register_command (FR_TYPE_COMMAND_LHA);
-	register_command (FR_TYPE_COMMAND_RAR);
-	register_command (FR_TYPE_COMMAND_RPM);
-	register_command (FR_TYPE_COMMAND_UNSTUFF);
-	register_command (FR_TYPE_COMMAND_ZIP);
-	register_command (FR_TYPE_COMMAND_LRZIP);
-	register_command (FR_TYPE_COMMAND_ZOO);
+#if HAVE_LIBARCHIVE
+	register_archive (FR_TYPE_LIBARCHIVE);
+#endif
+
+	register_archive (FR_TYPE_COMMAND_TAR);
+	register_archive (FR_TYPE_COMMAND_CFILE);
+	register_archive (FR_TYPE_COMMAND_7Z);
+	register_archive (FR_TYPE_COMMAND_DPKG);
+
+	register_archive (FR_TYPE_COMMAND_ACE);
+	register_archive (FR_TYPE_COMMAND_ALZ);
+	register_archive (FR_TYPE_COMMAND_AR);
+	register_archive (FR_TYPE_COMMAND_ARJ);
+	register_archive (FR_TYPE_COMMAND_CPIO);
+	register_archive (FR_TYPE_COMMAND_ISO);
+	register_archive (FR_TYPE_COMMAND_JAR);
+	register_archive (FR_TYPE_COMMAND_LHA);
+	register_archive (FR_TYPE_COMMAND_RAR);
+	register_archive (FR_TYPE_COMMAND_RPM);
+	register_archive (FR_TYPE_COMMAND_UNSTUFF);
+	register_archive (FR_TYPE_COMMAND_ZIP);
+	register_archive (FR_TYPE_COMMAND_LRZIP);
+	register_archive (FR_TYPE_COMMAND_ZOO);
 #if HAVE_JSON_GLIB
-	register_command (FR_TYPE_COMMAND_UNARCHIVER);
+	register_archive (FR_TYPE_COMMAND_UNARCHIVER);
 #endif
 }
 
 
 GType
-get_command_type_from_mime_type (const char    *mime_type,
-				 FrCommandCaps  requested_capabilities)
+get_archive_type_from_mime_type (const char    *mime_type,
+				 FrArchiveCaps  requested_capabilities)
 {
 	int i;
 
 	if (mime_type == NULL)
 		return 0;
 
-	for (i = 0; i < Registered_Commands->len; i++) {
-		FrRegisteredCommand *command;
-		FrCommandCaps        capabilities;
+	for (i = 0; i < Registered_Archives->len; i++) {
+		FrRegisteredArchive *command;
+		FrArchiveCaps        capabilities;
 
-		command = g_ptr_array_index (Registered_Commands, i);
-		capabilities = fr_registered_command_get_capabilities (command, mime_type);
+		command = g_ptr_array_index (Registered_Archives, i);
+		capabilities = fr_registered_archive_get_capabilities (command, mime_type);
 
 		/* the command must support all the requested capabilities */
 		if (((capabilities ^ requested_capabilities) & requested_capabilities) == 0)
@@ -390,21 +394,21 @@ get_command_type_from_mime_type (const char    *mime_type,
 
 
 GType
-get_preferred_command_for_mime_type (const char    *mime_type,
-				     FrCommandCaps  requested_capabilities)
+get_preferred_archive_for_mime_type (const char    *mime_type,
+				     FrArchiveCaps  requested_capabilities)
 {
 	int i;
 
-	for (i = 0; i < Registered_Commands->len; i++) {
-		FrRegisteredCommand *command;
-		FrCommandCaps        capabilities;
+	for (i = 0; i < Registered_Archives->len; i++) {
+		FrRegisteredArchive *archive;
+		FrArchiveCaps        capabilities;
 
-		command = g_ptr_array_index (Registered_Commands, i);
-		capabilities = fr_registered_command_get_potential_capabilities (command, mime_type);
+		archive = g_ptr_array_index (Registered_Archives, i);
+		capabilities = fr_registered_archive_get_potential_capabilities (archive, mime_type);
 
-		/* the command must support all the requested capabilities */
+		/* the archive must support all the requested capabilities */
 		if (((capabilities ^ requested_capabilities) & requested_capabilities) == 0)
-			return command->type;
+			return archive->type;
 	}
 
 	return 0;
@@ -412,27 +416,27 @@ get_preferred_command_for_mime_type (const char    *mime_type,
 
 
 void
-update_registered_commands_capabilities (void)
+update_registered_archives_capabilities (void)
 {
 	int i;
 
 	g_hash_table_remove_all (ProgramsCache);
 
-	for (i = 0; i < Registered_Commands->len; i++) {
-		FrRegisteredCommand *reg_com;
-		FrCommand           *command;
+	for (i = 0; i < Registered_Archives->len; i++) {
+		FrRegisteredArchive *reg_com;
+		FrArchive           *archive;
 		int                  j;
 
-		reg_com = g_ptr_array_index (Registered_Commands, i);
-		command = (FrCommand*) g_object_new (reg_com->type, NULL);
+		reg_com = g_ptr_array_index (Registered_Archives, i);
+		archive = g_object_new (reg_com->type, NULL);
 		for (j = 0; j < reg_com->caps->len; j++) {
 			FrMimeTypeCap *cap = g_ptr_array_index (reg_com->caps, j);
 
-			cap->current_capabilities = fr_command_get_capabilities (command, cap->mime_type, TRUE);
-			cap->potential_capabilities = fr_command_get_capabilities (command, cap->mime_type, FALSE);
+			cap->current_capabilities = fr_archive_get_capabilities (archive, cap->mime_type, TRUE);
+			cap->potential_capabilities = fr_archive_get_capabilities (archive, cap->mime_type, FALSE);
 		}
 
-		g_object_unref (command);
+		g_object_unref (archive);
 	}
 }
 
@@ -562,11 +566,11 @@ compute_supported_archive_types (void)
 	int sf_i = 0, s_i = 0, o_i = 0, c_i = 0;
 	int i;
 
-	for (i = 0; i < Registered_Commands->len; i++) {
-		FrRegisteredCommand *reg_com;
+	for (i = 0; i < Registered_Archives->len; i++) {
+		FrRegisteredArchive *reg_com;
 		int                  j;
 
-		reg_com = g_ptr_array_index (Registered_Commands, i);
+		reg_com = g_ptr_array_index (Registered_Archives, i);
 		for (j = 0; j < reg_com->caps->len; j++) {
 			FrMimeTypeCap *cap;
 			int            idx;
@@ -578,12 +582,12 @@ compute_supported_archive_types (void)
 				continue;
 			}
 			mime_type_desc[idx].capabilities |= cap->current_capabilities;
-			if (cap->current_capabilities & FR_COMMAND_CAN_READ)
+			if (cap->current_capabilities & FR_ARCHIVE_CAN_READ)
 				add_if_non_present (open_type, &o_i, idx);
-			if (cap->current_capabilities & FR_COMMAND_CAN_WRITE) {
-				if (cap->current_capabilities & FR_COMMAND_CAN_ARCHIVE_MANY_FILES) {
+			if (cap->current_capabilities & FR_ARCHIVE_CAN_WRITE) {
+				if (cap->current_capabilities & FR_ARCHIVE_CAN_STORE_MANY_FILES) {
 					add_if_non_present (save_type, &s_i, idx);
-					if (cap->current_capabilities & FR_COMMAND_CAN_WRITE)
+					if (cap->current_capabilities & FR_ARCHIVE_CAN_WRITE)
 						add_if_non_present (create_type, &c_i, idx);
 				}
 				add_if_non_present (single_file_save_type, &sf_i, idx);
@@ -617,7 +621,7 @@ initialize_data (void)
 					   PKG_DATA_DIR G_DIR_SEPARATOR_S "icons");
 
 	migrate_options_directory ();
-	register_commands ();
+	register_archives ();
 	compute_supported_archive_types ();
 	fr_stock_init ();
 }
diff --git a/src/fr-init.h b/src/fr-init.h
index 2639e70..e987dd0 100644
--- a/src/fr-init.h
+++ b/src/fr-init.h
@@ -46,7 +46,7 @@ typedef struct {
 extern GList                 *CommandList;
 extern gint                   ForceDirectoryCreation;
 extern GHashTable            *ProgramsCache;
-extern GPtrArray             *Registered_Commands;
+extern GPtrArray             *Registered_Archives;
 extern FrMimeTypeDescription  mime_type_desc[];
 extern FrExtensionType        file_ext_type[];
 extern int                    single_file_save_type[]; /* File types that can be saved when
@@ -57,11 +57,11 @@ extern int                    save_type[];             /* File types that can be
 extern int                    open_type[];             /* File types that can be opened. */
 extern int                    create_type[];           /* File types that can be created. */
 
-GType        get_command_type_from_mime_type         (const char    *mime_type,
-						      FrCommandCaps  requested_capabilities);
-GType        get_preferred_command_for_mime_type     (const char    *mime_type,
-						      FrCommandCaps  requested_capabilities);
-void         update_registered_commands_capabilities (void);
+GType        get_archive_type_from_mime_type         (const char    *mime_type,
+						      FrArchiveCaps  requested_capabilities);
+GType        get_preferred_archive_for_mime_type     (const char    *mime_type,
+						      FrArchiveCaps  requested_capabilities);
+void         update_registered_archives_capabilities (void);
 const char * get_mime_type_from_extension            (const char    *ext);
 const char * get_archive_filename_extension          (const char    *uri);
 int          get_mime_type_index                     (const char    *mime_type);
diff --git a/src/fr-process.c b/src/fr-process.c
index 2725e45..db427cc 100644
--- a/src/fr-process.c
+++ b/src/fr-process.c
@@ -3,7 +3,7 @@
 /*
  *  File-Roller
  *
- *  Copyright (C) 2001, 2003, 2008 Free Software Foundation, Inc.
+ *  Copyright (C) 2001, 2003, 2008, 2012 Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -30,27 +30,14 @@
 #include <unistd.h>
 #include <glib.h>
 #include "file-utils.h"
-#include "fr-proc-error.h"
 #include "fr-process.h"
-#include "fr-marshal.h"
 #include "glib-utils.h"
 
 #define REFRESH_RATE 20
 #define BUFFER_SIZE 16384
 
 
-G_DEFINE_TYPE (FrProcess, fr_process, G_TYPE_OBJECT)
-
-
-enum {
-	START,
-	DONE,
-	STICKY_ONLY,
-	LAST_SIGNAL
-};
-
-
-static guint fr_process_signals[LAST_SIGNAL] = { 0 };
+/* -- FrCommandInfo --  */
 
 
 typedef struct {
@@ -107,6 +94,9 @@ fr_command_info_free (FrCommandInfo *info)
 }
 
 
+/* -- FrChannelData -- */
+
+
 static void
 fr_channel_data_init (FrChannelData *channel)
 {
@@ -202,35 +192,78 @@ fr_channel_data_set_fd (FrChannelData *channel,
 }
 
 
-const char *try_charsets[] = { "UTF-8", "ISO-8859-1", "WINDOW-1252" };
-int n_charsets = G_N_ELEMENTS (try_charsets);
+/* -- ExecData -- */
+
+
+typedef struct {
+	FrProcess          *process;
+	GCancellable       *cancellable;
+	GSimpleAsyncResult *result;
+	gulong              cancel_id;
+	int                 error_command;       /* command that caused an error. */
+	FrError            *error;
+	FrError            *first_error;
+	GList              *first_error_stdout;
+	GList              *first_error_stderr;
+} ExecuteData;
+
+
+static void
+execute_data_free (ExecuteData *exec_data)
+{
+	if (exec_data == NULL)
+		return;
+
+	if (exec_data->cancel_id != 0)
+		g_cancellable_disconnect (exec_data->cancellable, exec_data->cancel_id);
+
+	_g_object_unref (exec_data->process);
+	_g_object_unref (exec_data->cancellable);
+	_g_object_unref (exec_data->result);
+	fr_error_free (exec_data->error);
+	fr_error_free (exec_data->first_error);
+	_g_string_list_free (exec_data->first_error_stdout);
+	_g_string_list_free (exec_data->first_error_stderr);
+	g_free (exec_data);
+}
+
+
+/* -- FrProcess  -- */
+
+
+G_DEFINE_TYPE (FrProcess, fr_process, G_TYPE_OBJECT)
+
+
+enum {
+	STICKY_ONLY,
+	LAST_SIGNAL
+};
+
+
+static guint       fr_process_signals[LAST_SIGNAL] = { 0 };
+static const char *try_charsets[] = { "UTF-8", "ISO-8859-1", "WINDOW-1252" };
+static int         n_charsets = G_N_ELEMENTS (try_charsets);
 
 
 struct _FrProcessPrivate {
 	GPtrArray   *comm;                /* FrCommandInfo elements. */
 	gint         n_comm;              /* total number of commands */
-	gint         current_comm;        /* currenlty editing command. */
+	gint         current_comm;        /* currently editing command. */
 
 	GPid         command_pid;
 	guint        check_timeout;
 
-	FrProcError  first_error;
-	GList       *first_error_stdout;
-	GList       *first_error_stderr;
-
 	gboolean     running;
 	gboolean     stopping;
 	gint         current_command;
-	gint         error_command;       /* command that coused an error. */
 
 	gboolean     use_standard_locale;
 	gboolean     sticky_only;         /* whether to execute only sticky
 			 		   * commands. */
 	int          current_charset;
-};
-
 
-static void fr_process_stop_priv (FrProcess *process, gboolean emit_signal);
+	ExecuteData *exec_data;
+};
 
 
 static void
@@ -243,21 +276,12 @@ fr_process_finalize (GObject *object)
 
 	process = FR_PROCESS (object);
 
-	fr_process_stop_priv (process, FALSE);
+	execute_data_free (process->priv->exec_data);
 	fr_process_clear (process);
-
 	g_ptr_array_free (process->priv->comm, FALSE);
-
 	fr_channel_data_free (&process->out);
 	fr_channel_data_free (&process->err);
 
-	g_clear_error (&process->error.gerror);
-	g_clear_error (&process->priv->first_error.gerror);
-	_g_string_list_free (process->priv->first_error_stdout);
-	_g_string_list_free (process->priv->first_error_stderr);
-
-	g_free (process->priv);
-
 	if (G_OBJECT_CLASS (fr_process_parent_class)->finalize)
 		G_OBJECT_CLASS (fr_process_parent_class)->finalize (object);
 }
@@ -269,47 +293,26 @@ fr_process_class_init (FrProcessClass *klass)
 	GObjectClass *gobject_class;
 
 	fr_process_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (FrProcessPrivate));
 
-	fr_process_signals[START] =
-		g_signal_new ("start",
-			      G_TYPE_FROM_CLASS (klass),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (FrProcessClass, start),
-			      NULL, NULL,
-			      fr_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
-	fr_process_signals[DONE] =
-		g_signal_new ("done",
-			      G_TYPE_FROM_CLASS (klass),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (FrProcessClass, done),
-			      NULL, NULL,
-			      fr_marshal_VOID__BOXED,
-			      G_TYPE_NONE, 1,
-			      FR_TYPE_PROC_ERROR);
 	fr_process_signals[STICKY_ONLY] =
 		g_signal_new ("sticky_only",
 			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (FrProcessClass, sticky_only),
 			      NULL, NULL,
-			      fr_marshal_VOID__VOID,
+			      g_cclosure_marshal_VOID__VOID,
 			      G_TYPE_NONE, 0);
 
 	gobject_class = G_OBJECT_CLASS (klass);
 	gobject_class->finalize = fr_process_finalize;
-
-	klass->start = NULL;
-	klass->done  = NULL;
 }
 
 
 static void
 fr_process_init (FrProcess *process)
 {
-	process->priv = g_new0 (FrProcessPrivate, 1);
-
-	process->term_on_stop = TRUE;
+	process->priv = G_TYPE_INSTANCE_GET_PRIVATE (process, FR_TYPE_PROCESS, FrProcessPrivate);
 
 	process->priv->comm = g_ptr_array_new ();
 	process->priv->n_comm = -1;
@@ -319,19 +322,14 @@ fr_process_init (FrProcess *process)
 	fr_channel_data_init (&process->out);
 	fr_channel_data_init (&process->err);
 
-	process->error.gerror = NULL;
-	process->priv->first_error.gerror = NULL;
-	process->priv->first_error_stdout = NULL;
-	process->priv->first_error_stderr = NULL;
-
 	process->priv->check_timeout = 0;
 	process->priv->running = FALSE;
 	process->priv->stopping = FALSE;
 	process->restart = FALSE;
 
 	process->priv->current_charset = -1;
-
 	process->priv->use_standard_locale = FALSE;
+	process->priv->exec_data = NULL;
 }
 
 
@@ -343,6 +341,29 @@ fr_process_new (void)
 
 
 void
+fr_process_clear (FrProcess *process)
+{
+	gint i;
+
+	g_return_if_fail (process != NULL);
+
+	for (i = 0; i <= process->priv->n_comm; i++) {
+		FrCommandInfo *info;
+
+		info = g_ptr_array_index (process->priv->comm, i);
+		fr_command_info_free (info);
+		g_ptr_array_index (process->priv->comm, i) = NULL;
+	}
+
+	for (i = 0; i <= process->priv->n_comm; i++)
+		g_ptr_array_remove_index_fast (process->priv->comm, 0);
+
+	process->priv->n_comm = -1;
+	process->priv->current_comm = -1;
+}
+
+
+void
 fr_process_begin_command (FrProcess  *process,
 			  const char *arg)
 {
@@ -562,25 +583,11 @@ fr_process_end_command (FrProcess *process)
 
 
 void
-fr_process_clear (FrProcess *process)
+fr_process_use_standard_locale (FrProcess *process,
+				gboolean   use_stand_locale)
 {
-	gint i;
-
 	g_return_if_fail (process != NULL);
-
-	for (i = 0; i <= process->priv->n_comm; i++) {
-		FrCommandInfo *info;
-
-		info = g_ptr_array_index (process->priv->comm, i);
-		fr_command_info_free (info);
-		g_ptr_array_index (process->priv->comm, i) = NULL;
-	}
-
-	for (i = 0; i <= process->priv->n_comm; i++)
-		g_ptr_array_remove_index_fast (process->priv->comm, 0);
-
-	process->priv->n_comm = -1;
-	process->priv->current_comm = -1;
+	process->priv->use_standard_locale = use_stand_locale;
 }
 
 
@@ -608,178 +615,141 @@ fr_process_set_err_line_func (FrProcess *process,
 }
 
 
-static gboolean check_child (gpointer data);
+/* fr_process_execute */
 
 
-static void
-child_setup (gpointer user_data)
+static gboolean
+command_is_sticky (FrProcess *process,
+		   int        i)
 {
-	FrProcess *process = user_data;
-
-	if (process->priv->use_standard_locale)
-		putenv ("LC_MESSAGES=C");
-
-	/* detach from the tty */
-
-	setsid ();
-
-	/* create a process group to kill all the child processes when
-	 * canceling the operation. */
+	FrCommandInfo *info;
 
-	setpgid (0, 0);
+	info = g_ptr_array_index (process->priv->comm, i);
+	return info->sticky;
 }
 
 
-static const char *
-fr_process_get_charset (FrProcess *process)
+static void
+allow_sticky_processes_only (ExecuteData *exec_data)
 {
-	const char *charset = NULL;
+	FrProcess *process = exec_data->process;
 
-	if (process->priv->current_charset >= 0)
-		charset = try_charsets[process->priv->current_charset];
-	else if (g_get_charset (&charset))
-		charset = NULL;
+	if (! process->priv->sticky_only) {
+		/* Remember the first error. */
 
-	return charset;
+		exec_data->error_command = process->priv->current_command;
+		exec_data->first_error = fr_error_copy (exec_data->error);
+		exec_data->first_error_stdout = g_list_reverse (_g_string_list_dup (process->out.raw));
+		exec_data->first_error_stderr = g_list_reverse (_g_string_list_dup (process->err.raw));
+	}
+
+	process->priv->sticky_only = TRUE;
+
+	if (! process->priv->stopping)
+		g_signal_emit (G_OBJECT (process),
+			       fr_process_signals[STICKY_ONLY],
+			       0);
 }
 
 
 static void
-start_current_command (FrProcess *process)
+execute_cancelled_cb (GCancellable *cancellable,
+		      gpointer      user_data)
 {
-	FrCommandInfo  *info;
-	GList          *scan;
-	char          **argv;
-	int             out_fd, err_fd;
-	int             i = 0;
+	ExecuteData *exec_data = user_data;
+	FrProcess   *process = exec_data->process;
 
-	debug (DEBUG_INFO, "%d/%d) ", process->priv->current_command, process->priv->n_comm);
+	g_cancellable_disconnect (exec_data->cancellable, exec_data->cancel_id);
+	exec_data->cancel_id = 0;
 
-	info = g_ptr_array_index (process->priv->comm, process->priv->current_command);
+	if (! process->priv->running)
+		return;
 
-	argv = g_new (char *, g_list_length (info->args) + 1);
-	for (scan = info->args; scan; scan = scan->next)
-		argv[i++] = scan->data;
-	argv[i] = NULL;
+	if (process->priv->stopping)
+		return;
 
-#ifdef DEBUG
-	{
-		int j;
+	process->priv->stopping = TRUE;
+	exec_data->error = fr_error_new (FR_ERROR_STOPPED, 0, NULL);
 
-		if (process->priv->use_standard_locale)
-			g_print ("\tLC_MESSAGES=C\n");
+	if (command_is_sticky (process, process->priv->current_command))
+		allow_sticky_processes_only (exec_data);
 
-		if (info->dir != NULL)
-			g_print ("\tcd %s\n", info->dir);
+	else if (process->priv->command_pid > 0)
+		killpg (process->priv->command_pid, SIGTERM);
 
-		g_print ("\t");
-		for (j = 0; j < i; j++)
-			g_print ("%s ", argv[j]);
-		g_print ("\n");
-	}
-#endif
+	else {
+		if (process->priv->check_timeout != 0) {
+			g_source_remove (process->priv->check_timeout);
+			process->priv->check_timeout = 0;
+		}
 
-	if (info->begin_func != NULL)
-		(*info->begin_func) (info->begin_data);
+		process->priv->command_pid = 0;
+		fr_channel_data_close_source (&process->out);
+		fr_channel_data_close_source (&process->err);
 
-	if (! g_spawn_async_with_pipes (info->dir,
-					argv,
-					NULL,
-					(G_SPAWN_LEAVE_DESCRIPTORS_OPEN
-					 | G_SPAWN_SEARCH_PATH
-					 | G_SPAWN_DO_NOT_REAP_CHILD),
-					child_setup,
-					process,
-					&process->priv->command_pid,
-					NULL,
-					&out_fd,
-					&err_fd,
-					&process->error.gerror))
-	{
-		process->error.type = FR_PROC_ERROR_SPAWN;
-		g_signal_emit (G_OBJECT (process),
-			       fr_process_signals[DONE],
-			       0,
-			       &process->error);
-		g_free (argv);
-		return;
-	}
+		process->priv->running = FALSE;
 
-	g_free (argv);
+		g_simple_async_result_complete_in_idle (exec_data->result);
+	}
+}
 
-	fr_channel_data_set_fd (&process->out, out_fd, fr_process_get_charset (process));
-	fr_channel_data_set_fd (&process->err, err_fd, fr_process_get_charset (process));
 
-	process->priv->check_timeout = g_timeout_add (REFRESH_RATE,
-					              check_child,
-					              process);
-}
+static void _fr_process_start (ExecuteData *exec_data);
 
 
-static gboolean
-command_is_sticky (FrProcess *process,
-		   int        i)
+static void
+_fr_process_restart (ExecuteData *exec_data)
 {
-	FrCommandInfo *info;
-
-	info = g_ptr_array_index (process->priv->comm, i);
-	return info->sticky;
+	exec_data->process->restart = TRUE;
+	_fr_process_start (exec_data);
 }
 
 
+static void  execute_current_command (ExecuteData *exec_data);
+
+
 static void
-allow_sticky_processes_only (FrProcess *process,
-			     gboolean   emit_signal)
+child_setup (gpointer user_data)
 {
-	if (! process->priv->sticky_only) {
-		/* Remember the first error. */
-		process->priv->error_command = process->priv->current_command;
-		process->priv->first_error.type = process->error.type;
-		process->priv->first_error.status = process->error.status;
-		g_clear_error (&process->priv->first_error.gerror);
-		if (process->error.gerror != NULL)
-			process->priv->first_error.gerror = g_error_copy (process->error.gerror);
-
-		_g_string_list_free (process->priv->first_error_stdout);
-		process->priv->first_error_stdout = g_list_reverse (_g_string_list_dup (process->out.raw));
-
-		_g_string_list_free (process->priv->first_error_stderr);
-		process->priv->first_error_stderr = g_list_reverse (_g_string_list_dup (process->err.raw));
-	}
+	FrProcess *process = user_data;
 
-	process->priv->sticky_only = TRUE;
-	if (emit_signal)
-		g_signal_emit (G_OBJECT (process),
-			       fr_process_signals[STICKY_ONLY],
-			       0);
+	if (process->priv->use_standard_locale)
+		putenv ("LC_MESSAGES=C");
+
+	/* detach from the tty */
+
+	setsid ();
+
+	/* create a process group to kill all the child processes when
+	 * canceling the operation. */
+
+	setpgid (0, 0);
 }
 
 
-static void
-fr_process_set_error (FrProcess       *process,
-		      FrProcErrorType  type,
-		      int              status,
-		      GError          *gerror)
+static const char *
+_fr_process_get_charset (FrProcess *process)
 {
-	process->error.type = type;
-	process->error.status = status;
-	if (gerror != process->error.gerror) {
-		g_clear_error (&process->error.gerror);
-		if (gerror != NULL)
-			process->error.gerror = g_error_copy (gerror);
-	}
+	const char *charset = NULL;
+
+	if (process->priv->current_charset >= 0)
+		charset = try_charsets[process->priv->current_charset];
+	else if (g_get_charset (&charset))
+		charset = NULL;
+
+	return charset;
 }
 
 
 static gint
 check_child (gpointer data)
 {
-	FrProcess      *process = data;
-	FrCommandInfo  *info;
-	pid_t           pid;
-	int             status;
-	gboolean        continue_process;
-	gboolean        channel_error = FALSE;
+	ExecuteData   *exec_data = data;
+	FrProcess     *process = exec_data->process;
+	FrCommandInfo *info;
+	pid_t          pid;
+	int            status;
+	gboolean       continue_process;
 
 	info = g_ptr_array_index (process->priv->comm, process->priv->current_command);
 
@@ -789,12 +759,10 @@ check_child (gpointer data)
 	process->priv->check_timeout = 0;
 
 	if (fr_channel_data_read (&process->out) == G_IO_STATUS_ERROR) {
-		fr_process_set_error (process, FR_PROC_ERROR_IO_CHANNEL, 0, process->out.error);
-		channel_error = TRUE;
+		exec_data->error = fr_error_new (FR_ERROR_IO_CHANNEL, 0, process->out.error);
 	}
 	else if (fr_channel_data_read (&process->err) == G_IO_STATUS_ERROR) {
-		fr_process_set_error (process, FR_PROC_ERROR_IO_CHANNEL, 0, process->err.error);
-		channel_error = TRUE;
+		exec_data->error = fr_error_new (FR_ERROR_IO_CHANNEL, 0, process->err.error);
 	}
 	else {
 		pid = waitpid (process->priv->command_pid, &status, WNOHANG);
@@ -802,41 +770,36 @@ check_child (gpointer data)
 			/* Add check again. */
 			process->priv->check_timeout = g_timeout_add (REFRESH_RATE,
 							              check_child,
-							              process);
+							              exec_data);
 			return FALSE;
 		}
 	}
 
 	if (info->ignore_error) {
-		process->error.type = FR_PROC_ERROR_NONE;
+		fr_clear_error (&exec_data->error);
 		debug (DEBUG_INFO, "[ignore error]\n");
 	}
-	else if (! channel_error && (process->error.type != FR_PROC_ERROR_STOPPED)) {
+	else if (exec_data->error == NULL) {
 		if (WIFEXITED (status)) {
-			if (WEXITSTATUS (status) == 0)
-				process->error.type = FR_PROC_ERROR_NONE;
-			else if (WEXITSTATUS (status) == 255)
-				process->error.type = FR_PROC_ERROR_COMMAND_NOT_FOUND;
-			else {
-				process->error.type = FR_PROC_ERROR_COMMAND_ERROR;
-				process->error.status = WEXITSTATUS (status);
+			if (WEXITSTATUS (status) == 255) {
+				exec_data->error = fr_error_new (FR_ERROR_COMMAND_NOT_FOUND, 0, NULL);
+			}
+			else if (WEXITSTATUS (status) != 0) {
+				exec_data->error = fr_error_new (FR_ERROR_COMMAND_ERROR, WEXITSTATUS (status), NULL);
 			}
 		}
 		else {
-			process->error.type = FR_PROC_ERROR_EXITED_ABNORMALLY;
-			process->error.status = 255;
+			exec_data->error = fr_error_new (FR_ERROR_EXITED_ABNORMALLY, 255, NULL);
 		}
 	}
 
 	process->priv->command_pid = 0;
 
-	if (fr_channel_data_flush (&process->out) == G_IO_STATUS_ERROR) {
-		fr_process_set_error (process, FR_PROC_ERROR_IO_CHANNEL, 0, process->out.error);
-		channel_error = TRUE;
-	}
-	else if (fr_channel_data_flush (&process->err) == G_IO_STATUS_ERROR) {
-		fr_process_set_error (process, FR_PROC_ERROR_IO_CHANNEL, 0, process->err.error);
-		channel_error = TRUE;
+	if (exec_data->error == NULL) {
+		if (fr_channel_data_flush (&process->out) == G_IO_STATUS_ERROR)
+			exec_data->error = fr_error_new (FR_ERROR_IO_CHANNEL, 0, process->out.error);
+		else if (fr_channel_data_flush (&process->err) == G_IO_STATUS_ERROR)
+			exec_data->error = fr_error_new (FR_ERROR_IO_CHANNEL, 0, process->err.error);
 	}
 
 	if (info->end_func != NULL)
@@ -844,32 +807,30 @@ check_child (gpointer data)
 
 	/**/
 
-	if (channel_error
-	    && (process->error.type == FR_PROC_ERROR_IO_CHANNEL)
-	    && g_error_matches (process->error.gerror, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
+	if ((exec_data->error != NULL)
+	    && (exec_data->error->type == FR_ERROR_IO_CHANNEL)
+	    && g_error_matches (exec_data->error->gerror, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
 	{
 		if (process->priv->current_charset < n_charsets - 1) {
 			/* try with another charset */
 			process->priv->current_charset++;
-			process->priv->running = FALSE;
-			process->restart = TRUE;
-			fr_process_start (process);
+			_fr_process_restart (exec_data);
 			return FALSE;
 		}
-		/*fr_process_set_error (process, FR_PROC_ERROR_NONE, 0, NULL);*/
-		fr_process_set_error (process, FR_PROC_ERROR_BAD_CHARSET, 0, process->error.gerror);
+		fr_error_free (exec_data->error);
+		exec_data->error = fr_error_new (FR_ERROR_BAD_CHARSET, 0, exec_data->error->gerror);
 	}
 
 	/* Check whether to continue or stop the process */
 
 	continue_process = TRUE;
 	if (info->continue_func != NULL)
-		continue_process = (*info->continue_func) (info->continue_data);
+		continue_process = (*info->continue_func) (&exec_data->error, info->continue_data);
 
-	/* Execute next command. */
+	/* Execute the next command. */
 	if (continue_process) {
-		if (process->error.type != FR_PROC_ERROR_NONE) {
-			allow_sticky_processes_only (process, TRUE);
+		if (exec_data->error != NULL) {
+			allow_sticky_processes_only (exec_data);
 #ifdef DEBUG
 			{
 				GList *scan;
@@ -884,14 +845,15 @@ check_child (gpointer data)
 		if (process->priv->sticky_only) {
 			do {
 				process->priv->current_command++;
-			} while ((process->priv->current_command <= process->priv->n_comm)
-				 && ! command_is_sticky (process, process->priv->current_command));
+			}
+			while ((process->priv->current_command <= process->priv->n_comm)
+				&& ! command_is_sticky (process, process->priv->current_command));
 		}
 		else
 			process->priv->current_command++;
 
 		if (process->priv->current_command <= process->priv->n_comm) {
-			start_current_command (process);
+			execute_current_command (exec_data);
 			return FALSE;
 		}
 	}
@@ -912,122 +874,214 @@ check_child (gpointer data)
 	if (process->priv->sticky_only) {
 		/* Restore the first error. */
 
-		fr_process_set_error (process,
-				      process->priv->first_error.type,
-				      process->priv->first_error.status,
-				      process->priv->first_error.gerror);
+		fr_error_free (exec_data->error);
+		exec_data->error = fr_error_copy (exec_data->first_error);
 
 		/* Restore the first error output as well. */
 
 		_g_string_list_free (process->out.raw);
-		process->out.raw = process->priv->first_error_stdout;
-		process->priv->first_error_stdout = NULL;
+		process->out.raw = exec_data->first_error_stdout;
+		exec_data->first_error_stdout = NULL;
 
 		_g_string_list_free (process->err.raw);
-		process->err.raw = process->priv->first_error_stderr;
-		process->priv->first_error_stderr = NULL;
+		process->err.raw = exec_data->first_error_stderr;
+		exec_data->first_error_stderr = NULL;
 	}
 
-	g_signal_emit (G_OBJECT (process),
-		       fr_process_signals[DONE],
-		       0,
-		       &process->error);
+	g_simple_async_result_complete_in_idle (exec_data->result);
 
 	return FALSE;
 }
 
 
-void
-fr_process_use_standard_locale (FrProcess *process,
-				gboolean   use_stand_locale)
+static void
+execute_current_command (ExecuteData *exec_data)
 {
-	g_return_if_fail (process != NULL);
-	process->priv->use_standard_locale = use_stand_locale;
+	FrProcess      *process = exec_data->process;
+	FrCommandInfo  *info;
+	GList          *scan;
+	char          **argv;
+	int             out_fd, err_fd;
+	int             i = 0;
+	GError         *error;
+
+	debug (DEBUG_INFO, "%d/%d) ", process->priv->current_command, process->priv->n_comm);
+
+	info = g_ptr_array_index (process->priv->comm, process->priv->current_command);
+
+	argv = g_new (char *, g_list_length (info->args) + 1);
+	for (scan = info->args; scan; scan = scan->next)
+		argv[i++] = scan->data;
+	argv[i] = NULL;
+
+#ifdef DEBUG
+	{
+		int j;
+
+		if (process->priv->use_standard_locale)
+			g_print ("\tLC_MESSAGES=C\n");
+
+		if (info->dir != NULL)
+			g_print ("\tcd %s\n", info->dir);
+
+		g_print ("\t");
+		for (j = 0; j < i; j++)
+			g_print ("%s ", argv[j]);
+		g_print ("\n");
+	}
+#endif
+
+	if (info->begin_func != NULL)
+		(*info->begin_func) (info->begin_data);
+
+	if (! g_spawn_async_with_pipes (info->dir,
+					argv,
+					NULL,
+					(G_SPAWN_LEAVE_DESCRIPTORS_OPEN
+					 | G_SPAWN_SEARCH_PATH
+					 | G_SPAWN_DO_NOT_REAP_CHILD),
+					child_setup,
+					process,
+					&process->priv->command_pid,
+					NULL,
+					&out_fd,
+					&err_fd,
+					&error))
+	{
+		exec_data->error = fr_error_new (FR_ERROR_SPAWN, 0, error);
+		g_simple_async_result_complete_in_idle (exec_data->result);
+
+		g_error_free (error);
+		g_free (argv);
+		return;
+	}
+
+	g_free (argv);
+
+	fr_channel_data_set_fd (&process->out, out_fd, _fr_process_get_charset (process));
+	fr_channel_data_set_fd (&process->err, err_fd, _fr_process_get_charset (process));
+
+	process->priv->check_timeout = g_timeout_add (REFRESH_RATE,
+					              check_child,
+					              exec_data);
 }
 
 
-void
-fr_process_start (FrProcess *process)
+static void
+_fr_process_start (ExecuteData *exec_data)
 {
-	g_return_if_fail (process != NULL);
+	FrProcess *process = exec_data->process;
 
-	if (process->priv->running)
-		return;
+	_g_string_list_free (exec_data->first_error_stdout);
+	exec_data->first_error_stdout = NULL;
+
+	_g_string_list_free (exec_data->first_error_stderr);
+	exec_data->first_error_stderr = NULL;
+
+        fr_error_free (exec_data->error);
+        exec_data->error = NULL;
 
 	fr_channel_data_reset (&process->out);
 	fr_channel_data_reset (&process->err);
 
 	process->priv->sticky_only = FALSE;
 	process->priv->current_command = 0;
-	fr_process_set_error (process, FR_PROC_ERROR_NONE, 0, NULL);
-
-	if (! process->restart) {
-		process->priv->current_charset = -1;
-		g_signal_emit (G_OBJECT (process),
-			       fr_process_signals[START],
-			       0);
-	}
-
 	process->priv->stopping = FALSE;
 
 	if (process->priv->n_comm == -1) {
 		process->priv->running = FALSE;
-		g_signal_emit (G_OBJECT (process),
-			       fr_process_signals[DONE],
-			       0,
-			       &process->error);
+		g_simple_async_result_complete_in_idle (exec_data->result);
 	}
 	else {
 		process->priv->running = TRUE;
-		start_current_command (process);
+		execute_current_command (exec_data);
 	}
 }
 
 
-static void
-fr_process_stop_priv (FrProcess *process,
-		      gboolean   emit_signal)
+void
+fr_process_execute (FrProcess           *process,
+		    GCancellable        *cancellable,
+		    GAsyncReadyCallback  callback,
+		    gpointer             user_data)
 {
-	g_return_if_fail (process != NULL);
+	ExecuteData *exec_data;
 
-	if (! process->priv->running)
-		return;
+	g_return_if_fail (! process->priv->running);
 
-	if (process->priv->stopping)
-		return;
+	execute_data_free (process->priv->exec_data);
 
-	process->priv->stopping = TRUE;
-	process->error.type = FR_PROC_ERROR_STOPPED;
+	process->priv->exec_data = exec_data = g_new0 (ExecuteData, 1);
+	exec_data->process = g_object_ref (process);
+	exec_data->cancellable = _g_object_ref (cancellable);
+	exec_data->cancel_id = 0;
+	exec_data->result = g_simple_async_result_new (G_OBJECT (process),
+						       callback,
+						       user_data,
+						       fr_process_execute);
 
-	if (command_is_sticky (process, process->priv->current_command))
-		allow_sticky_processes_only (process, emit_signal);
+        g_simple_async_result_set_op_res_gpointer (exec_data->result, exec_data, NULL);
 
-	else if (process->term_on_stop && (process->priv->command_pid > 0))
-		killpg (process->priv->command_pid, SIGTERM);
+	if (! process->restart)
+		process->priv->current_charset = -1;
 
-	else {
-		if (process->priv->check_timeout != 0) {
-			g_source_remove (process->priv->check_timeout);
-			process->priv->check_timeout = 0;
-		}
+	if (cancellable != NULL) {
+		GError *error = NULL;
 
-		process->priv->command_pid = 0;
-		fr_channel_data_close_source (&process->out);
-		fr_channel_data_close_source (&process->err);
+		if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
+			exec_data->error = fr_error_new (FR_ERROR_STOPPED, 0, error);
+			g_simple_async_result_complete_in_idle (exec_data->result);
 
-		process->priv->running = FALSE;
+			g_error_free (error);
+			return;
+		}
 
-		if (emit_signal)
-			g_signal_emit (G_OBJECT (process),
-				       fr_process_signals[DONE],
-				       0,
-				       &process->error);
+		exec_data->cancel_id = g_cancellable_connect (cancellable,
+							      G_CALLBACK (execute_cancelled_cb),
+							      exec_data,
+							      NULL);
 	}
+
+	_fr_process_start (exec_data);
+}
+
+
+gboolean
+fr_process_execute_finish (FrProcess     *process,
+			   GAsyncResult  *result,
+			   FrError      **error)
+{
+	ExecuteData *exec_data;
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (process), fr_process_execute), FALSE);
+
+	exec_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	if (exec_data->error == NULL)
+		return TRUE;
+
+	if (error != NULL)
+		*error = fr_error_copy (exec_data->error);
+
+	return FALSE;
 }
 
 
 void
-fr_process_stop (FrProcess *process)
+fr_process_restart (FrProcess *process)
 {
-	fr_process_stop_priv (process, TRUE);
+	if (process->priv->exec_data != NULL)
+		_fr_process_start (process->priv->exec_data);
+}
+
+
+void
+fr_process_cancel (FrProcess *process)
+{
+	if (! process->priv->running)
+		return;
+	if (process->priv->exec_data == NULL)
+		return;
+	if (process->priv->exec_data->cancellable == NULL)
+		return;
+	g_cancellable_cancel (process->priv->exec_data->cancellable);
 }
diff --git a/src/fr-process.h b/src/fr-process.h
index 857a74a..309f86b 100644
--- a/src/fr-process.h
+++ b/src/fr-process.h
@@ -25,6 +25,7 @@
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <sys/types.h>
+#include "fr-error.h"
 #include "typedefs.h"
 
 #define FR_TYPE_PROCESS            (fr_process_get_type ())
@@ -39,7 +40,7 @@ typedef struct _FrProcessClass   FrProcessClass;
 typedef struct _FrProcessPrivate FrProcessPrivate;
 
 typedef void     (*ProcFunc)     (gpointer data);
-typedef gboolean (*ContinueFunc) (gpointer data);
+typedef gboolean (*ContinueFunc) (FrError **error, gpointer data);
 typedef void     (*LineFunc)     (char *line, gpointer data);
 
 typedef struct {
@@ -54,23 +55,10 @@ typedef struct {
 struct _FrProcess {
 	GObject  __parent;
 
-	/*< public >*/
-
-	gboolean          term_on_stop;  /* whether we must terminate the
-					  * command when calling
-					  * fr_process_stop. */
-
-	/*< public read-only >*/
-
 	FrChannelData     out;
 	FrChannelData     err;
-	FrProcError       error;
-
-	/*< protected >*/
-
 	gboolean          restart;       /* whether to restart the process
 			  		  * after an error. */
-
 	FrProcessPrivate *priv;
 };
 
@@ -79,57 +67,61 @@ struct _FrProcessClass {
 
 	/* -- Signals -- */
 
-	void (* start)         (FrProcess   *fr_proc);
-	void (* done)          (FrProcess   *fr_proc,
-				FrProcError *error);
-	void (* sticky_only)   (FrProcess   *fr_proc);
+	void (* sticky_only) (FrProcess *fr_proc);
 };
 
 GType       fr_process_get_type             (void);
 FrProcess * fr_process_new                  (void);
-void        fr_process_clear                (FrProcess    *fr_proc);
-void        fr_process_begin_command        (FrProcess    *fr_proc,
-					     const char   *arg);
-void        fr_process_begin_command_at     (FrProcess    *fr_proc,
-					     const char   *arg,
-					     int           index);
-void        fr_process_add_arg              (FrProcess    *fr_proc,
-					     const char   *arg);
-void        fr_process_add_arg_concat       (FrProcess    *fr_proc,
-					     const char   *arg,
+void        fr_process_clear                (FrProcess            *fr_proc);
+void        fr_process_begin_command        (FrProcess            *fr_proc,
+					     const char           *arg);
+void        fr_process_begin_command_at     (FrProcess            *fr_proc,
+					     const char           *arg,
+					     int                   index);
+void        fr_process_add_arg              (FrProcess            *fr_proc,
+					     const char           *arg);
+void        fr_process_add_arg_concat       (FrProcess            *fr_proc,
+					     const char           *arg,
 					     ...) G_GNUC_NULL_TERMINATED;
-void        fr_process_add_arg_printf       (FrProcess    *fr_proc,
-					     const char   *format,
+void        fr_process_add_arg_printf       (FrProcess            *fr_proc,
+					     const char           *format,
 					     ...) G_GNUC_PRINTF (2, 3);
-void        fr_process_set_arg_at           (FrProcess    *fr_proc,
-					     int           n_comm,
-					     int           n_arg,
-					     const char   *arg);
-void        fr_process_set_begin_func       (FrProcess    *fr_proc,
-					     ProcFunc      func,
-					     gpointer      func_data);
-void        fr_process_set_end_func         (FrProcess    *fr_proc,
-					     ProcFunc      func,
-					     gpointer      func_data);
-void        fr_process_set_continue_func    (FrProcess    *fr_proc,
-					     ContinueFunc  func,
-					     gpointer      func_data);
-void        fr_process_end_command          (FrProcess    *fr_proc);
-void        fr_process_set_working_dir      (FrProcess    *fr_proc,
-					     const char   *arg);
-void        fr_process_set_sticky           (FrProcess    *fr_proc,
-					     gboolean      sticky);
-void        fr_process_set_ignore_error     (FrProcess    *fr_proc,
-					     gboolean      ignore_error);
-void        fr_process_use_standard_locale  (FrProcess    *fr_proc,
-					     gboolean      use_stand_locale);
-void        fr_process_set_out_line_func    (FrProcess    *fr_proc,
-					     LineFunc      func,
-					     gpointer      func_data);
-void        fr_process_set_err_line_func    (FrProcess    *fr_proc,
-					     LineFunc      func,
-					     gpointer      func_data);
-void        fr_process_start                (FrProcess    *fr_proc);
-void        fr_process_stop                 (FrProcess    *fr_proc);
+void        fr_process_set_arg_at           (FrProcess            *fr_proc,
+					     int                   n_comm,
+					     int                   n_arg,
+					     const char           *arg);
+void        fr_process_set_begin_func       (FrProcess            *fr_proc,
+					     ProcFunc              func,
+					     gpointer              func_data);
+void        fr_process_set_end_func         (FrProcess            *fr_proc,
+					     ProcFunc              func,
+					     gpointer              func_data);
+void        fr_process_set_continue_func    (FrProcess            *fr_proc,
+					     ContinueFunc          func,
+					     gpointer              func_data);
+void        fr_process_end_command          (FrProcess            *fr_proc);
+void        fr_process_set_working_dir      (FrProcess            *fr_proc,
+					     const char           *arg);
+void        fr_process_set_sticky           (FrProcess            *fr_proc,
+					     gboolean              sticky);
+void        fr_process_set_ignore_error     (FrProcess            *fr_proc,
+					     gboolean              ignore_error);
+void        fr_process_use_standard_locale  (FrProcess            *fr_proc,
+					     gboolean              use_stand_locale);
+void        fr_process_set_out_line_func    (FrProcess            *fr_proc,
+					     LineFunc              func,
+					     gpointer              func_data);
+void        fr_process_set_err_line_func    (FrProcess            *fr_proc,
+					     LineFunc              func,
+					     gpointer              func_data);
+void        fr_process_execute              (FrProcess            *process,
+					     GCancellable         *cancellable,
+					     GAsyncReadyCallback   callback,
+					     gpointer              user_data);
+gboolean    fr_process_execute_finish       (FrProcess            *process,
+					     GAsyncResult         *result,
+					     FrError             **error);
+void        fr_process_restart              (FrProcess            *process);
+void        fr_process_cancel               (FrProcess            *process);
 
 #endif /* FR_PROCESS_H */
diff --git a/src/fr-window.c b/src/fr-window.c
index 247eaa6..61fc551 100644
--- a/src/fr-window.c
+++ b/src/fr-window.c
@@ -42,6 +42,7 @@
 #include "fr-marshal.h"
 #include "fr-list-model.h"
 #include "fr-archive.h"
+#include "fr-command.h"
 #include "fr-error.h"
 #include "fr-stock.h"
 #include "fr-window.h"
@@ -128,12 +129,6 @@ typedef struct {
 } FRConvertData;
 
 
-typedef enum {
-	FR_CLIPBOARD_OP_CUT,
-	FR_CLIPBOARD_OP_COPY
-} FRClipboardOp;
-
-
 typedef struct {
 	GList       *file_list;
 	char        *extract_to_dir;
@@ -172,7 +167,7 @@ typedef struct {
 	int            refs;
 	char          *archive_uri;
 	char          *archive_password;
-	FRClipboardOp  op;
+	FrClipboardOp  op;
 	char          *base_dir;
 	GList         *files;
 	char          *tmp_dir;
@@ -245,7 +240,7 @@ enum {
 
 static guint fr_window_signals[LAST_SIGNAL] = { 0 };
 
-struct _FrWindowPrivateData {
+struct _FrWindowPrivate {
 	GtkWidget         *layout;
 	GtkWidget         *contents;
 	GtkWidget         *list_view;
@@ -388,6 +383,8 @@ struct _FrWindowPrivateData {
 
 	/* misc */
 
+	GCancellable     *cancellable;
+
 	GSettings        *settings_listing;
 	GSettings        *settings_ui;
 	GSettings        *settings_general;
@@ -512,7 +509,7 @@ fr_window_free_open_files (FrWindow *window)
 
 
 static void
-fr_window_convert_data_free (FrWindow   *window,
+_fr_window_convert_data_free (FrWindow   *window,
 			     gboolean    all)
 {
 	if (all) {
@@ -590,7 +587,7 @@ fr_window_free_private_data (FrWindow *window)
 
 	fr_window_free_open_files (window);
 
-	fr_window_convert_data_free (window, TRUE);
+	_fr_window_convert_data_free (window, TRUE);
 
 	g_clear_error (&window->priv->drag_error);
 	_g_string_list_free (window->priv->drag_file_list);
@@ -629,6 +626,8 @@ fr_window_free_private_data (FrWindow *window)
 	_g_object_unref (window->priv->settings_general);
 	_g_object_unref (window->priv->settings_dialogs);
 	_g_object_unref (window->priv->settings_nautilus);
+
+	_g_object_unref (window->priv->cancellable);
 }
 
 
@@ -791,11 +790,14 @@ fr_window_unrealized (GtkWidget *window,
 static void
 fr_window_init (FrWindow *window)
 {
-	window->priv = g_new0 (FrWindowPrivateData, 1);
+	window->priv = g_new0 (FrWindowPrivate, 1);
 	window->priv->update_dropped_files = FALSE;
 	window->priv->filter_mode = FALSE;
 	window->priv->use_progress_dialog = TRUE;
 	window->priv->batch_title = NULL;
+	window->priv->cancellable = g_cancellable_new ();
+
+	window->archive = NULL;
 
 	g_signal_connect (window,
 			  "realize",
@@ -880,8 +882,8 @@ fr_window_get_current_dir_list (FrWindow *window)
 
 	files = g_ptr_array_sized_new (128);
 
-	for (i = 0; i < window->archive->command->files->len; i++) {
-		FileData *fdata = g_ptr_array_index (window->archive->command->files, i);
+	for (i = 0; i < window->archive->files->len; i++) {
+		FileData *fdata = g_ptr_array_index (window->archive->files, i);
 
 		if (fdata->list_name == NULL)
 			continue;
@@ -1034,8 +1036,8 @@ get_dir_size (FrWindow   *window,
 	dirname_l = strlen (dirname);
 
 	size = 0;
-	for (i = 0; i < window->archive->command->files->len; i++) {
-		FileData *fd = g_ptr_array_index (window->archive->command->files, i);
+	for (i = 0; i < window->archive->files->len; i++) {
+		FileData *fd = g_ptr_array_index (window->archive->files, i);
 
 		if (strncmp (dirname, fd->full_path, dirname_l) == 0)
 			size += fd->size;
@@ -1182,8 +1184,8 @@ fr_window_dir_exists_in_archive (FrWindow   *window,
 	if (strcmp (dir_name, "/") == 0)
 		return TRUE;
 
-	for (i = 0; i < window->archive->command->files->len; i++) {
-		FileData *fdata = g_ptr_array_index (window->archive->command->files, i);
+	for (i = 0; i < window->archive->files->len; i++) {
+		FileData *fdata = g_ptr_array_index (window->archive->files, i);
 
 		if (strncmp (dir_name, fdata->full_path, dir_name_len) == 0) {
 			return TRUE;
@@ -1436,7 +1438,7 @@ fr_window_update_statusbar_list_info (FrWindow *window)
 	if (window == NULL)
 		return;
 
-	if ((window->archive == NULL) || (window->archive->command == NULL)) {
+	if (window->archive == NULL) {
 		gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), window->priv->list_info_cid);
 		return;
 	}
@@ -1744,8 +1746,8 @@ fr_window_update_dir_tree (FrWindow *window)
 	dirs = g_ptr_array_sized_new (128);
 
 	dir_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
-	for (i = 0; i < window->archive->command->files->len; i++) {
-		FileData *fdata = g_ptr_array_index (window->archive->command->files, i);
+	for (i = 0; i < window->archive->files->len; i++) {
+		FileData *fdata = g_ptr_array_index (window->archive->files, i);
 		char     *dir;
 
 		if (gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry)) != NULL) {
@@ -1786,7 +1788,7 @@ fr_window_update_dir_tree (FrWindow *window)
 		char        *uri;
 		char        *name;
 
-		uri = g_file_get_uri (window->archive->file);
+		uri = g_file_get_uri (fr_archive_get_file (window->archive));
 		name = _g_uri_display_basename (uri);
 
 		gtk_tree_store_append (window->priv->tree_store, &node, NULL);
@@ -1897,8 +1899,8 @@ fr_window_update_file_list (FrWindow *window,
 	fr_window_start_activity_mode (window);
 
 	if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
-		fr_window_compute_list_names (window, window->archive->command->files);
-		files = window->archive->command->files;
+		fr_window_compute_list_names (window, window->archive->files);
+		files = window->archive->files;
 		free_files = FALSE;
 	}
 	else {
@@ -1917,7 +1919,7 @@ fr_window_update_file_list (FrWindow *window,
 		}
 		g_free (current_dir);
 
-		fr_window_compute_list_names (window, window->archive->command->files);
+		fr_window_compute_list_names (window, window->archive->files);
 		files = fr_window_get_current_dir_list (window);
 		free_files = TRUE;
 	}
@@ -2020,7 +2022,6 @@ fr_window_update_paste_command_sensitivity (FrWindow     *window,
 	gboolean running;
 	gboolean no_archive;
 	gboolean ro;
-	gboolean compr_file;
 
 	if (window->priv->closing)
 		return;
@@ -2030,9 +2031,14 @@ fr_window_update_paste_command_sensitivity (FrWindow     *window,
 	running    = window->priv->activity_ref > 0;
 	no_archive = (window->archive == NULL) || ! window->priv->archive_present;
 	ro         = ! no_archive && window->archive->read_only;
-	compr_file = ! no_archive && window->archive->is_compressed_file;
 
-	set_sensitive (window, "Paste", ! no_archive && ! ro && ! running && ! compr_file && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT) && gtk_clipboard_wait_is_target_available (clipboard, FR_SPECIAL_URI_LIST));
+	set_sensitive (window, "Paste",
+		       ! no_archive
+		       && ! ro
+		       && ! running
+		       && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES)
+		       && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT)
+		       && gtk_clipboard_wait_is_target_available (clipboard, FR_SPECIAL_URI_LIST));
 }
 
 
@@ -2043,7 +2049,7 @@ fr_window_update_sensitivity (FrWindow *window)
 	gboolean ro;
 	gboolean file_op;
 	gboolean running;
-	gboolean compr_file;
+	gboolean can_store_many_files;
 	gboolean sel_not_null;
 	gboolean one_file_selected;
 	gboolean dir_selected;
@@ -2052,23 +2058,23 @@ fr_window_update_sensitivity (FrWindow *window)
 	if (window->priv->batch_mode)
 		return;
 
-	running           = window->priv->activity_ref > 0;
-	no_archive        = (window->archive == NULL) || ! window->priv->archive_present;
-	ro                = ! no_archive && window->archive->read_only;
-	file_op           = ! no_archive && ! window->priv->archive_new  && ! running;
-	compr_file        = ! no_archive && window->archive->is_compressed_file;
-	n_selected        = fr_window_get_n_selected_files (window);
-	sel_not_null      = n_selected > 0;
-	one_file_selected = n_selected == 1;
-	dir_selected      = selection_has_a_dir (window);
-
-	set_sensitive (window, "AddFiles", ! no_archive && ! ro && ! running && ! compr_file);
-	set_sensitive (window, "AddFiles_Toolbar", ! no_archive && ! ro && ! running && ! compr_file);
-	set_sensitive (window, "AddFolder", ! no_archive && ! ro && ! running && ! compr_file);
-	set_sensitive (window, "AddFolder_Toolbar", ! no_archive && ! ro && ! running && ! compr_file);
-	set_sensitive (window, "Copy", ! no_archive && ! ro && ! running && ! compr_file && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
-	set_sensitive (window, "Cut", ! no_archive && ! ro && ! running && ! compr_file && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
-	set_sensitive (window, "Delete", ! no_archive && ! ro && ! window->priv->archive_new && ! running && ! compr_file);
+	running              = window->priv->activity_ref > 0;
+	no_archive           = (window->archive == NULL) || ! window->priv->archive_present;
+	ro                   = ! no_archive && window->archive->read_only;
+	file_op              = ! no_archive && ! window->priv->archive_new  && ! running;
+	can_store_many_files = fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES);
+	n_selected           = fr_window_get_n_selected_files (window);
+	sel_not_null         = n_selected > 0;
+	one_file_selected    = n_selected == 1;
+	dir_selected         = selection_has_a_dir (window);
+
+	set_sensitive (window, "AddFiles", ! no_archive && ! ro && ! running && can_store_many_files);
+	set_sensitive (window, "AddFiles_Toolbar", ! no_archive && ! ro && ! running && can_store_many_files);
+	set_sensitive (window, "AddFolder", ! no_archive && ! ro && ! running && can_store_many_files);
+	set_sensitive (window, "AddFolder_Toolbar", ! no_archive && ! ro && ! running && can_store_many_files);
+	set_sensitive (window, "Copy", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
+	set_sensitive (window, "Cut", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
+	set_sensitive (window, "Delete", ! no_archive && ! ro && ! window->priv->archive_new && ! running && can_store_many_files);
 	set_sensitive (window, "DeselectAll", ! no_archive && sel_not_null);
 	set_sensitive (window, "Extract", file_op);
 	set_sensitive (window, "Extract_Toolbar", file_op);
@@ -2078,15 +2084,15 @@ fr_window_update_sensitivity (FrWindow *window)
 	set_sensitive (window, "Open_Toolbar", ! running);
 	set_sensitive (window, "OpenSelection", file_op && sel_not_null && ! dir_selected);
 	set_sensitive (window, "OpenFolder", file_op && one_file_selected && dir_selected);
-	set_sensitive (window, "Password", ! running && (window->priv->asked_for_password || (! no_archive && window->archive->command->propPassword)));
+	set_sensitive (window, "Password", ! running && (window->priv->asked_for_password || (! no_archive && window->archive->propPassword)));
 	set_sensitive (window, "Properties", file_op);
 	set_sensitive (window, "Close", !running || window->priv->stoppable);
 	set_sensitive (window, "Reload", ! (no_archive || running));
-	set_sensitive (window, "Rename", ! no_archive && ! ro && ! running && ! compr_file && one_file_selected);
-	set_sensitive (window, "SaveAs", ! no_archive && ! compr_file && ! running);
+	set_sensitive (window, "Rename", ! no_archive && ! ro && ! running && can_store_many_files && one_file_selected);
+	set_sensitive (window, "SaveAs", ! no_archive && can_store_many_files && ! running);
 	set_sensitive (window, "SelectAll", ! no_archive);
 	set_sensitive (window, "Stop", running && window->priv->stoppable);
-	set_sensitive (window, "TestArchive", ! no_archive && ! running && window->archive->command->propTest);
+	set_sensitive (window, "TestArchive", ! no_archive && ! running && window->archive->propTest);
 	set_sensitive (window, "ViewSelection", file_op && one_file_selected && ! dir_selected);
 	set_sensitive (window, "ViewSelection_Toolbar", file_op && one_file_selected && ! dir_selected);
 
@@ -2378,7 +2384,7 @@ fr_window_working_archive_cb (FrCommand  *command,
 
 
 static gboolean
-fr_window_message_cb (FrCommand  *command,
+fr_archive_message_cb (FrCommand  *command,
 		      const char *msg,
 		      FrWindow   *window)
 {
@@ -2514,7 +2520,7 @@ display_progress_dialog (gpointer data)
 			gtk_widget_show (GTK_WIDGET (window));
 		gtk_widget_hide (window->priv->progress_bar);
 		gtk_widget_show (window->priv->progress_dialog);
-		fr_window_message_cb (NULL, window->priv->pd_last_message, window);
+		fr_archive_message_cb (NULL, window->priv->pd_last_message, window);
 	}
 
 	window->priv->progress_timeout = 0;
@@ -2562,7 +2568,7 @@ open_progress_dialog (FrWindow *window,
 
 
 static gboolean
-fr_window_progress_cb (FrArchive *archive,
+fr_archive_progress_cb (FrArchive *archive,
 		       double     fraction,
 		       FrWindow  *window)
 {
@@ -2573,11 +2579,11 @@ fr_window_progress_cb (FrArchive *archive,
 			gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->pd_progress_bar), fraction);
 		gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->progress_bar), fraction);
 
-		if ((archive != NULL) && (archive->command->n_files > 1)) {
+		if ((archive != NULL) && (archive->n_files > 1)) {
 			char *message = NULL;
 			int   remaining_files;
 
-			remaining_files = archive->command->n_files - archive->command->n_file + 1;
+			remaining_files = archive->n_files - archive->n_file + 1;
 
 			switch (window->priv->action) {
 			case FR_ACTION_ADDING_FILES:
@@ -2592,7 +2598,7 @@ fr_window_progress_cb (FrArchive *archive,
 			}
 
 			if (message != NULL)
-				fr_command_message (archive->command, message);
+				fr_archive_message (archive, message);
 		}
 
 		window->priv->pd_last_fraction = fraction;
@@ -2632,8 +2638,8 @@ open_progress_dialog_with_open_destination (FrWindow *window)
 	gtk_widget_show (window->priv->pd_quit_button);
 	gtk_widget_show (window->priv->pd_close_button);
 	display_progress_dialog (window);
-	fr_window_progress_cb (NULL, 1.0, window);
-	fr_window_message_cb (NULL, _("Extraction completed successfully"), window);
+	fr_archive_progress_cb (NULL, 1.0, window);
+	fr_archive_message_cb (NULL, _("Extraction completed successfully"), window);
 }
 
 
@@ -2655,8 +2661,8 @@ open_progress_dialog_with_open_archive (FrWindow *window)
 	gtk_widget_show (window->priv->pd_open_archive_button);
 	gtk_widget_show (window->priv->pd_close_button);
 	display_progress_dialog (window);
-	fr_window_progress_cb (NULL, 1.0, window);
-	fr_window_message_cb (NULL, _("Archive created successfully"), window);
+	fr_archive_progress_cb (NULL, 1.0, window);
+	fr_archive_message_cb (NULL, _("Archive created successfully"), window);
 }
 
 
@@ -2712,10 +2718,8 @@ action_started (FrArchive *archive,
 		break;
 	}
 
-	if (archive->command != NULL) {
-		fr_command_progress (archive->command, -1.0);
-		fr_command_message (archive->command, _("Please waitâ"));
-	}
+	fr_archive_progress (archive, -1.0);
+	fr_archive_message (archive, _("Please waitâ"));
 }
 
 
@@ -2726,11 +2730,11 @@ fr_window_add_to_recent_list (FrWindow *window,
 	if (_g_path_is_temp_dir (uri))
 		return;
 
-	if (window->archive->content_type != NULL) {
+	if (window->archive->mime_type != NULL) {
 		GtkRecentData *recent_data;
 
 		recent_data = g_new0 (GtkRecentData, 1);
-		recent_data->mime_type = g_content_type_get_mime_type (window->archive->content_type);
+		recent_data->mime_type = g_content_type_get_mime_type (window->archive->mime_type);
 		recent_data->app_name = "File Roller";
 		recent_data->app_exec = "file-roller";
 		gtk_recent_manager_add_full (gtk_recent_manager_get_default (), uri, recent_data);
@@ -2780,7 +2784,7 @@ fr_window_show_error_dialog (FrWindow   *window,
 	if (window->priv->batch_mode && ! window->priv->use_progress_dialog) {
 		GError *error;
 
-		error = g_error_new_literal (FR_ERROR, FR_PROC_ERROR_GENERIC, details ? details : _("Command exited abnormally."));
+		error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, details ? details : _("Command exited abnormally."));
 		g_signal_emit (window,
 			       fr_window_signals[READY],
 			       0,
@@ -2820,40 +2824,57 @@ fr_window_destroy_with_error_dialog (FrWindow *window)
 }
 
 
-static gboolean
-handle_errors (FrWindow    *window,
-	       FrArchive   *archive,
-	       FrAction     action,
-	       FrProcError *error)
-{
-	if (error->type == FR_PROC_ERROR_ASK_PASSWORD) {
+static void
+_handle_archive_operation_error (FrWindow  *window,
+				 FrArchive *archive,
+				 FrAction   action,
+				 GError    *error,
+				 gboolean  *continue_batch,
+				 gboolean  *opens_dialog)
+{
+	GtkWindow *dialog_parent;
+	char      *msg;
+	char      *utf8_name;
+	char      *details;
+	GList     *output;
+	GtkWidget *dialog;
+
+	if (continue_batch) *continue_batch = (error == NULL);
+	if (opens_dialog) *opens_dialog = FALSE;
+
+	if (error == NULL)
+		return;
+
+	switch (error->code) {
+	case FR_ERROR_ASK_PASSWORD:
 		close_progress_dialog (window, TRUE);
 		dlg_ask_password (window);
-		return FALSE;
-	}
-	else if (error->type == FR_PROC_ERROR_UNSUPPORTED_FORMAT) {
+		if (opens_dialog) *opens_dialog = TRUE;
+		break;
+
+	case FR_ERROR_UNSUPPORTED_FORMAT:
 		close_progress_dialog (window, TRUE);
 		dlg_package_installer (window, archive, action);
-		return FALSE;
-	}
+		if (opens_dialog) *opens_dialog = TRUE;
+		break;
+
 #if 0
-	else if (error->type == FR_PROC_ERROR_BAD_CHARSET) {
+	case FR_PROC_ERROR_BAD_CHARSET:
 		close_progress_dialog (window, TRUE);
 		/* dlg_ask_archive_charset (window); FIXME: implement after feature freeze */
-		return FALSE;
-	}
+		break;
 #endif
-	else if (error->type == FR_PROC_ERROR_STOPPED) {
+
+	case FR_ERROR_STOPPED:
 		/* nothing */
-	}
-	else if (error->type != FR_PROC_ERROR_NONE) {
-		char      *msg = NULL;
-		char      *utf8_name;
-		char      *details = NULL;
-		GtkWindow *dialog_parent;
-		GtkWidget *dialog;
-		FrProcess *process = archive->process;
-		GList     *output = NULL;
+		break;
+
+	default:
+		/* generic error => show an error dialog */
+
+		msg = NULL;
+		details = NULL;
+		output = NULL;
 
 		if (window->priv->batch_mode) {
 			dialog_parent = NULL;
@@ -2913,26 +2934,23 @@ handle_errors (FrWindow    *window,
 			break;
 		}
 
-		switch (error->type) {
-		case FR_PROC_ERROR_COMMAND_NOT_FOUND:
+		switch (error->code) {
+		case FR_ERROR_COMMAND_NOT_FOUND:
 			details = _("Command not found.");
 			break;
-		case FR_PROC_ERROR_EXITED_ABNORMALLY:
+		case FR_ERROR_EXITED_ABNORMALLY:
 			details = _("Command exited abnormally.");
 			break;
-		case FR_PROC_ERROR_SPAWN:
-			details = error->gerror->message;
+		case FR_ERROR_SPAWN:
+			details = error->message;
 			break;
 		default:
-			if (error->gerror != NULL)
-				details = error->gerror->message;
-			else
-				details = NULL;
+			details = error->message;
 			break;
 		}
 
-		if (error->type != FR_PROC_ERROR_GENERIC)
-			output = (process->err.raw != NULL) ? process->err.raw : process->out.raw;
+		if ((error->code != FR_ERROR_GENERIC) && FR_IS_COMMAND (archive))
+			output = fr_command_get_last_output (FR_COMMAND (archive));
 
 		dialog = _gtk_error_dialog_new (dialog_parent,
 						0,
@@ -2941,55 +2959,182 @@ handle_errors (FrWindow    *window,
 						((details != NULL) ? "%s" : NULL),
 						details);
 		fr_window_show_error_dialog (window, dialog, dialog_parent, details);
-
-		return FALSE;
+		break;
 	}
-
-	return TRUE;
 }
 
 
+static void fr_window_exec_next_batch_action (FrWindow *window);
+
+
 static void
-convert__action_performed (FrArchive   *archive,
-			   FrAction     action,
-			   FrProcError *error,
-			   gpointer     data)
+_archive_operation_completed (FrWindow *window,
+			      FrAction  action,
+			      GError   *error)
 {
-	FrWindow *window = data;
+	gboolean  continue_batch = FALSE;
+	gboolean  opens_dialog;
+	gboolean  operation_canceled;
+	char     *archive_dir;
+	gboolean  temp_dir;
 
 #ifdef DEBUG
-	debug (DEBUG_INFO, "%s [CONVERT::DONE] (FR::Window)\n", action_names[action]);
+	debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
 #endif
 
-	if ((action == FR_ACTION_GETTING_FILE_LIST) || (action == FR_ACTION_ADDING_FILES)) {
-		fr_window_stop_activity_mode (window);
-		fr_window_pop_message (window);
+	fr_window_stop_activity_mode (window);
+	fr_window_pop_message (window);
+
+	_handle_archive_operation_error (window, window->archive, action, error, &continue_batch, &opens_dialog);
+	if (opens_dialog)
+		return;
+
+	operation_canceled = ((error != NULL) && (error->code == FR_ERROR_STOPPED));
+
+	switch (action) {
+	case FR_ACTION_CREATING_NEW_ARCHIVE:
+	case FR_ACTION_CREATING_ARCHIVE:
 		close_progress_dialog (window, FALSE);
-	}
+		if (! operation_canceled) {
+			fr_window_history_clear (window);
+			fr_window_go_to_location (window, "/", TRUE);
+			fr_window_update_dir_tree (window);
+			fr_window_update_title (window);
+			fr_window_update_sensitivity (window);
+		}
+		break;
 
-	if (action != FR_ACTION_ADDING_FILES)
+	case FR_ACTION_LOADING_ARCHIVE:
+		close_progress_dialog (window, FALSE);
+		if (error != NULL) {
+			fr_window_remove_from_recent_list (window, window->priv->archive_uri);
+			if (window->priv->non_interactive) {
+				fr_window_archive_close (window);
+				fr_window_stop_batch (window);
+			}
+		}
+		else {
+			fr_window_add_to_recent_list (window, window->priv->archive_uri);
+			if (! window->priv->non_interactive)
+				gtk_window_present (GTK_WINDOW (window));
+		}
+		continue_batch = FALSE;
+		g_signal_emit (window,
+			       fr_window_signals[ARCHIVE_LOADED],
+			       0,
+			       error == NULL);
+		break;
+
+	case FR_ACTION_LISTING_CONTENT:
+		/* update the uri because multi-volume archives can have
+		 * a different name after loading. */
+		g_free (window->priv->archive_uri);
+		window->priv->archive_uri = g_file_get_uri (fr_archive_get_file (window->archive));
+
+		close_progress_dialog (window, FALSE);
+		if (error != NULL) {
+			fr_window_remove_from_recent_list (window, window->priv->archive_uri);
+			fr_window_archive_close (window);
+			fr_window_set_password (window, NULL);
+			break;
+		}
+
+		/* error == NULL */
+
+		archive_dir = _g_path_remove_level (window->priv->archive_uri);
+		temp_dir = _g_path_is_temp_dir (archive_dir);
+		if (! window->priv->archive_present) {
+			window->priv->archive_present = TRUE;
+
+			fr_window_history_clear (window);
+			fr_window_history_add (window, "/");
+
+			if (! temp_dir) {
+				fr_window_set_open_default_dir (window, archive_dir);
+				fr_window_set_add_default_dir (window, archive_dir);
+				if (! window->priv->freeze_default_dir)
+					fr_window_set_extract_default_dir (window, archive_dir, FALSE);
+			}
+
+			window->priv->archive_new = FALSE;
+		}
+		g_free (archive_dir);
+
+		if (! temp_dir)
+			fr_window_add_to_recent_list (window, window->priv->archive_uri);
+
+		fr_window_update_title (window);
+		fr_window_go_to_location (window, fr_window_get_current_location (window), TRUE);
+		fr_window_update_dir_tree (window);
+		if (! window->priv->batch_mode && window->priv->non_interactive)
+			gtk_window_present (GTK_WINDOW (window));
+		break;
+
+	case FR_ACTION_DELETING_FILES:
+		close_progress_dialog (window, FALSE);
+		if (! operation_canceled)
+			fr_window_archive_reload (window);
 		return;
 
-	handle_errors (window, archive, action, error);
+	case FR_ACTION_ADDING_FILES:
+		close_progress_dialog (window, FALSE);
 
-	if (error->type == FR_PROC_ERROR_NONE)
-		open_progress_dialog_with_open_archive (window);
+		/* update the uri because multi-volume archives can have
+		 * a different name after creation. */
+		g_free (window->priv->archive_uri);
+		window->priv->archive_uri = g_file_get_uri (fr_archive_get_file (window->archive));
 
-	_g_path_remove_directory (window->priv->convert_data.temp_dir);
-	fr_window_convert_data_free (window, FALSE);
+		if (error == NULL) {
+			if (window->priv->archive_new)
+				window->priv->archive_new = FALSE;
+			fr_window_add_to_recent_list (window, window->priv->archive_uri);
+		}
+		if (! window->priv->batch_mode && ! operation_canceled) {
+			fr_window_archive_reload (window);
+			return;
+		}
+		break;
 
-	fr_window_update_sensitivity (window);
-	fr_window_update_statusbar_list_info (window);
+	case FR_ACTION_TESTING_ARCHIVE:
+		close_progress_dialog (window, FALSE);
+		if (error == NULL)
+			fr_window_view_last_output (window, _("Test Result"));
+		return;
+
+	case FR_ACTION_EXTRACTING_FILES:
+		if (window->priv->ask_to_open_destination_after_extraction)
+			open_progress_dialog_with_open_destination (window);
+		else
+			close_progress_dialog (window, FALSE);
+		break;
+
+	default:
+		close_progress_dialog (window, FALSE);
+		continue_batch = FALSE;
+		break;
+	}
+
+	if (window->priv->batch_action == NULL) {
+		fr_window_update_sensitivity (window);
+		fr_window_update_statusbar_list_info (window);
+	}
+
+	if (continue_batch) {
+		if (error != NULL)
+			fr_window_stop_batch (window);
+		else
+			fr_window_exec_next_batch_action (window);
+	}
 }
 
 
-static void fr_window_exec_next_batch_action (FrWindow *window);
+#if 0  /* FIXME: libarchive */
 
 
 static void
 action_performed (FrArchive   *archive,
 		  FrAction     action,
-		  FrProcError *error,
+		  FrError *error,
 		  gpointer     data)
 {
 	FrWindow *window = data;
@@ -3004,10 +3149,10 @@ action_performed (FrArchive   *archive,
 	fr_window_stop_activity_mode (window);
 	fr_window_pop_message (window);
 
-	continue_batch = handle_errors (window, archive, action, error);
+	continue_batch = _handle_archive_operation_error (window, archive, action, error);
 
-	if ((error->type == FR_PROC_ERROR_ASK_PASSWORD)
-	    || (error->type == FR_PROC_ERROR_UNSUPPORTED_FORMAT)
+	if ((error->type == FR_ERROR_ASK_PASSWORD)
+	    || (error->type == FR_ERROR_UNSUPPORTED_FORMAT)
 	    /*|| (error->type == FR_PROC_ERROR_BAD_CHARSET)*/)
 	{
 		return;
@@ -3017,7 +3162,7 @@ action_performed (FrArchive   *archive,
 	case FR_ACTION_CREATING_NEW_ARCHIVE:
 	case FR_ACTION_CREATING_ARCHIVE:
 		close_progress_dialog (window, FALSE);
-		if (error->type != FR_PROC_ERROR_STOPPED) {
+		if (error->type != FR_ERROR_STOPPED) {
 			fr_window_history_clear (window);
 			fr_window_go_to_location (window, "/", TRUE);
 			fr_window_update_dir_tree (window);
@@ -3028,7 +3173,7 @@ action_performed (FrArchive   *archive,
 
 	case FR_ACTION_LOADING_ARCHIVE:
 		close_progress_dialog (window, FALSE);
-		if (error->type != FR_PROC_ERROR_NONE) {
+		if (error->type != FR_ERROR_NONE) {
 			fr_window_remove_from_recent_list (window, window->priv->archive_uri);
 			if (window->priv->non_interactive) {
 				fr_window_archive_close (window);
@@ -3044,7 +3189,7 @@ action_performed (FrArchive   *archive,
 		g_signal_emit (window,
 			       fr_window_signals[ARCHIVE_LOADED],
 			       0,
-			       error->type == FR_PROC_ERROR_NONE);
+			       error->type == FR_ERROR_NONE);
 		break;
 
 	case FR_ACTION_LISTING_CONTENT:
@@ -3054,7 +3199,7 @@ action_performed (FrArchive   *archive,
 		window->priv->archive_uri = g_file_get_uri (window->archive->file);
 
 		close_progress_dialog (window, FALSE);
-		if (error->type != FR_PROC_ERROR_NONE) {
+		if (error->type != FR_ERROR_NONE) {
 			fr_window_remove_from_recent_list (window, window->priv->archive_uri);
 			fr_window_archive_close (window);
 			fr_window_set_password (window, NULL);
@@ -3092,7 +3237,7 @@ action_performed (FrArchive   *archive,
 
 	case FR_ACTION_DELETING_FILES:
 		close_progress_dialog (window, FALSE);
-		if (error->type != FR_PROC_ERROR_STOPPED)
+		if (error->type != FR_ERROR_STOPPED)
 			fr_window_archive_reload (window);
 		return;
 
@@ -3104,12 +3249,12 @@ action_performed (FrArchive   *archive,
 		g_free (window->priv->archive_uri);
 		window->priv->archive_uri = g_file_get_uri (window->archive->file);
 
-		if (error->type == FR_PROC_ERROR_NONE) {
+		if (error->type == FR_ERROR_NONE) {
 			if (window->priv->archive_new)
 				window->priv->archive_new = FALSE;
 			fr_window_add_to_recent_list (window, window->priv->archive_uri);
 		}
-		if (! window->priv->batch_mode && (error->type != FR_PROC_ERROR_STOPPED)) {
+		if (! window->priv->batch_mode && (error->type != FR_ERROR_STOPPED)) {
 			fr_window_archive_reload (window);
 			return;
 		}
@@ -3117,15 +3262,15 @@ action_performed (FrArchive   *archive,
 
 	case FR_ACTION_TESTING_ARCHIVE:
 		close_progress_dialog (window, FALSE);
-		if (error->type == FR_PROC_ERROR_NONE)
+		if (error->type == FR_ERROR_NONE)
 			fr_window_view_last_output (window, _("Test Result"));
 		return;
 
 	case FR_ACTION_EXTRACTING_FILES:
-		if (error->type != FR_PROC_ERROR_NONE) {
+		if (error->type != FR_ERROR_NONE) {
 			if (window->priv->convert_data.converting) {
 				_g_path_remove_directory (window->priv->convert_data.temp_dir);
-				fr_window_convert_data_free (window, TRUE);
+				_fr_window_convert_data_free (window, TRUE);
 			}
 			break;
 		}
@@ -3167,7 +3312,7 @@ action_performed (FrArchive   *archive,
 	}
 
 	if (continue_batch) {
-		if (error->type != FR_PROC_ERROR_NONE)
+		if (error->type != FR_ERROR_NONE)
 			fr_window_stop_batch (window);
 		else
 			fr_window_exec_next_batch_action (window);
@@ -3175,6 +3320,9 @@ action_performed (FrArchive   *archive,
 }
 
 
+#endif
+
+
 /* -- selections -- */
 
 
@@ -3192,8 +3340,8 @@ get_dir_list_from_path (FrWindow *window,
 	else
 		dirname = g_strdup (path);
 	dirname_l = strlen (dirname);
-	for (i = 0; i < window->archive->command->files->len; i++) {
-		FileData *fd = g_ptr_array_index (window->archive->command->files, i);
+	for (i = 0; i < window->archive->files->len; i++) {
+		FileData *fd = g_ptr_array_index (window->archive->files, i);
 
 		if (strncmp (dirname, fd->full_path, dirname_l) == 0)
 			list = g_list_prepend (list, g_strdup (fd->original_path));
@@ -3372,8 +3520,8 @@ fr_window_get_file_list_pattern (FrWindow    *window,
 
 	regexps = _g_regexp_split_from_patterns (pattern, G_REGEX_CASELESS);
 	list = NULL;
-	for (i = 0; i < window->archive->command->files->len; i++) {
-		FileData *fd = g_ptr_array_index (window->archive->command->files, i);
+	for (i = 0; i < window->archive->files->len; i++) {
+		FileData *fd = g_ptr_array_index (window->archive->files, i);
 		char     *utf8_name;
 
 		/* FIXME: only files in the current location ? */
@@ -3956,7 +4104,7 @@ fr_window_drag_data_received  (GtkWidget          *widget,
 	if (window->priv->archive_present
 	    && (window->archive != NULL)
 	    && ! window->archive->read_only
-	    && ! window->archive->is_compressed_file)
+	    && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES))
 	{
 		if (one_file && is_an_archive) {
 			GtkWidget *d;
@@ -4180,7 +4328,8 @@ get_selection_data_from_clipboard_data (FrWindow        *window,
 
 	list = g_string_new (NULL);
 
-	local_filename = g_file_get_uri (window->archive->local_copy);
+	/* FIXME: check if this works correctly */
+	local_filename = g_file_get_uri (fr_archive_get_file (window->archive));
 	g_string_append (list, local_filename);
 	g_free (local_filename);
 
@@ -4979,7 +5128,7 @@ theme_changed_cb (GtkIconTheme *theme, FrWindow *window)
 
 
 static gboolean
-fr_window_stoppable_cb (FrCommand  *command,
+fr_archive_stoppable_cb (FrCommand  *command,
 			gboolean    stoppable,
 			FrWindow   *window)
 {
@@ -4993,56 +5142,6 @@ fr_window_stoppable_cb (FrCommand  *command,
 }
 
 
-static gboolean
-fr_window_fake_load (FrArchive *archive,
-		     gpointer   data)
-{
-	/* fake loads are disabled to allow exact progress dialogs (#153281) */
-
-	return FALSE;
-
-#if 0
-	FrWindow *window = data;
-	gboolean  add_after_opening = FALSE;
-	gboolean  extract_after_opening = FALSE;
-	GList    *scan;
-
-	/* fake loads are used only in batch mode to avoid unnecessary
-	 * archive loadings. */
-
-	if (! window->priv->batch_mode)
-		return FALSE;
-
-	/* Check whether there is an ADD or EXTRACT action in the batch list. */
-
-	for (scan = window->priv->batch_action; scan; scan = scan->next) {
-		FRBatchAction *action;
-
-		action = (FRBatchAction *) scan->data;
-		if (action->type == FR_BATCH_ACTION_ADD) {
-			add_after_opening = TRUE;
-			break;
-		}
-		if ((action->type == FR_BATCH_ACTION_EXTRACT)
-		    || (action->type == FR_BATCH_ACTION_EXTRACT_HERE)
-		    || (action->type == FR_BATCH_ACTION_EXTRACT_INTERACT))
-		{
-			extract_after_opening = TRUE;
-			break;
-		}
-	}
-
-	/* use fake load when in batch mode and the archive type supports all
-	 * of the required features */
-
-	return (window->priv->batch_mode
-		&& ! (add_after_opening && window->priv->update_dropped_files && ! archive->command->propAddCanUpdate)
-		&& ! (add_after_opening && ! window->priv->update_dropped_files && ! archive->command->propAddCanReplace)
-		&& ! (extract_after_opening && !archive->command->propCanExtractAll));
-#endif
-}
-
-
 static void
 menu_item_select_cb (GtkMenuItem *proxy,
 		     FrWindow    *window)
@@ -5366,36 +5465,6 @@ fr_window_construct (FrWindow *window)
 
 	/* Initialize Data. */
 
-	window->archive = fr_archive_new ();
-	g_signal_connect (G_OBJECT (window->archive),
-			  "start",
-			  G_CALLBACK (action_started),
-			  window);
-	g_signal_connect (G_OBJECT (window->archive),
-			  "done",
-			  G_CALLBACK (action_performed),
-			  window);
-	g_signal_connect (G_OBJECT (window->archive),
-			  "progress",
-			  G_CALLBACK (fr_window_progress_cb),
-			  window);
-	g_signal_connect (G_OBJECT (window->archive),
-			  "message",
-			  G_CALLBACK (fr_window_message_cb),
-			  window);
-	g_signal_connect (G_OBJECT (window->archive),
-			  "stoppable",
-			  G_CALLBACK (fr_window_stoppable_cb),
-			  window);
-	g_signal_connect (G_OBJECT (window->archive),
-			  "working_archive",
-			  G_CALLBACK (fr_window_working_archive_cb),
-			  window);
-
-	fr_archive_set_fake_load_func (window->archive,
-				       fr_window_fake_load,
-				       window);
-
 	window->priv->sort_method = g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_SORT_METHOD);
 	window->priv->sort_type = g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_SORT_TYPE);
 
@@ -5909,12 +5978,45 @@ fr_window_new (void)
 
 
 static void
-fr_window_set_archive_uri (FrWindow   *window,
+_fr_window_set_archive (FrWindow  *window,
+			FrArchive *archive)
+{
+	if (window->archive != NULL) {
+		g_signal_handlers_disconnect_by_data (window->archive, window);
+		g_object_unref (window->archive);
+	}
+
+	window->archive = _g_object_ref (archive);
+
+	if (window->archive == NULL)
+		return;
+
+	g_signal_connect (G_OBJECT (window->archive),
+			  "progress",
+			  G_CALLBACK (fr_archive_progress_cb),
+			  window);
+	g_signal_connect (G_OBJECT (window->archive),
+			  "message",
+			  G_CALLBACK (fr_archive_message_cb),
+			  window);
+	g_signal_connect (G_OBJECT (window->archive),
+			  "stoppable",
+			  G_CALLBACK (fr_archive_stoppable_cb),
+			  window);
+	g_signal_connect (G_OBJECT (window->archive),
+			  "working_archive",
+			  G_CALLBACK (fr_window_working_archive_cb),
+			  window);
+}
+
+
+static void
+_fr_window_set_archive_uri (FrWindow   *window,
 			   const char *uri)
 {
 	if (window->priv->archive_uri != NULL)
-			g_free (window->priv->archive_uri);
-		window->priv->archive_uri = g_strdup (uri);
+		g_free (window->priv->archive_uri);
+	window->priv->archive_uri = g_strdup (uri);
 }
 
 
@@ -5922,30 +6024,101 @@ gboolean
 fr_window_archive_new (FrWindow   *window,
 		       const char *uri)
 {
-	g_return_val_if_fail (window != NULL, FALSE);
+	GFile     *file;
+	FrArchive *archive;
 
-	if (! fr_archive_create (window->archive, uri)) {
-		GtkWindow *file_sel = g_object_get_data (G_OBJECT (window), "fr_file_sel");
+	g_return_val_if_fail (window != NULL, FALSE);
+
+	file = g_file_new_for_uri (uri);
+	archive = fr_archive_create (file);
+	if (archive != NULL) {
+		fr_window_archive_close (window);
+		_fr_window_set_archive (window, archive);
+		_fr_window_set_archive_uri (window, uri);
+		window->priv->archive_present = TRUE;
+		window->priv->archive_new = TRUE;
+	}
+
+	g_object_unref (archive);
+	g_object_unref (file);
+
+	return archive != NULL;
+
+	/* FIXME: libarchive */
+#if 0
+
+	if (! fr_archive_create (window->archive, uri)) {
+		GtkWindow *file_sel = g_object_get_data (G_OBJECT (window), "fr_file_sel");
 
 		window->priv->load_error_parent_window = file_sel;
 		fr_archive_action_completed (window->archive,
 					     FR_ACTION_CREATING_NEW_ARCHIVE,
-					     FR_PROC_ERROR_GENERIC,
+					     FR_ERROR_GENERIC,
 					     _("Archive type not supported."));
 
 		return FALSE;
 	}
 
-	fr_window_set_archive_uri (window, uri);
+	_fr_window_set_archive_uri (window, uri);
 	window->priv->archive_present = TRUE;
 	window->priv->archive_new = TRUE;
 
 	fr_archive_action_completed (window->archive,
 				     FR_ACTION_CREATING_NEW_ARCHIVE,
-				     FR_PROC_ERROR_NONE,
+				     FR_ERROR_NONE,
 				     NULL);
 
 	return TRUE;
+#endif
+}
+
+
+static void
+archive_load_ready_cb (GObject      *source_object,
+		       GAsyncResult *result,
+		       gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error = NULL;
+
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+	_archive_operation_completed (window, FR_ACTION_LISTING_CONTENT, error);
+
+	_g_error_free (error);
+}
+
+
+static void
+fr_window_archive_load (FrWindow *window)
+{
+	fr_archive_load (window->archive,
+			 window->priv->password,
+			 window->priv->cancellable,
+			 archive_load_ready_cb,
+			 window);
+}
+
+
+static void
+archive_open_ready_cb (GObject      *source_object,
+		       GAsyncResult *result,
+		       gpointer      user_data)
+{
+	FrWindow  *window = user_data;
+	FrArchive *archive;
+	GError    *error = NULL;
+
+	archive = fr_archive_open_finish (G_FILE (source_object), result, &error);
+	if (archive == NULL) {
+		_archive_operation_completed (window, FR_ACTION_LOADING_ARCHIVE, error);
+		g_error_free (error);
+		return;
+	}
+
+	_fr_window_set_archive (window, archive);
+	fr_window_archive_load (window);
+
+	g_object_unref (archive);
 }
 
 
@@ -5955,6 +6128,7 @@ fr_window_archive_open (FrWindow   *current_window,
 			GtkWindow  *parent)
 {
 	FrWindow *window = current_window;
+	GFile    *file;
 
 	if (current_window->priv->archive_present)
 		window = (FrWindow *) fr_window_new ();
@@ -5962,9 +6136,7 @@ fr_window_archive_open (FrWindow   *current_window,
 	g_return_val_if_fail (window != NULL, FALSE);
 
 	fr_window_archive_close (window);
-
-	fr_window_set_archive_uri (window, uri);
-	window->priv->archive_present = FALSE;
+	_fr_window_set_archive_uri (window, uri);
 	window->priv->give_focus_to_the_list = TRUE;
 	window->priv->load_error_parent_window = parent;
 
@@ -5973,7 +6145,10 @@ fr_window_archive_open (FrWindow   *current_window,
 					    g_strdup (window->priv->archive_uri),
 					    (GFreeFunc) g_free);
 
-	fr_archive_load (window->archive, window->priv->archive_uri, window->priv->password);
+	file = g_file_new_for_uri (window->priv->archive_uri);
+	fr_archive_open (file, window->priv->cancellable, archive_open_ready_cb, window);
+
+	g_object_unref (file);
 
 	return window;
 }
@@ -5992,9 +6167,10 @@ fr_window_archive_close (FrWindow *window)
 	window->priv->copy_data = NULL;
 
 	fr_window_set_password (window, NULL);
-	fr_window_set_volume_size(window, 0);
+	fr_window_set_volume_size (window, 0);
 	fr_window_history_clear (window);
 
+	_fr_window_set_archive (window, NULL);
 	window->priv->archive_new = FALSE;
 	window->priv->archive_present = FALSE;
 
@@ -6076,6 +6252,157 @@ save_as_data_free (SaveAsData *sdata)
 }
 
 
+#if 0 /* FIXME: libarchive */
+
+
+static void
+convert__action_performed (FrArchive   *archive,
+			   FrAction     action,
+			   FrError *error,
+			   gpointer     data)
+{
+	FrWindow *window = data;
+
+#ifdef DEBUG
+	debug (DEBUG_INFO, "%s [CONVERT::DONE] (FR::Window)\n", action_names[action]);
+#endif
+
+	if ((action == FR_ACTION_GETTING_FILE_LIST) || (action == FR_ACTION_ADDING_FILES)) {
+		fr_window_stop_activity_mode (window);
+		fr_window_pop_message (window);
+		close_progress_dialog (window, FALSE);
+	}
+
+	if (action != FR_ACTION_ADDING_FILES)
+		return;
+
+	_handle_archive_operation_error (window, archive, action, error);
+
+	if (error->type == FR_ERROR_NONE)
+		open_progress_dialog_with_open_archive (window);
+
+	_g_path_remove_directory (window->priv->convert_data.temp_dir);
+	_fr_window_convert_data_free (window, FALSE);
+
+	fr_window_update_sensitivity (window);
+	fr_window_update_statusbar_list_info (window);
+}
+
+
+#endif
+
+
+#if 0
+
+
+if (error != NULL) {
+	/* FIXME
+	if (window->priv->convert_data.converting) {
+		_g_path_remove_directory (window->priv->convert_data.temp_dir);
+		_fr_window_convert_data_free (window, TRUE);
+	}
+	*/
+	break;
+}
+/* FIXME
+if (window->priv->convert_data.converting) {
+	char *source_dir;
+
+	source_dir = g_filename_to_uri (window->priv->convert_data.temp_dir, NULL, NULL);
+	fr_archive_add_with_wildcard (window->priv->convert_data.new_archive,
+				      "*",
+				      NULL,
+				      NULL,
+				      source_dir,
+				      NULL,
+				      FALSE,
+				      TRUE,
+				      window->priv->convert_data.password,
+				      window->priv->convert_data.encrypt_header,
+				      window->priv->compression,
+				      window->priv->convert_data.volume_size);
+	g_free (source_dir);
+}
+else */ {
+	if (window->priv->ask_to_open_destination_after_extraction)
+		open_progress_dialog_with_open_destination (window);
+	else
+		close_progress_dialog (window, FALSE);
+}
+
+
+#endif
+
+
+static void
+archive_add_ready_for_conversion_cb (GObject      *source_object,
+				     GAsyncResult *result,
+				     gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error = NULL;
+
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+
+	fr_window_stop_activity_mode (window);
+	fr_window_pop_message (window);
+	close_progress_dialog (window, FALSE);
+
+	if (error == NULL)
+		open_progress_dialog_with_open_archive (window);
+	else
+		_handle_archive_operation_error (window,
+						 window->priv->convert_data.new_archive,
+						 FR_ACTION_ADDING_FILES,
+						 error,
+						 NULL,
+						 NULL);
+
+	_g_path_remove_directory (window->priv->convert_data.temp_dir);
+	_fr_window_convert_data_free (window, FALSE);
+
+	fr_window_update_sensitivity (window);
+	fr_window_update_statusbar_list_info (window);
+}
+
+
+static void
+archive_extraction_ready_for_convertion_cb (GObject      *source_object,
+					    GAsyncResult *result,
+					    gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error = NULL;
+	char     *source_dir;
+
+	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
+		_g_path_remove_directory (window->priv->convert_data.temp_dir);
+		_fr_window_convert_data_free (window, TRUE);
+		_archive_operation_completed (window, FR_ACTION_EXTRACTING_FILES, error);
+		return;
+	}
+
+	source_dir = g_filename_to_uri (window->priv->convert_data.temp_dir, NULL, NULL);
+	fr_archive_add_with_wildcard (window->priv->convert_data.new_archive,
+				      "*",
+				      NULL,
+				      NULL,
+				      source_dir,
+				      NULL,
+				      FALSE,
+				      TRUE,
+				      window->priv->convert_data.password,
+				      window->priv->convert_data.encrypt_header,
+				      window->priv->compression,
+				      window->priv->convert_data.volume_size,
+				      window->priv->cancellable,
+				      archive_add_ready_for_conversion_cb,
+				      window);
+
+	g_free (source_dir);
+}
+
+
 void
 fr_window_archive_save_as (FrWindow   *window,
 			   const char *uri,
@@ -6083,17 +6410,22 @@ fr_window_archive_save_as (FrWindow   *window,
 			   gboolean    encrypt_header,
 			   guint       volume_size)
 {
+	GFile *file;
+
 	g_return_if_fail (window != NULL);
 	g_return_if_fail (uri != NULL);
 	g_return_if_fail (window->archive != NULL);
 
-	fr_window_convert_data_free (window, TRUE);
+	_fr_window_convert_data_free (window, TRUE);
 	window->priv->convert_data.new_file = g_strdup (uri);
 
 	/* create the new archive */
 
-	window->priv->convert_data.new_archive = fr_archive_new ();
-	if (! fr_archive_create (window->priv->convert_data.new_archive, uri)) {
+	file = g_file_new_for_uri (uri);
+	window->priv->convert_data.new_archive = fr_archive_create (file);
+	g_object_unref (file);
+
+	if (window->priv->convert_data.new_archive == NULL) {
 		GtkWidget *d;
 		char      *utf8_name;
 		char      *message;
@@ -6113,14 +6445,9 @@ fr_window_archive_save_as (FrWindow   *window,
 
 		g_free (message);
 
-		g_object_unref (window->priv->convert_data.new_archive);
-		window->priv->convert_data.new_archive = NULL;
-
 		return;
 	}
 
-	g_return_if_fail (window->priv->convert_data.new_archive->command != NULL);
-
 	if (password != NULL) {
 		window->priv->convert_data.password = g_strdup (password);
 		window->priv->convert_data.encrypt_header = encrypt_header;
@@ -6135,30 +6462,21 @@ fr_window_archive_save_as (FrWindow   *window,
 					    (GFreeFunc) save_as_data_free);
 
 	g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive),
-			  "start",
-			  G_CALLBACK (action_started),
-			  window);
-	g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive),
-			  "done",
-			  G_CALLBACK (convert__action_performed),
-			  window);
-	g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive),
 			  "progress",
-			  G_CALLBACK (fr_window_progress_cb),
+			  G_CALLBACK (fr_archive_progress_cb),
 			  window);
 	g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive),
 			  "message",
-			  G_CALLBACK (fr_window_message_cb),
+			  G_CALLBACK (fr_archive_message_cb),
 			  window);
 	g_signal_connect (G_OBJECT (window->priv->convert_data.new_archive),
 			  "stoppable",
-			  G_CALLBACK (fr_window_stoppable_cb),
+			  G_CALLBACK (fr_archive_stoppable_cb),
 			  window);
 
 	window->priv->convert_data.converting = TRUE;
 	window->priv->convert_data.temp_dir = _g_path_get_temp_work_dir (NULL);
 
-	fr_process_clear (window->archive->process);
 	fr_archive_extract_to_local (window->archive,
 				     NULL,
 				     window->priv->convert_data.temp_dir,
@@ -6166,8 +6484,10 @@ fr_window_archive_save_as (FrWindow   *window,
 				     TRUE,
 				     FALSE,
 				     FALSE,
-				     window->priv->password);
-	fr_process_start (window->archive->process);
+				     window->priv->password,
+				     window->priv->cancellable,
+				     archive_extraction_ready_for_convertion_cb,
+				     window);
 }
 
 
@@ -6180,14 +6500,31 @@ fr_window_archive_reload (FrWindow *window)
 		return;
 	if (window->priv->archive_new)
 		return;
+	if (window->archive == NULL)
+		return;
 
-	fr_archive_reload (window->archive, window->priv->password);
+	fr_window_archive_load (window);
 }
 
 
 /**/
 
 
+static void
+archive_add_files_ready_cb (GObject      *source_object,
+			    GAsyncResult *result,
+			    gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error = NULL;
+
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+	_archive_operation_completed (window, FR_ACTION_ADDING_FILES, error);
+
+	_g_error_free (error);
+}
+
+
 void
 fr_window_archive_add_files (FrWindow *window,
 			     GList    *file_list, /* GFile list */
@@ -6225,10 +6562,14 @@ fr_window_archive_add_files (FrWindow *window,
 			      base_uri,
 			      fr_window_get_current_location (window),
 			      update,
+			      FALSE,
 			      window->priv->password,
 			      window->priv->encrypt_header,
 			      window->priv->compression,
-			      window->priv->volume_size);
+			      window->priv->volume_size,
+			      window->priv->cancellable,
+			      archive_add_files_ready_cb,
+			      window);
 
 	g_free (base_uri);
 	_g_string_list_free (files);
@@ -6258,7 +6599,10 @@ fr_window_archive_add_with_wildcard (FrWindow      *window,
 				      window->priv->password,
 				      window->priv->encrypt_header,
 				      window->priv->compression,
-				      window->priv->volume_size);
+				      window->priv->volume_size,
+				      window->priv->cancellable,
+				      archive_add_files_ready_cb,
+				      window);
 }
 
 
@@ -6277,7 +6621,10 @@ fr_window_archive_add_directory (FrWindow      *window,
 				  window->priv->password,
 				  window->priv->encrypt_header,
 				  window->priv->compression,
-				  window->priv->volume_size);
+				  window->priv->volume_size,
+				  window->priv->cancellable,
+				  archive_add_files_ready_cb,
+				  window);
 }
 
 
@@ -6296,7 +6643,10 @@ fr_window_archive_add_items (FrWindow      *window,
 			      window->priv->password,
 			      window->priv->encrypt_header,
 			      window->priv->compression,
-			      window->priv->volume_size);
+			      window->priv->volume_size,
+			      window->priv->cancellable,
+			      archive_add_files_ready_cb,
+			      window);
 }
 
 
@@ -6313,7 +6663,25 @@ fr_window_archive_add_dropped_items (FrWindow *window,
 				      window->priv->password,
 				      window->priv->encrypt_header,
 				      window->priv->compression,
-				      window->priv->volume_size);
+				      window->priv->volume_size,
+				      window->priv->cancellable,
+				      archive_add_files_ready_cb,
+				      window);
+}
+
+
+static void
+archive_remove_ready_cb (GObject      *source_object,
+			 GAsyncResult *result,
+			 gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error = NULL;
+
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+	_archive_operation_completed (window, FR_ACTION_DELETING_FILES, error);
+
+	_g_error_free (error);
 }
 
 
@@ -6322,14 +6690,16 @@ fr_window_archive_remove (FrWindow *window,
 			  GList    *file_list)
 {
 	fr_window_clipboard_remove_file_list (window, file_list);
-
-	fr_process_clear (window->archive->process);
-	fr_archive_remove (window->archive, file_list, window->priv->compression);
-	fr_process_start (window->archive->process);
+	fr_archive_remove (window->archive,
+			   file_list,
+			   window->priv->compression,
+			   window->priv->cancellable,
+			   archive_remove_ready_cb,
+			   window);
 }
 
 
-/* -- window_archive_extract -- */
+/* -- fr_window_archive_extract -- */
 
 
 static ExtractData*
@@ -6387,95 +6757,6 @@ extract_data_free (ExtractData *edata)
 }
 
 
-static gboolean
-archive_is_encrypted (FrWindow *window,
-		      GList    *file_list)
-{
-	gboolean encrypted = FALSE;
-
-	if (file_list == NULL) {
-		int i;
-
-		for (i = 0; ! encrypted && i < window->archive->command->files->len; i++) {
-			FileData *fdata = g_ptr_array_index (window->archive->command->files, i);
-
-			if (fdata->encrypted)
-				encrypted = TRUE;
-		}
-	}
-	else {
-
-		GHashTable *file_hash;
-		int         i;
-		GList      *scan;
-
-		file_hash = g_hash_table_new (g_str_hash, g_str_equal);
-		for (i = 0; i < window->archive->command->files->len; i++) {
-			FileData *fdata = g_ptr_array_index (window->archive->command->files, i);
-			g_hash_table_insert (file_hash, fdata->original_path, fdata);
-		}
-
-		for (scan = file_list; ! encrypted && scan; scan = scan->next) {
-			char     *filename = scan->data;
-			FileData *fdata;
-
-			fdata = g_hash_table_lookup (file_hash, filename);
-			g_return_val_if_fail (fdata != NULL, FALSE);
-
-			if (fdata->encrypted)
-				encrypted = TRUE;
-		}
-
-		g_hash_table_destroy (file_hash);
-	}
-
-	return encrypted;
-}
-
-
-void
-fr_window_archive_extract_here (FrWindow   *window,
-				gboolean    skip_older,
-				gboolean    overwrite,
-				gboolean    junk_paths)
-{
-	ExtractData *edata;
-
-	edata = extract_data_new (NULL,
-				  NULL,
-				  NULL,
-				  skip_older,
-				  overwrite,
-				  junk_paths,
-				  TRUE,
-				  FALSE);
-	fr_window_set_current_batch_action (window,
-					    FR_BATCH_ACTION_EXTRACT,
-					    edata,
-					    (GFreeFunc) extract_data_free);
-
-	if (archive_is_encrypted (window, NULL) && (window->priv->password == NULL)) {
-		dlg_ask_password (window);
-		return;
-	}
-
-	window->priv->ask_to_open_destination_after_extraction = edata->ask_to_open_destination;
-
-	fr_process_clear (window->archive->process);
-	if (fr_archive_extract_here (window->archive,
-				     edata->skip_older,
-				     edata->overwrite,
-				     edata->junk_paths,
-				     window->priv->password))
-	{
-		fr_process_start (window->archive->process);
-	}
-}
-
-
-/* -- fr_window_archive_extract -- */
-
-
 typedef struct {
 	FrWindow    *window;
 	ExtractData *edata;
@@ -6489,12 +6770,26 @@ typedef struct {
 
 
 static void
+archive_extraction_ready_cb (GObject      *source_object,
+			     GAsyncResult *result,
+			     gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error = NULL;
+
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+	_archive_operation_completed (window, FR_ACTION_EXTRACTING_FILES, error);
+
+	_g_error_free (error);
+}
+
+
+static void
 _fr_window_archive_extract_from_edata (FrWindow    *window,
 				       ExtractData *edata)
 {
 	window->priv->ask_to_open_destination_after_extraction = edata->ask_to_open_destination;
 
-	fr_process_clear (window->archive->process);
 	fr_archive_extract (window->archive,
 			    edata->file_list,
 			    edata->extract_to_dir,
@@ -6502,8 +6797,10 @@ _fr_window_archive_extract_from_edata (FrWindow    *window,
 			    edata->skip_older,
 			    edata->overwrite == FR_OVERWRITE_YES,
 			    edata->junk_paths,
-			    window->priv->password);
-	fr_process_start (window->archive->process);
+			    window->priv->password,
+			    window->priv->cancellable,
+			    archive_extraction_ready_cb,
+			    window);
 }
 
 
@@ -6622,22 +6919,68 @@ _fr_window_ask_overwrite_dialog (OverwriteData *odata)
 			g_object_unref (info);
 			g_object_unref (file);
 
-			return;
+			return;
+		}
+
+		g_object_unref (info);
+		g_object_unref (file);
+	}
+
+	if (do_not_extract) {
+		fr_window_stop_batch (odata->window);
+		g_free (odata);
+		return;
+	}
+
+	odata->edata->overwrite = FR_OVERWRITE_YES;
+	_fr_window_archive_extract_from_edata (odata->window, odata->edata);
+	g_free (odata);
+}
+
+
+static gboolean
+archive_is_encrypted (FrWindow *window,
+		      GList    *file_list)
+{
+	gboolean encrypted = FALSE;
+
+	if (file_list == NULL) {
+		int i;
+
+		for (i = 0; ! encrypted && i < window->archive->files->len; i++) {
+			FileData *fdata = g_ptr_array_index (window->archive->files, i);
+
+			if (fdata->encrypted)
+				encrypted = TRUE;
+		}
+	}
+	else {
+
+		GHashTable *file_hash;
+		int         i;
+		GList      *scan;
+
+		file_hash = g_hash_table_new (g_str_hash, g_str_equal);
+		for (i = 0; i < window->archive->files->len; i++) {
+			FileData *fdata = g_ptr_array_index (window->archive->files, i);
+			g_hash_table_insert (file_hash, fdata->original_path, fdata);
 		}
 
-		g_object_unref (info);
-		g_object_unref (file);
-	}
+		for (scan = file_list; ! encrypted && scan; scan = scan->next) {
+			char     *filename = scan->data;
+			FileData *fdata;
 
-	if (do_not_extract) {
-		fr_window_stop_batch (odata->window);
-		g_free (odata);
-		return;
+			fdata = g_hash_table_lookup (file_hash, filename);
+			g_return_val_if_fail (fdata != NULL, FALSE);
+
+			if (fdata->encrypted)
+				encrypted = TRUE;
+		}
+
+		g_hash_table_destroy (file_hash);
 	}
 
-	odata->edata->overwrite = FR_OVERWRITE_YES;
-	_fr_window_archive_extract_from_edata (odata->window, odata->edata);
-	g_free (odata);
+	return encrypted;
 }
 
 
@@ -6761,6 +7104,66 @@ fr_window_archive_extract (FrWindow    *window,
 }
 
 
+/* -- fr_window_archive_extract_here -- */
+
+
+void
+fr_window_archive_extract_here (FrWindow   *window,
+				gboolean    skip_older,
+				gboolean    overwrite,
+				gboolean    junk_paths)
+{
+	ExtractData *edata;
+
+	edata = extract_data_new (NULL,
+				  NULL,
+				  NULL,
+				  skip_older,
+				  overwrite,
+				  junk_paths,
+				  TRUE,
+				  FALSE);
+	fr_window_set_current_batch_action (window,
+					    FR_BATCH_ACTION_EXTRACT,
+					    edata,
+					    (GFreeFunc) extract_data_free);
+
+	if (archive_is_encrypted (window, NULL) && (window->priv->password == NULL)) {
+		dlg_ask_password (window);
+		return;
+	}
+
+	window->priv->ask_to_open_destination_after_extraction = edata->ask_to_open_destination;
+
+	fr_archive_extract_here (window->archive,
+				 edata->skip_older,
+				 edata->overwrite,
+				 edata->junk_paths,
+				 window->priv->password,
+				 window->priv->cancellable,
+				 archive_extraction_ready_cb,
+				 window);
+}
+
+
+/* -- fr_window_archive_test -- */
+
+
+static void
+archive_test_ready_cb (GObject      *source_object,
+		       GAsyncResult *result,
+		       gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error = NULL;
+
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+	_archive_operation_completed (window, FR_ACTION_TESTING_ARCHIVE, error);
+
+	_g_error_free (error);
+}
+
+
 void
 fr_window_archive_test (FrWindow *window)
 {
@@ -6768,7 +7171,11 @@ fr_window_archive_test (FrWindow *window)
 					    FR_BATCH_ACTION_TEST,
 					    NULL,
 					    NULL);
-	fr_archive_test (window->archive, window->priv->password);
+	fr_archive_test (window->archive,
+			 window->priv->password,
+			 window->priv->cancellable,
+			 archive_test_ready_cb,
+			 window);
 }
 
 
@@ -7020,11 +7427,15 @@ fr_window_stop (FrWindow *window)
 	if (! window->priv->stoppable)
 		return;
 
+	g_cancellable_cancel (window->priv->cancellable);
+
+	/* FIXME: libarchive
 	if (window->priv->activity_ref > 0)
 		fr_archive_stop (window->archive);
 
 	if (window->priv->convert_data.converting)
-		fr_window_convert_data_free (window, TRUE);
+		_fr_window_convert_data_free (window, TRUE);
+	*/
 }
 
 
@@ -7173,7 +7584,10 @@ fr_window_view_last_output (FrWindow   *window,
 	/**/
 
 	gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 0);
-	scan = window->archive->process->out.raw;
+	if (FR_IS_COMMAND (window->archive))
+		scan = fr_command_get_last_output (FR_COMMAND (window->archive));
+	else
+		scan = NULL;
 	for (; scan; scan = scan->next) {
 		char        *line = scan->data;
 		char        *utf8_line;
@@ -7252,6 +7666,21 @@ rename_data_free (RenameData *rdata)
 
 
 static void
+archive_rename_ready_cb (GObject      *source_object,
+			 GAsyncResult *result,
+			 gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error = NULL;
+
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+	_archive_operation_completed (window, FR_ACTION_ADDING_FILES /* FIXME: FR_ACTION_RENAME_FILES ? */, error);
+
+	_g_error_free (error);
+}
+
+
+static void
 rename_selection (FrWindow   *window,
 		  const char *path_to_rename,
 		  const char *old_name,
@@ -7261,14 +7690,8 @@ rename_selection (FrWindow   *window,
 		  gboolean    dir_in_archive,
 		  const char *original_path)
 {
-	FrArchive  *archive = window->archive;
 	RenameData *rdata;
-	char       *tmp_dir;
 	GList      *file_list;
-	gboolean    added_dir;
-	char       *new_dirname;
-	GList      *new_file_list;
-	GList      *scan;
 
 	rdata = rename_data_new (path_to_rename,
 				 old_name,
@@ -7282,128 +7705,31 @@ rename_selection (FrWindow   *window,
 					    rdata,
 					    (GFreeFunc) rename_data_free);
 
-	fr_process_clear (archive->process);
-
-	tmp_dir = _g_path_get_temp_work_dir (NULL);
+	g_object_set (window->archive,
+		      "compression", window->priv->compression,
+		      "encrypt_header", window->priv->encrypt_header,
+		      "password", window->priv->password,
+		      "volume_size", window->priv->volume_size,
+		      NULL);
 
 	if (is_dir)
 		file_list = get_dir_list_from_path (window, rdata->path_to_rename);
 	else
 		file_list = g_list_append (NULL, g_strdup (rdata->path_to_rename));
-
-	fr_archive_extract_to_local (archive,
-				     file_list,
-				     tmp_dir,
-				     NULL,
-				     FALSE,
-				     TRUE,
-				     FALSE,
-				     window->priv->password);
-
-	/* temporarily add the dir to rename to the list if it's stored in the
-	 * archive, this way it will be removed from the archive... */
-	added_dir = FALSE;
-	if (is_dir && dir_in_archive && ! g_list_find_custom (file_list, original_path, (GCompareFunc) strcmp)) {
-		file_list = g_list_prepend (file_list, g_strdup (original_path));
-		added_dir = TRUE;
-	}
-
-	fr_archive_remove (archive, file_list, window->priv->compression);
 	fr_window_clipboard_remove_file_list (window, file_list);
+	fr_archive_rename (window->archive,
+			   file_list,
+			   old_name,
+			   new_name,
+			   current_dir,
+			   is_dir,
+			   dir_in_archive,
+			   original_path,
+			   window->priv->cancellable,
+			   archive_rename_ready_cb,
+			   window);
 
-	/* ...and remove it from the list again */
-	if (added_dir) {
-		GList *tmp;
-
-		tmp = file_list;
-		file_list = g_list_remove_link (file_list, tmp);
-
-		g_free (tmp->data);
-		g_list_free (tmp);
-	}
-
-	/* rename the files. */
-
-	new_dirname = g_build_filename (rdata->current_dir + 1, rdata->new_name, "/", NULL);
-	new_file_list = NULL;
-	if (rdata->is_dir) {
-		char *old_path;
-		char *new_path;
-
-		old_path = g_build_filename (tmp_dir, rdata->current_dir, rdata->old_name, NULL);
-		new_path = g_build_filename (tmp_dir, rdata->current_dir, rdata->new_name, NULL);
-
-		fr_process_begin_command (archive->process, "mv");
-		fr_process_add_arg (archive->process, "-f");
-		fr_process_add_arg (archive->process, old_path);
-		fr_process_add_arg (archive->process, new_path);
-		fr_process_end_command (archive->process);
-
-		g_free (old_path);
-		g_free (new_path);
-	}
-
-	for (scan = file_list; scan; scan = scan->next) {
-		const char *current_dir_relative = rdata->current_dir + 1;
-		const char *filename = (char*) scan->data;
-		char       *old_path = NULL, *common = NULL, *new_path = NULL;
-		char       *new_filename;
-
-		old_path = g_build_filename (tmp_dir, filename, NULL);
-
-		if (strlen (filename) > (strlen (rdata->current_dir) + strlen (rdata->old_name)))
-			common = g_strdup (filename + strlen (rdata->current_dir) + strlen (rdata->old_name));
-		new_path = g_build_filename (tmp_dir, rdata->current_dir, rdata->new_name, common, NULL);
-
-		if (! rdata->is_dir) {
-			fr_process_begin_command (archive->process, "mv");
-			fr_process_add_arg (archive->process, "-f");
-			fr_process_add_arg (archive->process, old_path);
-			fr_process_add_arg (archive->process, new_path);
-			fr_process_end_command (archive->process);
-		}
-
-		new_filename = g_build_filename (current_dir_relative, rdata->new_name, common, NULL);
-		new_file_list = g_list_prepend (new_file_list, new_filename);
-
-		g_free (old_path);
-		g_free (common);
-		g_free (new_path);
-	}
-	new_file_list = g_list_reverse (new_file_list);
-
-	/* FIXME: this is broken for tar archives.
-	if (is_dir && dir_in_archive && ! g_list_find_custom (new_file_list, new_dirname, (GCompareFunc) strcmp))
-		new_file_list = g_list_prepend (new_file_list, g_build_filename (rdata->current_dir + 1, rdata->new_name, NULL));
-	*/
-
-	fr_archive_add (archive,
-			new_file_list,
-			tmp_dir,
-			NULL,
-			FALSE,
-			FALSE,
-			window->priv->password,
-			window->priv->encrypt_header,
-			window->priv->compression,
-			window->priv->volume_size);
-
-	g_free (new_dirname);
-	_g_string_list_free (new_file_list);
 	_g_string_list_free (file_list);
-
-	/* remove the tmp dir */
-
-	fr_process_begin_command (archive->process, "rm");
-	fr_process_set_working_dir (archive->process, g_get_tmp_dir ());
-	fr_process_set_sticky (archive->process, TRUE);
-	fr_process_add_arg (archive->process, "-rf");
-	fr_process_add_arg (archive->process, tmp_dir);
-	fr_process_end_command (archive->process);
-
-	fr_process_start (archive->process);
-
-	g_free (tmp_dir);
 }
 
 
@@ -7456,8 +7782,8 @@ name_is_present (FrWindow    *window,
 	new_filename = g_build_filename (current_dir, new_name, NULL);
 	new_filename_l = strlen (new_filename);
 
-	for (i = 0; i < window->archive->command->files->len; i++) {
-		FileData   *fdata = g_ptr_array_index (window->archive->command->files, i);
+	for (i = 0; i < window->archive->files->len; i++) {
+		FileData   *fdata = g_ptr_array_index (window->archive->files, i);
 		const char *filename = fdata->full_path;
 
 		if ((strncmp (filename, new_filename, new_filename_l) == 0)
@@ -7609,6 +7935,9 @@ fr_window_rename_selection (FrWindow *window,
 }
 
 
+/* -- fr_window_paste_selection -- */
+
+
 static void
 fr_clipboard_get (GtkClipboard     *clipboard,
 		  GtkSelectionData *selection_data,
@@ -7684,7 +8013,7 @@ fr_window_get_selection (FrWindow   *window,
 
 static void
 fr_window_copy_or_cut_selection (FrWindow      *window,
-				 FRClipboardOp  op,
+				 FrClipboardOp  op,
 			  	 gboolean       from_sidebar)
 {
 	GList        *files;
@@ -7728,138 +8057,169 @@ fr_window_cut_selection (FrWindow *window,
 }
 
 
-static gboolean
-always_fake_load (FrArchive *archive,
-		  gpointer   data)
-{
-	return TRUE;
-}
+/* -- fr_window_paste_from_clipboard_data -- */
 
 
 static void
-add_pasted_files (FrWindow        *window,
-		  FrClipboardData *data)
+_paste_from_archive_operation_completed (FrWindow *window,
+					 FrAction  action,
+					 GError   *error)
 {
-	const char *current_dir_relative = data->current_dir + 1;
-	GList      *scan;
-	GList      *new_file_list = NULL;
-
-	if (window->priv->password_for_paste != NULL) {
-		g_free (window->priv->password_for_paste);
-		window->priv->password_for_paste = NULL;
-	}
+#ifdef DEBUG
+	debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
+#endif
 
-	fr_process_clear (window->archive->process);
-	for (scan = data->files; scan; scan = scan->next) {
-		const char *old_name = (char*) scan->data;
-		char       *new_name = g_build_filename (current_dir_relative, old_name + strlen (data->base_dir) - 1, NULL);
+	fr_window_stop_activity_mode (window);
+	fr_window_pop_message (window);
+	close_progress_dialog (window, FALSE);
 
-		/* skip folders */
+	if (error->code == FR_ERROR_ASK_PASSWORD) {
+		dlg_ask_password_for_paste_operation (window);
+		return;
+	}
 
-		if ((strcmp (old_name, new_name) != 0)
-		    && (old_name[strlen (old_name) - 1] != '/'))
-		{
-			fr_process_begin_command (window->archive->process, "mv");
-			fr_process_set_working_dir (window->archive->process, data->tmp_dir);
-			fr_process_add_arg (window->archive->process, "-f");
-			if (old_name[0] == '/')
-				old_name = old_name + 1;
-			fr_process_add_arg (window->archive->process, old_name);
-			fr_process_add_arg (window->archive->process, new_name);
-			fr_process_end_command (window->archive->process);
-		}
+	/* FIXME: do not use this function !! */
+	_archive_operation_completed (window, FR_ACTION_EXTRACTING_FILES, error);
 
-		new_file_list = g_list_prepend (new_file_list, new_name);
+	if (error->code != FR_ERROR_NONE) {
+		fr_clipboard_data_unref (window->priv->clipboard_data);
+		window->priv->clipboard_data = NULL;
 	}
+}
 
-	fr_archive_add (window->archive,
-			new_file_list,
-			data->tmp_dir,
-			NULL,
-			FALSE,
-			FALSE,
-			window->priv->password,
-			window->priv->encrypt_header,
-			window->priv->compression,
-			window->priv->volume_size);
 
-	_g_string_list_free (new_file_list);
+static void
+paste_from_archive_paste_clipboard_ready_cb (GObject      *source_object,
+					     GAsyncResult *result,
+					     gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error;
 
-	/* remove the tmp dir */
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+	_paste_from_archive_operation_completed (window, FR_ACTION_ADDING_FILES, error);
 
-	fr_process_begin_command (window->archive->process, "rm");
-	fr_process_set_working_dir (window->archive->process, g_get_tmp_dir ());
-	fr_process_set_sticky (window->archive->process, TRUE);
-	fr_process_add_arg (window->archive->process, "-rf");
-	fr_process_add_arg (window->archive->process, data->tmp_dir);
-	fr_process_end_command (window->archive->process);
+	fr_clipboard_data_unref (window->priv->clipboard_data);
+	window->priv->clipboard_data = NULL;
 
-	fr_process_start (window->archive->process);
+	_g_error_free (error);
 }
 
 
 static void
-copy_from_archive_action_performed_cb (FrArchive   *archive,
-				       FrAction     action,
-				       FrProcError *error,
-				       gpointer     data)
+add_pasted_files (FrWindow        *window,
+		  FrClipboardData *data)
 {
-	FrWindow *window = data;
+	if (window->priv->password_for_paste != NULL) {
+		g_free (window->priv->password_for_paste);
+		window->priv->password_for_paste = NULL;
+	}
 
-#ifdef DEBUG
-	debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
-#endif
+	fr_archive_paste_clipboard (window->archive,
+				    data->archive_uri,
+				    data->archive_password,
+				    window->priv->encrypt_header,
+				    window->priv->compression,
+				    window->priv->volume_size,
+				    data->op,
+				    data->base_dir,
+				    data->files,
+				    data->tmp_dir,
+				    data->current_dir,
+				    window->priv->cancellable,
+				    paste_from_archive_paste_clipboard_ready_cb,
+				    window);
+}
 
-	fr_window_stop_activity_mode (window);
-	fr_window_pop_message (window);
-	close_progress_dialog (window, FALSE);
 
-	if (error->type == FR_PROC_ERROR_ASK_PASSWORD) {
-		dlg_ask_password_for_paste_operation (window);
+static void
+paste_from_archive_remove_ready_cb (GObject      *source_object,
+				    GAsyncResult *result,
+				    gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error;
+
+	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
+		_paste_from_archive_operation_completed (window, FR_ACTION_DELETING_FILES, error);
+		g_error_free (error);
 		return;
 	}
 
-	(void) handle_errors (window, archive, action, error);
+	add_pasted_files (window, window->priv->clipboard_data);
+}
+
 
-	if (error->type != FR_PROC_ERROR_NONE) {
-		fr_clipboard_data_unref (window->priv->clipboard_data);
-		window->priv->clipboard_data = NULL;
+static void
+paste_from_archive_extract_ready_cb (GObject      *source_object,
+				     GAsyncResult *result,
+				     gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error;
+
+	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
+		_paste_from_archive_operation_completed (window, FR_ACTION_EXTRACTING_FILES, error);
+		g_error_free (error);
 		return;
 	}
 
-	switch (action) {
-	case FR_ACTION_LISTING_CONTENT:
-		fr_process_clear (window->priv->copy_from_archive->process);
-		fr_archive_extract_to_local (window->priv->copy_from_archive,
-					     window->priv->clipboard_data->files,
-					     window->priv->clipboard_data->tmp_dir,
-					     NULL,
-					     FALSE,
-					     TRUE,
-					     FALSE,
-					     window->priv->clipboard_data->archive_password);
-		fr_process_start (window->priv->copy_from_archive->process);
-		break;
+	if (window->priv->clipboard_data->op == FR_CLIPBOARD_OP_CUT)
+		fr_archive_remove (window->priv->copy_from_archive,
+				   window->priv->clipboard_data->files,
+				   window->priv->compression,
+				   window->priv->cancellable,
+				   paste_from_archive_remove_ready_cb,
+				   window);
+	else
+		add_pasted_files (window, window->priv->clipboard_data);
+}
 
-	case FR_ACTION_EXTRACTING_FILES:
-		if (window->priv->clipboard_data->op == FR_CLIPBOARD_OP_CUT) {
-			fr_process_clear (window->priv->copy_from_archive->process);
-			fr_archive_remove (window->priv->copy_from_archive,
-					   window->priv->clipboard_data->files,
-					   window->priv->compression);
-			fr_process_start (window->priv->copy_from_archive->process);
-		}
-		else
-			add_pasted_files (window, window->priv->clipboard_data);
-		break;
 
-	case FR_ACTION_DELETING_FILES:
-		add_pasted_files (window, window->priv->clipboard_data);
-		break;
+static void
+paste_from_archive_open_cb (GObject      *source_object,
+			    GAsyncResult *result,
+			    gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error;
 
-	default:
-		break;
+	_g_object_unref (window->priv->copy_from_archive);
+	window->priv->copy_from_archive = fr_archive_open_finish (G_FILE (source_object), result, &error);
+	if (window->priv->copy_from_archive == NULL) {
+		_paste_from_archive_operation_completed (window, FR_ACTION_LOADING_ARCHIVE, error);
+		g_error_free (error);
+		return;
 	}
+
+	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
+			  "start",
+			  G_CALLBACK (action_started),
+			  window);
+	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
+			  "progress",
+			  G_CALLBACK (fr_archive_progress_cb),
+			  window);
+	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
+			  "message",
+			  G_CALLBACK (fr_archive_message_cb),
+			  window);
+	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
+			  "stoppable",
+			  G_CALLBACK (fr_archive_stoppable_cb),
+			  window);
+
+	fr_archive_extract_to_local (window->priv->copy_from_archive,
+				     window->priv->clipboard_data->files,
+				     window->priv->clipboard_data->tmp_dir,
+				     NULL,
+				     FALSE,
+				     TRUE,
+				     FALSE,
+				     window->priv->clipboard_data->archive_password,
+				     window->priv->cancellable,
+				     paste_from_archive_extract_ready_cb,
+				     window);
 }
 
 
@@ -7870,6 +8230,7 @@ fr_window_paste_from_clipboard_data (FrWindow        *window,
 	const char *current_dir_relative;
 	GHashTable *created_dirs;
 	GList      *scan;
+	GFile      *file;
 
 	if (window->priv->password_for_paste != NULL)
 		fr_clipboard_data_set_password (data, window->priv->password_for_paste);
@@ -7911,33 +8272,13 @@ fr_window_paste_from_clipboard_data (FrWindow        *window,
 
 	/**/
 
-	if (window->priv->copy_from_archive == NULL) {
-		window->priv->copy_from_archive = fr_archive_new ();
-		g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
-				  "start",
-				  G_CALLBACK (action_started),
-				  window);
-		g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
-				  "done",
-				  G_CALLBACK (copy_from_archive_action_performed_cb),
-				  window);
-		g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
-				  "progress",
-				  G_CALLBACK (fr_window_progress_cb),
-				  window);
-		g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
-				  "message",
-				  G_CALLBACK (fr_window_message_cb),
-				  window);
-		g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
-				  "stoppable",
-				  G_CALLBACK (fr_window_stoppable_cb),
-				  window);
-		fr_archive_set_fake_load_func (window->priv->copy_from_archive, always_fake_load, NULL);
-	}
-	fr_archive_load (window->priv->copy_from_archive,
-			 data->archive_uri,
-			 data->archive_password);
+	file = g_file_new_for_uri (data->archive_uri);
+	fr_archive_open (file,
+			 window->priv->cancellable,
+			 paste_from_archive_open_cb,
+			 window);
+
+	g_object_unref (file);
 }
 
 
@@ -8114,6 +8455,9 @@ open_files_data_free (OpenFilesData *odata)
 }
 
 
+/* -- -- */
+
+
 void
 fr_window_update_dialog_closed (FrWindow *window)
 {
@@ -8121,10 +8465,32 @@ fr_window_update_dialog_closed (FrWindow *window)
 }
 
 
+static void
+update_files_ready_cb (GObject      *source_object,
+		       GAsyncResult *result,
+		       gpointer      user_data)
+{
+	FrWindow *window = user_data;
+	GError   *error;
+
+	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
+
+	fr_window_stop_activity_mode (window);
+	fr_window_pop_message (window);
+
+	/* FIXME: do not use this function !!! */
+	_handle_archive_operation_error (window, window->archive, FR_ACTION_ADDING_FILES, error, NULL, NULL);
+
+	_g_error_free (error);
+}
+
+
 gboolean
 fr_window_update_files (FrWindow *window,
-			GList    *file_list)
+			GList    *open_file_list)
 {
+	GList *file_list;
+	GList *dir_list;
 	GList *scan;
 
 	if (window->priv->activity_ref > 0)
@@ -8133,27 +8499,25 @@ fr_window_update_files (FrWindow *window,
 	if (window->archive->read_only)
 		return FALSE;
 
-	fr_process_clear (window->archive->process);
+	file_list = NULL;
+	dir_list = NULL;
+	for (scan = open_file_list; scan; scan = scan->next) {
+		OpenFile *open_file = scan->data;
 
-	for (scan = file_list; scan; scan = scan->next) {
-		OpenFile *file = scan->data;
-		GList    *local_file_list;
-
-		local_file_list = g_list_append (NULL, file->path);
-		fr_archive_add (window->archive,
-				local_file_list,
-				file->temp_dir,
-				"/",
-				FALSE,
-				FALSE,
-				window->priv->password,
-				window->priv->encrypt_header,
-				window->priv->compression,
-				window->priv->volume_size);
-		g_list_free (local_file_list);
+		file_list = g_list_prepend (file_list, open_file->path);
+		dir_list = g_list_prepend (dir_list, open_file->temp_dir);
 	}
 
-	fr_process_start (window->archive->process);
+	fr_archive_update_open_files (window->archive,
+				      file_list,
+				      dir_list,
+				      window->priv->password,
+				      window->priv->encrypt_header,
+				      window->priv->compression,
+				      window->priv->volume_size,
+				      window->priv->cancellable,
+				      update_files_ready_cb,
+				      window);
 
 	return TRUE;
 }
@@ -8316,22 +8680,20 @@ fr_window_open_extracted_files (OpenFilesData *odata)
 
 
 static void
-fr_window_open_files__extract_done_cb (FrArchive   *archive,
-				       FrAction     action,
-				       FrProcError *error,
-				       gpointer     callback_data)
+open_files_extract_ready_cb (GObject      *source_object,
+			     GAsyncResult *result,
+			     gpointer      user_data)
 {
-	OpenFilesData *odata = callback_data;
+	OpenFilesData *odata = user_data;
+	GError        *error;
 
-	g_signal_handlers_disconnect_matched (G_OBJECT (archive),
-					      G_SIGNAL_MATCH_DATA,
-					      0,
-					      0, NULL,
-					      0,
-					      odata);
+	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
+		/* FIXME: do not use this function!!! */
+		_archive_operation_completed (odata->window, FR_ACTION_EXTRACTING_FILES, error);
+		g_error_free (error);
+	}
 
-	if (error->type == FR_PROC_ERROR_NONE)
-		fr_window_open_extracted_files (odata);
+	fr_window_open_extracted_files (odata);
 }
 
 
@@ -8351,12 +8713,6 @@ fr_window_open_files (FrWindow *window,
 					    odata,
 					    (GFreeFunc) open_files_data_free);
 
-	g_signal_connect (G_OBJECT (window->archive),
-			  "done",
-			  G_CALLBACK (fr_window_open_files__extract_done_cb),
-			  odata);
-
-	fr_process_clear (window->archive->process);
 	fr_archive_extract_to_local (window->archive,
 				     odata->file_list,
 				     odata->cdata->temp_dir,
@@ -8364,8 +8720,10 @@ fr_window_open_files (FrWindow *window,
 				     FALSE,
 				     TRUE,
 				     FALSE,
-				     window->priv->password);
-	fr_process_start (window->archive->process);
+				     window->priv->password,
+				     window->priv->cancellable,
+				     open_files_extract_ready_cb,
+				     odata);
 }
 
 
@@ -8702,29 +9060,30 @@ fr_window_exec_batch_action (FrWindow      *window,
 void
 fr_window_reset_current_batch_action (FrWindow *window)
 {
-	FRBatchAction *adata = &window->priv->current_batch_action;
+	FRBatchAction *action = &window->priv->current_batch_action;
 
-	if ((adata->data != NULL) && (adata->free_func != NULL))
-		(*adata->free_func) (adata->data);
-	adata->type = FR_BATCH_ACTION_NONE;
-	adata->data = NULL;
-	adata->free_func = NULL;
+	if ((action->data != NULL) && (action->free_func != NULL))
+		(*action->free_func) (action->data);
+	action->type = FR_BATCH_ACTION_NONE;
+	action->data = NULL;
+	action->free_func = NULL;
 }
 
 
 void
 fr_window_set_current_batch_action (FrWindow          *window,
-				    FrBatchActionType  action,
+				    FrBatchActionType  action_type,
 				    void              *data,
 				    GFreeFunc          free_func)
 {
-	FRBatchAction *adata = &window->priv->current_batch_action;
+	FRBatchAction *action;
 
 	fr_window_reset_current_batch_action (window);
 
-	adata->type = action;
-	adata->data = data;
-	adata->free_func = free_func;
+	action = &window->priv->current_batch_action;
+	action->type = action_type;
+	action->data = data;
+	action->free_func = free_func;
 }
 
 
@@ -8796,7 +9155,6 @@ fr_window_start_batch (FrWindow *window)
 
 	window->priv->batch_mode = TRUE;
 	window->priv->batch_action = window->priv->batch_action_list;
-	window->archive->can_create_compressed_file = window->priv->batch_adding_one_file;
 
 	fr_window_exec_current_batch_action (window);
 }
@@ -8809,7 +9167,6 @@ fr_window_stop_batch (FrWindow *window)
 		return;
 
 	window->priv->extract_interact_use_default_dir = FALSE;
-	window->archive->can_create_compressed_file = FALSE;
 
 	if (window->priv->batch_mode) {
 		if (! window->priv->showing_error_dialog) {
diff --git a/src/fr-window.h b/src/fr-window.h
index 13a4ad5..723ce29 100644
--- a/src/fr-window.h
+++ b/src/fr-window.h
@@ -75,15 +75,15 @@ typedef enum {
 #define FR_IS_WINDOW_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), FR_TYPE_WINDOW))
 #define FR_WINDOW_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS((obj), FR_TYPE_WINDOW, FrWindowClass))
 
-typedef struct _FrWindow            FrWindow;
-typedef struct _FrWindowClass       FrWindowClass;
-typedef struct _FrWindowPrivateData FrWindowPrivateData;
+typedef struct _FrWindow        FrWindow;
+typedef struct _FrWindowClass   FrWindowClass;
+typedef struct _FrWindowPrivate FrWindowPrivate;
 
 struct _FrWindow
 {
 	GtkApplicationWindow __parent;
+	FrWindowPrivate *priv;
 	FrArchive *archive;
-	FrWindowPrivateData *priv;
 };
 
 struct _FrWindowClass
@@ -101,221 +101,220 @@ struct _FrWindowClass
 				GError     *error);
 };
 
-GType       fr_window_get_type                  (void);
-GtkWidget * fr_window_new                       (void);
-void        fr_window_close                     (FrWindow      *window);
+GType           fr_window_get_type                     (void);
+GtkWidget *     fr_window_new                          (void);
+void            fr_window_close                        (FrWindow      *window);
 
 /* archive operations */
 
-gboolean    fr_window_archive_new               (FrWindow      *window,
-						 const char    *uri);
-FrWindow *  fr_window_archive_open              (FrWindow      *window,
-						 const char    *uri,
-						 GtkWindow     *parent);
-void        fr_window_archive_close             (FrWindow      *window);
-const char *fr_window_get_archive_uri           (FrWindow      *window);
-const char *fr_window_get_paste_archive_uri     (FrWindow      *window);
-gboolean    fr_window_archive_is_present        (FrWindow      *window);
-void        fr_window_archive_save_as           (FrWindow      *window,
-						 const char    *filename,
-						 const char    *password,
-						 gboolean       encrypt_header,
-						 guint          volume_size);
-void        fr_window_archive_reload            (FrWindow      *window);
-void        fr_window_archive_add_files         (FrWindow      *window,
-						 GList         *file_list, /* GFile list */
-						 gboolean       update);
-void        fr_window_archive_add_with_wildcard (FrWindow      *window,
-						 const char    *include_files,
-						 const char    *exclude_files,
-						 const char    *exclude_folders,
-						 const char    *base_dir,
-						 const char    *dest_dir,
-						 gboolean       update,
-						 gboolean       follow_links);
-void        fr_window_archive_add_directory     (FrWindow      *window,
-						 const char    *directory,
-						 const char    *base_dir,
-						 const char    *dest_dir,
-						 gboolean       update);
-void        fr_window_archive_add_items         (FrWindow      *window,
-						 GList         *dir_list,
-						 const char    *base_dir,
-						 const char    *dest_dir,
-						 gboolean       update);
-void        fr_window_archive_add_dropped_items (FrWindow      *window,
-						 GList         *item_list,
-						 gboolean       update);
-void        fr_window_archive_remove            (FrWindow      *window,
-						 GList         *file_list);
-void        fr_window_archive_extract           (FrWindow      *window,
-						 GList         *file_list,
-						 const char    *extract_to_dir,
-						 const char    *base_dir,
-						 gboolean       skip_older,
-						 FrOverwrite    overwrite,
-						 gboolean       junk_paths,
-						 gboolean       ask_to_open_destination);
-void        fr_window_archive_extract_here      (FrWindow      *window,
-						 gboolean       skip_older,
-						 gboolean       overwrite,
-						 gboolean       junk_paths);
-void        fr_window_archive_test	        (FrWindow      *window);
+gboolean        fr_window_archive_new                  (FrWindow      *window,
+						        const char    *uri);
+FrWindow *      fr_window_archive_open                 (FrWindow      *window,
+						        const char    *uri,
+						        GtkWindow     *parent);
+void            fr_window_archive_close                (FrWindow      *window);
+const char *    fr_window_get_archive_uri              (FrWindow      *window);
+const char *    fr_window_get_paste_archive_uri        (FrWindow      *window);
+gboolean        fr_window_archive_is_present           (FrWindow      *window);
+void            fr_window_archive_save_as              (FrWindow      *window,
+						        const char    *filename,
+						        const char    *password,
+						        gboolean       encrypt_header,
+						        guint          volume_size);
+void            fr_window_archive_reload               (FrWindow      *window);
+void            fr_window_archive_add_files            (FrWindow      *window,
+						        GList         *file_list, /* GFile list */
+						        gboolean       update);
+void            fr_window_archive_add_with_wildcard    (FrWindow      *window,
+						        const char    *include_files,
+						        const char    *exclude_files,
+						        const char    *exclude_folders,
+						        const char    *base_dir,
+						        const char    *dest_dir,
+						        gboolean       update,
+						        gboolean       follow_links);
+void            fr_window_archive_add_directory        (FrWindow      *window,
+						        const char    *directory,
+						        const char    *base_dir,
+						        const char    *dest_dir,
+						        gboolean       update);
+void            fr_window_archive_add_items            (FrWindow      *window,
+						        GList         *dir_list,
+						        const char    *base_dir,
+						        const char    *dest_dir,
+						        gboolean       update);
+void            fr_window_archive_add_dropped_items    (FrWindow      *window,
+						        GList         *item_list,
+						        gboolean       update);
+void            fr_window_archive_remove               (FrWindow      *window,
+						        GList         *file_list);
+void            fr_window_archive_extract              (FrWindow      *window,
+						        GList         *file_list,
+						        const char    *extract_to_dir,
+						        const char    *base_dir,
+						        gboolean       skip_older,
+						        FrOverwrite    overwrite,
+						        gboolean       junk_paths,
+						        gboolean       ask_to_open_destination);
+void            fr_window_archive_extract_here         (FrWindow      *window,
+						        gboolean       skip_older,
+						        gboolean       overwrite,
+						        gboolean       junk_paths);
+void            fr_window_archive_test	               (FrWindow      *window);
 
 /**/
 
-void        fr_window_set_password              (FrWindow      *window,
-						 const char    *password);
-void        fr_window_set_password_for_paste    (FrWindow      *window,
-					         const char    *password);
-const char *fr_window_get_password              (FrWindow      *window);
-void        fr_window_set_encrypt_header        (FrWindow      *window,
-						 gboolean       encrypt_header);
-gboolean    fr_window_get_encrypt_header        (FrWindow      *window);
-void        fr_window_set_compression 	        (FrWindow      *window,
-						 FrCompression  compression);
-FrCompression fr_window_get_compression 	(FrWindow      *window);
-void        fr_window_set_volume_size 	        (FrWindow      *window,
-						 guint          volume_size);
-guint       fr_window_get_volume_size 	        (FrWindow      *window);
+void            fr_window_set_password                 (FrWindow      *window,
+						        const char    *password);
+void            fr_window_set_password_for_paste       (FrWindow      *window,
+						        const char    *password);
+const char *    fr_window_get_password                 (FrWindow      *window);
+void            fr_window_set_encrypt_header           (FrWindow      *window,
+						        gboolean       encrypt_header);
+gboolean        fr_window_get_encrypt_header           (FrWindow      *window);
+void            fr_window_set_compression 	       (FrWindow      *window,
+						        FrCompression  compression);
+FrCompression   fr_window_get_compression 	       (FrWindow      *window);
+void            fr_window_set_volume_size 	       (FrWindow      *window,
+						        guint          volume_size);
+guint           fr_window_get_volume_size 	       (FrWindow      *window);
 
 /**/
 
-void       fr_window_go_to_location             (FrWindow       *window,
-					 	 const char     *path,
-					 	 gboolean        force_update);
-const char*fr_window_get_current_location       (FrWindow       *window);
-void       fr_window_go_up_one_level            (FrWindow       *window);
-void       fr_window_go_back                    (FrWindow       *window);
-void       fr_window_go_forward                 (FrWindow       *window);
-void       fr_window_current_folder_activated   (FrWindow       *window,
-						 gboolean        from_sidebar);
-void       fr_window_set_list_mode              (FrWindow       *window,
-						 FrWindowListMode  list_mode);
+void            fr_window_go_to_location               (FrWindow      *window,
+						        const char    *path,
+						        gboolean       force_update);
+const char *    fr_window_get_current_location         (FrWindow      *window);
+void            fr_window_go_up_one_level              (FrWindow      *window);
+void            fr_window_go_back                      (FrWindow      *window);
+void            fr_window_go_forward                   (FrWindow      *window);
+void            fr_window_current_folder_activated     (FrWindow      *window,
+						        gboolean       from_sidebar);
+void            fr_window_set_list_mode                (FrWindow      *window,
+						        FrWindowListMode
+						        	       list_mode);
 
 /**/
 
-void       fr_window_update_list_order            (FrWindow    *window);
-GList *    fr_window_get_file_list_selection      (FrWindow    *window,
-						   gboolean     recursive,
-						   gboolean    *has_dirs);
-GList *    fr_window_get_file_list_from_path_list (FrWindow    *window,
-						   GList       *path_list,
-						   gboolean    *has_dirs);
-GList *    fr_window_get_file_list_pattern        (FrWindow    *window,
-						   const char  *pattern);
-int        fr_window_get_n_selected_files         (FrWindow    *window);
-GList *    fr_window_get_folder_tree_selection    (FrWindow    *window,
-				     		   gboolean     recursive,
-				     		   gboolean    *has_dirs);
-GList *    fr_window_get_selection                (FrWindow    *window,
-		  	 			   gboolean     from_sidebar,
-		  	 			   char       **return_base_dir);
-GtkTreeModel *
-	   fr_window_get_list_store               (FrWindow    *window);
-void       fr_window_find                         (FrWindow    *window);
-void       fr_window_select_all                   (FrWindow    *window);
-void       fr_window_unselect_all                 (FrWindow    *window);
-void       fr_window_set_sort_type                (FrWindow    *window,
-						   GtkSortType  sort_type);
+void            fr_window_update_list_order            (FrWindow    *window);
+GList *         fr_window_get_file_list_selection      (FrWindow    *window,
+						        gboolean     recursive,
+						        gboolean    *has_dirs);
+GList *         fr_window_get_file_list_from_path_list (FrWindow    *window,
+						        GList       *path_list,
+						        gboolean    *has_dirs);
+GList *         fr_window_get_file_list_pattern        (FrWindow    *window,
+						        const char  *pattern);
+int             fr_window_get_n_selected_files         (FrWindow    *window);
+GList *         fr_window_get_folder_tree_selection    (FrWindow    *window,
+						        gboolean     recursive,
+						        gboolean    *has_dirs);
+GList *         fr_window_get_selection                (FrWindow    *window,
+						        gboolean     from_sidebar,
+						        char       **return_base_dir);
+GtkTreeModel *  fr_window_get_list_store               (FrWindow    *window);
+void            fr_window_find                         (FrWindow    *window);
+void            fr_window_select_all                   (FrWindow    *window);
+void            fr_window_unselect_all                 (FrWindow    *window);
+void            fr_window_set_sort_type                (FrWindow    *window,
+						        GtkSortType  sort_type);
 
 /**/
 
-void       fr_window_rename_selection             (FrWindow    *window,
-						   gboolean     from_sidebar);
-void       fr_window_cut_selection                (FrWindow    *window,
-						   gboolean     from_sidebar);
-void       fr_window_copy_selection               (FrWindow    *window,
-						   gboolean     from_sidebar);
-void       fr_window_paste_selection              (FrWindow    *window,
-						   gboolean     from_sidebar);
+void            fr_window_rename_selection             (FrWindow    *window,
+						        gboolean     from_sidebar);
+void            fr_window_cut_selection                (FrWindow    *window,
+						        gboolean     from_sidebar);
+void            fr_window_copy_selection               (FrWindow    *window,
+						        gboolean     from_sidebar);
+void            fr_window_paste_selection              (FrWindow    *window,
+						        gboolean     from_sidebar);
 
 /**/
 
-void       fr_window_stop                         (FrWindow    *window);
-void       fr_window_start_activity_mode          (FrWindow    *window);
-void       fr_window_stop_activity_mode           (FrWindow    *window);
+void            fr_window_stop                         (FrWindow    *window);
+void            fr_window_start_activity_mode          (FrWindow    *window);
+void            fr_window_stop_activity_mode           (FrWindow    *window);
 
 /**/
 
-void        fr_window_view_last_output            (FrWindow   *window,
-						   const char *title);
-
-void        fr_window_open_files                  (FrWindow   *window,
-						   GList      *file_list,
-						   gboolean    ask_application);
-void        fr_window_open_files_with_command     (FrWindow   *window,
-						   GList      *file_list,
-						   char       *command);
-void        fr_window_open_files_with_application (FrWindow   *window,
-						   GList      *file_list,
-						   GAppInfo   *app);
-gboolean    fr_window_update_files                (FrWindow   *window,
-						   GList      *file_list);
-void        fr_window_update_columns_visibility   (FrWindow   *window);
-void        fr_window_update_history_list         (FrWindow   *window);
-void        fr_window_set_default_dir             (FrWindow   *window,
-						   const char *default_dir,
-						   gboolean    freeze);
-void        fr_window_set_open_default_dir        (FrWindow   *window,
-						   const char *default_dir);
-const char *fr_window_get_open_default_dir        (FrWindow   *window);
-void        fr_window_set_add_default_dir         (FrWindow   *window,
-						   const char *default_dir);
-const char *fr_window_get_add_default_dir         (FrWindow   *window);
-void        fr_window_set_extract_default_dir     (FrWindow   *window,
-						   const char *default_dir,
-						   gboolean    freeze);
-const char *fr_window_get_extract_default_dir     (FrWindow   *window);
-void        fr_window_push_message                (FrWindow   *window,
-						   const char *msg);
-void        fr_window_pop_message                 (FrWindow   *window);
-void        fr_window_set_toolbar_visibility      (FrWindow   *window,
-						   gboolean    value);
-void        fr_window_set_statusbar_visibility    (FrWindow   *window,
-						   gboolean    value);
-void        fr_window_set_folders_visibility      (FrWindow   *window,
-						   gboolean    value);
-void        fr_window_use_progress_dialog         (FrWindow   *window,
-						   gboolean    value);
+void            fr_window_view_last_output             (FrWindow   *window,
+						        const char *title);
+void            fr_window_open_files                   (FrWindow   *window,
+						        GList      *file_list,
+						        gboolean    ask_application);
+void            fr_window_open_files_with_command      (FrWindow   *window,
+						        GList      *file_list,
+						        char       *command);
+void            fr_window_open_files_with_application  (FrWindow   *window,
+						        GList      *file_list,
+						        GAppInfo   *app);
+gboolean        fr_window_update_files                 (FrWindow   *window,
+						        GList      *file_list);
+void            fr_window_update_columns_visibility    (FrWindow   *window);
+void            fr_window_update_history_list          (FrWindow   *window);
+void            fr_window_set_default_dir              (FrWindow   *window,
+						        const char *default_dir,
+						        gboolean    freeze);
+void            fr_window_set_open_default_dir         (FrWindow   *window,
+						        const char *default_dir);
+const char *    fr_window_get_open_default_dir         (FrWindow   *window);
+void            fr_window_set_add_default_dir          (FrWindow   *window,
+						        const char *default_dir);
+const char *    fr_window_get_add_default_dir          (FrWindow   *window);
+void            fr_window_set_extract_default_dir      (FrWindow   *window,
+						        const char *default_dir,
+						        gboolean    freeze);
+const char *    fr_window_get_extract_default_dir      (FrWindow   *window);
+void            fr_window_push_message                 (FrWindow   *window,
+						        const char *msg);
+void            fr_window_pop_message                  (FrWindow   *window);
+void            fr_window_set_toolbar_visibility       (FrWindow   *window,
+						        gboolean    value);
+void            fr_window_set_statusbar_visibility     (FrWindow   *window,
+						        gboolean    value);
+void            fr_window_set_folders_visibility       (FrWindow   *window,
+						        gboolean    value);
+void            fr_window_use_progress_dialog          (FrWindow   *window,
+						        gboolean    value);
 
 /* batch mode procedures. */
 
-void       fr_window_new_batch                    (FrWindow      *window,
-						   const char    *title);
-const char *
-           fr_window_get_batch_title              (FrWindow      *window);
-void       fr_window_set_current_batch_action     (FrWindow      *window,
-						   FrBatchActionType  action,
-						   void          *data,
-						   GFreeFunc      free_func);
-void       fr_window_reset_current_batch_action   (FrWindow      *window);
-void       fr_window_restart_current_batch_action (FrWindow      *window);
-void       fr_window_append_batch_action          (FrWindow      *window,
-						   FrBatchActionType  action,
-						   void          *data,
-						   GFreeFunc      free_func);
-void       fr_window_start_batch                  (FrWindow      *window);
-void       fr_window_stop_batch                   (FrWindow      *window);
-void       fr_window_resume_batch                 (FrWindow      *window);
-gboolean   fr_window_is_batch_mode                (FrWindow      *window);
-void       fr_window_set_batch__extract           (FrWindow      *window,
-						   const char    *filename,
-						   const char    *dest_dir);
-void       fr_window_set_batch__extract_here      (FrWindow      *window,
-						   const char    *filename);
-void       fr_window_set_batch__add               (FrWindow      *window,
-						   const char    *archive,
-						   GList         *file_list);
-void       fr_window_destroy_with_error_dialog    (FrWindow      *window);
+void            fr_window_new_batch                    (FrWindow      *window,
+						        const char    *title);
+const char *    fr_window_get_batch_title              (FrWindow      *window);
+void            fr_window_set_current_batch_action     (FrWindow      *window,
+						        FrBatchActionType
+						        	       action,
+						        void          *data,
+						        GFreeFunc      free_func);
+void            fr_window_reset_current_batch_action   (FrWindow      *window);
+void            fr_window_restart_current_batch_action (FrWindow      *window);
+void            fr_window_append_batch_action          (FrWindow      *window,
+						        FrBatchActionType
+						        	       action,
+						        void          *data,
+						        GFreeFunc      free_func);
+void            fr_window_start_batch                  (FrWindow      *window);
+void            fr_window_stop_batch                   (FrWindow      *window);
+void            fr_window_resume_batch                 (FrWindow      *window);
+gboolean        fr_window_is_batch_mode                (FrWindow      *window);
+void            fr_window_set_batch__extract           (FrWindow      *window,
+						        const char    *filename,
+						        const char    *dest_dir);
+void            fr_window_set_batch__extract_here      (FrWindow      *window,
+						        const char    *filename);
+void            fr_window_set_batch__add               (FrWindow      *window,
+						        const char    *archive,
+						        GList         *file_list);
+void            fr_window_destroy_with_error_dialog    (FrWindow      *window);
 
 /**/
 
-gboolean   fr_window_file_list_drag_data_get (FrWindow         *window,
-					      GdkDragContext   *context,
-					      GtkSelectionData *selection_data,
-					      GList            *path_list);
-
-void       fr_window_update_dialog_closed    (FrWindow *window);
+gboolean        fr_window_file_list_drag_data_get      (FrWindow         *window,
+						        GdkDragContext   *context,
+						        GtkSelectionData *selection_data,
+						        GList            *path_list);
+void            fr_window_update_dialog_closed         (FrWindow         *window);
 
 #endif /* FR_WINDOW_H */
diff --git a/src/glib-utils.c b/src/glib-utils.c
index b3715c6..59e8690 100644
--- a/src/glib-utils.c
+++ b/src/glib-utils.c
@@ -50,6 +50,29 @@ _g_object_unref (gpointer object)
 }
 
 
+void
+_g_clear_object (gpointer p)
+{
+	gpointer *object_p = (gpointer *) p;
+
+	if ((object_p != NULL) && (*object_p != NULL)) {
+		g_object_unref (*object_p);
+		*object_p = NULL;
+	}
+}
+
+
+/* error */
+
+
+void
+_g_error_free (GError *error)
+{
+	if (error != NULL)
+		g_error_free (error);
+}
+
+
 /* string */
 
 
diff --git a/src/glib-utils.h b/src/glib-utils.h
index 7fd180b..a5a584d 100644
--- a/src/glib-utils.h
+++ b/src/glib-utils.h
@@ -48,6 +48,11 @@
 
 gpointer            _g_object_ref                  (gpointer             object);
 void                _g_object_unref                (gpointer             object);
+void                _g_clear_object                (gpointer             p);
+
+/* error */
+
+void                _g_error_free                  (GError              *error);
 
 /* string */
 
diff --git a/src/main.c b/src/main.c
index 1bb014e..dc18820 100644
--- a/src/main.c
+++ b/src/main.c
@@ -200,16 +200,16 @@ client_save_state (EggSMClient *client,
 		     window = window->next, i++)
 		{
 			FrWindow *session = window->data;
-			gchar *key;
+			gchar    *key;
 
 			key = g_strdup_printf ("archive%d", i);
-			if ((session->archive == NULL) || (session->archive->file == NULL)) {
+			if ((session->archive == NULL) || (fr_archive_get_file (session->archive) == NULL)) {
 				g_key_file_set_string (state, "Session", key, "");
 			}
 			else {
 				gchar *uri;
 
-				uri = g_file_get_uri (session->archive->file);
+				uri = g_file_get_uri (fr_archive_get_file (session->archive));
 				g_key_file_set_string (state, "Session", key, uri);
 				g_free (uri);
 			}
@@ -310,7 +310,7 @@ handle_method_call (GDBusConnection       *connection,
 		    GDBusMethodInvocation *invocation,
 		    gpointer               user_data)
 {
-	update_registered_commands_capabilities ();
+	update_registered_archives_capabilities ();
 
 	if (g_strcmp0 (method_name, "GetSupportedTypes") == 0) {
 		char *action;
diff --git a/src/rar-utils.c b/src/rar-utils.c
index c1a35e0..3abb7ce 100644
--- a/src/rar-utils.c
+++ b/src/rar-utils.c
@@ -125,7 +125,7 @@ rar_check_multi_volume (FrCommand *comm)
 
 			parent = g_file_get_parent (file);
 			volume_file = g_file_get_child (parent, volume_name);
-			fr_command_set_multi_volume (comm, volume_file);
+			fr_archive_set_multi_volume (FR_ARCHIVE (comm), volume_file);
 
 			g_object_unref (volume_file);
 			g_object_unref (parent);
diff --git a/src/typedefs.h b/src/typedefs.h
index 28c78ab..a857e5f 100644
--- a/src/typedefs.h
+++ b/src/typedefs.h
@@ -29,6 +29,11 @@
 
 #define ADD_FOLDER_OPTIONS_DIR  "file-roller/options"
 
+typedef enum {
+	FR_CLIPBOARD_OP_CUT,
+	FR_CLIPBOARD_OP_COPY
+} FrClipboardOp;
+
 typedef enum { /*< skip >*/
 	FR_WINDOW_SORT_BY_NAME = 0,
 	FR_WINDOW_SORT_BY_SIZE = 1,
@@ -56,44 +61,23 @@ typedef enum {
 } FrOverwrite;
 
 typedef enum { /*< skip >*/
-	FR_PROC_ERROR_NONE,
-	FR_PROC_ERROR_GENERIC,
-	FR_PROC_ERROR_COMMAND_ERROR,
-	FR_PROC_ERROR_COMMAND_NOT_FOUND,
-	FR_PROC_ERROR_EXITED_ABNORMALLY,
-	FR_PROC_ERROR_SPAWN,
-	FR_PROC_ERROR_STOPPED,
-	FR_PROC_ERROR_ASK_PASSWORD,
-	FR_PROC_ERROR_MISSING_VOLUME,
-	FR_PROC_ERROR_IO_CHANNEL,
-	FR_PROC_ERROR_BAD_CHARSET,
-	FR_PROC_ERROR_UNSUPPORTED_FORMAT
-} FrProcErrorType;
-
-typedef struct {
-	FrProcErrorType  type;
-	int              status;
-	GError          *gerror;
-} FrProcError;
-
-typedef enum { /*< skip >*/
-	FR_COMMAND_CAN_DO_NOTHING = 0,
-	FR_COMMAND_CAN_READ = 1 << 0,
-	FR_COMMAND_CAN_WRITE = 1 << 1,
-	FR_COMMAND_CAN_ARCHIVE_MANY_FILES = 1 << 2,
-	FR_COMMAND_CAN_ENCRYPT = 1 << 3,
-	FR_COMMAND_CAN_ENCRYPT_HEADER = 1 << 4,
-	FR_COMMAND_CAN_CREATE_VOLUMES = 1 << 5
-} FrCommandCap;
+	FR_ARCHIVE_CAN_DO_NOTHING = 0,
+	FR_ARCHIVE_CAN_READ = 1 << 0,
+	FR_ARCHIVE_CAN_WRITE = 1 << 1,
+	FR_ARCHIVE_CAN_STORE_MANY_FILES = 1 << 2,
+	FR_ARCHIVE_CAN_ENCRYPT = 1 << 3,
+	FR_ARCHIVE_CAN_ENCRYPT_HEADER = 1 << 4,
+	FR_ARCHIVE_CAN_CREATE_VOLUMES = 1 << 5
+} FrArchiveCap;
 
-#define FR_COMMAND_CAN_READ_WRITE (FR_COMMAND_CAN_READ | FR_COMMAND_CAN_WRITE)
+#define FR_ARCHIVE_CAN_READ_WRITE (FR_ARCHIVE_CAN_READ | FR_ARCHIVE_CAN_WRITE)
 
-typedef guint8 FrCommandCaps;
+typedef guint8 FrArchiveCaps;
 
 typedef struct {
 	const char    *mime_type;
-	FrCommandCaps  current_capabilities;
-	FrCommandCaps  potential_capabilities;
+	FrArchiveCaps  current_capabilities;
+	FrArchiveCaps  potential_capabilities;
 } FrMimeTypeCap;
 
 typedef struct {
@@ -106,13 +90,13 @@ typedef struct {
 	GType      type;
 	GPtrArray *caps;  /* array of FrMimeTypeCap */
 	GPtrArray *packages;  /* array of FrMimeTypePackages */
-} FrRegisteredCommand;
+} FrRegisteredArchive;
 
 typedef struct {
 	const char    *mime_type;
 	char          *default_ext;
 	char          *name;
-	FrCommandCaps  capabilities;
+	FrArchiveCaps  capabilities;
 } FrMimeTypeDescription;
 
 typedef struct {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]