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 (CamelFolder *folder, CamelStore *parent_store,
63 CamelFolder *parent_folder, const gchar *name,
64 gchar separator, CamelException *ex);
65 static void _set_name(CamelFolder *folder, const gchar *name, CamelException *ex);
68 static void _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex);
69 static void _close (CamelFolder *folder, gboolean expunge, CamelException *ex);
70 static gboolean _exists (CamelFolder *folder, CamelException *ex);
71 static gboolean _create(CamelFolder *folder, CamelException *ex);
72 static gboolean _delete (CamelFolder *folder, gboolean recurse, CamelException *ex);
73 static gboolean _delete_messages (CamelFolder *folder, CamelException *ex);
74 static GList *_list_subfolders (CamelFolder *folder, CamelException *ex);
75 /* static CamelMimeMessage *_get_message_by_number (CamelFolder *folder, gint number, CamelException *ex);*/
76 static gint _get_message_count (CamelFolder *folder, CamelException *ex);
77 static void _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex);
78 static GList *_get_uid_list (CamelFolder *folder, CamelException *ex);
79 static CamelMimeMessage *_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex);
81 static void _expunge (CamelFolder *folder, CamelException *ex);
82 static void _copy_message_to (CamelFolder *folder, CamelMimeMessage *message, CamelFolder *dest_folder, CamelException *ex);
83 static const gchar *_get_message_uid (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex);
86 static GList *search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
88 static void _finalize (GtkObject *object);
91 camel_mbox_folder_class_init (CamelMboxFolderClass *camel_mbox_folder_class)
93 CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_mbox_folder_class);
94 GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (camel_folder_class);
96 parent_class = gtk_type_class (camel_folder_get_type ());
98 /* virtual method definition */
100 /* virtual method overload */
101 camel_folder_class->init = _init;
102 camel_folder_class->set_name = _set_name;
103 camel_folder_class->open = _open;
104 camel_folder_class->close = _close;
105 camel_folder_class->exists = _exists;
106 camel_folder_class->create = _create;
107 camel_folder_class->delete = _delete;
108 camel_folder_class->delete_messages = _delete_messages;
109 camel_folder_class->list_subfolders = _list_subfolders;
110 /* camel_folder_class->get_message_by_number = _get_message_by_number; */
111 camel_folder_class->get_message_count = _get_message_count;
112 camel_folder_class->append_message = _append_message;
113 camel_folder_class->get_uid_list = _get_uid_list;
115 camel_folder_class->expunge = _expunge;
116 camel_folder_class->copy_message_to = _copy_message_to;
117 camel_folder_class->get_message_uid = _get_message_uid;
119 camel_folder_class->get_message_by_uid = _get_message_by_uid;
121 camel_folder_class->search_by_expression = search_by_expression;
123 gtk_object_class->finalize = _finalize;
130 _finalize (GtkObject *object)
132 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (object);
134 CAMEL_LOG_FULL_DEBUG ("Entering CamelFolder::finalize\n");
137 g_free (mbox_folder->folder_file_path);
138 g_free (mbox_folder->folder_dir_path);
140 GTK_OBJECT_CLASS (parent_class)->finalize (object);
141 CAMEL_LOG_FULL_DEBUG ("Leaving CamelFolder::finalize\n");
149 camel_mbox_folder_get_type (void)
151 static GtkType camel_mbox_folder_type = 0;
153 if (!camel_mbox_folder_type) {
154 GtkTypeInfo camel_mbox_folder_info =
157 sizeof (CamelMboxFolder),
158 sizeof (CamelMboxFolderClass),
159 (GtkClassInitFunc) camel_mbox_folder_class_init,
160 (GtkObjectInitFunc) NULL,
161 /* reserved_1 */ NULL,
162 /* reserved_2 */ NULL,
163 (GtkClassInitFunc) NULL,
166 camel_mbox_folder_type = gtk_type_unique (CAMEL_FOLDER_TYPE, &camel_mbox_folder_info);
169 return camel_mbox_folder_type;
178 _init (CamelFolder *folder, CamelStore *parent_store,
179 CamelFolder *parent_folder, const gchar *name, gchar separator,
182 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
185 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::init_with_store\n");
187 /* call parent method */
188 parent_class->init (folder, parent_store, parent_folder,
189 name, separator, ex);
190 if (camel_exception_get_id (ex)) return;
192 /* we assume that the parent init
193 method checks for the existance of @folder */
195 folder->can_hold_messages = TRUE;
196 folder->can_hold_folders = TRUE;
197 folder->has_summary_capability = TRUE;
198 folder->has_uid_capability = TRUE;
199 folder->summary = camel_folder_summary_new ();
201 mbox_folder->folder_file_path = NULL;
202 mbox_folder->summary_file_path = NULL;
203 mbox_folder->folder_dir_path = NULL;
204 mbox_folder->index_file_path = NULL;
205 mbox_folder->internal_summary = NULL;
206 mbox_folder->uid_array = NULL;
208 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::init_with_store\n");
213 /* internal method used to :
214 - test for the existence of a summary file
215 - test the sync between the summary and the mbox file
216 - load the summary or create it if necessary
219 _check_get_or_maybe_generate_summary_file (CamelMboxFolder *mbox_folder, CamelException *ex)
221 CamelFolder *folder = CAMEL_FOLDER (mbox_folder);
222 GArray *message_info_array;
223 gboolean summary_file_exists;
224 gboolean summary_file_is_sync;
225 GArray *mbox_summary_info;
230 /* test for the existence of the summary file */
231 summary_file_exists = (access (mbox_folder->summary_file_path, F_OK) == 0);
233 /* if the summary file exists, test if the
234 md5 of the mbox file is still in sync
235 with the one we had computed the last time
236 we saved the summary file */
237 if (summary_file_exists) {
239 summary_file_is_sync =
240 camel_mbox_check_summary_sync (mbox_folder->summary_file_path,
241 mbox_folder->folder_file_path,
243 if (camel_exception_get_id (ex)) return;
247 /* in the case where the summary does not exist
248 or is not in sync with the mbox file
250 if ( !(summary_file_exists && summary_file_is_sync)) {
252 /* parse the mbox folder and get some
253 information about the messages */
255 mbox_file_fd = open (mbox_folder->folder_file_path, O_RDONLY);
256 message_info_array = camel_mbox_parse_file (mbox_file_fd,
266 close (mbox_file_fd);
267 if (camel_exception_get_id (ex)) {
272 next_uid = camel_mbox_write_xev (mbox_folder->folder_file_path,
273 message_info_array, &file_size, next_uid, ex);
275 if (camel_exception_get_id (ex)) {
276 /* ** FIXME : free the preparsed information */
281 parsed_information_to_mbox_summary (message_info_array);
283 /* **FIXME : Free the parsed information structure */
285 /* allocate an internal summary object */
286 mbox_folder->internal_summary = g_new (CamelMboxSummary, 1);
288 /* generate the folder md5 signature */
289 md5_get_digest_from_file (mbox_folder->folder_file_path, mbox_folder->internal_summary->md5_digest);
291 /* store the number of messages as well as the summary array */
292 mbox_folder->internal_summary->nb_message = mbox_summary_info->len;
293 mbox_folder->internal_summary->next_uid = next_uid;
294 mbox_folder->internal_summary->mbox_file_size = file_size;
295 mbox_folder->internal_summary->message_info = mbox_summary_info;
298 /* every thing seems ok, just read the summary file from disk */
299 mbox_folder->internal_summary = camel_mbox_load_summary (mbox_folder->summary_file_path, ex);
302 /* copy the internal summary information to the external
303 folder summary used by the display engines */
304 camel_mbox_summary_append_internal_to_external (mbox_folder->internal_summary, folder->summary, 0);
310 _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex)
312 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
313 //struct dirent *dir_entry;
314 //struct stat stat_buf;
317 if (folder->open_state == FOLDER_OPEN) {
318 camel_exception_set (ex,
319 CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
320 "folder is already open");
326 /* get (or create) uid list */
327 //if (!(mbox_load_uid_list (mbox_folder) > 0))
328 // mbox_generate_uid_list (mbox_folder);
330 _check_get_or_maybe_generate_summary_file (mbox_folder, ex);
335 _close (CamelFolder *folder, gboolean expunge, CamelException *ex)
337 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
340 /* call parent implementation */
341 parent_class->close (folder, expunge, ex);
343 /* save the folder summary on disc */
344 camel_mbox_save_summary (mbox_folder->internal_summary, mbox_folder->summary_file_path, ex);
351 _set_name (CamelFolder *folder, const gchar *name, CamelException *ex)
353 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
354 const gchar *root_dir_path;
356 //const gchar *parent_full_name;
358 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::set_name\n");
360 /* call default implementation */
361 parent_class->set_name (folder, name, ex);
362 if (camel_exception_get_id (ex)) return;
364 g_free (mbox_folder->folder_file_path);
365 g_free (mbox_folder->folder_dir_path);
366 g_free (mbox_folder->index_file_path);
368 root_dir_path = camel_mbox_store_get_toplevel_dir (CAMEL_MBOX_STORE(folder->parent_store));
370 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name full_name is %s\n", folder->full_name);
371 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name root_dir_path is %s\n", root_dir_path);
373 mbox_folder->folder_file_path = g_strdup_printf ("%s/%s", root_dir_path, folder->full_name);
374 mbox_folder->summary_file_path = g_strdup_printf ("%s/%s-ev-summary", root_dir_path, folder->full_name);
375 mbox_folder->folder_dir_path = g_strdup_printf ("%s/%s.sdb", root_dir_path, folder->full_name);
376 mbox_folder->index_file_path = g_strdup_printf ("%s/%s.ibex", root_dir_path, folder->full_name);
378 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name mbox_folder->folder_file_path is %s\n",
379 mbox_folder->folder_file_path);
380 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name mbox_folder->folder_dir_path is %s\n",
381 mbox_folder->folder_dir_path);
382 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::set_name\n");
391 _exists (CamelFolder *folder, CamelException *ex)
393 CamelMboxFolder *mbox_folder;
394 struct stat stat_buf;
398 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::exists\n");
401 /* check if the folder object exists */
403 camel_exception_set (ex,
404 CAMEL_EXCEPTION_FOLDER_NULL,
405 "folder object is NULL");
409 mbox_folder = CAMEL_MBOX_FOLDER(folder);
412 /* check if the mbox file path is determined */
413 if (!mbox_folder->folder_file_path) {
414 camel_exception_set (ex,
415 CAMEL_EXCEPTION_FOLDER_INVALID,
416 "undetermined folder file path. Maybe use set_name ?");
420 /* check if the mbox dir path is determined */
421 if (!mbox_folder->folder_dir_path) {
422 camel_exception_set (ex,
423 CAMEL_EXCEPTION_FOLDER_INVALID,
424 "undetermined folder directory path. Maybe use set_name ?");
429 /* we should not check for that here */
431 /* check if the mbox directory exists */
432 access_result = access (mbox_folder->folder_dir_path, F_OK);
433 if (access_result < 0) {
434 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists errot when executing access on %s\n",
435 mbox_folder->folder_dir_path);
436 CAMEL_LOG_FULL_DEBUG (" Full error text is : %s\n", strerror(errno));
437 camel_exception_set (ex,
438 CAMEL_EXCEPTION_SYSTEM,
442 stat_error = stat (mbox_folder->folder_dir_path, &stat_buf);
443 if (stat_error == -1) {
444 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists when executing stat on %s, stat_error = %d\n",
445 mbox_folder->folder_dir_path, stat_error);
446 CAMEL_LOG_FULL_DEBUG (" Full error text is : %s\n", strerror(errno));
447 camel_exception_set (ex,
448 CAMEL_EXCEPTION_SYSTEM,
452 exists = S_ISDIR (stat_buf.st_mode);
453 if (!exists) return FALSE;
457 /* check if the mbox file exists */
458 stat_error = stat (mbox_folder->folder_file_path, &stat_buf);
459 if (stat_error == -1)
462 exists = S_ISREG (stat_buf.st_mode);
463 /* we should check the rights here */
465 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::exists\n");
477 _create (CamelFolder *folder, CamelException *ex)
479 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
480 const gchar *folder_file_path, *folder_dir_path;
481 mode_t dir_mode = S_IRWXU;
483 gboolean folder_already_exists;
487 /* check if the folder object exists */
489 camel_exception_set (ex,
490 CAMEL_EXCEPTION_FOLDER_NULL,
491 "folder object is NULL");
496 /* call default implementation */
497 parent_class->create (folder, ex);
499 /* get the paths of what we need to create */
500 folder_file_path = mbox_folder->folder_file_path;
501 folder_dir_path = mbox_folder->folder_dir_path;
503 if (!(folder_file_path || folder_dir_path)) {
504 camel_exception_set (ex,
505 CAMEL_EXCEPTION_FOLDER_INVALID,
506 "invalid folder path. Use set_name ?");
511 /* if the folder already exists, simply return */
512 folder_already_exists = camel_folder_exists (folder,ex);
513 if (camel_exception_get_id (ex)) return FALSE;
515 if (folder_already_exists) return TRUE;
518 /* create the directory for the subfolders */
519 mkdir_error = mkdir (folder_dir_path, dir_mode);
520 if (mkdir_error == -1) goto io_error;
523 /* create the mbox file */
524 /* it must be rw for the user and none for the others */
525 old_umask = umask (0700);
526 creat_fd = open (folder_file_path,
527 O_WRONLY | O_CREAT | O_APPEND,
530 if (creat_fd == -1) goto io_error;
533 /* create the summary object */
534 mbox_folder->internal_summary = g_new (CamelMboxSummary, 1);
535 mbox_folder->internal_summary->nb_message = 0;
536 mbox_folder->internal_summary->next_uid = 1;
537 mbox_folder->internal_summary->mbox_file_size = 0;
538 mbox_folder->internal_summary->message_info = g_array_new (FALSE, FALSE, sizeof (CamelMboxSummaryInformation));
542 /* exception handling for io errors */
545 CAMEL_LOG_WARNING ("CamelMboxFolder::create, error when creating %s and %s\n",
546 folder_dir_path, folder_file_path);
547 CAMEL_LOG_FULL_DEBUG ( " Full error text is : %s\n", strerror(errno));
549 if (errno == EACCES) {
550 camel_exception_set (ex,
551 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
552 "You don't have the permission to create the mbox file.");
555 camel_exception_set (ex,
556 CAMEL_EXCEPTION_SYSTEM,
557 "Unable to create the mbox file.");
570 _delete (CamelFolder *folder, gboolean recurse, CamelException *ex)
572 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
573 const gchar *folder_file_path, *folder_dir_path;
574 gint rmdir_error = 0;
575 gint unlink_error = 0;
576 gboolean folder_already_exists;
578 /* check if the folder object exists */
580 camel_exception_set (ex,
581 CAMEL_EXCEPTION_FOLDER_NULL,
582 "folder object is NULL");
587 /* in the case where the folder does not exist,
589 folder_already_exists = camel_folder_exists (folder, ex);
590 if (camel_exception_get_id (ex)) return FALSE;
592 if (!folder_already_exists) return TRUE;
595 /* call default implementation.
596 It should delete the messages in the folder
597 and recurse the operation to subfolders */
598 parent_class->delete (folder, recurse, ex);
601 /* get the paths of what we need to be deleted */
602 folder_file_path = mbox_folder->folder_file_path;
603 folder_dir_path = mbox_folder->folder_file_path;
605 if (!(folder_file_path || folder_dir_path)) {
606 camel_exception_set (ex,
607 CAMEL_EXCEPTION_FOLDER_INVALID,
608 "invalid folder path. Use set_name ?");
613 /* physically delete the directory */
614 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::delete removing directory %s\n", folder_dir_path);
615 rmdir_error = rmdir (folder_dir_path);
616 if (rmdir_error == -1)
619 camel_exception_set (ex,
620 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
621 "Not enough permission to delete the mbox folder");
626 camel_exception_set (ex,
627 CAMEL_EXCEPTION_FOLDER_NON_EMPTY,
628 "mbox folder not empty. Cannot delete it. Maybe use recurse flag ?");
632 camel_exception_set (ex,
633 CAMEL_EXCEPTION_SYSTEM,
634 "Unable to delete the mbox folder.");
638 /* physically delete the file */
639 unlink_error = unlink (folder_dir_path);
640 if (unlink_error == -1)
645 camel_exception_set (ex,
646 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
647 "Not enough permission to delete the mbox file");
655 camel_exception_set (ex,
656 CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
657 "Invalid mbox file");
662 camel_exception_set (ex,
663 CAMEL_EXCEPTION_SYSTEM,
664 "Unable to delete the mbox folder.");
676 _delete_messages (CamelFolder *folder, CamelException *ex)
679 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
680 const gchar *folder_file_path;
681 gboolean folder_already_exists;
686 /* check if the folder object exists */
688 camel_exception_set (ex,
689 CAMEL_EXCEPTION_FOLDER_NULL,
690 "folder object is NULL");
694 /* in the case where the folder does not exist,
696 folder_already_exists = camel_folder_exists (folder, ex);
697 if (camel_exception_get_id (ex)) return FALSE;
699 if (!folder_already_exists) return TRUE;
703 /* get the paths of the mbox file we need to delete */
704 folder_file_path = mbox_folder->folder_file_path;
706 if (!folder_file_path) {
707 camel_exception_set (ex,
708 CAMEL_EXCEPTION_FOLDER_INVALID,
709 "invalid folder path. Use set_name ?");
714 /* create the mbox file */
715 /* it must be rw for the user and none for the others */
716 old_umask = umask (0700);
717 creat_fd = open (folder_file_path,
721 if (creat_fd == -1) goto io_error;
726 /* exception handling for io errors */
729 CAMEL_LOG_WARNING ("CamelMboxFolder::create, error when deleting files %s\n",
731 CAMEL_LOG_FULL_DEBUG ( " Full error text is : %s\n", strerror(errno));
733 if (errno == EACCES) {
734 camel_exception_set (ex,
735 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
736 "You don't have the permission to write in the mbox file.");
739 camel_exception_set (ex,
740 CAMEL_EXCEPTION_SYSTEM,
741 "Unable to write in the mbox file.");
757 _list_subfolders (CamelFolder *folder, CamelException *ex)
759 GList *subfolder_name_list = NULL;
761 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
762 const gchar *folder_dir_path;
763 gboolean folder_exists;
765 struct stat stat_buf;
769 gchar *full_entry_name;
770 gchar *real_folder_name;
771 struct dirent *dir_entry;
773 gboolean folder_suffix_found;
775 //gchar *io_error_text;
779 /* check if the folder object exists */
781 camel_exception_set (ex,
782 CAMEL_EXCEPTION_FOLDER_NULL,
783 "folder object is NULL");
788 /* in the case the folder does not exist,
789 raise an exception */
790 folder_exists = camel_folder_exists (folder, ex);
791 if (camel_exception_get_id (ex)) return FALSE;
793 if (!folder_exists) {
794 camel_exception_set (ex,
795 CAMEL_EXCEPTION_FOLDER_INVALID,
796 "Inexistant folder.");
801 /* get the mbox subfolders directories */
802 folder_dir_path = mbox_folder->folder_file_path;
803 if (!folder_dir_path) {
804 camel_exception_set (ex,
805 CAMEL_EXCEPTION_FOLDER_INVALID,
806 "Invalid folder path. Use set_name ?");
811 dir_handle = opendir (folder_dir_path);
813 /* read the first entry in the directory */
814 dir_entry = readdir (dir_handle);
815 while ((stat_error != -1) && (dir_entry != NULL)) {
817 /* get the name of the next entry in the dir */
818 entry_name = dir_entry->d_name;
819 full_entry_name = g_strdup_printf ("%s/%s", folder_dir_path, entry_name);
820 stat_error = stat (full_entry_name, &stat_buf);
821 g_free (full_entry_name);
823 /* is it a directory ? */
824 if ((stat_error != -1) && S_ISDIR (stat_buf.st_mode)) {
825 /* yes, add it to the list */
826 if (entry_name[0] != '.') {
827 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::list_subfolders adding "
830 /* if the folder is a netscape folder, remove the
831 ".sdb" from the name */
832 real_folder_name = string_prefix (entry_name, ".sdb", &folder_suffix_found);
833 /* stick here the tests for other folder suffixes if any */
835 if (!folder_suffix_found) real_folder_name = g_strdup (entry_name);
837 /* add the folder name to the list */
838 subfolder_name_list = g_list_append (subfolder_name_list,
842 /* read next entry */
843 dir_entry = readdir (dir_handle);
846 closedir (dir_handle);
848 return subfolder_name_list;
852 /* io exception handling */
856 camel_exception_setv (ex,
857 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
858 "Unable to list the directory. Full Error text is : %s ",
864 camel_exception_setv (ex,
865 CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
866 "Invalid mbox folder path. Full Error text is : %s ",
871 camel_exception_set (ex,
872 CAMEL_EXCEPTION_SYSTEM,
873 "Unable to delete the mbox folder.");
877 g_list_free (subfolder_name_list);
885 _get_message_count (CamelFolder *folder, CamelException *ex)
888 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
892 g_assert (mbox_folder->internal_summary);
894 message_count = mbox_folder->internal_summary->nb_message;
896 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::get_message_count found %d messages\n", message_count);
897 return message_count;
902 _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex)
904 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
905 //guint new_msg_number;
906 CamelStream *output_stream;
907 guint32 tmp_file_size;
910 GArray *message_info_array;
911 GArray *mbox_summary_info;
912 gchar *tmp_message_filename;
916 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::append_message\n");
918 tmp_message_filename = g_strdup_printf ("%s.tmp", mbox_folder->folder_file_path);
919 /* write the message itself */
920 output_stream = camel_stream_fs_new_with_name (tmp_message_filename, CAMEL_STREAM_FS_WRITE);
921 if (output_stream != NULL) {
922 camel_stream_write_string (output_stream, "From - \n");
923 camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), output_stream);
925 camel_stream_close (output_stream);
927 /* at this point we have saved the message to a
928 temporary file, now, we have to add the x-evolution
929 field and also update the main summary summary */
932 First : parse the mbox file, but only from the
933 position where the message has been added,
934 wich happens to be the last postion in the
935 mbox file before we added the message.
936 This position is still stored in the summary
939 next_uid = mbox_folder->internal_summary->next_uid;
940 tmp_file_fd = open (tmp_message_filename, O_RDONLY);
941 message_info_array = camel_mbox_parse_file (tmp_file_fd,
953 /* get the value of the last available UID
954 as saved in the summary file */
955 next_uid = mbox_folder->internal_summary->next_uid;
958 OK, this is not very efficient, we should not use the same
959 method as for parsing an entire mail file,
960 but I have no time to write a simpler parser
962 next_uid = camel_mbox_write_xev (tmp_message_filename,
963 message_info_array, &tmp_file_size, next_uid, ex);
965 if (camel_exception_get_id (ex)) {
966 /* ** FIXME : free the preparsed information */
971 parsed_information_to_mbox_summary (message_info_array);
976 /* store the number of messages as well as the summary array */
977 mbox_folder->internal_summary->nb_message += 1;
978 mbox_folder->internal_summary->next_uid = next_uid;
980 ((CamelMboxSummaryInformation *)(mbox_summary_info->data))->position += mbox_folder->internal_summary->mbox_file_size;
981 mbox_folder->internal_summary->mbox_file_size += tmp_file_size;
983 camel_mbox_summary_append_entries (mbox_folder->internal_summary, mbox_summary_info);
985 /* append the new entry of the internal summary to
986 the external summary */
987 camel_mbox_summary_append_internal_to_external (mbox_folder->internal_summary,
989 mbox_folder->internal_summary->nb_message-1);
991 g_array_free (mbox_summary_info, TRUE);
994 /* append the temporary file message to the mbox file */
995 fd1 = open (tmp_message_filename, O_RDONLY);
996 fd2 = open (mbox_folder->folder_file_path,
997 O_WRONLY | O_CREAT | O_APPEND,
1001 camel_exception_setv (ex,
1002 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
1003 "could not open the mbox folder file for appending the message\n"
1005 "Full error is : %s\n",
1006 mbox_folder->folder_file_path,
1011 camel_mbox_copy_file_chunk (fd1,
1018 /* remove the temporary file */
1019 unlink (tmp_message_filename);
1021 /* generate the folder md5 signature */
1022 md5_get_digest_from_file (mbox_folder->folder_file_path, mbox_folder->internal_summary->md5_digest);
1025 g_free (tmp_message_filename);
1026 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::append_message\n");
1033 _get_uid_list (CamelFolder *folder, CamelException *ex)
1035 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
1036 GArray *message_info_array;
1037 CamelMboxSummaryInformation *message_info;
1038 GList *uid_list = NULL;
1041 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::get_uid_list\n");
1043 message_info_array = mbox_folder->internal_summary->message_info;
1045 for (i=0; i<message_info_array->len; i++) {
1047 message_info = (CamelMboxSummaryInformation *)(message_info_array->data) + i;
1048 uid_list = g_list_prepend (uid_list, g_strdup_printf ("%u", message_info->uid));
1051 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1063 static CamelMimeMessage *
1064 _get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex)
1067 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
1068 GArray *message_info_array;
1069 CamelMboxSummaryInformation *message_info;
1070 guint32 searched_uid;
1073 CamelStream *message_stream;
1074 CamelMimeMessage *message = NULL;
1075 CamelStore *parent_store;
1077 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::get_uid_list\n");
1079 searched_uid = strtoul(uid, (char **)NULL, 10);
1081 message_info_array = mbox_folder->internal_summary->message_info;
1085 /* first, look for the message that has the searched uid */
1086 while ((i<message_info_array->len) && (!uid_found)) {
1087 message_info = (CamelMboxSummaryInformation *)(message_info_array->data) + i;
1088 uid_found = (message_info->uid == searched_uid);
1092 /* if the uid was not found, raise an exception and return */
1094 camel_exception_setv (ex,
1095 CAMEL_EXCEPTION_FOLDER_INVALID_UID,
1096 "uid %s not found in the folder",
1098 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1102 /* at this point, the message_info structure
1103 contains the informations concerning the
1104 message that was searched for */
1106 /* create a stream bound to the message */
1107 message_stream = camel_stream_fs_new_with_name_and_bounds (mbox_folder->folder_file_path,
1108 CAMEL_STREAM_FS_READ,
1109 message_info->position,
1110 message_info->position + message_info->size);
1113 /* get the parent store */
1114 parent_store = camel_folder_get_parent_store (folder, ex);
1115 if (camel_exception_get_id (ex)) {
1116 gtk_object_unref (GTK_OBJECT (message_stream));
1121 message = camel_mime_message_new_with_session (camel_service_get_session (CAMEL_SERVICE (parent_store)));
1122 camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (message), message_stream);
1127 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1132 search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
1134 return camel_mbox_folder_search_by_expression(folder, expression, ex);