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"
53 #include "alertpanel.h"
57 typedef struct _progress_widget progress_widget;
58 struct _progress_widget {
59 GtkWidget* progress_dialog;
64 GtkWidget* file_label;
71 A_FILE_EXISTS = 1 << 1,
72 A_FILE_IS_LINK = 1 << 2,
73 A_FILE_IS_DIR = 1 << 3,
74 A_FILE_NO_WRITE = 1 << 4,
75 A_FILE_UNKNOWN = 1 << 5
78 static progress_widget* progress = NULL;
80 static progress_widget* init_progress() {
81 progress_widget* ptr = malloc(sizeof(*ptr));
83 debug_print("creating progress struct\n");
84 ptr->progress_dialog = NULL;
88 ptr->add_label = NULL;
89 ptr->file_label = NULL;
96 static void progress_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
97 struct ArchivePage* page = (struct ArchivePage *) data;
99 debug_print("Cancel operation\n");
101 page->cancelled = TRUE;
102 archive_free_file_list(page->md5, page->rename);
103 gtk_widget_destroy(widget);
106 static void create_progress_dialog(struct ArchivePage* page) {
107 gchar* title = g_strdup_printf("%s %s", _("Archiving"), page->path);
108 MainWindow* mainwin = mainwindow_get_mainwindow();
110 progress->position = 0;
111 progress->progress_dialog = gtk_dialog_new_with_buttons (
113 GTK_WINDOW(mainwin->window),
114 GTK_DIALOG_DESTROY_WITH_PARENT,
120 progress->progress_dialog,
122 G_CALLBACK(progress_dialog_cb),
125 progress->frame = gtk_frame_new(_("Press Cancel button to stop archiving"));
126 gtk_frame_set_shadow_type(GTK_FRAME(progress->frame),
127 GTK_SHADOW_ETCHED_OUT);
128 gtk_container_set_border_width(GTK_CONTAINER(progress->frame), 4);
129 gtk_container_add(GTK_CONTAINER(
130 GTK_DIALOG(progress->progress_dialog)->vbox), progress->frame);
132 progress->vbox1 = gtk_vbox_new (FALSE, 4);
133 gtk_container_set_border_width (GTK_CONTAINER (progress->vbox1), 4);
134 gtk_container_add(GTK_CONTAINER(progress->frame), progress->vbox1);
136 progress->hbox1 = gtk_hbox_new(FALSE, 8);
137 gtk_container_set_border_width(GTK_CONTAINER(progress->hbox1), 8);
138 gtk_box_pack_start(GTK_BOX(progress->vbox1),
139 progress->hbox1, FALSE, FALSE, 0);
141 progress->add_label = gtk_label_new(_("Archiving:"));
142 gtk_box_pack_start(GTK_BOX(progress->hbox1),
143 progress->add_label, FALSE, FALSE, 0);
145 progress->file_label = gtk_label_new("");
146 gtk_label_set_ellipsize(GTK_LABEL(progress->file_label),
147 PANGO_ELLIPSIZE_START);
148 gtk_box_pack_start(GTK_BOX(progress->hbox1),
149 progress->file_label, TRUE, TRUE, 0);
151 progress->hbox1 = gtk_hbox_new(FALSE, 8);
152 gtk_container_set_border_width(GTK_CONTAINER(progress->hbox1), 8);
153 gtk_box_pack_start(GTK_BOX(progress->vbox1),
154 progress->hbox1, FALSE, FALSE, 0);
156 progress->progress = gtk_progress_bar_new();
157 gtk_box_pack_start(GTK_BOX(progress->hbox1),
158 progress->progress, TRUE, TRUE, 0);
159 gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(progress->progress), 0.25);
161 gtk_window_set_default_size(GTK_WINDOW(progress->progress_dialog), 400, 80);
162 gtk_widget_show_all(progress->progress_dialog);
165 static struct ArchivePage* init_archive_page() {
166 struct ArchivePage* page = malloc(sizeof(struct ArchivePage));
168 debug_print("creating ArchivePage\n");
173 page->response = FALSE;
174 page->force_overwrite = FALSE;
175 page->compress_methods = NULL;
176 page->archive_formats = NULL;
177 page->recursive = NULL;
178 page->cancelled = FALSE;
181 page->rename = FALSE;
182 page->rename_files = NULL;
183 page->isoDate = NULL;
184 page->unlink_files = NULL;
185 page->unlink = FALSE;
190 static void dispose_archive_page(struct ArchivePage* page) {
191 debug_print("freeing ArchivePage\n");
201 static gboolean valid_file_name(gchar* file) {
204 for (i = 0; INVALID_UNIX_CHARS[i] != '\0'; i++) {
205 if (g_utf8_strchr(file, g_utf8_strlen(file, -1), INVALID_UNIX_CHARS[i]))
211 static COMPRESS_METHOD get_compress_method(GSList* btn) {
215 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn->data))) {
216 name = gtk_widget_get_name(GTK_WIDGET(btn->data));
217 if (strcmp("GZIP", name) == 0) {
218 debug_print("GZIP compression enabled\n");
221 else if (strcmp("BZIP", name) == 0) {
222 debug_print("BZIP2 compression enabled\n");
225 else if (strcmp("COMPRESS", name) == 0) {
226 debug_print("COMPRESS compression enabled\n");
229 #if ARCHIVE_VERSION_NUMBER >= 2006990
230 else if (strcmp("LZMA", name) == 0) {
231 debug_print("LZMA compression enabled\n");
234 else if (strcmp("XZ", name) == 0) {
235 debug_print("XZ compression enabled\n");
239 #if ARCHIVE_VERSION_NUMBER >= 3000000
240 else if (strcmp("LZIP", name) == 0) {
241 debug_print("LZIP compression enabled\n");
245 #if ARCHIVE_VERSION_NUMBER >= 3001000
246 else if (strcmp("LRZIP", name) == 0) {
247 debug_print("LRZIP compression enabled\n");
250 else if (strcmp("LZOP", name) == 0) {
251 debug_print("LZOP compression enabled\n");
254 else if (strcmp("GRZIP", name) == 0) {
255 debug_print("GRZIP compression enabled\n");
259 #if ARCHIVE_VERSION_NUMBER >= 3001900
260 else if (strcmp("LZ4", name) == 0) {
261 debug_print("LZ4 compression enabled\n");
265 else if (strcmp("NONE", name) == 0) {
266 debug_print("Compression disabled\n");
270 btn = g_slist_next(btn);
275 static ARCHIVE_FORMAT get_archive_format(GSList* btn) {
279 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn->data))) {
280 name = gtk_widget_get_name(GTK_WIDGET(btn->data));
281 if (strcmp("TAR", name) == 0) {
282 debug_print("TAR archive enabled\n");
285 else if (strcmp("SHAR", name) == 0) {
286 debug_print("SHAR archive enabled\n");
289 else if (strcmp("PAX", name) == 0) {
290 debug_print("PAX archive enabled\n");
293 else if (strcmp("CPIO", name) == 0) {
294 debug_print("CPIO archive enabled\n");
298 btn = g_slist_next(btn);
303 static void create_md5sum(const gchar* file, const gchar* md5_file) {
306 gchar* md5sum = malloc(33);
308 debug_print("Creating md5sum file: %s\n", md5_file);
309 if (md5_hex_digest_file(md5sum, (const unsigned char *) file) == -1) {
313 debug_print("md5sum: %s\n", md5sum);
315 open(md5_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) {
319 text = g_strrstr_len(file, strlen(file), "/");
322 text = g_strdup_printf("%s %s\n", md5sum, text);
325 text = g_strdup_printf("%s %s\n", md5sum, file);
327 debug_print("md5sum: %s\n", text);
328 if (write(fd, text, strlen(text)) < 0)
334 static gchar* descriptive_file_name(
335 struct ArchivePage* page, const gchar* file, MsgInfo *msginfo) {
336 gchar* new_file = NULL;
337 gchar *name, *p, *to, *from, *date, *subject;
339 debug_print("renaming file\n");
340 p = g_strrstr_len(file, strlen(file), "/");
341 p = g_strndup(file, p - file);
345 to = g_strdup(msginfo->to);
351 from = g_strdup(msginfo->from);
352 extract_address(from);
357 date = g_strdup(msginfo->date);
358 subst_for_shellsafe_filename(date);
359 /* if not on windows we need to subst some more */
360 subst_chars(date, ":", '_');
364 if (msginfo->subject) {
365 subject = g_strdup(msginfo->subject);
366 subst_for_shellsafe_filename(subject);
367 /* if not on windows we need to subst some more */
368 subst_chars(subject, ":", '_');
371 subject = g_strdup("");
372 name = g_strdup_printf("%s_%s@%s@%s", date, from, to, subject);
373 /* ensure file name is not larger than 96 chars (max file name size
374 * is 100 chars but reserve for .md5)
376 if (strlen(name) > 96)
379 new_file = g_strconcat(p, "/", name, NULL);
388 debug_print("New_file: %s\n", new_file);
389 if (link(file, new_file) != 0) {
390 if (errno != EEXIST) {
393 new_file = g_strdup(file);
394 page->rename = FALSE;
401 static void walk_folder(struct ArchivePage* page, FolderItem* item,
402 gboolean recursive) {
409 gchar* md5_file = NULL;
412 MsgTrash* msg_trash = NULL;
413 const gchar* date = NULL;
415 if (recursive && ! page->cancelled) {
416 debug_print("Scanning recursive\n");
417 node = item->node->children;
418 while(node && ! page->cancelled) {
419 debug_print("Number of nodes: %d\n", g_node_n_children(node));
421 child = FOLDER_ITEM(node->data);
422 debug_print("new node: %d messages\n", child->total_msgs);
423 walk_folder(page, child, recursive);
428 if (! page->cancelled) {
429 date = gtk_entry_get_text(GTK_ENTRY(page->isoDate));
430 debug_print("cut-off date: %s\n", date);
432 page->files += item->total_msgs;
433 msglist = folder_item_get_msg_list(item);
434 msg_trash = new_msg_trash(item);
435 for (cur = msglist; cur && ! page->cancelled; cur = cur->next) {
436 msginfo = (MsgInfo *) cur->data;
437 debug_print("%s_%s_%s_%s\n",
438 msginfo->date, msginfo->to, msginfo->from, msginfo->subject);
439 file = folder_item_fetch_msg(item, msginfo->msgnum);
440 if (date && strlen(date) > 0 && !before_date(msginfo->date_t, date)) {
444 page->total_size += msginfo->size;
445 /*debug_print("Processing: %s\n", file);*/
448 archive_add_msg_mark(msg_trash, msginfo);
451 file = descriptive_file_name(page, file, msginfo);
453 /* Could not create a descriptive name */
454 file = folder_item_fetch_msg(item, msginfo->msgnum);
458 md5_file = g_strdup_printf("%s.md5", file);
459 create_md5sum(file, md5_file);
460 archive_add_file(md5_file);
463 archive_add_file(file);
467 if (count % 350 == 0) {
468 debug_print("pulse progressbar\n");
469 text = g_strdup_printf(
470 "Scanning %s: %d files", item->name, count);
471 gtk_progress_bar_set_text(
472 GTK_PROGRESS_BAR(progress->progress), text);
474 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress->progress));
479 procmsg_msg_list_free(msglist);
483 static AFileTest file_is_writeable(struct ArchivePage* page) {
486 if (g_file_test(page->name, G_FILE_TEST_EXISTS) &&
487 ! page->force_overwrite)
488 return A_FILE_EXISTS;
489 if (g_file_test(page->name, G_FILE_TEST_IS_SYMLINK))
490 return A_FILE_IS_LINK;
491 if (g_file_test(page->name, G_FILE_TEST_IS_DIR))
492 return A_FILE_IS_DIR;
493 if ((fd = open(page->name, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
495 case EACCES: return A_FILE_NO_WRITE;
496 case EEXIST: return A_FILE_OK;
497 default: return A_FILE_UNKNOWN;
502 claws_unlink(page->name);
507 static gboolean archiver_save_files(struct ArchivePage* page) {
509 COMPRESS_METHOD method;
510 ARCHIVE_FORMAT format;
514 const gchar* res = NULL;
517 gboolean folder_not_set;
518 gboolean file_not_set;
520 /* check if folder to archive and target archive filename are set */
521 folder_not_set = (*gtk_entry_get_text(GTK_ENTRY(page->folder)) == '\0');
522 file_not_set = (*gtk_entry_get_text(GTK_ENTRY(page->file)) == '\0');
523 if (folder_not_set || file_not_set) {
524 alertpanel_error(_("Some uninitialized data prevents from starting\n"
525 "the archiving process:\n"
527 folder_not_set ? _("\n- the folder to archive is not set") : "",
528 file_not_set ? _("\n- the name for archive is not set") : "");
531 /* sync page struct info with folder and archive name edit widgets */
536 page->path = g_strdup(gtk_entry_get_text(GTK_ENTRY(page->folder)));
537 g_strstrip(page->path);
538 debug_print("page->path: %s\n", page->path);
544 page->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(page->file)));
545 g_strstrip(page->name);
546 debug_print("page->name: %s\n", page->name);
548 if ((perm = file_is_writeable(page)) != A_FILE_OK) {
551 msg = g_strdup_printf(_("%s: Exists. Continue anyway?"), page->name);
554 msg = g_strdup_printf(_("%s: Is a link. Cannot continue"), page->name);
557 msg = g_strdup_printf(_("%s: Is a directory. Cannot continue"), page->name);
559 case A_FILE_NO_WRITE:
560 msg = g_strdup_printf(_("%s: Missing permissions. Cannot continue"), page->name);
563 msg = g_strdup_printf(_("%s: Unknown error. Cannot continue"), page->name);
568 if (perm == A_FILE_EXISTS) {
571 aval = alertpanel_full(_("Creating archive"), msg,
572 GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL, FALSE,
573 NULL, ALERT_WARNING, G_ALERTDEFAULT);
575 if (aval != G_ALERTALTERNATE)
578 alertpanel_error(msg);
583 if (! valid_file_name(page->name)) {
584 alertpanel_error(_("Not a valid file name:\n%s."), page->name);
587 item = folder_find_item_from_identifier(page->path);
589 alertpanel_error(_("Not a valid Claws Mail folder:\n%s."), page->name);
593 page->total_size = 0;
594 page->rename = gtk_toggle_button_get_active(
595 GTK_TOGGLE_BUTTON(page->rename_files));
596 recursive = gtk_toggle_button_get_active(
597 GTK_TOGGLE_BUTTON(page->recursive));
598 page->md5 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->md5sum));
599 page->unlink = gtk_toggle_button_get_active(
600 GTK_TOGGLE_BUTTON(page->unlink_files));
601 create_progress_dialog(page);
602 walk_folder(page, item, recursive);
605 list = archive_get_file_list();
606 orig_file = (page->md5) ? page->files * 2 : page->files;
607 debug_print("md5: %d, orig: %d, md5: %d\n",
608 page->md5, page->files, orig_file);
609 if (orig_file != g_slist_length(list)) {
612 msg = g_strdup_printf(
613 _("Adding files in folder failed\n"
614 "Files in folder: %d\n"
615 "Files in list: %d\n"
616 "\nContinue anyway?"),
617 orig_file, g_slist_length(list));
618 aval = alertpanel_full(_("Creating archive"), msg,
619 GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL, FALSE,
620 NULL, ALERT_WARNING, G_ALERTDEFAULT);
622 if (aval != G_ALERTALTERNATE) {
623 archive_free_file_list(page->md5, page->rename);
627 method = get_compress_method(page->compress_methods);
628 format = get_archive_format(page->archive_formats);
629 if ((res = archive_create(page->name, list, method, format)) != NULL) {
630 alertpanel_error(_("Archive creation error:\n%s"), res);
631 archive_free_file_list(page->md5, page->rename);
635 archive_free_archived_files();
640 static void entry_change_cb(GtkWidget* widget, gpointer data) {
641 const gchar* name = gtk_widget_get_name(widget);
642 struct ArchivePage* page = (struct ArchivePage *) data;
644 if (strcmp("folder", name) == 0) {
645 page->path = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
646 debug_print("page->folder = %s\n", page->path);
648 else if (strcmp("file", name) == 0) {
649 page->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
650 page->force_overwrite = FALSE;
651 debug_print("page->name = %s\n", page->name);
655 static void show_result(struct ArchivePage* page) {
667 GtkTreeViewColumn* header;
668 GtkCellRenderer* renderer;
671 gchar* method = NULL;
672 gchar* format = NULL;
674 MainWindow* mainwin = mainwindow_get_mainwindow();
676 switch (get_compress_method(page->compress_methods)) {
678 method = g_strdup("GZIP");
681 method = g_strdup("BZIP2");
684 method = g_strdup("Compress");
686 #if ARCHIVE_VERSION_NUMBER >= 2006990
688 method = g_strdup("LZMA");
691 method = g_strdup("XZ");
694 #if ARCHIVE_VERSION_NUMBER >= 3000000
696 method = g_strdup("LZIP");
699 #if ARCHIVE_VERSION_NUMBER >= 3001000
701 method = g_strdup("LRZIP");
704 method = g_strdup("LZOP");
707 method = g_strdup("GRZIP");
710 #if ARCHIVE_VERSION_NUMBER >= 3001900
712 method = g_strdup("LZ4");
716 method = g_strdup("No Compression");
720 switch (get_archive_format(page->archive_formats)) {
722 format = g_strdup("TAR");
725 format = g_strdup("SHAR");
728 format = g_strdup("PAX");
731 format = g_strdup("CPIO");
734 format = g_strdup("NO FORMAT");
737 if (g_stat(page->name, &st) == -1) {
738 alertpanel_error("Could not get size of archive file '%s'.", page->name);
741 dialog = gtk_dialog_new_with_buttons(
743 GTK_WINDOW(mainwin->window),
744 GTK_DIALOG_DESTROY_WITH_PARENT,
748 g_signal_connect_swapped(
751 G_CALLBACK(gtk_widget_destroy),
754 list = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
760 "headers-clickable", FALSE,
761 "reorderable", FALSE,
762 "enable-search", FALSE,
765 renderer = gtk_cell_renderer_text_new();
767 header = gtk_tree_view_column_new_with_attributes(
768 _("Attributes"), renderer, "text", STRING1, NULL);
769 gtk_tree_view_append_column(view, header);
771 header = gtk_tree_view_column_new_with_attributes(
772 _("Values"), renderer, "text", STRING2, NULL);
773 gtk_tree_view_append_column(view, header);
776 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(view));
778 gtk_list_store_append(list, &iter);
781 STRING1, _("Archive"),
782 STRING2, page->name, -1);
784 gtk_list_store_append(list, &iter);
787 STRING1, _("Archive format"),
788 STRING2, format, -1);
791 gtk_list_store_append(list, &iter);
794 STRING1, _("Compression method"),
795 STRING2, method, -1);
798 gtk_list_store_append(list, &iter);
799 msg = g_strdup_printf("%d", (page->md5) ? page->files * 2 : page->files);
802 STRING1, _("Number of files"),
806 gtk_list_store_append(list, &iter);
807 msg = g_strdup_printf("%d byte(s)", (guint) st.st_size);
810 STRING1, _("Archive Size"),
814 gtk_list_store_append(list, &iter);
815 msg = g_strdup_printf("%d byte(s)", page->total_size);
818 STRING1, _("Folder Size"),
822 gtk_list_store_append(list, &iter);
823 msg = g_strdup_printf("%d%%",
824 (guint)((st.st_size * 100) / page->total_size));
827 STRING1, _("Compression level"),
831 gtk_list_store_append(list, &iter);
832 msg = g_strdup_printf("%s", (page->md5) ? _("Yes") : _("No"));
835 STRING1, _("MD5 checksum"),
839 gtk_list_store_append(list, &iter);
840 msg = g_strdup_printf("%s", (page->rename) ? _("Yes") : _("No"));
843 STRING1, _("Descriptive names"),
847 gtk_list_store_append(list, &iter);
848 msg = g_strdup_printf("%s", (page->unlink) ? _("Yes") : _("No"));
851 STRING1, _("Delete selected files"),
855 msg = g_strdup(gtk_entry_get_text(GTK_ENTRY(page->isoDate)));
857 gtk_list_store_append(list, &iter);
860 STRING1, _("Select mails before"),
865 gtk_window_set_default_size(GTK_WINDOW(dialog), 320, 260);
867 gtk_widget_show_all(dialog);
870 static void archiver_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
871 struct ArchivePage* page = (struct ArchivePage *) data;
872 gboolean result = FALSE;
875 case GTK_RESPONSE_ACCEPT:
876 debug_print("User chose OK\n");
877 page->response = TRUE;
880 debug_print("User chose CANCEL\n");
881 page->response = FALSE;
882 archiver_gtk_done(page, widget);
885 debug_print("Settings:\naction: %d\n", page->response);
886 if (page->response) {
887 debug_print("Settings:\nfolder: %s\nname: %s\n",
888 (page->path) ? page->path : "(null)",
889 (page->name) ? page->name : "(null)");
890 result = archiver_save_files(page);
891 debug_print("Result->archiver_save_files: %d\n", result);
892 if (progress->progress_dialog &&
893 GTK_IS_WIDGET(progress->progress_dialog))
894 gtk_widget_destroy(progress->progress_dialog);
895 if (result && ! page->cancelled) {
897 archive_free_file_list(page->md5, page->rename);
898 archiver_gtk_done(page, widget);
901 if (page->cancelled) {
902 archiver_gtk_done(page, widget);
908 static void foldersel_cb(GtkWidget *widget, gpointer data)
913 struct ArchivePage* page = (struct ArchivePage *) data;
915 item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
916 if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
917 gtk_editable_delete_text(GTK_EDITABLE(page->folder), 0, -1);
918 gtk_editable_insert_text(GTK_EDITABLE(page->folder),
919 item_id, strlen(item_id), &newpos);
920 page->path = g_strdup(item_id);
923 debug_print("Folder to archive: %s\n",
924 gtk_entry_get_text(GTK_ENTRY(page->folder)));
927 static void filesel_cb(GtkWidget *widget, gpointer data)
932 const gchar* homedir;
933 struct ArchivePage* page = (struct ArchivePage *) data;
935 dialog = gtk_file_chooser_dialog_new(
936 _("Select file name for archive [suffix should reflect archive like .tgz]"),
938 GTK_FILE_CHOOSER_ACTION_SAVE,
939 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
940 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
942 homedir = g_getenv("HOME");
944 homedir = g_get_home_dir();
946 if (archiver_prefs.save_folder)
947 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
948 archiver_prefs.save_folder);
950 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), homedir);
951 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY) {
952 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
954 gtk_editable_delete_text(GTK_EDITABLE(page->file), 0, -1);
955 gtk_editable_insert_text(GTK_EDITABLE(page->file),
956 file, strlen(file), &newpos);
957 page->name = g_strdup(file);
959 page->force_overwrite = TRUE;
962 gtk_widget_destroy(dialog);
963 debug_print("Name for archive: %s\n",
964 gtk_entry_get_text(GTK_ENTRY(page->file)));
967 void set_progress_file_label(const gchar* file) {
968 debug_print("IsLabel: %s, Update label: %s\n",
969 GTK_IS_WIDGET(progress->file_label)? "Yes" : "No", file);
970 if (GTK_IS_WIDGET(progress->file_label))
971 gtk_label_set_text(GTK_LABEL(progress->file_label), file);
974 void set_progress_print_all(guint fraction, guint total, guint step) {
977 if (GTK_IS_WIDGET(progress->progress)) {
978 if ((fraction - progress->position) % step == 0) {
979 debug_print("frac: %d, total: %d, step: %d, prog->pos: %d\n",
980 fraction, total, step, progress->position);
981 gtk_progress_bar_set_fraction(
982 GTK_PROGRESS_BAR(progress->progress),
983 (total == 0) ? 0 : (gfloat)fraction / (gfloat)total);
984 text_count = g_strdup_printf(_("%ld of %ld"),
985 (long) fraction, (long) total);
986 gtk_progress_bar_set_text(
987 GTK_PROGRESS_BAR(progress->progress), text_count);
989 progress->position = fraction;
995 void archiver_gtk_show() {
1000 GtkWidget* folder_label;
1001 GtkWidget* folder_select;
1002 GtkWidget* file_label;
1003 GtkWidget* file_select;
1004 GtkWidget* gzip_radio_btn;
1005 GtkWidget* bzip_radio_btn;
1006 GtkWidget* compress_radio_btn;
1007 #if ARCHIVE_VERSION_NUMBER >= 2006990
1008 GtkWidget* lzma_radio_btn;
1009 GtkWidget* xz_radio_btn;
1011 #if ARCHIVE_VERSION_NUMBER >= 3000000
1012 GtkWidget* lzip_radio_btn;
1014 #if ARCHIVE_VERSION_NUMBER >= 3001000
1015 GtkWidget* lrzip_radio_btn;
1016 GtkWidget* lzop_radio_btn;
1017 GtkWidget* grzip_radio_btn;
1019 #if ARCHIVE_VERSION_NUMBER >= 3001900
1020 GtkWidget* lz4_radio_btn;
1022 GtkWidget* no_radio_btn;
1023 GtkWidget* shar_radio_btn;
1024 GtkWidget* pax_radio_btn;
1025 GtkWidget* cpio_radio_btn;
1026 GtkWidget* tar_radio_btn;
1027 struct ArchivePage* page;
1028 MainWindow* mainwin = mainwindow_get_mainwindow();
1030 /*debug_set_mode(TRUE);*/
1031 progress = init_progress();
1033 page = init_archive_page();
1035 dialog = gtk_dialog_new_with_buttons (
1036 _("Create Archive"),
1037 GTK_WINDOW(mainwin->window),
1038 GTK_DIALOG_DESTROY_WITH_PARENT,
1040 GTK_RESPONSE_CANCEL,
1042 GTK_RESPONSE_ACCEPT,
1048 G_CALLBACK(archiver_dialog_cb),
1051 frame = gtk_frame_new(_("Enter Archiver arguments"));
1052 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1053 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1054 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
1056 vbox1 = gtk_vbox_new (FALSE, 4);
1057 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 4);
1058 gtk_container_add(GTK_CONTAINER(frame), vbox1);
1060 hbox1 = gtk_hbox_new(FALSE, 4);
1061 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1062 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1064 folder_label = gtk_label_new(_("Folder to archive"));
1065 gtk_box_pack_start(GTK_BOX(hbox1), folder_label, FALSE, FALSE, 0);
1067 page->folder = gtk_entry_new();
1068 gtk_widget_set_name(page->folder, "folder");
1069 gtk_box_pack_start(GTK_BOX(hbox1), page->folder, TRUE, TRUE, 0);
1070 CLAWS_SET_TIP(page->folder,
1071 _("Folder which is the root of the archive"));
1073 folder_select = gtkut_get_browse_directory_btn(_("_Browse"));
1074 gtk_box_pack_start(GTK_BOX(hbox1), folder_select, FALSE, FALSE, 0);
1075 CLAWS_SET_TIP(folder_select,
1076 _("Click this button to select a folder which is to be root of the archive"));
1078 hbox1 = gtk_hbox_new(FALSE, 4);
1079 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1080 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1082 file_label = gtk_label_new(_("Name for archive"));
1083 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1085 page->file = gtk_entry_new();
1086 gtk_widget_set_name(page->file, "file");
1087 gtk_box_pack_start(GTK_BOX(hbox1), page->file, TRUE, TRUE, 0);
1088 CLAWS_SET_TIP(page->file, _("Archive location and name"));
1090 file_select = gtkut_get_browse_directory_btn(_("_Select"));
1091 gtk_box_pack_start(GTK_BOX(hbox1), file_select, FALSE, FALSE, 0);
1092 CLAWS_SET_TIP(file_select,
1093 _("Click this button to select a name and location for the archive"));
1095 frame = gtk_frame_new(_("Choose compression"));
1096 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1097 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1098 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1100 hbox1 = gtk_hbox_new(FALSE, 4);
1101 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1102 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1104 gzip_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "G_ZIP");
1105 gtk_widget_set_name(gzip_radio_btn, "GZIP");
1106 gtk_box_pack_start(GTK_BOX(hbox1), gzip_radio_btn, FALSE, FALSE, 0);
1107 CLAWS_SET_TIP(gzip_radio_btn,
1108 _("Choose this option to use GZIP compression for the archive"));
1110 bzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1111 GTK_RADIO_BUTTON(gzip_radio_btn), "BZIP_2");
1112 gtk_widget_set_name(bzip_radio_btn, "BZIP");
1113 gtk_box_pack_start(GTK_BOX(hbox1), bzip_radio_btn, FALSE, FALSE, 0);
1114 CLAWS_SET_TIP(bzip_radio_btn,
1115 _("Choose this option to use BZIP2 compression for the archive"));
1117 compress_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1118 GTK_RADIO_BUTTON(gzip_radio_btn), "Com_press");
1119 gtk_widget_set_name(compress_radio_btn, "COMPRESS");
1120 gtk_box_pack_start(GTK_BOX(hbox1), compress_radio_btn, FALSE, FALSE, 0);
1121 CLAWS_SET_TIP(compress_radio_btn,
1122 _("Choose this to use Compress compression for your archive"));
1124 #if ARCHIVE_VERSION_NUMBER >= 2006990
1125 lzma_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1126 GTK_RADIO_BUTTON(gzip_radio_btn), "_LZMA");
1127 gtk_widget_set_name(lzma_radio_btn, "LZMA");
1128 gtk_box_pack_start(GTK_BOX(hbox1), lzma_radio_btn, FALSE, FALSE, 0);
1129 CLAWS_SET_TIP(lzma_radio_btn,
1130 _("Choose this option to use LZMA compression for the archive"));
1132 xz_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1133 GTK_RADIO_BUTTON(gzip_radio_btn), "_XZ");
1134 gtk_widget_set_name(xz_radio_btn, "XZ");
1135 gtk_box_pack_start(GTK_BOX(hbox1), xz_radio_btn, FALSE, FALSE, 0);
1136 CLAWS_SET_TIP(xz_radio_btn,
1137 _("Choose this option to use XZ compression for the archive"));
1140 #if ARCHIVE_VERSION_NUMBER >= 3000000
1141 lzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1142 GTK_RADIO_BUTTON(gzip_radio_btn), "_LZIP");
1143 gtk_widget_set_name(lzip_radio_btn, "LZIP");
1144 gtk_box_pack_start(GTK_BOX(hbox1), lzip_radio_btn, FALSE, FALSE, 0);
1145 CLAWS_SET_TIP(lzip_radio_btn,
1146 _("Choose this option to use LZIP compression for the archive"));
1149 #if ARCHIVE_VERSION_NUMBER >= 3001000
1150 lrzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1151 GTK_RADIO_BUTTON(gzip_radio_btn), "L_RZIP");
1152 gtk_widget_set_name(lrzip_radio_btn, "LRZIP");
1153 gtk_box_pack_start(GTK_BOX(hbox1), lrzip_radio_btn, FALSE, FALSE, 0);
1154 CLAWS_SET_TIP(lrzip_radio_btn,
1155 _("Choose this option to use LRZIP compression for the archive"));
1157 lzop_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1158 GTK_RADIO_BUTTON(gzip_radio_btn), "LZ_OP");
1159 gtk_widget_set_name(lzop_radio_btn, "LZOP");
1160 gtk_box_pack_start(GTK_BOX(hbox1), lzop_radio_btn, FALSE, FALSE, 0);
1161 CLAWS_SET_TIP(lzop_radio_btn,
1162 _("Choose this option to use LZOP compression for the archive"));
1164 grzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1165 GTK_RADIO_BUTTON(gzip_radio_btn), "_GRZIP");
1166 gtk_widget_set_name(grzip_radio_btn, "GRZIP");
1167 gtk_box_pack_start(GTK_BOX(hbox1), grzip_radio_btn, FALSE, FALSE, 0);
1168 CLAWS_SET_TIP(grzip_radio_btn,
1169 _("Choose this option to use GRZIP compression for the archive"));
1172 #if ARCHIVE_VERSION_NUMBER >= 3001900
1173 lz4_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1174 GTK_RADIO_BUTTON(gzip_radio_btn), "LZ_4");
1175 gtk_widget_set_name(lz4_radio_btn, "LZ4");
1176 gtk_box_pack_start(GTK_BOX(hbox1), lz4_radio_btn, FALSE, FALSE, 0);
1177 CLAWS_SET_TIP(lz4_radio_btn,
1178 _("Choose this option to use LZ4 compression for the archive"));
1181 no_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1182 GTK_RADIO_BUTTON(gzip_radio_btn), _("_None"));
1183 gtk_widget_set_name(no_radio_btn, "NONE");
1184 gtk_box_pack_start(GTK_BOX(hbox1), no_radio_btn, FALSE, FALSE, 0);
1185 CLAWS_SET_TIP(no_radio_btn,
1186 _("Choose this option to disable compression for the archive"));
1188 page->compress_methods =
1189 gtk_radio_button_get_group(GTK_RADIO_BUTTON(gzip_radio_btn));
1191 switch (archiver_prefs.compression) {
1192 case COMPRESSION_GZIP:
1193 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gzip_radio_btn), TRUE);
1195 case COMPRESSION_BZIP:
1196 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bzip_radio_btn), TRUE);
1198 case COMPRESSION_COMPRESS:
1199 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compress_radio_btn), TRUE);
1201 #if ARCHIVE_VERSION_NUMBER >= 2006990
1202 case COMPRESSION_LZMA:
1203 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lzma_radio_btn), TRUE);
1205 case COMPRESSION_XZ:
1206 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xz_radio_btn), TRUE);
1209 #if ARCHIVE_VERSION_NUMBER >= 3000000
1210 case COMPRESSION_LZIP:
1211 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lzip_radio_btn), TRUE);
1214 #if ARCHIVE_VERSION_NUMBER >= 3001000
1215 case COMPRESSION_LRZIP:
1216 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lrzip_radio_btn), TRUE);
1218 case COMPRESSION_LZOP:
1219 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lzop_radio_btn), TRUE);
1221 case COMPRESSION_GRZIP:
1222 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(grzip_radio_btn), TRUE);
1225 #if ARCHIVE_VERSION_NUMBER >= 3001900
1226 case COMPRESSION_LZ4:
1227 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lz4_radio_btn), TRUE);
1230 case COMPRESSION_NONE:
1231 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(no_radio_btn), TRUE);
1235 frame = gtk_frame_new(_("Choose format"));
1236 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1237 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1238 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1240 hbox1 = gtk_hbox_new(FALSE, 4);
1241 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1242 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1244 tar_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_TAR");
1245 gtk_widget_set_name(tar_radio_btn, "TAR");
1246 gtk_box_pack_start(GTK_BOX(hbox1), tar_radio_btn, FALSE, FALSE, 0);
1247 CLAWS_SET_TIP(tar_radio_btn,
1248 _("Choose this option to use TAR as format for the archive"));
1250 shar_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1251 GTK_RADIO_BUTTON(tar_radio_btn), "S_HAR");
1252 gtk_widget_set_name(shar_radio_btn, "SHAR");
1253 gtk_box_pack_start(GTK_BOX(hbox1), shar_radio_btn, FALSE, FALSE, 0);
1254 CLAWS_SET_TIP(shar_radio_btn,
1255 _("Choose this to use SHAR as format for the archive"));
1257 cpio_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1258 GTK_RADIO_BUTTON(tar_radio_btn), "CP_IO");
1259 gtk_widget_set_name(cpio_radio_btn, "CPIO");
1260 gtk_box_pack_start(GTK_BOX(hbox1), cpio_radio_btn, FALSE, FALSE, 0);
1261 CLAWS_SET_TIP(cpio_radio_btn,
1262 _("Choose this option to use CPIO as format for the archive"));
1264 pax_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1265 GTK_RADIO_BUTTON(tar_radio_btn), "PA_X");
1266 gtk_widget_set_name(pax_radio_btn, "PAX");
1267 gtk_box_pack_start(GTK_BOX(hbox1), pax_radio_btn, FALSE, FALSE, 0);
1268 CLAWS_SET_TIP(pax_radio_btn,
1269 _("Choose this option to use PAX as format for the archive"));
1271 page->archive_formats =
1272 gtk_radio_button_get_group(GTK_RADIO_BUTTON(tar_radio_btn));
1274 switch (archiver_prefs.format) {
1276 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tar_radio_btn), TRUE);
1279 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shar_radio_btn), TRUE);
1282 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cpio_radio_btn), TRUE);
1285 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pax_radio_btn), TRUE);
1289 frame = gtk_frame_new(_("Miscellaneous options"));
1290 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1291 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1292 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1294 hbox1 = gtk_hbox_new(FALSE, 4);
1295 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1296 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1298 page->recursive = gtk_check_button_new_with_mnemonic(_("_Recursive"));
1299 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->recursive), archiver_prefs.recursive);
1300 gtk_box_pack_start(GTK_BOX(hbox1), page->recursive, FALSE, FALSE, 0);
1301 CLAWS_SET_TIP(page->recursive,
1302 _("Choose this option to include subfolders in the archive"));
1304 page->md5sum = gtk_check_button_new_with_mnemonic(_("_MD5sum"));
1305 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->md5sum), archiver_prefs.md5sum);
1306 gtk_box_pack_start(GTK_BOX(hbox1), page->md5sum, FALSE, FALSE, 0);
1307 CLAWS_SET_TIP(page->md5sum,
1308 _("Choose this option to add MD5 checksums for each file in the archive.\n"
1309 "Be aware though, that this dramatically increases the time it\n"
1310 "will take to create the archive"));
1312 page->rename_files = gtk_check_button_new_with_mnemonic(_("R_ename"));
1313 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->rename_files), archiver_prefs.rename);
1314 gtk_box_pack_start(GTK_BOX(hbox1), page->rename_files, FALSE, FALSE, 0);
1315 CLAWS_SET_TIP(page->rename_files,
1316 _("Choose this option to use descriptive names for each file in the archive.\n"
1317 "The naming scheme: date_from@to@subject.\n"
1318 "Names will be truncated to max 96 characters"));
1320 page->unlink_files = gtk_check_button_new_with_mnemonic(_("_Delete"));
1321 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->unlink_files), archiver_prefs.unlink);
1322 gtk_box_pack_start(GTK_BOX(hbox1), page->unlink_files, FALSE, FALSE, 0);
1323 CLAWS_SET_TIP(page->unlink_files,
1324 _("Choose this option to delete mails after archiving\n"
1325 "At this point only handles IMAP4, Local mbox and POP3"));
1328 frame = gtk_frame_new(_("Selection options"));
1329 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1330 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1331 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1333 hbox1 = gtk_hbox_new(FALSE, 4);
1334 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1335 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1337 file_label = gtk_label_new(_("Select mails before"));
1338 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1340 page->isoDate = gtk_entry_new();
1341 gtk_widget_set_name(page->isoDate, "isoDate");
1342 gtk_box_pack_start(GTK_BOX(hbox1), page->isoDate, TRUE, TRUE, 0);
1343 CLAWS_SET_TIP(page->isoDate,
1344 _("Select emails before a certain date\n"
1345 "Date must comply to ISO-8601 [YYYY-MM-DD]"));
1347 g_signal_connect(G_OBJECT(folder_select), "clicked",
1348 G_CALLBACK(foldersel_cb), page);
1349 g_signal_connect(G_OBJECT(file_select), "clicked",
1350 G_CALLBACK(filesel_cb), page);
1351 g_signal_connect(G_OBJECT(page->folder), "activate",
1352 G_CALLBACK(entry_change_cb), page);
1353 g_signal_connect(G_OBJECT(page->file), "activate",
1354 G_CALLBACK(entry_change_cb), page);
1356 gtk_widget_show_all(dialog);
1359 void archiver_gtk_done(struct ArchivePage* page, GtkWidget* widget) {
1360 dispose_archive_page(page);
1362 gtk_widget_destroy(widget);
1363 /*debug_set_mode(FALSE);*/