1 /* vim: set textwidth=80 tabstop=4 */
4 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
5 * Copyright (C) 1999-2008 Michael Rasmussen and the Claws Mail Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "claws-features.h"
28 #include <glib/gi18n.h>
33 #include <sys/types.h>
38 #include "gtk/gtkutils.h"
39 #include "common/claws.h"
40 #include "common/version.h"
41 #include "common/md5.h"
43 #include "mainwindow.h"
47 #include "foldersel.h"
49 #include "procheader.h"
50 #include "libarchive_archive.h"
52 #include "archiver_prefs.h"
54 typedef struct _progress_widget progress_widget;
55 struct _progress_widget {
56 GtkWidget* progress_dialog;
61 GtkWidget* file_label;
68 A_FILE_EXISTS = 1 << 1,
69 A_FILE_IS_LINK = 1 << 2,
70 A_FILE_IS_DIR = 1 << 3,
71 A_FILE_NO_WRITE = 1 << 4,
72 A_FILE_UNKNOWN = 1 << 5
75 static progress_widget* progress = NULL;
77 static progress_widget* init_progress() {
78 progress_widget* ptr = malloc(sizeof(*ptr));
80 debug_print("creating progress struct\n");
81 ptr->progress_dialog = NULL;
85 ptr->add_label = NULL;
86 ptr->file_label = NULL;
93 static void progress_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
94 struct ArchivePage* page = (struct ArchivePage *) data;
96 debug_print("Cancel operation\n");
98 page->cancelled = TRUE;
99 archive_free_file_list(page->md5, page->rename);
100 gtk_widget_destroy(widget);
103 static void create_progress_dialog(struct ArchivePage* page) {
104 gchar* title = g_strdup_printf("%s %s", _("Archiving"), page->path);
105 MainWindow* mainwin = mainwindow_get_mainwindow();
107 progress->position = 0;
108 progress->progress_dialog = gtk_dialog_new_with_buttons (
110 GTK_WINDOW(mainwin->window),
111 GTK_DIALOG_DESTROY_WITH_PARENT,
117 progress->progress_dialog,
119 G_CALLBACK(progress_dialog_cb),
122 progress->frame = gtk_frame_new(_("Press Cancel button to stop archiving"));
123 gtk_frame_set_shadow_type(GTK_FRAME(progress->frame),
124 GTK_SHADOW_ETCHED_OUT);
125 gtk_container_set_border_width(GTK_CONTAINER(progress->frame), 4);
126 gtk_container_add(GTK_CONTAINER(
127 GTK_DIALOG(progress->progress_dialog)->vbox), progress->frame);
129 progress->vbox1 = gtk_vbox_new (FALSE, 4);
130 gtk_container_set_border_width (GTK_CONTAINER (progress->vbox1), 4);
131 gtk_container_add(GTK_CONTAINER(progress->frame), progress->vbox1);
133 progress->hbox1 = gtk_hbox_new(FALSE, 8);
134 gtk_container_set_border_width(GTK_CONTAINER(progress->hbox1), 8);
135 gtk_box_pack_start(GTK_BOX(progress->vbox1),
136 progress->hbox1, FALSE, FALSE, 0);
138 progress->add_label = gtk_label_new(_("Archiving:"));
139 gtk_box_pack_start(GTK_BOX(progress->hbox1),
140 progress->add_label, FALSE, FALSE, 0);
142 progress->file_label = gtk_label_new("");
143 gtk_label_set_ellipsize(GTK_LABEL(progress->file_label),
144 PANGO_ELLIPSIZE_START);
145 gtk_box_pack_start(GTK_BOX(progress->hbox1),
146 progress->file_label, TRUE, TRUE, 0);
148 progress->hbox1 = gtk_hbox_new(FALSE, 8);
149 gtk_container_set_border_width(GTK_CONTAINER(progress->hbox1), 8);
150 gtk_box_pack_start(GTK_BOX(progress->vbox1),
151 progress->hbox1, FALSE, FALSE, 0);
153 progress->progress = gtk_progress_bar_new();
154 gtk_box_pack_start(GTK_BOX(progress->hbox1),
155 progress->progress, TRUE, TRUE, 0);
156 gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(progress->progress), 0.25);
158 gtk_window_set_default_size(GTK_WINDOW(progress->progress_dialog), 400, 80);
159 gtk_widget_show_all(progress->progress_dialog);
162 static struct ArchivePage* init_archive_page() {
163 struct ArchivePage* page = malloc(sizeof(struct ArchivePage));
165 debug_print("creating ArchivePage\n");
170 page->response = FALSE;
171 page->force_overwrite = FALSE;
172 page->compress_methods = NULL;
173 page->archive_formats = NULL;
174 page->recursive = NULL;
175 page->cancelled = FALSE;
178 page->rename = FALSE;
179 page->rename_files = NULL;
180 page->isoDate = NULL;
181 page->unlink_files = NULL;
182 page->unlink = FALSE;
187 static void dispose_archive_page(struct ArchivePage* page) {
188 debug_print("freeing ArchivePage\n");
198 static gboolean uncommitted_entry_info(struct ArchivePage* page) {
199 const gchar* path = gtk_entry_get_text(GTK_ENTRY(page->folder));
200 const gchar* name = gtk_entry_get_text(GTK_ENTRY(page->file));
202 if (! page->path && *path != '\0') {
203 debug_print("page->path: (NULL) -> %s\n", path);
204 page->path = g_strdup(path);
206 if (! page->name && *name != '\0') {
207 page->force_overwrite = FALSE;
208 debug_print("page->file: (NULL) -> %s\n", name);
209 page->name = g_strdup(name);
212 return (page->path && page->name) ? TRUE : FALSE;
215 static gboolean valid_file_name(gchar* file) {
218 for (i = 0; INVALID_UNIX_CHARS[i] != '\0'; i++) {
219 if (g_utf8_strchr(file, g_utf8_strlen(file, -1), INVALID_UNIX_CHARS[i]))
225 static COMPRESS_METHOD get_compress_method(GSList* btn) {
229 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn->data))) {
230 name = gtk_widget_get_name(GTK_WIDGET(btn->data));
231 if (strcmp("ZIP", name) == 0) {
232 debug_print("ZIP compression enabled\n");
235 else if (strcmp("BZIP", name) == 0) {
236 debug_print("BZIP2 compression enabled\n");
239 else if (strcmp("COMPRESS", name) == 0) {
240 debug_print("COMPRESS compression enabled\n");
243 else if (strcmp("NONE", name) == 0) {
244 debug_print("Compression disabled\n");
248 btn = g_slist_next(btn);
253 static ARCHIVE_FORMAT get_archive_format(GSList* btn) {
257 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn->data))) {
258 name = gtk_widget_get_name(GTK_WIDGET(btn->data));
259 if (strcmp("TAR", name) == 0) {
260 debug_print("TAR archive enabled\n");
263 else if (strcmp("SHAR", name) == 0) {
264 debug_print("SHAR archive enabled\n");
267 else if (strcmp("PAX", name) == 0) {
268 debug_print("PAX archive enabled\n");
271 else if (strcmp("CPIO", name) == 0) {
272 debug_print("CPIO archive enabled\n");
276 btn = g_slist_next(btn);
281 static void create_md5sum(const gchar* file, const gchar* md5_file) {
284 gchar* md5sum = malloc(33);
286 debug_print("Creating md5sum file: %s\n", md5_file);
287 if (md5_hex_digest_file(md5sum, (const unsigned char *) file) == -1)
289 debug_print("md5sum: %s\n", md5sum);
291 open(md5_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1)
293 text = g_strrstr_len(file, strlen(file), "/");
296 text = g_strdup_printf("%s %s\n", md5sum, text);
299 text = g_strdup_printf("%s %s\n", md5sum, file);
301 debug_print("md5sum: %s\n", text);
302 if (write(fd, text, strlen(text)) < 0)
308 static gchar* descriptive_file_name(
309 struct ArchivePage* page, const gchar* file, MsgInfo *msginfo) {
310 gchar* new_file = NULL;
311 gchar *name, *p, *to, *from, *date, *subject;
313 debug_print("renaming file\n");
314 p = g_strrstr_len(file, strlen(file), "/");
315 p = g_strndup(file, p - file);
319 to = g_strdup(msginfo->to);
325 from = g_strdup(msginfo->from);
326 extract_address(from);
331 date = g_strdup(msginfo->date);
332 subst_for_shellsafe_filename(date);
333 /* if not on windows we need to subst some more */
334 subst_chars(date, ":", '_');
338 if (msginfo->subject) {
339 subject = g_strdup(msginfo->subject);
340 subst_for_shellsafe_filename(subject);
341 /* if not on windows we need to subst some more */
342 subst_chars(subject, ":", '_');
345 subject = g_strdup("");
346 name = g_strdup_printf("%s_%s@%s@%s", date, from, to, subject);
347 /* ensure file name is not larger than 96 chars (max file name size
348 * is 100 chars but reserve for .md5)
350 if (strlen(name) > 96)
353 new_file = g_strconcat(p, "/", name, NULL);
362 debug_print("New_file: %s\n", new_file);
363 if (link(file, new_file) != 0) {
364 if (errno != EEXIST) {
367 new_file = g_strdup(file);
368 page->rename = FALSE;
375 static void walk_folder(struct ArchivePage* page, FolderItem* item,
376 gboolean recursive) {
383 gchar* md5_file = NULL;
386 MsgTrash* msg_trash = NULL;
387 const gchar* date = NULL;
389 if (recursive && ! page->cancelled) {
390 debug_print("Scanning recursive\n");
391 node = item->node->children;
392 while(node && ! page->cancelled) {
393 debug_print("Number of nodes: %d\n", g_node_n_children(node));
395 child = FOLDER_ITEM(node->data);
396 debug_print("new node: %d messages\n", child->total_msgs);
397 walk_folder(page, child, recursive);
402 if (! page->cancelled) {
403 date = gtk_entry_get_text(GTK_ENTRY(page->isoDate));
404 debug_print("cut-off date: %s\n", date);
406 page->files += item->total_msgs;
407 msglist = folder_item_get_msg_list(item);
408 msg_trash = new_msg_trash(item);
409 for (cur = msglist; cur && ! page->cancelled; cur = cur->next) {
410 msginfo = (MsgInfo *) cur->data;
411 debug_print("%s_%s_%s_%s\n",
412 msginfo->date, msginfo->to, msginfo->from, msginfo->subject);
413 file = folder_item_fetch_msg(item, msginfo->msgnum);
414 if (date && strlen(date) > 0 && !before_date(msginfo->date_t, date)) {
418 page->total_size += msginfo->size;
419 /*debug_print("Processing: %s\n", file);*/
422 archive_add_msg_mark(msg_trash, msginfo);
425 file = descriptive_file_name(page, file, msginfo);
427 /* Could not create a descriptive name */
428 file = folder_item_fetch_msg(item, msginfo->msgnum);
432 md5_file = g_strdup_printf("%s.md5", file);
433 create_md5sum(file, md5_file);
434 archive_add_file(md5_file);
437 archive_add_file(file);
441 if (count % 350 == 0) {
442 debug_print("pulse progressbar\n");
443 text = g_strdup_printf(
444 "Scanning %s: %d files", item->name, count);
445 gtk_progress_bar_set_text(
446 GTK_PROGRESS_BAR(progress->progress), text);
448 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress->progress));
453 procmsg_msg_list_free(msglist);
457 static AFileTest file_is_writeable(struct ArchivePage* page) {
460 if (g_file_test(page->name, G_FILE_TEST_EXISTS) &&
461 ! page->force_overwrite)
462 return A_FILE_EXISTS;
463 if (g_file_test(page->name, G_FILE_TEST_IS_SYMLINK))
464 return A_FILE_IS_LINK;
465 if (g_file_test(page->name, G_FILE_TEST_IS_DIR))
466 return A_FILE_IS_DIR;
467 if ((fd = open(page->name, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
469 case EACCES: return A_FILE_NO_WRITE;
470 case EEXIST: return A_FILE_OK;
471 default: return A_FILE_UNKNOWN;
476 claws_unlink(page->name);
481 static gboolean archiver_save_files(struct ArchivePage* page) {
483 MainWindow* mainwin = mainwindow_get_mainwindow();
485 COMPRESS_METHOD method;
486 ARCHIVE_FORMAT format;
491 const gchar* res = NULL;
495 if (page->path == NULL || page->name == NULL) {
496 /* Test if page->file and page->folder has uncommitted information */
497 if (! uncommitted_entry_info(page)) {
498 dialog = gtk_message_dialog_new(
499 GTK_WINDOW(mainwin->window),
500 GTK_DIALOG_DESTROY_WITH_PARENT,
503 _("Folder and archive must be selected"));
504 gtk_dialog_run (GTK_DIALOG (dialog));
505 gtk_widget_destroy (dialog);
509 if ((perm = file_is_writeable(page)) != A_FILE_OK) {
512 msg = g_strdup_printf(_("%s: Exists. Continue anyway?"), page->name);
515 msg = g_strdup_printf(_("%s: Is a link. Cannot continue"), page->name);
518 msg = g_strdup_printf(_("%s: Is a directory. Cannot continue"), page->name);
520 case A_FILE_NO_WRITE:
521 msg = g_strdup_printf(_("%s: Missing permissions. Cannot continue"), page->name);
524 msg = g_strdup_printf(_("%s: Unknown error. Cannot continue"), page->name);
528 if (perm == A_FILE_EXISTS) {
529 dialog = gtk_message_dialog_new(
530 GTK_WINDOW(mainwin->window),
531 GTK_DIALOG_DESTROY_WITH_PARENT,
533 GTK_BUTTONS_OK_CANCEL,
535 response = gtk_dialog_run(GTK_DIALOG (dialog));
536 gtk_widget_destroy(dialog);
538 if (response == GTK_RESPONSE_CANCEL) {
543 dialog = gtk_message_dialog_new(
544 GTK_WINDOW(mainwin->window),
545 GTK_DIALOG_DESTROY_WITH_PARENT,
549 response = gtk_dialog_run(GTK_DIALOG (dialog));
550 gtk_widget_destroy(dialog);
555 if (! valid_file_name(page->name)) {
556 dialog = gtk_message_dialog_new(
557 GTK_WINDOW(mainwin->window),
558 GTK_DIALOG_DESTROY_WITH_PARENT,
561 _("Not a valid file name:\n%s."),
563 gtk_dialog_run (GTK_DIALOG (dialog));
564 gtk_widget_destroy (dialog);
567 item = folder_find_item_from_identifier(page->path);
569 dialog = gtk_message_dialog_new(
570 GTK_WINDOW(mainwin->window),
571 GTK_DIALOG_DESTROY_WITH_PARENT,
574 _("Not a valid Claws Mail folder:\n%s."),
576 gtk_dialog_run (GTK_DIALOG (dialog));
577 gtk_widget_destroy (dialog);
581 page->total_size = 0;
582 page->rename = gtk_toggle_button_get_active(
583 GTK_TOGGLE_BUTTON(page->rename_files));
584 recursive = gtk_toggle_button_get_active(
585 GTK_TOGGLE_BUTTON(page->recursive));
586 page->md5 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->md5sum));
587 page->unlink = gtk_toggle_button_get_active(
588 GTK_TOGGLE_BUTTON(page->unlink_files));
589 create_progress_dialog(page);
590 walk_folder(page, item, recursive);
593 list = archive_get_file_list();
594 orig_file = (page->md5) ? page->files * 2 : page->files;
595 debug_print("md5: %d, orig: %d, md5: %d\n",
596 page->md5, page->files, orig_file);
597 if (orig_file != g_slist_length(list)) {
598 dialog = gtk_message_dialog_new(
599 GTK_WINDOW(mainwin->window),
600 GTK_DIALOG_DESTROY_WITH_PARENT,
602 GTK_BUTTONS_OK_CANCEL,
603 _("Adding files in folder failed\n"
604 "Files in folder: %d\n"
605 "Files in list: %d\n"
606 "\nContinue anyway?"),
607 orig_file, g_slist_length(list));
608 response = gtk_dialog_run(GTK_DIALOG (dialog));
609 gtk_widget_destroy(dialog);
610 if (response == GTK_RESPONSE_CANCEL) {
611 archive_free_file_list(page->md5, page->rename);
615 method = get_compress_method(page->compress_methods);
616 format = get_archive_format(page->archive_formats);
617 if ((res = archive_create(page->name, list, method, format)) != NULL) {
618 dialog = gtk_message_dialog_new(
619 GTK_WINDOW(mainwin->window),
620 GTK_DIALOG_DESTROY_WITH_PARENT,
624 gtk_dialog_run (GTK_DIALOG (dialog));
625 gtk_widget_destroy (dialog);
626 archive_free_file_list(page->md5, page->rename);
630 archive_free_archived_files();
635 static void entry_change_cb(GtkWidget* widget, gpointer data) {
636 const gchar* name = gtk_widget_get_name(widget);
637 struct ArchivePage* page = (struct ArchivePage *) data;
639 if (strcmp("folder", name) == 0) {
640 page->path = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
641 debug_print("page->folder = %s\n", page->path);
643 else if (strcmp("file", name) == 0) {
644 page->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
645 page->force_overwrite = FALSE;
646 debug_print("page->name = %s\n", page->name);
650 static void show_result(struct ArchivePage* page) {
662 GtkTreeViewColumn* header;
663 GtkCellRenderer* renderer;
666 gchar* method = NULL;
667 gchar* format = NULL;
669 MainWindow* mainwin = mainwindow_get_mainwindow();
671 switch (get_compress_method(page->compress_methods)) {
673 method = g_strdup("ZIP");
676 method = g_strdup("BZIP2");
679 method = g_strdup("Compress");
682 method = g_strdup("No Compression");
686 switch (get_archive_format(page->archive_formats)) {
688 format = g_strdup("TAR");
691 format = g_strdup("SHAR");
694 format = g_strdup("PAX");
697 format = g_strdup("CPIO");
700 format = g_strdup("NO FORMAT");
703 g_stat(page->name, &st);
704 dialog = gtk_dialog_new_with_buttons(
706 GTK_WINDOW(mainwin->window),
707 GTK_DIALOG_DESTROY_WITH_PARENT,
711 g_signal_connect_swapped(
714 G_CALLBACK(gtk_widget_destroy),
717 list = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
723 "headers-clickable", FALSE,
724 "reorderable", FALSE,
725 "enable-search", FALSE,
728 renderer = gtk_cell_renderer_text_new();
730 header = gtk_tree_view_column_new_with_attributes(
731 _("Attributes"), renderer, "text", STRING1, NULL);
732 gtk_tree_view_append_column(view, header);
734 header = gtk_tree_view_column_new_with_attributes(
735 _("Values"), renderer, "text", STRING2, NULL);
736 gtk_tree_view_append_column(view, header);
739 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(view));
741 gtk_list_store_append(list, &iter);
744 STRING1, _("Archive"),
745 STRING2, page->name, -1);
747 gtk_list_store_append(list, &iter);
750 STRING1, _("Archive format"),
751 STRING2, format, -1);
754 gtk_list_store_append(list, &iter);
757 STRING1, _("Compression method"),
758 STRING2, method, -1);
761 gtk_list_store_append(list, &iter);
762 msg = g_strdup_printf("%d", (page->md5) ? page->files * 2 : page->files);
765 STRING1, _("Number of files"),
769 gtk_list_store_append(list, &iter);
770 msg = g_strdup_printf("%d byte(s)", (guint) st.st_size);
773 STRING1, _("Archive Size"),
777 gtk_list_store_append(list, &iter);
778 msg = g_strdup_printf("%d byte(s)", page->total_size);
781 STRING1, _("Folder Size"),
785 gtk_list_store_append(list, &iter);
786 msg = g_strdup_printf("%d%%",
787 (guint)((st.st_size * 100) / page->total_size));
790 STRING1, _("Compression level"),
794 gtk_list_store_append(list, &iter);
795 msg = g_strdup_printf("%s", (page->md5) ? _("Yes") : _("No"));
798 STRING1, _("MD5 checksum"),
802 gtk_list_store_append(list, &iter);
803 msg = g_strdup_printf("%s", (page->rename) ? _("Yes") : _("No"));
806 STRING1, _("Descriptive names"),
810 gtk_list_store_append(list, &iter);
811 msg = g_strdup_printf("%s", (page->unlink) ? _("Yes") : _("No"));
814 STRING1, _("Delete selected files"),
818 msg = g_strdup(gtk_entry_get_text(GTK_ENTRY(page->isoDate)));
820 gtk_list_store_append(list, &iter);
823 STRING1, _("Select mails before"),
828 gtk_window_set_default_size(GTK_WINDOW(dialog), 320, 260);
830 gtk_widget_show_all(dialog);
833 static void archiver_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
834 struct ArchivePage* page = (struct ArchivePage *) data;
835 gboolean result = FALSE;
838 case GTK_RESPONSE_ACCEPT:
839 debug_print("User chose OK\n");
840 page->response = TRUE;
843 debug_print("User chose CANCEL\n");
844 page->response = FALSE;
845 archiver_gtk_done(page, widget);
848 debug_print("Settings:\naction: %d\n", page->response);
849 if (page->response) {
850 debug_print("Settings:\nfolder: %s\nname: %s\n",
851 (page->path) ? page->path : "(null)",
852 (page->name) ? page->name : "(null)");
853 result = archiver_save_files(page);
854 debug_print("Result->archiver_save_files: %d\n", result);
855 if (progress->progress_dialog &&
856 GTK_IS_WIDGET(progress->progress_dialog))
857 gtk_widget_destroy(progress->progress_dialog);
858 if (result && ! page->cancelled) {
860 archive_free_file_list(page->md5, page->rename);
861 archiver_gtk_done(page, widget);
864 if (page->cancelled) {
865 archiver_gtk_done(page, widget);
871 static void foldersel_cb(GtkWidget *widget, gpointer data)
876 struct ArchivePage* page = (struct ArchivePage *) data;
878 item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
879 if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
880 gtk_editable_delete_text(GTK_EDITABLE(page->folder), 0, -1);
881 gtk_editable_insert_text(GTK_EDITABLE(page->folder),
882 item_id, strlen(item_id), &newpos);
883 page->path = g_strdup(item_id);
886 debug_print("Folder to archive: %s\n",
887 gtk_entry_get_text(GTK_ENTRY(page->folder)));
890 static void filesel_cb(GtkWidget *widget, gpointer data)
895 const gchar* homedir;
896 struct ArchivePage* page = (struct ArchivePage *) data;
898 dialog = gtk_file_chooser_dialog_new(
899 _("Select file name for archive [suffix should reflect archive like .tgz]"),
901 GTK_FILE_CHOOSER_ACTION_SAVE,
902 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
903 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
905 homedir = g_getenv("HOME");
907 homedir = g_get_home_dir();
909 if (archiver_prefs.save_folder)
910 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
911 archiver_prefs.save_folder);
913 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), homedir);
914 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY) {
915 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
917 gtk_editable_delete_text(GTK_EDITABLE(page->file), 0, -1);
918 gtk_editable_insert_text(GTK_EDITABLE(page->file),
919 file, strlen(file), &newpos);
920 page->name = g_strdup(file);
922 page->force_overwrite = TRUE;
925 gtk_widget_destroy(dialog);
926 debug_print("Name for archive: %s\n",
927 gtk_entry_get_text(GTK_ENTRY(page->file)));
930 void set_progress_file_label(const gchar* file) {
931 debug_print("IsLabel: %s, Update label: %s\n",
932 GTK_IS_WIDGET(progress->file_label)? "Yes" : "No", file);
933 if (GTK_IS_WIDGET(progress->file_label))
934 gtk_label_set_text(GTK_LABEL(progress->file_label), file);
937 void set_progress_print_all(guint fraction, guint total, guint step) {
940 if (GTK_IS_WIDGET(progress->progress)) {
941 if ((fraction - progress->position) % step == 0) {
942 debug_print("frac: %d, total: %d, step: %d, prog->pos: %d\n",
943 fraction, total, step, progress->position);
944 gtk_progress_bar_set_fraction(
945 GTK_PROGRESS_BAR(progress->progress),
946 (total == 0) ? 0 : (gfloat)fraction / (gfloat)total);
947 text_count = g_strdup_printf(_("%ld of %ld"),
948 (long) fraction, (long) total);
949 gtk_progress_bar_set_text(
950 GTK_PROGRESS_BAR(progress->progress), text_count);
952 progress->position = fraction;
958 void archiver_gtk_show() {
963 GtkWidget* folder_label;
964 GtkWidget* folder_select;
965 GtkWidget* file_label;
966 GtkWidget* file_select;
967 GtkWidget* zip_radio_btn;
968 GtkWidget* bzip_radio_btn;
969 GtkWidget* compress_radio_btn;
970 GtkWidget* no_radio_btn;
971 GtkWidget* shar_radio_btn;
972 GtkWidget* pax_radio_btn;
973 GtkWidget* cpio_radio_btn;
974 GtkWidget* tar_radio_btn;
975 struct ArchivePage* page;
976 MainWindow* mainwin = mainwindow_get_mainwindow();
978 /*debug_set_mode(TRUE);*/
979 progress = init_progress();
981 page = init_archive_page();
983 dialog = gtk_dialog_new_with_buttons (
985 GTK_WINDOW(mainwin->window),
986 GTK_DIALOG_DESTROY_WITH_PARENT,
996 G_CALLBACK(archiver_dialog_cb),
999 frame = gtk_frame_new(_("Enter Archiver arguments"));
1000 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1001 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1002 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
1004 vbox1 = gtk_vbox_new (FALSE, 4);
1005 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 4);
1006 gtk_container_add(GTK_CONTAINER(frame), vbox1);
1008 hbox1 = gtk_hbox_new(FALSE, 4);
1009 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1010 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1012 folder_label = gtk_label_new(_("Folder to archive"));
1013 gtk_box_pack_start(GTK_BOX(hbox1), folder_label, FALSE, FALSE, 0);
1015 page->folder = gtk_entry_new();
1016 gtk_widget_set_name(page->folder, "folder");
1017 gtk_box_pack_start(GTK_BOX(hbox1), page->folder, TRUE, TRUE, 0);
1018 CLAWS_SET_TIP(page->folder,
1019 _("Folder which is the root of the archive"));
1021 folder_select = gtkut_get_browse_directory_btn(_("_Browse"));
1022 gtk_box_pack_start(GTK_BOX(hbox1), folder_select, FALSE, FALSE, 0);
1023 CLAWS_SET_TIP(folder_select,
1024 _("Click this button to select a folder which is to be root of the archive"));
1026 hbox1 = gtk_hbox_new(FALSE, 4);
1027 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1028 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1030 file_label = gtk_label_new(_("Name for archive"));
1031 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1033 page->file = gtk_entry_new();
1034 gtk_widget_set_name(page->file, "file");
1035 gtk_box_pack_start(GTK_BOX(hbox1), page->file, TRUE, TRUE, 0);
1036 CLAWS_SET_TIP(page->file, _("Archive location and name"));
1038 file_select = gtkut_get_browse_directory_btn(_("_Select"));
1039 gtk_box_pack_start(GTK_BOX(hbox1), file_select, FALSE, FALSE, 0);
1040 CLAWS_SET_TIP(file_select,
1041 _("Click this button to select a name and location for the archive"));
1043 frame = gtk_frame_new(_("Choose compression"));
1044 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1045 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1046 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1048 hbox1 = gtk_hbox_new(FALSE, 4);
1049 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1050 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1052 zip_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_ZIP");
1053 gtk_widget_set_name(zip_radio_btn, "ZIP");
1054 gtk_box_pack_start(GTK_BOX(hbox1), zip_radio_btn, FALSE, FALSE, 0);
1055 CLAWS_SET_TIP(zip_radio_btn,
1056 _("Choose this option to use ZIP compression for the archive"));
1058 bzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1059 GTK_RADIO_BUTTON(zip_radio_btn), "BZIP_2");
1060 gtk_widget_set_name(bzip_radio_btn, "BZIP");
1061 gtk_box_pack_start(GTK_BOX(hbox1), bzip_radio_btn, FALSE, FALSE, 0);
1062 CLAWS_SET_TIP(bzip_radio_btn,
1063 _("Choose this option to use BZIP2 compression for the archive"));
1065 compress_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1066 GTK_RADIO_BUTTON(zip_radio_btn), "Com_press");
1067 gtk_widget_set_name(compress_radio_btn, "COMPRESS");
1068 gtk_box_pack_start(GTK_BOX(hbox1), compress_radio_btn, FALSE, FALSE, 0);
1069 CLAWS_SET_TIP(compress_radio_btn,
1070 _("Choose this to use Compress compression for your archive"));
1072 no_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1073 GTK_RADIO_BUTTON(zip_radio_btn), _("_None"));
1074 gtk_widget_set_name(no_radio_btn, "NONE");
1075 gtk_box_pack_start(GTK_BOX(hbox1), no_radio_btn, FALSE, FALSE, 0);
1076 CLAWS_SET_TIP(no_radio_btn,
1077 _("Choose this option to disable compression for the archive"));
1079 page->compress_methods =
1080 gtk_radio_button_get_group(GTK_RADIO_BUTTON(zip_radio_btn));
1082 switch (archiver_prefs.compression) {
1083 case COMPRESSION_ZIP:
1084 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(zip_radio_btn), TRUE);
1086 case COMPRESSION_BZIP:
1087 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bzip_radio_btn), TRUE);
1089 case COMPRESSION_COMPRESS:
1090 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compress_radio_btn), TRUE);
1092 case COMPRESSION_NONE:
1093 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(no_radio_btn), TRUE);
1097 frame = gtk_frame_new(_("Choose format"));
1098 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1099 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1100 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1102 hbox1 = gtk_hbox_new(FALSE, 4);
1103 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1104 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1106 tar_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_TAR");
1107 gtk_widget_set_name(tar_radio_btn, "TAR");
1108 gtk_box_pack_start(GTK_BOX(hbox1), tar_radio_btn, FALSE, FALSE, 0);
1109 CLAWS_SET_TIP(tar_radio_btn,
1110 _("Choose this option to use TAR as format for the archive"));
1112 shar_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1113 GTK_RADIO_BUTTON(tar_radio_btn), "S_HAR");
1114 gtk_widget_set_name(shar_radio_btn, "SHAR");
1115 gtk_box_pack_start(GTK_BOX(hbox1), shar_radio_btn, FALSE, FALSE, 0);
1116 CLAWS_SET_TIP(shar_radio_btn,
1117 _("Choose this to use SHAR as format for the archive"));
1119 cpio_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1120 GTK_RADIO_BUTTON(tar_radio_btn), "CP_IO");
1121 gtk_widget_set_name(cpio_radio_btn, "CPIO");
1122 gtk_box_pack_start(GTK_BOX(hbox1), cpio_radio_btn, FALSE, FALSE, 0);
1123 CLAWS_SET_TIP(cpio_radio_btn,
1124 _("Choose this option to use CPIO as format for the archive"));
1126 pax_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1127 GTK_RADIO_BUTTON(tar_radio_btn), "PA_X");
1128 gtk_widget_set_name(pax_radio_btn, "PAX");
1129 gtk_box_pack_start(GTK_BOX(hbox1), pax_radio_btn, FALSE, FALSE, 0);
1130 CLAWS_SET_TIP(pax_radio_btn,
1131 _("Choose this option to use PAX as format for the archive"));
1133 page->archive_formats =
1134 gtk_radio_button_get_group(GTK_RADIO_BUTTON(tar_radio_btn));
1136 switch (archiver_prefs.format) {
1138 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tar_radio_btn), TRUE);
1141 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shar_radio_btn), TRUE);
1144 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cpio_radio_btn), TRUE);
1147 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pax_radio_btn), TRUE);
1151 frame = gtk_frame_new(_("Miscellaneous options"));
1152 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1153 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1154 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1156 hbox1 = gtk_hbox_new(FALSE, 4);
1157 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1158 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1160 page->recursive = gtk_check_button_new_with_mnemonic(_("_Recursive"));
1161 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->recursive), archiver_prefs.recursive);
1162 gtk_box_pack_start(GTK_BOX(hbox1), page->recursive, FALSE, FALSE, 0);
1163 CLAWS_SET_TIP(page->recursive,
1164 _("Choose this option to include subfolders in the archive"));
1166 page->md5sum = gtk_check_button_new_with_mnemonic(_("_MD5sum"));
1167 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->md5sum), archiver_prefs.md5sum);
1168 gtk_box_pack_start(GTK_BOX(hbox1), page->md5sum, FALSE, FALSE, 0);
1169 CLAWS_SET_TIP(page->md5sum,
1170 _("Choose this option to add MD5 checksums for each file in the archive.\n"
1171 "Be aware though, that this dramatically increases the time it\n"
1172 "will take to create the archive"));
1174 page->rename_files = gtk_check_button_new_with_mnemonic(_("R_ename"));
1175 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->rename_files), archiver_prefs.rename);
1176 gtk_box_pack_start(GTK_BOX(hbox1), page->rename_files, FALSE, FALSE, 0);
1177 CLAWS_SET_TIP(page->rename_files,
1178 _("Choose this option to use descriptive names for each file in the archive.\n"
1179 "The naming scheme: date_from@to@subject.\n"
1180 "Names will be truncated to max 96 characters"));
1182 page->unlink_files = gtk_check_button_new_with_mnemonic(_("_Delete"));
1183 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->unlink_files), archiver_prefs.unlink);
1184 gtk_box_pack_start(GTK_BOX(hbox1), page->unlink_files, FALSE, FALSE, 0);
1185 CLAWS_SET_TIP(page->unlink_files,
1186 _("Choose this option to delete mails after archiving\n"
1187 "At this point only handles IMAP4, Local mbox and POP3"));
1190 frame = gtk_frame_new(_("Selection options"));
1191 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1192 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1193 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1195 hbox1 = gtk_hbox_new(FALSE, 4);
1196 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1197 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1199 file_label = gtk_label_new(_("Select mails before"));
1200 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1202 page->isoDate = gtk_entry_new();
1203 gtk_widget_set_name(page->isoDate, "isoDate");
1204 gtk_box_pack_start(GTK_BOX(hbox1), page->isoDate, TRUE, TRUE, 0);
1205 CLAWS_SET_TIP(page->isoDate,
1206 _("Select emails before a certain date\n"
1207 "Date must comply to ISO-8601 [YYYY-MM-DD]"));
1209 g_signal_connect(G_OBJECT(folder_select), "clicked",
1210 G_CALLBACK(foldersel_cb), page);
1211 g_signal_connect(G_OBJECT(file_select), "clicked",
1212 G_CALLBACK(filesel_cb), page);
1213 g_signal_connect(G_OBJECT(page->folder), "activate",
1214 G_CALLBACK(entry_change_cb), page);
1215 g_signal_connect(G_OBJECT(page->file), "activate",
1216 G_CALLBACK(entry_change_cb), page);
1218 gtk_widget_show_all(dialog);
1221 void archiver_gtk_done(struct ArchivePage* page, GtkWidget* widget) {
1222 dispose_archive_page(page);
1224 gtk_widget_destroy(widget);
1225 /*debug_set_mode(FALSE);*/