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");
240 else if (strcmp("COMPRESS", name) == 0) {
241 debug_print("COMPRESS compression enabled\n");
245 else if (strcmp("NONE", name) == 0) {
246 debug_print("Compression disabled\n");
250 btn = g_slist_next(btn);
255 static ARCHIVE_FORMAT get_archive_format(GSList* btn) {
259 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn->data))) {
260 name = gtk_widget_get_name(GTK_WIDGET(btn->data));
261 if (strcmp("TAR", name) == 0) {
262 debug_print("TAR archive enabled\n");
265 else if (strcmp("SHAR", name) == 0) {
266 debug_print("SHAR archive enabled\n");
269 else if (strcmp("PAX", name) == 0) {
270 debug_print("PAX archive enabled\n");
273 else if (strcmp("CPIO", name) == 0) {
274 debug_print("CPIO archive enabled\n");
278 btn = g_slist_next(btn);
283 static void create_md5sum(const gchar* file, const gchar* md5_file) {
286 gchar* md5sum = malloc(33);
288 debug_print("Creating md5sum file: %s\n", md5_file);
289 if (md5_hex_digest_file(md5sum, (const unsigned char *) file) == -1)
291 debug_print("md5sum: %s\n", md5sum);
293 open(md5_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1)
295 text = g_strrstr_len(file, strlen(file), "/");
298 text = g_strdup_printf("%s %s\n", md5sum, text);
301 text = g_strdup_printf("%s %s\n", md5sum, file);
303 debug_print("md5sum: %s\n", text);
304 if (write(fd, text, strlen(text)) < 0)
310 static gchar* descriptive_file_name(
311 struct ArchivePage* page, const gchar* file, MsgInfo *msginfo) {
312 gchar* new_file = NULL;
313 gchar *name, *p, *to, *from, *date, *subject;
315 debug_print("renaming file\n");
316 p = g_strrstr_len(file, strlen(file), "/");
317 p = g_strndup(file, p - file);
321 to = g_strdup(msginfo->to);
327 from = g_strdup(msginfo->from);
328 extract_address(from);
333 date = g_strdup(msginfo->date);
334 subst_for_shellsafe_filename(date);
335 /* if not on windows we need to subst some more */
336 subst_chars(date, ":", '_');
340 if (msginfo->subject) {
341 subject = g_strdup(msginfo->subject);
342 subst_for_shellsafe_filename(subject);
343 /* if not on windows we need to subst some more */
344 subst_chars(subject, ":", '_');
347 subject = g_strdup("");
348 name = g_strdup_printf("%s_%s@%s@%s", date, from, to, subject);
349 /* ensure file name is not larger than 96 chars (max file name size
350 * is 100 chars but reserve for .md5)
352 if (strlen(name) > 96) {
353 name = realloc(name, 97);
357 new_file = g_strconcat(p, "/", name, NULL);
366 debug_print("New_file: %s\n", new_file);
367 if (link(file, new_file) != 0) {
368 if (errno != EEXIST) {
371 new_file = g_strdup(file);
372 page->rename = FALSE;
379 static void walk_folder(struct ArchivePage* page, FolderItem* item,
380 gboolean recursive) {
387 gchar* md5_file = NULL;
390 MsgTrash* msg_trash = NULL;
391 const gchar* date = NULL;
393 if (recursive && ! page->cancelled) {
394 debug_print("Scanning recursive\n");
395 node = item->node->children;
396 while(node && ! page->cancelled) {
397 debug_print("Number of nodes: %d\n", g_node_n_children(node));
399 child = FOLDER_ITEM(node->data);
400 debug_print("new node: %d messages\n", child->total_msgs);
401 walk_folder(page, child, recursive);
406 if (! page->cancelled) {
407 date = gtk_entry_get_text(GTK_ENTRY(page->isoDate));
408 debug_print("cut-off date: %s\n", date);
410 page->files += item->total_msgs;
411 msglist = folder_item_get_msg_list(item);
412 msg_trash = new_msg_trash(item);
413 for (cur = msglist; cur && ! page->cancelled; cur = cur->next) {
414 msginfo = (MsgInfo *) cur->data;
415 debug_print("%s_%s_%s_%s\n",
416 msginfo->date, msginfo->to, msginfo->from, msginfo->subject);
417 file = folder_item_fetch_msg(item, msginfo->msgnum);
418 if (date && strlen(date) > 0 && !before_date(msginfo->date_t, date)) {
422 page->total_size += msginfo->size;
423 /*debug_print("Processing: %s\n", file);*/
426 archive_add_msg_mark(msg_trash, msginfo);
429 file = descriptive_file_name(page, file, msginfo);
431 /* Could not create a descriptive name */
432 file = folder_item_fetch_msg(item, msginfo->msgnum);
436 md5_file = g_strdup_printf("%s.md5", file);
437 create_md5sum(file, md5_file);
438 archive_add_file(md5_file);
441 archive_add_file(file);
445 if (count % 350 == 0) {
446 debug_print("pulse progressbar\n");
447 text = g_strdup_printf(
448 "Scanning %s: %d files", item->name, count);
449 gtk_progress_bar_set_text(
450 GTK_PROGRESS_BAR(progress->progress), text);
452 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress->progress));
457 procmsg_msg_list_free(msglist);
461 static AFileTest file_is_writeable(struct ArchivePage* page) {
464 if (g_file_test(page->name, G_FILE_TEST_EXISTS) &&
465 ! page->force_overwrite)
466 return A_FILE_EXISTS;
467 if (g_file_test(page->name, G_FILE_TEST_IS_SYMLINK))
468 return A_FILE_IS_LINK;
469 if (g_file_test(page->name, G_FILE_TEST_IS_DIR))
470 return A_FILE_IS_DIR;
471 if ((fd = open(page->name, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
473 case EACCES: return A_FILE_NO_WRITE;
474 case EEXIST: return A_FILE_OK;
475 default: return A_FILE_UNKNOWN;
480 claws_unlink(page->name);
485 static gboolean archiver_save_files(struct ArchivePage* page) {
487 MainWindow* mainwin = mainwindow_get_mainwindow();
489 COMPRESS_METHOD method;
490 ARCHIVE_FORMAT format;
495 const gchar* res = NULL;
499 if (page->path == NULL || page->name == NULL) {
500 /* Test if page->file and page->folder has uncommitted information */
501 if (! uncommitted_entry_info(page)) {
502 dialog = gtk_message_dialog_new(
503 GTK_WINDOW(mainwin->window),
504 GTK_DIALOG_DESTROY_WITH_PARENT,
507 _("Folder and archive must be selected"));
508 gtk_dialog_run (GTK_DIALOG (dialog));
509 gtk_widget_destroy (dialog);
513 if ((perm = file_is_writeable(page)) != A_FILE_OK) {
516 msg = g_strdup_printf(_("%s: Exists. Continue anyway?"), page->name);
519 msg = g_strdup_printf(_("%s: Is a link. Cannot continue"), page->name);
522 msg = g_strdup_printf(_("%s: Is a directory. Cannot continue"), page->name);
524 case A_FILE_NO_WRITE:
525 msg = g_strdup_printf(_("%s: Missing permissions. Cannot continue"), page->name);
528 msg = g_strdup_printf(_("%s: Unknown error. Cannot continue"), page->name);
532 if (perm == A_FILE_EXISTS) {
533 dialog = gtk_message_dialog_new(
534 GTK_WINDOW(mainwin->window),
535 GTK_DIALOG_DESTROY_WITH_PARENT,
537 GTK_BUTTONS_OK_CANCEL,
539 response = gtk_dialog_run(GTK_DIALOG (dialog));
540 gtk_widget_destroy(dialog);
542 if (response == GTK_RESPONSE_CANCEL) {
547 dialog = gtk_message_dialog_new(
548 GTK_WINDOW(mainwin->window),
549 GTK_DIALOG_DESTROY_WITH_PARENT,
553 response = gtk_dialog_run(GTK_DIALOG (dialog));
554 gtk_widget_destroy(dialog);
559 if (! valid_file_name(page->name)) {
560 dialog = gtk_message_dialog_new(
561 GTK_WINDOW(mainwin->window),
562 GTK_DIALOG_DESTROY_WITH_PARENT,
565 _("Not a valid file name:\n%s."),
567 gtk_dialog_run (GTK_DIALOG (dialog));
568 gtk_widget_destroy (dialog);
571 item = folder_find_item_from_identifier(page->path);
573 dialog = gtk_message_dialog_new(
574 GTK_WINDOW(mainwin->window),
575 GTK_DIALOG_DESTROY_WITH_PARENT,
578 _("Not a valid Claws Mail folder:\n%s."),
580 gtk_dialog_run (GTK_DIALOG (dialog));
581 gtk_widget_destroy (dialog);
585 page->total_size = 0;
586 page->rename = gtk_toggle_button_get_active(
587 GTK_TOGGLE_BUTTON(page->rename_files));
588 recursive = gtk_toggle_button_get_active(
589 GTK_TOGGLE_BUTTON(page->recursive));
590 page->md5 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->md5sum));
591 page->unlink = gtk_toggle_button_get_active(
592 GTK_TOGGLE_BUTTON(page->unlink_files));
593 create_progress_dialog(page);
594 walk_folder(page, item, recursive);
597 list = archive_get_file_list();
598 orig_file = (page->md5) ? page->files * 2 : page->files;
599 debug_print("md5: %d, orig: %d, md5: %d\n",
600 page->md5, page->files, orig_file);
601 if (orig_file != g_slist_length(list)) {
602 dialog = gtk_message_dialog_new(
603 GTK_WINDOW(mainwin->window),
604 GTK_DIALOG_DESTROY_WITH_PARENT,
606 GTK_BUTTONS_OK_CANCEL,
607 _("Adding files in folder failed\n"
608 "Files in folder: %d\n"
609 "Files in list: %d\n"
610 "\nContinue anyway?"),
611 orig_file, g_slist_length(list));
612 response = gtk_dialog_run(GTK_DIALOG (dialog));
613 gtk_widget_destroy(dialog);
614 if (response == GTK_RESPONSE_CANCEL) {
615 archive_free_file_list(page->md5, page->rename);
619 method = get_compress_method(page->compress_methods);
620 format = get_archive_format(page->archive_formats);
621 if ((res = archive_create(page->name, list, method, format)) != NULL) {
622 dialog = gtk_message_dialog_new(
623 GTK_WINDOW(mainwin->window),
624 GTK_DIALOG_DESTROY_WITH_PARENT,
628 gtk_dialog_run (GTK_DIALOG (dialog));
629 gtk_widget_destroy (dialog);
630 archive_free_file_list(page->md5, page->rename);
634 archive_free_archived_files();
639 static void entry_change_cb(GtkWidget* widget, gpointer data) {
640 const gchar* name = gtk_widget_get_name(widget);
641 struct ArchivePage* page = (struct ArchivePage *) data;
643 if (strcmp("folder", name) == 0) {
644 page->path = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
645 debug_print("page->folder = %s\n", page->path);
647 else if (strcmp("file", name) == 0) {
648 page->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
649 page->force_overwrite = FALSE;
650 debug_print("page->name = %s\n", page->name);
654 static void show_result(struct ArchivePage* page) {
666 GtkTreeViewColumn* header;
667 GtkCellRenderer* renderer;
670 gchar* method = NULL;
671 gchar* format = NULL;
673 MainWindow* mainwin = mainwindow_get_mainwindow();
675 switch (get_compress_method(page->compress_methods)) {
677 method = g_strdup("ZIP");
680 method = g_strdup("BZIP2");
684 method = g_strdup("Compress");
688 method = g_strdup("No Compression");
692 switch (get_archive_format(page->archive_formats)) {
694 format = g_strdup("TAR");
697 format = g_strdup("SHAR");
700 format = g_strdup("PAX");
703 format = g_strdup("CPIO");
706 format = g_strdup("NO FORMAT");
709 g_stat(page->name, &st);
710 dialog = gtk_dialog_new_with_buttons(
712 GTK_WINDOW(mainwin->window),
713 GTK_DIALOG_DESTROY_WITH_PARENT,
717 g_signal_connect_swapped(
720 G_CALLBACK(gtk_widget_destroy),
723 list = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
729 "headers-clickable", FALSE,
730 "reorderable", FALSE,
731 "enable-search", FALSE,
734 renderer = gtk_cell_renderer_text_new();
736 header = gtk_tree_view_column_new_with_attributes(
737 _("Attributes"), renderer, "text", STRING1, NULL);
738 gtk_tree_view_append_column(view, header);
740 header = gtk_tree_view_column_new_with_attributes(
741 _("Values"), renderer, "text", STRING2, NULL);
742 gtk_tree_view_append_column(view, header);
745 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(view));
747 gtk_list_store_append(list, &iter);
750 STRING1, _("Archive"),
751 STRING2, page->name, -1);
753 gtk_list_store_append(list, &iter);
756 STRING1, _("Archive format"),
757 STRING2, format, -1);
760 gtk_list_store_append(list, &iter);
763 STRING1, _("Compression method"),
764 STRING2, method, -1);
767 gtk_list_store_append(list, &iter);
768 msg = g_strdup_printf("%d", (page->md5) ? page->files * 2 : page->files);
771 STRING1, _("Number of files"),
775 gtk_list_store_append(list, &iter);
776 msg = g_strdup_printf("%d byte(s)", (guint) st.st_size);
779 STRING1, _("Archive Size"),
783 gtk_list_store_append(list, &iter);
784 msg = g_strdup_printf("%d byte(s)", page->total_size);
787 STRING1, _("Folder Size"),
791 gtk_list_store_append(list, &iter);
792 msg = g_strdup_printf("%d%%",
793 (guint)((st.st_size * 100) / page->total_size));
796 STRING1, _("Compression level"),
800 gtk_list_store_append(list, &iter);
801 msg = g_strdup_printf("%s", (page->md5) ? _("Yes") : _("No"));
804 STRING1, _("MD5 checksum"),
808 gtk_list_store_append(list, &iter);
809 msg = g_strdup_printf("%s", (page->rename) ? _("Yes") : _("No"));
812 STRING1, _("Descriptive names"),
816 gtk_list_store_append(list, &iter);
817 msg = g_strdup_printf("%s", (page->unlink) ? _("Yes") : _("No"));
820 STRING1, _("Delete selected files"),
824 msg = g_strdup(gtk_entry_get_text(GTK_ENTRY(page->isoDate)));
826 gtk_list_store_append(list, &iter);
829 STRING1, _("Select mails before"),
834 gtk_window_set_default_size(GTK_WINDOW(dialog), 320, 260);
836 gtk_widget_show_all(dialog);
839 static void archiver_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
840 struct ArchivePage* page = (struct ArchivePage *) data;
841 gboolean result = FALSE;
844 case GTK_RESPONSE_ACCEPT:
845 debug_print("User chose OK\n");
846 page->response = TRUE;
849 debug_print("User chose CANCEL\n");
850 page->response = FALSE;
851 archiver_gtk_done(page, widget);
854 debug_print("Settings:\naction: %d\n", page->response);
855 if (page->response) {
856 debug_print("Settings:\nfolder: %s\nname: %s\n",
857 (page->path) ? page->path : "(null)",
858 (page->name) ? page->name : "(null)");
859 result = archiver_save_files(page);
860 debug_print("Result->archiver_save_files: %d\n", result);
861 if (progress->progress_dialog &&
862 GTK_IS_WIDGET(progress->progress_dialog))
863 gtk_widget_destroy(progress->progress_dialog);
864 if (result && ! page->cancelled) {
866 archive_free_file_list(page->md5, page->rename);
867 archiver_gtk_done(page, widget);
870 if (page->cancelled) {
871 archiver_gtk_done(page, widget);
877 static void foldersel_cb(GtkWidget *widget, gpointer data)
882 struct ArchivePage* page = (struct ArchivePage *) data;
884 item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
885 if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
886 gtk_editable_delete_text(GTK_EDITABLE(page->folder), 0, -1);
887 gtk_editable_insert_text(GTK_EDITABLE(page->folder),
888 item_id, strlen(item_id), &newpos);
889 page->path = g_strdup(item_id);
892 debug_print("Folder to archive: %s\n",
893 gtk_entry_get_text(GTK_ENTRY(page->folder)));
896 static void filesel_cb(GtkWidget *widget, gpointer data)
901 const gchar* homedir;
902 struct ArchivePage* page = (struct ArchivePage *) data;
904 dialog = gtk_file_chooser_dialog_new(
905 _("Select file name for archive [suffix should reflect archive like .tgz]"),
907 GTK_FILE_CHOOSER_ACTION_SAVE,
908 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
909 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
911 homedir = g_getenv("HOME");
913 homedir = g_get_home_dir();
915 if (archiver_prefs.save_folder)
916 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
917 archiver_prefs.save_folder);
919 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), homedir);
920 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY) {
921 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
923 gtk_editable_delete_text(GTK_EDITABLE(page->file), 0, -1);
924 gtk_editable_insert_text(GTK_EDITABLE(page->file),
925 file, strlen(file), &newpos);
926 page->name = g_strdup(file);
928 page->force_overwrite = TRUE;
931 gtk_widget_destroy(dialog);
932 debug_print("Name for archive: %s\n",
933 gtk_entry_get_text(GTK_ENTRY(page->file)));
936 void set_progress_file_label(const gchar* file) {
937 debug_print("IsLabel: %s, Update label: %s\n",
938 GTK_IS_WIDGET(progress->file_label)? "Yes" : "No", file);
939 if (GTK_IS_WIDGET(progress->file_label))
940 gtk_label_set_text(GTK_LABEL(progress->file_label), file);
943 void set_progress_print_all(guint fraction, guint total, guint step) {
946 if (GTK_IS_WIDGET(progress->progress)) {
947 if ((fraction - progress->position) % step == 0) {
948 debug_print("frac: %d, total: %d, step: %d, prog->pos: %d\n",
949 fraction, total, step, progress->position);
950 gtk_progress_bar_set_fraction(
951 GTK_PROGRESS_BAR(progress->progress),
952 (total == 0) ? 0 : (gfloat)fraction / (gfloat)total);
953 text_count = g_strdup_printf(_("%ld of %ld"),
954 (long) fraction, (long) total);
955 gtk_progress_bar_set_text(
956 GTK_PROGRESS_BAR(progress->progress), text_count);
958 progress->position = fraction;
964 void archiver_gtk_show() {
969 GtkWidget* folder_label;
970 GtkWidget* folder_select;
971 GtkWidget* file_label;
972 GtkWidget* file_select;
973 GtkWidget* zip_radio_btn;
974 GtkWidget* bzip_radio_btn;
976 GtkWidget* compress_radio_btn;
978 GtkWidget* no_radio_btn;
979 GtkWidget* shar_radio_btn;
980 GtkWidget* pax_radio_btn;
981 GtkWidget* cpio_radio_btn;
982 GtkWidget* tar_radio_btn;
983 struct ArchivePage* page;
984 MainWindow* mainwin = mainwindow_get_mainwindow();
986 /*debug_set_mode(TRUE);*/
987 progress = init_progress();
989 page = init_archive_page();
991 dialog = gtk_dialog_new_with_buttons (
993 GTK_WINDOW(mainwin->window),
994 GTK_DIALOG_DESTROY_WITH_PARENT,
1004 G_CALLBACK(archiver_dialog_cb),
1007 frame = gtk_frame_new(_("Enter Archiver arguments"));
1008 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1009 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1010 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
1012 vbox1 = gtk_vbox_new (FALSE, 4);
1013 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 4);
1014 gtk_container_add(GTK_CONTAINER(frame), vbox1);
1016 hbox1 = gtk_hbox_new(FALSE, 4);
1017 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1018 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1020 folder_label = gtk_label_new(_("Folder to archive"));
1021 gtk_box_pack_start(GTK_BOX(hbox1), folder_label, FALSE, FALSE, 0);
1023 page->folder = gtk_entry_new();
1024 gtk_widget_set_name(page->folder, "folder");
1025 gtk_box_pack_start(GTK_BOX(hbox1), page->folder, TRUE, TRUE, 0);
1026 CLAWS_SET_TIP(page->folder,
1027 _("Folder which is the root of the archive"));
1029 folder_select = gtkut_get_browse_directory_btn(_("_Browse"));
1030 gtk_box_pack_start(GTK_BOX(hbox1), folder_select, FALSE, FALSE, 0);
1031 CLAWS_SET_TIP(folder_select,
1032 _("Click this button to select a folder which is to be root of the archive"));
1034 hbox1 = gtk_hbox_new(FALSE, 4);
1035 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1036 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1038 file_label = gtk_label_new(_("Name for archive"));
1039 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1041 page->file = gtk_entry_new();
1042 gtk_widget_set_name(page->file, "file");
1043 gtk_box_pack_start(GTK_BOX(hbox1), page->file, TRUE, TRUE, 0);
1044 CLAWS_SET_TIP(page->file, _("Archive location and name"));
1046 file_select = gtkut_get_browse_directory_btn(_("_Select"));
1047 gtk_box_pack_start(GTK_BOX(hbox1), file_select, FALSE, FALSE, 0);
1048 CLAWS_SET_TIP(file_select,
1049 _("Click this button to select a name and location for the archive"));
1051 frame = gtk_frame_new(_("Choose compression"));
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_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1056 hbox1 = gtk_hbox_new(FALSE, 4);
1057 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1058 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1060 zip_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_ZIP");
1061 gtk_widget_set_name(zip_radio_btn, "ZIP");
1062 gtk_box_pack_start(GTK_BOX(hbox1), zip_radio_btn, FALSE, FALSE, 0);
1063 CLAWS_SET_TIP(zip_radio_btn,
1064 _("Choose this option to use ZIP compression for the archive"));
1066 bzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1067 GTK_RADIO_BUTTON(zip_radio_btn), "BZIP_2");
1068 gtk_widget_set_name(bzip_radio_btn, "BZIP");
1069 gtk_box_pack_start(GTK_BOX(hbox1), bzip_radio_btn, FALSE, FALSE, 0);
1070 CLAWS_SET_TIP(bzip_radio_btn,
1071 _("Choose this option to use BZIP2 compression for the archive"));
1074 compress_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1075 GTK_RADIO_BUTTON(zip_radio_btn), "Com_press");
1076 gtk_widget_set_name(compress_radio_btn, "COMPRESS");
1077 gtk_box_pack_start(GTK_BOX(hbox1), compress_radio_btn, FALSE, FALSE, 0);
1078 CLAWS_SET_TIP(compress_radio_btn,
1079 _("Choose this to use Compress compression for your archive"));
1082 no_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1083 GTK_RADIO_BUTTON(zip_radio_btn), _("_None"));
1084 gtk_widget_set_name(no_radio_btn, "NONE");
1085 gtk_box_pack_start(GTK_BOX(hbox1), no_radio_btn, FALSE, FALSE, 0);
1086 CLAWS_SET_TIP(no_radio_btn,
1087 _("Choose this option to disable compression for the archive"));
1089 page->compress_methods =
1090 gtk_radio_button_get_group(GTK_RADIO_BUTTON(zip_radio_btn));
1092 switch (archiver_prefs.compression) {
1093 case COMPRESSION_ZIP:
1094 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(zip_radio_btn), TRUE);
1096 case COMPRESSION_BZIP:
1097 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bzip_radio_btn), TRUE);
1100 case COMPRESSION_COMPRESS:
1101 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compress_radio_btn), TRUE);
1104 case COMPRESSION_NONE:
1105 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(no_radio_btn), TRUE);
1109 frame = gtk_frame_new(_("Choose format"));
1110 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1111 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1112 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1114 hbox1 = gtk_hbox_new(FALSE, 4);
1115 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1116 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1118 tar_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_TAR");
1119 gtk_widget_set_name(tar_radio_btn, "TAR");
1120 gtk_box_pack_start(GTK_BOX(hbox1), tar_radio_btn, FALSE, FALSE, 0);
1121 CLAWS_SET_TIP(tar_radio_btn,
1122 _("Choose this option to use TAR as format for the archive"));
1124 shar_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1125 GTK_RADIO_BUTTON(tar_radio_btn), "S_HAR");
1126 gtk_widget_set_name(shar_radio_btn, "SHAR");
1127 gtk_box_pack_start(GTK_BOX(hbox1), shar_radio_btn, FALSE, FALSE, 0);
1128 CLAWS_SET_TIP(shar_radio_btn,
1129 _("Choose this to use SHAR as format for the archive"));
1131 cpio_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1132 GTK_RADIO_BUTTON(tar_radio_btn), "CP_IO");
1133 gtk_widget_set_name(cpio_radio_btn, "CPIO");
1134 gtk_box_pack_start(GTK_BOX(hbox1), cpio_radio_btn, FALSE, FALSE, 0);
1135 CLAWS_SET_TIP(cpio_radio_btn,
1136 _("Choose this option to use CPIO as format for the archive"));
1138 pax_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1139 GTK_RADIO_BUTTON(tar_radio_btn), "PA_X");
1140 gtk_widget_set_name(pax_radio_btn, "PAX");
1141 gtk_box_pack_start(GTK_BOX(hbox1), pax_radio_btn, FALSE, FALSE, 0);
1142 CLAWS_SET_TIP(pax_radio_btn,
1143 _("Choose this option to use PAX as format for the archive"));
1145 page->archive_formats =
1146 gtk_radio_button_get_group(GTK_RADIO_BUTTON(tar_radio_btn));
1148 switch (archiver_prefs.format) {
1150 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tar_radio_btn), TRUE);
1153 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shar_radio_btn), TRUE);
1156 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cpio_radio_btn), TRUE);
1159 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pax_radio_btn), TRUE);
1163 frame = gtk_frame_new(_("Miscellaneous options"));
1164 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1165 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1166 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1168 hbox1 = gtk_hbox_new(FALSE, 4);
1169 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1170 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1172 page->recursive = gtk_check_button_new_with_mnemonic(_("_Recursive"));
1173 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->recursive), archiver_prefs.recursive);
1174 gtk_box_pack_start(GTK_BOX(hbox1), page->recursive, FALSE, FALSE, 0);
1175 CLAWS_SET_TIP(page->recursive,
1176 _("Choose this option to include subfolders in the archive"));
1178 page->md5sum = gtk_check_button_new_with_mnemonic(_("_MD5sum"));
1179 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->md5sum), archiver_prefs.md5sum);
1180 gtk_box_pack_start(GTK_BOX(hbox1), page->md5sum, FALSE, FALSE, 0);
1181 CLAWS_SET_TIP(page->md5sum,
1182 _("Choose this option to add MD5 checksums for each file in the archive.\n"
1183 "Be aware though, that this dramatically increases the time it\n"
1184 "will take to create the archive"));
1186 page->rename_files = gtk_check_button_new_with_mnemonic(_("R_ename"));
1187 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->rename_files), archiver_prefs.rename);
1188 gtk_box_pack_start(GTK_BOX(hbox1), page->rename_files, FALSE, FALSE, 0);
1189 CLAWS_SET_TIP(page->rename_files,
1190 _("Choose this option to use descriptive names for each file in the archive.\n"
1191 "The naming scheme: date_from@to@subject.\n"
1192 "Names will be truncated to max 96 characters"));
1194 page->unlink_files = gtk_check_button_new_with_mnemonic(_("_Delete"));
1195 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->unlink_files), archiver_prefs.unlink);
1196 gtk_box_pack_start(GTK_BOX(hbox1), page->unlink_files, FALSE, FALSE, 0);
1197 CLAWS_SET_TIP(page->unlink_files,
1198 _("Choose this option to delete mails after archiving\n"
1199 "At this point only handles IMAP4, Local mbox and POP3"));
1202 frame = gtk_frame_new(_("Selection options"));
1203 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1204 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1205 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1207 hbox1 = gtk_hbox_new(FALSE, 4);
1208 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1209 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1211 file_label = gtk_label_new(_("Select mails before"));
1212 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1214 page->isoDate = gtk_entry_new();
1215 gtk_widget_set_name(page->isoDate, "isoDate");
1216 gtk_box_pack_start(GTK_BOX(hbox1), page->isoDate, TRUE, TRUE, 0);
1217 CLAWS_SET_TIP(page->isoDate,
1218 _("Select emails before a certain date\n"
1219 "Date must comply to ISO-8601 [YYYY-MM-DD]"));
1221 g_signal_connect(G_OBJECT(folder_select), "clicked",
1222 G_CALLBACK(foldersel_cb), page);
1223 g_signal_connect(G_OBJECT(file_select), "clicked",
1224 G_CALLBACK(filesel_cb), page);
1225 g_signal_connect(G_OBJECT(page->folder), "activate",
1226 G_CALLBACK(entry_change_cb), page);
1227 g_signal_connect(G_OBJECT(page->file), "activate",
1228 G_CALLBACK(entry_change_cb), page);
1230 gtk_widget_show_all(dialog);
1233 void archiver_gtk_done(struct ArchivePage* page, GtkWidget* widget) {
1234 dispose_archive_page(page);
1236 gtk_widget_destroy(widget);
1237 /*debug_set_mode(FALSE);*/