From fed684880e2a47aaa0ee109bd8df0db1a5589c79 Mon Sep 17 00:00:00 2001 From: NotZed Date: Mon, 1 May 2000 19:47:12 +0000 Subject: More message cleanup. Flags now work, are saved, and the delete flag causes an expunge to expunge the deleted messages. 2000-05-01 NotZed * providers/mbox/camel-mbox-summary.c (camel_mbox_summary_set_flags_by_uid): New function to update the flags in the summary. (camel_mbox_summary_expunge): Expunge messages from a folder. (offset_content): Re-align offsets of summary when messages added/removed to an existing summary. (camel_mbox_summary_remove_uid): Remove a message summary entry by uid. (index_folder): Restore flags from X-Evolution header, if they are set. * providers/mbox/camel-mbox-folder.c (_get_message_by_uid): Connect to the message_changed signal. (_init): Set permanent flags to something reasonable. No user flags yet ... (message_changed): If the flags of the message change, update the flags in the summary. (mbox_expunge): Implement the expunge. (camel_mbox_folder_class_init): Renamed all leading _'s to mbox_'s * camel-folder.c (_finalize): Uh, dont free permanent_flags anymore (this wouldn't failed anyway, it was a GList !!!) * camel-folder.h (struct _CamelFolder): Change permanent_flags to a bitfield. (list_permanent_flags): Renamed to get_permanent_flags, and returns a bitfield. (camel_folder_expunge): Changed expunge to a void type. The messages would no longer be useful after they have been removed ... * camel-mime-message.c (set_flag): Removed. (camel_mime_message_set_flag): Removed. (get_flag): Removed. (camel_mime_message_get_flag): Removed. (add_flag_to_list): Removed. (get_flag_list): Removed. (camel_mime_message_get_flag_list): Removed. (camel_mime_message_get_flags): New interface to get system flags. (camel_mime_message_set_flags): " to set ". (camel_mime_message_get_user_flag): To get a user flag. (camel_mime_message_set_user_flag): To set a user flag. (finalize): Hmm, the old one free'd the key and data, not good when the data is a boolean ... svn path=/trunk/; revision=2716 --- camel/ChangeLog | 46 ++++++ camel/camel-folder.c | 24 ++-- camel/camel-folder.h | 16 +-- camel/camel-mime-message.c | 121 ++++++++-------- camel/camel-mime-message.h | 74 ++++------ camel/providers/mbox/camel-mbox-folder.c | 133 ++++++++++++------ camel/providers/mbox/camel-mbox-summary.c | 225 +++++++++++++++++++++++++++++- camel/providers/mbox/camel-mbox-summary.h | 6 + 8 files changed, 469 insertions(+), 176 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 6c28e6371c..e3e601cb09 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,49 @@ +2000-05-01 NotZed + + * providers/mbox/camel-mbox-summary.c + (camel_mbox_summary_set_flags_by_uid): New function to update the + flags in the summary. + (camel_mbox_summary_expunge): Expunge messages from a folder. + (offset_content): Re-align offsets of summary when messages + added/removed to an existing summary. + (camel_mbox_summary_remove_uid): Remove a message summary entry by + uid. + (index_folder): Restore flags from X-Evolution header, if they are set. + + * providers/mbox/camel-mbox-folder.c (_get_message_by_uid): + Connect to the message_changed signal. + (_init): Set permanent flags to something reasonable. No user + flags yet ... + (message_changed): If the flags of the message change, update the + flags in the summary. + (mbox_expunge): Implement the expunge. + (camel_mbox_folder_class_init): Renamed all leading _'s to mbox_'s + + * camel-folder.c (_finalize): Uh, dont free permanent_flags + anymore (this wouldn't failed anyway, it was a GList !!!) + + * camel-folder.h (struct _CamelFolder): Change permanent_flags to + a bitfield. + (list_permanent_flags): Renamed to get_permanent_flags, and + returns a bitfield. + (camel_folder_expunge): Changed expunge to a void type. The + messages would no longer be useful after they have been removed + ... + + * camel-mime-message.c (set_flag): Removed. + (camel_mime_message_set_flag): Removed. + (get_flag): Removed. + (camel_mime_message_get_flag): Removed. + (add_flag_to_list): Removed. + (get_flag_list): Removed. + (camel_mime_message_get_flag_list): Removed. + (camel_mime_message_get_flags): New interface to get system flags. + (camel_mime_message_set_flags): " to set ". + (camel_mime_message_get_user_flag): To get a user flag. + (camel_mime_message_set_user_flag): To set a user flag. + (finalize): Hmm, the old one free'd the key and data, not good + when the data is a boolean ... + 2000-04-30 Dan Winship * camel-provider.h: Tweak the definition of CamelProvider. Among diff --git a/camel/camel-folder.c b/camel/camel-folder.c index 31141da5c9..c0d0e5fcb3 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -74,8 +74,8 @@ static gboolean _can_hold_folders (CamelFolder *folder); static gboolean _can_hold_messages (CamelFolder *folder); static gboolean _exists (CamelFolder *folder, CamelException *ex); static gboolean _is_open (CamelFolder *folder); -static const GList *_list_permanent_flags (CamelFolder *folder, - CamelException *ex); +static guint32 _get_permanent_flags (CamelFolder *folder, + CamelException *ex); static CamelFolderOpenMode _get_mode (CamelFolder *folder, CamelException *ex); @@ -108,7 +108,7 @@ static gint _get_message_count (CamelFolder *folder, static gboolean _delete_messages (CamelFolder *folder, CamelException *ex); -static GList * _expunge (CamelFolder *folder, +static void _expunge (CamelFolder *folder, CamelException *ex); static void _append_message (CamelFolder *folder, CamelMimeMessage *message, @@ -172,7 +172,7 @@ camel_folder_class_init (CamelFolderClass *camel_folder_class) camel_folder_class->delete_message_by_number = _delete_message_by_number; camel_folder_class->get_message_count = _get_message_count; camel_folder_class->append_message = _append_message; - camel_folder_class->list_permanent_flags = _list_permanent_flags; + camel_folder_class->get_permanent_flags = _get_permanent_flags; 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; @@ -224,7 +224,6 @@ _finalize (GtkObject *object) g_free (camel_folder->name); g_free (camel_folder->full_name); - g_free (camel_folder->permanent_flags); if (camel_folder->parent_store) gtk_object_unref (GTK_OBJECT (camel_folder->parent_store)); @@ -974,12 +973,11 @@ camel_folder_list_subfolders (CamelFolder *folder, CamelException *ex) -static GList * +static void _expunge (CamelFolder *folder, CamelException *ex) { g_warning ("CamelFolder::expunge not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (folder))); - return NULL; } @@ -991,7 +989,7 @@ _expunge (CamelFolder *folder, CamelException *ex) * * Return value: list of expunged messages **/ -GList * +void camel_folder_expunge (CamelFolder *folder, CamelException *ex) { g_assert (folder != NULL); @@ -1154,18 +1152,18 @@ camel_folder_append_message (CamelFolder *folder, } -static const GList * -_list_permanent_flags (CamelFolder *folder, CamelException *ex) +static guint32 +_get_permanent_flags (CamelFolder *folder, CamelException *ex) { return folder->permanent_flags; } -const GList * -camel_folder_list_permanent_flags (CamelFolder *folder, CamelException *ex) +guint32 +camel_folder_get_permanent_flags (CamelFolder *folder, CamelException *ex) { g_assert (folder != NULL); - return CF_CLASS (folder)->list_permanent_flags (folder, ex); + return CF_CLASS (folder)->get_permanent_flags (folder, ex); } diff --git a/camel/camel-folder.h b/camel/camel-folder.h index b8b2db0da5..15d8194d2e 100644 --- a/camel/camel-folder.h +++ b/camel/camel-folder.h @@ -96,7 +96,6 @@ typedef struct { gchar *uid; guint32 flags; - time_t date_sent; time_t date_received; @@ -116,7 +115,7 @@ struct _CamelFolder gchar separator; CamelStore *parent_store; CamelFolder *parent_folder; - GList *permanent_flags; + guint32 permanent_flags; gboolean can_hold_folders:1; gboolean can_hold_messages:1; @@ -194,8 +193,8 @@ typedef struct { GList * (*list_subfolders) (CamelFolder *folder, CamelException *ex); - GList * (*expunge) (CamelFolder *folder, - CamelException *ex); + void (*expunge) (CamelFolder *folder, + CamelException *ex); gboolean (*has_message_number_capability) (CamelFolder *folder); @@ -214,8 +213,8 @@ typedef struct { CamelMimeMessage *message, CamelException *ex); - const GList * (*list_permanent_flags) (CamelFolder *folder, - CamelException *ex); + guint32 (*get_permanent_flags) (CamelFolder *folder, + CamelException *ex); void (*copy_message_to) (CamelFolder *folder, CamelMimeMessage *message, @@ -291,7 +290,7 @@ gboolean camel_folder_delete (CamelFolder *folder, CamelException *ex); gboolean camel_folder_delete_messages (CamelFolder *folder, CamelException *ex); -GList * camel_folder_expunge (CamelFolder *folder, +void camel_folder_expunge (CamelFolder *folder, CamelException *ex); @@ -303,8 +302,9 @@ const gchar * camel_folder_get_full_name (CamelFolder *folder); /* various properties accessors */ gboolean camel_folder_exists (CamelFolder *folder, CamelException *ex); -const GList * camel_folder_list_permanent_flags (CamelFolder *folder, +guint32 camel_folder_get_permanent_flags (CamelFolder *folder, CamelException *ex); + CamelFolderOpenMode camel_folder_get_mode (CamelFolder *folder, CamelException *ex); gboolean camel_folder_is_open (CamelFolder *folder); diff --git a/camel/camel-mime-message.c b/camel/camel-mime-message.c index 39da00593a..c1cf13403a 100644 --- a/camel/camel-mime-message.c +++ b/camel/camel-mime-message.c @@ -58,10 +58,13 @@ static char *recipient_names[] = { "To", "Cc", "Bcc", NULL }; +enum SIGNALS { + MESSAGE_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; -static void set_flag (CamelMimeMessage *mime_message, const gchar *flag, gboolean value); -static gboolean get_flag (CamelMimeMessage *mime_message, const gchar *flag); -static GList *get_flag_list (CamelMimeMessage *mime_message); static void set_message_number (CamelMimeMessage *mime_message, guint number); static guint get_message_number (CamelMimeMessage *mime_message); static int write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream); @@ -92,9 +95,6 @@ camel_mime_message_class_init (CamelMimeMessageClass *camel_mime_message_class) g_hash_table_insert (header_name_table, header_names[i], (gpointer)i+1); /* virtual method definition */ - camel_mime_message_class->set_flag = set_flag; - camel_mime_message_class->get_flag = get_flag; - camel_mime_message_class->get_flag_list = get_flag_list; camel_mime_message_class->set_message_number = set_message_number; camel_mime_message_class->get_message_number = get_message_number; @@ -107,6 +107,16 @@ camel_mime_message_class_init (CamelMimeMessageClass *camel_mime_message_class) camel_mime_part_class->construct_from_parser = construct_from_parser; + signals[MESSAGE_CHANGED] = + gtk_signal_new ("message_changed", + GTK_RUN_LAST, + gtk_object_class->type, + GTK_SIGNAL_OFFSET (CamelMimeMessageClass, message_changed), + gtk_marshal_NONE__INT, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + gtk_object_class_add_signals (gtk_object_class, signals, LAST_SIGNAL); + gtk_object_class->finalize = finalize; } @@ -126,7 +136,8 @@ camel_mime_message_init (gpointer object, gpointer klass) g_hash_table_insert(mime_message->recipients, recipient_names[i], camel_internet_address_new()); } - mime_message->flags = g_hash_table_new (g_strcase_hash, g_strcase_equal); + mime_message->user_flags = g_hash_table_new (g_strcase_hash, g_strcase_equal); + mime_message->flags = 0; mime_message->subject = NULL; mime_message->reply_to = NULL; @@ -168,6 +179,11 @@ static void g_lib_is_uber_crappy_shit(gpointer whocares, gpointer getlost, gpoin gtk_object_unref((GtkObject *)getlost); } +static void free_key_only(gpointer whocares, gpointer getlost, gpointer blah) +{ + g_free(whocares); +} + static void finalize (GtkObject *object) { @@ -179,13 +195,13 @@ finalize (GtkObject *object) g_free (message->from); g_hash_table_foreach (message->recipients, g_lib_is_uber_crappy_shit, NULL); + + if (message->user_flags) + g_hash_table_foreach (message->user_flags, free_key_only, NULL); + g_hash_table_destroy(message->user_flags); if (message->folder) gtk_object_unref (GTK_OBJECT (message->folder)); - - if (message->flags) - g_hash_table_foreach (message->flags, g_hash_table_generic_free, NULL); - g_hash_table_destroy(message->flags); GTK_OBJECT_CLASS (parent_class)->finalize (object); } @@ -413,81 +429,56 @@ camel_mime_message_get_recipients (CamelMimeMessage *mime_message, /* **** */ - -static void -set_flag (CamelMimeMessage *mime_message, const gchar *flag, gboolean value) +guint32 +camel_mime_message_get_flags (CamelMimeMessage *m) { - gchar *old_flags; - gboolean ptr_value; - - if (! g_hash_table_lookup_extended (mime_message->flags, - flag, - (gpointer)&(old_flags), - (gpointer)&(ptr_value)) ) { - - g_hash_table_insert (mime_message->flags, g_strdup (flag), GINT_TO_POINTER (value)); - } else - g_hash_table_insert (mime_message->flags, old_flags, GINT_TO_POINTER (value)); - + return m->flags; } void -camel_mime_message_set_flag (CamelMimeMessage *mime_message, const gchar *flag, gboolean value) +camel_mime_message_set_flags (CamelMimeMessage *m, guint32 flags, guint32 set) { - g_assert (mime_message); - g_return_if_fail (!mime_message->expunged); - CMM_CLASS (mime_message)->set_flag (mime_message, flag, value); -} + guint32 old; + printf("%p setting flags %x mask %x\n", m, flags, set); + old = m->flags; + m->flags = (m->flags & ~flags) | (set & flags); -static gboolean -get_flag (CamelMimeMessage *mime_message, const gchar *flag) -{ - return GPOINTER_TO_INT (g_hash_table_lookup (mime_message->flags, flag)); -} + printf("old = %x new = %x\n", old, m->flags); -gboolean -camel_mime_message_get_flag (CamelMimeMessage *mime_message, const gchar *flag) -{ - g_assert (mime_message); - g_return_val_if_fail (!mime_message->expunged, FALSE); - return CMM_CLASS (mime_message)->get_flag (mime_message, flag); + if (old != m->flags) + gtk_signal_emit((GtkObject *)m, signals[MESSAGE_CHANGED], MESSAGE_FLAGS_CHANGED); } - - -static void -add_flag_to_list (gpointer key, gpointer value, gpointer user_data) +gboolean +camel_mime_message_get_user_flag (CamelMimeMessage *m, const char *name) { - GList **flag_list = (GList **)user_data; - gchar *flag_name = (gchar *)key; - - if ((flag_name) && (flag_name[0] != '\0')) - *flag_list = g_list_append (*flag_list, flag_name); + return (gboolean)g_hash_table_lookup(m->user_flags, name); } -static GList * -get_flag_list (CamelMimeMessage *mime_message) +void +camel_mime_message_set_user_flag (CamelMimeMessage *m, const char *name, gboolean value) { - GList *flag_list = NULL; - - if (mime_message->flags) - g_hash_table_foreach (mime_message->flags, add_flag_to_list, &flag_list); - return flag_list; -} + gboolean there; + char *oldname; + gboolean oldvalue; + there = g_hash_table_lookup_extended(m->user_flags, name, &oldname, &oldvalue); -GList * -camel_mime_message_get_flag_list (CamelMimeMessage *mime_message) -{ - g_assert (mime_message); - g_return_val_if_fail (!mime_message->expunged, NULL); - return CMM_CLASS (mime_message)->get_flag_list (mime_message); + if (value && !there) { + g_hash_table_insert(m->user_flags, g_strdup(name), (void *)TRUE); + gtk_signal_emit((GtkObject *)m, signals[MESSAGE_CHANGED], MESSAGE_FLAGS_CHANGED); + } else if (there) { + g_hash_table_remove(m->user_flags, name); + g_free(oldname); + gtk_signal_emit((GtkObject *)m, signals[MESSAGE_CHANGED], MESSAGE_FLAGS_CHANGED); + } } +/* FIXME: to be removed??? */ static void set_message_number (CamelMimeMessage *mime_message, guint number) { diff --git a/camel/camel-mime-message.h b/camel/camel-mime-message.h index 141747e3cb..c790138f70 100644 --- a/camel/camel-mime-message.h +++ b/camel/camel-mime-message.h @@ -1,10 +1,8 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camelMimeMessage.h : class for a mime message */ - -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */ +/* camelMimeMessage.h : class for a mime message * - * Author : - * Bertrand Guiheneuf + * Authors: Bertrand Guiheneuf + * Michael Zucchi * * Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com) * @@ -54,6 +52,18 @@ extern "C" { /* specify local time */ #define CAMEL_MESSAGE_DATE_CURRENT (~0) +/* system flag bits */ +enum _CamelMessageFlags { + CAMEL_MESSAGE_ANSWERED = 1<<0, + CAMEL_MESSAGE_DELETED = 1<<1, + CAMEL_MESSAGE_DRAFT = 1<<2, + CAMEL_MESSAGE_FLAGGED = 1<<3, + CAMEL_MESSAGE_SEEN = 1<<4, + /* following flags are for the folder, and are not really permanent flags */ + CAMEL_MESSAGE_FOLDER_FLAGGED = 1<<16, /* for use by the folder implementation */ + CAMEL_MESSAGE_USER = 1<<31 /* supports user flags */ +}; + struct _CamelMimeMessage { CamelMimePart parent_object; @@ -71,49 +81,28 @@ struct _CamelMimeMessage GHashTable *recipients; /* hash table of CamelInternetAddress's */ /* other fields */ - GHashTable *flags; /* boolean values */ + guint32 flags; /* system flags */ + GHashTable *user_flags; /* if present, then true */ gboolean expunged; guint message_number; /* set by folder object when retrieving message */ gchar *message_uid; CamelFolder *folder; - }; - +enum _MessageChangeType { + MESSAGE_FLAGS_CHANGED, + MESSAGE_ENVELOPE_CHANGED, +}; typedef struct { CamelMimePartClass parent_class; - + + /* signals */ + void (*message_changed) (CamelMimeMessage *, enum _MessageChangeType type); + /* Virtual methods */ - void (*set_received_date) (CamelMimeMessage *mime_message, - const gchar *received_date); - const gchar * (*get_received_date) (CamelMimeMessage *mime_message); - const gchar * (*get_sent_date) (CamelMimeMessage *mime_message); - void (*set_reply_to) (CamelMimeMessage *mime_message, - const gchar *reply_to); - const gchar * (*get_reply_to) (CamelMimeMessage *mime_message); - void (*set_subject) (CamelMimeMessage *mime_message, - const gchar *subject); - const gchar * (*get_subject) (CamelMimeMessage *mime_message); - void (*set_from) (CamelMimeMessage *mime_message, - const gchar *from); - const gchar * (*get_from) (CamelMimeMessage *mime_message); - void (*add_recipient) (CamelMimeMessage *mime_message, - const gchar *recipient_type, - const gchar *recipient); - void (*remove_recipient) (CamelMimeMessage *mime_message, - const gchar *recipient_type, - const gchar *recipient); - const GList * (*get_recipients) (CamelMimeMessage *mime_message, - const gchar *recipient_type); - void (*set_flag) (CamelMimeMessage *mime_message, - const gchar *flag, - gboolean value); - gboolean (*get_flag) (CamelMimeMessage *mime_message, - const gchar *flag); - GList * (*get_flag_list) (CamelMimeMessage *mime_message); void (*set_message_number) (CamelMimeMessage *mime_message, guint number); guint (*get_message_number) (CamelMimeMessage *mime_message); @@ -157,13 +146,10 @@ void camel_mime_message_remove_recipient_name (CamelMimeMessage *mime_message, const CamelInternetAddress *camel_mime_message_get_recipients (CamelMimeMessage *mime_message, const char *type); - -void camel_mime_message_set_flag (CamelMimeMessage *mime_message, - const gchar *flag, - gboolean value); -gboolean camel_mime_message_get_flag (CamelMimeMessage *mime_message, - const gchar *flag); -GList * camel_mime_message_get_flag_list (CamelMimeMessage *mime_message); +guint32 camel_mime_message_get_flags (CamelMimeMessage *m); +void camel_mime_message_set_flags (CamelMimeMessage *m, guint32 flags, guint32 set); +gboolean camel_mime_message_get_user_flag (CamelMimeMessage *m, const char *name); +void camel_mime_message_set_user_flag (CamelMimeMessage *m, const char *name, gboolean value); guint camel_mime_message_get_message_number (CamelMimeMessage *mime_message); diff --git a/camel/providers/mbox/camel-mbox-folder.c b/camel/providers/mbox/camel-mbox-folder.c index 91ac79c22e..c6dfb657e7 100644 --- a/camel/providers/mbox/camel-mbox-folder.c +++ b/camel/providers/mbox/camel-mbox-folder.c @@ -57,31 +57,32 @@ static CamelFolderClass *parent_class=NULL; #define CMBOXS_CLASS(so) CAMEL_STORE_CLASS (GTK_OBJECT(so)->klass) -static void _init (CamelFolder *folder, CamelStore *parent_store, +static void mbox_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_folder, const gchar *name, gchar separator, CamelException *ex); -static void _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex); -static void _close (CamelFolder *folder, gboolean expunge, CamelException *ex); -static gboolean _exists (CamelFolder *folder, CamelException *ex); -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); -static CamelMimeMessage *_get_message_by_number (CamelFolder *folder, gint number, CamelException *ex); -static gint _get_message_count (CamelFolder *folder, 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); +static void mbox_open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex); +static void mbox_close (CamelFolder *folder, gboolean expunge, CamelException *ex); +static gboolean mbox_exists (CamelFolder *folder, CamelException *ex); +static gboolean mbox_create(CamelFolder *folder, CamelException *ex); +static gboolean mbox_delete (CamelFolder *folder, gboolean recurse, CamelException *ex); +static gboolean mbox_delete_messages (CamelFolder *folder, CamelException *ex); +static GList *mbox_list_subfolders (CamelFolder *folder, CamelException *ex); +static CamelMimeMessage *mbox_get_message_by_number (CamelFolder *folder, gint number, CamelException *ex); +static gint mbox_get_message_count (CamelFolder *folder, CamelException *ex); +static void mbox_append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex); +static GList *mbox_get_uid_list (CamelFolder *folder, CamelException *ex); +static CamelMimeMessage *mbox_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex); + +static void mbox_expunge (CamelFolder *folder, 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); #endif GPtrArray *summary_get_message_info (CamelFolder *folder, int first, int count); -static void _finalize (GtkObject *object); +static void mbox_finalize (GtkObject *object); static void camel_mbox_folder_class_init (CamelMboxFolderClass *camel_mbox_folder_class) @@ -94,24 +95,24 @@ camel_mbox_folder_class_init (CamelMboxFolderClass *camel_mbox_folder_class) /* virtual method definition */ /* virtual method overload */ - camel_folder_class->init = _init; - camel_folder_class->open = _open; - camel_folder_class->close = _close; - camel_folder_class->exists = _exists; - camel_folder_class->create = _create; - camel_folder_class->delete = _delete; - camel_folder_class->delete_messages = _delete_messages; - camel_folder_class->list_subfolders = _list_subfolders; - 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; + camel_folder_class->init = mbox_init; + camel_folder_class->open = mbox_open; + camel_folder_class->close = mbox_close; + camel_folder_class->exists = mbox_exists; + camel_folder_class->create = mbox_create; + camel_folder_class->delete = mbox_delete; + camel_folder_class->delete_messages = mbox_delete_messages; + camel_folder_class->list_subfolders = mbox_list_subfolders; + camel_folder_class->get_message_by_number = mbox_get_message_by_number; + camel_folder_class->get_message_count = mbox_get_message_count; + camel_folder_class->append_message = mbox_append_message; + camel_folder_class->get_uid_list = mbox_get_uid_list; + camel_folder_class->expunge = mbox_expunge; #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; #endif - camel_folder_class->get_message_by_uid = _get_message_by_uid; + camel_folder_class->get_message_by_uid = mbox_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; @@ -119,12 +120,12 @@ camel_mbox_folder_class_init (CamelMboxFolderClass *camel_mbox_folder_class) camel_folder_class->get_message_info = summary_get_message_info; - gtk_object_class->finalize = _finalize; + gtk_object_class->finalize = mbox_finalize; } static void -_finalize (GtkObject *object) +mbox_finalize (GtkObject *object) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (object); @@ -159,7 +160,7 @@ camel_mbox_folder_get_type (void) } static void -_init (CamelFolder *folder, CamelStore *parent_store, +mbox_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_folder, const gchar *name, gchar separator, CamelException *ex) { @@ -180,6 +181,12 @@ _init (CamelFolder *folder, CamelStore *parent_store, folder->has_uid_capability = TRUE; folder->has_search_capability = TRUE; + folder->permanent_flags = CAMEL_MESSAGE_ANSWERED | + CAMEL_MESSAGE_DELETED | + CAMEL_MESSAGE_DRAFT | + CAMEL_MESSAGE_FLAGGED | + CAMEL_MESSAGE_SEEN; + mbox_folder->summary = NULL; /* now set the name info */ @@ -196,7 +203,7 @@ _init (CamelFolder *folder, CamelStore *parent_store, } static void -_open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex) +mbox_open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder); @@ -222,13 +229,17 @@ _open (CamelFolder *folder, CamelFolderOpenMode mode, CamelException *ex) } static void -_close (CamelFolder *folder, gboolean expunge, CamelException *ex) +mbox_close (CamelFolder *folder, gboolean expunge, CamelException *ex) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder); /* call parent implementation */ parent_class->close (folder, expunge, ex); + if (expunge) { + mbox_expunge(folder, ex); + } + /* save index */ if (mbox_folder->index) { ibex_close(mbox_folder->index); @@ -240,9 +251,21 @@ _close (CamelFolder *folder, gboolean expunge, CamelException *ex) } +static void +mbox_expunge (CamelFolder *folder, CamelException *ex) +{ + CamelMboxFolder *mbox = (CamelMboxFolder *)folder; + + if (camel_mbox_summary_expunge(mbox->summary) == -1) { + camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID, /* FIXME: right error code */ + "Could not expunge: %s", strerror(errno)); + } +} + + /* FIXME: clean up this snot */ static gboolean -_exists (CamelFolder *folder, CamelException *ex) +mbox_exists (CamelFolder *folder, CamelException *ex) { CamelMboxFolder *mbox_folder; struct stat stat_buf; @@ -305,7 +328,7 @@ _exists (CamelFolder *folder, CamelException *ex) /* FIXME: clean up this snot */ static gboolean -_create (CamelFolder *folder, CamelException *ex) +mbox_create (CamelFolder *folder, CamelException *ex) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder); const gchar *folder_file_path, *folder_dir_path; @@ -376,7 +399,7 @@ _create (CamelFolder *folder, CamelException *ex) /* FIXME: cleanup */ static gboolean -_delete (CamelFolder *folder, gboolean recurse, CamelException *ex) +mbox_delete (CamelFolder *folder, gboolean recurse, CamelException *ex) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder); const gchar *folder_file_path, *folder_dir_path; @@ -476,7 +499,7 @@ _delete (CamelFolder *folder, gboolean recurse, CamelException *ex) /* TODO: remove this */ gboolean -_delete_messages (CamelFolder *folder, CamelException *ex) +mbox_delete_messages (CamelFolder *folder, CamelException *ex) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder); @@ -535,7 +558,7 @@ _delete_messages (CamelFolder *folder, CamelException *ex) /* FIXME: cleanup */ static GList * -_list_subfolders (CamelFolder *folder, CamelException *ex) +mbox_list_subfolders (CamelFolder *folder, CamelException *ex) { GList *subfolder_name_list = NULL; @@ -653,7 +676,7 @@ _list_subfolders (CamelFolder *folder, CamelException *ex) } static gint -_get_message_count (CamelFolder *folder, CamelException *ex) +mbox_get_message_count (CamelFolder *folder, CamelException *ex) { CamelMboxFolder *mbox_folder = (CamelMboxFolder *)folder; @@ -678,7 +701,7 @@ _get_message_count (CamelFolder *folder, CamelException *ex) /* FIXME: this may need some tweaking for performance? */ /* FIXME: MUST check all sytem call return codes MUST MUST */ static void -_append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex) +mbox_append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException *ex) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder), *source_folder; CamelStream *output_stream; @@ -786,7 +809,7 @@ _append_message (CamelFolder *folder, CamelMimeMessage *message, CamelException static GList * -_get_uid_list (CamelFolder *folder, CamelException *ex) +mbox_get_uid_list (CamelFolder *folder, CamelException *ex) { GList *uid_list = NULL; CamelMboxFolder *mbox_folder = (CamelMboxFolder *)folder; @@ -803,7 +826,7 @@ _get_uid_list (CamelFolder *folder, CamelException *ex) } static CamelMimeMessage * -_get_message_by_number (CamelFolder *folder, gint number, CamelException *ex) +mbox_get_message_by_number (CamelFolder *folder, gint number, CamelException *ex) { CamelMboxFolder *mbox_folder = (CamelMboxFolder *)folder; CamelMboxMessageInfo *info; @@ -818,11 +841,27 @@ _get_message_by_number (CamelFolder *folder, gint number, CamelException *ex) return NULL; } - return _get_message_by_uid (folder, info->info.uid, ex); + return mbox_get_message_by_uid (folder, info->info.uid, ex); +} + +/* track flag changes in the summary */ +static void +message_changed(CamelMimeMessage *m, int type, CamelMboxFolder *mf) +{ + printf("Message changed: %s: %d\n", m->message_uid, type); + switch (type) { + case MESSAGE_FLAGS_CHANGED: + camel_mbox_summary_set_flags_by_uid(mf->summary, m->message_uid, m->flags); + break; + default: + printf("Unhandled message change event: %d\n", type); + break; + } } + static CamelMimeMessage * -_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex) +mbox_get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex) { CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER (folder); CamelStream *message_stream; @@ -872,6 +911,10 @@ _get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex) message->folder = folder; gtk_object_ref((GtkObject *)folder); message->message_uid = g_strdup(uid); + message->flags = info->info.flags; + printf("%p flags = %x = %x\n", message, info->info.flags, message->flags); + + gtk_signal_connect((GtkObject *)message, "message_changed", message_changed, folder); return message; } diff --git a/camel/providers/mbox/camel-mbox-summary.c b/camel/providers/mbox/camel-mbox-summary.c index 5608afc3df..4d10709fcd 100644 --- a/camel/providers/mbox/camel-mbox-summary.c +++ b/camel/providers/mbox/camel-mbox-summary.c @@ -29,6 +29,8 @@ #include +#include + #include #include #include @@ -374,6 +376,7 @@ message_struct_new(CamelMimeParser *mp, CamelMboxMessageContentInfo *parent, int ms->info.content = (CamelMessageContentInfo *)body_part_new(mp, parent, start, body); ms->xev_offset = xev_offset; + return ms; } @@ -674,6 +677,10 @@ error: #define SAVEIT +/* TODO: Allow to sync with current summary info, without over-writing flags if they + already exist there */ +/* TODO: Lazy sync, make this read-only, and dont write out xev headers unless we need + to? */ static int index_folder(CamelMboxSummary *s, int startoffset) { CamelMimeParser *mp; @@ -705,7 +712,7 @@ static int index_folder(CamelMboxSummary *s, int startoffset) int write_offset = 0; /* how much does the dest differ from the source pos */ int old_offset = 0; - guint32 newuid; + guint32 newuid, newflags; off_t xevoffset = -1; char *tmpname; @@ -761,6 +768,7 @@ static int index_folder(CamelMboxSummary *s, int startoffset) case HSCAN_MULTIPART: case HSCAN_HEADER: /* starting a new header */ newuid=~0; + newflags=0; if (!toplevel) { char name[32]; unsigned int olduid, oldflags; @@ -775,6 +783,7 @@ static int index_folder(CamelMboxSummary *s, int startoffset) if (header_evolution_decode(xev, &olduid, &oldflags) != ~0) { d(printf(" uid = %d = %x\n", olduid, olduid)); newuid = olduid; + newflags = oldflags; #if 0 while (camel_mime_parser_step(mp, &data, &datalen) != HSCAN_FROM_END) ; @@ -834,6 +843,7 @@ static int index_folder(CamelMboxSummary *s, int startoffset) parent = (CamelMboxMessageContentInfo *)message->info.content; if (newuid != ~0) { message->info.uid = g_strdup_printf("%u", newuid); + message->info.flags = newflags; } else { g_warning("This shouldn't happen?"); } @@ -848,6 +858,7 @@ static int index_folder(CamelMboxSummary *s, int startoffset) body = (CamelMboxMessageContentInfo *)message->info.content; if (newuid != ~0) { message->info.uid = g_strdup_printf("%u", newuid); + message->info.flags = newflags; } else { g_warning("This shouldn't happen?"); } @@ -1259,6 +1270,218 @@ guint32 camel_mbox_summary_set_uid(CamelMboxSummary *s, guint32 uid) return s->nextuid; } +void camel_mbox_summary_set_flags_by_uid(CamelMboxSummary *s, const char *uid, guint32 flags) +{ + CamelMessageInfo *info; + + info = (CamelMessageInfo *)camel_mbox_summary_uid(s, uid); + if (info != NULL) { + if (info->flags != flags) { + info->flags = flags | CAMEL_MESSAGE_FOLDER_FLAGGED; + s->dirty = TRUE; + } + } else { + g_warning("Message has dissapeared from summary? uid %s", uid); + } +} + +/* update offsets in the summary to take account deleted parts */ +static void +offset_content(CamelMboxMessageContentInfo *content, off_t offset) +{ + content->pos -= offset; + content->bodypos -= offset; + content->endpos -= offset; + content = (CamelMboxMessageContentInfo *)content->info.childs; + while (content) { + offset_content(content, offset); + content = (CamelMboxMessageContentInfo *)content->info.next; + } +} + +void camel_mbox_summary_remove_uid(CamelMboxSummary *s, const char *uid) +{ + CamelMboxMessageInfo *oldinfo; + char *olduid; + + if (g_hash_table_lookup_extended(s->message_uid, uid, (void *)&olduid, (void *)&oldinfo)) { +#if 0 + /* FIXME: this code should be executed to update the summary info, + however, only if we're not depending on the info not changing yet */ + off_t offset = info->endpos - info->pos; + int i, count, got = FALSE; + + count = s->messages->len; + for (i=0;imessages, i); + if (got) { + offset_content(minfo, offset); + } else if (minfo == info) { + got = TRUE; + } + } +#endif + g_hash_table_remove(s->message_uid, uid); + g_ptr_array_remove(s->messages, oldinfo); + message_struct_free(oldinfo); + g_free(olduid); + } +} + +/* perform expunge/update xev headers, etc */ +/* TODO: merge this with the indexing code, so that it can index new parts + without having to reread everything again? */ +/* TODO: sync with the mbox, if it has changed */ +int +camel_mbox_summary_expunge(CamelMboxSummary *s) +{ + int quick = TRUE, work=FALSE; + int i, count; + CamelMboxMessageInfo *info; + + printf("Executing expunge ...\n"); + + count = camel_mbox_summary_message_count(s); + for (i=0;quick && ixev_offset == -1 || info->info.flags & CAMEL_MESSAGE_DELETED) + quick = FALSE; + else + work |= (info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0; + } + if (quick) { + int fd; + char name[32]; + + if (!work) + return 0; + + camel_mbox_summary_save(s); + + fd = open(s->folder_path, O_WRONLY); + + if (fd == -1) { + g_error("Cannot open folder for update: %s", strerror(errno)); + return -1; + } + + /* poke in the new xev info */ + for (i=0;ixev_offset != -1); + if (info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) { + printf("Setting new flags to message %s = %04x\n", info->info.uid, info->info.flags & 0xffff); + lseek(fd, info->xev_offset, SEEK_SET); + sprintf(name, "X-Evolution: %08x-%04x\n\n", (unsigned int)strtoul(info->info.uid, NULL, 10), info->info.flags & 0xffff); + write(fd, name, strlen(name)); + info->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; + } + } + close(fd); + } else { + char *tmpname; + int fd, fdout; + int last_write = 0, offset = 0, summary_end = 0, last_start = 0; + CamelMboxMessageContentInfo *content; + struct stat st; + + printf("We must expunge messages and/or write headers\n"); + + /* FIXME: This should check the current summary is correct */ + + /* we have to write out new headers or delete messages, starting from message i */ + + fd = open(s->folder_path, O_RDONLY); + if (fd == -1) { + g_error("Cannot open folder for read: %s", strerror(errno)); + return -1; + } + + tmpname = g_strdup_printf("%s.tmp", s->folder_path); + fdout = open(tmpname, O_WRONLY|O_CREAT|O_TRUNC, 0600); + if (fdout == -1) { + g_error("Cannot open tmp file for write: %s", strerror(errno)); + close(fd); + g_free(tmpname); + return -1; + } + + for (i=0;iinfo.content); + + content = (CamelMboxMessageContentInfo *)info->info.content; + + /* FIXME: Must also write out xev headers etc, as appropriate? */ + + /* we need to use the end of the previous message, becuase the beginning of + this message doesn't include the "^From " line. */ + + /* do we remove this message? */ + if (info->info.flags & CAMEL_MESSAGE_DELETED) { + printf("Deleting message: %s\n", info->info.uid); + camel_mbox_summary_copy_block(fd, fdout, last_write, last_start-last_write); + last_write = content->endpos; + last_start = last_write; + offset += (content->endpos - content->pos); + + /* remove this message from the index */ + if (s->index) { + char name[32]; + + sprintf(name, "%x", info->info.uid); + ibex_unindex(s->index, name); + } + + camel_mbox_summary_remove_uid(s, info->info.uid); + i--; /* redo this index */ + count--; + } else { + printf("Keeping message: %s\n", info->info.uid); + last_start = content->endpos; + offset_content(content, offset); + summary_end = content->endpos; + } + } + /* copy the rest of the file ... */ + camel_mbox_summary_copy_block(fd, fdout, last_write, INT_MAX); + + close(fd); + if (close(fdout) == -1) { + g_error("Cannot close tmp folder: %s", strerror(errno)); + unlink(tmpname); + g_free(tmpname); + return -1; + } + + if (rename(tmpname, s->folder_path) == -1) { + g_error("Cannot rename folder: %s", strerror(errno)); + unlink(tmpname); + g_free(tmpname); + return -1; + } + + /* force an index sync */ + if (s->index) { + ibex_write(s->index); + } + + /* update summary size to match the actual (written) folder size ... */ + s->size = summary_end; + /* and the time to match the newly written time, so we dont update needlessly */ + if (stat(s->folder_path, &st) == 0) { + s->time = st.st_mtime; + } + + camel_mbox_summary_save(s); + } + + return 0; +} + + #if 0 int main(int argc, char **argv) { diff --git a/camel/providers/mbox/camel-mbox-summary.h b/camel/providers/mbox/camel-mbox-summary.h index 80b59ef54f..fda574c6f8 100644 --- a/camel/providers/mbox/camel-mbox-summary.h +++ b/camel/providers/mbox/camel-mbox-summary.h @@ -63,15 +63,21 @@ void camel_mbox_summary_unref(CamelMboxSummary *); int camel_mbox_summary_load(CamelMboxSummary *); int camel_mbox_summary_save(CamelMboxSummary *); int camel_mbox_summary_check(CamelMboxSummary *); +int camel_mbox_summary_expunge(CamelMboxSummary *); guint32 camel_mbox_summary_next_uid(CamelMboxSummary *); /* set the minimum uid */ guint32 camel_mbox_summary_set_uid(CamelMboxSummary *s, guint32 uid); CamelMboxMessageInfo *camel_mbox_summary_uid(CamelMboxSummary *s, const char *uid); +/* dont use this function yet ... */ +void camel_mbox_summary_remove_uid(CamelMboxSummary *s, const char *uid); CamelMboxMessageInfo *camel_mbox_summary_index(CamelMboxSummary *, int index); int camel_mbox_summary_message_count(CamelMboxSummary *); +/* set flags within a summary item */ +void camel_mbox_summary_set_flags_by_uid(CamelMboxSummary *s, const char *uid, guint32 flags); + /* TODO: should be in a utility library */ int camel_mbox_summary_copy_block(int fromfd, int tofd, off_t readpos, size_t bytes); -- cgit v1.2.3