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