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) {
291 debug_print("md5sum: %s\n", md5sum);
293 open(md5_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) {
297 text = g_strrstr_len(file, strlen(file), "/");
300 text = g_strdup_printf("%s %s\n", md5sum, text);
303 text = g_strdup_printf("%s %s\n", md5sum, file);
305 debug_print("md5sum: %s\n", text);
306 if (write(fd, text, strlen(text)) < 0)
312 static gchar* descriptive_file_name(
313 struct ArchivePage* page, const gchar* file, MsgInfo *msginfo) {
314 gchar* new_file = NULL;
315 gchar *name, *p, *to, *from, *date, *subject;
317 debug_print("renaming file\n");
318 p = g_strrstr_len(file, strlen(file), "/");
319 p = g_strndup(file, p - file);
323 to = g_strdup(msginfo->to);
329 from = g_strdup(msginfo->from);
330 extract_address(from);
335 date = g_strdup(msginfo->date);
336 subst_for_shellsafe_filename(date);
337 /* if not on windows we need to subst some more */
338 subst_chars(date, ":", '_');
342 if (msginfo->subject) {
343 subject = g_strdup(msginfo->subject);
344 subst_for_shellsafe_filename(subject);
345 /* if not on windows we need to subst some more */
346 subst_chars(subject, ":", '_');
349 subject = g_strdup("");
350 name = g_strdup_printf("%s_%s@%s@%s", date, from, to, subject);
351 /* ensure file name is not larger than 96 chars (max file name size
352 * is 100 chars but reserve for .md5)
354 if (strlen(name) > 96)
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");
683 method = g_strdup("Compress");
686 method = g_strdup("No Compression");
690 switch (get_archive_format(page->archive_formats)) {
692 format = g_strdup("TAR");
695 format = g_strdup("SHAR");
698 format = g_strdup("PAX");
701 format = g_strdup("CPIO");
704 format = g_strdup("NO FORMAT");
707 g_stat(page->name, &st);
708 dialog = gtk_dialog_new_with_buttons(
710 GTK_WINDOW(mainwin->window),
711 GTK_DIALOG_DESTROY_WITH_PARENT,
715 g_signal_connect_swapped(
718 G_CALLBACK(gtk_widget_destroy),
721 list = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
727 "headers-clickable", FALSE,
728 "reorderable", FALSE,
729 "enable-search", FALSE,
732 renderer = gtk_cell_renderer_text_new();
734 header = gtk_tree_view_column_new_with_attributes(
735 _("Attributes"), renderer, "text", STRING1, NULL);
736 gtk_tree_view_append_column(view, header);
738 header = gtk_tree_view_column_new_with_attributes(
739 _("Values"), renderer, "text", STRING2, NULL);
740 gtk_tree_view_append_column(view, header);
743 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(view));
745 gtk_list_store_append(list, &iter);
748 STRING1, _("Archive"),
749 STRING2, page->name, -1);
751 gtk_list_store_append(list, &iter);
754 STRING1, _("Archive format"),
755 STRING2, format, -1);
758 gtk_list_store_append(list, &iter);
761 STRING1, _("Compression method"),
762 STRING2, method, -1);
765 gtk_list_store_append(list, &iter);
766 msg = g_strdup_printf("%d", (page->md5) ? page->files * 2 : page->files);
769 STRING1, _("Number of files"),
773 gtk_list_store_append(list, &iter);
774 msg = g_strdup_printf("%d byte(s)", (guint) st.st_size);
777 STRING1, _("Archive Size"),
781 gtk_list_store_append(list, &iter);
782 msg = g_strdup_printf("%d byte(s)", page->total_size);
785 STRING1, _("Folder Size"),
789 gtk_list_store_append(list, &iter);
790 msg = g_strdup_printf("%d%%",
791 (guint)((st.st_size * 100) / page->total_size));
794 STRING1, _("Compression level"),
798 gtk_list_store_append(list, &iter);
799 msg = g_strdup_printf("%s", (page->md5) ? _("Yes") : _("No"));
802 STRING1, _("MD5 checksum"),
806 gtk_list_store_append(list, &iter);
807 msg = g_strdup_printf("%s", (page->rename) ? _("Yes") : _("No"));
810 STRING1, _("Descriptive names"),
814 gtk_list_store_append(list, &iter);
815 msg = g_strdup_printf("%s", (page->unlink) ? _("Yes") : _("No"));
818 STRING1, _("Delete selected files"),
822 msg = g_strdup(gtk_entry_get_text(GTK_ENTRY(page->isoDate)));
824 gtk_list_store_append(list, &iter);
827 STRING1, _("Select mails before"),
832 gtk_window_set_default_size(GTK_WINDOW(dialog), 320, 260);
834 gtk_widget_show_all(dialog);
837 static void archiver_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
838 struct ArchivePage* page = (struct ArchivePage *) data;
839 gboolean result = FALSE;
842 case GTK_RESPONSE_ACCEPT:
843 debug_print("User chose OK\n");
844 page->response = TRUE;
847 debug_print("User chose CANCEL\n");
848 page->response = FALSE;
849 archiver_gtk_done(page, widget);
852 debug_print("Settings:\naction: %d\n", page->response);
853 if (page->response) {
854 debug_print("Settings:\nfolder: %s\nname: %s\n",
855 (page->path) ? page->path : "(null)",
856 (page->name) ? page->name : "(null)");
857 result = archiver_save_files(page);
858 debug_print("Result->archiver_save_files: %d\n", result);
859 if (progress->progress_dialog &&
860 GTK_IS_WIDGET(progress->progress_dialog))
861 gtk_widget_destroy(progress->progress_dialog);
862 if (result && ! page->cancelled) {
864 archive_free_file_list(page->md5, page->rename);
865 archiver_gtk_done(page, widget);
868 if (page->cancelled) {
869 archiver_gtk_done(page, widget);
875 static void foldersel_cb(GtkWidget *widget, gpointer data)
880 struct ArchivePage* page = (struct ArchivePage *) data;
882 item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
883 if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
884 gtk_editable_delete_text(GTK_EDITABLE(page->folder), 0, -1);
885 gtk_editable_insert_text(GTK_EDITABLE(page->folder),
886 item_id, strlen(item_id), &newpos);
887 page->path = g_strdup(item_id);
890 debug_print("Folder to archive: %s\n",
891 gtk_entry_get_text(GTK_ENTRY(page->folder)));
894 static void filesel_cb(GtkWidget *widget, gpointer data)
899 const gchar* homedir;
900 struct ArchivePage* page = (struct ArchivePage *) data;
902 dialog = gtk_file_chooser_dialog_new(
903 _("Select file name for archive [suffix should reflect archive like .tgz]"),
905 GTK_FILE_CHOOSER_ACTION_SAVE,
906 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
907 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
909 homedir = g_getenv("HOME");
911 homedir = g_get_home_dir();
913 if (archiver_prefs.save_folder)
914 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
915 archiver_prefs.save_folder);
917 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), homedir);
918 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY) {
919 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
921 gtk_editable_delete_text(GTK_EDITABLE(page->file), 0, -1);
922 gtk_editable_insert_text(GTK_EDITABLE(page->file),
923 file, strlen(file), &newpos);
924 page->name = g_strdup(file);
926 page->force_overwrite = TRUE;
929 gtk_widget_destroy(dialog);
930 debug_print("Name for archive: %s\n",
931 gtk_entry_get_text(GTK_ENTRY(page->file)));
934 void set_progress_file_label(const gchar* file) {
935 debug_print("IsLabel: %s, Update label: %s\n",
936 GTK_IS_WIDGET(progress->file_label)? "Yes" : "No", file);
937 if (GTK_IS_WIDGET(progress->file_label))
938 gtk_label_set_text(GTK_LABEL(progress->file_label), file);
941 void set_progress_print_all(guint fraction, guint total, guint step) {
944 if (GTK_IS_WIDGET(progress->progress)) {
945 if ((fraction - progress->position) % step == 0) {
946 debug_print("frac: %d, total: %d, step: %d, prog->pos: %d\n",
947 fraction, total, step, progress->position);
948 gtk_progress_bar_set_fraction(
949 GTK_PROGRESS_BAR(progress->progress),
950 (total == 0) ? 0 : (gfloat)fraction / (gfloat)total);
951 text_count = g_strdup_printf(_("%ld of %ld"),
952 (long) fraction, (long) total);
953 gtk_progress_bar_set_text(
954 GTK_PROGRESS_BAR(progress->progress), text_count);
956 progress->position = fraction;
962 void archiver_gtk_show() {
967 GtkWidget* folder_label;
968 GtkWidget* folder_select;
969 GtkWidget* file_label;
970 GtkWidget* file_select;
971 GtkWidget* zip_radio_btn;
972 GtkWidget* bzip_radio_btn;
973 GtkWidget* compress_radio_btn;
974 GtkWidget* no_radio_btn;
975 GtkWidget* shar_radio_btn;
976 GtkWidget* pax_radio_btn;
977 GtkWidget* cpio_radio_btn;
978 GtkWidget* tar_radio_btn;
979 struct ArchivePage* page;
980 MainWindow* mainwin = mainwindow_get_mainwindow();
982 /*debug_set_mode(TRUE);*/
983 progress = init_progress();
985 page = init_archive_page();
987 dialog = gtk_dialog_new_with_buttons (
989 GTK_WINDOW(mainwin->window),
990 GTK_DIALOG_DESTROY_WITH_PARENT,
1000 G_CALLBACK(archiver_dialog_cb),
1003 frame = gtk_frame_new(_("Enter Archiver arguments"));
1004 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1005 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1006 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
1008 vbox1 = gtk_vbox_new (FALSE, 4);
1009 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 4);
1010 gtk_container_add(GTK_CONTAINER(frame), vbox1);
1012 hbox1 = gtk_hbox_new(FALSE, 4);
1013 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1014 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1016 folder_label = gtk_label_new(_("Folder to archive"));
1017 gtk_box_pack_start(GTK_BOX(hbox1), folder_label, FALSE, FALSE, 0);
1019 page->folder = gtk_entry_new();
1020 gtk_widget_set_name(page->folder, "folder");
1021 gtk_box_pack_start(GTK_BOX(hbox1), page->folder, TRUE, TRUE, 0);
1022 CLAWS_SET_TIP(page->folder,
1023 _("Folder which is the root of the archive"));
1025 folder_select = gtkut_get_browse_directory_btn(_("_Browse"));
1026 gtk_box_pack_start(GTK_BOX(hbox1), folder_select, FALSE, FALSE, 0);
1027 CLAWS_SET_TIP(folder_select,
1028 _("Click this button to select a folder which is to be root of the archive"));
1030 hbox1 = gtk_hbox_new(FALSE, 4);
1031 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1032 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1034 file_label = gtk_label_new(_("Name for archive"));
1035 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1037 page->file = gtk_entry_new();
1038 gtk_widget_set_name(page->file, "file");
1039 gtk_box_pack_start(GTK_BOX(hbox1), page->file, TRUE, TRUE, 0);
1040 CLAWS_SET_TIP(page->file, _("Archive location and name"));
1042 file_select = gtkut_get_browse_directory_btn(_("_Select"));
1043 gtk_box_pack_start(GTK_BOX(hbox1), file_select, FALSE, FALSE, 0);
1044 CLAWS_SET_TIP(file_select,
1045 _("Click this button to select a name and location for the archive"));
1047 frame = gtk_frame_new(_("Choose compression"));
1048 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1049 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1050 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1052 hbox1 = gtk_hbox_new(FALSE, 4);
1053 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1054 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1056 zip_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_ZIP");
1057 gtk_widget_set_name(zip_radio_btn, "ZIP");
1058 gtk_box_pack_start(GTK_BOX(hbox1), zip_radio_btn, FALSE, FALSE, 0);
1059 CLAWS_SET_TIP(zip_radio_btn,
1060 _("Choose this option to use ZIP compression for the archive"));
1062 bzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1063 GTK_RADIO_BUTTON(zip_radio_btn), "BZIP_2");
1064 gtk_widget_set_name(bzip_radio_btn, "BZIP");
1065 gtk_box_pack_start(GTK_BOX(hbox1), bzip_radio_btn, FALSE, FALSE, 0);
1066 CLAWS_SET_TIP(bzip_radio_btn,
1067 _("Choose this option to use BZIP2 compression for the archive"));
1069 compress_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1070 GTK_RADIO_BUTTON(zip_radio_btn), "Com_press");
1071 gtk_widget_set_name(compress_radio_btn, "COMPRESS");
1072 gtk_box_pack_start(GTK_BOX(hbox1), compress_radio_btn, FALSE, FALSE, 0);
1073 CLAWS_SET_TIP(compress_radio_btn,
1074 _("Choose this to use Compress compression for your archive"));
1076 no_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1077 GTK_RADIO_BUTTON(zip_radio_btn), _("_None"));
1078 gtk_widget_set_name(no_radio_btn, "NONE");
1079 gtk_box_pack_start(GTK_BOX(hbox1), no_radio_btn, FALSE, FALSE, 0);
1080 CLAWS_SET_TIP(no_radio_btn,
1081 _("Choose this option to disable compression for the archive"));
1083 page->compress_methods =
1084 gtk_radio_button_get_group(GTK_RADIO_BUTTON(zip_radio_btn));
1086 switch (archiver_prefs.compression) {
1087 case COMPRESSION_ZIP:
1088 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(zip_radio_btn), TRUE);
1090 case COMPRESSION_BZIP:
1091 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bzip_radio_btn), TRUE);
1093 case COMPRESSION_COMPRESS:
1094 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compress_radio_btn), TRUE);
1096 case COMPRESSION_NONE:
1097 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(no_radio_btn), TRUE);
1101 frame = gtk_frame_new(_("Choose format"));
1102 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1103 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1104 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1106 hbox1 = gtk_hbox_new(FALSE, 4);
1107 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1108 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1110 tar_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_TAR");
1111 gtk_widget_set_name(tar_radio_btn, "TAR");
1112 gtk_box_pack_start(GTK_BOX(hbox1), tar_radio_btn, FALSE, FALSE, 0);
1113 CLAWS_SET_TIP(tar_radio_btn,
1114 _("Choose this option to use TAR as format for the archive"));
1116 shar_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1117 GTK_RADIO_BUTTON(tar_radio_btn), "S_HAR");
1118 gtk_widget_set_name(shar_radio_btn, "SHAR");
1119 gtk_box_pack_start(GTK_BOX(hbox1), shar_radio_btn, FALSE, FALSE, 0);
1120 CLAWS_SET_TIP(shar_radio_btn,
1121 _("Choose this to use SHAR as format for the archive"));
1123 cpio_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1124 GTK_RADIO_BUTTON(tar_radio_btn), "CP_IO");
1125 gtk_widget_set_name(cpio_radio_btn, "CPIO");
1126 gtk_box_pack_start(GTK_BOX(hbox1), cpio_radio_btn, FALSE, FALSE, 0);
1127 CLAWS_SET_TIP(cpio_radio_btn,
1128 _("Choose this option to use CPIO as format for the archive"));
1130 pax_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1131 GTK_RADIO_BUTTON(tar_radio_btn), "PA_X");
1132 gtk_widget_set_name(pax_radio_btn, "PAX");
1133 gtk_box_pack_start(GTK_BOX(hbox1), pax_radio_btn, FALSE, FALSE, 0);
1134 CLAWS_SET_TIP(pax_radio_btn,
1135 _("Choose this option to use PAX as format for the archive"));
1137 page->archive_formats =
1138 gtk_radio_button_get_group(GTK_RADIO_BUTTON(tar_radio_btn));
1140 switch (archiver_prefs.format) {
1142 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tar_radio_btn), TRUE);
1145 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shar_radio_btn), TRUE);
1148 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cpio_radio_btn), TRUE);
1151 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pax_radio_btn), TRUE);
1155 frame = gtk_frame_new(_("Miscellaneous options"));
1156 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1157 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1158 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1160 hbox1 = gtk_hbox_new(FALSE, 4);
1161 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1162 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1164 page->recursive = gtk_check_button_new_with_mnemonic(_("_Recursive"));
1165 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->recursive), archiver_prefs.recursive);
1166 gtk_box_pack_start(GTK_BOX(hbox1), page->recursive, FALSE, FALSE, 0);
1167 CLAWS_SET_TIP(page->recursive,
1168 _("Choose this option to include subfolders in the archive"));
1170 page->md5sum = gtk_check_button_new_with_mnemonic(_("_MD5sum"));
1171 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->md5sum), archiver_prefs.md5sum);
1172 gtk_box_pack_start(GTK_BOX(hbox1), page->md5sum, FALSE, FALSE, 0);
1173 CLAWS_SET_TIP(page->md5sum,
1174 _("Choose this option to add MD5 checksums for each file in the archive.\n"
1175 "Be aware though, that this dramatically increases the time it\n"
1176 "will take to create the archive"));
1178 page->rename_files = gtk_check_button_new_with_mnemonic(_("R_ename"));
1179 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->rename_files), archiver_prefs.rename);
1180 gtk_box_pack_start(GTK_BOX(hbox1), page->rename_files, FALSE, FALSE, 0);
1181 CLAWS_SET_TIP(page->rename_files,
1182 _("Choose this option to use descriptive names for each file in the archive.\n"
1183 "The naming scheme: date_from@to@subject.\n"
1184 "Names will be truncated to max 96 characters"));
1186 page->unlink_files = gtk_check_button_new_with_mnemonic(_("_Delete"));
1187 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->unlink_files), archiver_prefs.unlink);
1188 gtk_box_pack_start(GTK_BOX(hbox1), page->unlink_files, FALSE, FALSE, 0);
1189 CLAWS_SET_TIP(page->unlink_files,
1190 _("Choose this option to delete mails after archiving\n"
1191 "At this point only handles IMAP4, Local mbox and POP3"));
1194 frame = gtk_frame_new(_("Selection options"));
1195 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1196 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1197 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1199 hbox1 = gtk_hbox_new(FALSE, 4);
1200 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1201 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1203 file_label = gtk_label_new(_("Select mails before"));
1204 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1206 page->isoDate = gtk_entry_new();
1207 gtk_widget_set_name(page->isoDate, "isoDate");
1208 gtk_box_pack_start(GTK_BOX(hbox1), page->isoDate, TRUE, TRUE, 0);
1209 CLAWS_SET_TIP(page->isoDate,
1210 _("Select emails before a certain date\n"
1211 "Date must comply to ISO-8601 [YYYY-MM-DD]"));
1213 g_signal_connect(G_OBJECT(folder_select), "clicked",
1214 G_CALLBACK(foldersel_cb), page);
1215 g_signal_connect(G_OBJECT(file_select), "clicked",
1216 G_CALLBACK(filesel_cb), page);
1217 g_signal_connect(G_OBJECT(page->folder), "activate",
1218 G_CALLBACK(entry_change_cb), page);
1219 g_signal_connect(G_OBJECT(page->file), "activate",
1220 G_CALLBACK(entry_change_cb), page);
1222 gtk_widget_show_all(dialog);
1225 void archiver_gtk_done(struct ArchivePage* page, GtkWidget* widget) {
1226 dispose_archive_page(page);
1228 gtk_widget_destroy(widget);
1229 /*debug_set_mode(FALSE);*/