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->has_search_capability = TRUE;
200 folder->summary = camel_folder_summary_new ();
202 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::init_with_store\n");
207 /* internal method used to :
208 - test for the existence of a summary file
209 - test the sync between the summary and the mbox file
210 - load the summary or create it if necessary
213 _check_get_or_maybe_generate_summary_file (CamelMboxFolder *mbox_folder, CamelException *ex)
215 CamelFolder *folder = CAMEL_FOLDER (mbox_folder);
216 GArray *message_info_array;
217 gboolean summary_file_exists;
218 gboolean summary_file_is_sync;
219 GArray *mbox_summary_info;
224 /* test for the existence of the summary file */
225 summary_file_exists = (access (mbox_folder->summary_file_path, F_OK) == 0);
227 /* if the summary file exists, test if the
228 md5 of the mbox file is still in sync
229 with the one we had computed the last time
230 we saved the summary file */
231 if (summary_file_exists) {
233 summary_file_is_sync =
234 camel_mbox_check_summary_sync (mbox_folder->summary_file_path,
235 mbox_folder->folder_file_path,
237 if (camel_exception_get_id (ex)) return;
241 /* in the case where the summary does not exist
242 or is not in sync with the mbox file
244 if ( !(summary_file_exists && summary_file_is_sync)) {
246 /* parse the mbox folder and get some
247 information about the messages */
249 mbox_file_fd = open (mbox_folder->folder_file_path, O_RDONLY);
250 message_info_array = camel_mbox_parse_file (mbox_file_fd,
260 close (mbox_file_fd);
261 if (camel_exception_get_id (ex)) {
266 next_uid = camel_mbox_write_xev (mbox_folder->folder_file_path,
267 message_info_array, &file_size, next_uid, ex);
269 if (camel_exception_get_id (ex)) {
270 /* ** FIXME : free the preparsed information */
275 parsed_information_to_mbox_summary (message_info_array);
277 /* **FIXME : Free the parsed information structure */
279 /* allocate an internal summary object */
280 mbox_folder->internal_summary = g_new (CamelMboxSummary, 1);
282 /* generate the folder md5 signature */
283 md5_get_digest_from_file (mbox_folder->folder_file_path, mbox_folder->internal_summary->md5_digest);
285 /* store the number of messages as well as the summary array */
286 mbox_folder->internal_summary->nb_message = mbox_summary_info->len;
287 mbox_folder->internal_summary->next_uid = next_uid;
288 mbox_folder->internal_summary->mbox_file_size = file_size;
289 mbox_folder->internal_summary->message_info = mbox_summary_info;
292 /* every thing seems ok, just read the summary file from disk */
293 mbox_folder->internal_summary = camel_mbox_load_summary (mbox_folder->summary_file_path, ex);
296 /* copy the internal summary information to the external
297 folder summary used by the display engines */
298 camel_mbox_summary_append_internal_to_external (mbox_folder->internal_summary, folder->summary, 0);
304 _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex)
306 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
307 //struct dirent *dir_entry;
308 //struct stat stat_buf;
310 /* call parent class */
311 parent_class->open (folder, mode, ex);
312 if (camel_exception_get_id(ex))
315 /* get (or create) uid list */
316 //if (!(mbox_load_uid_list (mbox_folder) > 0))
317 // mbox_generate_uid_list (mbox_folder);
319 _check_get_or_maybe_generate_summary_file (mbox_folder, ex);
324 _close (CamelFolder *folder, gboolean expunge, CamelException *ex)
326 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
329 /* call parent implementation */
330 parent_class->close (folder, expunge, ex);
332 /* save the folder summary on disc */
333 camel_mbox_save_summary (mbox_folder->internal_summary, mbox_folder->summary_file_path, ex);
340 _set_name (CamelFolder *folder, const gchar *name, CamelException *ex)
342 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
343 const gchar *root_dir_path;
345 //const gchar *parent_full_name;
347 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::set_name\n");
349 /* call default implementation */
350 parent_class->set_name (folder, name, ex);
351 if (camel_exception_get_id (ex)) return;
353 g_free (mbox_folder->folder_file_path);
354 g_free (mbox_folder->folder_dir_path);
355 g_free (mbox_folder->index_file_path);
357 root_dir_path = camel_mbox_store_get_toplevel_dir (CAMEL_MBOX_STORE(folder->parent_store));
359 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name full_name is %s\n", folder->full_name);
360 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name root_dir_path is %s\n", root_dir_path);
362 mbox_folder->folder_file_path = g_strdup_printf ("%s/%s", root_dir_path, folder->full_name);
363 mbox_folder->summary_file_path = g_strdup_printf ("%s/%s-ev-summary", root_dir_path, folder->full_name);
364 mbox_folder->folder_dir_path = g_strdup_printf ("%s/%s.sdb", root_dir_path, folder->full_name);
365 mbox_folder->index_file_path = g_strdup_printf ("%s/%s.ibex", root_dir_path, folder->full_name);
367 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name mbox_folder->folder_file_path is %s\n",
368 mbox_folder->folder_file_path);
369 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name mbox_folder->folder_dir_path is %s\n",
370 mbox_folder->folder_dir_path);
371 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::set_name\n");
380 _exists (CamelFolder *folder, CamelException *ex)
382 CamelMboxFolder *mbox_folder;
383 struct stat stat_buf;
387 g_assert(folder != NULL);
389 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::exists\n");
391 mbox_folder = CAMEL_MBOX_FOLDER(folder);
393 /* check if the mbox file path is determined */
394 if (!mbox_folder->folder_file_path) {
395 camel_exception_set (ex,
396 CAMEL_EXCEPTION_FOLDER_INVALID,
397 "undetermined folder file path. Maybe use set_name ?");
401 /* check if the mbox dir path is determined */
402 if (!mbox_folder->folder_dir_path) {
403 camel_exception_set (ex,
404 CAMEL_EXCEPTION_FOLDER_INVALID,
405 "undetermined folder directory path. Maybe use set_name ?");
410 /* we should not check for that here */
412 /* check if the mbox directory exists */
413 access_result = access (mbox_folder->folder_dir_path, F_OK);
414 if (access_result < 0) {
415 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists errot when executing access on %s\n",
416 mbox_folder->folder_dir_path);
417 CAMEL_LOG_FULL_DEBUG (" Full error text is : %s\n", strerror(errno));
418 camel_exception_set (ex,
419 CAMEL_EXCEPTION_SYSTEM,
423 stat_error = stat (mbox_folder->folder_dir_path, &stat_buf);
424 if (stat_error == -1) {
425 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists when executing stat on %s, stat_error = %d\n",
426 mbox_folder->folder_dir_path, stat_error);
427 CAMEL_LOG_FULL_DEBUG (" Full error text is : %s\n", strerror(errno));
428 camel_exception_set (ex,
429 CAMEL_EXCEPTION_SYSTEM,
433 exists = S_ISDIR (stat_buf.st_mode);
434 if (!exists) return FALSE;
438 /* check if the mbox file exists */
439 stat_error = stat (mbox_folder->folder_file_path, &stat_buf);
440 if (stat_error == -1)
443 exists = S_ISREG (stat_buf.st_mode);
444 /* we should check the rights here */
446 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::exists\n");
458 _create (CamelFolder *folder, CamelException *ex)
460 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
461 const gchar *folder_file_path, *folder_dir_path;
462 mode_t dir_mode = S_IRWXU;
464 gboolean folder_already_exists;
468 g_assert(folder != NULL);
470 /* call default implementation */
471 parent_class->create (folder, ex);
473 /* get the paths of what we need to create */
474 folder_file_path = mbox_folder->folder_file_path;
475 folder_dir_path = mbox_folder->folder_dir_path;
477 if (!(folder_file_path || folder_dir_path)) {
478 camel_exception_set (ex,
479 CAMEL_EXCEPTION_FOLDER_INVALID,
480 "invalid folder path. Use set_name ?");
485 /* if the folder already exists, simply return */
486 folder_already_exists = camel_folder_exists (folder,ex);
487 if (camel_exception_get_id (ex)) return FALSE;
489 if (folder_already_exists) return TRUE;
492 /* create the directory for the subfolders */
493 mkdir_error = mkdir (folder_dir_path, dir_mode);
494 if (mkdir_error == -1) goto io_error;
497 /* create the mbox file */
498 /* it must be rw for the user and none for the others */
499 creat_fd = open (folder_file_path,
500 O_WRONLY | O_CREAT | O_APPEND,
501 S_IRUSR | S_IWUSR, 0600);
502 if (creat_fd == -1) goto io_error;
505 /* create the summary object */
506 mbox_folder->internal_summary = g_new (CamelMboxSummary, 1);
507 mbox_folder->internal_summary->nb_message = 0;
508 mbox_folder->internal_summary->next_uid = 1;
509 mbox_folder->internal_summary->mbox_file_size = 0;
510 mbox_folder->internal_summary->message_info = g_array_new (FALSE, FALSE, sizeof (CamelMboxSummaryInformation));
514 /* exception handling for io errors */
517 CAMEL_LOG_WARNING ("CamelMboxFolder::create, error when creating %s and %s\n",
518 folder_dir_path, folder_file_path);
519 CAMEL_LOG_FULL_DEBUG ( " Full error text is : %s\n", strerror(errno));
521 if (errno == EACCES) {
522 camel_exception_set (ex,
523 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
524 "You don't have the permission to create the mbox file.");
527 camel_exception_set (ex,
528 CAMEL_EXCEPTION_SYSTEM,
529 "Unable to create the mbox file.");
542 _delete (CamelFolder *folder, gboolean recurse, CamelException *ex)
544 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
545 const gchar *folder_file_path, *folder_dir_path;
546 gint rmdir_error = 0;
547 gint unlink_error = 0;
548 gboolean folder_already_exists;
550 g_assert(folder != NULL);
552 /* check if the folder object exists */
554 /* in the case where the folder does not exist,
556 folder_already_exists = camel_folder_exists (folder, ex);
557 if (camel_exception_get_id (ex)) return FALSE;
559 if (!folder_already_exists) return TRUE;
562 /* call default implementation.
563 It should delete the messages in the folder
564 and recurse the operation to subfolders */
565 parent_class->delete (folder, recurse, ex);
568 /* get the paths of what we need to be deleted */
569 folder_file_path = mbox_folder->folder_file_path;
570 folder_dir_path = mbox_folder->folder_file_path;
572 if (!(folder_file_path || folder_dir_path)) {
573 camel_exception_set (ex,
574 CAMEL_EXCEPTION_FOLDER_INVALID,
575 "invalid folder path. Use set_name ?");
580 /* physically delete the directory */
581 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::delete removing directory %s\n", folder_dir_path);
582 rmdir_error = rmdir (folder_dir_path);
583 if (rmdir_error == -1)
586 camel_exception_set (ex,
587 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
588 "Not enough permission to delete the mbox folder");
593 camel_exception_set (ex,
594 CAMEL_EXCEPTION_FOLDER_NON_EMPTY,
595 "mbox folder not empty. Cannot delete it. Maybe use recurse flag ?");
599 camel_exception_set (ex,
600 CAMEL_EXCEPTION_SYSTEM,
601 "Unable to delete the mbox folder.");
605 /* physically delete the file */
606 unlink_error = unlink (folder_dir_path);
607 if (unlink_error == -1)
612 camel_exception_set (ex,
613 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
614 "Not enough permission to delete the mbox file");
622 camel_exception_set (ex,
623 CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
624 "Invalid mbox file");
629 camel_exception_set (ex,
630 CAMEL_EXCEPTION_SYSTEM,
631 "Unable to delete the mbox folder.");
643 _delete_messages (CamelFolder *folder, CamelException *ex)
646 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
647 const gchar *folder_file_path;
648 gboolean folder_already_exists;
652 g_assert(folder!=NULL);
654 /* in the case where the folder does not exist,
656 folder_already_exists = camel_folder_exists (folder, ex);
657 if (camel_exception_get_id (ex)) return FALSE;
659 if (!folder_already_exists) return TRUE;
663 /* get the paths of the mbox file we need to delete */
664 folder_file_path = mbox_folder->folder_file_path;
666 if (!folder_file_path) {
667 camel_exception_set (ex,
668 CAMEL_EXCEPTION_FOLDER_INVALID,
669 "invalid folder path. Use set_name ?");
674 /* create the mbox file */
675 /* it must be rw for the user and none for the others */
676 creat_fd = open (folder_file_path,
678 S_IRUSR | S_IWUSR, 0600);
679 if (creat_fd == -1) goto io_error;
684 /* exception handling for io errors */
687 CAMEL_LOG_WARNING ("CamelMboxFolder::create, error when deleting files %s\n",
689 CAMEL_LOG_FULL_DEBUG ( " Full error text is : %s\n", strerror(errno));
691 if (errno == EACCES) {
692 camel_exception_set (ex,
693 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
694 "You don't have the permission to write in the mbox file.");
697 camel_exception_set (ex,
698 CAMEL_EXCEPTION_SYSTEM,
699 "Unable to write in the mbox file.");
715 _list_subfolders (CamelFolder *folder, CamelException *ex)
717 GList *subfolder_name_list = NULL;
719 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
720 const gchar *folder_dir_path;
721 gboolean folder_exists;
723 struct stat stat_buf;
727 gchar *full_entry_name;
728 gchar *real_folder_name;
729 struct dirent *dir_entry;
731 gboolean folder_suffix_found;
733 //gchar *io_error_text;
737 /* check if the folder object exists */
739 camel_exception_set (ex,
740 CAMEL_EXCEPTION_FOLDER_NULL,
741 "folder object is NULL");
746 /* in the case the folder does not exist,
747 raise an exception */
748 folder_exists = camel_folder_exists (folder, ex);
749 if (camel_exception_get_id (ex)) return FALSE;
751 if (!folder_exists) {
752 camel_exception_set (ex,
753 CAMEL_EXCEPTION_FOLDER_INVALID,
754 "Inexistant folder.");
759 /* get the mbox subfolders directories */
760 folder_dir_path = mbox_folder->folder_file_path;
761 if (!folder_dir_path) {
762 camel_exception_set (ex,
763 CAMEL_EXCEPTION_FOLDER_INVALID,
764 "Invalid folder path. Use set_name ?");
769 dir_handle = opendir (folder_dir_path);
771 /* read the first entry in the directory */
772 dir_entry = readdir (dir_handle);
773 while ((stat_error != -1) && (dir_entry != NULL)) {
775 /* get the name of the next entry in the dir */
776 entry_name = dir_entry->d_name;
777 full_entry_name = g_strdup_printf ("%s/%s", folder_dir_path, entry_name);
778 stat_error = stat (full_entry_name, &stat_buf);
779 g_free (full_entry_name);
781 /* is it a directory ? */
782 if ((stat_error != -1) && S_ISDIR (stat_buf.st_mode)) {
783 /* yes, add it to the list */
784 if (entry_name[0] != '.') {
785 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::list_subfolders adding "
788 /* if the folder is a netscape folder, remove the
789 ".sdb" from the name */
790 real_folder_name = string_prefix (entry_name, ".sdb", &folder_suffix_found);
791 /* stick here the tests for other folder suffixes if any */
793 if (!folder_suffix_found) real_folder_name = g_strdup (entry_name);
795 /* add the folder name to the list */
796 subfolder_name_list = g_list_append (subfolder_name_list,
800 /* read next entry */
801 dir_entry = readdir (dir_handle);
804 closedir (dir_handle);
806 return subfolder_name_list;
810 /* io exception handling */
814 camel_exception_setv (ex,
815 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
816 "Unable to list the directory. Full Error text is : %s ",
822 camel_exception_setv (ex,
823 CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
824 "Invalid mbox folder path. Full Error text is : %s ",
829 camel_exception_set (ex,
830 CAMEL_EXCEPTION_SYSTEM,
831 "Unable to delete the mbox folder.");
835 g_list_free (subfolder_name_list);
843 _get_message_count (CamelFolder *folder, CamelException *ex)
846 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
850 g_assert (mbox_folder->internal_summary);
852 message_count = mbox_folder->internal_summary->nb_message;
854 CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::get_message_count found %d messages\n", message_count);
855 return message_count;
860 _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex)
862 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
863 CamelStream *output_stream;
864 guint32 tmp_file_size;
867 GArray *message_info_array;
868 GArray *mbox_summary_info;
869 gchar *tmp_message_filename;
872 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::append_message\n");
874 tmp_message_filename = g_strdup_printf ("%s.tmp", mbox_folder->folder_file_path);
876 /* write the message itself */
877 output_stream = camel_stream_fs_new_with_name (tmp_message_filename, CAMEL_STREAM_FS_WRITE);
878 if (output_stream != NULL) {
879 camel_stream_write_string (output_stream, "From - \n");
880 camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), output_stream);
882 camel_stream_close (output_stream);
884 /* at this point we have saved the message to a
885 temporary file, now, we have to add the x-evolution
886 field and also update the main summary summary */
889 First : parse the mbox file, but only from the
890 position where the message has been added,
891 wich happens to be the last postion in the
892 mbox file before we added the message.
893 This position is still stored in the summary
896 next_uid = mbox_folder->internal_summary->next_uid;
897 tmp_file_fd = open (tmp_message_filename, O_RDONLY);
899 camel_mbox_parse_file (tmp_file_fd, "From - ", 0,
900 &tmp_file_size, &next_uid, TRUE,
905 /* get the value of the last available UID
906 as saved in the summary file */
907 next_uid = mbox_folder->internal_summary->next_uid;
910 OK, this is not very efficient, we should not use the same
911 method as for parsing an entire mail file,
912 but I have no time to write a simpler parser
914 next_uid = camel_mbox_write_xev (tmp_message_filename,
915 message_info_array, &tmp_file_size, next_uid, ex);
917 if (camel_exception_get_id (ex)) {
918 /* ** FIXME : free the preparsed information */
923 parsed_information_to_mbox_summary (message_info_array);
925 /* store the number of messages as well as the summary array */
926 mbox_folder->internal_summary->nb_message += 1;
927 mbox_folder->internal_summary->next_uid = next_uid;
929 ((CamelMboxSummaryInformation *)(mbox_summary_info->data))->position += mbox_folder->internal_summary->mbox_file_size;
930 mbox_folder->internal_summary->mbox_file_size += tmp_file_size;
932 camel_mbox_summary_append_entries (mbox_folder->internal_summary, mbox_summary_info);
934 /* append the new entry of the internal summary to
935 the external summary */
936 camel_mbox_summary_append_internal_to_external (mbox_folder->internal_summary,
938 mbox_folder->internal_summary->nb_message-1);
940 g_array_free (mbox_summary_info, TRUE);
943 /* append the temporary file message to the mbox file */
944 fd1 = open (tmp_message_filename, O_RDONLY);
945 fd2 = open (mbox_folder->folder_file_path,
946 O_WRONLY | O_CREAT | O_APPEND,
947 S_IRUSR | S_IWUSR, 0600);
950 camel_exception_setv (ex,
951 CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
952 "could not open the mbox folder file for appending the message\n"
954 "Full error is : %s\n",
955 mbox_folder->folder_file_path,
960 camel_mbox_copy_file_chunk (fd1,
967 /* remove the temporary file */
968 //unlink (tmp_message_filename);
970 /* generate the folder md5 signature */
971 md5_get_digest_from_file (mbox_folder->folder_file_path, mbox_folder->internal_summary->md5_digest);
973 g_free (tmp_message_filename);
974 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::append_message\n");
981 _get_uid_list (CamelFolder *folder, CamelException *ex)
983 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
984 GArray *message_info_array;
985 CamelMboxSummaryInformation *message_info;
986 GList *uid_list = NULL;
989 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::get_uid_list\n");
991 message_info_array = mbox_folder->internal_summary->message_info;
993 for (i=0; i<message_info_array->len; i++) {
995 message_info = (CamelMboxSummaryInformation *)(message_info_array->data) + i;
996 uid_list = g_list_prepend (uid_list, g_strdup_printf ("%u", message_info->uid));
999 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1011 static CamelMimeMessage *
1012 _get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex)
1015 CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
1016 GArray *message_info_array;
1017 CamelMboxSummaryInformation *message_info;
1018 guint32 searched_uid;
1021 CamelStream *message_stream;
1022 CamelMimeMessage *message = NULL;
1023 CamelStore *parent_store;
1025 CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::get_uid_list\n");
1027 searched_uid = strtoul(uid, (char **)NULL, 10);
1029 message_info_array = mbox_folder->internal_summary->message_info;
1033 /* first, look for the message that has the searched uid */
1034 while ((i<message_info_array->len) && (!uid_found)) {
1035 message_info = (CamelMboxSummaryInformation *)(message_info_array->data) + i;
1036 uid_found = (message_info->uid == searched_uid);
1040 /* if the uid was not found, raise an exception and return */
1042 camel_exception_setv (ex,
1043 CAMEL_EXCEPTION_FOLDER_INVALID_UID,
1044 "uid %s not found in the folder",
1046 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1050 /* at this point, the message_info structure
1051 contains the informations concerning the
1052 message that was searched for */
1054 /* create a stream bound to the message */
1055 message_stream = camel_stream_fs_new_with_name_and_bounds (mbox_folder->folder_file_path,
1056 CAMEL_STREAM_FS_READ,
1057 message_info->position,
1058 message_info->position + message_info->size);
1061 /* get the parent store */
1062 parent_store = camel_folder_get_parent_store (folder, ex);
1063 if (camel_exception_get_id (ex)) {
1064 gtk_object_unref (GTK_OBJECT (message_stream));
1069 message = camel_mime_message_new_with_session (camel_service_get_session (CAMEL_SERVICE (parent_store)));
1070 camel_data_wrapper_set_input_stream (CAMEL_DATA_WRAPPER (message), message_stream);
1076 CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
1081 search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
1083 return camel_mbox_folder_search_by_expression(folder, expression, ex);