Remove the "session" field from CamelMimeMessage. Nothing uses it, about
[platform/upstream/evolution-data-server.git] / camel / providers / mbox / camel-mbox-folder.c
index 674f56c..3b48895 100644 (file)
@@ -2,8 +2,9 @@
 /* camel-mbox-folder.c : Abstract class for an email folder */
 
 /* 
+ * Author : Bertrand Guiheneuf <bertrand@helixcode.com> 
  *
- * Copyright (C) 1999 Bertrand Guiheneuf <bertrand@helixcode.com> .
+ * Copyright (C) 1999 Helix Code .
  *
  * This program is free software; you can redistribute it and/or 
  * modify it under the terms of the GNU General Public License as 
@@ -24,6 +25,7 @@
 
 #include <config.h> 
 
+#include <stdlib.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <sys/stat.h>
 #include "camel-mbox-store.h"
 #include "string-utils.h"
 #include "camel-log.h"
-#include "camel-stream-buffered-fs.h"
-#include "camel-folder-summary.h"
+#include "camel-stream-fs.h"
+#include "camel-mbox-summary.h"
+#include "camel-mbox-parser.h"
+#include "camel-mbox-utils.h"
 #include "gmime-utils.h"
+#include "camel-mbox-search.h"
+#include "camel-data-wrapper.h"
+#include "camel-mime-message.h"
 
 #include "camel-exception.h"
 
-#if 0
-#include "mbox-utils.h"
-#include "mbox-uid.h"
-#include "mbox-summary.h"
-#endif 
-
 static CamelFolderClass *parent_class=NULL;
 
 /* Returns the class for a CamelMboxFolder */
@@ -56,7 +57,9 @@ static CamelFolderClass *parent_class=NULL;
 #define CMBOXS_CLASS(so) CAMEL_STORE_CLASS (GTK_OBJECT(so)->klass)
 
 
-static void _init_with_store (CamelFolder *folder, CamelStore *parent_store, CamelException *ex);
+static void _init (CamelFolder *folder, CamelStore *parent_store,
+                  CamelFolder *parent_folder, const gchar *name,
+                  gchar separator, CamelException *ex);
 static void _set_name(CamelFolder *folder, const gchar *name, CamelException *ex);
 
 
@@ -67,15 +70,15 @@ static gboolean _create(CamelFolder *folder, CamelException *ex);
 static gboolean _delete (CamelFolder *folder, gboolean recurse, CamelException *ex);
 static gboolean _delete_messages (CamelFolder *folder, CamelException *ex);
 static GList *_list_subfolders (CamelFolder *folder, CamelException *ex);
-#if 0
 static CamelMimeMessage *_get_message_by_number (CamelFolder *folder, gint number, CamelException *ex);
 static gint _get_message_count (CamelFolder *folder, CamelException *ex);
-static gint _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex);
+static void _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex);
+static GList *_get_uid_list  (CamelFolder *folder, CamelException *ex);
+static CamelMimeMessage *_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex);
+#if 0
 static void _expunge (CamelFolder *folder, CamelException *ex);
 static void _copy_message_to (CamelFolder *folder, CamelMimeMessage *message, CamelFolder *dest_folder, CamelException *ex);
 static const gchar *_get_message_uid (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex);
-static CamelMimeMessage *_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex);
-static GList *_get_uid_list  (CamelFolder *folder, CamelException *ex);
 #endif
 
 static void _finalize (GtkObject *object);
@@ -89,8 +92,9 @@ camel_mbox_folder_class_init (CamelMboxFolderClass *camel_mbox_folder_class)
        parent_class = gtk_type_class (camel_folder_get_type ());
                
        /* virtual method definition */
+
        /* virtual method overload */
-       camel_folder_class->init_with_store = _init_with_store;
+       camel_folder_class->init = _init;
        camel_folder_class->set_name = _set_name;
        camel_folder_class->open = _open;
        camel_folder_class->close = _close;
@@ -99,16 +103,21 @@ camel_mbox_folder_class_init (CamelMboxFolderClass *camel_mbox_folder_class)
        camel_folder_class->delete = _delete;
        camel_folder_class->delete_messages = _delete_messages;
        camel_folder_class->list_subfolders = _list_subfolders;
-#if 0
        camel_folder_class->get_message_by_number = _get_message_by_number;
        camel_folder_class->get_message_count = _get_message_count;
        camel_folder_class->append_message = _append_message;
+       camel_folder_class->get_uid_list = _get_uid_list;
+#if 0
        camel_folder_class->expunge = _expunge;
        camel_folder_class->copy_message_to = _copy_message_to;
        camel_folder_class->get_message_uid = _get_message_uid;
-       camel_folder_class->get_message_by_uid = _get_message_by_uid;
-       camel_folder_class->get_uid_list = _get_uid_list;
 #endif
+       camel_folder_class->get_message_by_uid = _get_message_by_uid;
+
+       camel_folder_class->search_by_expression = camel_mbox_folder_search_by_expression;
+       camel_folder_class->search_complete = camel_mbox_folder_search_complete;
+       camel_folder_class->search_cancel = camel_mbox_folder_search_cancel;
+
        gtk_object_class->finalize = _finalize;
        
 }
@@ -160,33 +169,123 @@ camel_mbox_folder_get_type (void)
 
 
 
-
 
 
 static void 
-_init_with_store (CamelFolder *folder, CamelStore *parent_store, CamelException *ex)
+_init (CamelFolder *folder, CamelStore *parent_store,
+       CamelFolder *parent_folder, const gchar *name, gchar separator,
+       CamelException *ex)
 {
-       CAMEL_LOG_FULL_DEBUG ("Entering CamelMhFolder::init_with_store\n");
+
+
+       CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::init_with_store\n");
 
        /* call parent method */
-       parent_class->init_with_store (folder, parent_store, ex);
+       parent_class->init (folder, parent_store, parent_folder,
+                           name, separator, ex);
        if (camel_exception_get_id (ex)) return;
 
-       /* we assume that the parent init_with_store 
+       /* we assume that the parent init
           method checks for the existance of @folder */
           
        folder->can_hold_messages = TRUE;
        folder->can_hold_folders = TRUE;
        folder->has_summary_capability = TRUE;
        folder->has_uid_capability = TRUE;
-       folder->summary = NULL;
-       
-       CAMEL_LOG_FULL_DEBUG ("Leaving CamelMhFolder::init_with_store\n");
+       folder->has_search_capability = TRUE;
+       folder->summary = NULL;
+
+       CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::init_with_store\n");
 }
 
 
 
+/* internal method used to : 
+   - test for the existence of a summary file 
+   - test the sync between the summary and the mbox file
+   - load the summary or create it if necessary 
+*/ 
+static void
+_check_get_or_maybe_generate_summary_file (CamelMboxFolder *mbox_folder,
+                                          CamelException *ex)
+{
+       CamelFolder *folder = CAMEL_FOLDER (mbox_folder);
+       CamelMboxSummary *summ;
+       GArray *message_info_array;
+       gint mbox_file_fd;
+       guint32 next_uid;
+       guint32 file_size;
+       struct stat st;
+
+       folder->summary = NULL;
+
+       /* Test for the existence and up-to-dateness of the summary file. */
+       if (access (mbox_folder->summary_file_path, F_OK) == 0) {
+               summ = camel_mbox_summary_load (mbox_folder->summary_file_path,
+                                               ex);
+               if (summ) {
+                       if (stat (mbox_folder->folder_file_path, &st) == 0 &&
+                           summ->mbox_file_size == st.st_size &&
+                           summ->mbox_modtime == st.st_mtime)
+                               folder->summary = CAMEL_FOLDER_SUMMARY (summ);
+                       else
+                               gtk_object_destroy (GTK_OBJECT (summ));
+               } else {
+                       /* Bad summary file */
+                       if (camel_exception_get_id (ex) !=
+                           CAMEL_EXCEPTION_FOLDER_SUMMARY_INVALID)
+                               return;
+                       camel_exception_clear (ex);
+               }
+       }
+
+       /* In the case where the summary does not exist (or was the
+        * wrong version), or is not in sync with the mbox file,
+        * regenerate it.
+        */
+       if (folder->summary == NULL) {
+               /* Parse the mbox folder and get some information
+                * about the messages.
+                */
+               mbox_file_fd = open (mbox_folder->folder_file_path, O_RDONLY);
+               if (mbox_file_fd != -1) {
+                       message_info_array =
+                               camel_mbox_parse_file (mbox_file_fd, "From ",
+                                                      0, &file_size,
+                                                      &next_uid, TRUE,
+                                                      NULL, 0, ex); 
+                       close (mbox_file_fd);
+                       if (camel_exception_get_id (ex))
+                               return;
+
+                       next_uid = camel_mbox_write_xev (mbox_folder,
+                                                        mbox_folder->folder_file_path, 
+                                                        message_info_array,
+                                                        &file_size,
+                                                        next_uid, ex);
+                       if (camel_exception_get_id (ex)) { 
+                               /* ** FIXME : free the preparsed information */
+                               return;
+                       }
+
+                       summ = CAMEL_MBOX_SUMMARY (gtk_object_new (camel_mbox_summary_get_type (), NULL));
+                       summ->message_info = parsed_information_to_mbox_summary (message_info_array);
+                       summ->nb_message = summ->message_info->len;
+                       summ->next_uid = next_uid;
+                       summ->mbox_file_size = file_size;
+                       /* **FIXME : Free the parsed information structure */
+               } else {
+                       summ = CAMEL_MBOX_SUMMARY (gtk_object_new (camel_mbox_summary_get_type (), NULL));
+                       summ->message_info = g_array_new (FALSE, FALSE, sizeof (CamelMboxSummaryInformation));
+                       summ->nb_message = 0;
+                       summ->next_uid = 0;
+                       summ->mbox_file_size = 0;
+               }
+
+               folder->summary = CAMEL_FOLDER_SUMMARY (summ);
+       }
+}
 
 
 
@@ -194,45 +293,50 @@ static void
 _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex)
 {
        CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
-       struct dirent *dir_entry;
-       
-       
-       if (folder->open_state == FOLDER_OPEN) {
-               camel_exception_set (ex, 
-                                    CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
-                                    "folder is already open");
-               return;
+
+       mbox_folder->index = ibex_open(mbox_folder->index_file_path, O_CREAT|O_RDWR, 0600);
+       if (mbox_folder->index == NULL) {
+               g_warning("Could not open/create index file: %s: indexing will not function",
+                         strerror(errno));
        }
 
-       
+       /* call parent class */
+       parent_class->open (folder, mode, ex);
+       if (camel_exception_get_id(ex))
+               return;
+
 #if 0
-       Here, we need to check for the summary file 
-       existence and create it if necessary.
        /* get (or create) uid list */
        if (!(mbox_load_uid_list (mbox_folder) > 0))
                mbox_generate_uid_list (mbox_folder);
-
-       /* get or create summary */
-       /* it is important that it comes after uid list reading/generation */
-       if (!(mbox_load_summary (mbox_folder) > 0))
-               mbox_generate_summary (folder);
+#endif
        
-#endif 
+       _check_get_or_maybe_generate_summary_file (mbox_folder, ex);
 }
 
 
-
-
-
-
 static void
 _close (CamelFolder *folder, gboolean expunge, CamelException *ex)
 {
        CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
-
+       CamelMboxSummary *mbox_summary = CAMEL_MBOX_SUMMARY (folder->summary);
+       struct stat st;
 
        /* call parent implementation */
        parent_class->close (folder, expunge, ex);
+
+       /* save index */
+       if (mbox_folder->index) {
+               ibex_close(mbox_folder->index);
+       }
+
+       /* Update the summary and save it to disk */
+       if (stat (mbox_folder->folder_file_path, &st) == 0) {
+               mbox_summary->mbox_file_size = st.st_size;
+               mbox_summary->mbox_modtime = st.st_mtime;
+       }
+       camel_mbox_summary_save (mbox_summary,
+                                mbox_folder->summary_file_path, ex);
 }
 
 
@@ -243,9 +347,6 @@ _set_name (CamelFolder *folder, const gchar *name, CamelException *ex)
 {
        CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
        const gchar *root_dir_path;
-       gchar *full_name;
-       const gchar *parent_full_name;
-       gchar separator;
        
        CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::set_name\n");
 
@@ -255,18 +356,18 @@ _set_name (CamelFolder *folder, const gchar *name, CamelException *ex)
 
        g_free (mbox_folder->folder_file_path);
        g_free (mbox_folder->folder_dir_path);
+       g_free (mbox_folder->index_file_path);
 
-       separator = camel_store_get_separator (folder->parent_store);
        root_dir_path = camel_mbox_store_get_toplevel_dir (CAMEL_MBOX_STORE(folder->parent_store));
 
        CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name full_name is %s\n", folder->full_name);
        CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name root_dir_path is %s\n", root_dir_path);
-       CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::separator is %c\n", separator);
 
-       mbox_folder->folder_file_path = g_strdup_printf ("%s%c%s", root_dir_path, separator, folder->full_name);
-       mbox_folder->folder_dir_path = g_strdup_printf ("%s%c%s.sdb", root_dir_path, separator, folder->full_name);
-       
-       
+       mbox_folder->folder_file_path = g_strdup_printf ("%s/%s", root_dir_path, folder->full_name);
+       mbox_folder->summary_file_path = g_strdup_printf ("%s/%s-ev-summary", root_dir_path, folder->full_name);
+       mbox_folder->folder_dir_path = g_strdup_printf ("%s/%s.sdb", root_dir_path, folder->full_name);
+       mbox_folder->index_file_path = g_strdup_printf ("%s/%s.ibex", root_dir_path, folder->full_name);
+
        CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name mbox_folder->folder_file_path is %s\n", 
                              mbox_folder->folder_file_path);
        CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::set_name mbox_folder->folder_dir_path is %s\n", 
@@ -282,20 +383,16 @@ _set_name (CamelFolder *folder, const gchar *name, CamelException *ex)
 static gboolean
 _exists (CamelFolder *folder, CamelException *ex)
 {
-       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
+       CamelMboxFolder *mbox_folder;
        struct stat stat_buf;
        gint stat_error;
        gboolean exists;
 
+       g_assert(folder != NULL);
+
        CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::exists\n");
 
-       /* check if the folder object exists */
-       if (!folder) {
-               camel_exception_set (ex, 
-                                    CAMEL_EXCEPTION_FOLDER_NULL,
-                                    "folder object is NULL");
-               return FALSE;
-       }
+       mbox_folder = CAMEL_MBOX_FOLDER (folder);
 
        /* check if the mbox file path is determined */
        if (!mbox_folder->folder_file_path) {
@@ -312,8 +409,21 @@ _exists (CamelFolder *folder, CamelException *ex)
                                     "undetermined folder directory path. Maybe use set_name ?");
                return FALSE;
        }
-       
+
+
+       /* we should not check for that here */
+#if 0
        /* check if the mbox directory exists */
+       access_result = access (mbox_folder->folder_dir_path, F_OK);
+       if (access_result < 0) {
+               CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists errot when executing access on %s\n", 
+                                     mbox_folder->folder_dir_path);
+               CAMEL_LOG_FULL_DEBUG ("  Full error text is : %s\n", strerror(errno));
+               camel_exception_set (ex, 
+                                    CAMEL_EXCEPTION_SYSTEM,
+                                    strerror(errno));
+               return FALSE;
+       }
        stat_error = stat (mbox_folder->folder_dir_path, &stat_buf);
        if (stat_error == -1)  {
                CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists when executing stat on %s, stat_error = %d\n", 
@@ -326,20 +436,15 @@ _exists (CamelFolder *folder, CamelException *ex)
        }
        exists = S_ISDIR (stat_buf.st_mode);
        if (!exists) return FALSE;
+#endif 
+
 
        /* check if the mbox file exists */
        stat_error = stat (mbox_folder->folder_file_path, &stat_buf);
-       if (stat_error == -1)  {
-               CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::exists when executing stat on %s, stat_error = %d\n", 
-                                     mbox_folder->folder_file_path, stat_error);
-               CAMEL_LOG_FULL_DEBUG ("  Full error text is : %s\n", strerror(errno));
-               camel_exception_set (ex, 
-                                    CAMEL_EXCEPTION_SYSTEM,
-                                    strerror(errno));
+       if (stat_error == -1)
                return FALSE;
-       }
-
-       exists = S_REG (stat_buf.st_mode);
+       
+       exists = S_ISREG (stat_buf.st_mode);
        /* we should  check the rights here  */
        
        CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::exists\n");
@@ -356,29 +461,22 @@ _exists (CamelFolder *folder, CamelException *ex)
 static gboolean
 _create (CamelFolder *folder, CamelException *ex)
 {
-       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
+       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
+       CamelMboxSummary *summary;
        const gchar *folder_file_path, *folder_dir_path;
        mode_t dir_mode = S_IRWXU;
        gint mkdir_error;
        gboolean folder_already_exists;
        int creat_fd;
-       mode_t old_umask;
-
-       /* check if the folder object exists */
-       if (!folder) {
-               camel_exception_set (ex, 
-                                    CAMEL_EXCEPTION_FOLDER_NULL,
-                                    "folder object is NULL");
-               return FALSE;
-       }
 
+       g_assert(folder != NULL);
 
        /* call default implementation */
        parent_class->create (folder, ex);
 
        /* get the paths of what we need to create */
        folder_file_path = mbox_folder->folder_file_path;
-       folder_dir_path = mbox_folder->folder_file_path;
+       folder_dir_path = mbox_folder->folder_dir_path;
        
        if (!(folder_file_path || folder_dir_path)) {
                camel_exception_set (ex, 
@@ -390,26 +488,36 @@ _create (CamelFolder *folder, CamelException *ex)
        
        /* if the folder already exists, simply return */
        folder_already_exists = camel_folder_exists (folder,ex);
-       if (camel_exception_get_id (ex)) return FALSE;
+       if (camel_exception_get_id (ex))
+               return FALSE;
 
-       if (folder_already_exists) return TRUE;
+       if (folder_already_exists)
+               return TRUE;
 
 
        /* create the directory for the subfolders */
        mkdir_error = mkdir (folder_dir_path, dir_mode);
-       if (mkdir_error == -1) goto io_error;
+       if (mkdir_error == -1)
+               goto io_error;
        
 
        /* create the mbox file */ 
        /* it must be rw for the user and none for the others */
-       old_umask = umask (0700);
        creat_fd = open (folder_file_path, 
                         O_WRONLY | O_CREAT | O_APPEND,
-                        S_IRUSR  | S_IWUSR); 
-       umask (old_umask);
-       if (creat_fd == -1) goto io_error;
+                        0600);
+       if (creat_fd == -1)
+               goto io_error;
+
        close (creat_fd);
-       
+
+       /* create the summary object */
+       summary = CAMEL_MBOX_SUMMARY (gtk_object_new (camel_mbox_summary_get_type (), NULL));
+       summary->nb_message = 0;
+       summary->next_uid = 1;
+       summary->mbox_file_size = 0;
+       summary->message_info = g_array_new (FALSE, FALSE, sizeof (CamelMboxSummaryInformation));
+
        return TRUE;
 
        /* exception handling for io errors */
@@ -434,35 +542,27 @@ _create (CamelFolder *folder, CamelException *ex)
 
 
 
-
-
-
-
-
 static gboolean
 _delete (CamelFolder *folder, gboolean recurse, CamelException *ex)
 {
-       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
+       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
        const gchar *folder_file_path, *folder_dir_path;
        gint rmdir_error = 0;
        gint unlink_error = 0;
        gboolean folder_already_exists;
 
-       /* check if the folder object exists */
-       if (!folder) {
-               camel_exception_set (ex, 
-                                    CAMEL_EXCEPTION_FOLDER_NULL,
-                                    "folder object is NULL");
-               return FALSE;
-       }
+       g_assert(folder != NULL);
 
+       /* check if the folder object exists */
 
        /* in the case where the folder does not exist, 
           return immediatly */
        folder_already_exists = camel_folder_exists (folder, ex);
-       if (camel_exception_get_id (ex)) return FALSE;
+       if (camel_exception_get_id (ex))
+               return FALSE;
 
-       if (!folder_already_exists) return TRUE;
+       if (!folder_already_exists)
+               return TRUE;
 
 
        /* call default implementation.
@@ -471,7 +571,7 @@ _delete (CamelFolder *folder, gboolean recurse, CamelException *ex)
        parent_class->delete (folder, recurse, ex);
        
 
-       /* get the paths of what we need to delete */
+       /* get the paths of what we need to be deleted */
        folder_file_path = mbox_folder->folder_file_path;
        folder_dir_path = mbox_folder->folder_file_path;
        
@@ -487,7 +587,7 @@ _delete (CamelFolder *folder, gboolean recurse, CamelException *ex)
        CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::delete removing directory %s\n", folder_dir_path);
        rmdir_error = rmdir (folder_dir_path);
        if (rmdir_error == -1) 
-               switch errno { 
+               switch (errno) { 
                case EACCES :
                        camel_exception_set (ex, 
                                             CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
@@ -511,7 +611,7 @@ _delete (CamelFolder *folder, gboolean recurse, CamelException *ex)
        /* physically delete the file */
        unlink_error = unlink (folder_dir_path);
        if (unlink_error == -1) 
-               switch errno { 
+               switch (errno) { 
                case EACCES :
                case EPERM :
                case EROFS :
@@ -549,21 +649,13 @@ gboolean
 _delete_messages (CamelFolder *folder, CamelException *ex)
 {
        
-       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
+       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
        const gchar *folder_file_path;
        gboolean folder_already_exists;
        int creat_fd;
-       mode_t old_umask;
-       
-
-       /* check if the folder object exists */
-       if (!folder) {
-               camel_exception_set (ex, 
-                                    CAMEL_EXCEPTION_FOLDER_NULL,
-                                    "folder object is NULL");
-               return FALSE;
-       }
 
+       g_assert(folder!=NULL);
+       
        /* in the case where the folder does not exist, 
           return immediatly */
        folder_already_exists = camel_folder_exists (folder, ex);
@@ -586,12 +678,11 @@ _delete_messages (CamelFolder *folder, CamelException *ex)
                
        /* create the mbox file */ 
        /* it must be rw for the user and none for the others */
-       old_umask = umask (0700);
        creat_fd = open (folder_file_path, 
                         O_WRONLY | O_TRUNC,
-                        S_IRUSR  | S_IWUSR); 
-       umask (old_umask);
-       if (creat_fd == -1) goto io_error;
+                        0600); 
+       if (creat_fd == -1)
+               goto io_error;
        close (creat_fd);
        
        return TRUE;
@@ -619,25 +710,17 @@ _delete_messages (CamelFolder *folder, CamelException *ex)
 }
 
 
-
-
-
-
-
-
-
 static GList *
 _list_subfolders (CamelFolder *folder, CamelException *ex)
 {
        GList *subfolder_name_list = NULL;
 
-       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
+       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
        const gchar *folder_dir_path;
        gboolean folder_exists;
 
        struct stat stat_buf;
        gint stat_error = 0;
-       GList *file_list;
        gchar *entry_name;
        gchar *full_entry_name;
        gchar *real_folder_name;
@@ -645,9 +728,6 @@ _list_subfolders (CamelFolder *folder, CamelException *ex)
        DIR *dir_handle;
        gboolean folder_suffix_found;
        
-       gchar *io_error_text;
-       
-
 
        /* check if the folder object exists */
        if (!folder) {
@@ -700,7 +780,7 @@ _list_subfolders (CamelFolder *folder, CamelException *ex)
                                CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::list_subfolders adding "
                                                      "%s\n", entry_name);
 
-                               /* if the folder is a netscape folder, remove the 
+                               /* if the folder is a netscape folder, remove the  
                                   ".sdb" from the name */
                                real_folder_name = string_prefix (entry_name, ".sdb", &folder_suffix_found);
                                /* stick here the tests for other folder suffixes if any */
@@ -723,9 +803,7 @@ _list_subfolders (CamelFolder *folder, CamelException *ex)
        
 
        /* io exception handling */
-       io_error : 
-
-               switch errno { 
+               switch (errno) { 
                case EACCES :
                        
                        camel_exception_setv (ex, 
@@ -756,61 +834,262 @@ _list_subfolders (CamelFolder *folder, CamelException *ex)
 
 
 
+static gint
+_get_message_count (CamelFolder *folder, CamelException *ex)
+{
+       gint message_count;
 
+       g_assert (folder);
+       g_assert (folder->summary);
+       
+       message_count = CAMEL_MBOX_SUMMARY (folder->summary)->nb_message;
 
+       CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::get_message_count found %d messages\n", message_count);
+       return message_count;
+}
 
 
+static void
+_append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex)
+{
+       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
+       CamelMboxSummary *summary = CAMEL_MBOX_SUMMARY (folder->summary);
+       CamelStream *output_stream;
+       guint32 tmp_file_size;
+       guint32 next_uid;
+       gint tmp_file_fd;
+       GArray *message_info_array;
+       GArray *mbox_summary_info;
+       gchar *tmp_message_filename;
+       gint fd1, fd2;
+       int i;
+
+       CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::append_message\n");
+
+       tmp_message_filename = g_strdup_printf ("%s.tmp",
+                                               mbox_folder->folder_file_path);
+
+       /* write the message itself */
+       output_stream = camel_stream_fs_new_with_name (tmp_message_filename,
+                                                      CAMEL_STREAM_FS_WRITE);
+       if (output_stream != NULL) {
+               camel_stream_write_string (output_stream, "From - \n");
+               camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), output_stream);
+       }
+       camel_stream_close (output_stream);
+       gtk_object_unref (GTK_OBJECT (output_stream));
+
+       /* at this point we have saved the message to a
+          temporary file, now, we have to add the x-evolution 
+          field and also update the main summary */
+
+       /* 
+          First : parse the mbox file, but only from the 
+          position where the message has been added, 
+          wich happens to be the last postion in the 
+          mbox file before we added the message.
+          This position is still stored in the summary 
+          for the moment 
+       */
+       next_uid = summary->next_uid;
+       tmp_file_fd = open (tmp_message_filename, O_RDONLY);
+       message_info_array =
+               camel_mbox_parse_file (tmp_file_fd, "From - ", 0,
+                                      &tmp_file_size, &next_uid, TRUE,
+                                      NULL, 0, ex); 
+       
+       close (tmp_file_fd);
+
+       /* get the value of the last available UID
+          as saved in the summary file, again */
+       next_uid = summary->next_uid;
+
+       /* make sure all our of message info's have 0 uid - ignore any
+          set elsewhere */
+       for (i=0;i<message_info_array->len;i++) {
+               g_array_index(message_info_array, CamelMboxParserMessageInfo, i).uid = 0;
+       }
+
+       /* 
+          OK, this is not very efficient, we should not use the same
+          method as for parsing an entire mail file, 
+          but I have no time to write a simpler parser 
+       */
+       next_uid = camel_mbox_write_xev (mbox_folder, tmp_message_filename, 
+                                        message_info_array, &tmp_file_size, next_uid, ex);
+       
+       if (camel_exception_get_id (ex)) { 
+               /* ** FIXME : free the preparsed information */
+               return;
+       }
+
+       mbox_summary_info =
+               parsed_information_to_mbox_summary (message_info_array);
+
+       /* store the number of messages as well as the summary array */
+       summary->nb_message += 1;               
+       summary->next_uid = next_uid;   
+
+       ((CamelMboxSummaryInformation *)(mbox_summary_info->data))->position +=
+               summary->mbox_file_size;
+       summary->mbox_file_size += tmp_file_size;               
+
+       camel_mbox_summary_append_entries (summary, mbox_summary_info);
+       g_array_free (mbox_summary_info, TRUE); 
+       
+
+       /* append the temporary file message to the mbox file */
+       fd1 = open (tmp_message_filename, O_RDONLY);
+       fd2 = open (mbox_folder->folder_file_path, 
+                   O_WRONLY | O_CREAT | O_APPEND,
+                   0600);
+
+       if (fd2 == -1) {
+               camel_exception_setv (ex, 
+                                     CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
+                                     "could not open the mbox folder file for appending the message\n"
+                                     "\t%s\n"
+                                     "Full error is : %s\n",
+                                     mbox_folder->folder_file_path,
+                                     strerror (errno));
+               return;
+       }
+
+       camel_mbox_copy_file_chunk (fd1,
+                                   fd2, 
+                                   tmp_file_size, 
+                                   ex);
+       close (fd1);
+       close (fd2);
+
+       /* remove the temporary file */
+       unlink (tmp_message_filename);
+
+       g_free (tmp_message_filename);
+       CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::append_message\n");
+}
+
+
+
+
+static GList *
+_get_uid_list (CamelFolder *folder, CamelException *ex) 
+{
+       GArray *message_info_array;
+       CamelMboxSummaryInformation *message_info;
+       GList *uid_list = NULL;
+       int i;
+
+       CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::get_uid_list\n");
+       
+       message_info_array =
+               CAMEL_MBOX_SUMMARY (folder->summary)->message_info;
+       
+       for (i=0; i<message_info_array->len; i++) {
+               message_info = (CamelMboxSummaryInformation *)(message_info_array->data) + i;
+               uid_list = g_list_prepend (uid_list, g_strdup_printf ("%u", message_info->uid));
+       }
+       
+       CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
+       
+       return uid_list;
+}
+
 
 
-#if 0
 
 static CamelMimeMessage *
 _get_message_by_number (CamelFolder *folder, gint number, CamelException *ex)
 {
-       CamelMhFolder *mh_folder = CAMEL_MH_FOLDER(folder);
-       const gchar *directory_path;
-       gchar *message_name;
-       gchar *message_file_name;
-       CamelStream *input_stream = NULL;
+       GArray *message_info_array;
+       CamelMboxSummaryInformation *message_info;
+       char uidbuf[20];
+
+       message_info_array =
+               CAMEL_MBOX_SUMMARY (folder->summary)->message_info;
+
+       if (number > message_info_array->len) {
+               camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID,
+                                     "No such message %d in folder `%s'.",
+                                     number, folder->name);
+               return NULL;
+       }
+
+       message_info =
+               (CamelMboxSummaryInformation *)(message_info_array->data) +
+               (number - 1);
+       sprintf (uidbuf, "%lu", message_info->uid);
+
+       return _get_message_by_uid (folder, uidbuf, ex);
+}
+
+
+static CamelMimeMessage *
+_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex)
+{
+       
+       CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder);
+       GArray *message_info_array;
+       CamelMboxSummaryInformation *message_info = NULL;
+       guint32 searched_uid;
+       int i;
+       gboolean uid_found;
+       CamelStream *message_stream;
        CamelMimeMessage *message = NULL;
-       GList *message_list = NULL;
+       CamelStore *parent_store;
+
+       CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::get_message_by_uid\n");
        
-       g_assert(folder);
+        searched_uid = strtoul (uid, NULL, 10);
+
+       message_info_array =
+               CAMEL_MBOX_SUMMARY (folder->summary)->message_info;
+       i=0;
+       uid_found = FALSE;
        
+       /* first, look for the message that has the searched uid */
+       while ((i<message_info_array->len) && (!uid_found)) {
+               message_info = (CamelMboxSummaryInformation *)(message_info_array->data) + i;
+               uid_found = (message_info->uid == searched_uid);
+               i++;
+       }
        
-       directory_path = mh_folder->directory_path;
-       if (!directory_path) return NULL;       
-
-               
+       /* if the uid was not found, raise an exception and return */
+       if (!uid_found) {
+               camel_exception_setv (ex, 
+                                    CAMEL_EXCEPTION_FOLDER_INVALID_UID,
+                                    "uid %s not found in the folder",
+                                     uid);
+               CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");
+               return NULL;
+       }
        
-       message_name = g_list_nth_data (mh_folder->file_name_list, number);
+       /* at this point, the message_info structure 
+          contains the informations concerning the 
+          message that was searched for */
        
-       if (message_name != NULL) {
-               CAMEL_LOG_FULL_DEBUG  ("CanelMhFolder::get_message message number = %d, name = %s\n", 
-                                      number, message_name);
-               message_file_name = g_strdup_printf ("%s/%s", directory_path, message_name);
-               input_stream = camel_stream_buffered_fs_new_with_name (message_file_name, CAMEL_STREAM_BUFFERED_FS_READ);
-               
-               if (input_stream != NULL) {
-#warning use session field here
-                       message = camel_mime_message_new_with_session ( (CamelSession *)NULL);
-                       camel_data_wrapper_construct_from_stream ( CAMEL_DATA_WRAPPER (message), input_stream);
-                       gtk_object_unref (GTK_OBJECT (input_stream));
-                       message->message_number = number;
-                       gtk_object_set_data_full (GTK_OBJECT (message), "filename", 
-                                                 g_strdup (message_name), _filename_free);
-                       
-#warning Set flags and all this stuff here
-               }
-               g_free (message_file_name);
+        /* create a stream bound to the message */
+       message_stream = camel_stream_fs_new_with_name_and_bounds (mbox_folder->folder_file_path, 
+                                                                  CAMEL_STREAM_FS_READ,
+                                                                  message_info->position, 
+                                                                  message_info->position + message_info->size);
+
+
+       /* get the parent store */
+       parent_store = camel_folder_get_parent_store (folder, ex);
+       if (camel_exception_get_id (ex)) {
+               gtk_object_unref (GTK_OBJECT (message_stream));
+               return NULL;
+       }
 
-       } else 
-               CAMEL_LOG_FULL_DEBUG  ("CanelMhFolder::get_message message number = %d, not found\n", number);
+       
+       message = camel_mime_message_new ();
+       camel_data_wrapper_set_input_stream (CAMEL_DATA_WRAPPER (message), message_stream);
+       
        
        
-       return message;   
-}
-
-#endif 
-
 
+       
+       CAMEL_LOG_FULL_DEBUG ("Leaving CamelMboxFolder::get_uid_list\n");       
+       return message;
+}