From de8e7223eac6c40b10d2a095210d2120aa97fa55 Mon Sep 17 00:00:00 2001 From: bertrand Date: Thu, 20 Jan 2000 03:02:13 +0000 Subject: implemented. 2000-01-19 bertrand * camel/providers/mbox/camel-mbox-folder.c (_get_message_count): implemented. * camel/providers/mbox/camel-mbox-summary.c (camel_mbox_save_summary): (camel_mbox_load_summary): save/load the next uid. * camel/providers/mbox/camel-mbox-parser.c (camel_mbox_parse_file): Compute the next available uid. * camel/providers/mbox/camel-mbox-folder.c (_create): (_check_get_or_maybe_generate_summary_file): Set and use the next_uid field properly. * camel/providers/mbox/camel-mbox-summary.h: added an extra field to store the next available uid. * camel/providers/mbox/camel-mbox-folder.c (_check_get_or_maybe_generate_summary_file): routine called when the folder is opened. Reads or creates the summary file. (_create): initialize the internal summary structure. (_close): save the summary file on closing. (_init_with_store): initialize mbox specific folder members. svn path=/trunk/; revision=1597 --- camel/providers/mbox/camel-mbox-folder.c | 256 ++++++++++++++++++------------ camel/providers/mbox/camel-mbox-folder.h | 11 +- camel/providers/mbox/camel-mbox-parser.c | 13 +- camel/providers/mbox/camel-mbox-parser.h | 1 + camel/providers/mbox/camel-mbox-summary.c | 49 +++++- camel/providers/mbox/camel-mbox-summary.h | 9 +- 6 files changed, 223 insertions(+), 116 deletions(-) (limited to 'camel') diff --git a/camel/providers/mbox/camel-mbox-folder.c b/camel/providers/mbox/camel-mbox-folder.c index 2420e59f43..64e589cba1 100644 --- a/camel/providers/mbox/camel-mbox-folder.c +++ b/camel/providers/mbox/camel-mbox-folder.c @@ -39,16 +39,14 @@ #include "camel-log.h" #include "camel-stream-buffered-fs.h" #include "camel-folder-summary.h" +#include "camel-mbox-summary.h" +#include "camel-mbox-parser.h" +#include "camel-mbox-utils.h" +#include "md5-utils.h" #include "gmime-utils.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 */ @@ -68,9 +66,9 @@ 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 CamelMimeMessage *_get_message_by_number (CamelFolder *folder, gint number, CamelException *ex);*/ static gint _get_message_count (CamelFolder *folder, CamelException *ex); +#if 0 static gint _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex); static void _expunge (CamelFolder *folder, CamelException *ex); static void _copy_message_to (CamelFolder *folder, CamelMimeMessage *message, CamelFolder *dest_folder, CamelException *ex); @@ -90,6 +88,7 @@ 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->set_name = _set_name; @@ -100,9 +99,9 @@ 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_by_number = _get_message_by_number; */ camel_folder_class->get_message_count = _get_message_count; +#if 0 camel_folder_class->append_message = _append_message; camel_folder_class->expunge = _expunge; camel_folder_class->copy_message_to = _copy_message_to; @@ -167,6 +166,9 @@ camel_mbox_folder_get_type (void) static void _init_with_store (CamelFolder *folder, CamelStore *parent_store, CamelException *ex) { + CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder); + + CAMEL_LOG_FULL_DEBUG ("Entering CamelMhFolder::init_with_store\n"); /* call parent method */ @@ -180,14 +182,104 @@ _init_with_store (CamelFolder *folder, CamelStore *parent_store, CamelException folder->can_hold_folders = TRUE; folder->has_summary_capability = TRUE; folder->has_uid_capability = TRUE; - - folder->summary = NULL; + folder->summary = NULL; + + mbox_folder->folder_file_path = NULL; + mbox_folder->summary_file_path = NULL; + mbox_folder->folder_dir_path = NULL; + mbox_folder->summary = NULL; + mbox_folder->uid_array = NULL; CAMEL_LOG_FULL_DEBUG ("Leaving CamelMhFolder::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) +{ + GArray *message_info_array; + gboolean summary_file_exists; + gboolean summary_file_is_sync; + GArray *mbox_summary_info; + gint mbox_file_fd; + guint32 next_uid; + + /* test for the existence of the summary file */ + summary_file_exists = (access (mbox_folder->summary_file_path, F_OK) == 0); + + /* if the summary file exists, test if the + md5 of the mbox file is still in sync + with the one we had computed the last time + we saved the summary file */ + if (summary_file_exists) { + + summary_file_is_sync = + camel_mbox_check_summary_sync (mbox_folder->summary_file_path, + mbox_folder->folder_file_path, + ex); + if (camel_exception_get_id (ex)) return; + } + + + /* in the case where the summary does not exist + or is not in sync with the mbox file + regenerate it */ + if ( !(summary_file_exists && summary_file_is_sync)) { + + /* parse the mbox folder and get some + information about the messages */ + + mbox_file_fd = open (mbox_folder->folder_file_path, O_RDONLY); + message_info_array = camel_mbox_parse_file (mbox_file_fd, + "From - ", + 0, + &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->folder_file_path, + message_info_array, 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); + + /* **FIXME : Free the parsed information structure */ + + /* allocate an internal summary object */ + mbox_folder->summary = g_new (CamelMboxSummary, 1); + + /* generate the folder md5 signature */ + md5_get_digest_from_file (mbox_folder->folder_file_path, mbox_folder->summary->md5_digest); + + /* store the number of messages as well as the summary array */ + mbox_folder->summary->nb_message = mbox_summary_info->len; + mbox_folder->summary->next_uid = next_uid; + mbox_folder->summary->message_info = mbox_summary_info; + + } else { + /* every thing seems ok, just read the summary file from disk */ + mbox_folder->summary = camel_mbox_load_summary ("ev-summary.mbox", ex); + } +} @@ -195,37 +287,27 @@ static void _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder); - struct dirent *dir_entry; - - + //struct dirent *dir_entry; + //struct stat stat_buf; + + if (folder->open_state == FOLDER_OPEN) { camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE, "folder is already open"); 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); + //if (!(mbox_load_uid_list (mbox_folder) > 0)) + // mbox_generate_uid_list (mbox_folder); -#endif + _check_get_or_maybe_generate_summary_file (mbox_folder, ex); } - - - - static void _close (CamelFolder *folder, gboolean expunge, CamelException *ex) { @@ -234,6 +316,9 @@ _close (CamelFolder *folder, gboolean expunge, CamelException *ex) /* call parent implementation */ parent_class->close (folder, expunge, ex); + + /* save the folder summary on disc */ + camel_mbox_save_summary (mbox_folder->summary, mbox_folder->summary_file_path, ex); } @@ -244,8 +329,8 @@ _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 *full_name; + //const gchar *parent_full_name; gchar separator; CAMEL_LOG_FULL_DEBUG ("Entering CamelMboxFolder::set_name\n"); @@ -265,6 +350,7 @@ _set_name (CamelFolder *folder, const gchar *name, CamelException *ex) 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->summary_file_path = g_strdup_printf ("%s%c.%s-ev-summary", 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); @@ -313,8 +399,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", @@ -327,19 +426,14 @@ _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_ISREG (stat_buf.st_mode); /* we should check the rights here */ @@ -410,7 +504,13 @@ _create (CamelFolder *folder, CamelException *ex) umask (old_umask); if (creat_fd == -1) goto io_error; close (creat_fd); - + + /* create the summary object */ + mbox_folder->summary = g_new (CamelMboxSummary, 1); + mbox_folder->summary->nb_message = 0; + mbox_folder->summary->next_uid = 1; + mbox_folder->summary->message_info = g_array_new (FALSE, FALSE, sizeof (CamelMboxSummaryInformation)); + return TRUE; /* exception handling for io errors */ @@ -472,7 +572,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; @@ -638,7 +738,7 @@ _list_subfolders (CamelFolder *folder, CamelException *ex) struct stat stat_buf; gint stat_error = 0; - GList *file_list; + //GList *file_list; gchar *entry_name; gchar *full_entry_name; gchar *real_folder_name; @@ -646,7 +746,7 @@ _list_subfolders (CamelFolder *folder, CamelException *ex) DIR *dir_handle; gboolean folder_suffix_found; - gchar *io_error_text; + //gchar *io_error_text; @@ -701,7 +801,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 */ @@ -757,61 +857,19 @@ _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) { - CamelMhFolder *mh_folder = CAMEL_MH_FOLDER(folder); - const gchar *directory_path; - gchar *message_name; - gchar *message_file_name; - CamelStream *input_stream = NULL; - CamelMimeMessage *message = NULL; - GList *message_list = NULL; - - g_assert(folder); - - directory_path = mh_folder->directory_path; - if (!directory_path) return NULL; + CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder); + gint message_count; - - - message_name = g_list_nth_data (mh_folder->file_name_list, number); + g_assert (folder); + g_assert (mbox_folder->summary); - 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); + message_count = mbox_folder->summary->nb_message; - } else - CAMEL_LOG_FULL_DEBUG ("CanelMhFolder::get_message message number = %d, not found\n", number); - - - return message; + CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::get_message_count found %d messages\n", message_count); + return message_count; } -#endif - - diff --git a/camel/providers/mbox/camel-mbox-folder.h b/camel/providers/mbox/camel-mbox-folder.h index 1f010ce605..0923d28d2e 100644 --- a/camel/providers/mbox/camel-mbox-folder.h +++ b/camel/providers/mbox/camel-mbox-folder.h @@ -35,6 +35,8 @@ extern "C" { #include #include "camel-folder.h" +#include "camel-mbox-summary.h" + /* #include "camel-store.h" */ #define CAMEL_MBOX_FOLDER_TYPE (camel_mbox_folder_get_type ()) @@ -46,9 +48,12 @@ extern "C" { typedef struct { CamelFolder parent_object; - gchar *folder_file_path; /* contains the messages */ - gchar *folder_dir_path; /* contains the subfolders */ - GArray *uid_array; + gchar *folder_file_path; /* contains the messages */ + gchar *summary_file_path; /* contains the messages summary */ + gchar *folder_dir_path; /* contains the subfolders */ + + CamelMboxSummary *summary; /* internal summary object */ + GList *uid_array; } CamelMboxFolder; diff --git a/camel/providers/mbox/camel-mbox-parser.c b/camel/providers/mbox/camel-mbox-parser.c index 7503470426..63c79a48e1 100644 --- a/camel/providers/mbox/camel-mbox-parser.c +++ b/camel/providers/mbox/camel-mbox-parser.c @@ -561,6 +561,7 @@ GArray * camel_mbox_parse_file (int fd, const gchar *message_delimiter, glong start_position, + guint32 *next_uid, gboolean get_message_summary, camel_mbox_preparser_status_callback *status_callback, double status_interval, @@ -577,8 +578,11 @@ camel_mbox_parse_file (int fd, gboolean newline; GArray *return_value; gchar *x_ev_header_content; + guint32 next_available_uid = 1; + g_assert (next_uid); + /* get file size */ fstat_result = fstat (fd, &stat_buf); if (fstat_result == -1) { @@ -720,11 +724,8 @@ camel_mbox_parse_file (int fd, G_STRUCT_OFFSET (CamelMboxPreParser, current_message_info) + G_STRUCT_OFFSET (CamelMboxParserMessageInfo, status))); g_free (x_ev_header_content); - - /* - parser->current_message_info.x_evolution_length = - parser->real_position - parser->current_message_info.x_evolution_position; - */ + next_available_uid = MAX (next_available_uid, parser->current_message_info.uid); + newline = TRUE; continue; } @@ -760,7 +761,7 @@ camel_mbox_parse_file (int fd, } return_value = parser->preparsed_messages; - + *next_uid = next_available_uid; /* free the parser */ parser_free (parser); diff --git a/camel/providers/mbox/camel-mbox-parser.h b/camel/providers/mbox/camel-mbox-parser.h index be01c2e0a5..fdf643d90c 100644 --- a/camel/providers/mbox/camel-mbox-parser.h +++ b/camel/providers/mbox/camel-mbox-parser.h @@ -57,6 +57,7 @@ GArray * camel_mbox_parse_file (int fd, const gchar *message_delimiter, glong start_position, + guint32 *next_uid, gboolean get_message_summary, camel_mbox_preparser_status_callback *status_callback, double status_interval, diff --git a/camel/providers/mbox/camel-mbox-summary.c b/camel/providers/mbox/camel-mbox-summary.c index 6915cd4a9b..c8ba96fe2f 100644 --- a/camel/providers/mbox/camel-mbox-summary.c +++ b/camel/providers/mbox/camel-mbox-summary.c @@ -65,11 +65,11 @@ camel_mbox_save_summary (CamelMboxSummary *summary, const gchar *filename, Camel /* compute and write the mbox file md5 signature */ //md5_get_digest_from_file (filename, summary->md5_digest); - /* write the number of messages + the md5 signatures */ - write (fd, summary, sizeof (guint) + sizeof (guchar) * 16); + /* write the number of messages + the md5 signatures + + next UID */ + write (fd, summary, sizeof (guint) + sizeof (guchar) * 16 + sizeof (guint32)); - printf ("%d %d\n", summary->nb_message, summary->message_info->len); for (cur_msg=0; cur_msg < summary->nb_message; cur_msg++) { msg_info = (CamelMboxSummaryInformation *)(summary->message_info->data) + cur_msg; @@ -80,7 +80,6 @@ camel_mbox_save_summary (CamelMboxSummary *summary, const gchar *filename, Camel sizeof (guint32) + sizeof (guint) + sizeof (guint32) + sizeof (guchar)); - //printf ("IN iewr subject = %s\n", msg_info->subject); /* write subject */ field_lgth = msg_info->subject ? strlen (msg_info->subject) : 0; write (fd, &field_lgth, sizeof (guint)); @@ -142,8 +141,9 @@ camel_mbox_load_summary (const gchar *filename, CamelException *ex) } summary = g_new0 (CamelMboxSummary, 1); - /* read the message number as well as the md5 signature */ - read (fd, summary, sizeof (guint) + sizeof (guchar) * 16); + /* read the message number, the md5 signature + and the next available UID */ + read (fd, summary, sizeof (guint) + sizeof (guchar) * 16 + sizeof (guint32)); summary->message_info = g_array_new (FALSE, FALSE, sizeof (CamelMboxSummaryInformation)); summary->message_info = g_array_set_size (summary->message_info, summary->nb_message); @@ -209,6 +209,43 @@ camel_mbox_load_summary (const gchar *filename, CamelException *ex) +gboolean +camel_mbox_check_summary_sync (gchar *summary_filename, + gchar *mbox_filename, + CamelException *ex) +{ + gint fd; + guchar summary_md5[16]; + guchar real_md5[16]; + + + CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::save_summary entering \n"); + fd = open (summary_filename, O_RDONLY); + if (fd == -1) { + camel_exception_setv (ex, + CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, + "could not open the mbox summary file\n" + "\t%s\n" + "Full error is : %s\n", + summary_filename, + strerror (errno)); + return FALSE; + } + + /* skip the message number field */ + lseek (fd, sizeof (guint), SEEK_SET); + + /* read the md5 signature stored in the summary file */ + read (fd, summary_md5, + sizeof (guchar) * 16); + close (fd); + /* ** FIXME : check for exception in all these operations */ + + /* compute the actual md5 signature on the + mbox file */ + md5_get_digest_from_file (mbox_filename, real_md5); + + return (strncmp (real_md5, summary_md5, 16) == 0); +} diff --git a/camel/providers/mbox/camel-mbox-summary.h b/camel/providers/mbox/camel-mbox-summary.h index 95d9574395..2d08e36164 100644 --- a/camel/providers/mbox/camel-mbox-summary.h +++ b/camel/providers/mbox/camel-mbox-summary.h @@ -26,7 +26,6 @@ #define MBOX_SUMMARY_H 1 #include -#include "camel-mbox-folder.h" @@ -47,7 +46,8 @@ typedef struct { typedef struct { guint nb_message; /* number of messages in the summary */ - guchar md5_digest[16]; /* md5 signature of the mbox file */ + guchar md5_digest[16]; /* md5 signature of the mbox file */ + guint32 next_uid; GArray *message_info; /* array of CamelMboxSummaryInformation */ @@ -60,6 +60,11 @@ camel_mbox_save_summary (CamelMboxSummary *summary, const gchar *filename, Camel CamelMboxSummary * camel_mbox_load_summary (const gchar *filename, CamelException *ex); +gboolean +camel_mbox_check_summary_sync (gchar *summary_filename, + gchar *mbox_filename, + CamelException *ex); + #endif /* MH_SUMMARY_H */ -- cgit