Remove unchecked realloc which is unnecessary
[claws.git] / src / plugins / archive / archiver_gtk.c
1 /* vim: set textwidth=80 tabstop=4 */
2
3 /*
4  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
5  * Copyright (C) 1999-2008 Michael Rasmussen and the Claws Mail Team
6  *
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.
11  ii*
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.
16  *
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/>.
19  * 
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #include "claws-features.h"
25 #endif
26
27 #include <glib.h>
28 #include <glib/gi18n.h>
29
30 #include "defs.h"
31
32 #include <gtk/gtk.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <errno.h>
37
38 #include "gtk/gtkutils.h"
39 #include "common/claws.h"
40 #include "common/version.h"
41 #include "common/md5.h"
42 #include "plugin.h"
43 #include "mainwindow.h"
44 #include "utils.h"
45 #include "prefs.h"
46 #include "folder.h"
47 #include "foldersel.h"
48 #include "procmsg.h"
49 #include "procheader.h"
50 #include "libarchive_archive.h"
51 #include "archiver.h"
52 #include "archiver_prefs.h"
53
54 typedef struct _progress_widget progress_widget;
55 struct _progress_widget {
56         GtkWidget*      progress_dialog;
57         GtkWidget*      frame;
58         GtkWidget*      vbox1;
59         GtkWidget*      hbox1;
60         GtkWidget*      add_label;
61         GtkWidget*      file_label;
62         GtkWidget*      progress;
63         guint           position;
64 };
65
66 typedef enum {
67     A_FILE_OK           = 1 << 0,
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
73 } AFileTest;
74
75 static progress_widget* progress = NULL;
76
77 static progress_widget* init_progress() {
78         progress_widget* ptr = malloc(sizeof(*ptr));
79
80         debug_print("creating progress struct\n");
81         ptr->progress_dialog = NULL;
82         ptr->frame = NULL;
83         ptr->vbox1 = NULL;
84         ptr->hbox1 = NULL;
85         ptr->add_label = NULL;
86         ptr->file_label = NULL;
87         ptr->progress = NULL;
88         ptr->position = 0;
89
90         return ptr;
91 }
92
93 static void progress_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
94         struct ArchivePage* page = (struct ArchivePage *) data;
95
96         debug_print("Cancel operation\n");
97         stop_archiving();
98         page->cancelled = TRUE;
99         archive_free_file_list(page->md5, page->rename);
100         gtk_widget_destroy(widget);
101 }
102
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();
106
107         progress->position = 0;
108         progress->progress_dialog = gtk_dialog_new_with_buttons (
109                                 title,
110                                 GTK_WINDOW(mainwin->window),
111                                 GTK_DIALOG_DESTROY_WITH_PARENT,
112                                 GTK_STOCK_CANCEL,
113                                 GTK_RESPONSE_CANCEL,
114                                 NULL);
115
116         g_signal_connect (
117                                 progress->progress_dialog,
118                                 "response",
119                                 G_CALLBACK(progress_dialog_cb),
120                                 page);
121
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);
128
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);
132         
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);
137
138         progress->add_label = gtk_label_new(_("Archiving:"));
139         gtk_box_pack_start(GTK_BOX(progress->hbox1),
140                                         progress->add_label, FALSE, FALSE, 0);
141
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);
147
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);
152
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);
157
158         gtk_window_set_default_size(GTK_WINDOW(progress->progress_dialog), 400, 80);
159         gtk_widget_show_all(progress->progress_dialog);
160 }
161
162 static struct ArchivePage* init_archive_page() {
163         struct ArchivePage* page = malloc(sizeof(struct ArchivePage));
164
165         debug_print("creating ArchivePage\n");
166         page->path = NULL;
167         page->name = NULL;
168         page->file = NULL;
169         page->folder = NULL;
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;
176         page->md5 = FALSE;
177         page->md5sum = NULL;
178         page->rename = FALSE;
179         page->rename_files = NULL;
180         page->isoDate = NULL;
181         page->unlink_files = NULL;
182         page->unlink = FALSE;
183
184         return page;
185 }
186
187 static void dispose_archive_page(struct ArchivePage* page) {
188         debug_print("freeing ArchivePage\n");
189         if (page->path)
190                 g_free(page->path);
191         page->path = NULL;
192         if (page->name)
193                 g_free(page->name);
194         page->name = NULL;
195         g_free(page);
196 }
197
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));
201         
202         if (! page->path && *path != '\0') {
203                 debug_print("page->path: (NULL) -> %s\n", path);
204                 page->path = g_strdup(path);
205         }
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);
210         }
211         
212         return (page->path && page->name) ? TRUE : FALSE;
213 }
214
215 static gboolean valid_file_name(gchar* file) {
216         int i;
217
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]))
220                         return FALSE;
221         }
222         return TRUE;
223 }
224
225 static COMPRESS_METHOD get_compress_method(GSList* btn) {
226         const gchar* name;
227
228         while (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");
233                                 return ZIP;
234                         }
235                         else if (strcmp("BZIP", name) == 0) {
236                                 debug_print("BZIP2 compression enabled\n");
237                                 return BZIP2;
238                         }
239             else if (strcmp("COMPRESS", name) == 0) {
240                                 debug_print("COMPRESS compression enabled\n");
241                                 return COMPRESS;
242                         }
243                         else if (strcmp("NONE", name) == 0) {
244                                 debug_print("Compression disabled\n");
245                                 return NO_COMPRESS;
246                         }
247                 }
248                 btn = g_slist_next(btn);
249         }
250         return NO_COMPRESS;
251 }
252
253 static ARCHIVE_FORMAT get_archive_format(GSList* btn) {
254         const gchar* name;
255
256         while (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");
261                                 return TAR;
262                         }
263                         else if (strcmp("SHAR", name) == 0) {
264                                 debug_print("SHAR archive enabled\n");
265                                 return SHAR;
266                         }
267                         else if (strcmp("PAX", name) == 0) {
268                                 debug_print("PAX archive enabled\n");
269                                 return PAX;
270                         }
271                         else if (strcmp("CPIO", name) == 0) {
272                                 debug_print("CPIO archive enabled\n");
273                                 return CPIO;
274                         }
275                 }
276                 btn = g_slist_next(btn);
277         }
278         return NO_FORMAT;
279 }
280
281 static void create_md5sum(const gchar* file, const gchar* md5_file) {
282         int fd;
283         gchar* text = NULL;
284         gchar* md5sum = malloc(33);
285
286         debug_print("Creating md5sum file: %s\n", md5_file);
287         if (md5_hex_digest_file(md5sum, (const unsigned char *) file) == -1)
288                 return;
289         debug_print("md5sum: %s\n", md5sum);
290         if ((fd = 
291                 open(md5_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1)
292                 return;
293         text = g_strrstr_len(file, strlen(file), "/");
294         if (text) {
295                 text++;
296                 text = g_strdup_printf("%s  %s\n", md5sum, text);
297         }
298         else
299                 text = g_strdup_printf("%s  %s\n", md5sum, file);
300         g_free(md5sum);
301         debug_print("md5sum: %s\n", text);
302         if (write(fd, text, strlen(text)) < 0)
303                 perror("write");
304         close(fd);
305         g_free(text);
306 }
307
308 static gchar* descriptive_file_name(
309                 struct ArchivePage* page, const gchar* file, MsgInfo *msginfo) {
310         gchar* new_file = NULL;
311         gchar *name, *p, *to, *from, *date, *subject;
312
313         debug_print("renaming file\n");
314         p = g_strrstr_len(file, strlen(file), "/");
315         p = g_strndup(file, p - file);
316         if (!p)
317                 return NULL;
318         if (msginfo->to) {
319                 to = g_strdup(msginfo->to);
320                 extract_address(to);
321         }
322         else
323                 to = g_strdup("");
324         if (msginfo->from) {
325                 from = g_strdup(msginfo->from);
326                 extract_address(from);
327         }
328         else
329                 from = g_strdup("");
330         if (msginfo->date) {
331                 date = g_strdup(msginfo->date);
332                 subst_for_shellsafe_filename(date);
333                 /* if not on windows we need to subst some more */
334                 subst_chars(date, ":", '_');
335         }
336         else
337                 date = g_strdup("");
338         if (msginfo->subject) {
339                 subject = g_strdup(msginfo->subject);
340                 subst_for_shellsafe_filename(subject);
341                 /* if not on windows we need to subst some more */
342                 subst_chars(subject, ":", '_');
343         }
344         else
345                 subject = g_strdup("");
346         name = g_strdup_printf("%s_%s@%s@%s", date, from, to, subject);
347         /* ensure file name is not larger than 96 chars (max file name size
348          * is 100 chars but reserve for .md5)
349          */
350         if (strlen(name) > 96)
351                 name[96] = 0;
352         
353         new_file = g_strconcat(p, "/", name, NULL);
354
355         g_free(name);
356         g_free(p);
357         g_free(to);
358         g_free(from);
359         g_free(date);
360         g_free(subject);
361
362         debug_print("New_file: %s\n", new_file);
363         if (link(file, new_file) != 0) {
364                 if (errno != EEXIST) {
365                         perror("link");
366                         g_free(new_file);
367                         new_file = g_strdup(file);
368                         page->rename = FALSE;
369                 }
370         }
371
372         return new_file;
373 }
374
375 static void walk_folder(struct ArchivePage* page, FolderItem* item,
376                                 gboolean recursive) {
377         FolderItem* child;
378         GSList *msglist;
379         GSList *cur;
380         MsgInfo *msginfo;
381         GNode* node;
382         int count;
383         gchar* md5_file = NULL;
384         gchar* text = NULL;
385         gchar* file = NULL;
386         MsgTrash* msg_trash = NULL;
387         const gchar* date = NULL;
388
389         if (recursive && ! page->cancelled) {
390                 debug_print("Scanning recursive\n");
391                 node = item->node->children;
392                 while(node && ! page->cancelled) {
393                         debug_print("Number of nodes: %d\n", g_node_n_children(node));
394                         if (node->data) {
395                                 child = FOLDER_ITEM(node->data);
396                                 debug_print("new node: %d messages\n", child->total_msgs);
397                                 walk_folder(page, child, recursive);
398                         }
399                         node = node->next;
400                 }
401         }
402         if (! page->cancelled) {
403                 date = gtk_entry_get_text(GTK_ENTRY(page->isoDate));
404                 debug_print("cut-off date: %s\n", date);
405                 count = 0;
406                 page->files += item->total_msgs;
407                 msglist = folder_item_get_msg_list(item);
408                 msg_trash = new_msg_trash(item);
409                 for (cur = msglist; cur && ! page->cancelled; cur = cur->next) {
410                         msginfo = (MsgInfo *) cur->data;
411                         debug_print("%s_%s_%s_%s\n",
412                                 msginfo->date, msginfo->to, msginfo->from, msginfo->subject);
413                         file = folder_item_fetch_msg(item, msginfo->msgnum);
414                         if (date && strlen(date) > 0 && !before_date(msginfo->date_t, date)) {
415                             page->files--;
416                             continue;
417                         }
418                         page->total_size += msginfo->size;
419                         /*debug_print("Processing: %s\n", file);*/
420                         if (file) {
421                                 if (page->unlink) {
422                                     archive_add_msg_mark(msg_trash, msginfo);
423                                 }
424                                 if (page->rename) {
425                                         file = descriptive_file_name(page, file, msginfo);
426                                         if (!file) {
427                                                 /* Could not create a descriptive name */
428                                             file = folder_item_fetch_msg(item, msginfo->msgnum);
429                                         }
430                                 }
431                                 if (page->md5) {
432                                         md5_file = g_strdup_printf("%s.md5", file);
433                                         create_md5sum(file, md5_file);
434                                         archive_add_file(md5_file);
435                                         g_free(md5_file);
436                                 }
437                                 archive_add_file(file);
438                                 if (page->rename)
439                                         g_free(file);
440                         }
441                         if (count % 350 == 0) {
442                                 debug_print("pulse progressbar\n");
443                                 text = g_strdup_printf(
444                                                         "Scanning %s: %d files", item->name, count);
445                                 gtk_progress_bar_set_text(
446                                                 GTK_PROGRESS_BAR(progress->progress), text);
447                                 g_free(text);
448                                 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress->progress));
449                                 GTK_EVENTS_FLUSH();
450                         }
451                         count++;
452                 }
453                 procmsg_msg_list_free(msglist);
454         }
455 }
456
457 static AFileTest file_is_writeable(struct ArchivePage* page) {
458     int fd;
459
460     if (g_file_test(page->name, G_FILE_TEST_EXISTS) &&
461                                 ! page->force_overwrite)
462         return A_FILE_EXISTS;
463     if (g_file_test(page->name, G_FILE_TEST_IS_SYMLINK))
464         return A_FILE_IS_LINK;
465     if (g_file_test(page->name, G_FILE_TEST_IS_DIR))
466         return A_FILE_IS_DIR;
467     if ((fd = open(page->name, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
468         switch (errno) {
469             case EACCES: return A_FILE_NO_WRITE;
470             case EEXIST: return A_FILE_OK;
471             default:     return A_FILE_UNKNOWN;
472         }
473     }
474     else {
475         close(fd);
476         claws_unlink(page->name);
477     }
478     return A_FILE_OK;
479 }
480
481 static gboolean archiver_save_files(struct ArchivePage* page) {
482         GtkWidget* dialog;
483         MainWindow* mainwin = mainwindow_get_mainwindow();
484         FolderItem* item;
485         COMPRESS_METHOD method;
486         ARCHIVE_FORMAT format;
487         gboolean recursive;
488         int response;
489         guint orig_file;
490         GSList* list = NULL;
491         const gchar* res = NULL;
492         AFileTest perm;
493         gchar* msg = NULL;
494
495         if (page->path == NULL || page->name == NULL) {
496                 /* Test if page->file and page->folder has uncommitted information */
497                 if (! uncommitted_entry_info(page)) {
498                         dialog = gtk_message_dialog_new(
499                                 GTK_WINDOW(mainwin->window),
500                                 GTK_DIALOG_DESTROY_WITH_PARENT,
501                                 GTK_MESSAGE_ERROR,
502                                 GTK_BUTTONS_CLOSE,
503                                 _("Folder and archive must be selected"));
504                         gtk_dialog_run (GTK_DIALOG (dialog));
505                         gtk_widget_destroy (dialog);
506                         return FALSE;
507                 }
508         }
509         if ((perm = file_is_writeable(page)) != A_FILE_OK) {
510             switch (perm) {
511                 case A_FILE_EXISTS:
512                     msg = g_strdup_printf(_("%s: Exists. Continue anyway?"), page->name);
513                     break;
514                 case A_FILE_IS_LINK:
515                     msg = g_strdup_printf(_("%s: Is a link. Cannot continue"), page->name);
516                     break;
517                  case A_FILE_IS_DIR:
518                      msg = g_strdup_printf(_("%s: Is a directory. Cannot continue"), page->name);
519                     break;
520                 case A_FILE_NO_WRITE:
521                      msg = g_strdup_printf(_("%s: Missing permissions. Cannot continue"), page->name);
522                     break;
523                 case A_FILE_UNKNOWN:
524                     msg = g_strdup_printf(_("%s: Unknown error. Cannot continue"), page->name);
525                     break;
526                 default: break;
527             }
528             if (perm == A_FILE_EXISTS) {
529                 dialog = gtk_message_dialog_new(
530                         GTK_WINDOW(mainwin->window),
531                         GTK_DIALOG_DESTROY_WITH_PARENT,
532                         GTK_MESSAGE_WARNING,
533                         GTK_BUTTONS_OK_CANCEL,
534                         "%s", msg);
535                 response = gtk_dialog_run(GTK_DIALOG (dialog));
536                 gtk_widget_destroy(dialog);
537                 g_free(msg);
538                 if (response == GTK_RESPONSE_CANCEL) {
539                         return FALSE;
540                 }
541             }
542             else {
543                 dialog = gtk_message_dialog_new(
544                         GTK_WINDOW(mainwin->window),
545                         GTK_DIALOG_DESTROY_WITH_PARENT,
546                         GTK_MESSAGE_ERROR,
547                         GTK_BUTTONS_OK,
548                         "%s", msg);
549                 response = gtk_dialog_run(GTK_DIALOG (dialog));
550                 gtk_widget_destroy(dialog);
551                 g_free(msg);
552                 return FALSE;
553             }
554         }
555         if (! valid_file_name(page->name)) {
556                 dialog = gtk_message_dialog_new(
557                         GTK_WINDOW(mainwin->window),
558                         GTK_DIALOG_DESTROY_WITH_PARENT,
559                         GTK_MESSAGE_ERROR,
560                         GTK_BUTTONS_CLOSE,
561                         _("Not a valid file name:\n%s."),
562                         page->name);
563                 gtk_dialog_run (GTK_DIALOG (dialog));
564                 gtk_widget_destroy (dialog);
565                 return FALSE;
566         }
567         item = folder_find_item_from_identifier(page->path);
568         if (! item) {
569                 dialog = gtk_message_dialog_new(
570                         GTK_WINDOW(mainwin->window),
571                         GTK_DIALOG_DESTROY_WITH_PARENT,
572                         GTK_MESSAGE_ERROR,
573                         GTK_BUTTONS_CLOSE,
574                         _("Not a valid Claws Mail folder:\n%s."),
575                         page->path);
576                 gtk_dialog_run (GTK_DIALOG (dialog));
577                 gtk_widget_destroy (dialog);
578                 return FALSE;
579         }
580         page->files = 0;
581         page->total_size = 0;
582         page->rename = gtk_toggle_button_get_active(
583                         GTK_TOGGLE_BUTTON(page->rename_files));
584         recursive = gtk_toggle_button_get_active(
585                                         GTK_TOGGLE_BUTTON(page->recursive));
586         page->md5 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->md5sum));
587         page->unlink = gtk_toggle_button_get_active(
588                         GTK_TOGGLE_BUTTON(page->unlink_files));
589         create_progress_dialog(page);
590         walk_folder(page, item, recursive);
591         if (page->cancelled)
592                 return FALSE;
593         list = archive_get_file_list();
594         orig_file = (page->md5) ? page->files * 2 : page->files;
595         debug_print("md5: %d, orig: %d, md5: %d\n", 
596                                         page->md5, page->files, orig_file);
597         if (orig_file != g_slist_length(list)) {
598                 dialog = gtk_message_dialog_new(
599                                 GTK_WINDOW(mainwin->window),
600                                 GTK_DIALOG_DESTROY_WITH_PARENT,
601                                 GTK_MESSAGE_WARNING,
602                                 GTK_BUTTONS_OK_CANCEL,
603                                 _("Adding files in folder failed\n"
604                                   "Files in folder: %d\n"
605                                   "Files in list:   %d\n"
606                                   "\nContinue anyway?"),
607                                 orig_file, g_slist_length(list));
608                 response = gtk_dialog_run(GTK_DIALOG (dialog));
609                 gtk_widget_destroy(dialog);
610                 if (response == GTK_RESPONSE_CANCEL) {
611                         archive_free_file_list(page->md5, page->rename);
612                         return FALSE;
613                 }
614         }
615         method = get_compress_method(page->compress_methods);
616         format = get_archive_format(page->archive_formats);
617         if ((res = archive_create(page->name, list, method, format)) != NULL) {
618                 dialog = gtk_message_dialog_new(
619                         GTK_WINDOW(mainwin->window),
620                         GTK_DIALOG_DESTROY_WITH_PARENT,
621                         GTK_MESSAGE_ERROR,
622                         GTK_BUTTONS_CLOSE,
623                         "%s", res);
624                 gtk_dialog_run (GTK_DIALOG (dialog));
625                 gtk_widget_destroy (dialog);
626                 archive_free_file_list(page->md5, page->rename);
627                 return FALSE;
628         }
629         if (page->unlink) {
630             archive_free_archived_files();
631         }
632         return TRUE;
633 }
634
635 static void entry_change_cb(GtkWidget* widget, gpointer data) {
636         const gchar* name = gtk_widget_get_name(widget);
637         struct ArchivePage* page = (struct ArchivePage *) data;
638
639         if (strcmp("folder", name) == 0) {
640                 page->path = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
641                 debug_print("page->folder = %s\n", page->path);
642         }
643         else if (strcmp("file", name) == 0) {
644                 page->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
645                 page->force_overwrite = FALSE;
646                 debug_print("page->name = %s\n", page->name);
647         }
648 }
649
650 static void show_result(struct ArchivePage* page) {
651         
652         enum {
653                 STRING1,
654                 STRING2,
655                 N_COLUMNS
656         };
657
658         GStatBuf st;
659         GtkListStore* list;
660         GtkTreeIter iter;
661         GtkTreeView* view;
662         GtkTreeViewColumn* header;
663         GtkCellRenderer* renderer;
664         GtkWidget* dialog;
665         gchar* msg = NULL;
666         gchar* method = NULL;
667         gchar* format = NULL;
668
669         MainWindow* mainwin = mainwindow_get_mainwindow();
670
671         switch (get_compress_method(page->compress_methods)) {
672                 case ZIP:
673                         method = g_strdup("ZIP");
674                         break;
675                 case BZIP2:
676                         method = g_strdup("BZIP2");
677                         break;
678         case COMPRESS:
679                         method = g_strdup("Compress");
680                         break;
681                 case NO_COMPRESS:
682                         method = g_strdup("No Compression");
683                         break;
684         }
685         
686         switch (get_archive_format(page->archive_formats)) {
687                 case TAR:
688                         format = g_strdup("TAR");
689                         break;
690                 case SHAR:
691                         format = g_strdup("SHAR");
692                         break;
693                 case PAX:
694                         format = g_strdup("PAX");
695                         break;
696                 case CPIO:
697                         format = g_strdup("CPIO");
698                         break;
699                 case NO_FORMAT:
700                         format = g_strdup("NO FORMAT");
701         }
702
703         g_stat(page->name, &st);
704         dialog = gtk_dialog_new_with_buttons(
705                         _("Archive result"),
706                         GTK_WINDOW(mainwin->window),
707                         GTK_DIALOG_DESTROY_WITH_PARENT,
708                         GTK_STOCK_OK,
709                         GTK_RESPONSE_NONE,
710                         NULL);
711         g_signal_connect_swapped(
712                                 dialog,
713                                 "response",
714                                 G_CALLBACK(gtk_widget_destroy),
715                                 dialog);
716
717         list = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
718         
719         view = g_object_new(
720                                 GTK_TYPE_TREE_VIEW,
721                                 "model", list,
722                                 "rules-hint", FALSE,
723                                 "headers-clickable", FALSE,
724                                 "reorderable", FALSE,
725                                 "enable-search", FALSE,
726                                 NULL);
727
728         renderer = gtk_cell_renderer_text_new();
729
730         header = gtk_tree_view_column_new_with_attributes(
731                                 _("Attributes"), renderer, "text", STRING1, NULL);
732         gtk_tree_view_append_column(view, header);
733
734         header = gtk_tree_view_column_new_with_attributes(
735                                 _("Values"), renderer, "text", STRING2, NULL);
736         gtk_tree_view_append_column(view, header);
737
738         gtk_container_add(
739                                 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(view));
740
741         gtk_list_store_append(list, &iter);
742         gtk_list_store_set(
743                                 list, &iter,
744                                 STRING1, _("Archive"),
745                                 STRING2, page->name, -1);
746
747         gtk_list_store_append(list, &iter);
748         gtk_list_store_set(
749                                 list, &iter,
750                                 STRING1, _("Archive format"),
751                                 STRING2, format, -1);
752         g_free(format);
753
754         gtk_list_store_append(list, &iter);
755         gtk_list_store_set(
756                                 list, &iter,
757                                 STRING1, _("Compression method"),
758                                 STRING2, method, -1);
759         g_free(method);
760
761         gtk_list_store_append(list, &iter);
762         msg = g_strdup_printf("%d", (page->md5) ? page->files * 2 : page->files);
763         gtk_list_store_set(
764                                 list, &iter,
765                                 STRING1, _("Number of files"),
766                                 STRING2, msg, -1);
767         g_free(msg);
768
769         gtk_list_store_append(list, &iter);
770         msg = g_strdup_printf("%d byte(s)", (guint) st.st_size);
771         gtk_list_store_set(
772                                 list, &iter,
773                                 STRING1, _("Archive Size"),
774                                 STRING2, msg, -1);
775         g_free(msg);
776
777         gtk_list_store_append(list, &iter);
778         msg = g_strdup_printf("%d byte(s)", page->total_size);
779         gtk_list_store_set(
780                                 list, &iter,
781                                 STRING1, _("Folder Size"),
782                                 STRING2, msg, -1);
783         g_free(msg);
784
785         gtk_list_store_append(list, &iter);
786         msg = g_strdup_printf("%d%%", 
787                                         (guint)((st.st_size * 100) / page->total_size));
788         gtk_list_store_set(
789                                 list, &iter,
790                                 STRING1, _("Compression level"),
791                                 STRING2, msg, -1);
792         g_free(msg);
793
794         gtk_list_store_append(list, &iter);
795         msg = g_strdup_printf("%s", (page->md5) ? _("Yes") : _("No"));
796         gtk_list_store_set(
797                                 list, &iter,
798                                 STRING1, _("MD5 checksum"),
799                                 STRING2, msg, -1);
800         g_free(msg);
801
802         gtk_list_store_append(list, &iter);
803         msg = g_strdup_printf("%s", (page->rename) ? _("Yes") : _("No"));
804         gtk_list_store_set(
805                                 list, &iter,
806                                 STRING1, _("Descriptive names"),
807                                 STRING2, msg, -1);
808         g_free(msg);
809
810         gtk_list_store_append(list, &iter);
811         msg = g_strdup_printf("%s", (page->unlink) ? _("Yes") : _("No"));
812         gtk_list_store_set(
813                                 list, &iter,
814                                 STRING1, _("Delete selected files"),
815                                 STRING2, msg, -1);
816         g_free(msg);
817         
818         msg = g_strdup(gtk_entry_get_text(GTK_ENTRY(page->isoDate)));
819         if (msg) {
820             gtk_list_store_append(list, &iter);
821             gtk_list_store_set(
822                                 list, &iter,
823                                 STRING1, _("Select mails before"),
824                                 STRING2, msg, -1);
825         }
826         g_free(msg);
827
828         gtk_window_set_default_size(GTK_WINDOW(dialog), 320, 260);
829
830         gtk_widget_show_all(dialog);
831 }
832
833 static void archiver_dialog_cb(GtkWidget* widget, gint action, gpointer data) {
834         struct ArchivePage* page = (struct ArchivePage *) data;
835         gboolean result = FALSE;
836
837         switch (action) {
838                 case GTK_RESPONSE_ACCEPT:
839                         debug_print("User chose OK\n");
840                         page->response = TRUE;
841                         break;
842                 default:
843                         debug_print("User chose CANCEL\n");
844                         page->response = FALSE;
845                         archiver_gtk_done(page, widget);
846                         return;
847         }
848         debug_print("Settings:\naction: %d\n", page->response);
849         if (page->response) {
850                 debug_print("Settings:\nfolder: %s\nname: %s\n",
851                                 (page->path) ? page->path : "(null)",
852                                 (page->name) ? page->name : "(null)");
853                 result = archiver_save_files(page);
854                 debug_print("Result->archiver_save_files: %d\n", result);
855                 if (progress->progress_dialog && 
856                                                 GTK_IS_WIDGET(progress->progress_dialog))
857                         gtk_widget_destroy(progress->progress_dialog);          
858                 if (result && ! page->cancelled) {
859                         show_result(page);
860                         archive_free_file_list(page->md5, page->rename);
861                         archiver_gtk_done(page, widget);
862                         return;
863                 }
864                 if (page->cancelled) {
865                         archiver_gtk_done(page, widget);
866                         archiver_gtk_show();
867                 }
868         }
869 }
870
871 static void foldersel_cb(GtkWidget *widget, gpointer data)
872 {
873         FolderItem *item;
874         gchar *item_id;
875         gint newpos = 0;
876         struct ArchivePage* page = (struct ArchivePage *) data;
877
878         item = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
879         if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
880                 gtk_editable_delete_text(GTK_EDITABLE(page->folder), 0, -1);
881                 gtk_editable_insert_text(GTK_EDITABLE(page->folder),
882                                         item_id, strlen(item_id), &newpos);
883                 page->path = g_strdup(item_id);
884                 g_free(item_id);
885         }
886         debug_print("Folder to archive: %s\n", 
887                                 gtk_entry_get_text(GTK_ENTRY(page->folder)));
888 }
889
890 static void filesel_cb(GtkWidget *widget, gpointer data)
891 {
892         GtkWidget *dialog;
893         gchar* file;
894         gint newpos = 0;
895         const gchar* homedir;
896         struct ArchivePage* page = (struct ArchivePage *) data;
897
898         dialog = gtk_file_chooser_dialog_new(
899                 _("Select file name for archive [suffix should reflect archive like .tgz]"),
900                         NULL,
901                         GTK_FILE_CHOOSER_ACTION_SAVE,
902                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
903                         GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
904                         NULL);
905         homedir = g_getenv("HOME");
906         if (!homedir)
907                 homedir = g_get_home_dir();
908
909         if (archiver_prefs.save_folder)
910                 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), 
911                                                     archiver_prefs.save_folder);
912         else
913                 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), homedir);
914         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY) {
915                 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
916                 if (file) {
917                         gtk_editable_delete_text(GTK_EDITABLE(page->file), 0, -1);
918                         gtk_editable_insert_text(GTK_EDITABLE(page->file),
919                                                 file, strlen(file), &newpos);
920                         page->name = g_strdup(file);
921                         g_free(file);
922                         page->force_overwrite = TRUE;
923                 }
924         }
925         gtk_widget_destroy(dialog);
926         debug_print("Name for archive: %s\n",
927                                 gtk_entry_get_text(GTK_ENTRY(page->file)));
928 }
929
930 void set_progress_file_label(const gchar* file) {
931         debug_print("IsLabel: %s, Update label: %s\n", 
932                                 GTK_IS_WIDGET(progress->file_label)? "Yes" : "No", file);
933         if (GTK_IS_WIDGET(progress->file_label))
934                 gtk_label_set_text(GTK_LABEL(progress->file_label), file);
935 }
936
937 void set_progress_print_all(guint fraction, guint total, guint step) {
938         gchar* text_count;
939
940         if (GTK_IS_WIDGET(progress->progress)) {
941                 if ((fraction - progress->position) % step == 0) {
942                         debug_print("frac: %d, total: %d, step: %d, prog->pos: %d\n",
943                                         fraction, total, step, progress->position);
944                         gtk_progress_bar_set_fraction(
945                                         GTK_PROGRESS_BAR(progress->progress), 
946                                         (total == 0) ? 0 : (gfloat)fraction / (gfloat)total);
947                         text_count = g_strdup_printf(_("%ld of %ld"), 
948                                         (long) fraction, (long) total);
949                         gtk_progress_bar_set_text(
950                                         GTK_PROGRESS_BAR(progress->progress), text_count);
951                         g_free(text_count);
952                         progress->position = fraction;
953                         GTK_EVENTS_FLUSH();
954                 }
955         }
956 }
957
958 void archiver_gtk_show() {
959         GtkWidget* dialog;
960         GtkWidget* frame;
961         GtkWidget* vbox1;
962         GtkWidget* hbox1;
963         GtkWidget* folder_label;
964         GtkWidget* folder_select;
965         GtkWidget* file_label;
966         GtkWidget* file_select;
967         GtkWidget* zip_radio_btn;
968         GtkWidget* bzip_radio_btn;
969     GtkWidget* compress_radio_btn;
970         GtkWidget* no_radio_btn;
971         GtkWidget* shar_radio_btn;
972         GtkWidget* pax_radio_btn;
973         GtkWidget* cpio_radio_btn;
974         GtkWidget* tar_radio_btn;
975         struct ArchivePage* page;
976         MainWindow* mainwin = mainwindow_get_mainwindow();
977
978         /*debug_set_mode(TRUE);*/
979         progress = init_progress();
980
981         page = init_archive_page();
982
983         dialog = gtk_dialog_new_with_buttons (
984                                 _("Create Archive"),
985                                 GTK_WINDOW(mainwin->window),
986                                 GTK_DIALOG_DESTROY_WITH_PARENT,
987                                 GTK_STOCK_CANCEL,
988                                 GTK_RESPONSE_CANCEL,
989                                 GTK_STOCK_OK,
990                                 GTK_RESPONSE_ACCEPT,
991                                 NULL);
992
993         g_signal_connect (
994                                 dialog,
995                                 "response",
996                                 G_CALLBACK(archiver_dialog_cb),
997                                 page);
998
999         frame = gtk_frame_new(_("Enter Archiver arguments"));
1000         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1001         gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1002         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
1003
1004         vbox1 = gtk_vbox_new (FALSE, 4);
1005         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 4);
1006         gtk_container_add(GTK_CONTAINER(frame), vbox1);
1007         
1008         hbox1 = gtk_hbox_new(FALSE, 4);
1009         gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1010         gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1011
1012         folder_label = gtk_label_new(_("Folder to archive"));
1013         gtk_box_pack_start(GTK_BOX(hbox1), folder_label, FALSE, FALSE, 0);
1014         
1015         page->folder = gtk_entry_new();
1016         gtk_widget_set_name(page->folder, "folder");
1017         gtk_box_pack_start(GTK_BOX(hbox1), page->folder, TRUE, TRUE, 0);
1018         CLAWS_SET_TIP(page->folder,
1019                         _("Folder which is the root of the archive"));
1020
1021         folder_select = gtkut_get_browse_directory_btn(_("_Browse"));
1022         gtk_box_pack_start(GTK_BOX(hbox1), folder_select, FALSE, FALSE, 0);
1023         CLAWS_SET_TIP(folder_select,
1024                         _("Click this button to select a folder which is to be root of the archive"));
1025
1026         hbox1 = gtk_hbox_new(FALSE, 4);
1027         gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1028         gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
1029
1030         file_label = gtk_label_new(_("Name for archive"));
1031         gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1032         
1033         page->file = gtk_entry_new();
1034         gtk_widget_set_name(page->file, "file");
1035         gtk_box_pack_start(GTK_BOX(hbox1), page->file, TRUE, TRUE, 0);
1036         CLAWS_SET_TIP(page->file, _("Archive location and name"));
1037
1038         file_select = gtkut_get_browse_directory_btn(_("_Select"));
1039         gtk_box_pack_start(GTK_BOX(hbox1), file_select, FALSE, FALSE, 0);
1040         CLAWS_SET_TIP(file_select,
1041                         _("Click this button to select a name and location for the archive"));
1042
1043         frame = gtk_frame_new(_("Choose compression"));
1044         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1045         gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1046         gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1047
1048         hbox1 = gtk_hbox_new(FALSE, 4);
1049         gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1050         gtk_container_add(GTK_CONTAINER(frame), hbox1);
1051
1052         zip_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_ZIP");
1053         gtk_widget_set_name(zip_radio_btn, "ZIP");
1054         gtk_box_pack_start(GTK_BOX(hbox1), zip_radio_btn, FALSE, FALSE, 0);
1055         CLAWS_SET_TIP(zip_radio_btn,
1056                         _("Choose this option to use ZIP compression for the archive"));
1057
1058         bzip_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1059                                         GTK_RADIO_BUTTON(zip_radio_btn), "BZIP_2");
1060         gtk_widget_set_name(bzip_radio_btn, "BZIP");
1061         gtk_box_pack_start(GTK_BOX(hbox1), bzip_radio_btn, FALSE, FALSE, 0);
1062         CLAWS_SET_TIP(bzip_radio_btn,
1063                         _("Choose this option to use BZIP2 compression for the archive"));
1064
1065         compress_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1066                                         GTK_RADIO_BUTTON(zip_radio_btn), "Com_press");
1067         gtk_widget_set_name(compress_radio_btn, "COMPRESS");
1068         gtk_box_pack_start(GTK_BOX(hbox1), compress_radio_btn, FALSE, FALSE, 0);
1069         CLAWS_SET_TIP(compress_radio_btn,
1070                 _("Choose this to use Compress compression for your archive"));
1071
1072         no_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1073                                         GTK_RADIO_BUTTON(zip_radio_btn), _("_None"));
1074         gtk_widget_set_name(no_radio_btn, "NONE");
1075         gtk_box_pack_start(GTK_BOX(hbox1), no_radio_btn, FALSE, FALSE, 0);
1076         CLAWS_SET_TIP(no_radio_btn,
1077                 _("Choose this option to disable compression for the archive"));
1078
1079         page->compress_methods = 
1080                         gtk_radio_button_get_group(GTK_RADIO_BUTTON(zip_radio_btn));
1081
1082         switch (archiver_prefs.compression) {
1083         case COMPRESSION_ZIP:
1084                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(zip_radio_btn), TRUE);
1085                 break;
1086         case COMPRESSION_BZIP:
1087                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bzip_radio_btn), TRUE);
1088                 break;
1089         case COMPRESSION_COMPRESS:
1090             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(compress_radio_btn), TRUE);
1091                 break;
1092             case COMPRESSION_NONE:
1093                     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(no_radio_btn), TRUE);
1094                 break;
1095         }
1096
1097         frame = gtk_frame_new(_("Choose format"));
1098         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1099         gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1100         gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1101
1102         hbox1 = gtk_hbox_new(FALSE, 4);
1103         gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1104         gtk_container_add(GTK_CONTAINER(frame), hbox1);
1105
1106         tar_radio_btn = gtk_radio_button_new_with_mnemonic(NULL, "_TAR");
1107         gtk_widget_set_name(tar_radio_btn, "TAR");
1108         gtk_box_pack_start(GTK_BOX(hbox1), tar_radio_btn, FALSE, FALSE, 0);
1109         CLAWS_SET_TIP(tar_radio_btn,
1110                         _("Choose this option to use TAR as format for the archive"));
1111
1112         shar_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1113                                         GTK_RADIO_BUTTON(tar_radio_btn), "S_HAR");
1114         gtk_widget_set_name(shar_radio_btn, "SHAR");
1115         gtk_box_pack_start(GTK_BOX(hbox1), shar_radio_btn, FALSE, FALSE, 0);
1116         CLAWS_SET_TIP(shar_radio_btn,
1117                         _("Choose this to use SHAR as format for the archive"));
1118
1119         cpio_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1120                                         GTK_RADIO_BUTTON(tar_radio_btn), "CP_IO");
1121         gtk_widget_set_name(cpio_radio_btn, "CPIO");
1122         gtk_box_pack_start(GTK_BOX(hbox1), cpio_radio_btn, FALSE, FALSE, 0);
1123         CLAWS_SET_TIP(cpio_radio_btn,
1124                 _("Choose this option to use CPIO as format for the archive"));
1125
1126         pax_radio_btn = gtk_radio_button_new_with_mnemonic_from_widget(
1127                                         GTK_RADIO_BUTTON(tar_radio_btn), "PA_X");
1128         gtk_widget_set_name(pax_radio_btn, "PAX");
1129         gtk_box_pack_start(GTK_BOX(hbox1), pax_radio_btn, FALSE, FALSE, 0);
1130         CLAWS_SET_TIP(pax_radio_btn,
1131                 _("Choose this option to use PAX as format for the archive"));
1132
1133         page->archive_formats = 
1134                         gtk_radio_button_get_group(GTK_RADIO_BUTTON(tar_radio_btn));
1135
1136         switch (archiver_prefs.format) {
1137         case FORMAT_TAR:
1138                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tar_radio_btn), TRUE);
1139                 break;
1140         case FORMAT_SHAR:
1141                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shar_radio_btn), TRUE);
1142                 break;
1143         case FORMAT_CPIO:
1144                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cpio_radio_btn), TRUE);
1145                 break;
1146         case FORMAT_PAX:
1147                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pax_radio_btn), TRUE);
1148                 break;
1149         }
1150
1151         frame = gtk_frame_new(_("Miscellaneous options"));
1152         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1153         gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1154         gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1155
1156         hbox1 = gtk_hbox_new(FALSE, 4);
1157         gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1158         gtk_container_add(GTK_CONTAINER(frame), hbox1);
1159
1160         page->recursive = gtk_check_button_new_with_mnemonic(_("_Recursive"));
1161         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->recursive), archiver_prefs.recursive);
1162         gtk_box_pack_start(GTK_BOX(hbox1), page->recursive, FALSE, FALSE, 0);
1163         CLAWS_SET_TIP(page->recursive,
1164                 _("Choose this option to include subfolders in the archive"));
1165         
1166         page->md5sum = gtk_check_button_new_with_mnemonic(_("_MD5sum"));
1167         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->md5sum), archiver_prefs.md5sum);
1168         gtk_box_pack_start(GTK_BOX(hbox1), page->md5sum, FALSE, FALSE, 0);
1169         CLAWS_SET_TIP(page->md5sum,
1170                 _("Choose this option to add MD5 checksums for each file in the archive.\n"
1171                   "Be aware though, that this dramatically increases the time it\n"
1172                   "will take to create the archive"));
1173
1174         page->rename_files = gtk_check_button_new_with_mnemonic(_("R_ename"));
1175         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->rename_files), archiver_prefs.rename);
1176         gtk_box_pack_start(GTK_BOX(hbox1), page->rename_files, FALSE, FALSE, 0);
1177         CLAWS_SET_TIP(page->rename_files,
1178                 _("Choose this option to use descriptive names for each file in the archive.\n"
1179                   "The naming scheme: date_from@to@subject.\n"
1180                   "Names will be truncated to max 96 characters"));
1181
1182         page->unlink_files = gtk_check_button_new_with_mnemonic(_("_Delete"));
1183         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(page->unlink_files), archiver_prefs.unlink);
1184         gtk_box_pack_start(GTK_BOX(hbox1), page->unlink_files, FALSE, FALSE, 0);
1185         CLAWS_SET_TIP(page->unlink_files,
1186                 _("Choose this option to delete mails after archiving\n"
1187                   "At this point only handles IMAP4, Local mbox and POP3"));
1188
1189
1190         frame = gtk_frame_new(_("Selection options"));
1191         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
1192         gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
1193         gtk_box_pack_start(GTK_BOX(vbox1), frame, FALSE, FALSE, 0);
1194
1195         hbox1 = gtk_hbox_new(FALSE, 4);
1196         gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);
1197         gtk_container_add(GTK_CONTAINER(frame), hbox1);
1198
1199         file_label = gtk_label_new(_("Select mails before"));
1200         gtk_box_pack_start(GTK_BOX(hbox1), file_label, FALSE, FALSE, 0);
1201         
1202         page->isoDate = gtk_entry_new();
1203         gtk_widget_set_name(page->isoDate, "isoDate");
1204         gtk_box_pack_start(GTK_BOX(hbox1), page->isoDate, TRUE, TRUE, 0);
1205         CLAWS_SET_TIP(page->isoDate, 
1206                 _("Select emails before a certain date\n"
1207                   "Date must comply to ISO-8601 [YYYY-MM-DD]"));
1208
1209         g_signal_connect(G_OBJECT(folder_select), "clicked", 
1210                          G_CALLBACK(foldersel_cb), page);
1211         g_signal_connect(G_OBJECT(file_select), "clicked",
1212                          G_CALLBACK(filesel_cb), page);
1213         g_signal_connect(G_OBJECT(page->folder), "activate",
1214                          G_CALLBACK(entry_change_cb), page);
1215         g_signal_connect(G_OBJECT(page->file), "activate",
1216                          G_CALLBACK(entry_change_cb), page);
1217
1218         gtk_widget_show_all(dialog);
1219 }
1220
1221 void archiver_gtk_done(struct ArchivePage* page, GtkWidget* widget) {
1222         dispose_archive_page(page);
1223         free(progress);
1224         gtk_widget_destroy(widget);
1225         /*debug_set_mode(FALSE);*/
1226 }
1227