/*
 *  Copyright (C) 2006 Giuseppe Torelli - <colossus73@gmail.com>
 *  Copyright (C) 2006 Benedikt Meurer - <benny@xfce.org>
 *
 *  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
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
 */

#include <gtk/gtk.h>
#include <stdlib.h>
#include "extract_dialog.h"
#include "interface.h"
#include "callbacks.h"
#include "string_utils.h"
#include "support.h"

gboolean stop_flag;
extern gboolean cli;

Extract_dialog_data *xa_create_extract_dialog (gint selected , XArchive *archive)
{
	Extract_dialog_data *dialog_data;
	stop_flag = FALSE;

	dialog_data = g_new0 (Extract_dialog_data, 1);
	dialog_data->radio_group = NULL;
	dialog_data->dialog1 = gtk_dialog_new ();
	if (archive->type == XARCHIVETYPE_BZIP2 || archive->type == XARCHIVETYPE_GZIP)
		gtk_window_set_title (GTK_WINDOW (dialog_data->dialog1), _("Decompress file"));		
	else
		gtk_window_set_title (GTK_WINDOW (dialog_data->dialog1), _("Extract files from archive"));
	gtk_window_set_type_hint (GTK_WINDOW (dialog_data->dialog1), GDK_WINDOW_TYPE_HINT_DIALOG);
	gtk_window_set_transient_for ( GTK_WINDOW (dialog_data->dialog1) , GTK_WINDOW (MainWindow) );

	dialog_data->option_tooltip = gtk_tooltips_new ();
	dialog_data->dialog_vbox1 = GTK_DIALOG (dialog_data->dialog1)->vbox;
	gtk_widget_show (dialog_data->dialog_vbox1);

	dialog_data->vbox1 = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (dialog_data->vbox1);
	gtk_box_pack_start (GTK_BOX (dialog_data->dialog_vbox1), dialog_data->vbox1, TRUE, TRUE, 0);

	dialog_data->hbox3 = gtk_hbox_new (FALSE, 0);
	gtk_widget_show (dialog_data->hbox3);
	gtk_box_pack_start (GTK_BOX (dialog_data->vbox1), dialog_data->hbox3, FALSE, TRUE, 17);

	dialog_data->extract_to_label = gtk_label_new (_("Extract to:"));
	gtk_widget_show (dialog_data->extract_to_label);
	gtk_box_pack_start (GTK_BOX (dialog_data->hbox3), dialog_data->extract_to_label, FALSE, TRUE, 0);

	dialog_data->destination_path_entry = gtk_entry_new ();
	gtk_widget_show (dialog_data->destination_path_entry);
	gtk_box_pack_start (GTK_BOX (dialog_data->hbox3), dialog_data->destination_path_entry, TRUE, TRUE, 0);
	gtk_widget_set_size_request (dialog_data->destination_path_entry, 385, -1);
	gtk_entry_set_activates_default (GTK_ENTRY (dialog_data->destination_path_entry), TRUE);

	gchar *dummy = StripPathFromFilename(archive->path, ".");
	if (dummy != NULL)
	{
		dummy++;
		unsigned short int x = strlen (archive->path) - strlen ( dummy );
		gchar *extraction_string = (gchar *) g_malloc ( x + 1);
		strncpy ( extraction_string, archive->path, x );
		extraction_string [x-1] = '\0';

		if ( strstr (extraction_string , ".tar") )
		{
			extraction_string = g_realloc ( extraction_string, x - 5);
			strncpy ( extraction_string, archive->path, x - 5);
			extraction_string[x-5] = '\0';
		}
		gtk_entry_set_text (GTK_ENTRY(dialog_data->destination_path_entry), extraction_string);
		g_free (extraction_string);
	}
	else
		gtk_entry_set_text (GTK_ENTRY(dialog_data->destination_path_entry), archive->path);

	dialog_data->button1 = gtk_button_new ();
	gtk_widget_set_size_request (dialog_data->button1, 33, 27);
	gtk_widget_show (dialog_data->button1);

	dialog_data->image1 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_BUTTON);
	gtk_widget_show (dialog_data->image1);
	gtk_box_pack_end(GTK_BOX (dialog_data->hbox3), dialog_data->button1, FALSE, TRUE, 0);
	gtk_widget_set_size_request (dialog_data->image1, 30, 30);

	gtk_container_add(GTK_CONTAINER(dialog_data->button1), dialog_data->image1);
	gtk_tooltips_set_tip (dialog_data->option_tooltip,dialog_data->button1 , _("Choose a folder where to extract files"), NULL );
	g_signal_connect ( (gpointer) dialog_data->button1, "clicked", G_CALLBACK (Show_File_Dialog) ,  "extract" );

	dialog_data->hbox4 = gtk_hbox_new (TRUE, 7);
	gtk_widget_show (dialog_data->hbox4);
	gtk_box_pack_start (GTK_BOX (dialog_data->vbox1), dialog_data->hbox4, FALSE, FALSE, 0);

	dialog_data->frame1 = gtk_frame_new (NULL);
	gtk_widget_show (dialog_data->frame1);
	gtk_box_pack_start (GTK_BOX (dialog_data->hbox4), dialog_data->frame1, TRUE, TRUE, 0);
	gtk_widget_set_size_request (dialog_data->frame1, 1, -1);
	gtk_frame_set_shadow_type (GTK_FRAME (dialog_data->frame1), GTK_SHADOW_OUT);

	dialog_data->alignment1 = gtk_alignment_new (0.5, 0.5, 1, 1);
	gtk_widget_show (dialog_data->alignment1);
	gtk_container_add (GTK_CONTAINER (dialog_data->frame1), dialog_data->alignment1);
	gtk_alignment_set_padding (GTK_ALIGNMENT (dialog_data->alignment1), 0, 0, 12, 0);

	dialog_data->vbox3 = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (dialog_data->vbox3);
	gtk_container_add (GTK_CONTAINER (dialog_data->alignment1), dialog_data->vbox3);

	dialog_data->all_files_radio = gtk_radio_button_new_with_mnemonic (NULL, _("All"));
	gtk_widget_show (dialog_data->all_files_radio);
	gtk_box_pack_start (GTK_BOX (dialog_data->vbox3), dialog_data->all_files_radio, FALSE, FALSE, 0);
	gtk_radio_button_set_group (GTK_RADIO_BUTTON (dialog_data->all_files_radio), dialog_data->radio_group);
	dialog_data->radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (dialog_data->all_files_radio));

	dialog_data->selected_files_radio = gtk_radio_button_new_with_mnemonic (NULL, _("Only selected"));
	gtk_widget_show (dialog_data->selected_files_radio);
	gtk_box_pack_start (GTK_BOX (dialog_data->vbox3), dialog_data->selected_files_radio, FALSE, FALSE, 0);
	gtk_radio_button_set_group (GTK_RADIO_BUTTON (dialog_data->selected_files_radio), dialog_data->radio_group);
	dialog_data->radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (dialog_data->selected_files_radio));

	if (selected)
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog_data->selected_files_radio), TRUE);
	else
		gtk_widget_set_sensitive (dialog_data->selected_files_radio , FALSE);
	
	dialog_data->files_frame_label = gtk_label_new (_("<b>Files to extract </b>"));
	gtk_widget_show (dialog_data->files_frame_label);
	gtk_frame_set_label_widget (GTK_FRAME (dialog_data->frame1), dialog_data->files_frame_label);
	gtk_label_set_use_markup (GTK_LABEL (dialog_data->files_frame_label), TRUE);

	dialog_data->frame2 = gtk_frame_new (NULL);
	gtk_widget_show (dialog_data->frame2);
	gtk_box_pack_start (GTK_BOX (dialog_data->hbox4), dialog_data->frame2, TRUE, TRUE, 0);
	gtk_frame_set_shadow_type (GTK_FRAME (dialog_data->frame2), GTK_SHADOW_OUT);

	dialog_data->alignment2 = gtk_alignment_new (0.5, 0.5, 1, 1);
	gtk_widget_show (dialog_data->alignment2);
	gtk_container_add (GTK_CONTAINER (dialog_data->frame2), dialog_data->alignment2);
	gtk_alignment_set_padding (GTK_ALIGNMENT (dialog_data->alignment2), 0, 0, 12, 0);

	dialog_data->vbox4 = gtk_vbox_new (FALSE, 0);
	gtk_widget_show (dialog_data->vbox4);
	gtk_container_add (GTK_CONTAINER (dialog_data->alignment2), dialog_data->vbox4);

	dialog_data->overwrite_check = gtk_check_button_new_with_mnemonic (_("Overwrite existing files"));
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog_data->overwrite_check), archive->overwrite);
	gtk_widget_show (dialog_data->overwrite_check);
	gtk_box_pack_start (GTK_BOX (dialog_data->vbox4), dialog_data->overwrite_check, FALSE, FALSE, 0);

	dialog_data->extract_full = gtk_check_button_new_with_mnemonic (_("Extract files with full path"));
	if (cli && (archive->type == XARCHIVETYPE_TAR || archive->type == XARCHIVETYPE_TAR_GZ || archive->type == XARCHIVETYPE_TAR_BZ2) )
	{
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog_data->extract_full), TRUE);
		gtk_widget_set_sensitive (dialog_data->extract_full, FALSE);
	}
	else
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog_data->extract_full), archive->full_path);
	gtk_widget_show (dialog_data->extract_full);
	gtk_tooltips_set_tip (dialog_data->option_tooltip,dialog_data->extract_full , _("The archive's directory structure is recreated in the extraction directory."), NULL );
	gtk_box_pack_start (GTK_BOX (dialog_data->vbox4), dialog_data->extract_full, FALSE, FALSE, 0);

	if (archive->type == XARCHIVETYPE_TAR || archive->type == XARCHIVETYPE_TAR_GZ || archive->type == XARCHIVETYPE_TAR_BZ2)
	{
		dialog_data->touch = gtk_check_button_new_with_mnemonic (_("Touch files"));
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog_data->touch), archive->tar_touch);
		gtk_widget_show (dialog_data->touch);
		gtk_tooltips_set_tip (dialog_data->option_tooltip,dialog_data->touch, _("When this option is used, tar leaves the data modification times of the files it extracts as the times when the files were extracted, instead of setting it to the times recorded in the archive."), NULL );
		gtk_box_pack_start (GTK_BOX (dialog_data->vbox4), dialog_data->touch, FALSE, FALSE, 0);

		dialog_data->hbox6 = gtk_hbox_new (FALSE, 2);
		gtk_widget_show (dialog_data->hbox6);
		gtk_box_pack_start (GTK_BOX (dialog_data->vbox4), dialog_data->hbox6, FALSE, FALSE, 0);

	}
	else
		dialog_data->touch = NULL;

	if (archive->type == XARCHIVETYPE_RAR || archive->type == XARCHIVETYPE_ZIP || archive->type == XARCHIVETYPE_ARJ)
	{
		dialog_data->fresh = gtk_check_button_new_with_mnemonic (_("Freshen existing files"));
		gtk_tooltips_set_tip (dialog_data->option_tooltip,dialog_data->fresh , _("Extract only those files that already exist on disk and that are newer than the disk copies."), NULL );
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog_data->fresh), archive->freshen);
		gtk_widget_show (dialog_data->fresh);
		gtk_box_pack_start (GTK_BOX (dialog_data->vbox4), dialog_data->fresh, FALSE, FALSE, 0);
		g_signal_connect (G_OBJECT (dialog_data->fresh),"toggled",G_CALLBACK (fresh_update_toggled_cb) , dialog_data);

		dialog_data->update = gtk_check_button_new_with_mnemonic (_("Update existing files"));
		gtk_tooltips_set_tip (dialog_data->option_tooltip,dialog_data->update , _("This option performs the same function as the freshen one, extracting files that are newer than those with the same name on disk, and in addition it extracts those files that do not already exist on disk."), NULL );
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog_data->update), archive->update);
		gtk_widget_show (dialog_data->update);
		gtk_box_pack_start (GTK_BOX (dialog_data->vbox4), dialog_data->update, FALSE, FALSE, 0);
		g_signal_connect (G_OBJECT (dialog_data->update),"toggled",G_CALLBACK (update_fresh_toggled_cb) , dialog_data);
	}
	else
	{
		dialog_data->fresh = NULL;
		dialog_data->update = NULL;
	}
	dialog_data->hbox5 = gtk_hbox_new (FALSE, 2);
	gtk_widget_show (dialog_data->hbox5);
	gtk_box_pack_start (GTK_BOX (dialog_data->vbox4), dialog_data->hbox5, FALSE, FALSE, 0);

	dialog_data->label_password = gtk_label_new (_("Password:"));
	gtk_widget_show (dialog_data->label_password);
	gtk_box_pack_start (GTK_BOX (dialog_data->hbox5), dialog_data->label_password, FALSE, FALSE, 0);

	dialog_data->password_entry = gtk_entry_new ();
	gtk_widget_show (dialog_data->password_entry);
	gtk_box_pack_start (GTK_BOX (dialog_data->hbox5), dialog_data->password_entry, FALSE, FALSE, 0);
	gtk_entry_set_visibility (GTK_ENTRY (dialog_data->password_entry), FALSE);
	if ( archive->has_passwd )
    {
		gtk_widget_set_sensitive (dialog_data->label_password, TRUE);
		gtk_widget_set_sensitive (dialog_data->password_entry, TRUE);
		if (archive->passwd != NULL)
			gtk_entry_set_text (GTK_ENTRY(dialog_data->password_entry) , archive->passwd);
    }
	else
	{
		gtk_widget_set_sensitive (dialog_data->label_password, FALSE);
		gtk_widget_set_sensitive (dialog_data->password_entry, FALSE);
	}

	dialog_data->options_frame_label = gtk_label_new (_("<b>Options </b>"));
	gtk_widget_show (dialog_data->options_frame_label);
	gtk_frame_set_label_widget (GTK_FRAME (dialog_data->frame2), dialog_data->options_frame_label);
	gtk_label_set_use_markup (GTK_LABEL (dialog_data->options_frame_label), TRUE);

	dialog_data->dialog_action_area1 = GTK_DIALOG (dialog_data->dialog1)->action_area;
	gtk_widget_show (dialog_data->dialog_action_area1);
	gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_data->dialog_action_area1), GTK_BUTTONBOX_END);

	dialog_data->cancel_button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
	gtk_widget_show (dialog_data->cancel_button);
	gtk_dialog_add_action_widget (GTK_DIALOG (dialog_data->dialog1), dialog_data->cancel_button, GTK_RESPONSE_CANCEL);
	GTK_WIDGET_SET_FLAGS (dialog_data->cancel_button, GTK_CAN_DEFAULT);

	dialog_data->extract_button = gtk_button_new();
	dialog_data->extract_image = xa_main_window_find_image("extract_button.png", GTK_ICON_SIZE_SMALL_TOOLBAR);
	dialog_data->extract_hbox = gtk_hbox_new(FALSE, 4);
	dialog_data->extract_label = gtk_label_new_with_mnemonic(_("_Extract"));

	dialog_data->alignment3 = gtk_alignment_new (0.5, 0.5, 0, 0);
	gtk_widget_show (dialog_data->alignment3);
	gtk_container_add (GTK_CONTAINER (dialog_data->alignment3), dialog_data->extract_hbox);

	gtk_box_pack_start(GTK_BOX(dialog_data->extract_hbox), dialog_data->extract_image, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(dialog_data->extract_hbox), dialog_data->extract_label, FALSE, FALSE, 0);
	gtk_widget_show_all(dialog_data->extract_hbox);
	gtk_container_add(GTK_CONTAINER(dialog_data->extract_button), dialog_data->alignment3);
	gtk_widget_show (dialog_data->extract_button);
	gtk_dialog_add_action_widget (GTK_DIALOG (dialog_data->dialog1), dialog_data->extract_button, GTK_RESPONSE_OK);
	GTK_WIDGET_SET_FLAGS (dialog_data->extract_button, GTK_CAN_DEFAULT);
	gtk_dialog_set_default_response (GTK_DIALOG (dialog_data->dialog1), GTK_RESPONSE_OK);
	return dialog_data;
}

void fresh_update_toggled_cb (GtkToggleButton *button, Extract_dialog_data *data)
{
	gboolean active = gtk_toggle_button_get_active (button);
	if (active)
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->update), FALSE);
}

void update_fresh_toggled_cb (GtkToggleButton *button, Extract_dialog_data *data)
{
	if (data->fresh == NULL)
		return;
	gboolean active = gtk_toggle_button_get_active (button);
	if (active)
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (data->fresh), FALSE);
}

gchar *xa_parse_extract_dialog_options ( XArchive *archive , Extract_dialog_data *dialog_data, GtkTreeSelection *selection)
{
	gchar *command = NULL;
	gchar *tar;
	gchar *destination_path = NULL;
	gboolean done = FALSE;
	gboolean end = FALSE;
	GtkTreeIter iter;

    while ( ! done )
	{
		switch (gtk_dialog_run ( GTK_DIALOG (dialog_data->dialog1 ) ) )
		{
			case GTK_RESPONSE_CANCEL:
			case GTK_RESPONSE_DELETE_EVENT:
			done = TRUE;
			if (archive->type == XARCHIVETYPE_GZIP || archive->type == XARCHIVETYPE_BZIP2)
			{
				gtk_widget_set_sensitive (Stop_button,FALSE);
				Update_StatusBar (_("Operation canceled.") );
				gtk_widget_hide (viewport2);
				archive->status = XA_ARCHIVESTATUS_IDLE;
			}
			break;

			case GTK_RESPONSE_OK:
			destination_path = g_strdup (gtk_entry_get_text ( GTK_ENTRY (dialog_data->destination_path_entry) ));
			archive->extraction_path = EscapeBadChars ( destination_path , "$\'`\"\\!?* ()&|@#:;" );

			if ( strlen ( archive->extraction_path ) == 0 )
			{
				response = ShowGtkMessageDialog (GTK_WINDOW (MainWindow),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK, _("You missed where to extract the files!"),_("Please enter the extraction path.") );
				break;
			}
			if (archive->has_passwd)
				archive->passwd  = g_strdup (gtk_entry_get_text ( GTK_ENTRY (dialog_data->password_entry) ));

			if (archive->has_passwd && strlen( archive->passwd ) == 0 )
			{
				response = ShowGtkMessageDialog (GTK_WINDOW (MainWindow),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK, _("This archive is encrypted!"),_("Please enter the password.") );
				break;
			}
			if (g_file_test (destination_path , G_FILE_TEST_EXISTS) == FALSE) 
			{
				int result = mkdir (destination_path , S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXGRP);
				if (result == -1)
				{
					gchar *msg = g_strdup_printf(_("Can't create directory \"%s\""), destination_path);
					response = ShowGtkMessageDialog (GTK_WINDOW (MainWindow),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK, msg, g_strerror(errno ) );
					g_free (msg);
					break;
				}
			}
			if ( g_file_test (destination_path , G_FILE_TEST_IS_DIR) && access (destination_path, R_OK | W_OK | X_OK ) )
			{
				gchar *utf8_path;
				gchar  *msg;

                utf8_path = g_filename_to_utf8 (destination_path, -1, NULL, NULL, NULL);
                msg = g_strdup_printf (_("You don't have the right permissions to extract the files to the folder \"%s\"."), utf8_path);
				response = ShowGtkMessageDialog (GTK_WINDOW (MainWindow),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK, _("Can't perform extraction!"),msg );
                g_free (utf8_path);
				g_free (msg);
				g_free (destination_path);
				break;
			}
			done = TRUE;
			archive->overwrite = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON ( dialog_data->overwrite_check ));
			if ( dialog_data->touch != NULL)
				archive->tar_touch = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON ( dialog_data->touch ));
			
			if (dialog_data->extract_full != NULL)
				archive->full_path = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON ( dialog_data->extract_full ));

			if (dialog_data->fresh != NULL)
				archive->freshen = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON ( dialog_data->fresh ));

			if (dialog_data->update != NULL)
				archive->update = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON ( dialog_data->update ));

			gtk_widget_set_sensitive (Stop_button,TRUE);
			gtk_widget_hide (dialog_data->dialog1);
			archive->status = XA_ARCHIVESTATUS_EXTRACT;
			/* Are all files selected? */
			if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON ( dialog_data->all_files_radio )) )
			{
				if ( ! cli )
				{
					gchar *text = g_strdup_printf(_("Extracting files to %s"), destination_path);
					Update_StatusBar ( text );
					g_free (text);
				}
				g_free (destination_path);
        tar = g_find_program_in_path ("gtar");
        if (tar == NULL)
          tar = g_strdup ("tar");
				switch ( archive->type )
				{
					case XARCHIVETYPE_BZIP2:
					gzip_bzip2_extract (archive , 0);
					break;

					case XARCHIVETYPE_GZIP:
					gzip_bzip2_extract (archive , 1);
					break;
					
					case XARCHIVETYPE_RAR:
					if (archive->passwd != NULL)
						command = g_strconcat ( "rar " , archive->full_path ? "x " : "e ",
												archive->freshen ? "-f " : "" , archive->update ? "-u " : "",
												" -p",archive->passwd,
												archive->overwrite ? " -o+" : " -o-",
												" -idp ",
												archive->escaped_path , " " , archive->extraction_path , NULL );
					else
						command = g_strconcat ( "rar " , archive->full_path ? "x " : "e ",
												archive->freshen ? "-f " : "" , archive->update ? "-u " : "",
												archive->overwrite ? "-o+" : "-o-",
												" -idp ",
												archive->escaped_path , " " , archive->extraction_path , NULL );
					break;

					case XARCHIVETYPE_TAR:
					if (archive->full_path == 1)
					{
						command = g_strconcat (tar, " -xvf ", archive->escaped_path,
											archive->overwrite ? " --overwrite" : " --keep-old-files",
											archive->tar_touch ? " --touch" : "",
											" -C " , archive->extraction_path , NULL );
					}
					else
					{
						xa_extract_tar_without_directories ( "tar -xvf " , archive->escaped_path, archive->overwrite,archive->tar_touch,archive->extraction_path, FALSE );
						command = NULL;
					}
					break;

					case XARCHIVETYPE_TAR_BZ2:
					if (archive->full_path == 1)
					{
						command = g_strconcat (tar, " -xvjf " , archive->escaped_path,
											archive->overwrite ? " --overwrite" : " --keep-old-files",
											archive->tar_touch ? " --touch" : "",
											" -C " , archive->extraction_path , NULL );
					}
					else
					{
						xa_extract_tar_without_directories ( "tar -xvjf " , archive->escaped_path, archive->overwrite,archive->tar_touch,archive->extraction_path , FALSE );
						command = NULL;
					}
					break;

					case XARCHIVETYPE_TAR_GZ:
					if (archive->full_path == 1)
					{
						command = g_strconcat (tar, " -xvzf " , archive->escaped_path,
											archive->overwrite ? " --overwrite" : " --keep-old-files",
											archive->tar_touch ? " --touch" : "",
											" -C " , archive->extraction_path , NULL );
					}
					else
					{
						xa_extract_tar_without_directories ( "tar -xvzf " , archive->escaped_path, archive->overwrite,archive->tar_touch,archive->extraction_path, FALSE );
						command = NULL;
					}
					break;

                    case XARCHIVETYPE_ZIP:
                    if ( archive->passwd != NULL )
						command = g_strconcat ( "unzip ", archive->freshen ? "-f " : "",
												archive->update ? "-u " : "" ,
												archive->overwrite ? "-o" : "-n",
												" -P " , archive->passwd,
												archive->full_path ? "" : " -j ",
												archive->escaped_path , " -d ", archive->extraction_path , NULL );
                    else
						command = g_strconcat ( "unzip ", archive->freshen ? "-f " : "",
												archive->update ? "-u " : "",
												archive->overwrite ? "-o " : "-n ",
												archive->full_path ? "" : " -j ",
												archive->escaped_path , " -d ", archive->extraction_path , NULL );
					break;

					case XARCHIVETYPE_RPM:
					if (archive->full_path == 1)
					{
						chdir ( archive->extraction_path );
						command = g_strconcat ( "cpio --make-directories -F " , archive->tmp , " -i" , NULL );
					}
					else
					{
						xa_extract_tar_without_directories ( "tar -xvzf " , archive->escaped_path, archive->overwrite,archive->tar_touch,archive->extraction_path , TRUE);
						command = NULL;
					}
                    break;

                    case XARCHIVETYPE_7ZIP:
                    if (archive->passwd != NULL)
						command = g_strconcat ( "7za " , archive->full_path ? "x " : "e ",
												archive->overwrite ? "-aoa" : "-aos",
												" -bd -p",archive->passwd," ",
												archive->escaped_path , " -o" , archive->extraction_path , NULL );
					else
						command = g_strconcat ( "7za " , archive->full_path ? "x " : "e ",
												archive->overwrite ? "-aoa" : "-aos",
												" -bd ",
												archive->escaped_path , " -o" , archive->extraction_path , NULL );
                    break;

					case XARCHIVETYPE_ARJ:
					if (archive->passwd != NULL)
						command = g_strconcat ( "arj " , archive->full_path ? "x " : "e ",
												"-g",archive->passwd,
												archive->overwrite ? "" : " -n" , " -i ",
												archive->freshen ? "-f " : "" , archive->update ? "-u " : "",
												"-y " , archive->escaped_path , " " , archive->extraction_path , NULL );
                    else
						command = g_strconcat ( "arj " , archive->full_path ? "x " : "e ",
												archive->overwrite ? "" : " -n" , " -i ",
												archive->freshen ? "-f " : "" , archive->update ? "-u " : "",
												"-y " , archive->escaped_path , " " , archive->extraction_path , NULL );
					break;

					case XARCHIVETYPE_ISO:
					end = gtk_tree_model_get_iter_first (model , &iter);
					gtk_widget_show ( viewport2 );
					g_timeout_add (200, xa_progressbar_pulse, NULL );
					while (end)
					{
						if (stop_flag)
							break;
						gtk_tree_model_get (model, &iter,
						0, &name,
						1, &permissions,
						2, &file_size,
						4, &file_offset,
						-1);
						if (xa_extract_iso_file (archive, permissions, archive->extraction_path, name , file_size, file_offset ) == FALSE )
						{
							g_free (name);
							g_free (permissions);
							return NULL;
						}
						end = gtk_tree_model_iter_next (model,&iter);
						g_free (name);
						g_free (permissions);
					}
					xa_set_button_state (1,1,0,1,1);
					OffTooltipPadlock();
					archive->status =XA_ARCHIVESTATUS_IDLE;
					Update_StatusBar ( _("Operation completed.") );
					break;
						
					default:
					command = NULL;
				}
				g_free (tar);

				if ( command != NULL )
					return command;
			}
			else
			{
				names = g_string_new ( " " );
				gtk_tree_selection_selected_foreach (selection, (GtkTreeSelectionForeachFunc) ConcatenateFileNames, names );
				command = xa_extract_single_files ( archive , names, archive->extraction_path );
				g_string_free (names, TRUE);
			}
		}
	}
	return command;
}

gchar *xa_extract_single_files ( XArchive *archive , GString *files, gchar *path)
{
	gchar *command = NULL;
	gchar *tar;

	gchar *msg = g_strdup_printf( _("Extracting archive to %s") , path);
	Update_StatusBar (msg);
	g_free (msg);
	tar = g_find_program_in_path ("gtar");
	if (tar == NULL)
		tar = g_strdup ("tar");
	switch (archive->type)
	{
		case XARCHIVETYPE_BZIP2:
		gzip_bzip2_extract (archive , 0);
		break;

		case XARCHIVETYPE_GZIP:
		gzip_bzip2_extract (archive , 1);
		break;

		case XARCHIVETYPE_RAR:
		if (archive->passwd != NULL)
			command = g_strconcat ( "rar " , archive->full_path ? "x " : "e " ,
									archive->freshen ? "-f " : "" , archive->update ? "-u " : "",
									" -p",archive->passwd,
									archive->overwrite ? " -o+" : " -o-",
									" -idp ",
									archive->escaped_path , " " , files->str , " " , path , NULL );
        else
			command = g_strconcat ( "rar ", archive->full_path ? "x " : "e " ,
									archive->freshen ? "-f " : "" , archive->update ? "-u " : "",
									archive->overwrite ? "-o+" : "-o-",
									" -idp ",
									archive->escaped_path , " " , files->str , " ", path ,NULL);
		break;

		case XARCHIVETYPE_TAR:
		if (archive->full_path == 1)
		{
			command = g_strconcat (tar, " -xvf " , archive->escaped_path,
								archive->overwrite ? " --overwrite" : " --keep-old-files",
								archive->tar_touch ? " --touch" : "",
								" -C " , path , files->str , NULL );
		}
		else
		{
			xa_extract_tar_without_directories ( "tar -xvf " , archive->escaped_path, archive->overwrite,archive->tar_touch,path, FALSE );
			command = NULL;
		}
		break;

		case XARCHIVETYPE_TAR_BZ2:
		if (archive->full_path == 1)
		{
			command = g_strconcat (tar, " -xjvf " , archive->escaped_path,
								archive->overwrite ? " --overwrite" : " --keep-old-files",
								archive->tar_touch ? " --touch" : "",
								" -C " , path , files->str , NULL );
		}
		else
		{
			xa_extract_tar_without_directories ( "tar -xjvf " , archive->escaped_path, archive->overwrite,archive->tar_touch,path, FALSE );
			command = NULL;
		}
		break;

		case XARCHIVETYPE_TAR_GZ:
		if (archive->full_path == 1)
		{
			command = g_strconcat (tar, " -xzvf " , archive->escaped_path,
								archive->overwrite ? " --overwrite" : " --keep-old-files",
								archive->tar_touch ? " --touch" : "",
								" -C " , path , files->str , NULL );
		}
		else
		{
			xa_extract_tar_without_directories ( "tar -xzvf " , archive->escaped_path, archive->overwrite,archive->tar_touch,path, FALSE );
			command = NULL;
		}
		break;

		case XARCHIVETYPE_ZIP:
        if ( archive->passwd != NULL )
			command = g_strconcat ( "unzip ", archive->freshen ? "-f " : "",
									archive->update ? "-u " : "",
									archive->overwrite ? "-o" : "-n",
									" -P " , archive->passwd,
									archive->full_path ? "" : " -j ",
									archive->escaped_path , files->str," -d " , path , NULL );
        else
			command = g_strconcat ( "unzip ", archive->freshen ? "-f " : "",
									archive->update ? "-u " : "",
									archive->overwrite ? "-o " : "-n ",
									archive->full_path ? "" : " -j ",
									archive->escaped_path , files->str," -d " , path , NULL );
		break;

        case XARCHIVETYPE_RPM:
        if (archive->full_path == 1)
		{
			chdir ( path );
			command = g_strconcat ( "cpio --make-directories " , files->str , " -F " , archive->tmp , " -i" , NULL);
		}
		else
		{
			xa_extract_tar_without_directories ( "tar -xvzf " , archive->escaped_path, archive->overwrite,archive->tar_touch,path , TRUE);
			command = NULL;
		}
        break;

        case XARCHIVETYPE_7ZIP:
        if ( archive->passwd != NULL)
			command = g_strconcat ("7za " , archive->full_path ? "x" : "e",
									" -p",archive->passwd,
									archive->overwrite ? " -aoa" : " -aos",
									" -bd ",
									archive->escaped_path , files->str , " -o" , path , NULL );
        else
			command = g_strconcat ( "7za " , archive->full_path ? "x" : "e",
									archive->overwrite ? " -aoa" : " -aos",
									" -bd ",
									archive->escaped_path , files->str , " -o" , path , NULL );
        break;

		case XARCHIVETYPE_ARJ:
		if (archive->passwd != NULL)
			command = g_strconcat ( "arj ",archive->full_path ? "x" : "e",
									" -g",archive->passwd,
									archive->overwrite ? "" : " -n" , 
									" -i " ,
									archive->freshen ? "-f " : "" ,
									archive->update ? "-u " : " ",
									"-y ",
									archive->escaped_path , " " , path , files->str , NULL );
        else
			command = g_strconcat ( "arj ",archive->full_path ? "x" : "e",
									archive->overwrite ? "" : " -n" ,
									" -i " , archive->freshen ? "-f " : "",
									archive->update ? "-u " : " ",
									"-y ",
									archive->escaped_path , " " , path , files->str, NULL );
		break;
		
		case XARCHIVETYPE_ISO:
		{
			GList *row_list = NULL;
			GtkTreeSelection *selection;

			selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW (treeview1) );
			row_list = gtk_tree_selection_get_selected_rows (selection, &model);
			while (row_list)
			{
				if (stop_flag)
					break;
				gtk_tree_model_get_iter(model, &iter, row_list->data);
				gtk_tree_model_get (model, &iter,
				0, &name,
				1, &permissions,
				2, &file_size,
				4, &file_offset,
				-1);
				gtk_tree_path_free (row_list->data);

				xa_extract_single_iso_file (archive, permissions, archive->extraction_path, name , file_size, file_offset );
				g_free (name);
				g_free (permissions);
				row_list = row_list->next;
			}
			g_list_free (row_list);
			xa_set_button_state (1,1,0,1,1);
			OffTooltipPadlock();
			archive->status =XA_ARCHIVESTATUS_IDLE;
			Update_StatusBar ( _("Operation completed.") );
			command = NULL;
		}
		break;

		default:
		command = NULL;
    }
	g_free (tar);
	return command;
}

gboolean xa_extract_tar_without_directories ( gchar *string, gchar *escaped_path, gboolean overwrite, gboolean tar_touch, gchar *extract_path, gboolean cpio_flag )
{
	gchar *command = NULL;
	gchar *name = NULL;
	gchar *permission = NULL;
	gchar tmp_dir[14] = "";
	GtkTreeSelection *selection;
	GString *names, *unescaped_names;
	gboolean end = FALSE;
	GtkTreeIter iter;
	GList *row_list;
	GSList *filenames = NULL;
	gboolean result;

	names = g_string_new ("");
	unescaped_names = g_string_new ("");
	selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW (treeview1) );
	row_list = gtk_tree_selection_get_selected_rows (selection, &model);
	
	if (row_list != NULL)
	{
		while (row_list)
		{
			gtk_tree_model_get_iter(model, &iter, row_list->data);
			gtk_tree_model_get (model, &iter,
								0, &name,
								1, &permission,
								-1);
			gtk_tree_path_free (row_list->data);

			if (strstr (permission ,"d") == NULL)
			{
				ConcatenateFileNames2 ( name , names );
				filenames = g_slist_append ( filenames,name );
			}
			g_free (permission);
			row_list = row_list->next;
		}
		g_list_free (row_list);
	}
	else
	{
		end = gtk_tree_model_get_iter_first (model , &iter);
		while (end)
		{
			gtk_tree_model_get (model, &iter,	0, &name,
												1, &permission, -1);
			if (strstr (permission ,"d") == NULL)
			{
				ConcatenateFileNames2 ( name , names );
				filenames = g_slist_append ( filenames,name );
			}
			g_free (permission);
			end = gtk_tree_model_iter_next (model,&iter);
		}
	}
	result = xa_create_temp_directory (tmp_dir);
	if (result == 0)
		return FALSE;

	if (cpio_flag)
	{
		chdir (tmp_dir);
		command = g_strconcat ( "cpio --make-directories -F " , archive->tmp , " -i" , NULL );
	}
	else
		command = g_strconcat ( string, escaped_path,
										overwrite ? " --overwrite" : " --keep-old-files",
										tar_touch ? " --touch" : "",
										" -C " , tmp_dir , names->str, NULL );
	result = xa_run_command (command , 0);
	g_string_free (names, TRUE);
	g_free (command);

	if (result == 0 || stop_flag)
	{
		xa_delete_temp_directory ( tmp_dir, 0 );
		gtk_widget_hide (viewport2);
		Update_StatusBar (_("Operation aborted."));
		return FALSE;
	}
	chdir (tmp_dir);
	while (filenames)
	{
		gchar *unescaped = EscapeBadChars ( filenames->data , "$\'`\"\\!?* ()[]&|@#:;");
		g_string_prepend ( unescaped_names, unescaped );
		g_string_prepend_c (unescaped_names, ' ');
		g_free (unescaped);
		filenames = filenames->next;
	}
	command = g_strconcat ( "mv -f ", unescaped_names->str, " " , extract_path , NULL );
	result = xa_run_command (command , 0);
	g_free (command);
	g_slist_free (filenames);
	g_string_free ( unescaped_names, TRUE );

	if (result == 0 || stop_flag)
	{
		xa_delete_temp_directory ( tmp_dir, 0 );
		gtk_widget_hide (viewport2);
		Update_StatusBar (_("Operation aborted."));
		return FALSE;
	}
	if (cpio_flag)
		xa_delete_temp_directory ( tmp_dir, 0 );
	else
		xa_delete_temp_directory ( tmp_dir, 1 );
	
	return result;
}

gboolean xa_delete_temp_directory ( gchar *dir_name, gboolean flag)
{
	gchar *command;
	gboolean result;

	command = g_strconcat ( "rm -rf ", dir_name , NULL );
	result = xa_run_command (command , flag );
	g_free (command);
	return result;
}

gboolean xa_create_temp_directory ( gchar tmp_dir[] )
{
	strcpy (tmp_dir,"/tmp/xa-XXXXXX");
	if ( mkdtemp ( tmp_dir ) == 0)
	{
		response = ShowGtkMessageDialog (GTK_WINDOW (MainWindow),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Can't create temporary directory in /tmp:"),g_strerror(errno) );
		gtk_widget_set_sensitive (Stop_button, FALSE);
		Update_StatusBar (_("Operation failed."));
		return FALSE;
	}
	return TRUE;
}

