1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-mbox-folder.c : Abstract class for an email folder */
5 * Author : Bertrand Guiheneuf <bertrand@helixcode.com>
7 * Copyright (C) 1999 Helix Code .
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include <sys/types.h>
37 #include "camel-mbox-folder.h"
38 #include "camel-mbox-store.h"
39 #include "string-utils.h"
40 #include "camel-log.h"
41 #include "camel-stream-buffered-fs.h"
42 #include "camel-folder-summary.h"
43 #include "camel-mbox-summary.h"
44 #include "camel-mbox-parser.h"
45 #include "camel-mbox-utils.h"
46 #include "md5-utils.h"
47 #include "gmime-utils.h"
48 #include "camel-mbox-search.h"
49 #include "camel-data-wrapper.h"
50 #include "camel-mime-message.h"
52 #include "camel-exception.h"
54 static CamelFolderClass *parent_class=NULL;
56 /* Returns the class for a CamelMboxFolder */
57 #define CMBOXF_CLASS(so) CAMEL_MBOX_FOLDER_CLASS (GTK_OBJECT(so)->klass)
58 #define CF_CLASS(so) CAMEL_FOLDER_CLASS (GTK_OBJECT(so)->klass)
59 #define CMBOXS_CLASS(so) CAMEL_STORE_CLASS (GTK_OBJECT(so)->klass)
62 static void _init_with_store (CamelFolder *folder, CamelStore *parent_store, CamelException *ex);
63 static void _set_name(CamelFolder *folder, const gchar *name, CamelException *ex);
66 static void _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex);
67 static void _close (CamelFolder *folder, gboolean expunge, CamelException *ex);
68 static gboolean _exists (CamelFolder *folder, CamelException *ex);
69 static gboolean _create(CamelFolder *folder, CamelException *ex);
70 static gboolean _delete (CamelFolder *folder, gboolean recurse, CamelException *ex);
71 static gboolean _delete_messages (CamelFolder *folder, CamelException *ex);
72 static GList *_list_subfolders (CamelFolder *folder, CamelException *ex);
73 /* static CamelMimeMessage *_get_message_by_number (CamelFolder *folder, gint number, CamelException *ex);*/
74 static gint _get_message_count (CamelFolder *folder, CamelException *ex);
75 static void _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex);
76 static GList *_get_uid_list (CamelFolder *folder, CamelException *ex);
77 static CamelMimeMessage *_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex);
79 static void _expunge (CamelFolder *folder, CamelException *ex);
80 static void _copy_message_to (CamelFolder *folder, CamelMimeMessage *message, CamelFolder *dest_folder, CamelException *ex);
81 static const gchar *_get_message_uid (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex);
84 static GList *search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
86 static void _finalize (GtkObject *object);
89 camel_mbox_folder_class_init (CamelMboxFolderClass *camel_mbox_folder_class)
91 CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_mbox_folder_class);
92 GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (camel_folder_class);
94 parent_class = gtk_type_class (camel_folder_get_type ());
96 /* virtual method definition */
98 /* virtual method overload */
99 camel_folder_class->init_with_store = _init_with_store;
100 camel_folder_class->set_name = _set_name;
101 camel_folder_class->open = _open;
102 camel_folder_class->close = _close;
103 camel_folder_class->exists = _exists;
104 camel_folder_class->create = _create;
105 camel_folder_class->delete = _delete;
106 camel_folder_class->delete_messages = _delete_messages;
107 camel_folder_class->list_subfolders = _list_subfolders;
108 /* camel_folder_class->get_message_by_number = _get_message_by_number; */
109 camel_folder_class->get_message_count = _get_message_count;
110 camel_folder_class->append_message = _append_message;
111 camel_folder_class->get_uid_list = _get_uid_list;
113 camel_folder_class->expunge = _expunge;
114 camel_folder_class->copy_message_to = _copy_message_to;
115 camel_folder_class->get_message_uid = _get_message_uid;
117 camel_folder_class->get_message_by_uid = _get_message_by_uid;
119 camel_folder_class->search_by_expression = search_by_expression;
121 gtk_object_class->finalize = _finalize;
128 _finalize (GtkObject *object)
130 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (object);
132 CAMEL_LOG_FULL_DEBUG ("Entering CamelFolder::finalize\n");
135 g_free (mbox_folder->folder_file_path);
136 g_free (mbox_folder->folder_dir_path);
138 GTK_OBJECT_CLASS (parent_class)->finalize (object);
139 CAMEL_LOG_FULL_DEBUG ("Leaving CamelFolder::finalize\n");
147 camel_mbox_folder_get_type (void)
149 static GtkType camel_mbox_folder_type = 0;
151 if (!camel_mbox_folder_type) {
152 GtkTypeInfo camel_mbox_folder_info =
155 sizeof (CamelMboxFolder),
156 sizeof (CamelMboxFolderClass),
157 (GtkClassInitFunc) camel_mbox_folder_class_init,
158 (GtkObjectInitFunc) NULL,
159 /* reserved_1 */ NULL,
160 /* reserved_2 */ NULL,
161 (GtkClassInitFunc) NULL,
164 camel_mbox_folder_type = gtk_type_unique (CAMEL_FOLDER_TYPE, &camel_mbox_folder_info);
167 return camel_mbox_folder_type;
176 _init_with_store (CamelFolder *folder, CamelStore *parent_store, CamelException *ex)
178 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
181 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::init_with_store\n");
183 /* call parent method */
184 parent_class->init_with_store (folder, parent_store, ex);
185 if (camel_exception_get_id (ex)) return;
187 /* we assume that the parent init_with_store
188 method checks for the existance of @folder */
190 folder->can_hold_messages = TRUE;
191 folder->can_hold_folders = TRUE;
192 folder->has_summary_capability = TRUE;
193 folder->has_uid_capability = TRUE;
194 folder->summary = camel_folder_summary_new ();
196 mbox_folder->folder_file_path = NULL;
197 mbox_folder->summary_file_path = NULL;
198 mbox_folder->folder_dir_path = NULL;
199 mbox_folder->index_file_path = NULL;
200 mbox_folder->internal_summary = NULL;
201 mbox_folder->uid_array = NULL;
203 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMhFolder::init_with_store\n");
208 /* internal method used to :
209 - test for the existence of a summary file
210 - test the sync between the summary and the mbox file
211 - load the summary or create it if necessary
214 _check_get_or_maybe_generate_summary_file (CamelMboxFolder *mbox_folder, CamelException *ex)
216 CamelFolder *folder = CAMEL_FOLDER (mbox_folder);
217 GArray *message_info_array;
218 gboolean summary_file_exists;
219 gboolean summary_file_is_sync;
220 GArray *mbox_summary_info;
225 /* test for the existence of the summary file */
226 summary_file_exists = (access (mbox_folder->summary_file_path, F_OK) == 0);
228 /* if the summary file exists, test if the
229 md5 of the mbox file is still in sync
230 with the one we had computed the last time
231 we saved the summary file */
232 if (summary_file_exists) {
234 summary_file_is_sync =
235 camel_mbox_check_summary_sync (mbox_folder->summary_file_path,
236 mbox_folder->folder_file_path,
238 if (camel_exception_get_id (ex)) return;
242 /* in the case where the summary does not exist
243 or is not in sync with the mbox file
245 if ( !(summary_file_exists && summary_file_is_sync)) {
247 /* parse the mbox folder and get some
248 information about the messages */
250 mbox_file_fd = open (mbox_folder->folder_file_path, O_RDONLY);
251 message_info_array = camel_mbox_parse_file (mbox_file_fd,
261 close (mbox_file_fd);
262 if (camel_exception_get_id (ex)) {
267 next_uid = camel_mbox_write_xev (mbox_folder->folder_file_path,
268 message_info_array, &file_size, next_uid, ex);
270 if (camel_exception_get_id (ex)) {
271 /* ** FIXME : free the preparsed information */
276 parsed_information_to_mbox_summary (message_info_array);
278 /* **FIXME : Free the parsed information structure */
280 /* allocate an internal summary object */
281 mbox_folder->internal_summary = g_new (CamelMboxSummary, 1);
283 /* generate the folder md5 signature */
284 md5_get_digest_from_file (mbox_folder->folder_file_path, mbox_folder->internal_summary->md5_digest);
286 /* store the number of messages as well as the summary array */
287 mbox_folder->internal_summary->nb_message = mbox_summary_info->len;
288 mbox_folder->internal_summary->next_uid = next_uid;
289 mbox_folder->internal_summary->mbox_file_size = file_size;
290 mbox_folder->internal_summary->message_info = mbox_summary_info;
293 /* every thing seems ok, just read the summary file from disk */
294 mbox_folder->internal_summary = camel_mbox_load_summary (mbox_folder->summary_file_path, ex);
297 /* copy the internal summary information to the external
298 folder summary used by the display engines */
299 camel_mbox_summary_append_internal_to_external (mbox_folder->internal_summary, folder->summary, 0);
305 _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex)
307 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
308 //struct dirent *dir_entry;
309 //struct stat stat_buf;
312 if (folder->open_state == FOLDER_OPEN) {
313 camel_exception_set (ex,
314 CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
315 "folder is already open");
321 /* get (or create) uid list */
322 //if (!(mbox_load_uid_list (mbox_folder) > 0))
323 // mbox_generate_uid_list (mbox_folder);
325 _check_get_or_maybe_generate_summary_file (mbox_folder, ex);
330 _close (CamelFolder *folder, gboolean expunge, CamelException *ex)
332 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
335 /* call parent implementation */
336 parent_class->close (folder, expunge, ex);
338 /* save the folder summary on disc */
339 camel_mbox_save_summary (mbox_folder->internal_summary, mbox_folder->summary_file_path, ex);
346 _set_name (CamelFolder *folder, const gchar *name, CamelException *ex)
348 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
349 const gchar *root_dir_path;
351 //const gchar *parent_full_name;
354 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::set_name\n");
356 /* call default implementation */
357 parent_class->set_name (folder, name, ex);
358 if (camel_exception_get_id (ex)) return;
360 g_free (mbox_folder->folder_file_path);
361 g_free (mbox_folder->folder_dir_path);
362 g_free (mbox_folder->index_file_path);
364 separator = camel_store_get_separator (folder->parent_store, ex);
365 root_dir_path = camel_mbox_store_get_toplevel_dir (CAMEL_MBOX_STORE(folder->parent_store));
367 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name full_name is %s\n", folder->full_name);
368 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name root_dir_path is %s\n", root_dir_path);
369 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::separator is %c\n", separator);
371 mbox_folder->folder_file_path = g_strdup_printf ("%s%c%s", root_dir_path, separator, folder->full_name);
372 mbox_folder->summary_file_path = g_strdup_printf ("%s%c%s-ev-summary", root_dir_path, separator, folder->full_name);
373 mbox_folder->folder_dir_path = g_strdup_printf ("%s%c%s.sdb", root_dir_path, separator, folder->full_name);
374 mbox_folder->index_file_path = g_strdup_printf ("%s%c%s.ibex", root_dir_path, separator, folder->full_name);
376 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name mbox_folder->folder_file_path is %s\n",
377 mbox_folder->folder_file_path);
378 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name mbox_folder->folder_dir_path is %s\n",
379 mbox_folder->folder_dir_path);
380 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::set_name\n");
389 _exists (CamelFolder *folder, CamelException *ex)
391 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
392 struct stat stat_buf;
396 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::exists\n");
398 /* check if the folder object exists */
400 camel_exception_set (ex,
401 CAMEL_EXCEPTION_FOLDER_NULL,
402 "folder object is NULL");
406 /* check if the mbox file path is determined */
407 if (!mbox_folder->folder_file_path) {
408 camel_exception_set (ex,
409 CAMEL_EXCEPTION_FOLDER_INVALID,
410 "undetermined folder file path. Maybe use set_name ?");
414 /* check if the mbox dir path is determined */
415 if (!mbox_folder->folder_dir_path) {
416 camel_exception_set (ex,
417 CAMEL_EXCEPTION_FOLDER_INVALID,
418 "undetermined folder directory path. Maybe use set_name ?");
423 /* we should not check for that here */
425 /* check if the mbox directory exists */
426 access_result = access (mbox_folder->folder_dir_path, F_OK);
427 if (access_result < 0) {
428 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists errot when executing access on %s\n",
429 mbox_folder->folder_dir_path);
430 CAMEL_LOG_FULL_DEBUG (" Full error text is : %s\n", strerror(errno));
431 camel_exception_set (ex,
432 CAMEL_EXCEPTION_SYSTEM,
436 stat_error = stat (mbox_folder->folder_dir_path, &stat_buf);
437 if (stat_error == -1) {
438 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists when executing stat on %s, stat_error = %d\n",
439 mbox_folder->folder_dir_path, stat_error);
440 CAMEL_LOG_FULL_DEBUG (" Full error text is : %s\n", strerror(errno));
441 camel_exception_set (ex,
442 CAMEL_EXCEPTION_SYSTEM,
446 exists = S_ISDIR (stat_buf.st_mode);
447 if (!exists) return FALSE;
451 /* check if the mbox file exists */
452 stat_error = stat (mbox_folder->folder_file_path, &stat_buf);
453 if (stat_error == -1)
456 exists = S_ISREG (stat_buf.st_mode);
457 /* we should check the rights here */
459 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::exists\n");
471 _create (CamelFolder *folder, CamelException *ex)
473 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
474 const gchar *folder_file_path, *folder_dir_path;
475 mode_t dir_mode = S_IRWXU;
477 gboolean folder_already_exists;
481 /* check if the folder object exists */
483 camel_exception_set (ex,
484 CAMEL_EXCEPTION_FOLDER_NULL,
485 "folder object is NULL");
490 /* call default implementation */
491 parent_class->create (folder, ex);
493 /* get the paths of what we need to create */
494 folder_file_path = mbox_folder->folder_file_path;
495 folder_dir_path = mbox_folder->folder_file_path;
497 if (!(folder_file_path || folder_dir_path)) {
498 camel_exception_set (ex,
499 CAMEL_EXCEPTION_FOLDER_INVALID,
500 "invalid folder path. Use set_name ?");
505 /* if the folder already exists, simply return */
506 folder_already_exists = camel_folder_exists (folder,ex);
507 if (camel_exception_get_id (ex)) return FALSE;
509 if (folder_already_exists) return TRUE;
512 /* create the directory for the subfolders */
513 mkdir_error = mkdir (folder_dir_path, dir_mode);
514 if (mkdir_error == -1) goto io_error;
517 /* create the mbox file */
518 /* it must be rw for the user and none for the others */
519 old_umask = umask (0700);
520 creat_fd = open (folder_file_path,
521 O_WRONLY | O_CREAT | O_APPEND,
524 if (creat_fd == -1) goto io_error;
527 /* create the summary object */
528 mbox_folder->internal_summary = g_new (CamelMboxSummary, 1);
529 mbox_folder->internal_summary->nb_message = 0;
530 mbox_folder->internal_summary->next_uid = 1;
531 mbox_folder->internal_summary->mbox_file_size = 0;
532 mbox_folder->internal_summary->message_info = g_array_new (FALSE, FALSE, sizeof (CamelMboxSummaryInformation));
536 /* exception handling for io errors */
539 CAMEL_LOG_WARNING ("CamelMboxFolder::create, error when creating %s and %s\n",
540 folder_dir_path, folder_file_path);
541 CAMEL_LOG_FULL_DEBUG ( " Full error text is : %s\n", strerror(errno));
543 if (errno == EACCES) {
544 camel_exception_set (ex,
545 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
546 "You don't have the permission to create the mbox file.");
549 camel_exception_set (ex,
550 CAMEL_EXCEPTION_SYSTEM,
551 "Unable to create the mbox file.");
564 _delete (CamelFolder *folder, gboolean recurse, CamelException *ex)
566 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
567 const gchar *folder_file_path, *folder_dir_path;
568 gint rmdir_error = 0;
569 gint unlink_error = 0;
570 gboolean folder_already_exists;
572 /* check if the folder object exists */
574 camel_exception_set (ex,
575 CAMEL_EXCEPTION_FOLDER_NULL,
576 "folder object is NULL");
581 /* in the case where the folder does not exist,
583 folder_already_exists = camel_folder_exists (folder, ex);
584 if (camel_exception_get_id (ex)) return FALSE;
586 if (!folder_already_exists) return TRUE;
589 /* call default implementation.
590 It should delete the messages in the folder
591 and recurse the operation to subfolders */
592 parent_class->delete (folder, recurse, ex);
595 /* get the paths of what we need to be deleted */
596 folder_file_path = mbox_folder->folder_file_path;
597 folder_dir_path = mbox_folder->folder_file_path;
599 if (!(folder_file_path || folder_dir_path)) {
600 camel_exception_set (ex,
601 CAMEL_EXCEPTION_FOLDER_INVALID,
602 "invalid folder path. Use set_name ?");
607 /* physically delete the directory */
608 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::delete removing directory %s\n", folder_dir_path);
609 rmdir_error = rmdir (folder_dir_path);
610 if (rmdir_error == -1)
613 camel_exception_set (ex,
614 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
615 "Not enough permission to delete the mbox folder");
620 camel_exception_set (ex,
621 CAMEL_EXCEPTION_FOLDER_NON_EMPTY,
622 "mbox folder not empty. Cannot delete it. Maybe use recurse flag ?");
626 camel_exception_set (ex,
627 CAMEL_EXCEPTION_SYSTEM,
628 "Unable to delete the mbox folder.");
632 /* physically delete the file */
633 unlink_error = unlink (folder_dir_path);
634 if (unlink_error == -1)
639 camel_exception_set (ex,
640 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
641 "Not enough permission to delete the mbox file");
649 camel_exception_set (ex,
650 CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
651 "Invalid mbox file");
656 camel_exception_set (ex,
657 CAMEL_EXCEPTION_SYSTEM,
658 "Unable to delete the mbox folder.");
670 _delete_messages (CamelFolder *folder, CamelException *ex)
673 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
674 const gchar *folder_file_path;
675 gboolean folder_already_exists;
680 /* check if the folder object exists */
682 camel_exception_set (ex,
683 CAMEL_EXCEPTION_FOLDER_NULL,
684 "folder object is NULL");
688 /* in the case where the folder does not exist,
690 folder_already_exists = camel_folder_exists (folder, ex);
691 if (camel_exception_get_id (ex)) return FALSE;
693 if (!folder_already_exists) return TRUE;
697 /* get the paths of the mbox file we need to delete */
698 folder_file_path = mbox_folder->folder_file_path;
700 if (!folder_file_path) {
701 camel_exception_set (ex,
702 CAMEL_EXCEPTION_FOLDER_INVALID,
703 "invalid folder path. Use set_name ?");
708 /* create the mbox file */
709 /* it must be rw for the user and none for the others */
710 old_umask = umask (0700);
711 creat_fd = open (folder_file_path,
715 if (creat_fd == -1) goto io_error;
720 /* exception handling for io errors */
723 CAMEL_LOG_WARNING ("CamelMboxFolder::create, error when deleting files %s\n",
725 CAMEL_LOG_FULL_DEBUG ( " Full error text is : %s\n", strerror(errno));
727 if (errno == EACCES) {
728 camel_exception_set (ex,
729 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
730 "You don't have the permission to write in the mbox file.");
733 camel_exception_set (ex,
734 CAMEL_EXCEPTION_SYSTEM,
735 "Unable to write in the mbox file.");
751 _list_subfolders (CamelFolder *folder, CamelException *ex)
753 GList *subfolder_name_list = NULL;
755 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
756 const gchar *folder_dir_path;
757 gboolean folder_exists;
759 struct stat stat_buf;
763 gchar *full_entry_name;
764 gchar *real_folder_name;
765 struct dirent *dir_entry;
767 gboolean folder_suffix_found;
769 //gchar *io_error_text;
773 /* check if the folder object exists */
775 camel_exception_set (ex,
776 CAMEL_EXCEPTION_FOLDER_NULL,
777 "folder object is NULL");
782 /* in the case the folder does not exist,
783 raise an exception */
784 folder_exists = camel_folder_exists (folder, ex);
785 if (camel_exception_get_id (ex)) return FALSE;
787 if (!folder_exists) {
788 camel_exception_set (ex,
789 CAMEL_EXCEPTION_FOLDER_INVALID,
790 "Inexistant folder.");
795 /* get the mbox subfolders directories */
796 folder_dir_path = mbox_folder->folder_file_path;
797 if (!folder_dir_path) {
798 camel_exception_set (ex,
799 CAMEL_EXCEPTION_FOLDER_INVALID,
800 "Invalid folder path. Use set_name ?");
805 dir_handle = opendir (folder_dir_path);
807 /* read the first entry in the directory */
808 dir_entry = readdir (dir_handle);
809 while ((stat_error != -1) && (dir_entry != NULL)) {
811 /* get the name of the next entry in the dir */
812 entry_name = dir_entry->d_name;
813 full_entry_name = g_strdup_printf ("%s/%s", folder_dir_path, entry_name);
814 stat_error = stat (full_entry_name, &stat_buf);
815 g_free (full_entry_name);
817 /* is it a directory ? */
818 if ((stat_error != -1) && S_ISDIR (stat_buf.st_mode)) {
819 /* yes, add it to the list */
820 if (entry_name[0] != '.') {
821 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::list_subfolders adding "
824 /* if the folder is a netscape folder, remove the
825 ".sdb" from the name */
826 real_folder_name = string_prefix (entry_name, ".sdb", &folder_suffix_found);
827 /* stick here the tests for other folder suffixes if any */
829 if (!folder_suffix_found) real_folder_name = g_strdup (entry_name);
831 /* add the folder name to the list */
832 subfolder_name_list = g_list_append (subfolder_name_list,
836 /* read next entry */
837 dir_entry = readdir (dir_handle);
840 closedir (dir_handle);
842 return subfolder_name_list;
846 /* io exception handling */
850 camel_exception_setv (ex,
851 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
852 "Unable to list the directory. Full Error text is : %s ",
858 camel_exception_setv (ex,
859 CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
860 "Invalid mbox folder path. Full Error text is : %s ",
865 camel_exception_set (ex,
866 CAMEL_EXCEPTION_SYSTEM,
867 "Unable to delete the mbox folder.");
871 g_list_free (subfolder_name_list);
879 _get_message_count (CamelFolder *folder, CamelException *ex)
882 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
886 g_assert (mbox_folder->internal_summary);
888 message_count = mbox_folder->internal_summary->nb_message;
890 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::get_message_count found %d messages\n", message_count);
891 return message_count;
896 _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex)
898 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
899 //guint new_msg_number;
900 CamelStream *output_stream;
901 guint32 tmp_file_size;
904 GArray *message_info_array;
905 GArray *mbox_summary_info;
906 gchar *tmp_message_filename;
910 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::append_message\n");
912 tmp_message_filename = g_strdup_printf ("%s.tmp", mbox_folder->folder_file_path);
913 /* write the message itself */
914 output_stream = camel_stream_fs_new_with_name (tmp_message_filename, CAMEL_STREAM_FS_WRITE);
915 if (output_stream != NULL) {
916 camel_stream_write_string (output_stream, "From - \n");
917 camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), output_stream);
919 camel_stream_close (output_stream);
921 /* at this point we have saved the message to a
922 temporary file, now, we have to add the x-evolution
923 field and also update the main summary summary */
926 First : parse the mbox file, but only from the
927 position where the message has been added,
928 wich happens to be the last postion in the
929 mbox file before we added the message.
930 This position is still stored in the summary
933 next_uid = mbox_folder->internal_summary->next_uid;
934 tmp_file_fd = open (tmp_message_filename, O_RDONLY);
935 message_info_array = camel_mbox_parse_file (tmp_file_fd,
947 /* get the value of the last available UID
948 as saved in the summary file */
949 next_uid = mbox_folder->internal_summary->next_uid;
952 OK, this is not very efficient, we should not use the same
953 method as for parsing an entire mail file,
954 but I have no time to write a simpler parser
956 next_uid = camel_mbox_write_xev (tmp_message_filename,
957 message_info_array, &tmp_file_size, next_uid, ex);
959 if (camel_exception_get_id (ex)) {
960 /* ** FIXME : free the preparsed information */
965 parsed_information_to_mbox_summary (message_info_array);
970 /* store the number of messages as well as the summary array */
971 mbox_folder->internal_summary->nb_message += 1;
972 mbox_folder->internal_summary->next_uid = next_uid;
974 ((CamelMboxSummaryInformation *)(mbox_summary_info->data))->position += mbox_folder->internal_summary->mbox_file_size;
975 mbox_folder->internal_summary->mbox_file_size += tmp_file_size;
977 camel_mbox_summary_append_entries (mbox_folder->internal_summary, mbox_summary_info);
979 /* append the new entry of the internal summary to
980 the external summary */
981 camel_mbox_summary_append_internal_to_external (mbox_folder->internal_summary,
983 mbox_folder->internal_summary->nb_message-1);
985 g_array_free (mbox_summary_info, TRUE);
988 /* append the temporary file message to the mbox file */
989 fd1 = open (tmp_message_filename, O_RDONLY);
990 fd2 = open (mbox_folder->folder_file_path,
991 O_WRONLY | O_CREAT | O_APPEND,
995 camel_exception_setv (ex,
996 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
997 "could not open the mbox folder file for appending the message\n"
999 "Full error is : %s\n",
1000 mbox_folder->folder_file_path,
1005 camel_mbox_copy_file_chunk (fd1,
1012 /* remove the temporary file */
1013 unlink (tmp_message_filename);
1015 /* generate the folder md5 signature */
1016 md5_get_digest_from_file (mbox_folder->folder_file_path, mbox_folder->internal_summary->md5_digest);
1019 g_free (tmp_message_filename);
1020 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::append_message\n");
1027 _get_uid_list (CamelFolder *folder, CamelException *ex)
1029 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
1030 GArray *message_info_array;
1031 CamelMboxSummaryInformation *message_info;
1032 GList *uid_list = NULL;
1035 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::get_uid_list\n");
1037 message_info_array = mbox_folder->internal_summary->message_info;
1039 for (i=0; i<message_info_array->len; i++) {
1041 message_info = (CamelMboxSummaryInformation *)(message_info_array->data) + i;
1042 uid_list = g_list_prepend (uid_list, g_strdup_printf ("%u", message_info->uid));
1045 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1057 static CamelMimeMessage *
1058 _get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex)
1061 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
1062 GArray *message_info_array;
1063 CamelMboxSummaryInformation *message_info;
1064 guint32 searched_uid;
1067 CamelStream *message_stream;
1068 CamelMimeMessage *message = NULL;
1069 CamelStore *parent_store;
1071 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::get_uid_list\n");
1073 searched_uid = strtoul(uid, (char **)NULL, 10);
1075 message_info_array = mbox_folder->internal_summary->message_info;
1079 /* first, look for the message that has the searched uid */
1080 while ((i<message_info_array->len) && (!uid_found)) {
1081 message_info = (CamelMboxSummaryInformation *)(message_info_array->data) + i;
1082 uid_found = (message_info->uid == searched_uid);
1086 /* if the uid was not found, raise an exception and return */
1088 camel_exception_setv (ex,
1089 CAMEL_EXCEPTION_FOLDER_INVALID_UID,
1090 "uid %s not found in the folder",
1092 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1096 /* at this point, the message_info structure
1097 contains the informations concerning the
1098 message that was searched for */
1100 /* create a stream bound to the message */
1101 message_stream = camel_stream_fs_new_with_name_and_bounds (mbox_folder->folder_file_path,
1102 CAMEL_STREAM_FS_READ,
1103 message_info->position,
1104 message_info->position + message_info->size);
1107 /* get the parent store */
1108 parent_store = camel_folder_get_parent_store (folder, ex);
1109 if (camel_exception_get_id (ex)) {
1110 gtk_object_unref (GTK_OBJECT (message_stream));
1115 message = camel_mime_message_new_with_session (camel_service_get_session (CAMEL_SERVICE (parent_store)));
1116 camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (message), message_stream);
1121 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1126 search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
1128 return camel_mbox_folder_search_by_expression(folder, expression, ex);