From a74c859d8c64ac576255fbc36b5f59468b42ddce Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 25 Mar 2000 05:18:55 +0000 Subject: change the CamelFolderSummary interfaces to allow partial summary queries * camel-folder-summary.[ch]: change the CamelFolderSummary interfaces to allow partial summary queries (for dealing with very large folders). Remove the "extended_fields" from CamelFolderInfo and CamelMessageInfo: this is better dealt with by subtyping. * providers/mbox/camel-mbox-summary.[ch]: Make CamelMboxSummary a subclass of CamelFolderSummary. Update interfaces for that. Remove the internal/external summary distinction. Remove the (unused) md5 checksum in the folder summary. Change the summary file format (primarily to make it no longer byte-order dependent) and add a version number to it so it will be easier to change in the future. * providers/mbox/camel-mbox-folder.[ch] * providers/mbox/camel-mbox-search.c * providers/mbox/camel-mbox-utils.c: update for summary changes * camel-exception-list.def: add CAMEL_EXCEPTION_FOLDER_SUMMARY_INVALID svn path=/trunk/; revision=2159 --- camel/providers/mbox/camel-mbox-summary.c | 564 ++++++++++++++++-------------- 1 file changed, 307 insertions(+), 257 deletions(-) (limited to 'camel/providers/mbox/camel-mbox-summary.c') diff --git a/camel/providers/mbox/camel-mbox-summary.c b/camel/providers/mbox/camel-mbox-summary.c index 9216f89e97..fd72206226 100644 --- a/camel/providers/mbox/camel-mbox-summary.c +++ b/camel/providers/mbox/camel-mbox-summary.c @@ -28,7 +28,6 @@ #include "camel-exception.h" #include "camel-mbox-folder.h" #include "camel-mbox-summary.h" -#include "camel-folder-summary.h" #include "md5-utils.h" @@ -41,104 +40,230 @@ #include #include +static CamelFolderSummaryClass *parent_class = NULL; +static int count_messages (CamelFolderSummary *summary); +static int count_subfolders (CamelFolderSummary *summary); +static GPtrArray *get_subfolder_info (CamelFolderSummary *summary, + int first, int count); +static GPtrArray *get_message_info (CamelFolderSummary *summary, + int first, int count); +static void finalize (GtkObject *object); +static void +camel_mbox_summary_class_init (CamelMboxSummaryClass *camel_mbox_summary_class) +{ + GtkObjectClass *gtk_object_class = + GTK_OBJECT_CLASS (camel_mbox_summary_class); + CamelFolderSummaryClass *camel_folder_summary_class = + CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_class); -/* - * The mbox provider uses a summary files, - * so that it has an internal and an external - * summary. The internal summary is a summary - * containing a lot of information, including - * infos on how to access mails in the mbox file - * - * On the other hand, the external summary is - * an implementation of the structure defined in - * the camel-folder-summary file (toplevel camel - * directory) - * - * To sum up, the internal summary is only a - * subset of the internal summary. - */ + parent_class = gtk_type_class (camel_folder_summary_get_type ()); + + /* virtual method override */ + camel_folder_summary_class->count_messages = count_messages; + camel_folder_summary_class->count_subfolders = count_subfolders; + camel_folder_summary_class->get_subfolder_info = get_subfolder_info; + camel_folder_summary_class->get_message_info = get_message_info; + + gtk_object_class->finalize = finalize; +} + + +GtkType +camel_mbox_summary_get_type (void) +{ + static GtkType camel_mbox_summary_type = 0; + + if (!camel_mbox_summary_type) { + GtkTypeInfo camel_mbox_summary_info = + { + "CamelMboxSummary", + sizeof (CamelMboxSummary), + sizeof (CamelMboxSummaryClass), + (GtkClassInitFunc) camel_mbox_summary_class_init, + (GtkObjectInitFunc) NULL, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + camel_mbox_summary_type = gtk_type_unique (camel_folder_summary_get_type (), &camel_mbox_summary_info); + } + + return camel_mbox_summary_type; +} + +static void +finalize (GtkObject *object) +{ + CamelMboxSummary *summary = CAMEL_MBOX_SUMMARY (object); + CamelMboxSummaryInformation *info; + int i; + + for (i = 0; i < summary->message_info->len; i++) { + info = &(((CamelMboxSummaryInformation *)summary->message_info->data)[i]); + g_free (info->headers.subject); + g_free (info->headers.sender); + g_free (info->headers.to); + g_free (info->headers.sent_date); + g_free (info->headers.received_date); + g_free (info->headers.uid); + } + g_array_free (summary->message_info, TRUE); + + GTK_OBJECT_CLASS (parent_class)->finalize (object); +} + +static int +count_messages (CamelFolderSummary *summary) +{ + return CAMEL_MBOX_SUMMARY (summary)->nb_message; +} + +static int +count_subfolders (CamelFolderSummary *summary) +{ + /* XXX */ + g_warning ("CamelMboxSummary::count_subfolders not implemented"); + return 0; +} +static GPtrArray * +get_subfolder_info (CamelFolderSummary *summary, int first, int count) +{ + /* XXX */ + g_warning ("CamelMboxSummary::count_subfolders not implemented"); + return 0; +} +static GPtrArray * +get_message_info (CamelFolderSummary *summary, int first, int count) +{ + CamelMboxSummary *mbox_summary = CAMEL_MBOX_SUMMARY (summary); + CamelMboxSummaryInformation *info; + GPtrArray *arr; + + /* XXX bounds check */ + + arr = g_ptr_array_new (); + for (; count; count--) { + info = &((CamelMboxSummaryInformation *)mbox_summary->message_info->data)[first++]; + g_ptr_array_add (arr, info); + } + + return arr; +} /** - * camel_mbox_save_summary: + * camel_mbox_summary_save: * @summary: * @filename: * @ex: * - * save the internal summary into a file + * save the summary into a file **/ void -camel_mbox_save_summary (CamelMboxSummary *summary, const gchar *filename, CamelException *ex) +camel_mbox_summary_save (CamelMboxSummary *summary, const gchar *filename, + CamelException *ex) { CamelMboxSummaryInformation *msg_info; guint cur_msg; - guint field_lgth; + guint field_length; gint fd; - gint write_result; + gint write_result; /* XXX use this */ + guint32 data; CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::save_summary entering \n"); - fd = open (filename, - O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR); + fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR); if (fd == -1) { - camel_exception_setv (ex, - CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, - "could not create the mbox summary file\n" - "\t%s\n" - "Full error is : %s\n", - filename, - strerror (errno)); - return; - } - - /* 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 - + next UID + mbox file size */ - write_result = write (fd, summary, G_STRUCT_OFFSET (CamelMboxSummary, message_info)); - - - for (cur_msg=0; cur_msg < summary->nb_message; cur_msg++) { - - msg_info = (CamelMboxSummaryInformation *)(summary->message_info->data) + cur_msg; - - /* write message position + message size - + x-evolution offset + uid + status */ - write (fd, (gchar *)msg_info, - sizeof (guint32) + 2 * sizeof (guint) + - sizeof (guint32) + sizeof (guchar)); - - /* write subject */ - field_lgth = msg_info->subject ? strlen (msg_info->subject) : 0; - write (fd, &field_lgth, sizeof (guint)); - if (field_lgth) - write (fd, msg_info->subject, field_lgth); - /* write sender */ - field_lgth = msg_info->sender ? strlen (msg_info->sender) : 0; - write (fd, &field_lgth, sizeof (gint)); - if (field_lgth) - write (fd, msg_info->sender, field_lgth); - - /* write to */ - field_lgth = msg_info->to ? strlen (msg_info->to) : 0; - write (fd, &field_lgth, sizeof (gint)); - if (field_lgth) - write (fd, msg_info->to, field_lgth); - - /* write date */ - field_lgth = msg_info->date ? strlen (msg_info->date) : 0; - write (fd, &field_lgth, sizeof (guint)); - if (field_lgth) - write (fd, msg_info->date, field_lgth); - + camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, + "could not create the mbox summary " + "file\n\t%s\nFull error is : %s\n", + filename, + strerror (errno)); + return; + } + /* We write the file out in network byte order, not because + * that makes sense, but because it's easy. + */ + + data = htons (CAMEL_MBOX_SUMMARY_VERSION); + write (fd, &data, sizeof (data)); + + data = htons (summary->nb_message); + write (fd, &data, sizeof (data)); + data = htons (summary->next_uid); + write (fd, &data, sizeof (data)); + data = htons (summary->mbox_file_size); + write (fd, &data, sizeof (data)); + data = htons (summary->mbox_modtime); + write (fd, &data, sizeof (data)); + + for (cur_msg = 0; cur_msg < summary->nb_message; cur_msg++) { + msg_info = (CamelMboxSummaryInformation *) + (summary->message_info->data) + cur_msg; + + /* Write meta-info. */ + data = htons (msg_info->position); + write (fd, &data, sizeof (data)); + data = htons (msg_info->size); + write (fd, &data, sizeof (data)); + data = htons (msg_info->x_evolution_offset); + write (fd, &data, sizeof (data)); + data = htons (msg_info->uid); + write (fd, &data, sizeof (data)); + write (fd, &msg_info->status, 1); + + /* Write subject. */ + if (msg_info->headers.subject) + field_length = htons (strlen (msg_info->headers.subject)); + else + field_length = 0; + write (fd, &field_length, sizeof (field_length)); + if (msg_info->headers.subject) + write (fd, msg_info->headers.subject, field_length); + + /* Write sender. */ + if (msg_info->headers.sender) + field_length = htons (strlen (msg_info->headers.sender)); + else + field_length = 0; + write (fd, &field_length, sizeof (field_length)); + if (msg_info->headers.sender) + write (fd, msg_info->headers.sender, field_length); + + /* Write to. */ + if (msg_info->headers.to) + field_length = htons (strlen (msg_info->headers.to)); + else + field_length = 0; + write (fd, &field_length, sizeof (field_length)); + if (msg_info->headers.to) + write (fd, msg_info->headers.to, field_length); + + /* Write sent date. */ + if (msg_info->headers.sent_date) + field_length = htons (strlen (msg_info->headers.sent_date)); + else + field_length = 0; + write (fd, &field_length, sizeof (field_length)); + if (msg_info->headers.sent_date) + write (fd, msg_info->headers.sent_date, field_length); + + /* Write received date. */ + if (msg_info->headers.received_date) + field_length = htons (strlen (msg_info->headers.received_date)); + else + field_length = 0; + write (fd, &field_length, sizeof (field_length)); + if (msg_info->headers.received_date) + write (fd, msg_info->headers.received_date, field_length); } - + close (fd); CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::save_summary leaving \n"); @@ -146,227 +271,152 @@ camel_mbox_save_summary (CamelMboxSummary *summary, const gchar *filename, Camel - - /** - * camel_mbox_load_summary: + * camel_mbox_summary_load: * @filename: * @ex: * - * load the internal summary from a file + * load the summary from a file * * Return value: **/ CamelMboxSummary * -camel_mbox_load_summary (const gchar *filename, CamelException *ex) +camel_mbox_summary_load (const gchar *filename, CamelException *ex) { CamelMboxSummaryInformation *msg_info; guint cur_msg; - guint field_lgth; + guint field_length; gint fd; CamelMboxSummary *summary; gint read_result; + guint32 data; CAMEL_LOG_FULL_DEBUG ("CamelMboxFolder::save_summary entering \n"); fd = open (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", - filename, - strerror (errno)); - return NULL; - } - summary = g_new0 (CamelMboxSummary, 1); - - /* read the message number, the md5 signature - and the next available UID + mbox file size */ - read_result = read (fd, summary, G_STRUCT_OFFSET (CamelMboxSummary, message_info)); - - - summary->message_info = g_array_new (FALSE, FALSE, sizeof (CamelMboxSummaryInformation)); - summary->message_info = g_array_set_size (summary->message_info, summary->nb_message); - - - for (cur_msg=0; cur_msg < summary->nb_message; cur_msg++) { - - msg_info = (CamelMboxSummaryInformation *)(summary->message_info->data) + cur_msg; - - /* read message position + message size - + x-evolution offset + uid + status */ - read (fd, (gchar *)msg_info, - sizeof (guint32) + 2 * sizeof (guint) + - sizeof (guint32) + sizeof (guchar)); - + camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, + "could not open the mbox summary file\n" + "\t%s\nFull error is : %s\n", + filename, strerror (errno)); + return NULL; + } - /* read the subject */ - read (fd, &field_lgth, sizeof (gint)); - if (field_lgth > 0) { - msg_info->subject = g_new0 (gchar, field_lgth + 1); - read (fd, msg_info->subject, field_lgth); + /* Verify version number. */ + read (fd, &data, sizeof(data)); + data = ntohs (data); + + if (data != CAMEL_MBOX_SUMMARY_VERSION) { + camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_SUMMARY_INVALID, + "This folder summary was written by " + "%s version of this software.", + data < CAMEL_MBOX_SUMMARY_VERSION ? + "an older" : "a newer"); + return NULL; + } + + summary = CAMEL_MBOX_SUMMARY (gtk_object_new (camel_mbox_summary_get_type (), NULL)); + + read (fd, &data, sizeof(data)); + summary->nb_message = ntohs (data); + read (fd, &data, sizeof(data)); + summary->next_uid = ntohs (data); + read (fd, &data, sizeof(data)); + summary->mbox_file_size = ntohs (data); + read (fd, &data, sizeof(data)); + summary->mbox_modtime = ntohs (data); + + summary->message_info = + g_array_new (FALSE, FALSE, + sizeof (CamelMboxSummaryInformation)); + g_array_set_size (summary->message_info, summary->nb_message); + + for (cur_msg = 0; cur_msg < summary->nb_message; cur_msg++) { + msg_info = (CamelMboxSummaryInformation *) + (summary->message_info->data) + cur_msg; + + /* Read the meta-info. */ + read (fd, &data, sizeof(data)); + msg_info->position = ntohs (data); + read (fd, &data, sizeof(data)); + msg_info->size = ntohs (data); + read (fd, &data, sizeof(data)); + msg_info->x_evolution_offset = ntohs (data); + read (fd, &(msg_info->status), 1); + read (fd, &data, sizeof(data)); + msg_info->uid = ntohs (data); + msg_info->headers.uid = g_strdup_printf ("%d", msg_info->uid); + read (fd, &msg_info->status, 1); + + /* Read the subject. */ + read (fd, &field_length, sizeof (field_length)); + field_length = ntohs (field_length); + if (field_length > 0) { + msg_info->headers.subject = + g_new0 (gchar, field_length + 1); + read (fd, msg_info->headers.subject, field_length); } else - msg_info->subject = NULL; + msg_info->headers.subject = NULL; - /* read the sender */ - read (fd, &field_lgth, sizeof (gint)); - if (field_lgth > 0) { - msg_info->sender = g_new0 (gchar, field_lgth + 1); - read (fd, msg_info->sender, field_lgth); + /* Read the sender. */ + read (fd, &field_length, sizeof (field_length)); + field_length = ntohs (field_length); + if (field_length > 0) { + msg_info->headers.sender = + g_new0 (gchar, field_length + 1); + read (fd, msg_info->headers.sender, field_length); } else - msg_info->sender = NULL; + msg_info->headers.sender = NULL; - /* read the "to" field */ - read (fd, &field_lgth, sizeof (gint)); - if (field_lgth > 0) { - msg_info->to = g_new0 (gchar, field_lgth + 1); - read (fd, msg_info->to, field_lgth); + /* Read the "to" field. */ + read (fd, &field_length, sizeof (field_length)); + field_length = ntohs (field_length); + if (field_length > 0) { + msg_info->headers.to = + g_new0 (gchar, field_length + 1); + read (fd, msg_info->headers.to, field_length); } else - msg_info->to = NULL; - - /* read the "date" field */ - read (fd, &field_lgth, sizeof (gint)); - if (field_lgth > 0) { - msg_info->date = g_new0 (gchar, field_lgth + 1); - read (fd, msg_info->date, field_lgth); + msg_info->headers.to = NULL; + + /* Read the sent date field. */ + read (fd, &field_length, sizeof (field_length)); + field_length = ntohs (field_length); + if (field_length > 0) { + msg_info->headers.sent_date = + g_new0 (gchar, field_length + 1); + read (fd, msg_info->headers.sent_date, field_length); } else - msg_info->date = NULL; - - - - + msg_info->headers.sent_date = NULL; + + /* Read the received date field. */ + read (fd, &field_length, sizeof (field_length)); + field_length = ntohs (field_length); + if (field_length > 0) { + msg_info->headers.received_date = + g_new0 (gchar, field_length + 1); + read (fd, msg_info->headers.received_date, + field_length); + } else + msg_info->headers.received_date = NULL; } - - close (fd); - return summary; -} - - - - - - - - - -/** - * camel_mbox_check_summary_sync: - * @summary_filename: - * @mbox_filename: - * @ex: - * - * check if the summary file is in sync with the mbox file - * - * Return value: - **/ -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); + return summary; } - - - /** * camel_mbox_summary_append_entries: * @summary: * @entries: * - * append an entry to an internal summary + * append an entry to a summary **/ void camel_mbox_summary_append_entries (CamelMboxSummary *summary, GArray *entries) { - - summary->message_info = g_array_append_vals (summary->message_info, entries->data, entries->len); - -} - - - - -/** - * camel_mbox_summary_append_internal_to_external: - * @internal: - * @external: - * @first_entry: first entry to append. - * - * append some entries from the internal summary to - * the external one. - **/ -void -camel_mbox_summary_append_internal_to_external (CamelMboxSummary *internal, - CamelFolderSummary *external, - guint first_entry) -{ - GArray *internal_array; - GArray *external_array; - - CamelMessageInfo external_entry; - CamelMboxSummaryInformation *internal_entry; - - int i; - - - internal_array = internal->message_info; - external_array = external->message_info_list; - - /* we don't set any extra fields */ - external_entry.extended_fields = NULL; - - - for (i=first_entry; ilen; i++) { - internal_entry = (CamelMboxSummaryInformation *)(internal_array->data) + i; - - external_entry.subject = internal_entry->subject ? strdup (internal_entry->subject) : NULL; - external_entry.uid = g_strdup_printf ("%u", internal_entry->uid); - external_entry.sent_date = internal_entry->date ? strdup (internal_entry->date) : NULL; - external_entry.sender = internal_entry->sender ? strdup (internal_entry->sender) : NULL; - external_entry.size = internal_entry->size; - - g_array_append_vals (external_array, &external_entry, 1); - - } - - + summary->message_info = g_array_append_vals (summary->message_info, + entries->data, + entries->len); } - -- cgit v1.2.3