1 /* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
4 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
5 * Copyright (C) 1999-2008 Michael Rasmussen and the Claws Mail Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "claws-features.h"
28 #include <glib/gi18n.h>
30 #include "libarchive_archive.h"
33 # include "archiver.h"
35 # include "mainwindow.h"
39 #include <sys/types.h>
43 #include <archive_entry.h>
53 #define READ_BLOCK_SIZE 10240
60 static GSList* msg_trash_list = NULL;
61 static GSList* file_list = NULL;
62 static gboolean stop_action = FALSE;
65 static int permissions = 0;
68 static void free_msg_trash(MsgTrash* trash) {
70 debug_print("Freeing files in %s\n", folder_item_get_name(trash->item));
72 g_slist_free(trash->msgs);
78 MsgTrash* new_msg_trash(FolderItem* item) {
82 g_return_val_if_fail(item != NULL, NULL);
84 /* FolderType must be F_MH, F_MBOX, F_MAILDIR or F_IMAP */
85 type = item->folder->klass->type;
86 if (!(type == F_MH || type == F_MBOX ||
87 type == F_MAILDIR || type == F_IMAP))
89 msg_trash = g_new0(MsgTrash, 1);
90 msg_trash->item = item;
91 msg_trash->msgs = NULL;
92 msg_trash_list = g_slist_prepend(msg_trash_list, msg_trash);
97 void archive_free_archived_files() {
102 for (l = msg_trash_list; l; l = g_slist_next(l)) {
103 mt = (MsgTrash *) l->data;
104 debug_print("Trashing messages in folder: %s\n",
105 folder_item_get_name(mt->item));
106 res = folder_item_remove_msgs(mt->item, mt->msgs);
107 debug_print("Result was %d\n", res);
110 g_slist_free(msg_trash_list);
111 msg_trash_list = NULL;
114 void archive_add_msg_mark(MsgTrash* trash, MsgInfo* msg) {
115 g_return_if_fail(trash != NULL || msg != NULL);
116 debug_print("Marking msg #%d for removal\n", msg->msgnum);
117 trash->msgs = g_slist_prepend(trash->msgs, msg);
120 static void free_all(GDate* date, gchar** parts) {
127 static gboolean is_iso_string(gchar** items) {
134 debug_print("Date part %d: %s\n", i, item);
137 if (strlen(item) != 4)
142 if (strlen(item) != 2)
149 debug_print("Leaving\n");
153 static GDate* iso2GDate(const gchar* date) {
155 gchar** parts = NULL;
158 g_return_val_if_fail(date != NULL, NULL);
160 gdate = g_date_new();
161 parts = g_strsplit(date, "-", 3);
162 if (! is_iso_string(parts))
166 for (i = 0; i < 3; i++) {
167 int t = atoi(parts[i]);
170 if (t < 1 || t > 9999) {
171 free_all(gdate, parts);
174 g_date_set_year(gdate, t);
177 if (t < 1 || t > 12) {
178 free_all(gdate, parts);
181 g_date_set_month(gdate, t);
184 if (t < 1 || t > 31) {
185 free_all(gdate, parts);
188 g_date_set_day(gdate, t);
196 gboolean before_date(time_t msg_mtime, const gchar* before) {
201 #if !GLIB_CHECK_VERSION(2,10,0)
205 debug_print("Cut-off date: %s\n", before);
206 if ((date = iso2GDate(before)) == NULL) {
207 g_warning("Bad date format: %s\n", before);
211 file_t = g_date_new();
212 #if GLIB_CHECK_VERSION(2,10,0)
213 g_date_set_time_t(file_t, msg_mtime);
215 gtime = (GTime) msg_mtime;
216 g_date_set_time(file_t, gtime);
219 if (debug_get_mode()) {
220 pos = g_new0(char, 100);
221 g_date_strftime(pos, 100, "%F", file_t);
222 fprintf(stderr, "File date: %s\n", pos);
226 if (! g_date_valid(file_t)) {
227 g_warning("Invalid msg date\n");
231 res = (g_date_compare(file_t, date) >= 0) ? FALSE : TRUE;
236 static void archive_free_file_info(struct file_info* file) {
247 void stop_archiving() {
248 debug_print("stop action set to true\n");
252 void archive_free_file_list(gboolean md5, gboolean rename) {
253 struct file_info* file = NULL;
256 debug_print("freeing file list\n");
260 file = (struct file_info *) file_list->data;
261 if (!rename && md5 && g_str_has_suffix(file->name, ".md5")) {
262 path = g_strdup_printf("%s/%s", file->path, file->name);
263 debug_print("unlinking %s\n", path);
268 path = g_strdup_printf("%s/%s", file->path, file->name);
269 debug_print("unlinking %s\n", path);
273 archive_free_file_info(file);
274 file_list->data = NULL;
275 file_list = g_slist_next(file_list);
278 g_slist_free(file_list);
283 static struct file_info* archive_new_file_info() {
284 struct file_info* new_file_info = malloc(sizeof(struct file_info));
286 new_file_info->path = NULL;
287 new_file_info->name = NULL;
288 return new_file_info;
291 static void archive_add_to_list(struct file_info* file) {
294 file_list = g_slist_prepend(file_list, (gpointer) file);
297 static gchar* strip_leading_dot_slash(gchar* path) {
298 gchar* stripped = path;
299 gchar* result = NULL;
301 if (stripped && stripped[0] == '.') {
303 if (stripped && stripped[0] == '/')
305 result = g_strdup(stripped);
308 result = g_strdup(path);
312 static gchar* get_full_path(struct file_info* file) {
313 char* path = malloc(PATH_MAX);
315 if (file->path && *(file->path))
316 sprintf(path, "%s/%s", file->path, file->name);
318 sprintf(path, "%s", file->name);
323 static gchar* strip_leading_slash(gchar* path) {
324 gchar* stripped = path;
325 gchar* result = NULL;
327 if (stripped && stripped[0] == '/') {
329 result = g_strdup(stripped);
332 result = g_strdup(path);
336 static int archive_get_permissions() {
341 void archive_set_permissions(int perm) {
345 static int archive_copy_data(struct archive* in, struct archive* out) {
349 int res = ARCHIVE_OK;
351 while (res == ARCHIVE_OK) {
352 res = archive_read_data_block(in, &buf, &size, &offset);
353 if (res == ARCHIVE_OK) {
354 res = archive_write_data_block(out, buf, size, offset);
357 return (res == ARCHIVE_EOF) ? ARCHIVE_OK : res;
361 void archive_add_file(gchar* path) {
362 struct file_info* file = archive_new_file_info();
363 gchar* filename = NULL;
365 g_return_if_fail(path != NULL);
368 debug_print("add %s to list\n", path);
370 filename = g_strrstr_len(path, strlen(path), "/");
372 g_warning("%s\n", path);
373 g_return_if_fail(filename != NULL);
376 file->name = g_strdup(filename);
377 file->path = strip_leading_dot_slash(dirname(path));
378 archive_add_to_list(file);
381 GSList* archive_get_file_list() {
386 const gchar* archive_extract(const char* archive_name, int flags) {
389 struct archive_entry* entry;
390 int res = ARCHIVE_OK;
392 const char* result == NULL;
394 g_return_val_if_fail(archive_name != NULL, ARCHIVE_FATAL);
396 fprintf(stdout, "%s: extracting\n", archive_name);
397 in = archive_read_new();
398 if ((res = archive_read_support_format_tar(in)) == ARCHIVE_OK) {
399 if ((res = archive_read_support_compression_gzip(in)) == ARCHIVE_OK) {
400 if ((res = archive_read_open_file(
401 in, archive_name, READ_BLOCK_SIZE)) != ARCHIVE_OK) {
402 buf = g_strdup_printf(
403 "%s: %s\n", archive_name, archive_error_string(in));
404 g_warning("%s\n", buf);
406 result = archive_error_string(in);
409 out = archive_write_disk_new();
410 if ((res = archive_write_disk_set_options(
411 out, flags)) == ARCHIVE_OK) {
412 res = archive_read_next_header(in, &entry);
413 while (res == ARCHIVE_OK) {
414 fprintf(stdout, "%s\n", archive_entry_pathname(entry));
415 res = archive_write_header(out, entry);
416 if (res != ARCHIVE_OK) {
417 buf = g_strdup_printf("%s\n",
418 archive_error_string(out));
419 g_warning("%s\n", buf);
421 /* skip this file an continue */
425 res = archive_copy_data(in, out);
426 if (res != ARCHIVE_OK) {
427 buf = g_strdup_printf("%s\n",
428 archive_error_string(in));
429 g_warning("%s\n", buf);
431 /* skip this file an continue */
435 res = archive_read_next_header(in, &entry);
438 if (res == ARCHIVE_EOF)
440 if (res != ARCHIVE_OK) {
441 buf = g_strdup_printf("%s\n", archive_error_string(in));
444 buf = g_strdup_printf("%s: Unknown error\n", archive_name);
446 g_warning("%s\n", buf);
448 result = archive_error_string(in);
452 result = archive_error_string(out);
453 archive_read_close(in);
455 archive_read_finish(in);
458 result = archive_error_string(in);
461 result = archive_error_string(in);
466 const gchar* archive_create(const char* archive_name, GSList* files,
467 COMPRESS_METHOD method, ARCHIVE_FORMAT format) {
468 struct archive* arch;
469 struct archive_entry* entry;
474 struct file_info* file;
475 gchar* filename = NULL;
480 gint total = g_slist_length (files);
483 g_return_val_if_fail(files != NULL, "No files for archiving");
485 debug_print("File: %s\n", archive_name);
486 arch = archive_write_new();
489 if (archive_write_set_compression_gzip(arch) != ARCHIVE_OK)
490 return archive_error_string(arch);
493 if (archive_write_set_compression_bzip2(arch) != ARCHIVE_OK)
494 return archive_error_string(arch);
498 if (archive_write_set_compression_compress(arch) != ARCHIVE_OK)
499 return archive_error_string(arch);
503 if (archive_write_set_compression_none(arch) != ARCHIVE_OK)
504 return archive_error_string(arch);
509 if (archive_write_set_format_ustar(arch) != ARCHIVE_OK)
510 return archive_error_string(arch);
513 if (archive_write_set_format_shar(arch) != ARCHIVE_OK)
514 return archive_error_string(arch);
517 if (archive_write_set_format_pax(arch) != ARCHIVE_OK)
518 return archive_error_string(arch);
521 if (archive_write_set_format_cpio(arch) != ARCHIVE_OK)
522 return archive_error_string(arch);
525 return "Missing archive format";
527 if (archive_write_open_file(arch, archive_name) != ARCHIVE_OK)
528 return archive_error_string(arch);
530 while (files && ! stop_action) {
532 set_progress_print_all(num++, total, 30);
534 file = (struct file_info *) files->data;
537 filename = get_full_path(file);
538 /* libarchive will crash if instructed to add archive to it self */
539 if (g_utf8_collate(archive_name, filename) == 0) {
541 buf = g_strdup_printf(
542 "%s: Not dumping to %s", archive_name, filename);
543 g_warning("%s\n", buf);
545 debug_print("%s\n", buf);
551 debug_print("Adding: %s\n", filename);
552 msg = g_strdup_printf("%s", filename);
553 set_progress_file_label(msg);
556 entry = archive_entry_new();
557 lstat(filename, &st);
558 if ((fd = open(filename, O_RDONLY)) == -1) {
562 archive_entry_copy_stat(entry, &st);
563 archive_entry_set_pathname(entry, filename);
564 if (S_ISLNK(st.st_mode)) {
566 buf = malloc(PATH_MAX + 1);
567 if ((len = readlink(filename, buf, PATH_MAX)) < 0)
568 perror("error in readlink");
571 archive_entry_set_symlink(entry, buf);
573 archive_entry_set_size(entry, 0);
574 archive_write_header(arch, entry);
577 if (archive_write_header(arch, entry) != ARCHIVE_OK)
578 g_warning("%s", archive_error_string(arch));
580 buf = malloc(READ_BLOCK_SIZE);
581 len = read(fd, buf, READ_BLOCK_SIZE);
583 if (archive_write_data(arch, buf, len) == -1)
584 g_warning("%s", archive_error_string(arch));
585 memset(buf, 0, READ_BLOCK_SIZE);
586 len = read(fd, buf, READ_BLOCK_SIZE);
591 archive_entry_free(entry);
595 files = g_slist_next(files);
599 unlink(archive_name);
602 archive_write_close(arch);
603 archive_write_finish(arch);
608 void archive_scan_folder(const char* dir) {
613 gchar path[PATH_MAX];
615 getcwd(cwd, PATH_MAX);
617 if (g_stat(dir, &st) == -1)
619 if (! S_ISDIR(st.st_mode))
621 if (!(root = opendir(dir)))
625 while ((ent = readdir(root)) != NULL) {
626 if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
628 g_stat(ent->d_name, &st);
629 sprintf(path, "%s/%s", dir, ent->d_name);
630 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
631 archive_add_file(path);
633 else if (S_ISDIR(st.st_mode)) {
634 archive_scan_folder(path);
641 int main(int argc, char** argv) {
642 char* archive = NULL;
646 int perm = ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME |
647 ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_SECURE_SYMLINKS;
649 gboolean remove = FALSE;
650 const char *p = NULL;
653 getcwd(cwd, PATH_MAX);
655 while (*++argv && **argv == '-') {
658 while ((opt = *p++) != '\0') {
662 archive = (char *) p;
674 fprintf(stderr, "Missing archive name!\n");
678 fprintf(stderr, "Expected arguments after options!\n");
683 archive_scan_folder(*argv++);
684 res = archive_create(archive, file_list);
685 if (res != ARCHIVE_OK) {
686 fprintf(stderr, "%s: Creating archive failed\n", archive);
690 pid = (int) getpid();
691 sprintf(buf, "/tmp/%d", pid);
692 fprintf(stdout, "Creating: %s\n", buf);
695 if (strcmp(dirname(archive), ".") == 0)
696 sprintf(buf, "%s/%s", cwd, basename(archive));
698 sprintf(buf, "%s", archive);
699 archive_extract(buf, perm);
702 sprintf(buf, "rm -rf /tmp/%d", pid);
703 fprintf(stdout, "Executing: %s\n", buf);
706 archive_free_list(file_list);