1 /*
2  *  Copyright (C) 2008 Giuseppe Torelli - <colossus73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  *  MA 02110-1301 USA.
18  */
19 
20 #include "config.h"
21 #include <errno.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <gdk/gdkkeysyms.h>
26 #include <glib/gprintf.h>
27 #include <glib/gstdio.h>
28 #include <sys/stat.h>
29 #include "window.h"
30 #include "add_dialog.h"
31 #include "exe.h"
32 #include "extract_dialog.h"
33 #include "interface.h"
34 #include "main.h"
35 #include "mime.h"
36 #include "new_dialog.h"
37 #include "open-with-dlg.h"
38 #include "pref_dialog.h"
39 #include "string_utils.h"
40 #include "support.h"
41 #include "tar.h"
42 
43 #ifdef __APPLE__
44 #include <libkern/OSByteOrder.h>
45 #define le32toh(x) OSSwapLittleToHostInt32(x)
46 #elif defined(__FreeBSD__)
47 #include <sys/endian.h>
48 #else
49 #include <endian.h>
50 #endif
51 
52 #ifdef HAVE_SOCKET
53 #include "socket.h"
54 #endif
55 
56 #define	XDS_FILENAME "xds.txt"
57 #define bswap(word) (((word << 8) & 0xff00) | ((word >> 8) & 0x00ff))
58 
59 gchar *current_open_directory;
60 
61 static GtkWidget *comment_dialog;
62 
xa_remove_columns(XArchive * archive)63 static void xa_remove_columns (XArchive *archive)
64 {
65 	GList *columns = gtk_tree_view_get_columns ( GTK_TREE_VIEW (archive->treeview));
66 	while (columns != NULL)
67 	{
68 		gtk_tree_view_remove_column (GTK_TREE_VIEW (archive->treeview),columns->data);
69 		columns = columns->next;
70 	}
71 	g_list_free (columns);
72 }
73 
xa_open_file_dialog()74 static gchar *xa_open_file_dialog ()
75 {
76 	static GtkWidget *File_Selector = NULL;
77 	static GtkFileFilter *open_file_filter;
78 	GtkFileFilter *filter;
79 	GSList *sorted;
80 	gchar *path = NULL;
81 	int response;
82 
83 	if (File_Selector == NULL)
84 	{
85 		File_Selector = gtk_file_chooser_dialog_new ( _("Open an archive"),
86 						GTK_WINDOW (xa_main_window),
87 						GTK_FILE_CHOOSER_ACTION_OPEN,
88 						GTK_STOCK_CANCEL,
89 						GTK_RESPONSE_CANCEL,
90 						"gtk-open",
91 						GTK_RESPONSE_ACCEPT,
92 						NULL);
93 
94 		gtk_dialog_set_default_response (GTK_DIALOG (File_Selector),GTK_RESPONSE_ACCEPT);
95 		gtk_window_set_destroy_with_parent (GTK_WINDOW (File_Selector) ,TRUE);
96 
97 		filter = gtk_file_filter_new ();
98 		gtk_file_filter_set_name ( filter ,_("All files"));
99 		gtk_file_filter_add_pattern ( filter,"*");
100 		gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (File_Selector),filter);
101 
102 		filter = gtk_file_filter_new ();
103 		gtk_file_filter_set_name ( filter ,_("Only archives"));
104 		gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (File_Selector),filter);
105 
106 		sorted = xa_file_filter_add_archiver_pattern_sort(filter);
107 
108 		while (sorted)
109 		{
110 			filter = gtk_file_filter_new();
111 			gtk_file_filter_set_name(filter, sorted->data);
112 			gtk_file_filter_add_pattern(filter, sorted->data);
113 			gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(File_Selector), filter);
114 			sorted = sorted->next;
115 		}
116 
117 		g_slist_free(sorted);
118 
119 		gtk_window_set_modal (GTK_WINDOW (File_Selector),TRUE);
120 	}
121 	if (open_file_filter != NULL)
122 		gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (File_Selector) ,open_file_filter);
123 
124 	if (current_open_directory != NULL)
125 		gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER (File_Selector) ,current_open_directory);
126 
127 	response = gtk_dialog_run (GTK_DIALOG (File_Selector));
128 
129 	if (current_open_directory != NULL)
130 		g_free (current_open_directory);
131 
132 	current_open_directory = gtk_file_chooser_get_current_folder ( GTK_FILE_CHOOSER (File_Selector));
133 	open_file_filter = gtk_file_chooser_get_filter ( GTK_FILE_CHOOSER (File_Selector));
134 
135 	if (response == GTK_RESPONSE_ACCEPT)
136 		path = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER (File_Selector));
137 	else if ( (response == GTK_RESPONSE_CANCEL) || (response == GTK_RESPONSE_DELETE_EVENT))
138 		path = NULL;
139 
140 	/* Hiding the window instead of destroying it will preserve the pointers to the file chooser stuff */
141 	gtk_widget_hide (File_Selector);
142 	return path;
143 }
144 
xa_detect_archive_comment(int type,gchar * filename,XArchive * archive)145 static gboolean xa_detect_archive_comment (int type, gchar *filename, XArchive *archive)
146 {
147 	FILE *stream;
148 	char sig = '1';
149 	guint cmt_len = 0;
150 	int byte;
151 	unsigned char eocds[] = { 0x50,0x4b,0x05,0x06 };
152 	guint64 eocds_position = 0;
153 
154 	unsigned short int len = 0;
155 	int eof;
156 	size_t seqptr = 0;
157 
158 	stream = fopen (filename,"r");
159 	if (stream == NULL)
160 		return FALSE;
161 
162 	if (type == XARCHIVETYPE_ZIP)
163 	{
164 		/* Let's position the file indicator to 64KB before the end of the archive */
165 		if (fseek(stream, -65535 - 22, SEEK_END) == -1)
166 			fseek(stream, 0L, SEEK_SET);
167 		/* Let's reach the end of central directory signature now */
168 		while( ! feof(stream))
169 		{
170 			byte = (eof = fgetc(stream));
171 			if (eof == EOF)
172 				break;
173 			if (byte == eocds[seqptr])
174 			{
175 				if (++seqptr == sizeof(eocds))
176 				{
177 					eocds_position = ftell(stream) + 16 ;
178 					seqptr = 0;
179 				}
180 				continue;
181 			}
182 			else
183 			{
184 				if (seqptr)
185 					seqptr = 0;
186 			}
187 		}
188 		fseek (stream,eocds_position,SEEK_SET);
189 		fread(&len, sizeof(len), 1, stream);
190 		if (len == 0)
191 		{
192 			fclose(stream);
193 			return FALSE;
194 		}
195 		else
196 		{
197 			archive->comment = g_string_new("");
198 			while (cmt_len != len)
199 			{
200 				fread(&sig, sizeof(sig), 1, stream);
201 				g_string_append_c (archive->comment,sig);
202 				cmt_len++;
203 			}
204 			fclose(stream);
205 			return TRUE;
206 		}
207 	}
208 	else if (type == XARCHIVETYPE_ARJ)
209 	{
210 		/* Let's avoid the archive name */
211 		fseek ( stream,39 ,SEEK_SET);
212 		while (sig != 0)
213 		{
214 			fread(&sig, sizeof(sig), 1, stream);
215 			cmt_len++;
216 		}
217 		fseek ( stream,39 + cmt_len ,SEEK_SET);
218 		sig = 1;
219 		/* Let's read the archive comment byte after byte now */
220 		archive->comment = g_string_new("");
221 		while (sig != 0)
222 		{
223 			fread(&sig, sizeof(sig), 1, stream);
224 
225 			if (sig == 0 && archive->comment->len == 0)
226 			{
227 				g_string_free (archive->comment,FALSE);
228 				archive->comment = NULL;
229 				fclose(stream);
230 				return FALSE;
231 			}
232 			else
233 				g_string_append_c (archive->comment,sig);
234 		}
235 		fclose(stream);
236 		return TRUE;
237 	}
238 	fclose(stream);
239 	return FALSE;
240 }
241 
xa_set_size_string(guint64 file_size)242 static gchar *xa_set_size_string (guint64 file_size)
243 {
244 	gchar *message = NULL;
245 	gchar *measure;
246 	double content_size;
247 
248 	if (file_size > 1024*1024*1024)
249 	{
250 		content_size = (double)file_size / (1024*1024*1024);
251 		measure = "GB";
252 	}
253 	else if (file_size > 1024*1024)
254 	{
255 		content_size = (double)file_size / (1024*1024);
256 		measure = "MB";
257 	}
258 
259     else if (file_size > 1024)
260 	{
261 		content_size = (double)file_size / 1024;
262 		measure = "KB";
263 	}
264 	else
265 	{
266 		measure = "Bytes";
267 		content_size = file_size;
268 	}
269     message = g_strdup_printf ("%.1f %s",content_size,measure);
270 	return message;
271 }
272 
xa_print_entry_in_file(XEntry * entry,gint idx,FILE * stream,int bp)273 static void xa_print_entry_in_file (XEntry *entry, gint idx, FILE *stream, int bp)
274 {
275 	gchar *path, *path_utf8;
276 	static int x = 1;
277 	guint i;
278 	gpointer current_column;
279 	guint64 file_size = 0;
280 
281 	if (!entry)
282 		return;
283 
284     if (entry->filename && !entry->is_dir)
285     {
286 			current_column = entry->columns;
287 		/* Let's retrieve the sizes of the entry from its column */
288 		if (!g_utf8_validate(entry->filename, -1, NULL))
289 		{
290 			gchar *entry_utf8 = g_filename_display_name(entry->filename);
291 			g_free(entry->filename);
292 			entry->filename = entry_utf8;
293 		}
294 		path = xa_build_full_path_name_from_entry(entry);
295 		path_utf8 = g_filename_display_name(path);
296 		g_free(path);
297 		if (strlen(path_utf8) == 0)
298 			goto here;
299 		for (i = 2; i < archive[idx]->columns - 1; i++)
300 		{
301 			switch(archive[idx]->column_types[i])
302 			{
303 				case G_TYPE_STRING:
304 					current_column += sizeof(gchar *);
305 				break;
306 
307 				case G_TYPE_UINT64:
308 					file_size = (*((guint64 *)current_column));
309 					current_column += sizeof(guint64);
310 				break;
311 			}
312 		}
313 		if (bp)
314 		{
315 			g_fprintf(stream,"<tr class=\"row%d\">",x);
316 			g_fprintf(stream, "<td>%s</td><td>%" G_GUINT64_FORMAT "</td></tr>", path_utf8, file_size);
317 			if (x == 2)
318 				x = 1;
319 			else
320 				x = 2;
321 		}
322 		else
323 			g_fprintf(stream, "%-90s %" G_GUINT64_FORMAT "\n", path_utf8, file_size);
324 
325 		g_free(path_utf8);
326 	}
327 here:
328 	xa_print_entry_in_file(entry->child,idx,stream,bp);
329 	xa_print_entry_in_file(entry->next,idx,stream,bp);
330 }
331 
xa_open_sfx_file_selector()332 static gchar *xa_open_sfx_file_selector ()
333 {
334 	gchar *sfx_name = NULL;
335 	GtkWidget *sfx_file_selector = NULL;
336 	int response;
337 
338 	sfx_file_selector = gtk_file_chooser_dialog_new ( _("Save the self-extracting archive as"),
339 						GTK_WINDOW (xa_main_window),
340 						GTK_FILE_CHOOSER_ACTION_SAVE,
341 						GTK_STOCK_CANCEL,
342 						GTK_RESPONSE_CANCEL,
343 						"gtk-save",
344 						GTK_RESPONSE_ACCEPT,
345 						NULL);
346 
347 	gtk_dialog_set_default_response (GTK_DIALOG (sfx_file_selector),GTK_RESPONSE_ACCEPT);
348 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (sfx_file_selector),TRUE);
349 	response = gtk_dialog_run ( GTK_DIALOG(sfx_file_selector));
350 
351 	if (response == GTK_RESPONSE_ACCEPT)
352 		sfx_name = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER (sfx_file_selector));
353 
354 	gtk_widget_destroy (sfx_file_selector);
355 	return sfx_name;
356 }
357 
xa_activate_link(GtkAboutDialog * about,const gchar * link,gpointer user_data)358 static void xa_activate_link (GtkAboutDialog *about, const gchar *link, gpointer user_data)
359 {
360 	if (!xdg_open)
361 	{
362 		gchar *browser_path = NULL;
363 		browser_path = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(prefs_window->combo_prefered_web_browser));
364 		if (!browser_path || !*browser_path)
365 		{
366 			xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_INFO,GTK_BUTTONS_OK,_("You didn't set which browser to use!"),_("Please go to Preferences->Advanced and set it."));
367 			g_free (browser_path);
368 			return;
369 		}
370 		xa_launch_external_program(browser_path, link);
371 		g_free(browser_path);
372 	}
373 	else
374 		xa_launch_external_program(xdg_open, link);
375 }
376 
xa_rename_cell_edited_canceled(GtkCellRenderer * renderer,gpointer user_data)377 static void xa_rename_cell_edited_canceled (GtkCellRenderer *renderer, gpointer user_data)
378 {
379 	g_object_set(renderer,"editable",FALSE,NULL);
380 	gtk_widget_add_accelerator(delete_menu, "activate", accel_group, GDK_KEY_Delete, (GdkModifierType) 0, GTK_ACCEL_VISIBLE);
381 }
382 
xa_rename_cell_edited(GtkCellRendererText * cell,const gchar * path_string,const gchar * new_name,XArchive * archive)383 static void xa_rename_cell_edited (GtkCellRendererText *cell, const gchar *path_string, const gchar *new_name, XArchive *archive)
384 {
385 	GtkTreeIter iter;
386 	GtkTreeModel *model;
387 	XEntry *entry;
388 	gchar *old_name, *q_old_name, *q_new_name, *command;
389 	GSList *names = NULL, *file_list;
390 	gboolean result = FALSE;
391 
392 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(archive->treeview));
393 	if (gtk_tree_model_get_iter_from_string(model,&iter,path_string))
394 	{
395 		gtk_tree_model_get(model, &iter, archive->columns - 1, &entry, -1);
396 		if (entry->is_encrypted)
397 		{
398 			if (!xa_check_password(archive))
399 				goto done;
400 		}
401 		g_free(archive->extraction_dir);
402 		xa_create_working_directory(archive);
403 		archive->extraction_dir = g_strdup(archive->working_dir);
404 		old_name = xa_build_full_path_name_from_entry(entry);
405 		q_old_name = g_shell_quote(old_name);
406 		names = g_slist_append(names,old_name);
407 
408 		archive->do_overwrite = archive->do_full_path = TRUE;
409 
410 		archive->status = XARCHIVESTATUS_EXTRACT;
411 		result = (*archive->archiver->extract) (archive,names);
412 
413 		if (result == FALSE)
414 		{
415 			g_free(q_old_name);
416 			goto done;
417 		}
418 		/* Rename the file in the tmp dir as the new file entered by the user */
419 		q_new_name = g_shell_quote(new_name);
420 		if (strcmp(q_new_name, q_old_name) == 0)
421 		{
422 			g_free(q_old_name);
423 			g_free(q_new_name);
424 			goto done;
425 		}
426 		command = g_strconcat("mv -f ", archive->working_dir, "/", q_old_name, " ", archive->working_dir, "/", q_new_name, NULL);
427 		xa_run_command(archive, command);
428 		g_free(command);
429 		g_free(q_old_name);
430 		g_free(q_new_name);
431 
432 		/* Delete the selected file from the archive */
433 		old_name = xa_build_full_path_name_from_entry(entry);
434 		file_list = g_slist_append(NULL, old_name);
435 
436 		archive->status = XARCHIVESTATUS_DELETE;
437 		(*archive->archiver->delete)(archive, file_list);
438 
439 		/* Add the renamed file to the archive */
440 		file_list = g_slist_append(NULL, g_strdup(new_name));
441 		chdir(archive->working_dir);
442 		xa_execute_add_commands(archive, file_list, FALSE, NULL);
443 	}
444 done:
445 	xa_rename_cell_edited_canceled(GTK_CELL_RENDERER(cell), NULL);
446 }
447 
xa_get_archive_format(XArchive * archive)448 static const gchar *xa_get_archive_format (XArchive *archive)
449 {
450 	gint pos;
451 
452 	pos = g_slist_index(archiver[archive->type].tags, GUINT_TO_POINTER(archive->tag));
453 
454 	if (pos >= 0)
455 		return g_slist_nth_data(archiver[archive->type].tags, pos + 1);
456 	else
457 		return archiver[archive->type].type->data;
458 }
459 
xa_get_statusbar_message(guint64 total_size,gint n_elem,gint dirs,gboolean selection)460 static gchar *xa_get_statusbar_message (guint64 total_size, gint n_elem, gint dirs, gboolean selection)
461 {
462 	gchar *measure = NULL,*info = NULL;
463 	gchar *text = "";
464 
465 	measure = xa_set_size_string(total_size);
466 	if (selection)
467 		text = _("selected");
468 
469 	if (dirs)
470 	{
471 		if (n_elem)
472 		{
473 			gchar *format = g_strconcat(ngettext("%d file", "%d files", n_elem), " ", _("and"), " ", ngettext("%d dir %s (%s)", "%d dirs %s (%s)", dirs), NULL);
474 			info = g_strdup_printf(format, n_elem, dirs, text, measure);
475 			g_free(format);
476 		}
477 		else
478 			info = g_strdup_printf(ngettext ("%d dir %s (%s)","%d dirs %s (%s)",dirs),dirs,text,measure);
479 	}
480 	else
481 		info = g_strdup_printf(ngettext ("%d file %s (%s)","%d files %s (%s)",n_elem),n_elem,text,measure);
482 
483 	g_free(measure);
484 	return info;
485 }
486 
xa_set_environment(gpointer display)487 static void xa_set_environment (gpointer display)
488 {
489 	if (!g_getenv("WAYLAND_DISPLAY"))
490 		g_setenv("DISPLAY", display, TRUE);
491 }
492 
xa_determine_program_to_run(gchar * file)493 static void xa_determine_program_to_run (gchar *file)
494 {
495 	gchar *program;
496 
497 	if (xdg_open)
498 		program = g_strdup(xdg_open);
499 	else
500 	{
501 		gchar *basename;
502 		const char *type;
503 
504 		basename = g_path_get_basename(file);
505 		type = xa_get_stock_mime_icon(basename);
506 
507 		if (strcmp(type, "text-html") == 0)
508 		{
509 			program = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(prefs_window->combo_prefered_web_browser));
510 		}
511 		else if (strcmp(type, "text-x-generic") == 0)
512 		{
513 			program = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(prefs_window->combo_prefered_editor));
514 		}
515 		else if (strcmp(type, "image-x-generic") == 0)
516 			program = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(prefs_window->combo_prefered_viewer));
517 		else if (strcmp(type, "package-x-generic") == 0)
518 			program = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(prefs_window->combo_prefered_archiver));
519 		else
520 		{
521 			gchar *basename_utf8 = g_filename_display_name(basename);
522 			xa_create_open_with_dialog(basename_utf8, g_shell_quote(file), 1);
523 			g_free(basename_utf8);
524 			g_free(basename);
525 			return;
526 		}
527 
528 		g_free(basename);
529 	}
530 
531 	if (program && *program)
532 	{
533 		gchar *q_file = g_shell_quote(file);
534 		xa_launch_external_program(program, q_file);
535 		g_free(q_file);
536 	}
537 	else
538 		xa_show_message_dialog(GTK_WINDOW(xa_main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, _("You didn't set which program to use for opening this file!"), _("Please go to Preferences->Advanced and set it."));
539 
540 	g_free(program);
541 }
542 
xa_clear_comment_window(GtkButton * button,gpointer buf)543 static void xa_clear_comment_window (GtkButton *button, gpointer buf)
544 {
545 	GtkTextIter start,end;
546 
547 	gtk_text_buffer_get_iter_at_offset(buf,&start,0);
548 	gtk_text_buffer_get_end_iter(buf,&end);
549 	gtk_text_buffer_delete(buf,&start,&end);
550 }
551 
xa_load_comment_window_from_file(GtkButton * button,gpointer buf)552 static void xa_load_comment_window_from_file (GtkButton *button, gpointer buf)
553 {
554 	GtkTextMark *textmark;
555 	GtkTextIter iter;
556 	GtkWidget *file;
557 	gchar *path = NULL;
558 	gchar *utf8_data = NULL;
559 	gchar *content = NULL;
560 	GError *error = NULL;
561 	gboolean response;
562 	gsize bytes;
563 
564 	file = gtk_file_chooser_dialog_new (_("Open a text file"),
565 						GTK_WINDOW (xa_main_window),
566 						GTK_FILE_CHOOSER_ACTION_OPEN,
567 						GTK_STOCK_CANCEL,
568 						GTK_RESPONSE_CANCEL,
569 						"gtk-open",
570 						GTK_RESPONSE_ACCEPT,
571 						NULL);
572 
573 	response = gtk_dialog_run (GTK_DIALOG(file));
574 	if (response == GTK_RESPONSE_ACCEPT)
575 		path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file));
576 	gtk_widget_destroy (file);
577 	if (path != NULL)
578 	{
579 		response = g_file_get_contents(path, &content, &bytes, &error);
580 
581 		if (response == FALSE)
582 		{
583 			gchar *msg = g_strdup_printf (_("Can't open file %s:"),path);
584 			g_free(path);
585 			response = xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,
586 			msg,error->message);
587 			g_free (msg);
588 			g_error_free(error);
589 			return;
590 		}
591 		g_free(path);
592 
593 		if (g_utf8_validate(content, -1, NULL))
594 			utf8_data = content;
595 		else
596 		{
597 			utf8_data = g_locale_to_utf8(content, -1, NULL, &bytes, NULL);
598 			g_free(content);
599 		}
600 
601 		textmark = gtk_text_buffer_get_insert(buf);
602 		gtk_text_buffer_get_iter_at_mark(buf,&iter,textmark);
603 		gtk_text_buffer_insert_with_tags_by_name (buf,&iter,utf8_data,bytes,"font",NULL);
604 		g_free (utf8_data);
605 	}
606 }
607 
xa_comment_window_insert_in_archive(GtkButton * button,gpointer buf)608 static void xa_comment_window_insert_in_archive (GtkButton *button, gpointer buf)
609 {
610 	GtkTextIter start,end;
611 	FILE *stream;
612 	gint idx;
613 	gchar *command, *content, *tmp = NULL;
614 
615 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
616 
617 	gtk_text_buffer_get_iter_at_offset(buf,&start,0);
618 	gtk_text_buffer_get_end_iter(buf,&end);
619 	content = gtk_text_buffer_get_text(buf,&start,&end,FALSE);
620 
621 	xa_create_working_directory(archive[idx]);
622 	tmp = g_strconcat(archive[idx]->working_dir, "/xa-tmp.comment", NULL);
623 	gtk_widget_destroy(comment_dialog);
624 
625 	if (archive[idx]->comment == NULL)
626 	{
627 		archive[idx]->comment = g_string_new("");
628 		archive[idx]->has_comment = TRUE;
629 	}
630 	/* Return if the user hasn't modified the comment */
631 	if (strcmp(archive[idx]->comment->str,content) == 0)
632 		return;
633 
634 	stream = fopen (tmp,"w");
635 
636 	if (stream == NULL)
637 	{
638 		g_free(tmp);
639 		return;
640 	}
641 
642 	fwrite(content, strlen(content), 1, stream);
643 	fclose (stream);
644 
645 	switch (archive[idx]->type)
646 	{
647 		case XARCHIVETYPE_ARJ:
648 		command = g_strconcat ("arj c ",archive[idx]->path[1]," -z",tmp,NULL);
649 		break;
650 
651 		case XARCHIVETYPE_RAR:
652 		command = g_strconcat ("rar c ",archive[idx]->path[1]," -z",tmp,NULL);
653 		break;
654 
655 		case XARCHIVETYPE_ZIP:
656 		command = g_strconcat ("sh -c \"zip ",archive[idx]->path[1]," -z <",tmp,"\"",NULL);
657 		break;
658 
659 		default:
660 		command = NULL;
661 		break;
662 	}
663 	if (strlen(archive[idx]->comment->str) > 0)
664 		g_string_erase(archive[idx]->comment,0,strlen(archive[idx]->comment->str));
665 	if (strlen(content) > 0)
666 		g_string_append(archive[idx]->comment,content);
667 
668 	if (command != NULL)
669 	{
670 		xa_run_command(archive[idx], command);
671 		g_free(command);
672 	}
673 	g_free(tmp);
674 }
675 
xa_clipboard_data_new()676 static XAClipboard *xa_clipboard_data_new ()
677 {
678 	XAClipboard *data = NULL;
679 
680 	data = g_new0(XAClipboard,1);
681 
682 	return data;
683 }
684 
xa_get_paste_data_from_clipboard_selection(const guchar * data)685 static XAClipboard *xa_get_paste_data_from_clipboard_selection (const guchar *data)
686 {
687 	gchar **uris;
688 	gint i;
689 	XAClipboard *clipboard_data;
690 
691 	clipboard_data = xa_clipboard_data_new();
692 	uris = g_strsplit((const gchar *) data,"\r\n",-1);
693 	clipboard_data->mode = (strcmp(uris[0], "copy") == 0 ? XA_CLIPBOARD_COPY : XA_CLIPBOARD_CUT);
694 	sscanf(uris[1], "%p", &clipboard_data->target);
695 	for (i = 2; uris[i]; i++)
696 		if (uris[i][0] != '\0')
697 			clipboard_data->files = g_slist_prepend (clipboard_data->files,g_strdup (uris[i]));
698 	clipboard_data->files = g_slist_reverse (clipboard_data->files);
699 	g_strfreev(uris);
700 	return clipboard_data;
701 }
702 
xa_clipboard_get(GtkClipboard * clipboard,GtkSelectionData * selection_data,guint info,XArchive * archive)703 static void xa_clipboard_get (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, XArchive *archive)
704 {
705 	GSList *files = archive->clipboard->files;
706 	GString *params = g_string_new("");
707 	if (gtk_selection_data_get_target(selection_data) != XA_INFO_LIST)
708 		return;
709 
710 	g_string_append(params, archive->clipboard->mode == XA_CLIPBOARD_COPY ? "copy" : "cut");
711 	g_string_append (params,"\r\n");
712 	g_string_append_printf (params,"%p",archive);
713 	g_string_append (params,"\r\n");
714 
715 	while (files)
716 	{
717 		g_string_append(params, files->data);
718 		g_string_append (params,"\r\n");
719 		files = files->next;
720 	}
721 	gtk_selection_data_set(selection_data, gtk_selection_data_get_target(selection_data), 8, (guchar *) params->str, strlen(params->str));
722 	g_string_free (params,TRUE);
723 }
724 
xa_clipboard_cut_copy_operation(XArchive * archive,XAClipboardMode mode)725 static void xa_clipboard_cut_copy_operation (XArchive *archive, XAClipboardMode mode)
726 {
727 	GtkClipboard *clipboard;
728 	XAClipboard *clipboard_data = NULL;
729 	GSList *files = NULL;
730 	GtkTreeSelection *selection;
731 	GtkTargetEntry targets[] =
732 	{
733 		{ "application/xarchiver-info-list",0,1 }
734 	};
735 
736 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(archive->treeview));
737 	gtk_tree_selection_selected_foreach(selection,(GtkTreeSelectionForeachFunc) xa_concat_selected_filenames,&files);
738 
739 	clipboard = gtk_clipboard_get (XA_CLIPBOARD);
740 	clipboard_data = xa_clipboard_data_new();
741 	if (clipboard_data == NULL)
742 		return;
743 
744 	clipboard_data->files = xa_slist_copy(files);
745 	clipboard_data->mode  = mode;
746 	gtk_clipboard_set_with_data(clipboard, targets, G_N_ELEMENTS(targets), (GtkClipboardGetFunc) xa_clipboard_get, (GtkClipboardClearFunc) xa_clipboard_clear, archive);
747 	archive->clipboard = clipboard_data;
748 	gtk_widget_set_sensitive(paste,TRUE);
749 
750 	/* Let's extract the selected files to the archive tmp dir */
751 	if (archive->has_password)
752 	{
753 		if (!xa_check_password(archive))
754 			return;
755 	}
756 	g_free(archive->extraction_dir);
757 	xa_create_working_directory(archive);
758 	archive->extraction_dir = g_strdup(archive->working_dir);
759 	archive->do_full_path = TRUE;
760 	archive->do_overwrite = TRUE;
761 
762 	archive->status = XARCHIVESTATUS_EXTRACT;
763 	(*archive->archiver->extract) (archive,files);
764 }
765 
xa_expand_containing_directory(XArchive * archive)766 static void xa_expand_containing_directory (XArchive *archive)
767 {
768 	if (xa_has_containing_directory(archive))
769 	{
770 		GtkTreePath *path;
771 		GtkTreeSelection *selection;
772 
773 		path = gtk_tree_path_new_first();
774 		gtk_tree_view_expand_to_path(GTK_TREE_VIEW(archive_dir_treeview), path);
775 		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(archive_dir_treeview));
776 		gtk_tree_selection_select_path(selection, path);
777 		gtk_tree_selection_unselect_path(selection, path);
778 		gtk_tree_path_free(path);
779 	}
780 }
781 
xa_child_processed(XAChildProcess process,gboolean success,XArchive * archive)782 void xa_child_processed (XAChildProcess process, gboolean success, XArchive *archive)
783 {
784 	static gboolean okay[XA_CHILD_PROCS];
785 
786 	okay[process] = success;
787 
788 	if (process == XA_CHILD_EXIT)
789 	{
790 		archive->child_pid = 0;
791 
792 		if (xa_main_window)
793 		{
794 			gtk_widget_set_sensitive(Stop_button, FALSE);
795 			xa_set_button_state(1, 1, 1, 1, archive->can_test, 1, archive->can_add, archive->can_extract, archive->sorted, archive->can_sfx, archive->has_comment, archive->output, archive->has_password);
796 		}
797 	}
798 
799 	if (--archive->child_ref == 0)
800 	{
801 		if (archive->output)
802 			archive->output = g_slist_reverse(archive->output);
803 
804 		if (okay[XA_CHILD_EXIT] && okay[XA_CHILD_STDOUT] && okay[XA_CHILD_STDERR])
805 		{
806 			if (xa_main_window)
807 			{
808 				if (archive->parse_output)
809 				{
810 					xa_block_signal_dir_treeview_selection(TRUE);
811 					gtk_widget_grab_focus(archive_dir_treeview);
812 					xa_block_signal_dir_treeview_selection(FALSE);
813 					xa_update_window_with_archive_entries(archive, NULL);
814 					xa_expand_containing_directory(archive);
815 					gtk_tree_view_set_model(GTK_TREE_VIEW(archive->treeview), archive->model);
816 					g_object_unref(archive->model);
817 				}
818 
819 				xa_set_statusbar_message_for_displayed_rows(archive);
820 
821 				if (archive->status == XARCHIVESTATUS_LIST && archive->has_comment && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs_window->check_show_comment)))
822 					xa_show_archive_comment(NULL, NULL);
823 
824 				if (archive->status == XARCHIVESTATUS_TEST)
825 				{
826 					if (archive->output)
827 						xa_show_archive_output(GUINT_TO_POINTER(TRUE), archive);
828 					else
829 						xa_show_message_dialog(GTK_WINDOW(xa_main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, _("Test result:"), _("The archive is okay."));
830 				}
831 			}
832 
833 			archive->parse_output = NULL;
834 			archive->status = XARCHIVESTATUS_IDLE;
835 		}
836 		else
837 		{
838 			if (xa_main_window && archive->parse_output)
839 			{
840 				xa_update_window_with_archive_entries(archive, NULL);
841 				archive->parse_output = NULL;
842 			}
843 
844 			if (xa_main_window && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs_window->store_output)))
845 				xa_show_message_dialog(GTK_WINDOW(xa_main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("An error occurred!"), _("Please check the 'Store archiver output' option to see it."));
846 			else
847 				xa_show_archive_output(NULL, archive);
848 
849 			if (xa_main_window)
850 				gtk_label_set_text(GTK_LABEL(total_label), _("An error occurred!"));
851 
852 			/* in case the user has supplied a wrong password, reset it so they can try again */
853 			if (archive->password && (archive->status == XARCHIVESTATUS_TEST || archive->status == XARCHIVESTATUS_SFX))
854 			{
855 				g_free(archive->password);
856 				archive->password = NULL;
857 			}
858 
859 			archive->status = XARCHIVESTATUS_ERROR;
860 		}
861 	}
862 }
863 
xa_reload_archive_content(XArchive * this_archive)864 void xa_reload_archive_content (XArchive *this_archive)
865 {
866 	XEntry *entry;
867 
868 	g_slist_free(this_archive->forward);
869 	this_archive->forward = NULL;
870 
871 	g_slist_free(this_archive->back);
872 	this_archive->back = NULL;
873 
874 	xa_free_entry(this_archive, this_archive->root_entry);
875 
876 	g_free(this_archive->column_types);
877 	xa_remove_columns(this_archive);
878 
879 	entry = g_new0(XEntry,1);
880 	entry->filename = "";
881 	this_archive->root_entry = entry;
882 
883 	gtk_label_set_text(GTK_LABEL(total_label), _("Reloading archive, please wait..."));
884 
885 	/* this reload will be called internally during adding and deleting */
886 	this_archive->status = XARCHIVESTATUS_RELOAD;
887 	(*this_archive->archiver->list)(this_archive);
888 }
889 
xa_show_archive_output(GtkMenuItem * menuitem,XArchive * this_archive)890 void xa_show_archive_output (GtkMenuItem *menuitem, XArchive *this_archive)
891 {
892 	GSList *output = NULL;
893 	gchar *title = NULL, *cmd;
894 	GtkWidget *dialog, *show_cmd, *label, *image, *hbox, *vbox, *textview, *scrolledwindow;
895 	GtkTextBuffer *textbuffer;
896 	GtkTextIter iter;
897 	gint response;
898 
899 	if (this_archive == NULL)
900 	{
901 		gint idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
902 
903 		if (idx < 0)
904 			return;
905 		this_archive = archive[idx];
906 	}
907 
908 	if (xa_main_window)
909 		title = _("Archiver output");
910 	else
911 		title = PACKAGE_NAME " " VERSION;
912 
913 	dialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(xa_main_window), GTK_DIALOG_MODAL, NULL, NULL);
914 
915 	show_cmd = gtk_dialog_add_button(GTK_DIALOG(dialog), _("Show command"), GTK_RESPONSE_APPLY);
916 	gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);
917 	gtk_dialog_set_default_response (GTK_DIALOG (dialog),GTK_RESPONSE_OK);
918 
919 	gtk_container_set_border_width (GTK_CONTAINER (dialog),6);
920 	gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), 6);
921 	gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), 8);
922 	gtk_widget_set_size_request(dialog, 672, 420);
923 
924 	scrolledwindow = gtk_scrolled_window_new (NULL,NULL);
925 	g_object_set (G_OBJECT (scrolledwindow),"hscrollbar-policy",GTK_POLICY_AUTOMATIC,"shadow-type",GTK_SHADOW_IN,"vscrollbar-policy",GTK_POLICY_AUTOMATIC,NULL);
926 	gtk_widget_set_size_request (scrolledwindow,-1,200);
927 
928 	textbuffer = gtk_text_buffer_new (NULL);
929 	gtk_text_buffer_create_tag (textbuffer,"font","family","monospace",NULL);
930 	gtk_text_buffer_get_iter_at_offset (textbuffer,&iter,0);
931 
932 	textview = gtk_text_view_new_with_buffer (textbuffer);
933 	g_object_unref (textbuffer);
934 	gtk_text_view_set_editable (GTK_TEXT_VIEW (textview),FALSE);
935 	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview),FALSE);
936 
937 	vbox = gtk_vbox_new (FALSE,6);
938 	gtk_container_set_border_width (GTK_CONTAINER (vbox),5);
939 
940 	if (!menuitem)
941 	{
942 		image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,GTK_ICON_SIZE_DIALOG);
943 		gtk_misc_set_alignment (GTK_MISC (image),0.5,0.0);
944 
945 		label = gtk_label_new (_("An error occurred while accessing the archive:"));
946 		hbox = gtk_hbox_new (FALSE,6);
947 		gtk_box_pack_start (GTK_BOX (hbox),image,FALSE,FALSE,0);
948 		gtk_box_pack_start (GTK_BOX (hbox),label,TRUE,TRUE,0);
949 		gtk_box_pack_start (GTK_BOX (vbox),hbox,FALSE,FALSE,0);
950 	}
951 	gtk_container_add (GTK_CONTAINER (scrolledwindow),textview);
952 	gtk_box_pack_start (GTK_BOX (vbox),scrolledwindow,TRUE,TRUE,0);
953 	gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox, TRUE, TRUE, 0);
954 
955 	output = this_archive->output;
956 	while (output)
957 	{
958 		gtk_text_buffer_insert_with_tags_by_name(textbuffer, &iter, output->data, -1, "font", NULL);
959 		output = output->next;
960 	}
961 	gtk_widget_show_all (vbox);
962 
963 run_dialog:
964 	response = gtk_dialog_run(GTK_DIALOG(dialog));
965 
966 	if (response == GTK_RESPONSE_APPLY)
967 	{
968 		gtk_text_buffer_get_iter_at_offset(textbuffer, &iter, 0);
969 		cmd = g_strdup_printf("%s: %s\n\n", _("Command"), this_archive->command);
970 		gtk_text_buffer_insert_with_tags_by_name(textbuffer, &iter, cmd, -1, "font", NULL);
971 		g_free(cmd);
972 		gtk_widget_hide(show_cmd);
973 		goto run_dialog;
974 	}
975 
976 	gtk_widget_destroy (GTK_WIDGET (dialog));
977 }
978 
xa_new_archive(GtkMenuItem * menuitem,gpointer user_data)979 void xa_new_archive (GtkMenuItem *menuitem,gpointer user_data)
980 {
981 	gint current_page;
982 
983 	current_page = xa_get_new_archive_idx();
984 	if (current_page == -1)
985 		return;
986 
987 	archive[current_page] = xa_new_archive_dialog(NULL, archive);
988 
989 	if (archive[current_page] == NULL)
990 		return;
991 
992 	xa_add_page (archive[current_page]);
993 	xa_set_button_state(1, 1, 1, 1, archive[current_page]->can_test, 1, archive[current_page]->can_add, archive[current_page]->can_extract, archive[current_page]->sorted, archive[current_page]->can_sfx, archive[current_page]->has_comment, archive[current_page]->output, archive[current_page]->has_password);
994     xa_disable_delete_buttons(FALSE);
995 
996 	xa_set_window_title(xa_main_window, archive[current_page]->path[0]);
997 	gtk_label_set_text(GTK_LABEL(total_label),"");
998 }
999 
xa_show_message_dialog(GtkWindow * window,int mode,int type,int button,const gchar * message1,const gchar * message2)1000 int xa_show_message_dialog (GtkWindow *window,int mode,int type,int button,const gchar *message1,const gchar *message2)
1001 {
1002 	GtkWidget *dialog;
1003 	int response;
1004 
1005 	dialog = gtk_message_dialog_new (window,mode,type,button,"%s",message1);
1006 	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),"%s",message2);
1007 	response = gtk_dialog_run (GTK_DIALOG (dialog));
1008 	gtk_widget_destroy (GTK_WIDGET (dialog));
1009 	return response;
1010 }
1011 
xa_save_archive(GtkMenuItem * menuitem,gpointer user_data)1012 void xa_save_archive (GtkMenuItem *menuitem, gpointer user_data)
1013 {
1014 	gint idx;
1015 	GtkWidget *save = NULL;
1016 	gchar *path = NULL, *command, *filename, *filename_utf8;
1017 	int response;
1018 
1019 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1020 
1021 	save = gtk_file_chooser_dialog_new (_("Save the archive as"),
1022 						GTK_WINDOW (xa_main_window),
1023 						GTK_FILE_CHOOSER_ACTION_SAVE,
1024 						GTK_STOCK_CANCEL,
1025 						GTK_RESPONSE_CANCEL,
1026 						"gtk-save",
1027 						GTK_RESPONSE_ACCEPT,
1028 						NULL);
1029 	filename = g_path_get_basename(archive[idx]->path[1]);
1030 	filename_utf8 = g_filename_display_name(filename);
1031 	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save), filename_utf8);
1032 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (save),TRUE);
1033 	g_free(filename_utf8);
1034 	g_free(filename);
1035 	response = gtk_dialog_run (GTK_DIALOG(save));
1036 	if (response == GTK_RESPONSE_ACCEPT)
1037 		path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(save));
1038 	gtk_widget_destroy (save);
1039 	if (path != NULL)
1040 	{
1041 		command = g_strconcat ("cp ",archive[idx]->path[1]," ",path,NULL);
1042 		g_free(path);
1043 		xa_run_command(archive[idx], command);
1044 		g_free(command);
1045 	}
1046 }
1047 
xa_open_archive(GtkWidget * widget,gchar * path)1048 void xa_open_archive (GtkWidget *widget, gchar *path)
1049 {
1050 	gchar *utf8_path,*msg;
1051 	gint current_page;
1052 	gint x;
1053 	ArchiveType xa;
1054 
1055 	if (path == NULL)
1056     {
1057 		path = xa_open_file_dialog ();
1058 		if (path == NULL)
1059 			return;
1060 	}
1061 
1062 	/* Let's check if the archive is already opened */
1063 	for (x = 0; x < gtk_notebook_get_n_pages (notebook); x++)
1064 	{
1065 		current_page = xa_find_archive_index (x);
1066 		if (current_page == -1)
1067 			break;
1068 		if (strcmp(path, archive[current_page]->path[0]) == 0)
1069 		{
1070 			g_free (path);
1071 			gtk_notebook_set_current_page (notebook,current_page);
1072 			return;
1073 		}
1074 	}
1075 	xa = xa_detect_archive_type(path);
1076 
1077 	if (xa.type == XARCHIVETYPE_UNKNOWN || xa.type == XARCHIVETYPE_NOT_FOUND)
1078 	{
1079 		utf8_path = g_filename_to_utf8 (path,-1,NULL,NULL,NULL);
1080 		msg = g_strdup_printf (_("Can't open file \"%s\":"),utf8_path);
1081 		if (xa.type == XARCHIVETYPE_UNKNOWN)
1082 			xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,msg,_("Archive format is not recognized!"));
1083 		else
1084 			xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,msg,g_strerror(errno));
1085 
1086 		g_free (utf8_path);
1087 		g_free (msg);
1088 		g_free (path);
1089 		return;
1090 	}
1091 
1092 	if (!archiver[xa.type].list)
1093 	{
1094 		xa_show_message_dialog(GTK_WINDOW(xa_main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Sorry, this archive format is not supported:"), _("The proper archiver is not installed!"));
1095 		g_free(path);
1096 		return;
1097 	}
1098 
1099 	current_page = xa_get_new_archive_idx();
1100 	if (current_page == -1)
1101 	{
1102 		g_free (path);
1103 		return;
1104 	}
1105 	archive[current_page] = xa_init_archive_structure(xa);
1106 	if (archive[current_page] == NULL)
1107 	{
1108 		xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Can't allocate memory for the archive structure:"),_("Operation aborted!"));
1109 		g_free (path);
1110 		return;
1111 	}
1112 	/* Detect archive comment,rar one is detected in rar.c */
1113 	if (xa.type == XARCHIVETYPE_ZIP)
1114 		archive[current_page]->has_comment = xa_detect_archive_comment (XARCHIVETYPE_ZIP,path,archive[current_page]);
1115 	else if (xa.type == XARCHIVETYPE_ARJ)
1116 		archive[current_page]->has_comment = xa_detect_archive_comment (XARCHIVETYPE_ARJ,path,archive[current_page]);
1117 
1118 	if (g_path_is_absolute(path) == FALSE)
1119 		archive[current_page]->path[0] = g_strconcat(g_get_current_dir() ,"/", path, NULL);
1120 	else
1121 		archive[current_page]->path[0] = g_strdup(path);
1122 
1123 	archive[current_page]->path[1] = xa_escape_bad_chars(archive[current_page]->path[0], ESCAPES);
1124 	xa_add_page (archive[current_page]);
1125 
1126 	xa_disable_delete_buttons (FALSE);
1127 	g_free (path);
1128 
1129 	xa_set_button_state(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
1130 	gtk_label_set_text(GTK_LABEL(total_label),_("Opening archive, please wait..."));
1131 
1132 	archive[current_page]->status = XARCHIVESTATUS_LIST;
1133 	(*archive[current_page]->archiver->list)(archive[current_page]);
1134 }
1135 
xa_test_archive(GtkMenuItem * menuitem,gpointer user_data)1136 void xa_test_archive (GtkMenuItem *menuitem,gpointer user_data)
1137 {
1138 	gint idx;
1139 
1140 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1141 
1142 	if (archive[idx]->has_password)
1143 	{
1144 		if (!xa_check_password(archive[idx]))
1145 			return;
1146 	}
1147 	gtk_label_set_text(GTK_LABEL(total_label),_("Testing archive, please wait..."));
1148 
1149 	archive[idx]->status = XARCHIVESTATUS_TEST;
1150 	(*archive[idx]->archiver->test)(archive[idx]);
1151 }
1152 
xa_list_archive(GtkMenuItem * menuitem,gpointer data)1153 void xa_list_archive (GtkMenuItem *menuitem,gpointer data)
1154 {
1155 	unsigned short int bp = GPOINTER_TO_UINT(data);
1156 	gint idx;
1157 	FILE *stream;
1158 	GtkWidget *save = NULL;
1159 	gchar *t, *_filename, *filename, *filename_plus, *filename_plus_utf8, *pref_path, *pref_path_local = NULL;
1160 	int response;
1161 	struct stat my_stat;
1162 	guint64 file_size;
1163 
1164 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1165 
1166 	if (bp)
1167 		_filename = _("Print the archive content as HTML");
1168 	else
1169 		_filename = _("Print the archive content as text");
1170 
1171 	save = gtk_file_chooser_dialog_new (_filename,
1172 						GTK_WINDOW (xa_main_window),
1173 						GTK_FILE_CHOOSER_ACTION_SAVE,
1174 						GTK_STOCK_CANCEL,
1175 						GTK_RESPONSE_CANCEL,
1176 						"gtk-save",
1177 						GTK_RESPONSE_ACCEPT,
1178 						NULL);
1179 
1180 	filename = g_path_get_basename(archive[idx]->path[1]);
1181 	_filename = strstr(filename,".");
1182 	if (_filename)
1183 		_filename = g_strndup(filename,(_filename-filename));
1184 	else
1185 		_filename = filename;
1186 
1187 	filename_plus = g_strconcat (_filename,bp ? ".html" : ".txt",NULL);
1188 	filename_plus_utf8 = g_filename_display_name(filename_plus);
1189 	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save), filename_plus_utf8);
1190 	gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (save),TRUE);
1191 	g_free(filename);
1192 	g_free(filename_plus);
1193 	g_free(filename_plus_utf8);
1194 	filename = NULL;
1195 
1196 	pref_path = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(prefs_window->combo_prefered_extract_dir));
1197 
1198 	if (pref_path && *pref_path)
1199 		pref_path_local = g_filename_from_utf8(pref_path, -1, NULL, NULL, NULL);
1200 	g_free(pref_path);
1201 
1202 	if (current_open_directory || pref_path_local)
1203 		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save), pref_path_local ? pref_path_local : current_open_directory);
1204 	g_free(pref_path_local);
1205 	response = gtk_dialog_run (GTK_DIALOG(save));
1206 
1207 	if (current_open_directory != NULL)
1208 		g_free (current_open_directory);
1209 
1210 	current_open_directory = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(save));
1211 
1212 	if (response == GTK_RESPONSE_ACCEPT)
1213 		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(save));
1214 	gtk_widget_destroy (save);
1215 
1216 	if (filename != NULL)
1217 	{
1218 		stream = fopen (filename,"w");
1219 		g_free(filename);
1220 
1221 		if (stream == NULL)
1222 			return;
1223 
1224 		filename = g_filename_display_name(archive[idx]->path[1]);
1225 		if (bp)
1226 		{
1227 			g_fprintf(stream, "<html><head><meta charset=\"UTF-8\"><meta name=GENERATOR content=\"" PACKAGE_NAME " " VERSION "\"><title>%s</title>\n", filename);
1228 			g_fprintf (stream,"<style>\ntd     { font: normal .7em ; }\nth     { font: bold 0.7em ; color: #FFFFFF; text-align: left; background: #42578A}\n.row1  { background-color: #DDDDDD; }\n.row2  { background-color: #EEEEEE; }\n</style>\n");
1229 			g_fprintf(stream,"</head>");
1230 			g_fprintf (stream,"<body bgcolor=#FFFFFF>\n");
1231 			g_fprintf (stream,"<b><u>");
1232 		}
1233 		g_fprintf (stream,_("Archive content:\n"));
1234 
1235 		if (bp)
1236 			g_fprintf(stream, "</u></b><br><br><b>");
1237 		g_fprintf (stream,_("\nName: "));
1238 		if (bp)
1239 			g_fprintf(stream, "</b><a href=\"file://%s\">", filename);
1240 		g_fprintf(stream, "%s\n", filename);
1241 		if (bp)
1242 			g_fprintf(stream,"</a><br><br><b>");
1243 		stat(archive[idx]->path[0], &my_stat);
1244     	file_size = my_stat.st_size;
1245     	t = xa_set_size_string(file_size);
1246 		g_fprintf (stream,_("Compressed   size: "));
1247     	if (bp)
1248     		g_fprintf (stream,"</b>");
1249     	g_fprintf (stream,"%s\n",t);
1250     	g_free(t);
1251     	if (bp)
1252 			g_fprintf(stream,"<br><br><b>");
1253     	g_fprintf (stream,_("Uncompressed size: "));
1254     	t = xa_set_size_string(archive[idx]->files_size);
1255     	if (bp)
1256     		g_fprintf (stream,"</b>");
1257     	g_fprintf (stream,"%s\n",t);
1258     	g_free(t);
1259     	if (bp)
1260 			g_fprintf(stream,"<br><br><b>");
1261     	g_fprintf (stream,_("Number of files: "));
1262     	if (bp)
1263 			g_fprintf(stream,"</b>");
1264 		g_fprintf(stream, "%u\n", archive[idx]->files);
1265 		if (bp)
1266 			g_fprintf(stream,"<br><br><b>");
1267 		if (archive[idx]->has_comment)
1268 		{
1269 			g_fprintf (stream,_("Comment:\n"));
1270 			if (bp)
1271 				g_fprintf(stream,"</b><pre>");
1272 			g_fprintf (stream,"%s",archive[idx]->comment->str);
1273 			if (bp)
1274 				g_fprintf(stream,"</pre>");
1275 			g_fprintf (stream,"\n");
1276 			if (bp)
1277 				g_fprintf(stream,"<br>");
1278 		}
1279 		if ( ! bp)
1280 		{
1281 			g_fprintf (stream,"-------------------------------------------------------------------------------------------------------------\n");
1282 			g_fprintf(stream, _("Files:%*s%s"), 80, " ", _("|Size\n"));
1283 			g_fprintf (stream,"-------------------------------------------------------------------------------------------------------------\n");
1284 		}
1285 		else
1286 		{
1287 			g_fprintf(stream,"<br><table border=0 cellpadding=6 cellspacing=1><tr>");
1288 			g_fprintf(stream,_("<th>Files:</th>"));
1289 			g_fprintf(stream, _("<th>Size:</th>"));
1290 			g_fprintf(stream, "</tr>");
1291 
1292 		}
1293 		xa_print_entry_in_file(archive[idx]->root_entry,idx,stream,bp);
1294 		if (bp)
1295 			g_fprintf (stream,"</table></body></html>");
1296 
1297 		g_free(filename);
1298 		fclose (stream);
1299 	}
1300 }
1301 
xa_close_archive(GtkWidget * widget,gpointer page)1302 void xa_close_archive (GtkWidget *widget, gpointer page)
1303 {
1304 	gint current_page;
1305 	gint idx;
1306 
1307 	current_page = gtk_notebook_page_num(notebook, page);
1308 	idx = xa_find_archive_index (current_page);
1309 	gtk_notebook_remove_page ( notebook ,current_page);
1310 
1311 	current_page = gtk_notebook_get_n_pages(notebook);
1312 	if (current_page == 0)
1313 	{
1314 		gtk_widget_set_sensitive (up_button,FALSE);
1315 		gtk_widget_set_sensitive (home_button,FALSE);
1316 		gtk_widget_set_sensitive (deselect_all,FALSE);
1317 		xa_disable_delete_buttons (FALSE);
1318 		xa_set_button_state(1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
1319 		xa_set_window_title (xa_main_window,NULL);
1320 		gtk_tree_store_clear(archive_dir_treestore);
1321 		gtk_entry_set_text(GTK_ENTRY(location_entry),"");
1322 		gtk_label_set_text(GTK_LABEL(total_label),_("Select \"New\" to create or \"Open\" to open an archive"));
1323 		gtk_widget_hide(selected_frame);
1324 	}
1325 	else if ( current_page == 1)
1326 		gtk_notebook_set_show_tabs (notebook,FALSE);
1327 	else
1328 		gtk_notebook_set_show_tabs (notebook,TRUE);
1329 
1330 	xa_clean_archive_structure (archive[idx]);
1331 	archive[idx] = NULL;
1332 }
1333 
xa_quit_application(GtkWidget * widget,GdkEvent * event,gpointer user_data)1334 void xa_quit_application (GtkWidget *widget, GdkEvent *event, gpointer user_data)
1335 {
1336 	gint i;
1337 	gint idx;
1338 
1339 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1340 
1341 	if (idx > -1 && archive[idx]->child_pid)
1342 		return;
1343 
1344 	for (i = 0; i < gtk_notebook_get_n_pages(notebook) ; i++)
1345 	{
1346 		idx = xa_find_archive_index (i);
1347 		if (archive[idx] != NULL)
1348 		{
1349 			xa_clean_archive_structure (archive[idx]);
1350 			archive[idx] = NULL;
1351 		}
1352 	}
1353 
1354 	if (current_open_directory != NULL)
1355 		g_free (current_open_directory);
1356 
1357 	xa_prefs_save_options (prefs_window,config_file);
1358 	gtk_widget_destroy(prefs_window->dialog1);
1359 	g_free(prefs_window);
1360 
1361 	gtk_widget_destroy (extract_window->dialog1);
1362 	g_free(extract_window);
1363 
1364 	gtk_widget_destroy (add_window->dialog1);
1365 	g_free(add_window);
1366 
1367 	gtk_widget_destroy (multi_extract_window->multi_extract);
1368 	g_free(multi_extract_window);
1369 
1370 	gtk_widget_destroy(xa_popup_menu);
1371 	g_free (config_file);
1372 	xa_free_icon_cache();
1373 
1374 #ifdef HAVE_SOCKET
1375 	socket_finalize();
1376 #endif
1377 	gtk_main_quit();
1378 	return;
1379 }
1380 
xa_delete_archive(GtkMenuItem * menuitem,gpointer user_data)1381 void xa_delete_archive (GtkMenuItem *menuitem,gpointer user_data)
1382 {
1383 	GList  *row_list = NULL;
1384 	XEntry *entry = NULL;
1385 	GtkTreeIter iter;
1386 	GSList *list = NULL;
1387 	gint idx, response;
1388 
1389 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1390 
1391 	GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(archive[idx]->treeview));
1392 
1393 	row_list = gtk_tree_selection_get_selected_rows(selection, &archive[idx]->model);
1394 	if (row_list != NULL)
1395 	{
1396 		while (row_list)
1397 		{
1398 			gtk_tree_model_get_iter(archive[idx]->model, &iter, row_list->data);
1399 			gtk_tree_model_get(archive[idx]->model, &iter, archive[idx]->columns - 1, &entry, -1);
1400 			gtk_tree_path_free (row_list->data);
1401 
1402 			list = g_slist_prepend(list, xa_build_full_path_name_from_entry(entry));
1403 
1404 			if (entry->is_dir)
1405 				xa_fill_list_with_recursed_entries(entry->child, &list);
1406 
1407 			row_list = row_list->next;
1408 		}
1409 		g_list_free (row_list);
1410 	}
1411 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs_window->confirm_deletion)))
1412 	{
1413 		response = xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_QUESTION,GTK_BUTTONS_OK_CANCEL,_("You are about to delete entries from the archive."),_( "Are you sure you want to do this?"));
1414 		if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT)
1415 			return;
1416 	}
1417 
1418 	archive[idx]->status = XARCHIVESTATUS_DELETE;
1419 	(*archive[idx]->archiver->delete)(archive[idx], list);
1420 	xa_reload_archive_content(archive[idx]);
1421 }
1422 
xa_add_files_archive(GtkMenuItem * menuitem,gpointer user_data)1423 void xa_add_files_archive (GtkMenuItem *menuitem, gpointer user_data)
1424 {
1425 	gint idx;
1426 
1427 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1428 
1429 	xa_set_add_dialog_options(add_window,archive[idx]);
1430 	xa_parse_add_dialog_options (archive[idx],add_window);
1431 }
1432 
xa_extract_archive(GtkMenuItem * menuitem,gpointer user_data)1433 void xa_extract_archive (GtkMenuItem *menuitem,gpointer user_data)
1434 {
1435 	gint idx, selected;
1436 
1437 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1438 
1439 	GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(archive[idx]->treeview));
1440 	selected = gtk_tree_selection_count_selected_rows (selection);
1441 	xa_set_extract_dialog_options(extract_window,selected,archive[idx]);
1442     xa_parse_extract_dialog_options(archive[idx],extract_window,selection);
1443 }
1444 
xa_show_prefs_dialog(GtkMenuItem * menuitem,gpointer user_data)1445 void xa_show_prefs_dialog (GtkMenuItem *menuitem,gpointer user_data)
1446 {
1447 	int response;
1448 
1449 	if (prefs_window == NULL)
1450 		prefs_window = xa_create_prefs_dialog();
1451 
1452 	gtk_widget_show_all (prefs_window->dialog1);
1453 	xa_prefs_iconview_changed(GTK_ICON_VIEW(prefs_window->iconview), prefs_window);
1454 	response = gtk_dialog_run (GTK_DIALOG(prefs_window->dialog1));
1455 	gtk_widget_hide (prefs_window->dialog1);
1456 
1457 	if (response == GTK_RESPONSE_OK)
1458 		xa_prefs_apply_options(prefs_window);
1459 }
1460 
xa_convert_sfx(GtkMenuItem * menuitem,gpointer user_data)1461 void xa_convert_sfx (GtkMenuItem *menuitem ,gpointer user_data)
1462 {
1463 	gchar *command;
1464 	gboolean result;
1465 	gint idx;
1466 
1467 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1468 
1469     archive[idx]->status = XARCHIVESTATUS_SFX;
1470     switch ( archive[idx]->type)
1471 	{
1472 		case XARCHIVETYPE_RAR:
1473 			command = g_strconcat ("rar s -o+ ",archive[idx]->path[1],NULL);
1474 			xa_run_command(archive[idx], command);
1475 			g_free(command);
1476 		break;
1477 
1478 	    case XARCHIVETYPE_ZIP:
1479 		{
1480 			gchar *archive_name = NULL;
1481 			gchar *archive_name_quoted;
1482 			FILE *sfx_archive;
1483 			FILE *archive_not_sfx;
1484 			gchar *content;
1485             gsize length;
1486             GError *error = NULL;
1487 			gchar *unzipsfx_path = NULL;
1488 			gchar buffer[1024];
1489 
1490 			archive_name = xa_open_sfx_file_selector();
1491 
1492 			if (archive_name == NULL)
1493 				return;
1494 
1495 			archive_name_quoted = g_shell_quote(archive_name);
1496 			unzipsfx_path = g_find_program_in_path ("unzipsfx");
1497 			if (unzipsfx_path != NULL)
1498 			{
1499 				/* Load the unzipsfx executable in memory,about 50 KB */
1500 				result = g_file_get_contents (unzipsfx_path,&content,&length,&error);
1501 				if ( ! result)
1502 				{
1503 					xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Can't convert the archive to self-extracting:"),error->message);
1504 					g_error_free (error);
1505 					g_free (unzipsfx_path);
1506 					return;
1507 				}
1508 				g_free (unzipsfx_path);
1509 
1510 				/* Write unzipsfx to a new file */
1511 				sfx_archive = fopen ( archive_name ,"w");
1512 				if (sfx_archive == NULL)
1513 				{
1514 					xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Can't write the unzipsfx module to the archive:"),g_strerror(errno));
1515 					return;
1516 				}
1517 				fwrite(content, length, 1, sfx_archive);
1518 				g_free (content);
1519 
1520 				archive_not_sfx = fopen(archive[idx]->path[0], "r");
1521 
1522 				if (archive_not_sfx == NULL)
1523 				{
1524 					fclose(sfx_archive);
1525 					return;
1526 				}
1527 
1528 				/* Read archive data and write it after the sfx module in the new file */
1529 				while ( ! feof(archive_not_sfx))
1530 				{
1531 					fread(&buffer, sizeof(buffer), 1, archive_not_sfx);
1532 					fwrite(&buffer, sizeof(buffer), 1, sfx_archive);
1533 				}
1534 				fclose (archive_not_sfx);
1535 				fclose (sfx_archive);
1536 
1537 				g_chmod(archive_name, 0755);
1538 				command = g_strconcat ("zip -A ",archive_name_quoted,NULL);
1539 				xa_run_command(archive[idx], command);
1540 				g_free(command);
1541 			}
1542 			g_free (archive_name);
1543 			g_free (archive_name_quoted);
1544 		}
1545         break;
1546 
1547         case XARCHIVETYPE_7ZIP:
1548         {
1549         	gchar *archive_name = NULL;
1550 			gchar *archive_name_quoted;
1551 			FILE *sfx_archive;
1552 			FILE *archive_not_sfx;
1553 			gchar *content;
1554             gsize length;
1555             GError *error = NULL;
1556 			gchar *sfx_path = NULL;
1557 			gchar buffer[1024];
1558 			int response;
1559 			GtkWidget *locate_7zcon = NULL;
1560 			GtkFileFilter *sfx_filter;
1561 
1562         	archive_name = xa_open_sfx_file_selector ();
1563 
1564 			if (archive_name == NULL)
1565 				return;
1566 			archive_name_quoted = g_shell_quote(archive_name);
1567 
1568 			if (g_file_test ( "/usr/lib/p7zip/7zCon.sfx",G_FILE_TEST_EXISTS))
1569 				sfx_path = g_strdup("/usr/lib/p7zip/7zCon.sfx");
1570 			else if (g_file_test ( "/usr/local/lib/p7zip/7zCon.sfx",G_FILE_TEST_EXISTS))
1571 				sfx_path = g_strdup ("/usr/local/lib/p7zip/7zCon.sfx");
1572 			else if (g_file_test ( "/usr/libexec/p7zip/7zCon.sfx",G_FILE_TEST_EXISTS))
1573 				sfx_path = g_strdup ("/usr/libexec/p7zip/7zCon.sfx");
1574 			else
1575 			{
1576 				sfx_filter = gtk_file_filter_new ();
1577 				gtk_file_filter_set_name (sfx_filter,"");
1578 				gtk_file_filter_add_pattern (sfx_filter,"*.sfx");
1579 
1580 				locate_7zcon = gtk_file_chooser_dialog_new ( _("Please select the 7zCon.sfx module"),
1581 						GTK_WINDOW (xa_main_window),
1582 						GTK_FILE_CHOOSER_ACTION_OPEN,
1583 						GTK_STOCK_CANCEL,
1584 						GTK_RESPONSE_CANCEL,
1585 						"gtk-open",
1586 						GTK_RESPONSE_ACCEPT,
1587 						NULL);
1588 
1589 				gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (locate_7zcon),sfx_filter);
1590 				gtk_dialog_set_default_response (GTK_DIALOG (locate_7zcon),GTK_RESPONSE_ACCEPT);
1591 				response = gtk_dialog_run (GTK_DIALOG(locate_7zcon));
1592 				if (response == GTK_RESPONSE_ACCEPT)
1593 				{
1594 					sfx_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(locate_7zcon));
1595 					gtk_widget_destroy (locate_7zcon);
1596 				}
1597 				else
1598 				{
1599 					gtk_widget_destroy (locate_7zcon);
1600 					return;
1601 				}
1602 			}
1603 			if ( sfx_path != NULL)
1604 			{
1605 				/* Load the 7zCon.sfx executable in memory ~ 500 KB; is it too much for 128 MB equipped PCs ? */
1606 				result = g_file_get_contents (sfx_path,&content,&length,&error);
1607 				if ( ! result)
1608 				{
1609 					response = xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Can't convert the archive to self-extracting:"),error->message);
1610 					g_error_free (error);
1611 					g_free (sfx_path);
1612 					return;
1613 				}
1614 				g_free (sfx_path);
1615 
1616 				/* Write 7zCon.sfx to a new file */
1617 				sfx_archive = fopen ( archive_name ,"w");
1618 				if (sfx_archive == NULL)
1619 				{
1620 					response = xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Can't write the unzipsfx module to the archive:"),g_strerror(errno));
1621 					return;
1622 				}
1623 				fwrite(content, length, 1, sfx_archive);
1624 				g_free (content);
1625 
1626 				archive_not_sfx = fopen(archive[idx]->path[0], "r");
1627 
1628 				if (archive_not_sfx == NULL)
1629 				{
1630 					fclose(sfx_archive);
1631 					return;
1632 				}
1633 
1634 				/* Read archive data and write it after the sfx module in the new file */
1635 				while ( ! feof(archive_not_sfx))
1636 				{
1637 					fread(&buffer, sizeof(buffer), 1, archive_not_sfx);
1638 					fwrite(&buffer, sizeof(buffer), 1, sfx_archive);
1639 				}
1640 				fclose (archive_not_sfx);
1641 				fclose (sfx_archive);
1642 
1643 				command = g_strconcat ("chmod 755 ",archive_name_quoted,NULL);
1644 				xa_run_command(archive[idx], command);
1645 				g_free(command);
1646 			}
1647 			g_free (archive_name);
1648 			g_free (archive_name_quoted);
1649 		}
1650 		break;
1651 
1652 		case XARCHIVETYPE_ARJ:
1653         	command = g_strconcat ("arj y -je1 " ,archive[idx]->path[1],NULL);
1654         	xa_run_command(archive[idx], command);
1655         	g_free(command);
1656 		break;
1657 
1658 		default:
1659 		command = NULL;
1660 	}
1661 }
1662 
xa_about(GtkMenuItem * menuitem,gpointer user_data)1663 void xa_about (GtkMenuItem *menuitem,gpointer user_data)
1664 {
1665     static GtkWidget *about = NULL;
1666     const char *authors[] =
1667     {
1668         "",
1669         "This version:",
1670         MAINTAINER " <ib@wupperonline.de>",
1671         "",
1672         "Original developer:",
1673         "Giuseppe Torelli <colossus73@gmail.com>",
1674         "",
1675         "Archive navigation code:",
1676         "John Berthels",
1677         "",
1678         "Code fixing:",
1679         "Enrico Tröger",
1680         "",
1681         "LHA and DEB support:",
1682         "Łukasz Zemczak <sil2100@vexillium.org>",
1683         "",
1684         "LZMA support:",
1685         "Thomas Dy <dysprosium66@gmail.com>",
1686         "",
1687         "LZOP support:",
1688         "Kevin Day",
1689         "",
1690         "RARv5, XZ, TAR.XZ support:",
1691         "Frederick GUERIN <fguerin01@gmail.com>",
1692         "",
1693         "GTK+ 3 port:",
1694         "Balló György <ballogyor@gmail.com>",
1695         "",
1696         NULL
1697     };
1698     const char *documenters[] =
1699     {
1700         "",
1701         "Special thanks to Bjoern Martensen for",
1702         "bugs hunting and " PACKAGE_NAME "'s Tango logo.",
1703         "",
1704         "Thanks to:",
1705         "Benedikt Meurer",
1706         "Stephan Arts",
1707         "Bruno Jesus <00cpxxx@gmail.com>",
1708         "Uracile for the stunning logo",
1709         "",
1710         NULL
1711     };
1712 
1713 	if (about == NULL)
1714 	{
1715 		about = gtk_about_dialog_new ();
1716 		GTK_COMPAT_ABOUT_DIALOG_URI(about, xa_activate_link);
1717 		gtk_window_set_position (GTK_WINDOW (about),GTK_WIN_POS_CENTER_ON_PARENT);
1718 		gtk_window_set_transient_for (GTK_WINDOW (about),GTK_WINDOW (xa_main_window));
1719 		gtk_window_set_destroy_with_parent (GTK_WINDOW (about),TRUE);
1720 		g_object_set (about,
1721 			"program-name", PACKAGE_NAME,
1722 			"version",PACKAGE_VERSION,
1723 			"copyright","Copyright \xC2\xA9 " COPYRIGHT_YEAR " " COPYRIGHT_HOLDER "\n"
1724 			            "Copyright \xC2\xA9 " MAINTAINER_YEAR " " MAINTAINER,
1725 			"comments",_("A GTK+ only lightweight archive manager"),
1726 			"authors",authors,
1727 			"documenters",documenters,
1728 			"translator_credits",_("translator-credits"),
1729 			"logo_icon_name","xarchiver",
1730 			"website","https://wiki.github.com/ib/xarchiver",
1731 			"license","Copyright \xC2\xA9 " COPYRIGHT_YEAR " " COPYRIGHT_HOLDER " - Colossus <colossus73@gmail.com>\n"
1732 			          "Copyright \xC2\xA9 " MAINTAINER_YEAR " " MAINTAINER "\n\n"
1733 					"This program is free software; you can redistribute it and/or modify it\n"
1734 					"under the terms of the GNU General Public License as published by the\n"
1735 					"Free Software Foundation; either version 2 of the License, or (at your option)\n"
1736 					"any later version.\n"
1737 					"\n"
1738 					"This program is distributed in the hope that it will be useful, but WITHOUT\n"
1739 					"ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n"
1740 					"or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n"
1741 					"License for more details.\n"
1742 					"\n"
1743 					"You should have received a copy of the GNU General Public License\n"
1744 					"along with this program; if not, write to the Free Software Foundation, Inc.,\n"
1745 					"51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.",
1746 		      NULL);
1747 	}
1748 	gtk_dialog_run ( GTK_DIALOG(about));
1749 	gtk_widget_hide (about);
1750 }
1751 
xa_detect_archive_type(const gchar * filename)1752 ArchiveType xa_detect_archive_type (const gchar *filename)
1753 {
1754 	FILE *file;
1755 	unsigned char magic[14];
1756 	long bytes;
1757 	uint32_t *uint32_magic = (uint32_t *) magic;
1758 	unsigned short *short_magic = (unsigned short *) magic;
1759 	ArchiveType xa = {XARCHIVETYPE_UNKNOWN, 0};
1760 
1761 	file = fopen(filename, "r");
1762 
1763 	if (!file)
1764 	{
1765 		xa.type = XARCHIVETYPE_NOT_FOUND;
1766 		return xa;
1767 	}
1768 
1769 	memset(magic, 0, sizeof(magic));
1770 	bytes = fread(magic, 1, sizeof(magic), file);
1771 
1772 	/* lz4 and zstd skippable frame */
1773 	while (memcmp(magic + 1, "\x2a\x4d\x18", 3) == 0 && (magic[0] & 0xf0) == 0x50 && bytes >= 8)
1774 	{
1775 		uint32_t frame_size = le32toh(uint32_magic[1]);
1776 
1777 		fseek(file, -bytes + 8, SEEK_CUR);
1778 
1779 		if (frame_size > 0x7fffffff)
1780 		{
1781 			fseek(file, 0x7fffffff, SEEK_CUR);
1782 			frame_size -= 0x7fffffff;
1783 		}
1784 
1785 		fseek(file, frame_size, SEEK_CUR);
1786 
1787 		memset(magic, 0, sizeof(magic));
1788 		bytes = fread(magic, 1, sizeof(magic), file);
1789 	}
1790 
1791 	if (memcmp(magic, "7z" "\xbc\xaf\x27\x1c", 6) == 0)
1792 		xa.type = XARCHIVETYPE_7ZIP;
1793 	else if (memcmp(magic, "!<arch>\n", 8) == 0)
1794 	{
1795 		xa.type = XARCHIVETYPE_AR;
1796 
1797 		if (memcmp(magic + 8, "debian", 6) == 0)
1798 			xa.tag = 'd';
1799 	}
1800 	else if (memcmp(magic, "\x60\xea", 2) == 0)
1801 		xa.type = XARCHIVETYPE_ARJ;
1802 	else if (memcmp(magic, "BZh", 3) == 0)
1803 		xa.type = XARCHIVETYPE_BZIP2;
1804 	else if (memcmp(magic, "\x1f\x9d", 2) == 0)
1805 		xa.type = XARCHIVETYPE_COMPRESS;
1806 	else if (memcmp(magic, "070701", 6) == 0 ||
1807 	         memcmp(magic, "070702", 6) == 0 ||
1808 	         memcmp(magic, "070707", 6) == 0 ||
1809 	         *short_magic == 070707 ||
1810 	         *short_magic == bswap(070707))
1811 	{
1812 		xa.type = XARCHIVETYPE_CPIO;
1813 
1814 		if (*short_magic == bswap(070707))
1815 			/* different endianness */
1816 			xa.tag = 'E';
1817 	}
1818 	else if (memcmp(magic, "\x1f\x8b", 2) == 0 ||
1819 	         memcmp(magic, "\x1f\x9e", 2) == 0)
1820 		xa.type = XARCHIVETYPE_GZIP;
1821 	else if ((memcmp(magic + 2, "-lh", 3) == 0 && ((magic[5] >= '0' && magic[5] <= '7') || magic[5] == 'd') && magic[6] == '-') ||
1822 	         (memcmp(magic + 2, "-lz", 3) == 0 && (magic[5] == '4' || magic[5] == '5' || magic[5] == 's') && magic[6] == '-'))
1823 		xa.type = XARCHIVETYPE_LHA;
1824 	else if (memcmp(magic, "LRZI", 4) == 0)
1825 		xa.type = XARCHIVETYPE_LRZIP;
1826 	else if (memcmp(magic, "\x04\x22\x4d\x18", 4) == 0 ||
1827 	         memcmp(magic, "\x02\x21\x4c\x18", 4) == 0)
1828 		xa.type = XARCHIVETYPE_LZ4;
1829 	else if (memcmp(magic, "LZIP", 4) == 0)
1830 		xa.type = XARCHIVETYPE_LZIP;
1831 	else if (memcmp(magic, "\x5d\x00\x00", 3) == 0)
1832 		xa.type = XARCHIVETYPE_LZMA;
1833 	else if (memcmp(magic, "\211LZO", 4) == 0)
1834 		xa.type = XARCHIVETYPE_LZOP;
1835 	else if (memcmp(magic, "Rar!" "\x1a\x07\x00", 7) == 0 ||
1836 	         memcmp(magic, "Rar!" "\x1a\x07\x01", 7) == 0)
1837 	{
1838 		xa.type = XARCHIVETYPE_RAR;
1839 
1840 		if (magic[6] == 1)
1841 			xa.tag = 5;
1842 
1843 		/* a rar5 archive without a rar v5 compatible executable can't be opened */
1844 		if ((xa.tag == 5) && !g_slist_find(archiver[xa.type].tags, GUINT_TO_POINTER(xa.tag)))
1845 			archiver[xa.type].list = NULL;
1846 	}
1847 	else if (memcmp(magic, "\xed\xab\xee\xdb", 4) == 0)
1848 		xa.type = XARCHIVETYPE_RPM;
1849 	else if (memcmp(magic, "\xfd" "7zXZ" "\x00", 6) == 0)
1850 		xa.type = XARCHIVETYPE_XZ;
1851 	else if (memcmp(magic, "PK" "\x03\x04", 4) == 0 ||
1852 	         memcmp(magic, "PK" "\x05\x06", 4) == 0 ||
1853 	         memcmp(magic + 4, "PK" "\x01\x02", 4) == 0)
1854 	{
1855 		xa.type = XARCHIVETYPE_ZIP;
1856 
1857 		if (g_str_has_suffix(filename, ".apk"))
1858 			xa.tag = 'a';
1859 		else if (g_str_has_suffix(filename, ".cbz"))
1860 			xa.tag = 'c';
1861 		else if (g_str_has_suffix(filename, ".epub"))
1862 			xa.tag = 'e';
1863 		else if (g_str_has_suffix(filename, ".jar"))
1864 			xa.tag = 'j';
1865 		else if (g_str_has_suffix(filename, ".oxt"))
1866 			xa.tag = 'o';
1867 		else if (g_str_has_suffix(filename, ".xpi"))
1868 			xa.tag = 'x';
1869 	}
1870 	else if (g_str_has_suffix(filename, ".exe") && (memcmp(magic, "MZ", 2) == 0))
1871 		xa = exetype(file);
1872 	else if (memcmp(magic + 1, "\xb5\x2f\xfd", 3) == 0 &&
1873 	         (*magic == '\x1e' || (*magic >= '\x22' && *magic <= '\x28')))
1874 		xa.type = XARCHIVETYPE_ZSTD;
1875 	/* partly heuristic methods must come last */
1876 	else if (isTar(file))
1877 		xa.type = XARCHIVETYPE_TAR;
1878 
1879 	fclose(file);
1880 
1881 	return xa;
1882 }
1883 
xa_create_liststore(XArchive * archive,const gchar * titles[])1884 void xa_create_liststore (XArchive *archive, const gchar *titles[])
1885 {
1886 	guint i;
1887 	GtkCellRenderer *renderer;
1888 	GtkTreeViewColumn *column;
1889 
1890 	/* check for batch mode */
1891 	if (!xa_main_window)
1892 		return;
1893 
1894 	archive->liststore = gtk_list_store_newv(archive->columns, archive->column_types);
1895 	gtk_tree_view_set_model ( GTK_TREE_VIEW (archive->treeview),GTK_TREE_MODEL (archive->liststore));
1896 
1897 	archive->model = GTK_TREE_MODEL(archive->liststore);
1898 
1899 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs_window->check_sort_filename_column)))
1900 	{
1901 		gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(archive->model), 1, GTK_SORT_ASCENDING);
1902 		archive->sorted = TRUE;
1903 	}
1904 
1905 	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(archive->liststore), 1, (GtkTreeIterCompareFunc) xa_sort_dirs_before_files, archive, NULL);
1906 
1907 	g_object_ref(archive->model);
1908 	gtk_tree_view_set_model(GTK_TREE_VIEW(archive->treeview),NULL);
1909 
1910 	/* icon and filename */
1911 	column = gtk_tree_view_column_new();
1912 	archive->pixbuf_renderer = gtk_cell_renderer_pixbuf_new();
1913 	gtk_tree_view_column_pack_start(column, archive->pixbuf_renderer, FALSE);
1914 	gtk_tree_view_column_set_attributes(column, archive->pixbuf_renderer, "pixbuf", 0, NULL);
1915 
1916 	archive->text_renderer = gtk_cell_renderer_text_new();
1917 	gtk_tree_view_column_pack_start(column, archive->text_renderer, TRUE);
1918 	gtk_tree_view_column_set_attributes(column, archive->text_renderer, "text", 1, NULL);
1919 	gtk_tree_view_column_set_title(column,_("Filename"));
1920 	gtk_tree_view_column_set_resizable (column,TRUE);
1921 	gtk_tree_view_column_set_sort_column_id (column,1);
1922 	gtk_tree_view_append_column (GTK_TREE_VIEW (archive->treeview),column);
1923 	gtk_tree_view_column_set_sizing (column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1924 	g_signal_connect(archive->text_renderer, "editing-canceled", G_CALLBACK(xa_rename_cell_edited_canceled), archive);
1925 	g_signal_connect(archive->text_renderer, "edited", G_CALLBACK(xa_rename_cell_edited), archive);
1926 
1927 	/* archive's individual items */
1928 	for (i = 0; i < archive->columns - 3; i++)
1929 	{
1930 		renderer = gtk_cell_renderer_text_new();
1931 		column = gtk_tree_view_column_new_with_attributes(titles[i], renderer, "text", i + 2, NULL);
1932 		gtk_tree_view_column_set_resizable(column, TRUE);
1933 		gtk_tree_view_column_set_sort_column_id(column, i + 2);
1934 		gtk_tree_view_append_column(GTK_TREE_VIEW(archive->treeview), column);
1935 	}
1936 
1937 	/* internally used pointer to XEntry (invisible) */
1938 	column = gtk_tree_view_column_new();
1939 	gtk_tree_view_column_set_visible(column, FALSE);
1940 	gtk_tree_view_append_column(GTK_TREE_VIEW(archive->treeview), column);
1941 }
1942 
treeview_select_search(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer user_data)1943 gboolean treeview_select_search (GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer user_data)
1944 {
1945     char *filename;
1946     gboolean result;
1947 
1948     gtk_tree_model_get(model,iter,1,&filename,-1);
1949     if (strcasestr (filename,key))
1950     	result = FALSE;
1951 	else
1952 		result = TRUE;
1953     g_free (filename);
1954     return result;
1955 }
1956 
xa_cancel_archive(GtkMenuItem * menuitem,gpointer user_data)1957 void xa_cancel_archive (GtkMenuItem *menuitem, gpointer user_data)
1958 {
1959 	gint idx, response;
1960 
1961 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1962 	if (gtk_widget_get_visible(multi_extract_window->multi_extract))
1963 	{
1964 		multi_extract_window->stop_pressed = TRUE;
1965 		kill (multi_extract_window->archive->child_pid,SIGINT);
1966 	}
1967 	else
1968 	{
1969 		if (archive[idx]->status == XARCHIVESTATUS_ADD || archive[idx]->status == XARCHIVESTATUS_SFX)
1970 		{
1971 			response = xa_show_message_dialog (GTK_WINDOW(xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_QUESTION,GTK_BUTTONS_OK_CANCEL,_("Doing so will probably corrupt your archive!"),_("Do you really want to cancel?"));
1972 			if (response == GTK_RESPONSE_CANCEL)
1973 				return;
1974 		}
1975 		if (archive[idx]->child_pid)
1976 			kill (archive[idx]->child_pid,SIGINT);
1977 
1978 		gtk_label_set_text(GTK_LABEL(total_label),"");
1979 		/* !!! setting total_label isn't enough cleanup to be done !!! */
1980 	}
1981 }
1982 
xa_archive_properties(GtkMenuItem * menuitem,gpointer user_data)1983 void xa_archive_properties (GtkMenuItem *menuitem,gpointer user_data)
1984 {
1985 	GtkWidget *archive_properties_window;
1986 	struct stat my_stat;
1987     gchar *utf8_string ,*dummy_string,*t;
1988     char date[64];
1989 	gint idx;
1990 	guint64 file_size;
1991 	double content_size;
1992 
1993 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
1994     if (stat(archive[idx]->path[0], &my_stat) == 0)
1995 		file_size = my_stat.st_size;
1996 	else
1997 		file_size = 0;
1998     archive_properties_window = xa_create_archive_properties_window();
1999     dummy_string = g_path_get_basename(archive[idx]->path[1]);
2000     utf8_string = g_filename_display_name(dummy_string);
2001 	gtk_label_set_text(GTK_LABEL(name_data),utf8_string);
2002 	g_free (utf8_string);
2003     g_free(dummy_string);
2004     /* Path */
2005     dummy_string = xa_remove_level_from_path(archive[idx]->path[0]);
2006     if (strlen(dummy_string) == 0 || strcmp(dummy_string,"..") == 0 || strcmp(dummy_string,".") == 0)
2007 		utf8_string = g_filename_display_name (g_get_current_dir());
2008     else
2009 		utf8_string = g_filename_display_name (dummy_string);
2010     g_free ( dummy_string);
2011 
2012     gtk_label_set_text(GTK_LABEL(path_data),utf8_string);
2013     g_free ( utf8_string);
2014 	/* Type */
2015 	gtk_label_set_text(GTK_LABEL(type_data), xa_get_archive_format(archive[idx]));
2016 	/* archiver */
2017 	t = g_strconcat(archiver[archive[idx]->type].program[0], archiver[archive[idx]->type].program[1] ? "\n" : "", archiver[archive[idx]->type].program[1], NULL);
2018 	utf8_string = g_filename_display_name(t);
2019 	gtk_label_set_text(GTK_LABEL(archiver_data), utf8_string);
2020 	g_free(utf8_string);
2021 	g_free(t);
2022     /* Modified Date */
2023     strftime (date,64,"%c",localtime (&my_stat.st_mtime));
2024     t = g_locale_to_utf8(date, -1, NULL, NULL, NULL);
2025     gtk_label_set_text(GTK_LABEL(modified_data),t);
2026     g_free (t);
2027     /* Archive Size */
2028 	t = xa_set_size_string(file_size);
2029     gtk_label_set_text(GTK_LABEL(size_data),t);
2030     g_free (t);
2031     /* content_size */
2032     t = xa_set_size_string(archive[idx]->files_size);
2033     gtk_label_set_text(GTK_LABEL(content_data),t);
2034     g_free (t);
2035     /* Has Comment */
2036     if (archive[idx]->has_comment)
2037 		gtk_label_set_text(GTK_LABEL(comment_data),_("Yes"));
2038 	else
2039 		gtk_label_set_text(GTK_LABEL(comment_data),_("No"));
2040 
2041     /* Compression_ratio */
2042     if (file_size)
2043     {
2044       content_size = (double) archive[idx]->files_size / file_size;
2045       t = g_strdup_printf("%.2f:1", content_size);
2046     }
2047     else
2048       t = g_strdup("-");
2049     gtk_label_set_text(GTK_LABEL(compression_data),t);
2050     g_free (t);
2051     /* Number of files */
2052     t = g_strdup_printf("%u", archive[idx]->files);
2053     gtk_label_set_text(GTK_LABEL(number_of_files_data),t);
2054     g_free (t);
2055 
2056     if (archive[idx]->has_password)
2057     	gtk_label_set_text(GTK_LABEL(encrypted_data),_("Yes"));
2058 	else
2059 		gtk_label_set_text(GTK_LABEL(encrypted_data),_("No"));
2060     gtk_widget_show_all (archive_properties_window);
2061 }
2062 
xa_set_statusbar_message_for_displayed_rows(XArchive * archive)2063 void xa_set_statusbar_message_for_displayed_rows(XArchive *archive)
2064 {
2065 	gchar *info = NULL;
2066 	GtkTreePath *path = NULL;
2067 	GtkTreeIter iter;
2068 	gint n_elem = 0, dirs = 0;
2069 	guint64 total_size = 0;
2070 	guint64 size = 0;
2071 	XEntry *entry = NULL;
2072 
2073 	path = gtk_tree_path_new_first();
2074 	if (! GTK_IS_TREE_MODEL(archive->model) || gtk_tree_model_get_iter (archive->model,&iter,path) == FALSE)
2075 	{
2076 		gtk_tree_path_free(path);
2077 		return;
2078 	}
2079 
2080 	gtk_tree_path_free(path);
2081 	do
2082 	{
2083 		gtk_tree_model_get(archive->model, &iter, archive->size_column, &size, -1);
2084 		gtk_tree_model_get(archive->model, &iter, archive->columns - 1, &entry, -1);
2085 		if (entry->is_dir)
2086 			dirs++;
2087 		else
2088 			n_elem++;
2089 		total_size += size;
2090 	}
2091 	while (gtk_tree_model_iter_next (archive->model,&iter));
2092 	info = xa_get_statusbar_message(total_size,n_elem,dirs,FALSE);
2093 	gtk_label_set_text (GTK_LABEL(total_label),info);
2094 	g_free(info);
2095 }
2096 
xa_row_selected(GtkTreeSelection * selection,XArchive * archive)2097 void xa_row_selected (GtkTreeSelection *selection,XArchive *archive)
2098 {
2099 	GList *list = NULL;
2100 	gchar *msg = NULL;
2101 	GtkTreeIter iter;
2102 	gint selected, dirs = 0;
2103 	guint64 total_size = 0;
2104 	guint64 size = 0;
2105 	XEntry *entry;
2106 
2107 	selected = gtk_tree_selection_count_selected_rows (selection);
2108 
2109 	if (selected == 0)
2110 	{
2111 		xa_disable_delete_buttons (FALSE);
2112 		gtk_widget_hide(selected_frame);
2113 		return;
2114 	}
2115 
2116 	gtk_widget_show(selected_frame);
2117 	gtk_widget_set_sensitive(deselect_all, TRUE);
2118 	gtk_widget_set_sensitive(delete_menu, archive->can_delete);
2119 	gtk_widget_set_sensitive(rename_menu, selected == 1 ? can_rename(archive) : FALSE);
2120 
2121 	selected = 0;
2122 	list = gtk_tree_selection_get_selected_rows(selection,NULL);
2123 	while (list)
2124 	{
2125 		gtk_tree_model_get_iter(archive->model, &iter, list->data);
2126 		gtk_tree_model_get(archive->model, &iter, archive->size_column, &size, -1);
2127 		gtk_tree_model_get(archive->model, &iter, archive->columns - 1, &entry, -1);
2128 		if (entry->is_dir)
2129 			dirs++;
2130 		else
2131 			selected++;
2132 		gtk_tree_path_free (list->data);
2133 		total_size += size;
2134 		list = list->next;
2135 	}
2136 	g_list_free(list);
2137 	msg = xa_get_statusbar_message(total_size,selected,dirs,TRUE);
2138 	gtk_label_set_text (GTK_LABEL(selected_label),msg);
2139 	g_free(msg);
2140 }
2141 
drag_begin(GtkWidget * widget,GdkDragContext * context,XArchive * archive)2142 void drag_begin (GtkWidget *widget, GdkDragContext *context, XArchive *archive)
2143 {
2144     GtkTreeSelection *selection;
2145     GtkTreeIter       iter;
2146     GList            *row_list;
2147 	XEntry *entry;
2148 
2149 	if (archive->child_pid)
2150 		gtk_drag_source_set_icon_stock(widget, "gtk-stop");
2151 	else
2152 		gtk_drag_source_set_icon_name(widget, "xarchiver");
2153 
2154 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
2155 
2156 	row_list = gtk_tree_selection_get_selected_rows (selection,NULL);
2157 	if (row_list == NULL)
2158 		return;
2159 
2160 	gtk_tree_model_get_iter(archive->model,&iter,(GtkTreePath*) (row_list->data));
2161 	gtk_tree_model_get(GTK_TREE_MODEL(archive->liststore), &iter, archive->columns - 1, &entry, -1);
2162 
2163 	gdk_property_change(gdk_drag_context_get_source_window(context),
2164 					gdk_atom_intern ("XdndDirectSave0",FALSE),
2165 					gdk_atom_intern ("text/plain",FALSE),
2166 					8,GDK_PROP_MODE_REPLACE,
2167 					(guchar *) XDS_FILENAME,
2168 			     	strlen (XDS_FILENAME));
2169 
2170 	g_list_free_full(row_list, (GDestroyNotify) gtk_tree_path_free);
2171 }
2172 
drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * data,guint info,guint time,XArchive * archive)2173 void drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *data, guint info, guint time, XArchive *archive)
2174 {
2175 	GtkTreeSelection *selection;
2176 	GList *row_list;
2177 	GSList *names = NULL;
2178 	gint length;
2179 	guchar *_destination;
2180 	gchar *destination, *to_send, *extraction_dir;
2181 
2182 	if (archive->child_pid)
2183 		return;
2184 
2185 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (archive->treeview));
2186 	row_list = gtk_tree_selection_get_selected_rows (selection,NULL);
2187 
2188 	if (row_list == NULL)
2189 		return;
2190 
2191 	g_list_free_full(row_list, (GDestroyNotify) gtk_tree_path_free);
2192 
2193 	gdk_property_get(gdk_drag_context_get_source_window(context),
2194 	                 gdk_atom_intern("XdndDirectSave0", FALSE),
2195 	                 gdk_atom_intern("text/plain", FALSE),
2196 	                 0, 4096, FALSE, NULL, NULL, &length, &_destination);
2197 
2198 	if (_destination)
2199 	{
2200 		_destination = g_realloc(_destination, length + 1);
2201 		_destination[length] = 0;
2202 
2203 		if (strcmp((const char *) _destination, XDS_FILENAME) == 0)
2204 		{
2205 			g_free(_destination);
2206 			return;
2207 		}
2208 
2209 		destination = g_filename_from_uri((gchar*)_destination,NULL,NULL);
2210 		g_free(_destination);
2211 
2212 		if (!destination) return;
2213 
2214 		extraction_dir = xa_remove_level_from_path(destination);
2215 		g_free(destination);
2216 
2217 		if (archive->has_password)
2218 		{
2219 			if (!xa_check_password(archive))
2220 			{
2221 				gtk_drag_finish(context, FALSE, FALSE, time);
2222 				g_free(extraction_dir);
2223 				return;
2224 			}
2225 		}
2226 
2227 		if (access(extraction_dir, R_OK | W_OK | X_OK))
2228 		{
2229 			gchar *utf8_path;
2230 			gchar  *msg;
2231 
2232 			utf8_path = g_filename_to_utf8(extraction_dir, -1, NULL, NULL, NULL);
2233 			msg = g_strdup_printf (_("You don't have the right permissions to extract the files to the directory \"%s\"."),utf8_path);
2234 			xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Can't perform extraction!"),msg );
2235 			g_free (utf8_path);
2236 			g_free (msg);
2237 			to_send = "E";
2238 		}
2239 		else
2240 		{
2241 			gtk_tree_selection_selected_foreach (selection,(GtkTreeSelectionForeachFunc) xa_concat_selected_filenames,&names);
2242 			archive->do_full_path = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(extract_window->extract_full));
2243 			archive->do_overwrite = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(extract_window->overwrite_check));
2244 			g_free(archive->extraction_dir);
2245 			archive->extraction_dir = xa_escape_bad_chars(extraction_dir, ESCAPES);
2246 
2247 			gtk_label_set_text(GTK_LABEL(total_label), _("Extracting files from archive, please wait..."));
2248 			archive->status = XARCHIVESTATUS_EXTRACT;
2249 			(*archive->archiver->extract) (archive,names);
2250 
2251 			to_send = "S";
2252 		}
2253 
2254 		g_free(extraction_dir);
2255 
2256 		gtk_selection_data_set(data, gtk_selection_data_get_target(data), 8, (const guchar *) to_send, 1);
2257 	}
2258 }
2259 
on_drag_data_received(GtkWidget * widget,GdkDragContext * context,int x,int y,GtkSelectionData * data,unsigned int info,unsigned int time,gpointer user_data)2260 void on_drag_data_received (GtkWidget *widget,GdkDragContext *context,int x,int y,GtkSelectionData *data,unsigned int info,unsigned int time,gpointer user_data)
2261 {
2262 	gchar **array = NULL;
2263 	gchar *filename = NULL;
2264 	gchar *current_dir;
2265 	GSList *list = NULL;
2266 	gboolean one_file;
2267 	unsigned int len = 0;
2268 	gint current_page, idx;
2269 	ArchiveType xa;
2270 
2271 	array = gtk_selection_data_get_uris(data);
2272 
2273 	if (array == NULL)
2274 	{
2275 		xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Sorry, I could not perform the operation!"),"");
2276 		gtk_drag_finish(context,FALSE,FALSE,time);
2277 		return;
2278 	}
2279 	gtk_drag_finish (context,TRUE,FALSE,time);
2280 	one_file = (array[1] == NULL);
2281 
2282 	if (one_file)
2283 	{
2284 		filename = g_filename_from_uri(array[0],NULL,NULL);
2285 
2286 		if (filename == NULL)
2287 			return;
2288 
2289 		xa = xa_detect_archive_type(filename);
2290 
2291 		if (xa.type != XARCHIVETYPE_UNKNOWN && xa.type != XARCHIVETYPE_NOT_FOUND)
2292 		{
2293 			xa_open_archive(NULL,filename);
2294 			g_strfreev(array);
2295 			return;
2296 		}
2297     }
2298 
2299 	current_page = gtk_notebook_get_current_page(notebook);
2300 
2301 	if (current_page == -1)
2302 	{
2303 		idx = xa_get_new_archive_idx();
2304 		if (idx == -1)
2305 			return;
2306 		archive[idx] = xa_new_archive_dialog(filename, archive);
2307 		if (archive[idx] == NULL)
2308 			return;
2309 		xa_add_page (archive[idx]);
2310 	}
2311 	else
2312 		idx = xa_find_archive_index (current_page);
2313 
2314 	if (!archive[idx]->can_add)
2315 	{
2316 		xa_show_message_dialog(GTK_WINDOW(xa_main_window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Can't perform this action:"), _("You can't add content to this archive type!"));
2317 		gtk_drag_finish(context,FALSE,FALSE,time);
2318 		return;
2319 	}
2320 	current_dir = g_path_get_dirname(array[0]);
2321 	archive[idx]->child_dir = g_filename_from_uri(current_dir, NULL, NULL);
2322 	g_free(current_dir);
2323 	while (array[len])
2324 	{
2325 		filename = g_filename_from_uri (array[len],NULL,NULL);
2326 		list = g_slist_append(list,filename);
2327 		len++;
2328 	}
2329 	archive[idx]->do_full_path = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(add_window->store_path));
2330 	xa_execute_add_commands(archive[idx], list, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs_window->allow_sub_dir)), NULL);
2331 	g_strfreev (array);
2332 }
2333 
xa_concat_selected_filenames(GtkTreeModel * model,GtkTreePath * treepath,GtkTreeIter * iter,GSList ** data)2334 void xa_concat_selected_filenames (GtkTreeModel *model,GtkTreePath *treepath,GtkTreeIter *iter,GSList **data)
2335 {
2336 	XEntry *entry = NULL;
2337 	gchar *filename = NULL;
2338 	gint idx;
2339 
2340 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2341 
2342 	gtk_tree_model_get(model, iter, archive[idx]->columns - 1, &entry, -1);
2343 	if (entry->is_dir)
2344 		xa_fill_list_with_recursed_entries(entry->child,data);
2345 	filename = xa_build_full_path_name_from_entry(entry);
2346 	*data = g_slist_prepend (*data,filename);
2347 }
2348 
xa_select_all(GtkMenuItem * menuitem,gpointer user_data)2349 void xa_select_all(GtkMenuItem *menuitem,gpointer user_data)
2350 {
2351 	gint idx;
2352 	gint current_page;
2353 
2354 	current_page = gtk_notebook_get_current_page (notebook);
2355 	idx = xa_find_archive_index (current_page);
2356 
2357 	gtk_tree_selection_select_all ( gtk_tree_view_get_selection (GTK_TREE_VIEW (archive[idx]->treeview)));
2358 	gtk_widget_set_sensitive (select_all,FALSE);
2359 	gtk_widget_set_sensitive (deselect_all,TRUE);
2360 }
2361 
xa_deselect_all(GtkMenuItem * menuitem,gpointer user_data)2362 void xa_deselect_all (GtkMenuItem *menuitem,gpointer user_data)
2363 {
2364 	gint idx;
2365 
2366 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2367 
2368 	gtk_tree_selection_unselect_all (gtk_tree_view_get_selection(GTK_TREE_VIEW(archive[idx]->treeview)));
2369 	gtk_widget_set_sensitive (select_all,TRUE);
2370 	gtk_widget_set_sensitive (deselect_all,FALSE);
2371 }
2372 
xa_launch_external_program(const gchar * program,const gchar * arg)2373 gboolean xa_launch_external_program (const gchar *program, const gchar *arg)
2374 {
2375 	GtkWidget *message;
2376 	GError *error = NULL;
2377 	gchar *program_local, *arg_local, *command_line;
2378 	gchar **argv;
2379 	GdkDisplay *display;
2380 	gboolean success = TRUE;
2381 
2382 	if (g_utf8_validate(program, -1, NULL))
2383 		program_local = g_filename_from_utf8(program, -1, NULL, NULL, NULL);
2384 	else
2385 		program_local = g_strdup(program);
2386 
2387 	if (g_utf8_validate(arg, -1, NULL))
2388 		arg_local = g_filename_from_utf8(arg, -1, NULL, NULL, NULL);
2389 	else
2390 		arg_local = g_strdup(arg);
2391 
2392 	command_line = g_strconcat(program_local, " ", arg_local, NULL);
2393 	g_shell_parse_argv(command_line,NULL,&argv,NULL);
2394 	g_free(command_line);
2395 	g_free(program_local);
2396 	g_free(arg_local);
2397 
2398 	display = gdk_display_get_default();
2399 
2400 	if (!GDK_COMPAT_SPAWN(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, xa_set_environment, (gpointer) gdk_display_get_name(display), NULL, &error))
2401 	{
2402 		message = gtk_message_dialog_new (GTK_WINDOW (xa_main_window),
2403 										GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2404 										GTK_MESSAGE_ERROR,
2405 										GTK_BUTTONS_CLOSE,
2406 										_("Failed to launch the application!"));
2407 		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message),"%s.",error->message);
2408 		gtk_dialog_run (GTK_DIALOG (message));
2409 		gtk_widget_destroy (message);
2410 		g_error_free (error);
2411 		success = FALSE;
2412 	}
2413 	g_strfreev(argv);
2414 	return success;
2415 }
2416 
xa_show_help(GtkMenuItem * menuitem,gpointer user_data)2417 void xa_show_help (GtkMenuItem *menuitem,gpointer user_data)
2418 {
2419 	xa_activate_link (NULL,"file://" HTMLDIR "/index.html",NULL);
2420 }
2421 
xa_enter_password(GtkMenuItem * menuitem,gpointer user_data)2422 void xa_enter_password (GtkMenuItem *menuitem ,gpointer user_data)
2423 {
2424 	gint idx;
2425 
2426 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2427 
2428 	if (archive[idx] == NULL)
2429 		return;
2430 	else
2431 	{
2432 		g_free(archive[idx]->password);
2433 		archive[idx]->password = NULL;
2434 	}
2435 
2436 	xa_check_password(archive[idx]);
2437 }
2438 
xa_show_archive_comment(GtkMenuItem * menuitem,gpointer user_data)2439 void xa_show_archive_comment (GtkMenuItem *menuitem,gpointer user_data)
2440 {
2441 	gchar *utf8_line;
2442 	gsize len;
2443 	gint idx;
2444 	GtkWidget *textview;
2445 	GtkWidget *dialog_vbox1;
2446 	GtkWidget *scrolledwindow1;
2447 	GtkWidget *tmp_image,*file,*clear,*close,*cancel,*file_hbox,*file_label;
2448 	GtkWidget *alignment2;
2449 	GtkTextBuffer *textbuffer;
2450 	GtkTextIter iter;
2451 
2452 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2453 
2454 	comment_dialog = gtk_dialog_new_with_buttons (_("Comment"),GTK_WINDOW(xa_main_window),GTK_DIALOG_MODAL,NULL,NULL);
2455 	gtk_window_set_position (GTK_WINDOW (comment_dialog),GTK_WIN_POS_CENTER_ON_PARENT);
2456 	gtk_window_set_type_hint (GTK_WINDOW (comment_dialog),GDK_WINDOW_TYPE_HINT_DIALOG);
2457 	dialog_vbox1 = gtk_dialog_get_content_area(GTK_DIALOG(comment_dialog));
2458 	gtk_widget_set_size_request(comment_dialog, 672, 420);
2459 
2460 	scrolledwindow1 = gtk_scrolled_window_new (NULL,NULL);
2461 	gtk_widget_show (scrolledwindow1);
2462 	gtk_box_pack_start (GTK_BOX (dialog_vbox1),scrolledwindow1,TRUE,TRUE,0);
2463 	g_object_set (G_OBJECT (scrolledwindow1),"hscrollbar-policy",GTK_POLICY_AUTOMATIC,"shadow-type",GTK_SHADOW_IN,"vscrollbar-policy",GTK_POLICY_AUTOMATIC,NULL);
2464 
2465 	textbuffer = gtk_text_buffer_new (NULL);
2466 	gtk_text_buffer_create_tag (textbuffer,"font","family","monospace",NULL);
2467 	gtk_text_buffer_get_iter_at_offset (textbuffer,&iter,0);
2468 
2469 	textview = gtk_text_view_new_with_buffer (textbuffer);
2470 	g_object_unref (textbuffer);
2471 	gtk_container_add (GTK_CONTAINER (scrolledwindow1),textview);
2472 
2473 	clear = gtk_button_new_from_stock ("gtk-clear");
2474 	gtk_dialog_add_action_widget (GTK_DIALOG (comment_dialog),clear,0);
2475 	g_signal_connect (G_OBJECT (clear),"clicked",G_CALLBACK (xa_clear_comment_window),textbuffer);
2476 
2477 	file = gtk_button_new();
2478 	tmp_image = gtk_image_new_from_stock ("gtk-harddisk",GTK_ICON_SIZE_BUTTON);
2479 	file_hbox = gtk_hbox_new(FALSE,4);
2480 	file_label = gtk_label_new_with_mnemonic(_("From File"));
2481 
2482 	alignment2 = gtk_alignment_new (0.5,0.5,0,0);
2483 	gtk_container_add (GTK_CONTAINER (alignment2),file_hbox);
2484 	gtk_box_pack_start(GTK_BOX(file_hbox),tmp_image,FALSE,TRUE,0);
2485 	gtk_box_pack_start(GTK_BOX(file_hbox),file_label,FALSE,TRUE,0);
2486 	gtk_container_add(GTK_CONTAINER(file),alignment2);
2487 	gtk_dialog_add_action_widget (GTK_DIALOG (comment_dialog),file,0);
2488 	g_signal_connect (G_OBJECT (file),"clicked",G_CALLBACK (xa_load_comment_window_from_file),textbuffer);
2489 
2490 	cancel = gtk_button_new_from_stock ("gtk-cancel");
2491 	gtk_dialog_add_action_widget (GTK_DIALOG (comment_dialog),cancel,GTK_RESPONSE_CANCEL);
2492 	g_signal_connect_swapped(G_OBJECT(cancel), "clicked", G_CALLBACK(gtk_widget_destroy), comment_dialog);
2493 
2494 	close = gtk_button_new_from_stock ("gtk-ok");
2495 	gtk_dialog_add_action_widget (GTK_DIALOG (comment_dialog),close,GTK_RESPONSE_OK);
2496 	g_signal_connect (G_OBJECT (close),"clicked",G_CALLBACK (xa_comment_window_insert_in_archive),textbuffer);
2497 
2498 	if (archive[idx]->comment)
2499 	{
2500 		if (g_utf8_validate(archive[idx]->comment->str, -1, NULL))
2501 		{
2502 			utf8_line = g_strdup(archive[idx]->comment->str);
2503 			len = -1;
2504 		}
2505 		else
2506 			utf8_line = g_locale_to_utf8(archive[idx]->comment->str, -1, NULL, &len, NULL);
2507 
2508 		gtk_text_buffer_insert_with_tags_by_name (textbuffer,&iter,utf8_line,len,"font",NULL);
2509 		g_free(utf8_line);
2510 	}
2511 	gtk_widget_show_all(comment_dialog);
2512 }
2513 
xa_location_entry_activated(GtkEntry * entry,gpointer user_data)2514 void xa_location_entry_activated (GtkEntry *entry,gpointer user_data)
2515 {
2516 	XEntry *prev_entry = NULL;
2517 	XEntry *new_entry  = NULL;
2518 	gint idx;
2519 	gchar* pathname_local;
2520 
2521 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2522 
2523 	/* Avoid segfault if there's no file opened */
2524 	if(idx<0)
2525 		return;
2526 
2527 	if (strlen(gtk_entry_get_text(GTK_ENTRY(location_entry))) == 0)
2528 	{
2529 		xa_update_window_with_archive_entries(archive[idx],new_entry);
2530 		return;
2531 	}
2532 
2533 	pathname_local = g_filename_from_utf8(gtk_entry_get_text(GTK_ENTRY(location_entry)), -1, NULL, NULL, NULL);
2534 	new_entry = xa_find_entry_from_dirpath(archive[idx], pathname_local);
2535 	g_free(pathname_local);
2536 	if (new_entry == NULL)
2537 	{
2538 		if (archive[idx]->location_path)
2539 		{
2540 			gchar *entry_utf8 = g_filename_display_name(archive[idx]->location_path);
2541 			gtk_entry_set_text(GTK_ENTRY(location_entry), entry_utf8);
2542 			g_free(entry_utf8);
2543 		}
2544 		return;
2545 	}
2546 
2547 	if (archive[idx]->location_path)
2548 		prev_entry = xa_find_entry_from_dirpath(archive[idx], archive[idx]->location_path);
2549 
2550 	if (prev_entry != NULL)
2551 		archive[idx]->back = g_slist_prepend(archive[idx]->back,prev_entry);
2552 	else
2553 		archive[idx]->back = g_slist_prepend(archive[idx]->back,NULL);
2554 
2555 	xa_dir_sidebar_select_row(new_entry);
2556 	xa_update_window_with_archive_entries(archive[idx],new_entry);
2557 }
2558 
xa_mouse_button_event(GtkWidget * widget,GdkEventButton * event,XArchive * archive)2559 gboolean xa_mouse_button_event (GtkWidget *widget, GdkEventButton *event, XArchive *archive)
2560 {
2561 	XEntry *entry;
2562 	GtkTreePath *path;
2563 	GtkTreeIter iter;
2564 	GtkTreeSelection *selection;
2565 	gint selected;
2566 	GtkClipboard *clipboard;
2567 	GtkSelectionData *clipboard_selection;
2568 	XAClipboard *paste_data;
2569 	gboolean pasteable = FALSE;
2570 
2571 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(archive->treeview));
2572 	selected = gtk_tree_selection_count_selected_rows(selection);
2573 	gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(archive->treeview), event->x, event->y, &path, NULL, NULL, NULL);
2574 
2575 	if (path == NULL)
2576 		return FALSE;
2577 
2578 	if (event->type == GDK_BUTTON_PRESS && (event->button == 2 || event->button == 3))
2579 	{
2580 		gtk_tree_model_get_iter(GTK_TREE_MODEL(archive->liststore), &iter, path);
2581 		gtk_tree_model_get(archive->model, &iter, archive->columns - 1, &entry, -1);
2582 
2583 		if (!gtk_tree_selection_iter_is_selected(selection, &iter))
2584 		{
2585 			gtk_tree_selection_unselect_all(selection);
2586 			gtk_tree_selection_select_iter(selection, &iter);
2587 			selected = 1;
2588 		}
2589 
2590 		if (event->button == 2 && selected <= 1)
2591 			xa_treeview_row_activated(GTK_TREE_VIEW(archive->treeview), path, NULL, archive);
2592 		else if (event->button == 3)
2593 		{
2594 			gtk_widget_set_sensitive(open_popupmenu, !entry->is_dir && archive->can_extract);
2595 			gtk_widget_set_sensitive(view, (selected == 1) && !entry->is_dir && archive->can_extract);
2596 			gtk_widget_set_sensitive(rrename, (selected == 1) && !entry->is_dir && can_rename(archive));
2597 
2598 			clipboard = gtk_clipboard_get(XA_CLIPBOARD);
2599 			clipboard_selection = gtk_clipboard_wait_for_contents(clipboard, XA_INFO_LIST);
2600 
2601 			if (clipboard_selection != NULL)
2602 			{
2603 				paste_data = xa_get_paste_data_from_clipboard_selection(gtk_selection_data_get_data(clipboard_selection));
2604 				gtk_selection_data_free(clipboard_selection);
2605 
2606 				pasteable = (strcmp(archive->path[1], paste_data->target->path[1]) != 0);
2607 			}
2608 
2609 			gtk_widget_set_sensitive(eextract, archive->can_extract);
2610 			gtk_widget_set_sensitive(cut, archive->can_extract && archive->can_delete);
2611 			gtk_widget_set_sensitive(copy, archive->can_extract);
2612 			gtk_widget_set_sensitive(paste, pasteable && archive->can_add);
2613 			gtk_widget_set_sensitive(ddelete, archive->can_delete);
2614 			gtk_menu_popup(GTK_MENU(xa_popup_menu), NULL, NULL, NULL, xa_main_window, event->button, event->time);
2615 		}
2616 
2617 		return TRUE;
2618 	}
2619 
2620 	gtk_tree_path_free(path);
2621 
2622 	return FALSE;
2623 }
2624 
xa_clipboard_cut(GtkMenuItem * item,gpointer user_data)2625 void xa_clipboard_cut (GtkMenuItem *item, gpointer user_data)
2626 {
2627 	gint idx;
2628 
2629 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2630 
2631 	xa_clipboard_cut_copy_operation(archive[idx],XA_CLIPBOARD_CUT);
2632 }
2633 
xa_clipboard_copy(GtkMenuItem * item,gpointer user_data)2634 void xa_clipboard_copy (GtkMenuItem *item, gpointer user_data)
2635 {
2636 	gint idx;
2637 
2638 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2639 	xa_clipboard_cut_copy_operation(archive[idx],XA_CLIPBOARD_COPY);
2640 }
2641 
xa_clipboard_paste(GtkMenuItem * item,gpointer user_data)2642 void xa_clipboard_paste (GtkMenuItem *item, gpointer user_data)
2643 {
2644 	gint idx;
2645 	GtkClipboard *clipboard;
2646 	GtkSelectionData *selection;
2647 	XAClipboard *paste_data;
2648 	GSList *list = NULL;
2649 
2650 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2651 
2652 	clipboard = gtk_clipboard_get(XA_CLIPBOARD);
2653 	selection = gtk_clipboard_wait_for_contents(clipboard,XA_INFO_LIST);
2654 	if (selection == NULL)
2655 		return;
2656 	paste_data = xa_get_paste_data_from_clipboard_selection(gtk_selection_data_get_data(selection));
2657 	gtk_selection_data_free (selection);
2658 
2659 	/* Let's add the already extracted files in the tmp dir to the current archive dir */
2660 	list = xa_slist_copy(paste_data->files);
2661 	archive[idx]->do_full_path = FALSE;
2662 	archive[idx]->child_dir = g_strdup(paste_data->target->working_dir);
2663 	xa_execute_add_commands(archive[idx], list, FALSE, NULL);
2664 	if (archive[idx]->status == XARCHIVESTATUS_ERROR)
2665 		return;
2666 
2667 	if (paste_data->mode == XA_CLIPBOARD_CUT)
2668 	{
2669 		list = xa_slist_copy(paste_data->files);
2670 
2671 		paste_data->target->status = XARCHIVESTATUS_DELETE;
2672 		(*paste_data->target->archiver->delete)(paste_data->target, list);
2673 		xa_reload_archive_content(paste_data->target);
2674 	}
2675 }
2676 
xa_clipboard_clear(GtkClipboard * clipboard,XArchive * archive)2677 void xa_clipboard_clear (GtkClipboard *clipboard, XArchive *archive)
2678 {
2679 	if (archive->clipboard != NULL)
2680 	{
2681 		if (archive->clipboard->files != NULL)
2682 		{
2683 			g_slist_free_full(archive->clipboard->files, g_free);
2684 			archive->clipboard->files = NULL;
2685 		}
2686 
2687 		g_free(archive->clipboard);
2688 		archive->clipboard = NULL;
2689 	}
2690 }
2691 
xa_rename_archive(GtkMenuItem * item,gpointer user_data)2692 void xa_rename_archive (GtkMenuItem *item, gpointer user_data)
2693 {
2694 	gint idx;
2695 	GtkTreeSelection *selection;
2696 	GtkTreeViewColumn *column;
2697 	GtkTreeModel *model;
2698 	GList *row_list = NULL;
2699 
2700 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2701 
2702 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (archive[idx]->treeview));
2703 	model = gtk_tree_view_get_model(GTK_TREE_VIEW (archive[idx]->treeview));
2704 	row_list = gtk_tree_selection_get_selected_rows(selection,&model);
2705 
2706 	g_object_set(archive[idx]->text_renderer, "editable", TRUE, NULL);
2707 	gtk_widget_remove_accelerator(delete_menu, accel_group, GDK_KEY_Delete, (GdkModifierType) 0);
2708 	column = gtk_tree_view_get_column(GTK_TREE_VIEW (archive[idx]->treeview),0);
2709 	gtk_tree_view_set_cursor(GTK_TREE_VIEW(archive[idx]->treeview),row_list->data,column,TRUE);
2710 	gtk_tree_path_free (row_list->data);
2711 	g_list_free(row_list);
2712 }
2713 
xa_open_with_from_popupmenu(GtkMenuItem * item,gpointer user_data)2714 void xa_open_with_from_popupmenu (GtkMenuItem *item, gpointer user_data)
2715 {
2716 	gboolean result		= FALSE;
2717 	gint idx, nr;
2718 	GtkTreeSelection *selection;
2719 	GtkTreeIter iter;
2720 	GList *row_list = NULL;
2721 	GSList *list = NULL;
2722 	GSList *list_of_files = NULL;
2723 	GString *names = g_string_new("");
2724 	gchar *dummy = NULL,*e_filename = NULL;
2725 	XEntry *entry;
2726 
2727 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2728 
2729 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (archive[idx]->treeview));
2730 	row_list = gtk_tree_selection_get_selected_rows(selection,&archive[idx]->model);
2731 	if (row_list == NULL)
2732 		return;
2733 
2734 	nr = gtk_tree_selection_count_selected_rows(selection);
2735 	while (row_list)
2736 	{
2737 		gtk_tree_model_get_iter(archive[idx]->model,&iter,row_list->data);
2738 		gtk_tree_model_get(archive[idx]->model, &iter, archive[idx]->columns - 1, &entry, -1);
2739 		gtk_tree_path_free(row_list->data);
2740 		if (entry->is_encrypted)
2741 		{
2742 			if (!xa_check_password(archive[idx]))
2743 				return;
2744 		}
2745 		list = g_slist_append(list, xa_build_full_path_name_from_entry(entry));
2746 		row_list = row_list->next;
2747 	}
2748 	g_list_free (row_list);
2749 	g_free(archive[idx]->extraction_dir);
2750 	xa_create_working_directory(archive[idx]);
2751 	archive[idx]->extraction_dir = g_strdup(archive[idx]->working_dir);
2752 
2753 	archive[idx]->do_full_path = FALSE;
2754 	archive[idx]->do_overwrite = TRUE;
2755 	list_of_files = xa_slist_copy(list);
2756 
2757 	archive[idx]->status = XARCHIVESTATUS_EXTRACT;
2758 	result = (*archive[idx]->archiver->extract) (archive[idx],list);
2759 	if (result == FALSE)
2760 		return;
2761 
2762 	chdir(archive[idx]->working_dir);
2763 	do
2764 	{
2765 		dummy = g_path_get_basename(list_of_files->data);
2766 		e_filename = g_shell_quote(dummy);
2767 		g_free(dummy);
2768 		g_string_append (names,e_filename);
2769 		g_string_append_c (names,' ');
2770 		list_of_files = list_of_files->next;
2771 	}
2772 	while (list_of_files);
2773 	xa_create_open_with_dialog(entry->filename,names->str,nr);
2774 	g_string_free(names, FALSE);
2775 	g_slist_free_full(list_of_files, g_free);
2776 }
2777 
xa_view_from_popupmenu(GtkMenuItem * item,gpointer user_data)2778 void xa_view_from_popupmenu (GtkMenuItem *item, gpointer user_data)
2779 {
2780 	GtkTreeSelection *selection;
2781 	GtkTreeIter iter;
2782 	GSList *list = NULL;
2783 	GList *row_list = NULL;
2784 	gboolean result		= FALSE;
2785 	gint idx;
2786 	gchar *entry_local, *filename;
2787 	XEntry *entry;
2788 
2789 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
2790 
2791 	xa_create_working_directory(archive[idx]);
2792 
2793 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (archive[idx]->treeview));
2794 	row_list = gtk_tree_selection_get_selected_rows(selection,&archive[idx]->model);
2795 	gtk_tree_model_get_iter(archive[idx]->model,&iter,row_list->data);
2796 	gtk_tree_model_get(archive[idx]->model, &iter, archive[idx]->columns - 1, &entry, -1);
2797 	gtk_tree_path_free(row_list->data);
2798 	list = g_slist_append(list, xa_build_full_path_name_from_entry(entry));
2799 	g_list_free(row_list);
2800 
2801 	if (entry->is_encrypted)
2802 	{
2803 		if (!xa_check_password(archive[idx]))
2804 			return;
2805 	}
2806 	entry_local = g_filename_from_utf8(entry->filename, -1, NULL, NULL, NULL);
2807 	filename = g_strconcat(archive[idx]->working_dir, "/", entry_local, NULL);
2808 	g_free(entry_local);
2809 	if (g_file_test(filename,G_FILE_TEST_EXISTS))
2810 		goto here;
2811 	g_free(archive[idx]->extraction_dir);
2812 	archive[idx]->extraction_dir = g_strdup(archive[idx]->working_dir);
2813 	archive[idx]->do_full_path = FALSE;
2814 	archive[idx]->do_overwrite = TRUE;
2815 
2816 	archive[idx]->status = XARCHIVESTATUS_EXTRACT;
2817 	result = (*archive[idx]->archiver->extract) (archive[idx],list);
2818 	if (result == FALSE)
2819 		return;
2820 
2821 here:
2822 	xa_determine_program_to_run(filename);
2823 	g_free(filename);
2824 }
2825 
xa_treeview_row_activated(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,XArchive * archive)2826 void xa_treeview_row_activated(GtkTreeView *tree_view,GtkTreePath *path,GtkTreeViewColumn *column,XArchive *archive)
2827 {
2828 	XEntry *entry;
2829 	GtkTreeIter iter;
2830 	gchar *item, *entry_local, *file;
2831 	GSList *names = NULL;
2832 	gboolean result = FALSE;
2833 
2834 	if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (archive->liststore),&iter,path))
2835 		return;
2836 
2837 	gtk_tree_model_get(GTK_TREE_MODEL(archive->liststore), &iter, archive->columns - 1, &entry, -1);
2838 	if (entry->is_dir)
2839 	{
2840 		if (archive->location_path)
2841 			archive->back = g_slist_prepend(archive->back, xa_find_entry_from_dirpath(archive, archive->location_path));
2842 		/* Put NULL so to display the root entry */
2843 		else
2844 			archive->back = g_slist_prepend(archive->back,NULL);
2845 		xa_dir_sidebar_select_row(entry);
2846 	}
2847 	/* The selected entry it's not a dir so extract it to the tmp dir and send it to xa_determine_program_to_run() */
2848 	else
2849 	{
2850 		if (entry->is_encrypted)
2851 		{
2852 	    if (!xa_check_password(archive))
2853 	     return;
2854 		}
2855 	   	g_free(archive->extraction_dir);
2856 	   	xa_create_working_directory(archive);
2857 	   	archive->extraction_dir = g_strdup(archive->working_dir);
2858 	   	item = xa_build_full_path_name_from_entry(entry);
2859 	   	names = g_slist_append(names,item);
2860 	   	archive->do_full_path = FALSE;
2861 	   	archive->do_overwrite = TRUE;
2862 		archive->status = XARCHIVESTATUS_EXTRACT;
2863 		result = (*archive->archiver->extract) (archive,names);
2864 
2865 		if (result == FALSE)
2866 			return;
2867 		entry_local = g_filename_from_utf8(entry->filename, -1, NULL, NULL, NULL);
2868 		file = g_strconcat(archive->working_dir, "/", entry_local, NULL);
2869 		g_free(entry_local);
2870 		xa_determine_program_to_run(file);
2871 		g_free(file);
2872 	}
2873 }
2874 
xa_update_window_with_archive_entries(XArchive * archive,XEntry * entry)2875 void xa_update_window_with_archive_entries (XArchive *archive,XEntry *entry)
2876 {
2877 	gboolean reload;
2878 	GdkPixbuf *pixbuf = NULL;
2879 	GtkTreeIter iter;
2880 	guint i;
2881 	gpointer current_column;
2882 	gchar *location_path = NULL, *filename;
2883 	gint size;
2884 	gchar *entry_utf8;
2885 
2886 	if (archive->status == XARCHIVESTATUS_RELOAD && archive->location_path != NULL)
2887 	{
2888 		entry = xa_find_entry_from_dirpath(archive, archive->location_path);
2889 
2890 		if (entry) location_path = g_strdup(archive->location_path);
2891 	}
2892 	else
2893 		archive->current_entry = entry;
2894 
2895 	g_free(archive->location_path);
2896 	archive->location_path = NULL;
2897 
2898 	if (entry == NULL)
2899 	{
2900 		reload = TRUE;
2901 		entry = archive->root_entry->child;
2902 		gtk_entry_set_text(GTK_ENTRY(location_entry),"\0");
2903 		gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(archive_dir_treeview)));
2904 
2905 		gtk_widget_set_sensitive(back_button,FALSE);
2906 		gtk_widget_set_sensitive(up_button,FALSE);
2907 		gtk_widget_set_sensitive(home_button,FALSE);
2908 	}
2909 	else
2910 	{
2911 		reload = (archive->status == XARCHIVESTATUS_RELOAD);
2912 		gtk_widget_set_sensitive(back_button, archive->back != NULL);
2913 		gtk_widget_set_sensitive(up_button,TRUE);
2914 		gtk_widget_set_sensitive(home_button,TRUE);
2915 		archive->location_path = xa_build_full_path_name_from_entry(entry);
2916 		entry_utf8 = g_filename_display_name(archive->location_path);
2917 		gtk_entry_set_text(GTK_ENTRY(location_entry), entry_utf8);
2918 		g_free(entry_utf8);
2919 		entry = entry->child;
2920 	}
2921 	gtk_list_store_clear(archive->liststore);
2922 
2923 	while (entry)
2924 	{
2925 		current_column = entry->columns;
2926 		gtk_list_store_prepend(archive->liststore, &iter);
2927 		if(!g_utf8_validate(entry->filename,-1,NULL))
2928 		{
2929 			gchar *entry_utf8 = g_filename_display_name(entry->filename);
2930 			g_free(entry->filename);
2931 			entry->filename = entry_utf8;
2932 		}
2933 		if (entry->is_dir)
2934 			filename = "folder";
2935 		else if (entry->is_encrypted)
2936 			filename = "lock";
2937 		else
2938 			filename = entry->filename;
2939 
2940 		switch (gtk_combo_box_get_active(GTK_COMBO_BOX(prefs_window->combo_icon_size)))
2941 		{
2942 			case 0:
2943 				size = 20;
2944 				break;
2945 
2946 			case 1:
2947 				size = 22;
2948 				break;
2949 
2950 			case 2:
2951 				size = 24;
2952 				break;
2953 
2954 			case 3:
2955 				size = 30;
2956 				break;
2957 
2958 			default:
2959 				size = 32;
2960 				break;
2961 		}
2962 
2963 		pixbuf = xa_get_pixbuf_icon_from_cache(filename,size);
2964 		gtk_list_store_set(archive->liststore, &iter, archive->columns - 1, entry, -1);
2965 		gtk_list_store_set (archive->liststore,&iter,0,pixbuf,1,entry->filename,-1);
2966 
2967 		for (i = 2; i < archive->columns - 1; i++)
2968 		{
2969 			switch(archive->column_types[i])
2970 			{
2971 				case G_TYPE_STRING:
2972 					//g_message ("%d - %s",i,(*((gchar **)current_column)));
2973 					gtk_list_store_set(archive->liststore, &iter, i, *(gchar **) current_column, -1);
2974 					current_column += sizeof(gchar *);
2975 				break;
2976 
2977 				case G_TYPE_UINT64:
2978 					//g_message ("*%d - %lu",i,(*((guint64 *)current_column)));
2979 					gtk_list_store_set(archive->liststore, &iter, i, *(guint64 *) current_column, -1);
2980 					current_column += sizeof(guint64);
2981 				break;
2982 			}
2983 		}
2984 		entry = entry->next;
2985 	}
2986 	xa_fill_dir_sidebar(archive, reload);
2987 
2988 	if (location_path)
2989 	{
2990 		entry = xa_find_entry_from_dirpath(archive, location_path);
2991 		xa_block_signal_dir_treeview_selection(TRUE);
2992 		xa_dir_sidebar_select_row(entry);
2993 		xa_block_signal_dir_treeview_selection(FALSE);
2994 		g_free(location_path);
2995 	}
2996 
2997 	xa_set_statusbar_message_for_displayed_rows(archive);
2998 }
2999 
xa_show_multi_extract_dialog(GtkMenuItem * menu_item,gpointer user_data)3000 void xa_show_multi_extract_dialog (GtkMenuItem *menu_item, gpointer user_data)
3001 {
3002 	xa_multi_extract_dialog(multi_extract_window);
3003 	if (progress)
3004 		gtk_widget_hide(progress->window);
3005 	//xa_close_archive (NULL,data);
3006 }
3007 
xa_unsort(GtkMenuItem * menu_item,gpointer user_data)3008 void xa_unsort (GtkMenuItem *menu_item, gpointer user_data)
3009 {
3010 	gint idx;
3011 	XArchiveStatus status;
3012 
3013 	idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
3014 
3015 	if (idx < 0)
3016 		return;
3017 
3018 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(archive[idx]->model), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, (GtkSortType) 0);
3019 	gtk_widget_set_sensitive(unsort_menu, FALSE);
3020 	archive[idx]->sorted = FALSE;
3021 
3022 	status = archive[idx]->status;
3023 	archive[idx]->status = XARCHIVESTATUS_RELOAD;
3024 	xa_update_window_with_archive_entries(archive[idx], NULL);
3025 	archive[idx]->status = status;
3026 }
3027 
xa_main_window_find_image(gchar * filename,GtkIconSize size)3028 GtkWidget *xa_main_window_find_image (gchar *filename, GtkIconSize size)
3029 {
3030   gchar *name, *ext, *path;
3031   GdkPixbuf *file_pixbuf = NULL;
3032   GtkWidget *file_image;
3033 
3034   name = g_strdup(filename);
3035   ext = g_strrstr(name, ".png");
3036 
3037   if (ext)
3038   {
3039     *ext = 0;
3040     file_pixbuf = gtk_icon_theme_load_icon(icon_theme, name, size, (GtkIconLookupFlags) 0, NULL);
3041   }
3042 
3043   g_free(name);
3044 
3045   if (file_pixbuf == NULL)
3046   {
3047     path = g_strconcat(PIXMAPSDIR, "/", filename, NULL);
3048     file_pixbuf = gdk_pixbuf_new_from_file(path, NULL);
3049     g_free(path);
3050   }
3051 
3052   if (file_pixbuf == NULL)
3053     file_image = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, size);
3054   else
3055   {
3056     file_image = gtk_image_new_from_pixbuf(file_pixbuf);
3057     g_object_unref(file_pixbuf);
3058   }
3059 
3060   return file_image;
3061 }
3062