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 <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include "archive.h"
28 #include "interface.h"
29 #include "main.h"
30 #include "pref_dialog.h"
31 #include "support.h"
32 #include "window.h"
33
34 #ifndef NCARGS
35 #define NCARGS _POSIX_ARG_MAX
36 #endif
37
38 #define MAX_CMD_LEN (NCARGS * 2 / 3)
39
40 #define MAX_XARCHIVES 100
41
42 XArchive *archive[MAX_XARCHIVES];
43
xa_process_stdout(GIOChannel * ioc,GIOCondition cond,XArchive * archive)44 static gboolean xa_process_stdout (GIOChannel *ioc, GIOCondition cond, XArchive *archive)
45 {
46 GIOStatus status;
47 gchar *line;
48
49 if (cond & G_IO_IN)
50 {
51 status = g_io_channel_read_line(ioc, &line, NULL, NULL, NULL);
52
53 if (status == G_IO_STATUS_NORMAL)
54 {
55 if (xa_main_window)
56 {
57 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs_window->store_output)))
58 archive->output = g_slist_prepend(archive->output, g_strdup(line));
59 }
60
61 if (archive->parse_output)
62 (*archive->parse_output)(line, archive);
63
64 g_free(line);
65
66 while (gtk_events_pending())
67 gtk_main_iteration();
68
69 return TRUE;
70 }
71 else if (status == G_IO_STATUS_AGAIN)
72 return TRUE;
73 else
74 cond &= ~G_IO_IN;
75 }
76
77 g_io_channel_shutdown(ioc, FALSE, NULL);
78 g_io_channel_unref(ioc);
79
80 xa_child_processed(XA_CHILD_STDOUT, cond == G_IO_HUP, archive);
81
82 return FALSE;
83 }
84
xa_process_stderr(GIOChannel * ioc,GIOCondition cond,XArchive * archive)85 static gboolean xa_process_stderr (GIOChannel *ioc, GIOCondition cond, XArchive *archive)
86 {
87 GIOStatus status;
88 gchar *line;
89
90 if (cond & G_IO_IN)
91 {
92 status = g_io_channel_read_line(ioc, &line, NULL, NULL, NULL);
93
94 if (status == G_IO_STATUS_NORMAL)
95 {
96 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prefs_window->store_output)))
97 {
98 if (!g_utf8_validate(line, -1, NULL))
99 {
100 gchar *utf8 = g_locale_to_utf8(line, -1, NULL, NULL, NULL);
101
102 if (utf8)
103 {
104 g_free(line);
105 line = utf8;
106 }
107 }
108
109 archive->output = g_slist_prepend(archive->output, g_strdup(line));
110 }
111
112 g_free(line);
113
114 return TRUE;
115 }
116 else if (status == G_IO_STATUS_AGAIN)
117 return TRUE;
118 else
119 cond &= ~G_IO_IN;
120 }
121
122 g_io_channel_shutdown(ioc, FALSE, NULL);
123 g_io_channel_unref(ioc);
124
125 xa_child_processed(XA_CHILD_STDERR, cond == G_IO_HUP, archive);
126
127 return FALSE;
128 }
129
xa_process_exit(GPid pid,gint status,XArchive * archive)130 static void xa_process_exit (GPid pid, gint status, XArchive *archive)
131 {
132 gboolean result;
133
134 if (WIFEXITED(status))
135 {
136 result = (WEXITSTATUS(status) == 0 || (archive->status == XARCHIVESTATUS_RELOAD &&
137 !g_file_test(archive->path[0], G_FILE_TEST_EXISTS)));
138 g_spawn_close_pid(pid);
139 xa_child_processed(XA_CHILD_EXIT, result, archive);
140 }
141 }
142
xa_delete_working_directory(XArchive * archive)143 static void xa_delete_working_directory (XArchive *archive)
144 {
145 if (xa_main_window)
146 xa_launch_external_program("rm -rf", archive->working_dir);
147 else
148 {
149 char *argv[4];
150 argv[0] = "rm";
151 argv[1] = "-rf";
152 argv[2] = archive->working_dir;
153 argv[3] = NULL;
154 g_spawn_sync (NULL, argv, NULL,G_SPAWN_SEARCH_PATH,NULL, NULL,NULL,NULL, NULL,NULL);
155 }
156 }
157
xa_alloc_memory_for_each_row(guint columns,GType column_types[])158 static XEntry *xa_alloc_memory_for_each_row (guint columns, GType column_types[])
159 {
160 XEntry *entry = NULL;
161 guint i;
162 gint size = 0;
163
164 entry = g_new0(XEntry,1);
165 if (entry == NULL)
166 return NULL;
167
168 for (i = 2; i < columns - 1; i++)
169 {
170 switch(column_types[i])
171 {
172 case G_TYPE_STRING:
173 size += sizeof(gchar *);
174 break;
175
176 case G_TYPE_UINT64:
177 size += sizeof(guint64);
178 break;
179 }
180 }
181 entry->columns = g_malloc0 (size);
182 return entry;
183 }
184
xa_find_directory_entry(XEntry * entry,const gchar * name)185 static XEntry *xa_find_directory_entry (XEntry *entry, const gchar *name)
186 {
187 gchar *filename;
188
189 if (entry == NULL)
190 return NULL;
191
192 if (g_utf8_validate(entry->filename, -1, NULL))
193 filename = g_filename_display_name(name);
194 else
195 filename = g_strdup(name);
196
197 if (entry->is_dir && strcmp(entry->filename, filename) == 0)
198 {
199 g_free(filename);
200 return entry;
201 }
202
203 g_free(filename);
204
205 return xa_find_directory_entry(entry->next, name);
206 }
207
xa_fill_archive_entry_columns_for_each_row(XArchive * archive,XEntry * entry,gpointer * items)208 static gpointer *xa_fill_archive_entry_columns_for_each_row (XArchive *archive, XEntry *entry, gpointer *items)
209 {
210 guint i;
211 gpointer current_column;
212
213 current_column = entry->columns;
214
215 for (i = 2; i < archive->columns - 1; i++)
216 {
217 switch(archive->column_types[i])
218 {
219 case G_TYPE_STRING:
220 *(gchar **) current_column = g_strdup((gchar *) items[i - 2]);
221 //g_message ("%d - %s",i,(*((gchar **)current_column)));
222 current_column += sizeof(gchar *);
223 break;
224
225 case G_TYPE_UINT64:
226 *(guint64 *) current_column = g_ascii_strtoull(items[i - 2], NULL, 0);
227 //g_message ("*%d - %lu",i,(*((guint64 *)current_column)));
228 current_column += sizeof(guint64);
229 break;
230 }
231 }
232 return entry->columns;
233 }
234
xa_build_dir_sidebar(XEntry * entry,GtkTreeStore * model,gchar * path,GtkTreeIter * containing_iter)235 static void xa_build_dir_sidebar (XEntry *entry, GtkTreeStore *model, gchar *path, GtkTreeIter *containing_iter)
236 {
237 GtkTreeIter child_iter;
238
239 if (!entry)
240 return;
241
242 if (strlen(entry->filename) == 0)
243 return xa_build_dir_sidebar(entry->child, model, path, containing_iter);
244
245 if (entry->is_dir)
246 {
247 gtk_tree_store_append(model,&child_iter,containing_iter);
248
249 if (!g_utf8_validate(entry->filename, -1, NULL))
250 {
251 gchar *entry_utf8 = g_filename_display_name(entry->filename);
252 g_free(entry->filename);
253 entry->filename = entry_utf8;
254 }
255
256 gtk_tree_store_set(model,&child_iter,0,"gtk-directory",1,entry->filename,2,entry,-1);
257 }
258 xa_build_dir_sidebar(entry->child, model, NULL, &child_iter);
259 xa_build_dir_sidebar(entry->next, model, NULL, containing_iter);
260
261 }
262
xa_dir_sidebar_find_row(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer entry)263 static gboolean xa_dir_sidebar_find_row (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer entry)
264 {
265 XEntry *entry2;
266 GtkTreeIter parent;
267 gboolean value;
268
269 gtk_tree_model_get (model,iter,2,&entry2,-1);
270 if (entry == entry2)
271 {
272 gtk_tree_model_iter_parent(model,&parent,iter);
273 if ( ! gtk_tree_view_row_expanded(GTK_TREE_VIEW(archive_dir_treeview),path))
274 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(archive_dir_treeview),path);
275
276 gtk_tree_selection_select_iter(gtk_tree_view_get_selection (GTK_TREE_VIEW (archive_dir_treeview)),iter);
277 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(archive_dir_treeview),path,NULL,FALSE,0,0);
278 value = TRUE;
279 }
280 else
281 value = FALSE;
282
283 return value;
284 }
285
xa_get_compressed_tar_type(XArchiveType * type)286 gboolean xa_get_compressed_tar_type (XArchiveType *type)
287 {
288 switch (*type)
289 {
290 case XARCHIVETYPE_BZIP2:
291 *type = XARCHIVETYPE_TAR_BZIP2;
292 break;
293
294 case XARCHIVETYPE_COMPRESS:
295 *type = XARCHIVETYPE_TAR_COMPRESS;
296 break;
297
298 case XARCHIVETYPE_GZIP:
299 *type = XARCHIVETYPE_TAR_GZIP;
300 break;
301
302 case XARCHIVETYPE_LRZIP:
303 *type = XARCHIVETYPE_TAR_LRZIP;
304 break;
305
306 case XARCHIVETYPE_LZ4:
307 *type = XARCHIVETYPE_TAR_LZ4;
308 break;
309
310 case XARCHIVETYPE_LZIP:
311 *type = XARCHIVETYPE_TAR_LZIP;
312 break;
313
314 case XARCHIVETYPE_LZMA:
315 *type = XARCHIVETYPE_TAR_LZMA;
316 break;
317
318 case XARCHIVETYPE_LZOP:
319 *type = XARCHIVETYPE_TAR_LZOP;
320 break;
321
322 case XARCHIVETYPE_XZ:
323 *type = XARCHIVETYPE_TAR_XZ;
324 break;
325
326 case XARCHIVETYPE_ZSTD:
327 *type = XARCHIVETYPE_TAR_ZSTD;
328 break;
329
330 default:
331 return FALSE;
332 }
333
334 return TRUE;
335 }
336
xa_init_archive_structure(ArchiveType xa)337 XArchive *xa_init_archive_structure (ArchiveType xa)
338 {
339 XArchive *archive;
340 XEntry *entry;
341
342 archive = g_new0(XArchive, 1);
343
344 if (!archive)
345 return NULL;
346
347 archive->type = xa.type;
348 archive->tag = xa.tag;
349
350 entry = g_new0(XEntry, 1);
351
352 if (!entry)
353 {
354 g_free(archive);
355 return NULL;
356 }
357
358 entry->filename = "";
359 archive->root_entry = entry;
360
361 archive->archiver = &archiver[xa.type];
362
363 if (archive_dir_treestore)
364 gtk_tree_store_clear(archive_dir_treestore);
365
366 (*archive->archiver->ask)(archive);
367
368 return archive;
369 }
370
xa_spawn_async_process(XArchive * archive,const gchar * command)371 void xa_spawn_async_process (XArchive *archive, const gchar *command)
372 {
373 gint argc;
374 gchar **argv;
375 GError *error = NULL;
376 GIOChannel *ioc;
377
378 g_shell_parse_argv(command, &argc, &argv, NULL);
379
380 if (!g_spawn_async_with_pipes(archive->child_dir,
381 argv,
382 NULL,
383 G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
384 NULL,
385 NULL,
386 &archive->child_pid,
387 NULL,
388 &archive->child_fdout,
389 &archive->child_fderr,
390 &error))
391 {
392 g_strfreev(argv);
393
394 xa_show_message_dialog(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Can't run the archiver executable:"), error->message);
395 g_error_free(error);
396
397 if (xa_main_window)
398 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);
399
400 archive->status = XARCHIVESTATUS_ERROR;
401 return;
402 }
403
404 g_strfreev(argv);
405
406 g_free(archive->command);
407 archive->command = g_strdup(command);
408
409 archive->child_ref = XA_CHILD_PROCS;
410
411 if (xa_main_window)
412 {
413 gtk_widget_set_sensitive(Stop_button, TRUE);
414 g_timeout_add(350, (GSourceFunc) xa_flash_led_indicator, archive);
415 }
416 else if (progress && !progress->multi_extract)
417 g_timeout_add(100, xa_pulse_progress_bar, NULL);
418
419 if (archive->output)
420 {
421 g_slist_free_full(archive->output, g_free);
422 archive->output = NULL;
423 }
424
425 ioc = g_io_channel_unix_new(archive->child_fdout);
426 g_io_channel_set_encoding(ioc, NULL, NULL);
427 g_io_channel_set_flags(ioc, G_IO_FLAG_NONBLOCK, NULL);
428 g_io_add_watch(ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) xa_process_stdout, archive);
429
430 ioc = g_io_channel_unix_new(archive->child_fderr);
431 g_io_channel_set_encoding(ioc, NULL, NULL);
432 g_io_channel_set_flags(ioc, G_IO_FLAG_NONBLOCK, NULL);
433 g_io_add_watch(ioc, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) xa_process_stderr, archive);
434
435 if (archive->parse_output)
436 g_child_watch_add_full(G_PRIORITY_LOW, archive->child_pid, (GChildWatchFunc) xa_process_exit, archive, NULL);
437 }
438
439 /* TODO: workaround for bug #3235
440 *
441 * gchar *xa_split_command_line(XArchive *archive,GSList *list)
442 {
443 gchar *command = NULL;
444 GSList *chunks = NULL;
445 GSList *scan = NULL;
446 int length;
447
448 for (scan = list; scan != NULL;)
449 {
450 length = 0;
451 while ((scan != NULL) && (length < 5000)) //MAX_CMD_LEN
452 {
453 length += strlen (scan->data);
454 chunks = g_slist_prepend(chunks,scan->data);
455 scan = scan->next;
456 }
457 chunks = g_slist_prepend(chunks,"****** ");
458 }
459 chunks = g_slist_reverse(chunks);
460 return command;
461 }
462 */
463
xa_clean_archive_structure(XArchive * archive)464 void xa_clean_archive_structure (XArchive *archive)
465 {
466 xa_free_entry(archive, archive->root_entry);
467
468 if (archive->working_dir)
469 {
470 xa_delete_working_directory(archive);
471 g_free(archive->working_dir);
472 }
473
474 if (archive->comment)
475 g_string_free(archive->comment, TRUE);
476
477 if (archive->output)
478 g_slist_free_full(archive->output, g_free);
479
480 if (archive->clipboard)
481 xa_clipboard_clear(NULL, archive);
482
483 g_free(archive->column_types);
484 g_free(archive->path[0]);
485 g_free(archive->path[1]);
486 g_free(archive->path[2]);
487 g_free(archive->destination_path);
488 g_free(archive->extraction_dir);
489 g_free(archive->password);
490 g_free(archive->child_dir);
491 g_free(archive->command);
492 g_free(archive);
493 }
494
xa_create_working_directory(XArchive * archive)495 gboolean xa_create_working_directory (XArchive *archive)
496 {
497 gchar *tmp_dir;
498 gchar *value;
499
500 if (archive->working_dir != NULL)
501 return TRUE;
502
503 value = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(prefs_window->combo_prefered_temp_dir));
504
505 if (value && *value)
506 {
507 gchar *value_local = g_filename_from_utf8(value, -1, NULL, NULL, NULL);
508 tmp_dir = g_strconcat(value_local, "/xa-XXXXXX", NULL);
509 g_free(value_local);
510 }
511 else
512 tmp_dir = g_strdup("");
513
514 g_free(value);
515
516 if (!g_mkdtemp(tmp_dir))
517 {
518 g_free(tmp_dir);
519 tmp_dir = NULL;
520
521 xa_show_message_dialog (GTK_WINDOW (xa_main_window),GTK_DIALOG_MODAL,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("Can't create temporary directory:"),g_strerror(errno));
522 return FALSE;
523 }
524
525 archive->working_dir = tmp_dir;
526 return TRUE;
527 }
528
xa_create_containing_directory(XArchive * archive,const gchar * path)529 gchar *xa_create_containing_directory (XArchive *archive, const gchar *path)
530 {
531 gchar *stem, *dir;
532 char *dot;
533 guint i;
534
535 stem = g_path_get_basename(archive->path[0]);
536 dot = strrchr(stem, '.');
537
538 if (dot)
539 *dot = 0;
540
541 if (g_str_has_suffix(stem, ".tar"))
542 {
543 dot = strrchr(stem, '.');
544 *dot = 0;
545 }
546
547 dir = g_strconcat(path, "/", stem, NULL);
548
549 for (i = 0; i < 100; i++)
550 {
551 if (i > 0)
552 {
553 g_free(dir);
554 dir = g_strdup_printf("%s/%s-(%d)", path, stem, i);
555 }
556
557 if (!g_file_test(dir, G_FILE_TEST_EXISTS))
558 {
559 if (g_mkdir_with_parents(dir, 0700) == 0)
560 {
561 g_free(stem);
562
563 return dir;
564 }
565 }
566 }
567
568 g_free(stem);
569
570 return NULL;
571 }
572
xa_run_command(XArchive * archive,const gchar * command)573 gboolean xa_run_command (XArchive *archive, const gchar *command)
574 {
575 pid_t pid = 0;
576 int status;
577 gboolean result;
578
579 /* batch mode and archive's list function has completed */
580 if (!xa_main_window && archive->column_types)
581 xa_show_progress_bar(archive);
582
583 xa_spawn_async_process(archive, command);
584
585 if (archive->child_pid == 0)
586 result = FALSE;
587 else
588 {
589 while (pid != archive->child_pid && pid != -1)
590 {
591 pid = waitpid(archive->child_pid, &status, WNOHANG);
592
593 while (gtk_events_pending())
594 gtk_main_iteration();
595 }
596
597 result = (WIFEXITED(status) && (WEXITSTATUS(status) == 0));
598 }
599
600 xa_child_processed(XA_CHILD_EXIT, result, archive);
601
602 return result;
603 }
604
xa_has_containing_directory(XArchive * archive)605 gboolean xa_has_containing_directory (XArchive *archive)
606 {
607 XEntry *entry;
608 guint n = 0;
609
610 entry = archive->root_entry->child;
611
612 while (entry)
613 {
614 if (++n > 1) break;
615
616 entry = entry->next;
617 }
618
619 return (n == 1) && archive->root_entry->child->is_dir;
620 }
621
xa_find_archive_index(gint page_num)622 gint xa_find_archive_index (gint page_num)
623 {
624 GtkWidget *page;
625 gint i;
626
627 page = gtk_notebook_get_nth_page(notebook, page_num);
628
629 for (i = 0; i < MAX_XARCHIVES; i++)
630 {
631 if (archive[i] != NULL && archive[i]->page == page)
632 return i;
633 }
634
635 return -1;
636 }
637
xa_get_new_archive_idx()638 gint xa_get_new_archive_idx()
639 {
640 gint i;
641
642 for (i = 0; i < MAX_XARCHIVES; i++)
643 {
644 if (archive[i] == NULL)
645 return i;
646 }
647 return -1;
648 }
649
xa_free_entry(XArchive * archive,XEntry * entry)650 void xa_free_entry (XArchive *archive, XEntry *entry)
651 {
652 gpointer current_column;
653 guint i;
654
655 if (entry->child)
656 xa_free_entry(archive, entry->child);
657
658 if (entry->next)
659 xa_free_entry(archive, entry->next);
660
661 if (entry->columns)
662 {
663 current_column = entry->columns;
664
665 if (*entry->filename)
666 {
667 for (i = 2; i < archive->columns - 1; i++)
668 {
669 switch (archive->column_types[i])
670 {
671 case G_TYPE_STRING:
672 g_free(*(gchar **) current_column);
673 current_column += sizeof(gchar *);
674 break;
675
676 case G_TYPE_UINT64:
677 current_column += sizeof(guint64);
678 break;
679 }
680 }
681
682 g_free(entry->columns);
683 g_free(entry->filename);
684 }
685 }
686
687 g_free(entry);
688 }
689
xa_set_archive_entries_for_each_row(XArchive * archive,const gchar * filename,gpointer * items)690 XEntry *xa_set_archive_entries_for_each_row (XArchive *archive, const gchar *filename, gpointer *items)
691 {
692 XEntry *entry = NULL, *last = archive->root_entry;
693 gchar **components;
694 guint n = 0;
695
696 components = g_strsplit(filename, "/", -1);
697
698 if (*filename == '/')
699 {
700 gchar *slashdir;
701
702 n = 1;
703 slashdir = g_strconcat("/", components[n], NULL);
704 g_free(components[n]);
705 components[n] = slashdir;
706 }
707
708 while (components[n] && *components[n])
709 {
710 entry = xa_find_directory_entry(last->child, components[n]);
711
712 if (entry == NULL)
713 {
714 entry = xa_alloc_memory_for_each_row(archive->columns, archive->column_types);
715
716 if (entry == NULL)
717 return NULL;
718
719 entry->filename = g_strdup(components[n]);
720
721 if (components[n + 1])
722 entry->is_dir = TRUE;
723
724 entry->next = last->child;
725 last->child = entry;
726 entry->prev = last;
727 }
728
729 if (components[n + 1] == NULL || *components[n + 1] == 0)
730 entry->columns = xa_fill_archive_entry_columns_for_each_row(archive, entry, items);
731
732 last = entry;
733 n++;
734 }
735
736 g_strfreev(components);
737
738 return entry;
739 }
740
xa_find_entry_from_dirpath(XArchive * archive,const gchar * dirpath)741 XEntry* xa_find_entry_from_dirpath (XArchive *archive, const gchar *dirpath)
742 {
743 XEntry *root = archive->root_entry, *entry = NULL;
744 gchar **components;
745 guint n = 0;
746
747 components = g_strsplit(dirpath, "/", -1);
748
749 while (components[n] && *components[n])
750 {
751 entry = xa_find_directory_entry(root->child, components[n]);
752 root = entry;
753 n++;
754 }
755
756 g_strfreev(components);
757
758 return entry;
759 }
760
xa_build_full_path_name_from_entry(XEntry * entry)761 gchar *xa_build_full_path_name_from_entry (XEntry *entry)
762 {
763 GString *path;
764 gchar *path_local;
765
766 path = g_string_new("");
767
768 while (entry)
769 {
770 if (entry->is_dir)
771 path = g_string_prepend_c(path, '/');
772
773 path = g_string_prepend(path, entry->filename);
774
775 entry = entry->prev;
776 }
777
778 if (g_utf8_validate(path->str, -1, NULL))
779 path_local = g_filename_from_utf8(path->str, -1, NULL, NULL, NULL);
780 else
781 path_local = g_strdup(path->str);
782
783 g_string_free(path, TRUE);
784
785 return path_local;
786 }
787
xa_fill_list_with_recursed_entries(XEntry * entry,GSList ** p_file_list)788 void xa_fill_list_with_recursed_entries(XEntry *entry,GSList **p_file_list)
789 {
790 if (entry == NULL)
791 return;
792
793 xa_fill_list_with_recursed_entries(entry->next ,p_file_list);
794 xa_fill_list_with_recursed_entries(entry->child,p_file_list);
795 *p_file_list = g_slist_prepend(*p_file_list, xa_build_full_path_name_from_entry(entry));
796 }
797
xa_detect_encrypted_archive(XArchive * archive)798 void xa_detect_encrypted_archive (XArchive *archive)
799 {
800 archive->status = XARCHIVESTATUS_LIST;
801 (*archive->archiver->list)(archive);
802
803 do
804 {
805 while (gtk_events_pending())
806 gtk_main_iteration();
807 }
808 while (archive->child_ref);
809 }
810
xa_fill_dir_sidebar(XArchive * archive,gboolean force_reload)811 void xa_fill_dir_sidebar(XArchive *archive,gboolean force_reload)
812 {
813 GtkTreeIter iter;
814
815 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(archive_dir_treestore), &iter) && force_reload == FALSE)
816 return;
817
818 gtk_tree_store_clear(archive_dir_treestore);
819 xa_build_dir_sidebar(archive->root_entry, archive_dir_treestore, NULL, NULL);
820 }
821
xa_dir_sidebar_row_selected(GtkTreeSelection * selection,gpointer user_data)822 void xa_dir_sidebar_row_selected (GtkTreeSelection *selection, gpointer user_data)
823 {
824 XEntry *entry;
825 GtkTreeIter iter;
826 GtkTreeIter parent;
827 GtkTreePath *path;
828 GtkTreeModel *model;
829 GString *string = g_string_new("");
830 gchar *dir;
831 gint idx;
832
833 idx = xa_find_archive_index(gtk_notebook_get_current_page(notebook));
834
835 if ((idx >= 0) && gtk_tree_selection_get_selected(selection, &model, &iter))
836 {
837 path = gtk_tree_model_get_path(model,&iter);
838 if ( ! gtk_tree_view_row_expanded(GTK_TREE_VIEW(archive_dir_treeview),path))
839 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(archive_dir_treeview),path);
840 gtk_tree_path_free(path);
841 /* Let get the last selected dir */
842 gtk_tree_model_get(model,&iter,1,&dir,-1);
843 g_string_prepend_c(string,'/');
844 g_string_prepend(string,dir);
845 /* Get the memory address of entry so to update the main listview */
846 gtk_tree_model_get(model,&iter,2,&entry,-1);
847 while (gtk_tree_model_iter_parent(model,&parent,&iter))
848 {
849 gtk_tree_model_get(model,&parent,1,&dir,-1);
850 g_string_prepend_c(string,'/');
851 g_string_prepend(string,dir);
852 iter = parent;
853 }
854 gtk_entry_set_text(GTK_ENTRY(location_entry),string->str);
855 g_string_free(string,TRUE);
856
857 xa_update_window_with_archive_entries(archive[idx],entry);
858 xa_set_statusbar_message_for_displayed_rows(archive[idx]);
859 }
860 }
861
xa_dir_sidebar_select_row(XEntry * entry)862 void xa_dir_sidebar_select_row (XEntry *entry)
863 {
864 gtk_tree_model_foreach(GTK_TREE_MODEL(archive_dir_treestore), xa_dir_sidebar_find_row, entry);
865 }
866
xa_sort_dirs_before_files(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,XArchive * archive)867 gint xa_sort_dirs_before_files (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, XArchive *archive)
868 {
869 XEntry *entry1, *entry2;
870
871 gtk_tree_model_get(model, a, archive->columns - 1, &entry1, -1);
872 gtk_tree_model_get(model, b, archive->columns - 1, &entry2, -1);
873 if (entry1->is_dir != entry2->is_dir)
874 {
875 if (entry1->is_dir)
876 return -1;
877 else
878 return 1;
879 }
880 /* This for sorting the files */
881 return strcasecmp (entry1->filename,entry2->filename);
882 }
883