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 write(fd, text, strlen(text));
309 static gchar* descriptive_file_name(
310 struct ArchivePage* page, const gchar* file, MsgInfo *msginfo) {
311 gchar* new_file = NULL;
312 gchar *name, *p, *to, *from, *date, *subject;
314 debug_print("renaming file\n");
315 p = g_strrstr_len(file, strlen(file), "/");
316 p = g_strndup(file, p - file);
320 to = g_strdup(msginfo->to);
326 from = g_strdup(msginfo->from);
327 extract_address(from);
332 date = g_strdup(msginfo->date);
333 subst_for_shellsafe_filename(date);
334 /* if not on windows we need to subst some more */
335 subst_chars(date, ":", '_');
339 if (msginfo->subject) {
340 subject = g_strdup(msginfo->subject);
341 subst_for_shellsafe_filename(subject);
342 /* if not on windows we need to subst some more */
343 subst_chars(subject, ":", '_');
346 subject = g_strdup("");
347 name = g_strdup_printf("%s_%s@%s@%s", date, from, to, subject);
348 /* ensure file name is not larger than 96 chars (max file name size
349 * is 100 chars but reserve for .md5)
351 if (strlen(name) > 96) {
352 name = realloc(name, 97);
356 new_file = g_strconcat(p, "/", name, NULL);
365 debug_print("New_file: %s\n", new_file);
366 if (link(file, new_file) != 0) {
367 if (errno != EEXIST) {
370 new_file = g_strdup(file);
371 page->rename = FALSE;
378 static void walk_folder(struct ArchivePage* page, FolderItem* item,
379 gboolean recursive) {
386 gchar* md5_file = NULL;
389 MsgTrash* msg_trash = NULL;
390 const gchar* date = NULL;
392 if (recursive && ! page->cancelled) {
393 debug_print("Scanning recursive\n");
394 node = item->node->children;
395 while(node && ! page->cancelled) {
396 debug_print("Number of nodes: %d\n", g_node_n_children(node));
398 child = FOLDER_ITEM(node->data);
399 debug_print("new node: %d messages\n", child->total_msgs);
400 walk_folder(page, child, recursive);
405 if (! page->cancelled) {
406 date = gtk_entry_get_text(GTK_ENTRY(page->isoDate));
407 debug_print("cut-off date: %s\n", date);
409 page->files += item->total_msgs;
410 msglist = folder_item_get_msg_list(item);
411 msg_trash = new_msg_trash(item);
412 for (cur = msglist; cur && ! page->cancelled; cur = cur->next) {
413 msginfo = (MsgInfo *) cur->data;
414 debug_print("%s_%s_%s_%s\n",
415 msginfo->date, msginfo->to, msginfo->from, msginfo->subject);
416 file = folder_item_fetch_msg(item, msginfo->msgnum);
417 if (date && strlen(date) > 0 && !before_date(msginfo->date_t, date)) {
421 page->total_size += msginfo->size;
422 /*debug_print("Processing: %s\n", file);*/
425 archive_add_msg_mark(msg_trash, msginfo);
428 file = descriptive_file_name(page, file, msginfo);
430 /* Could not create a descriptive name */
431 file = folder_item_fetch_msg(item, msginfo->msgnum);
435 md5_file = g_strdup_printf("%s.md5", file);
436 create_md5sum(file, md5_file);
437 archive_add_file(md5_file);
440 archive_add_file(file);
444 if (count % 350 == 0) {
445 debug_print("pulse progressbar\n");
446 text = g_strdup_printf(
447 "Scanning %s: %d files", item->name, count);
448 gtk_progress_bar_set_text(
449 GTK_PROGRESS_BAR(progress->progress), text);
451 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress->progress));
456 procmsg_msg_list_free(msglist);
460 static AFileTest file_is_writeable(struct ArchivePage* page) {
463 if (g_file_test(page->name, G_FILE_TEST_EXISTS) &&
464 ! page->force_overwrite)
465 return A_FILE_EXISTS;
466 if (g_file_test(page->name, G_FILE_TEST_IS_SYMLINK))
467 return A_FILE_IS_LINK;
468 if (g_file_test(page->name, G_FILE_TEST_IS_DIR))
469 return A_FILE_IS_DIR;
470 if ((fd = open(page->name, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
472 case EACCES: return A_FILE_NO_WRITE;
473 case EEXIST: return A_FILE_OK;
474 default: return A_FILE_UNKNOWN;
479 claws_unlink(page->name);
484 static gboolean archiver_save_files(struct ArchivePage* page) {
486 MainWindow* mainwin = mainwindow_get_mainwindow();
488 COMPRESS_METHOD method;
489 ARCHIVE_FORMAT format;
494 const gchar* res = NULL;
498 if (page->path == NULL || page->name == NULL) {
499 /* Test if page->file and page->folder has uncommitted information */
500 if (! uncommitted_entry_info(page)) {
501 dialog = gtk_message_dialog_new(
502 GTK_WINDOW(mainwin->window),
503 GTK_DIALOG_DESTROY_WITH_PARENT,
506 _("Folder and archive must be selected"));
507 gtk_dialog_run (GTK_DIALOG (dialog));
508 gtk_widget_destroy (dialog);
512 if ((perm = file_is_writeable(page)) != A_FILE_OK) {
515 msg = g_strdup_printf(_("%s: Exists. Continue anyway?"), page->name);
518 msg = g_strdup_printf(_("%s: Is a link. Cannot continue"), page->name);
521 msg = g_strdup_printf(_("%s: Is a directory. Cannot continue"), page->name);
523 case A_FILE_NO_WRITE:
524 msg = g_strdup_printf(_("%s: Missing permissions. Cannot continue"), page->name);
527 msg = g_strdup_printf(_("%s: Unknown error. Cannot continue"), page->name);
531 if (perm == A_FILE_EXISTS) {
532 dialog = gtk_message_dialog_new(
533 GTK_WINDOW(mainwin->window),
534 GTK_DIALOG_DESTROY_WITH_PARENT,
536 GTK_BUTTONS_OK_CANCEL,
538 response = gtk_dialog_run(GTK_DIALOG (dialog));
539 gtk_widget_destroy(dialog);
541 if (response == GTK_RESPONSE_CANCEL) {
546 dialog = gtk_message_dialog_new(
547 GTK_WINDOW(mainwin->window),
548 GTK_DIALOG_DESTROY_WITH_PARENT,
552 response = gtk_dialog_run(GTK_DIALOG (dialog));
553 gtk_widget_destroy(dialog);
558 if (! valid_file_name(page->name)) {
559 dialog = gtk_message_dialog_new(
560 GTK_WINDOW(mainwin->window),
561 GTK_DIALOG_DESTROY_WITH_PARENT,
564 _("Not a valid file name:\n%s."),
566 gtk_dialog_run (GTK_DIALOG (dialog));
567 gtk_widget_destroy (dialog);
570 item = folder_find_item_from_identifier(page->path);
572 dialog = gtk_message_dialog_new(
573 GTK_WINDOW(mainwin->window),
574 GTK_DIALOG_DESTROY_WITH_PARENT,
577 _("Not a valid Claws Mail folder:\n%s."),
579 gtk_dialog_run (GTK_DIALOG (dialog));
580 gtk_widget_destroy (dialog);
584 page->total_size = 0;
585 page->rename = gtk_toggle_button_get_active(
586 GTK_TOGGLE_BUTTON(page->rename_files));
587 recursive = gtk_toggle_button_get_active(
588 GTK_TOGGLE_BUTTON(page->recursive));
589 page->md5 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->md5sum));
590 page->unlink = gtk_toggle_button_get_active(
591 GTK_TOGGLE_BUTTON(page->unlink_files));
592 create_progress_dialog(page);
593 walk_folder(page, item, recursive);
596 list = archive_get_file_list();
597 orig_file = (page->md5) ? page->files * 2 : page->files;
598 debug_print("md5: %d, orig: %d, md5: %d\n",
599 page->md5, page->files, orig_file);
600 if (orig_file != g_slist_length(list)) {
601 dialog = gtk_message_dialog_new(
602 GTK_WINDOW(mainwin->window),
603 GTK_DIALOG_DESTROY_WITH_PARENT,
605 GTK_BUTTONS_OK_CANCEL,
606 _("Adding files in folder failed\n"
607 "Files in folder: %d\n"
608 "Files in list: %d\n"
609 "\nContinue anyway?"),
610 orig_file, g_slist_length(list));
611 response = gtk_dialog_run(GTK_DIALOG (dialog));
612 gtk_widget_destroy(dialog);
613 if (response == GTK_RESPONSE_CANCEL) {
614 archive_free_file_list(page->md5, page->rename);
618 method = get_compress_method(page->compress_methods);
619 format = get_archive_format(page->archive_formats);
620 if ((res = archive_create(page->name, list, method, format)) != NULL) {
621 dialog = gtk_message_dialog_new(
622 GTK_WINDOW(mainwin->window),
623 GTK_DIALOG_DESTROY_WITH_PARENT,
627 gtk_dialog_run (GTK_DIALOG (dialog));
628 gtk_widget_destroy (dialog);
629 archive_free_file_list(page->md5, page->rename);
633 archive_free_archived_files();
638 static void entry_change_cb(GtkWidget* widget, gpointer data) {
639 const gchar* name = gtk_widget_get_name(widget);
640 struct ArchivePage* page = (struct ArchivePage *) data;
642 if (strcmp("folder", name) == 0) {
643 page->path = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
644 debug_print("page->folder = %s\n", page->path);
646 else if (strcmp("file", name) == 0) {
647 page->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
648 page->force_overwrite = FALSE;
649 debug_print("page->name = %s\n", page->name);
653 static void show_result(struct ArchivePage* page) {
665 GtkTreeViewColumn* header;
666 GtkCellRenderer* renderer;
669 gchar* method = NULL;
670 gchar* format = NULL;
672 MainWindow* mainwin = mainwindow_get_mainwindow();
674 switch (get_compress_method(page->compress_methods)) {
676 method = g_strdup("ZIP");
679 method = g_strdup("BZIP2");
683 method = g_strdup("Compress");
687 method = g_strdup("No Compression");
691 switch (get_archive_format(page->archive_formats)) {
693 format = g_strdup("TAR");
696 format = g_strdup("SHAR");
699 format = g_strdup("PAX");
702 format = g_strdup("CPIO");
705 format = g_strdup("NO FORMAT");
708 g_stat(page->name, &st);
709 dialog = gtk_dialog_new_with_buttons(
711 GTK_WINDOW(mainwin->window),
712 GTK_DIALOG_DESTROY_WITH_PARENT,
716 g_signal_connect_swapped(
719 G_CALLBACK(gtk_widget_destroy),
722 list = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
728 "headers-clickable", FALSE,
729 "reorderable", FALSE,
730 "enable-search", FALSE,
733 renderer = gtk_cell_renderer_text_new();
735 header = gtk_tree_view_column_new_with_attributes(
736 _("Attributes"), renderer, "text", STRING1, NULL);
737 gtk_tree_view_append_column(view, header);
739 header = gtk_tree_view_column_new_with_attributes(
740 _("Values"), renderer, "text", STRING2, NULL);
741 gtk_tree_view_append_column(view, header);
744 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(view));
746 gtk_list_store_append(list, &iter);
749 STRING1, _("Archive"),
750 STRING2, page->name, -1);
752 gtk_list_store_append(list, &iter);
755 STRING1, _("Archive format"),
756 STRING2, format, -1);
759 gtk_list_store_append(list, &iter);
762 STRING1, _("Compression method"),
763 STRING2, method, -1);
766 gtk_list_store_append(list, &iter);
767 msg = g_strdup_printf("%d", (page->md5) ? page->files * 2 : page->files);
770 STRING1, _("Number of files"),
774 gtk_list_store_append(list, &iter);
775 msg = g_strdup_printf("%d byte(s)", (guint) st.st_size);
778 STRING1, _("Archive Size"),
782 gtk_list_store_append(list, &iter);
783 msg = g_strdup_printf("%d byte(s)", page->total_size);
786 STRING1, _("Folder Size"),
790 gtk_list_store_append(list, &iter);
791 msg = g_strdup_printf("%d%%",
792 (guint)((st.st_size * 100) / page->total_size));
795 STRING1, _("Compression level"),
799 gtk_list_store_append(list, &iter);
800 msg = g_strdup_printf("%s", (page->md5) ? _("Yes") : _("No"));
803 STRING1, _("MD5 checksum"),
807 gtk_list_store_append(list, &iter);
808 msg = g_strdup_printf("%s", (page->rename) ? _("Yes") : _("No"));
811 STRING1, _("Descriptive names"),
815 gtk_list_store_append(list, &iter);
816 msg = g_strdup_printf("%s", (page->unlink) ? _("Yes") : _("No"));
819 STRING1, _("Delete selected files"),
823 msg = g_strdup(gtk_entry_get_text(GTK_ENTRY(page->isoDate)));
825 gtk_list_store_append(list, &iter);
828 STRING1, _("Select mails before"),
833 gtk_window_set_default_size(GTK_WINDOW(dialog), 320, 260);
835 gtk_widget_show_all(dialog);
838 static void archiver_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
839 struct ArchivePage* page = (struct ArchivePage *) data;
840 gboolean result = FALSE;
843 case GTK_RESPONSE_ACCEPT:
844 debug_print("User chose OK\n");
845 page->response = TRUE;
848 debug_print("User chose CANCEL\n");
849 page->response = FALSE;
850 archiver_gtk_done(page, widget);
853 debug_print("Settings:\naction: %d\n", page->response);
854 if (page->response) {
855 debug_print("Settings:\nfolder: %s\nname: %s\n",
856 (page->path) ? page->path : "(null)",
857 (page->name) ? page->name : "(null)");
858 result = archiver_save_files(page);
859 debug_print("Result->archiver_save_files: %d\n", result);
860 if (progress->progress_dialog &&
861 GTK_IS_WIDGET(progress->progress_dialog))
862 gtk_widget_destroy(progress->progress_dialog);
863 if (result && ! page->cancelled) {
865 archive_free_file_list(page->md5, page->rename);
866 archiver_gtk_done(page, widget);
869 if (page->cancelled) {
870 archiver_gtk_done(page, widget);
876 static void foldersel_cb(GtkWidget *widget, gpointer data)
881 struct ArchivePage* page = (struct ArchivePage *) data;
883 item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
884 if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
885 gtk_editable_delete_text(GTK_EDITABLE(page->folder), 0, -1);
886 gtk_editable_insert_text(GTK_EDITABLE(page->folder),
887 item_id, strlen(item_id), &newpos);
888 page->path = g_strdup(item_id);
891 debug_print("Folder to archive: %s\n",
892 gtk_entry_get_text(GTK_ENTRY(page->folder)));
895 static void filesel_cb(GtkWidget *widget, gpointer data)
900 const gchar* homedir;
901 struct ArchivePage* page = (struct ArchivePage *) data;
903 dialog = gtk_file_chooser_dialog_new(
904 _("Select file name for archive [suffix should reflect archive like .tgz]"),
906 GTK_FILE_CHOOSER_ACTION_SAVE,
907 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
908 GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
910 homedir = g_getenv("HOME");
912 homedir = g_get_home_dir();
914 if (archiver_prefs.save_folder)
915 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
916 archiver_prefs.save_folder);
918 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), homedir);
919 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY) {
920 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
922 gtk_editable_delete_text(GTK_EDITABLE(page->file), 0, -1);
923 gtk_editable_insert_text(GTK_EDITABLE(page->file),
924 file, strlen(file), &newpos);
925 page->name = g_strdup(file);
927 page->force_overwrite = TRUE;
930 gtk_widget_destroy(dialog);
931 debug_print("Name for archive: %s\n",
932 gtk_entry_get_text(GTK_ENTRY(page->file)));
935 void set_progress_file_label(const gchar* file) {
936 debug_print("IsLabel: %s, Update label: %s\n",
937 GTK_IS_WIDGET(progress->file_label)? "Yes" : "No", file);
938 if (GTK_IS_WIDGET(progress->file_label))
939 gtk_label_set_text(GTK_LABEL(progress->file_label), file);
942 void set_progress_print_all(guint fraction, guint total, guint step) {
945 if (GTK_IS_WIDGET(progress->progress)) {
946 if ((fraction - progress->position) % step == 0) {
947 debug_print("frac: %d, total: %d, step: %d, prog->pos: %d\n",
948 fraction, total, step, progress->position);
949 gtk_progress_bar_set_fraction(
950 GTK_PROGRESS_BAR(progress->progress),
951 (total == 0) ? 0 : (gfloat)fraction / (gfloat)total);
952 text_count = g_strdup_printf(_("%ld of %ld"),
953 (long) fraction, (long) total);
954 gtk_progress_bar_set_text(
955 GTK_PROGRESS_BAR(progress->progress), text_count);
957 progress->position = fraction;
963 void archiver_gtk_show() {
968 GtkWidget* folder_label;
969 GtkWidget* folder_select;
970 GtkWidget* file_label;
971 GtkWidget* file_select;
972 GtkWidget* zip_radio_btn;
973 GtkWidget* bzip_radio_btn;
975 GtkWidget* compress_radio_btn;
977 GtkWidget* no_radio_btn;
978 GtkWidget* shar_radio_btn;
979 GtkWidget* pax_radio_btn;
980 GtkWidget* cpio_radio_btn;
981 GtkWidget* tar_radio_btn;
982 struct ArchivePage* page;
983 MainWindow* mainwin = mainwindow_get_mainwindow();
985 /*debug_set_mode(TRUE);*/
986 progress = init_progress();
988 page = init_archive_page();
990 dialog = gtk_dialog_new_with_buttons (
992 GTK_WINDOW(mainwin->window),
993 GTK_DIALOG_DESTROY_WITH_PARENT,
1003 G_CALLBACK(archiver_dialog_cb),
1006 frame = gtk_frame_new(_("Enter Archiver arguments"));
1007 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1008 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1009 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
1011 vbox1 = gtk_vbox_new (FALSE, 4);
1012 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 4);
1013 gtk_container_add(GTK_CONTAINER(frame), vbox1);
1015 hbox1 = gtk_hbox_new(FALSE, 4);
1016 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1017 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1019 folder_label = gtk_label_new(_("Folder to archive"));
1020 gtk_box_pack_start(GTK_BOX(hbox1), folder_label, FALSE, FALSE, 0);
1022 page->folder = gtk_entry_new();
1023 gtk_widget_set_name(page->folder, "folder");
1024 gtk_box_pack_start(GTK_BOX(hbox1), page->folder, TRUE, TRUE, 0);
1025 CLAWS_SET_TIP(page->folder,
1026 _("Folder which is the root of the archive"));
1028 folder_select = gtkut_get_browse_directory_btn(_("_Browse"));
1029 gtk_box_pack_start(GTK_BOX(hbox1), folder_select, FALSE, FALSE, 0);
1030 CLAWS_SET_TIP(folder_select,
1031 _("Click this button to select a folder which is to be root of the archive"));
1033 hbox1 = gtk_hbox_new(FALSE, 4);
1034 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1035 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1037 file_label = gtk_label_new(_("Name for archive"));
1038 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1040 page->file = gtk_entry_new();
1041 gtk_widget_set_name(page->file, "file");
1042 gtk_box_pack_start(GTK_BOX(hbox1), page->file, TRUE, TRUE, 0);
1043 CLAWS_SET_TIP(page->file, _("Archive location and name"));
1045 file_select = gtkut_get_browse_directory_btn(_("_Select"));
1046 gtk_box_pack_start(GTK_BOX(hbox1), file_select, FALSE, FALSE, 0);
1047 CLAWS_SET_TIP(file_select,
1048 _("Click this button to select a name and location for the archive"));
1050 frame = gtk_frame_new(_("Choose compression"));
1051 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1052 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1053 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1055 hbox1 = gtk_hbox_new(FALSE, 4);
1056 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1057 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1059 zip_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_ZIP");
1060 gtk_widget_set_name(zip_radio_btn, "ZIP");
1061 gtk_box_pack_start(GTK_BOX(hbox1), zip_radio_btn, FALSE, FALSE, 0);
1062 CLAWS_SET_TIP(zip_radio_btn,
1063 _("Choose this option to use ZIP compression for the archive"));
1065 bzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1066 GTK_RADIO_BUTTON(zip_radio_btn), "BZIP_2");
1067 gtk_widget_set_name(bzip_radio_btn, "BZIP");
1068 gtk_box_pack_start(GTK_BOX(hbox1), bzip_radio_btn, FALSE, FALSE, 0);
1069 CLAWS_SET_TIP(bzip_radio_btn,
1070 _("Choose this option to use BZIP2 compression for the archive"));
1073 compress_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1074 GTK_RADIO_BUTTON(zip_radio_btn), "Com_press");
1075 gtk_widget_set_name(compress_radio_btn, "COMPRESS");
1076 gtk_box_pack_start(GTK_BOX(hbox1), compress_radio_btn, FALSE, FALSE, 0);
1077 CLAWS_SET_TIP(compress_radio_btn,
1078 _("Choose this to use Compress compression for your archive"));
1081 no_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1082 GTK_RADIO_BUTTON(zip_radio_btn), _("_None"));
1083 gtk_widget_set_name(no_radio_btn, "NONE");
1084 gtk_box_pack_start(GTK_BOX(hbox1), no_radio_btn, FALSE, FALSE, 0);
1085 CLAWS_SET_TIP(no_radio_btn,
1086 _("Choose this option to disable compression for the archive"));
1088 page->compress_methods =
1089 gtk_radio_button_get_group(GTK_RADIO_BUTTON(zip_radio_btn));
1091 switch (archiver_prefs.compression) {
1092 case COMPRESSION_ZIP:
1093 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(zip_radio_btn), TRUE);
1095 case COMPRESSION_BZIP:
1096 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bzip_radio_btn), TRUE);
1099 case COMPRESSION_COMPRESS:
1100 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compress_radio_btn), TRUE);
1103 case COMPRESSION_NONE:
1104 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(no_radio_btn), TRUE);
1108 frame = gtk_frame_new(_("Choose format"));
1109 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1110 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1111 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1113 hbox1 = gtk_hbox_new(FALSE, 4);
1114 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1115 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1117 tar_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_TAR");
1118 gtk_widget_set_name(tar_radio_btn, "TAR");
1119 gtk_box_pack_start(GTK_BOX(hbox1), tar_radio_btn, FALSE, FALSE, 0);
1120 CLAWS_SET_TIP(tar_radio_btn,
1121 _("Choose this option to use TAR as format for the archive"));
1123 shar_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1124 GTK_RADIO_BUTTON(tar_radio_btn), "S_HAR");
1125 gtk_widget_set_name(shar_radio_btn, "SHAR");
1126 gtk_box_pack_start(GTK_BOX(hbox1), shar_radio_btn, FALSE, FALSE, 0);
1127 CLAWS_SET_TIP(shar_radio_btn,
1128 _("Choose this to use SHAR as format for the archive"));
1130 cpio_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1131 GTK_RADIO_BUTTON(tar_radio_btn), "CP_IO");
1132 gtk_widget_set_name(cpio_radio_btn, "CPIO");
1133 gtk_box_pack_start(GTK_BOX(hbox1), cpio_radio_btn, FALSE, FALSE, 0);
1134 CLAWS_SET_TIP(cpio_radio_btn,
1135 _("Choose this option to use CPIO as format for the archive"));
1137 pax_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1138 GTK_RADIO_BUTTON(tar_radio_btn), "PA_X");
1139 gtk_widget_set_name(pax_radio_btn, "PAX");
1140 gtk_box_pack_start(GTK_BOX(hbox1), pax_radio_btn, FALSE, FALSE, 0);
1141 CLAWS_SET_TIP(pax_radio_btn,
1142 _("Choose this option to use PAX as format for the archive"));
1144 page->archive_formats =
1145 gtk_radio_button_get_group(GTK_RADIO_BUTTON(tar_radio_btn));
1147 switch (archiver_prefs.format) {
1149 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tar_radio_btn), TRUE);
1152 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shar_radio_btn), TRUE);
1155 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cpio_radio_btn), TRUE);
1158 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pax_radio_btn), TRUE);
1162 frame = gtk_frame_new(_("Miscellaneous options"));
1163 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1164 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1165 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1167 hbox1 = gtk_hbox_new(FALSE, 4);
1168 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1169 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1171 page->recursive = gtk_check_button_new_with_mnemonic(_("_Recursive"));
1172 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->recursive), archiver_prefs.recursive);
1173 gtk_box_pack_start(GTK_BOX(hbox1), page->recursive, FALSE, FALSE, 0);
1174 CLAWS_SET_TIP(page->recursive,
1175 _("Choose this option to include subfolders in the archive"));
1177 page->md5sum = gtk_check_button_new_with_mnemonic(_("_MD5sum"));
1178 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->md5sum), archiver_prefs.md5sum);
1179 gtk_box_pack_start(GTK_BOX(hbox1), page->md5sum, FALSE, FALSE, 0);
1180 CLAWS_SET_TIP(page->md5sum,
1181 _("Choose this option to add MD5 checksums for each file in the archive.\n"
1182 "Be aware though, that this dramatically increases the time it\n"
1183 "will take to create the archive"));
1185 page->rename_files = gtk_check_button_new_with_mnemonic(_("R_ename"));
1186 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->rename_files), archiver_prefs.rename);
1187 gtk_box_pack_start(GTK_BOX(hbox1), page->rename_files, FALSE, FALSE, 0);
1188 CLAWS_SET_TIP(page->rename_files,
1189 _("Choose this option to use descriptive names for each file in the archive.\n"
1190 "The naming scheme: date_from@to@subject.\n"
1191 "Names will be truncated to max 96 characters"));
1193 page->unlink_files = gtk_check_button_new_with_mnemonic(_("_Delete"));
1194 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->unlink_files), archiver_prefs.unlink);
1195 gtk_box_pack_start(GTK_BOX(hbox1), page->unlink_files, FALSE, FALSE, 0);
1196 CLAWS_SET_TIP(page->unlink_files,
1197 _("Choose this option to delete mails after archiving\n"
1198 "At this point only handles IMAP4, Local mbox and POP3"));
1201 frame = gtk_frame_new(_("Selection options"));
1202 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1203 gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1204 gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1206 hbox1 = gtk_hbox_new(FALSE, 4);
1207 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1208 gtk_container_add(GTK_CONTAINER(frame), hbox1);
1210 file_label = gtk_label_new(_("Select mails before"));
1211 gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1213 page->isoDate = gtk_entry_new();
1214 gtk_widget_set_name(page->isoDate, "isoDate");
1215 gtk_box_pack_start(GTK_BOX(hbox1), page->isoDate, TRUE, TRUE, 0);
1216 CLAWS_SET_TIP(page->isoDate,
1217 _("Select emails before a certain date\n"
1218 "Date must comply to ISO-8601 [YYYY-MM-DD]"));
1220 g_signal_connect(G_OBJECT(folder_select), "clicked",
1221 G_CALLBACK(foldersel_cb), page);
1222 g_signal_connect(G_OBJECT(file_select), "clicked",
1223 G_CALLBACK(filesel_cb), page);
1224 g_signal_connect(G_OBJECT(page->folder), "activate",
1225 G_CALLBACK(entry_change_cb), page);
1226 g_signal_connect(G_OBJECT(page->file), "activate",
1227 G_CALLBACK(entry_change_cb), page);
1229 gtk_widget_show_all(dialog);
1232 void archiver_gtk_done(struct ArchivePage* page, GtkWidget* widget) {
1233 dispose_archive_page(page);
1235 gtk_widget_destroy(widget);
1236 /*debug_set_mode(FALSE);*/