add support for Ayatana indicator to Notification plugin
[claws.git] / src / plugins / mailmbox / mailmbox_folder.c
blob179ec2486b35c94028ac05c9d468c907cd045ac4
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2024 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 # include "claws-features.h"
22 #endif
24 #include <glib.h>
25 #include <glib/gi18n.h>
27 #include "defs.h"
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <sys/mman.h>
37 #undef MEASURE_TIME
39 #ifdef MEASURE_TIME
40 # include <sys/time.h>
41 #endif
43 #include "folder.h"
44 #include "procmsg.h"
45 #include "procheader.h"
46 #include "statusbar.h"
47 #include "utils.h"
48 #include "gtkutils.h"
49 #include "localfolder.h"
50 #include "mailmbox.h"
51 #include "mailmbox_folder.h"
52 #include "mailmbox_parse.h"
53 #include "file-utils.h"
55 #define MAILMBOX_CACHE_DIR "mailmboxcache"
57 static Folder *s_claws_mailmbox_folder_new(const gchar *name, const gchar *path);
59 static void claws_mailmbox_folder_destroy(Folder *folder);
61 static FolderItem *claws_mailmbox_folder_item_new(Folder *folder);
63 static void claws_mailmbox_folder_item_destroy(Folder *folder, FolderItem *_item);
65 static gchar *claws_mailmbox_item_get_path(Folder *folder, FolderItem *item);
67 static gint claws_mailmbox_get_num_list(Folder *folder, FolderItem *item,
68 GSList **list, gboolean *old_uids_valid);
70 static MsgInfo *claws_mailmbox_get_msginfo(Folder *folder,
71 FolderItem *item, gint num);
73 static GSList *claws_mailmbox_get_msginfos(Folder *folder, FolderItem *item,
74 GSList *msgnum_list);
76 static gchar *s_claws_mailmbox_fetch_msg(Folder *folder, FolderItem *item, gint num);
78 static gint claws_mailmbox_add_msg(Folder *folder, FolderItem *dest,
79 const gchar *file, MsgFlags *flags);
81 static gint claws_mailmbox_add_msgs(Folder *folder, FolderItem *dest,
82 GSList *file_list,
83 GHashTable *relation);
85 static gint s_claws_mailmbox_copy_msg(Folder *folder,
86 FolderItem *dest, MsgInfo *msginfo);
88 static gint claws_mailmbox_copy_msgs(Folder *folder, FolderItem *dest,
89 MsgInfoList *msglist, GHashTable *relation);
91 static gint claws_mailmbox_remove_msg(Folder *folder, FolderItem *item, gint num);
92 static gint claws_mailmbox_remove_msgs( Folder *folder, FolderItem *item, MsgInfoList *msglist, GHashTable *relation );
93 static gint claws_mailmbox_remove_all_msg(Folder *folder, FolderItem *item);
95 static FolderItem *claws_mailmbox_create_folder(Folder *folder, FolderItem *parent,
96 const gchar *name);
98 static gboolean claws_mailmbox_scan_required(Folder *folder, FolderItem *_item);
100 static gint claws_mailmbox_rename_folder(Folder *folder,
101 FolderItem *item, const gchar *name);
103 static gint claws_mailmbox_remove_folder(Folder *folder, FolderItem *item);
105 static gint claws_mailmbox_create_tree(Folder *folder);
107 static gint claws_mailmbox_folder_item_close(Folder *folder, FolderItem *item);
109 static FolderClass claws_mailmbox_class;
111 static gchar * get_cache_dir(void)
113 static gchar *mbox_cache_dir = NULL;
115 if (!mbox_cache_dir)
116 mbox_cache_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
117 MAILMBOX_CACHE_DIR, NULL);
119 return mbox_cache_dir;
123 FolderClass *claws_mailmbox_get_class(void)
125 if (claws_mailmbox_class.idstr == NULL) {
126 claws_mailmbox_class.type = F_MBOX;
127 claws_mailmbox_class.idstr = "mailmbox";
128 claws_mailmbox_class.uistr = "mbox";
130 /* Folder functions */
131 claws_mailmbox_class.new_folder = s_claws_mailmbox_folder_new;
132 claws_mailmbox_class.destroy_folder = claws_mailmbox_folder_destroy;
133 claws_mailmbox_class.set_xml = folder_local_set_xml;
134 claws_mailmbox_class.get_xml = folder_local_get_xml;
135 claws_mailmbox_class.create_tree = claws_mailmbox_create_tree;
137 /* FolderItem functions */
138 claws_mailmbox_class.item_new = claws_mailmbox_folder_item_new;
139 claws_mailmbox_class.item_destroy = claws_mailmbox_folder_item_destroy;
140 claws_mailmbox_class.item_get_path = claws_mailmbox_item_get_path;
141 claws_mailmbox_class.create_folder = claws_mailmbox_create_folder;
142 claws_mailmbox_class.rename_folder = claws_mailmbox_rename_folder;
143 claws_mailmbox_class.remove_folder = claws_mailmbox_remove_folder;
144 claws_mailmbox_class.close = claws_mailmbox_folder_item_close;
145 claws_mailmbox_class.get_num_list = claws_mailmbox_get_num_list;
146 claws_mailmbox_class.scan_required = claws_mailmbox_scan_required;
148 /* Message functions */
149 claws_mailmbox_class.get_msginfo = claws_mailmbox_get_msginfo;
150 claws_mailmbox_class.get_msginfos = claws_mailmbox_get_msginfos;
151 claws_mailmbox_class.fetch_msg = s_claws_mailmbox_fetch_msg;
152 claws_mailmbox_class.add_msg = claws_mailmbox_add_msg;
153 claws_mailmbox_class.add_msgs = claws_mailmbox_add_msgs;
154 claws_mailmbox_class.copy_msg = s_claws_mailmbox_copy_msg;
155 claws_mailmbox_class.copy_msgs = claws_mailmbox_copy_msgs;
156 claws_mailmbox_class.remove_msg = claws_mailmbox_remove_msg;
157 claws_mailmbox_class.remove_msgs = claws_mailmbox_remove_msgs;
158 claws_mailmbox_class.remove_all_msg = claws_mailmbox_remove_all_msg;
160 return &claws_mailmbox_class;
164 static void claws_mailmbox_folder_init(Folder *folder,
165 const gchar *name, const gchar *path)
167 folder_local_folder_init(folder, name, path);
170 static Folder *s_claws_mailmbox_folder_new(const gchar *name, const gchar *path)
172 Folder *folder;
174 folder = (Folder *)g_new0(MAILMBOXFolder, 1);
175 folder->klass = &claws_mailmbox_class;
176 claws_mailmbox_folder_init(folder, name, path);
178 return folder;
181 static void claws_mailmbox_folder_destroy(Folder *folder)
183 folder_local_folder_destroy(LOCAL_FOLDER(folder));
186 typedef struct _MAILMBOXFolderItem MAILMBOXFolderItem;
187 struct _MAILMBOXFolderItem
189 FolderItem item;
190 guint old_max_uid;
191 struct claws_mailmbox_folder * mbox;
194 static FolderItem *claws_mailmbox_folder_item_new(Folder *folder)
196 MAILMBOXFolderItem *item;
198 item = g_new0(MAILMBOXFolderItem, 1);
199 item->mbox = NULL;
200 item->old_max_uid = 0;
202 return (FolderItem *)item;
205 #define MAX_UID_FILE "max-uid"
207 static void read_max_uid_value(FolderItem *item, guint * pmax_uid)
209 gchar * path;
210 gchar * file;
211 FILE * f;
212 guint max_uid;
213 size_t r;
215 path = folder_item_get_path(item);
216 file = g_strconcat(path, G_DIR_SEPARATOR_S, MAX_UID_FILE, NULL);
217 g_free(path);
219 f = claws_fopen(file, "r");
220 g_free(file);
221 if (f == NULL)
222 return;
223 r = claws_fread(&max_uid, sizeof(max_uid), 1, f);
224 if (r == 0) {
225 claws_fclose(f);
226 return;
229 claws_fclose(f);
231 * pmax_uid = max_uid;
234 static void write_max_uid_value(FolderItem *item, guint max_uid)
236 gchar * path;
237 gchar * file;
238 FILE * f;
239 size_t r;
241 path = folder_item_get_path(item);
242 file = g_strconcat(path, G_DIR_SEPARATOR_S, MAX_UID_FILE, NULL);
243 g_free(path);
245 f = claws_fopen(file, "w");
246 g_free(file);
247 if (f == NULL)
248 return;
249 r = claws_fwrite(&max_uid, sizeof(max_uid), 1, f);
250 if (r == 0) {
251 claws_fclose(f);
252 return;
255 claws_safe_fclose(f);
258 static void claws_mailmbox_folder_item_destroy(Folder *folder, FolderItem *_item)
260 MAILMBOXFolderItem *item = (MAILMBOXFolderItem *)_item;
262 g_return_if_fail(item != NULL);
264 if (item->mbox != NULL) {
265 write_max_uid_value(_item, item->mbox->mb_written_uid);
266 claws_mailmbox_done(item->mbox);
268 g_free(_item);
271 static gint claws_mailmbox_folder_item_close(Folder *folder, FolderItem *item_)
273 MAILMBOXFolderItem *item = (MAILMBOXFolderItem *)item_;
275 g_return_val_if_fail(folder->klass->type == F_MBOX, -1);
276 g_return_val_if_fail(item != NULL, -1);
277 g_return_val_if_fail(item->mbox != NULL, -1);
279 return -claws_mailmbox_expunge(item->mbox);
282 static void claws_mailmbox_folder_create_parent(const gchar * path)
284 if (!is_file_exist(path)) {
285 gchar * new_path;
287 new_path = g_path_get_dirname(path);
288 if (new_path[strlen(new_path) - 1] == G_DIR_SEPARATOR)
289 new_path[strlen(new_path) - 1] = '\0';
291 if (!is_dir_exist(new_path))
292 make_dir_hier(new_path);
293 g_free(new_path);
298 static gchar * claws_mailmbox_folder_get_path(Folder *folder, FolderItem *item)
300 gchar *folder_path;
301 gchar *path;
303 g_return_val_if_fail(item != NULL, NULL);
305 if (item->path && item->path[0] == G_DIR_SEPARATOR) {
306 claws_mailmbox_folder_create_parent(item->path);
307 return g_strdup(item->path);
310 folder_path = g_strdup(LOCAL_FOLDER(item->folder)->rootpath);
311 g_return_val_if_fail(folder_path != NULL, NULL);
313 if (folder_path[0] == G_DIR_SEPARATOR) {
314 if (item->path) {
315 path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
316 item->path, NULL);
318 else
319 path = g_strdup(folder_path);
320 } else {
321 if (item->path)
322 path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
323 folder_path, G_DIR_SEPARATOR_S,
324 item->path, NULL);
325 else
326 path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
327 folder_path, NULL);
330 g_free(folder_path);
332 claws_mailmbox_folder_create_parent(path);
334 return path;
337 static int claws_mailmbox_item_sync(FolderItem *_item, int validate_uid)
339 MAILMBOXFolderItem *item = (MAILMBOXFolderItem *)_item;
340 int r;
342 if (item->mbox == NULL) {
343 guint written_uid;
344 gchar * path;
346 written_uid = 0;
347 read_max_uid_value(_item, &written_uid);
348 path = claws_mailmbox_folder_get_path(_item->folder, _item);
349 r = claws_mailmbox_init(path, 0, 0, written_uid, &item->mbox);
350 debug_print("init %d: %p\n", r, item->mbox);
351 g_free(path);
352 if (r != MAILMBOX_NO_ERROR)
353 return -1;
356 if (!validate_uid) {
357 r = claws_mailmbox_validate_read_lock(item->mbox);
358 if (r != MAILMBOX_NO_ERROR) {
359 debug_print("read lock: %d\n", r);
360 goto err;
363 claws_mailmbox_read_unlock(item->mbox);
365 else {
366 r = claws_mailmbox_validate_write_lock(item->mbox);
367 if (r != MAILMBOX_NO_ERROR) {
368 debug_print("write lock: %d\n", r);
369 goto err;
372 if (item->mbox->mb_written_uid < item->mbox->mb_max_uid) {
373 r = claws_mailmbox_expunge_no_lock(item->mbox);
374 if (r != MAILMBOX_NO_ERROR)
375 goto unlock;
377 claws_mailmbox_write_unlock(item->mbox);
380 return 0;
382 unlock:
383 claws_mailmbox_write_unlock(item->mbox);
384 err:
385 return -1;
388 static struct claws_mailmbox_folder * get_mbox(FolderItem *_item, int validate_uid)
390 MAILMBOXFolderItem *item = (MAILMBOXFolderItem *)_item;
392 claws_mailmbox_item_sync(_item, validate_uid);
394 return item->mbox;
397 static gint claws_mailmbox_get_num_list(Folder *folder, FolderItem *item,
398 GSList **list, gboolean *old_uids_valid)
400 gint nummsgs = 0;
401 guint i;
402 struct claws_mailmbox_folder * mbox;
404 g_return_val_if_fail(item != NULL, -1);
406 debug_print("mbox_get_last_num(): Scanning %s ...\n", item->path);
408 *old_uids_valid = TRUE;
410 mbox = get_mbox(item, 1);
411 if (mbox == NULL)
412 return -1;
414 for(i = 0 ; i < carray_count(mbox->mb_tab) ; i ++) {
415 struct claws_mailmbox_msg_info * msg;
417 msg = carray_get(mbox->mb_tab, i);
418 if (msg != NULL) {
419 *list = g_slist_prepend(*list,
420 GINT_TO_POINTER(msg->msg_uid));
421 nummsgs ++;
425 return nummsgs;
428 static gchar *s_claws_mailmbox_fetch_msg(Folder *folder, FolderItem *item, gint num)
430 gchar *path;
431 gchar *file;
432 int r;
433 struct claws_mailmbox_folder * mbox;
434 const char * data;
435 size_t len;
436 FILE * f;
437 mode_t old_mask;
439 g_return_val_if_fail(item != NULL, NULL);
440 g_return_val_if_fail(num > 0, NULL);
442 mbox = get_mbox(item, 0);
443 if (mbox == NULL)
444 return NULL;
446 path = folder_item_get_path(item);
447 if (!is_dir_exist(path))
448 make_dir_hier(path);
449 file = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
450 g_free(path);
451 if (is_file_exist(file)) {
452 return file;
455 r = claws_mailmbox_fetch_msg(mbox, num, &data, &len);
456 if (r != MAILMBOX_NO_ERROR)
457 goto free;
459 old_mask = umask(0077);
460 f = claws_fopen(file, "w");
461 umask(old_mask);
462 if (f == NULL)
463 goto free;
465 r = claws_fwrite(data, 1, len, f);
466 if (r == 0)
467 goto close;
469 claws_safe_fclose(f);
471 return file;
473 close:
474 claws_fclose(f);
475 unlink(file);
476 free:
477 free(file);
478 return NULL;
481 static MsgInfo *claws_mailmbox_parse_msg(guint uid,
482 const char * data, size_t len, FolderItem *_item)
484 MsgInfo *msginfo;
485 MsgFlags flags;
486 struct claws_mailmbox_folder * mbox;
487 chashdatum key;
488 chashdatum value;
489 struct claws_mailmbox_msg_info * info;
490 int r;
491 MAILMBOXFolderItem * item = (MAILMBOXFolderItem *)_item;
493 flags.perm_flags = MSG_NEW|MSG_UNREAD;
494 flags.tmp_flags = 0;
496 g_return_val_if_fail(item != NULL, NULL);
497 g_return_val_if_fail(data != NULL, NULL);
499 if (_item->stype == F_QUEUE) {
500 MSG_SET_TMP_FLAGS(flags, MSG_QUEUED);
501 } else if (_item->stype == F_DRAFT) {
502 MSG_SET_TMP_FLAGS(flags, MSG_DRAFT);
505 mbox = item->mbox;
507 key.data = (char *) &uid;
508 key.len = sizeof(uid);
510 r = chash_get(mbox->mb_hash, &key, &value);
511 if (r < 0)
512 return NULL;
514 info = (struct claws_mailmbox_msg_info *) value.data;
516 msginfo = procheader_parse_str(data, flags, FALSE, FALSE);
517 if (!msginfo) return NULL;
519 msginfo->msgnum = uid;
520 msginfo->folder = _item;
521 msginfo->size = (goffset)(info->msg_size - info->msg_start_len);
523 return msginfo;
526 static MsgInfo *claws_mailmbox_get_msginfo(Folder *folder,
527 FolderItem *item, gint num)
529 MsgInfo *msginfo;
530 int r;
531 const char * data;
532 size_t len;
533 struct claws_mailmbox_folder * mbox;
535 g_return_val_if_fail(item != NULL, NULL);
536 g_return_val_if_fail(num > 0, NULL);
538 mbox = get_mbox(item, 0);
539 if (mbox == NULL)
540 goto err;
542 r = claws_mailmbox_validate_read_lock(mbox);
543 if (r != MAILMBOX_NO_ERROR)
544 goto err;
546 r = claws_mailmbox_fetch_msg_headers_no_lock(mbox, num, &data, &len);
547 if (r != MAILMBOX_NO_ERROR)
548 goto unlock;
550 msginfo = claws_mailmbox_parse_msg(num, data, len, item);
551 if (!msginfo)
552 goto unlock;
554 claws_mailmbox_read_unlock(mbox);
556 return msginfo;
558 unlock:
559 claws_mailmbox_read_unlock(mbox);
560 err:
561 return NULL;
564 static GSList *claws_mailmbox_get_msginfos(Folder *folder, FolderItem *item,
565 GSList *msgnum_list)
567 int r;
568 GSList * cur;
569 GSList * ret;
570 struct claws_mailmbox_folder * mbox;
572 g_return_val_if_fail(item != NULL, NULL);
574 mbox = get_mbox(item, 0);
575 if (mbox == NULL)
576 goto err;
578 r = claws_mailmbox_validate_read_lock(mbox);
579 if (r != MAILMBOX_NO_ERROR)
580 goto err;
582 ret = NULL;
584 for (cur = msgnum_list ; cur != NULL ; cur = g_slist_next(cur)) {
585 const char * data;
586 size_t len;
587 gint num;
588 MsgInfo *msginfo;
590 num = GPOINTER_TO_INT(cur->data);
592 r = claws_mailmbox_fetch_msg_headers_no_lock(mbox, num, &data, &len);
593 if (r != MAILMBOX_NO_ERROR)
594 continue;
596 msginfo = claws_mailmbox_parse_msg(num, data, len, item);
597 if (!msginfo)
598 continue;
600 ret = g_slist_append(ret, msginfo);
603 claws_mailmbox_read_unlock(mbox);
605 return ret;
607 err:
608 return NULL;
611 static gint claws_mailmbox_add_msg(Folder *folder, FolderItem *dest,
612 const gchar *file, MsgFlags *flags)
614 gint ret;
615 GSList file_list;
616 MsgFileInfo fileinfo;
618 g_return_val_if_fail(file != NULL, -1);
620 fileinfo.msginfo = NULL;
621 fileinfo.file = (gchar *)file;
622 fileinfo.flags = flags;
623 file_list.data = &fileinfo;
624 file_list.next = NULL;
626 ret = claws_mailmbox_add_msgs(folder, dest, &file_list, NULL);
627 return ret;
630 /* ok */
632 static gint claws_mailmbox_add_msgs(Folder *folder, FolderItem *dest,
633 GSList *file_list,
634 GHashTable *relation)
636 GSList *cur;
637 gint last_num;
638 struct claws_mailmbox_folder * mbox;
639 carray * append_list;
640 struct claws_mailmbox_append_info append_info;
641 int r;
643 g_return_val_if_fail(dest != NULL, -1);
644 g_return_val_if_fail(file_list != NULL, -1);
646 mbox = get_mbox(dest, 0);
647 if (mbox == NULL) {
648 debug_print("mbox not found\n");
649 return -1;
651 r = claws_mailmbox_validate_write_lock(mbox);
652 if (r != MAILMBOX_NO_ERROR) {
653 debug_print("claws_mailmbox_validate_write_lock failed with %d\n", r);
654 return -1;
656 r = claws_mailmbox_expunge_no_lock(mbox);
657 if (r != MAILMBOX_NO_ERROR) {
658 debug_print("claws_mailmbox_expunge_no_lock failed with %d\n", r);
659 goto unlock;
662 last_num = -1;
664 append_list = carray_new(1);
665 if (append_list == NULL) {
666 debug_print("append_list is null\n");
667 goto unlock;
670 r = carray_set_size(append_list, 1);
671 if (r < 0) {
672 debug_print("carray_set_size failed with %d\n", r);
673 goto free;
676 carray_set(append_list, 0, &append_info);
678 for (cur = file_list; cur != NULL; cur = cur->next) {
679 int fd;
680 struct stat stat_info;
681 char * data;
682 size_t len;
683 struct claws_mailmbox_msg_info * msg;
684 size_t cur_token;
685 MsgFileInfo *fileinfo;
687 fileinfo = (MsgFileInfo *)cur->data;
689 fd = open(fileinfo->file, O_RDONLY);
690 if (fd == -1) {
691 debug_print("%s couldn't be opened\n", fileinfo->file);
692 goto err;
695 r = fstat(fd, &stat_info);
696 if (r < 0) {
697 debug_print("%s couldn't be stat'ed\n", fileinfo->file);
698 goto close;
701 len = stat_info.st_size;
702 data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
703 if (data == MAP_FAILED) {
704 debug_print("mmap failed\n");
705 goto close;
708 append_info.ai_message = data;
709 append_info.ai_size = len;
711 cur_token = mbox->mb_mapping_size;
713 r = claws_mailmbox_append_message_list_no_lock(mbox, append_list);
714 if (r != MAILMBOX_NO_ERROR) {
715 debug_print("claws_mailmbox_append_message_list_no_lock failed with %d\n", r);
716 goto unmap;
719 munmap(data, len);
720 close(fd);
722 r = claws_mailmbox_parse_additionnal(mbox, &cur_token);
723 if (r != MAILMBOX_NO_ERROR) {
724 debug_print("claws_mailmbox_parse_additionnal failed with %d\n", r);
725 goto unlock;
728 msg = carray_get(mbox->mb_tab, carray_count(mbox->mb_tab) - 1);
730 if (relation != NULL)
731 g_hash_table_insert(relation,
732 fileinfo->msginfo != NULL ?
733 (gpointer) fileinfo->msginfo :
734 (gpointer) fileinfo,
735 GINT_TO_POINTER(msg->msg_uid));
737 last_num = msg->msg_uid;
739 continue;
741 unmap:
742 munmap(data, len);
743 close:
744 close(fd);
745 err:
746 continue;
749 claws_mailmbox_sync(mbox);
751 carray_free(append_list);
752 claws_mailmbox_write_unlock(mbox);
754 return last_num;
756 free:
757 carray_free(append_list);
758 unlock:
759 claws_mailmbox_write_unlock(mbox);
760 return -1;
763 static gint s_claws_mailmbox_copy_msg(Folder *folder,
764 FolderItem *dest, MsgInfo *msginfo)
766 GSList msglist;
768 g_return_val_if_fail(msginfo != NULL, -1);
770 msglist.data = msginfo;
771 msglist.next = NULL;
773 return claws_mailmbox_copy_msgs(folder, dest, &msglist, NULL);
776 static gint claws_mailmbox_copy_msgs(Folder *folder, FolderItem *dest,
777 MsgInfoList *msglist, GHashTable *relation)
779 MsgInfo *msginfo;
780 GSList *file_list;
781 gint ret;
783 g_return_val_if_fail(folder != NULL, -1);
784 g_return_val_if_fail(dest != NULL, -1);
785 g_return_val_if_fail(msglist != NULL, -1);
787 msginfo = (MsgInfo *)msglist->data;
788 g_return_val_if_fail(msginfo->folder != NULL, -1);
790 file_list = procmsg_get_message_file_list(msglist);
791 g_return_val_if_fail(file_list != NULL, -1);
793 ret = claws_mailmbox_add_msgs(folder, dest, file_list, relation);
795 procmsg_message_file_list_free(file_list);
797 return ret;
801 static gint claws_mailmbox_remove_msg(Folder *folder, FolderItem *item, gint num)
803 struct claws_mailmbox_folder * mbox;
804 int r;
806 g_return_val_if_fail(item != NULL, -1);
808 mbox = get_mbox(item, 0);
809 if (mbox == NULL)
810 return -1;
812 r = claws_mailmbox_delete_msg(mbox, num);
813 if (r != MAILMBOX_NO_ERROR)
814 return -1;
816 return 0;
819 static gint
820 claws_mailmbox_remove_msgs( Folder *folder, FolderItem *item,
821 MsgInfoList *msglist, GHashTable *relation )
823 struct claws_mailmbox_folder *mbox;
824 int r;
825 gint total = 0, curnum = 0;
827 g_return_val_if_fail( item!=NULL, -1 );
828 mbox=get_mbox(item,0);
829 g_return_val_if_fail( mbox!=NULL, -1 );
831 total = g_slist_length(msglist);
832 if (total > 100) {
833 statusbar_print_all(_("Deleting messages..."));
836 MsgInfoList *cur;
837 for( cur=msglist; cur; cur=cur->next )
839 MsgInfo *msginfo=(MsgInfo*) cur->data;
840 if( !msginfo )
842 continue;
844 if( MSG_IS_MOVE(msginfo->flags) && MSG_IS_MOVE_DONE(msginfo->flags) )
846 msginfo->flags.tmp_flags&=~MSG_MOVE_DONE;
847 continue;
849 if (total > 100) {
850 statusbar_progress_all(curnum, total, 100);
851 if (curnum % 100 == 0)
852 GTK_EVENTS_FLUSH();
853 curnum++;
855 claws_mailmbox_delete_msg(mbox,msginfo->msgnum);
858 /* Fix for bug 1434
860 r = claws_mailmbox_expunge(mbox);
861 if (total > 100) {
862 statusbar_progress_all(0,0,0);
863 statusbar_pop_all();
866 return r;
870 static gint claws_mailmbox_remove_all_msg(Folder *folder, FolderItem *item)
872 struct claws_mailmbox_folder * mbox;
873 int r;
874 guint i;
876 g_return_val_if_fail(item != NULL, -1);
878 mbox = get_mbox(item, 0);
879 if (mbox == NULL)
880 return -1;
882 for(i = 0 ; i < carray_count(mbox->mb_tab) ; i ++) {
883 struct claws_mailmbox_msg_info * msg;
885 msg = carray_get(mbox->mb_tab, i);
886 if (msg == NULL)
887 continue;
889 r = claws_mailmbox_delete_msg(mbox, msg->msg_uid);
890 if (r != MAILMBOX_NO_ERROR)
891 continue;
894 return 0;
898 static gchar * claws_mailmbox_get_new_path(FolderItem * parent, gchar * name)
900 gchar * path;
902 if (strchr(name, G_DIR_SEPARATOR) == NULL) {
903 if (parent->path != NULL)
904 path = g_strconcat(parent->path, ".sbd", G_DIR_SEPARATOR_S, name, NULL);
905 else
906 path = g_strdup(name);
908 else
909 path = g_strdup(name);
911 return path;
914 static gchar * claws_mailmbox_get_folderitem_name(gchar * name)
916 gchar * foldername;
918 foldername = g_path_get_basename(name);
920 return foldername;
923 static FolderItem *claws_mailmbox_create_folder(Folder *folder, FolderItem *parent,
924 const gchar *name)
926 gchar * path;
927 FolderItem *new_item;
928 gchar * foldername;
930 g_return_val_if_fail(folder != NULL, NULL);
931 g_return_val_if_fail(parent != NULL, NULL);
932 g_return_val_if_fail(name != NULL, NULL);
934 path = claws_mailmbox_get_new_path(parent, (gchar *) name);
936 foldername = claws_mailmbox_get_folderitem_name((gchar *) name);
938 new_item = folder_item_new(folder, foldername, path);
939 folder_item_append(parent, new_item);
941 if (!strcmp(name, "inbox")) {
942 new_item->stype = F_INBOX;
943 new_item->folder->inbox = new_item;
944 } else if (!strcmp(name, "outbox")) {
945 new_item->stype = F_OUTBOX;
946 new_item->folder->outbox = new_item;
947 } else if (!strcmp(name, "draft")) {
948 new_item->stype = F_DRAFT;
949 new_item->folder->draft = new_item;
950 } else if (!strcmp(name, "queue")) {
951 new_item->stype = F_QUEUE;
952 new_item->folder->queue = new_item;
953 } else if (!strcmp(name, "trash")) {
954 new_item->stype = F_TRASH;
955 new_item->folder->trash = new_item;
958 g_free(foldername);
959 g_free(path);
961 return new_item;
966 static gboolean claws_mailmbox_scan_required(Folder *folder, FolderItem *_item)
968 struct claws_mailmbox_folder * mbox;
969 MAILMBOXFolderItem *item = (MAILMBOXFolderItem *)_item;
970 int scan_required;
972 g_return_val_if_fail(folder != NULL, FALSE);
973 g_return_val_if_fail(item != NULL, FALSE);
975 if (item->item.path == NULL)
976 return FALSE;
978 mbox = get_mbox(_item, 0);
979 if (mbox == NULL)
980 return FALSE;
982 scan_required = (item->old_max_uid != item->mbox->mb_max_uid);
984 item->old_max_uid = item->mbox->mb_max_uid;
986 return scan_required;
990 static gint claws_mailmbox_rename_folder(Folder *folder,
991 FolderItem *item, const gchar *name)
993 gchar * path;
994 gchar * foldername;
995 FolderItem *parent;
997 g_return_val_if_fail(folder != NULL, -1);
998 g_return_val_if_fail(item != NULL, -1);
999 g_return_val_if_fail(item->path != NULL, -1);
1000 g_return_val_if_fail(name != NULL, -1);
1002 parent = folder_item_parent(item);
1003 g_return_val_if_fail(parent, -1);
1005 path = claws_mailmbox_get_new_path(parent, (gchar *) name);
1006 foldername = claws_mailmbox_get_folderitem_name((gchar *) name);
1008 if (rename(item->path, path) == -1) {
1009 g_free(foldername);
1010 g_free(path);
1011 debug_print("Cannot rename folder item\n");
1013 return -1;
1015 else {
1016 g_free(item->name);
1017 g_free(item->path);
1018 item->path = path;
1019 item->name = foldername;
1021 return 0;
1025 static gint claws_mailmbox_remove_folder(Folder *folder, FolderItem *item)
1027 g_return_val_if_fail(folder != NULL, -1);
1028 g_return_val_if_fail(item != NULL, -1);
1029 g_return_val_if_fail(item->path != NULL, -1);
1031 folder_item_remove(item);
1032 return 0;
1035 #define MAKE_DIR_IF_NOT_EXIST(dir) \
1037 if (!is_dir_exist(dir)) { \
1038 if (is_file_exist(dir)) { \
1039 debug_print("File `%s' already exists.\n" \
1040 "Can't create folder.", dir); \
1041 return -1; \
1043 if (mkdir(dir, S_IRWXU) < 0) { \
1044 FILE_OP_ERROR(dir, "mkdir"); \
1045 return -1; \
1047 if (chmod(dir, S_IRWXU) < 0) \
1048 FILE_OP_ERROR(dir, "chmod"); \
1052 static gint claws_mailmbox_create_tree(Folder *folder)
1054 gchar *rootpath;
1056 g_return_val_if_fail(folder != NULL, -1);
1058 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), -1);
1059 rootpath = LOCAL_FOLDER(folder)->rootpath;
1060 MAKE_DIR_IF_NOT_EXIST(rootpath);
1061 CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1);
1063 return 0;
1066 #undef MAKE_DIR_IF_NOT_EXIST
1069 static char * quote_mailbox(char * mb)
1071 char path[PATH_MAX];
1072 char * str;
1073 size_t remaining;
1074 char * p;
1076 remaining = sizeof(path) - 1;
1077 p = path;
1079 while (* mb != 0) {
1081 if (((* mb >= 'a') && (* mb <= 'z')) ||
1082 ((* mb >= 'A') && (* mb <= 'Z')) ||
1083 ((* mb >= '0') && (* mb <= '9'))) {
1084 if (remaining < 1)
1085 return NULL;
1086 * p = * mb;
1087 p ++;
1088 remaining --;
1090 else {
1091 if (remaining < 3)
1092 return NULL;
1093 * p = '%';
1094 p ++;
1095 snprintf(p, 3, "%02x", (unsigned char) (* mb));
1096 p += 2;
1098 mb ++;
1101 * p = 0;
1103 str = strdup(path);
1104 if (str == NULL)
1105 return NULL;
1107 return str;
1110 static gchar *claws_mailmbox_item_get_path(Folder *folder, FolderItem *item)
1112 gchar *itempath, *path;
1113 gchar * folderpath;
1115 if (item->path == NULL)
1116 return NULL;
1118 if (folder->name == NULL)
1119 return NULL;
1121 folderpath = quote_mailbox(folder->name);
1122 if (folderpath == NULL)
1123 return NULL;
1124 itempath = quote_mailbox(item->path);
1125 if (itempath == NULL) {
1126 free(folderpath);
1127 return NULL;
1129 path = g_strconcat(get_cache_dir(),
1130 G_DIR_SEPARATOR_S, folderpath,
1131 G_DIR_SEPARATOR_S, itempath, NULL);
1132 free(itempath);
1133 free(folderpath);
1135 return path;