diff options
-rw-r--r-- | mail/ChangeLog | 55 | ||||
-rw-r--r-- | mail/component-factory.c | 67 | ||||
-rw-r--r-- | mail/folder-browser.c | 26 | ||||
-rw-r--r-- | mail/folder-browser.h | 3 | ||||
-rw-r--r-- | mail/mail-folder-cache.c | 26 | ||||
-rw-r--r-- | mail/mail-folder-cache.h | 1 | ||||
-rw-r--r-- | mail/mail-local.c | 1334 | ||||
-rw-r--r-- | mail/mail-ops.c | 74 | ||||
-rw-r--r-- | mail/mail-ops.h | 5 |
9 files changed, 831 insertions, 760 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index 9a0818edbf..fc6eea85b9 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,13 @@ +2001-09-10 <NotZed@Ximian.com> + + * mail-local.c (mail_local_reconfigure_folder): Dynamically create + the folder type list from camel. + (reconfigure_clicked): And change code to handle changes. + +2001-09-10 <NotZed@Ximian.com> + + * merged mail_local patch from peterw. Many changes. + 2001-09-10 Iain Holmes <iain@ximian.com> * mail-config.c (impl_GNOME_Evolution_MailConfig_addAccount): Add a @@ -45,6 +55,7 @@ mistake in previous commit that made it *always* complain you had invalid recipients. +>>>>>>> 1.1665 2001-09-09 Jon Trowbridge <trow@ximian.com> * mail-callbacks.c (composer_get_message): Complain if we are @@ -249,6 +260,50 @@ * mail-send-recv.c (build_dialogue): Fix capitalization. Fixes bug #7486. +======= +2001-09-04 Peter Williams <peterw@ximian.com> + + * mail-local.c (mlf_init): Remove accidentally left-in "choke on + this" preprocessor thingie. + (mail_local_folder_reconfigure): Instead of creating our own local + exception, just assert that ex != NULL. + (*): Staticize everything that can be and remove some obnoxious + prototypes. + +2001-08-31 Peter Williams <peterw@ximian.com> + + * mail-local.c (mail_local_reconfigure_folder): Use (NULL, NULL) + as the arguments to g_hash_table_new instead of g_direct_foo. + Instead of checking the URI, check MAIL_IS_LOCAL_FOLDER (fb->folder) + to check whether we can reconfigure the folder. Instead of + gnome_dialog_run_and_close, use gnome_dialog_run... + (reconfigure_clicked): And deal with removing the hash table + elements here. + (local_storage_new_folder_cb): Set the folder's name to the + displayName to i18nize correctly (after shell patch is applied). + +2001-08-30 Peter Williams <peterw@ximian.com> + + * mail-local.c: Rewrite as a more complete CamelStore. + + * component-factory.c (create_folder): We can now chuck out most + of this function and just call mail_get_folder. + (xfer_folder_done): If we succeeded in moving the messages, now + delete the source folder as we should be. + (xfer_folder): In order to do so, create a new xfer_folder_data + struct that records the value of 'remove_source' Fix a leak by + unreffing the source folder. + + * mail-ops.[ch]: We no longer need the mail_new_folder operation. + + * folder-browser.[ch]: Don't need the 'reconfigure' member + anymore, because the loaded folder's URL doesn't change. + (do_message_selected): Don't check it + (on_right_click): Same. + (folder_browser_set_uri): Same. + (got_folder): Same. + +>>>>>>> 1.1642.2.4 2001-08-31 Zbigniew Chyla <cyba@gnome.pl> * mail-vfolder.c (vfolder_create_storage): Marked string for diff --git a/mail/component-factory.c b/mail/component-factory.c index ea48357bdb..32194cc177 100644 --- a/mail/component-factory.c +++ b/mail/component-factory.c @@ -202,26 +202,16 @@ create_folder (EvolutionShellComponent *shell_component, void *closure) { CORBA_Environment ev; - CamelURL *url; - char *uri; - + CORBA_exception_init (&ev); - url = physical_uri ? camel_url_new (physical_uri, NULL) : NULL; - - if (url && !strcmp (type, "mail")) { - camel_url_set_protocol (url, "mbox"); - uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - mail_create_folder (uri, create_folder_done, CORBA_Object_duplicate (listener, &ev)); - g_free (uri); + if (!strcmp (type, "mail")) { + mail_get_folder (physical_uri, create_folder_done, CORBA_Object_duplicate (listener, &ev)); } else { GNOME_Evolution_ShellComponentListener_notifyResult ( listener, GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, &ev); } - - if (url) - camel_url_free (url); - + CORBA_exception_free (&ev); } @@ -265,22 +255,36 @@ remove_folder (EvolutionShellComponent *shell_component, CORBA_exception_free (&ev); } +typedef struct _xfer_folder_data { + GNOME_Evolution_ShellComponentListener listener; + gboolean remove_source; + char *source_uri; +} xfer_folder_data; + static void xfer_folder_done (gboolean ok, void *data) { - GNOME_Evolution_ShellComponentListener listener = data; + xfer_folder_data *xfd = (xfer_folder_data *)data; + GNOME_Evolution_ShellComponentListener listener = xfd->listener; GNOME_Evolution_ShellComponentListener_Result result; CORBA_Environment ev; + + if (xfd->remove_source && ok) { + mail_remove_folder (xfd->source_uri, remove_folder_done, xfd->listener); + } else { + if (ok) + result = GNOME_Evolution_ShellComponentListener_OK; + else + result = GNOME_Evolution_ShellComponentListener_INVALID_URI; - if (ok) - result = GNOME_Evolution_ShellComponentListener_OK; - else - result = GNOME_Evolution_ShellComponentListener_INVALID_URI; - - CORBA_exception_init (&ev); - GNOME_Evolution_ShellComponentListener_notifyResult (listener, result, &ev); - CORBA_Object_release (listener, &ev); - CORBA_exception_free (&ev); + CORBA_exception_init (&ev); + GNOME_Evolution_ShellComponentListener_notifyResult (listener, result, &ev); + CORBA_Object_release (listener, &ev); + CORBA_exception_free (&ev); + } + + g_free (xfd->source_uri); + g_free (xfd); } static void @@ -298,7 +302,7 @@ xfer_folder (EvolutionShellComponent *shell_component, CamelException ex; GPtrArray *uids; CamelURL *url; - + url = camel_url_new (destination_physical_uri, NULL); noselect = url ? camel_url_get_param (url, "noselect") : NULL; @@ -323,10 +327,17 @@ xfer_folder (EvolutionShellComponent *shell_component, CORBA_exception_init (&ev); if (source) { + xfer_folder_data *xfd; + + xfd = g_new0 (xfer_folder_data, 1); + xfd->remove_source = remove_source; + xfd->source_uri = g_strdup (source_physical_uri); + xfd->listener = CORBA_Object_duplicate (listener, &ev); + uids = camel_folder_get_uids (source); mail_transfer_messages (source, uids, remove_source, destination_physical_uri, - xfer_folder_done, - CORBA_Object_duplicate (listener, &ev)); + xfer_folder_done, xfd); + camel_object_unref (CAMEL_OBJECT (source)); } else GNOME_Evolution_ShellComponentListener_notifyResult (listener, GNOME_Evolution_ShellComponentListener_INVALID_URI, &ev); CORBA_exception_free (&ev); @@ -633,7 +644,7 @@ owner_set_cb (EvolutionShellComponent *shell_component, evolution_dir = g_strdup (evolution_homedir); mail_session_init (); - + storages_hash = g_hash_table_new (NULL, NULL); vfolder_create_storage (shell_component); diff --git a/mail/folder-browser.c b/mail/folder-browser.c index df9155f554..cadd95035f 100644 --- a/mail/folder-browser.c +++ b/mail/folder-browser.c @@ -720,10 +720,6 @@ got_folder(char *uri, CamelFolder *folder, void *data) done: gtk_object_unref (GTK_OBJECT (fb)); - /* Sigh, i dont like this (it can be set in reconfigure folder), - but its just easier right now to do it this way */ - fb->reconfigure = FALSE; - gtk_signal_emit (GTK_OBJECT (fb), folder_browser_signals [FOLDER_LOADED], fb->uri); } @@ -733,12 +729,8 @@ folder_browser_set_uri (FolderBrowser *folder_browser, const char *uri) if (uri && *uri) { gtk_object_ref((GtkObject *)folder_browser); mail_get_folder(uri, got_folder, folder_browser); - } else { - /* Sigh, i dont like this (it can be set in reconfigure folder), - but its just easier right now to do it this way */ - folder_browser->reconfigure = FALSE; } - + return TRUE; } @@ -1370,12 +1362,7 @@ on_right_click (ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event char *mailing_list_name = NULL; char *subject_match = NULL, *from_match = NULL; GtkMenu *menu; - - if (fb->reconfigure) { - enable_mask = 0; - goto display_menu; - } - + if (fb->folder != sent_folder) { enable_mask |= CAN_RESEND; hide_mask |= CAN_RESEND; @@ -1763,15 +1750,6 @@ do_message_selected (FolderBrowser *fb) { d(printf ("selecting uid %s (delayed)\n", fb->new_uid ? fb->new_uid : "NONE")); - /* keep polling if we are busy */ - if (fb->reconfigure) { - if (fb->new_uid == NULL) { - mail_display_set_message (fb->mail_display, NULL); - return FALSE; - } - return TRUE; - } - fb->loading_id = 0; /* if we are loading, then set a pending, but leave the loading, coudl cancel here (?) */ diff --git a/mail/folder-browser.h b/mail/folder-browser.h index 2ade1bff88..7f95e324b5 100644 --- a/mail/folder-browser.h +++ b/mail/folder-browser.h @@ -56,9 +56,6 @@ struct _FolderBrowser { /* a folder we are expunging, dont use other than to compare the pointer value */ CamelFolder *expunging; - /* set to true when we are reconfiguring stuff == can't do much else */ - int reconfigure; - MessageList *message_list; MailDisplay *mail_display; GtkWidget *vpaned; diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c index 4a98ad1df1..10f0aeaf5b 100644 --- a/mail/mail-folder-cache.c +++ b/mail/mail-folder-cache.c @@ -36,8 +36,8 @@ #include "mail-mt.h" #include "mail-folder-cache.h" -#define ld(x) -#define d(x) +#define ld(x) +#define d(x) /* Structures */ @@ -896,6 +896,28 @@ mail_folder_cache_try_folder (const gchar *uri) return ret; } +gchar * +mail_folder_cache_try_name (const gchar *uri) +{ + mail_folder_info *mfi; + gchar *ret; + + g_return_val_if_fail (uri, NULL); + + LOCK_FOLDERS (); + + mfi = get_folder_info (uri); + + if (mfi->flags & MAIL_FIF_NAME_VALID) + ret = g_strdup (mfi->name); + else + ret = NULL; + + UNLOCK_FOLDERS (); + + return ret; +} + void mail_folder_cache_set_shell_view (GNOME_Evolution_ShellView sv) { diff --git a/mail/mail-folder-cache.h b/mail/mail-folder-cache.h index 9902933cf8..df99ef7283 100644 --- a/mail/mail-folder-cache.h +++ b/mail/mail-folder-cache.h @@ -56,6 +56,7 @@ void mail_folder_cache_note_folderinfo (const gchar *uri, CamelFolderInfo *f void mail_folder_cache_note_name (const gchar *uri, const gchar *name); CamelFolder *mail_folder_cache_try_folder (const gchar *uri); +gchar * mail_folder_cache_try_name (const gchar *uri); void mail_folder_cache_set_shell_view (GNOME_Evolution_ShellView sv); void mail_folder_cache_set_folder_browser (FolderBrowser *fb); diff --git a/mail/mail-local.c b/mail/mail-local.c index 3f9c9bdd74..c5b10fde0f 100644 --- a/mail/mail-local.c +++ b/mail/mail-local.c @@ -26,40 +26,27 @@ * USA */ -/* - TODO: - - If we are going to have all this LocalStore stuff, then the LocalStore - should have a reconfigure_folder method on it, as, in reality, it is - the maintainer of this information. - -*/ - #ifdef HAVE_CONFIG_H #include <config.h> #endif +#include <unistd.h> +#include <errno.h> + #include <gnome-xml/xmlmemory.h> #include <libgnomeui/gnome-dialog.h> #include <libgnomeui/gnome-dialog-util.h> #include <glade/glade.h> +#include "gal/widgets/e-gui-utils.h" +#include "e-util/e-path.h" + #include "Evolution.h" #include "evolution-storage.h" #include "evolution-shell-component.h" #include "evolution-storage-listener.h" -#include "gal/widgets/e-gui-utils.h" -#include "e-util/e-path.h" - #include "camel/camel.h" -#include "camel/camel-vee-store.h" -#include "camel/camel-vee-folder.h" -#include "camel/camel-vtrash-folder.h" - -#include "filter/vfolder-context.h" -#include "filter/vfolder-rule.h" -#include "filter/vfolder-editor.h" #include "mail.h" #include "mail-local.h" @@ -69,83 +56,131 @@ #include "mail-folder-cache.h" #include "mail-vfolder.h" -#define d(x) +#define d(x) x +/* ** MailLocalStore ** (protos) ************************************************** */ -/* Local folder metainfo */ +#define MAIL_LOCAL_STORE_TYPE (mail_local_store_get_type ()) +#define MAIL_LOCAL_STORE(obj) (CAMEL_CHECK_CAST((obj), MAIL_LOCAL_STORE_TYPE, MailLocalStore)) +#define MAIL_LOCAL_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_LOCAL_STORE_TYPE, MailLocalStoreClass)) +#define MAIL_IS_LOCAL_STORE(o) (CAMEL_CHECK_TYPE((o), MAIL_LOCAL_STORE_TYPE)) + +typedef struct { + CamelStore parent_object; +} MailLocalStore; + +typedef struct { + CamelStoreClass parent_class; +} MailLocalStoreClass; + +static CamelType mail_local_store_get_type (void); + +/* ** MailLocalFolder ** (protos) ************************************************* */ + +#define MAIL_LOCAL_FOLDER_TYPE (mail_local_folder_get_type ()) +#define MAIL_LOCAL_FOLDER(obj) (CAMEL_CHECK_CAST((obj), MAIL_LOCAL_FOLDER_TYPE, MailLocalFolder)) +#define MAIL_LOCAL_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_LOCAL_FOLDER_TYPE, MailLocalFolderClass)) +#define MAIL_IS_LOCAL_FOLDER(o) (CAMEL_CHECK_TYPE((o), MAIL_LOCAL_FOLDER_TYPE)) struct _local_meta { - char *path; /* path of metainfo file */ + char *path; /* path of metainfo */ char *format; /* format of mailbox */ - char *name; /* name of mbox itself */ - int indexed; /* do we index the body? */ + char *name; /* name of actual mbox */ + int indexed; /* is body indexed? */ }; +typedef struct { + CamelFolder parent_object; + + CamelFolder *real_folder; + CamelStore *real_store; + + struct _local_meta *meta; + + GMutex *real_folder_lock; /* no way to use the CamelFolder's lock, so... */ +} MailLocalFolder; + +typedef struct { + CamelFolderClass parent_class; +} MailLocalFolderClass; + +static CamelType mail_local_folder_get_type (void); + +#ifdef ENABLE_THREADS +#define LOCAL_FOLDER_LOCK(folder) (g_mutex_lock (((MailLocalFolder *)folder)->real_folder_lock)) +#define LOCAL_FOLDER_UNLOCK(folder) (g_mutex_unlock (((MailLocalFolder *)folder)->real_folder_lock)) +#else +#define LOCAL_FOLDER_LOCK(folder) +#define LOCAL_FOLDER_UNLOCK(folder) +#endif + +/* ** MailLocalFolder ************************************************************* */ + static struct _local_meta * -load_metainfo (const char *path) +load_metainfo(const char *path) { xmlDocPtr doc; xmlNodePtr node; struct _local_meta *meta; - - meta = g_malloc0 (sizeof (*meta)); - meta->path = g_strdup (path); - - d(printf("Loading folder metainfo from : %s\n", meta->path)); - - doc = xmlParseFile (meta->path); - if (doc == NULL) { + + d(printf("Loading folder metainfo from : %s\n", path)); + + meta = g_malloc0(sizeof(*meta)); + meta->path = g_strdup(path); + + doc = xmlParseFile(path); + if (doc == NULL) goto dodefault; - } + node = doc->root; - if (strcmp (node->name, "folderinfo")) { + if (strcmp(node->name, "folderinfo")) goto dodefault; - } + node = node->childs; while (node) { - if (!strcmp (node->name, "folder")) { + if (!strcmp(node->name, "folder")) { char *index, *txt; - txt = xmlGetProp (node, "type"); - meta->format = g_strdup (txt ? txt : "mbox"); - xmlFree (txt); + txt = xmlGetProp(node, "type"); + meta->format = g_strdup(txt?txt:"mbox"); + xmlFree(txt); - txt = xmlGetProp (node, "name"); - meta->name = g_strdup (txt ? txt : "mbox"); - xmlFree (txt); + txt = xmlGetProp(node, "name"); + meta->name = g_strdup(txt?txt:"mbox"); + xmlFree(txt); - index = xmlGetProp (node, "index"); + index = xmlGetProp(node, "index"); if (index) { - meta->indexed = atoi (index); - xmlFree (index); + meta->indexed = atoi(index); + xmlFree(index); } else meta->indexed = TRUE; } node = node->next; } - xmlFreeDoc (doc); + xmlFreeDoc(doc); return meta; dodefault: - meta->format = g_strdup ("mbox"); /* defaults */ - meta->name = g_strdup ("mbox"); + meta->format = g_strdup("mbox"); /* defaults */ + meta->name = g_strdup("mbox"); meta->indexed = TRUE; - xmlFreeDoc (doc); + xmlFreeDoc(doc); return meta; } static void -free_metainfo (struct _local_meta *meta) +free_metainfo(struct _local_meta *meta) { - g_free (meta->path); - g_free (meta->format); - g_free (meta->name); - g_free (meta); + g_free(meta->path); + g_free(meta->format); + g_free(meta->name); + g_free(meta); } -static int +static gboolean save_metainfo(struct _local_meta *meta) { xmlDocPtr doc; @@ -165,455 +200,561 @@ save_metainfo(struct _local_meta *meta) ret = xmlSaveFile(meta->path, doc); xmlFreeDoc(doc); + return ret; } +/* forward a bunch of functions to the real folder. This pretty + * much sucks but I haven't found a better way of doing it. + */ -/* MailLocalStore implementation */ -#define MAIL_LOCAL_STORE_TYPE (mail_local_store_get_type ()) -#define MAIL_LOCAL_STORE(obj) (CAMEL_CHECK_CAST((obj), MAIL_LOCAL_STORE_TYPE, MailLocalStore)) -#define MAIL_LOCAL_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_LOCAL_STORE_TYPE, MailLocalStoreClass)) -#define MAIL_IS_LOCAL_STORE(o) (CAMEL_CHECK_TYPE((o), MAIL_LOCAL_STORE_TYPE)) - -typedef struct { - CamelStore parent_object; - - EvolutionStorage *storage; - GNOME_Evolution_Storage corba_storage; - EvolutionStorageListener *local_storage_listener; - - char *local_path; - int local_pathlen; - GHashTable *folders; /* points to MailLocalFolder */ -} MailLocalStore; +/* We need to do it without having locked our folder, otherwise + we can get sync hangs with vfolders/trash */ +static void +mlf_refresh_info(CamelFolder *folder, CamelException *ex) +{ + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); + CamelFolder *f; -typedef struct { - CamelStoreClass parent_class; -} MailLocalStoreClass; + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); -typedef struct { - CamelFolder *folder; - MailLocalStore *local_store; - char *path, *name, *uri; -} MailLocalFolder; + camel_folder_refresh_info(f, ex); + camel_object_unref((CamelObject *)f); +} -static MailLocalStore *local_store; +static void +mlf_sync(CamelFolder *folder, gboolean expunge, CamelException *ex) +{ + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); + CamelFolder *f; -CamelType mail_local_store_get_type (void); + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); -static char *get_name (CamelService *service, gboolean brief); + camel_folder_sync(f, expunge, ex); + camel_object_unref((CamelObject *)f); +} -static CamelFolder *get_folder (CamelStore *store, const char *folder_name, - guint32 flags, CamelException *ex); -static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, - guint32 flags, CamelException *ex); -static void delete_folder (CamelStore *store, const char *folder_name, - CamelException *ex); -static void rename_folder (CamelStore *store, const char *old_name, - const char *new_name, CamelException *ex); +static void +mlf_expunge(CamelFolder *folder, CamelException *ex) +{ + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); + CamelFolder *f; -static void init_trash (CamelStore *store); + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); -static CamelStoreClass *local_parent_class; + camel_folder_expunge(f, ex); + camel_object_unref((CamelObject *)f); +} static void -mail_local_store_class_init (MailLocalStoreClass *mail_local_store_class) +mlf_append_message(CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, CamelException *ex) { - CamelStoreClass *camel_store_class = - CAMEL_STORE_CLASS (mail_local_store_class); - CamelServiceClass *camel_service_class = - CAMEL_SERVICE_CLASS (mail_local_store_class); - - /* virtual method overload */ - camel_service_class->get_name = get_name; - - /* Don't cache folders */ - camel_store_class->hash_folder_name = NULL; - camel_store_class->compare_folder_name = NULL; - - camel_store_class->init_trash = init_trash; - camel_store_class->get_folder = get_folder; - camel_store_class->get_folder_info = get_folder_info; - camel_store_class->free_folder_info = camel_store_free_folder_info_full; - camel_store_class->delete_folder = delete_folder; - camel_store_class->rename_folder = rename_folder; - - local_parent_class = (CamelStoreClass *)camel_type_get_global_classfuncs (camel_store_get_type ()); + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); + CamelFolder *f; + + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); + + camel_folder_append_message(f, message, info, ex); + camel_object_unref((CamelObject *)f); } -static void -mail_local_store_init (gpointer object, gpointer klass) +static CamelMimeMessage * +mlf_get_message(CamelFolder *folder, const char *uid, CamelException *ex) { - MailLocalStore *local_store = MAIL_LOCAL_STORE (object); - - local_store->corba_storage = CORBA_OBJECT_NIL; + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); + CamelMimeMessage *ret; + CamelFolder *f; + + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); + + ret = camel_folder_get_message(f, uid, ex); + camel_object_unref((CamelObject *)f); + + return ret; } -static void -free_local_folder (MailLocalFolder *lf) +static GPtrArray * +mlf_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex) { - if (lf->folder) - camel_object_unref ((CamelObject *)lf->folder); - - g_free (lf->path); - g_free (lf->name); - g_free (lf->uri); - camel_object_unref ((CamelObject *)lf->local_store); + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (folder); + GPtrArray *ret; + CamelFolder *f; + + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); + + ret = camel_folder_search_by_expression(f, expression, ex); + camel_object_unref((CamelObject *)f); + + return ret; } static void -free_folder (gpointer key, gpointer data, gpointer user_data) +mlf_search_free(CamelFolder *folder, GPtrArray *result) { - MailLocalFolder *lf = data; - - g_free (key); - free_local_folder (lf); + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); + CamelFolder *f; + + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); + + camel_folder_search_free(f, result); + camel_object_unref((CamelObject *)f); } static void -mail_local_store_finalize (gpointer object) +mlf_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value) { - MailLocalStore *local_store = MAIL_LOCAL_STORE (object); - CORBA_Environment ev; - - CORBA_exception_init (&ev); - if (!CORBA_Object_is_nil (local_store->corba_storage, &ev)) - bonobo_object_release_unref (local_store->corba_storage, &ev); - CORBA_exception_free (&ev); - - if (local_store->local_storage_listener) - gtk_object_unref (GTK_OBJECT (local_store->local_storage_listener)); + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); + CamelFolder *f; - g_hash_table_foreach (local_store->folders, free_folder, NULL); - g_hash_table_destroy (local_store->folders); + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); - g_free (local_store->local_path); + camel_folder_set_message_user_flag(mlf->real_folder, uid, name, value); + camel_object_unref((CamelObject *)f); } -CamelType -mail_local_store_get_type (void) +static void +mlf_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value) { - static CamelType mail_local_store_type = CAMEL_INVALID_TYPE; + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); + CamelFolder *f; - if (mail_local_store_type == CAMEL_INVALID_TYPE) { - mail_local_store_type = camel_type_register ( - CAMEL_STORE_TYPE, "MailLocalStore", - sizeof (MailLocalStore), - sizeof (MailLocalStoreClass), - (CamelObjectClassInitFunc) mail_local_store_class_init, - NULL, - (CamelObjectInitFunc) mail_local_store_init, - (CamelObjectFinalizeFunc) mail_local_store_finalize); - } + LOCAL_FOLDER_LOCK(mlf); + f = mlf->real_folder; + camel_object_ref((CamelObject *)f); + LOCAL_FOLDER_UNLOCK(mlf); - return mail_local_store_type; + camel_folder_set_message_user_tag(mlf->real_folder, uid, name, value); + camel_object_unref((CamelObject *)f); } -static CamelFolder * -get_folder (CamelStore *store, - const char *folder_name, - guint32 flags, - CamelException *ex) +/* and, conversely, forward the real folder's signals. */ + +static void +mlf_proxy_message_changed(CamelObject *real_folder, gpointer event_data, gpointer user_data) { - MailLocalStore *local_store = (MailLocalStore *)store; - MailLocalFolder *local_folder; - CamelFolder *folder; - - local_folder = g_hash_table_lookup (local_store->folders, folder_name); - - if (local_folder) { - folder = local_folder->folder; - camel_object_ref (CAMEL_OBJECT (folder)); - } else { - folder = NULL; - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("No such folder /%s"), folder_name); - } - - return folder; + camel_object_trigger_event((CamelObject *)user_data, "message_changed", event_data); } static void -trash_add_folder (gpointer key, gpointer value, gpointer data) +mlf_proxy_folder_changed(CamelObject *real_folder, gpointer event_data, gpointer user_data) { - MailLocalFolder *local_folder = (MailLocalFolder *) value; - CamelFolder *folder = local_folder->folder; - CamelStore *store = CAMEL_STORE (data); - - camel_vee_folder_add_folder (CAMEL_VEE_FOLDER (store->vtrash), folder); + camel_object_trigger_event((CamelObject *)user_data, "folder_changed", event_data); } static void -trash_finalize (CamelObject *trash, gpointer event_data, gpointer user_data) +mlf_unset_folder (MailLocalFolder *mlf) { - CamelStore *store = CAMEL_STORE (user_data); - - store->vtrash = NULL; + CamelFolder *folder = (CamelFolder *)mlf; + + g_assert(mlf->real_folder); + + camel_object_unhook_event(CAMEL_OBJECT(mlf->real_folder), + "message_changed", + mlf_proxy_message_changed, + mlf); + camel_object_unhook_event(CAMEL_OBJECT(mlf->real_folder), + "folder_changed", + mlf_proxy_folder_changed, + mlf); + + camel_object_unref((CamelObject *)folder->summary); + folder->summary = NULL; + camel_object_unref((CamelObject *)mlf->real_folder); + mlf->real_folder = NULL; + camel_object_unref((CamelObject *)mlf->real_store); + mlf->real_store = NULL; + + folder->permanent_flags = 0; + folder->has_summary_capability = 0; + folder->has_search_capability = 0; } - -static void -init_trash (CamelStore *store) + +static gboolean +mlf_set_folder(MailLocalFolder *mlf, guint32 flags, CamelException *ex) { - MailLocalStore *local_store = MAIL_LOCAL_STORE (store); - - store->vtrash = camel_vtrash_folder_new (store, CAMEL_VTRASH_NAME); - - if (store->vtrash) { - /* attach to the finalize event of the vtrash */ - camel_object_hook_event (CAMEL_OBJECT (store->vtrash), "finalize", - trash_finalize, store); - - /* add all the pre-opened folders to the vtrash */ - if (local_store->folders) { - /* lock? */ - g_hash_table_foreach (local_store->folders, trash_add_folder, store); - /* unlock? */ - } + CamelFolder *folder = (CamelFolder *)mlf; + char *uri; + + g_assert(mlf->real_folder == NULL); - /* would prefer not to special-case this, but... */ - mail_folder_cache_note_folder ("vtrash:file:/", store->vtrash); - mail_folder_cache_set_update_lstorage ("vtrash:file:/", - local_store->corba_storage, - "/Trash"); + uri = g_strdup_printf("%s:%s%s", mlf->meta->format, ((CamelService *)folder->parent_store)->url->path, folder->full_name); + d(printf("opening real store: %s\n", uri)); + mlf->real_store = camel_session_get_store(session, uri, ex); + g_free(uri); + if (mlf->real_store == NULL) + return FALSE; + + if (mlf->meta->indexed) + flags |= CAMEL_STORE_FOLDER_BODY_INDEX; + + mlf->real_folder = camel_store_get_folder(mlf->real_store, mlf->meta->name, flags, ex); + if (mlf->real_folder == NULL) + return FALSE; + + if (mlf->real_folder->has_summary_capability) { + folder->summary = mlf->real_folder->summary; + camel_object_ref((CamelObject *)mlf->real_folder->summary); } -} -static void -populate_folders (gpointer key, gpointer data, gpointer user_data) -{ - GPtrArray *folders = user_data; - MailLocalFolder *folder; - CamelFolderInfo *fi; - - folder = data; - - fi = g_new0 (CamelFolderInfo, 1); - fi->full_name = g_strdup (folder->path); - fi->name = g_strdup (folder->name); - fi->url = g_strdup (folder->uri); - fi->unread_message_count = -1; - - g_ptr_array_add (folders, fi); + folder->permanent_flags = mlf->real_folder->permanent_flags; + folder->has_summary_capability = mlf->real_folder->has_summary_capability; + folder->has_search_capability = mlf->real_folder->has_search_capability; + + camel_object_hook_event((CamelObject *)mlf->real_folder, "message_changed", mlf_proxy_message_changed, mlf); + camel_object_hook_event((CamelObject *)mlf->real_folder, "folder_changed", mlf_proxy_folder_changed, mlf); + + return TRUE; } -static CamelFolderInfo * -get_folder_info (CamelStore *store, const char *top, - guint32 flags, CamelException *ex) +static void +mlf_class_init (CamelObjectClass *camel_object_class) { - MailLocalStore *local_store = MAIL_LOCAL_STORE (store); - CamelFolderInfo *fi = NULL; - GPtrArray *folders; - - folders = g_ptr_array_new (); - g_hash_table_foreach (local_store->folders, populate_folders, folders); - - fi = camel_folder_info_build (folders, top, '/', TRUE); - g_ptr_array_free (folders, TRUE); - - return fi; + CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_object_class); + + /* override all the functions subclassed in providers/local/ */ + + camel_folder_class->refresh_info = mlf_refresh_info; + camel_folder_class->sync = mlf_sync; + camel_folder_class->expunge = mlf_expunge; + camel_folder_class->append_message = mlf_append_message; + camel_folder_class->get_message = mlf_get_message; + camel_folder_class->search_free = mlf_search_free; + + camel_folder_class->search_by_expression = mlf_search_by_expression; + camel_folder_class->set_message_user_flag = mlf_set_message_user_flag; + camel_folder_class->set_message_user_tag = mlf_set_message_user_tag; } static void -delete_folder (CamelStore *store, const char *folder_name, CamelException *ex) +mlf_init (CamelObject *obj) { - /* No-op. The shell local storage deals with this. */ + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (obj); + +#ifdef ENABLE_THREADS + mlf->real_folder_lock = g_mutex_new(); +#endif } static void -rename_folder (CamelStore *store, const char *old, const char *new, - CamelException *ex) +mlf_finalize (CamelObject *obj) { - /* Probable no-op... */ -} + MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (obj); -static char * -get_name (CamelService *service, gboolean brief) -{ - return g_strdup ("Local mail folders"); + if (mlf->real_folder) + mlf_unset_folder(mlf); + + free_metainfo(mlf->meta); + +#ifdef ENABLE_THREADS + g_mutex_free (mlf->real_folder_lock); +#endif } +static CamelType +mail_local_folder_get_type (void) +{ + static CamelType mail_local_folder_type = CAMEL_INVALID_TYPE; + + if (mail_local_folder_type == CAMEL_INVALID_TYPE) { + mail_local_folder_type = camel_type_register(CAMEL_FOLDER_TYPE, + "MailLocalFolder", + sizeof (MailLocalFolder), + sizeof (MailLocalFolderClass), + mlf_class_init, + NULL, + mlf_init, + mlf_finalize); + } -/* Callbacks for the EvolutionStorageListner signals. */ + return mail_local_folder_type; +} -static void -local_storage_destroyed_cb (EvolutionStorageListener *storage_listener, - void *data) +static MailLocalFolder * +mail_local_folder_construct(MailLocalFolder *mlf, MailLocalStore *parent_store, const char *full_name, CamelException *ex) { - /* FIXME: Dunno how to handle this yet. */ - g_warning ("%s -- The LocalStorage has gone?!", __FILE__); -} + const char *name; + char *metapath; -/* ********************************************************************** */ -/* Register folder */ + name = strrchr(full_name, '/'); + if (name == NULL) + name = full_name; + name = name + 1; -struct _register_msg { - struct _mail_msg msg; + d(printf("constructing local folder: full = %s, name = %s\n", full_name, name)); - MailLocalFolder *local_folder; -}; + camel_folder_construct(CAMEL_FOLDER (mlf), CAMEL_STORE(parent_store), full_name, name); -static char * -register_folder_desc (struct _mail_msg *mm, int done) -{ - struct _register_msg *m = (struct _register_msg *)mm; - - return g_strdup_printf (_("Registering '%s'"), m->local_folder->uri); + metapath = g_strdup_printf("%s/%s/local-metadata.xml", ((CamelService *)parent_store)->url->path, full_name); + mlf->meta = load_metainfo(metapath); + g_free(metapath); + + return mlf; } -static void -register_folder_register (struct _mail_msg *mm) +static gboolean +mail_local_folder_reconfigure (MailLocalFolder *mlf, const char *new_format, CamelException *ex) { - struct _register_msg *m = (struct _register_msg *)mm; - MailLocalFolder *local_folder = m->local_folder; - char *name, *path = local_folder->uri + 7; - struct _local_meta *meta; - CamelStore *store; - guint32 flags; + CamelStore *fromstore = NULL; + CamelFolder *fromfolder = NULL; + char *oldformat = NULL; + char *tmpname; + char *store_uri; + GPtrArray *uids; + int real_folder_frozen = FALSE; + + camel_operation_start(NULL, _("Reconfiguring folder")); + + /* first things first */ + g_assert (ex); + LOCAL_FOLDER_LOCK (mlf); + + /* first, 'close' the old folder */ + if (mlf->real_folder) { + camel_folder_sync(mlf->real_folder, FALSE, ex); + if (camel_exception_is_set (ex)) + goto cleanup; + mlf_unset_folder(mlf); + } + + store_uri = g_strdup_printf("%s:%s%s", mlf->meta->format, + ((CamelService *)((CamelFolder *)mlf)->parent_store)->url->path, ((CamelFolder *)mlf)->full_name); + fromstore = camel_session_get_store(session, store_uri, ex); + g_free(store_uri); + if (fromstore == NULL) + goto cleanup; + + oldformat = mlf->meta->format; + mlf->meta->format = g_strdup(new_format); + + /* rename the old mbox and open it again, without indexing */ + tmpname = g_strdup_printf ("%s_reconfig", mlf->meta->name); + d(printf("renaming %s to %s, and opening it\n", mlf->meta->name, tmpname)); - name = g_strdup_printf ("%s/local-metadata.xml", path); - meta = load_metainfo (name); - g_free (name); + camel_store_rename_folder(fromstore, mlf->meta->name, tmpname, ex); + if (camel_exception_is_set(ex)) + goto cleanup; - name = g_strdup_printf ("%s:%s", meta->format, path); - store = camel_session_get_store (session, name, &mm->ex); - g_free (name); + /* we dont need to set the create flag ... or need an index if it has one */ + fromfolder = camel_store_get_folder(fromstore, tmpname, 0, ex); + if (fromfolder == NULL || camel_exception_is_set(ex)) { + /* try and recover ... */ + camel_exception_clear(ex); + camel_store_rename_folder(fromstore, tmpname, mlf->meta->name, ex); + goto cleanup; + } - if (!store) { - free_metainfo (meta); - return; + /* create a new mbox */ + d(printf("Creating the destination mbox\n")); + + if (!mlf_set_folder(mlf, CAMEL_STORE_FOLDER_CREATE, ex)) { + d(printf("cannot open destination folder\n")); + /* try and recover ... */ + camel_exception_clear(ex); + camel_store_rename_folder(fromstore, tmpname, mlf->meta->name, ex); + goto cleanup; } + + real_folder_frozen = TRUE; + camel_folder_freeze(mlf->real_folder); + + uids = camel_folder_get_uids(fromfolder); + camel_folder_move_messages_to(fromfolder, uids, mlf->real_folder, ex); + camel_folder_free_uids(fromfolder, uids); + if (camel_exception_is_set(ex)) + goto cleanup; - flags = CAMEL_STORE_FOLDER_CREATE; - if (meta->indexed) - flags |= CAMEL_STORE_FOLDER_BODY_INDEX; - local_folder->folder = camel_store_get_folder (store, meta->name, flags, &mm->ex); + camel_folder_expunge(fromfolder, ex); + + d(printf("delete old mbox ...\n")); + camel_object_unref(CAMEL_OBJECT(fromfolder)); + fromfolder = NULL; + camel_store_delete_folder(fromstore, tmpname, ex); - camel_object_unref (CAMEL_OBJECT (store)); - free_metainfo (meta); + /* switch format */ + g_free(oldformat); + oldformat = NULL; + if (save_metainfo(mlf->meta) == FALSE) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot save folder metainfo; " + "you'll probably find you can't\n" + "open this folder anymore: %s: %s"), + mlf->meta->path, strerror(errno)); + } + + cleanup: + if (oldformat) { + g_free(mlf->meta->format); + mlf->meta->format = oldformat; + } + if (mlf->real_folder == NULL) + mlf_set_folder (mlf, CAMEL_STORE_FOLDER_CREATE, ex); + if (fromfolder) + camel_object_unref((CamelObject *)fromfolder); + if (fromstore) + camel_object_unref((CamelObject *)fromstore); + + LOCAL_FOLDER_UNLOCK (mlf); + + if (real_folder_frozen) + camel_folder_thaw(mlf->real_folder); + + camel_operation_end(NULL); + + return !camel_exception_is_set(ex); } + +/* ******************************************************************************** */ -static void -register_folder_registered (struct _mail_msg *mm) +static CamelObjectClass *local_store_parent_class = NULL; + +static CamelFolder * +mls_get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) { - struct _register_msg *m = (struct _register_msg *)mm; - MailLocalFolder *local_folder = m->local_folder; - - if (local_folder->folder) { - gchar *name; - - g_hash_table_insert (local_folder->local_store->folders, - local_folder->uri + 8, - local_folder); - - /* Remove the circular ref once the local store knows about the folder */ - camel_object_unref ((CamelObject *)local_folder->local_store); - - /* add the folder to the vfolder lists FIXME: merge stuff above with this */ - vfolder_register_source (local_folder->folder); - - mail_folder_cache_set_update_lstorage (local_folder->uri, - local_folder->local_store->corba_storage, - local_folder->path); - - name = strrchr (local_folder->path, '/'); - if (name) /* should always be true... */ { - name += 1; /* skip the slash */ - mail_folder_cache_note_name (local_folder->uri, name); + MailLocalStore *local_store = MAIL_LOCAL_STORE (store); + MailLocalFolder *folder; + char *physical_uri; + + d(printf("get_folder: %s", folder_name)); + + folder = (MailLocalFolder *)camel_object_new(MAIL_LOCAL_FOLDER_TYPE); + folder = mail_local_folder_construct(folder, local_store, folder_name, ex); + if (folder == NULL) + return NULL; + + if (!mlf_set_folder(folder, flags, ex)) { + camel_object_unref(CAMEL_OBJECT(folder)); + return NULL; + } + + if (flags & CAMEL_STORE_FOLDER_CREATE) { + if (save_metainfo(folder->meta) == -1) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot save folder metainfo to %s: %s"), + folder->meta->path, strerror(errno)); + camel_object_unref(CAMEL_OBJECT (folder)); + return NULL; } - - /* Do this after specifying the name so it isn't 'mbox' */ - mail_folder_cache_note_folder (local_folder->uri, local_folder->folder); - - m->local_folder = NULL; } + + /* FIXME: why is this here? */ + physical_uri = g_strdup_printf("file://%s/%s", ((CamelService *)store)->url->path, folder_name); + mail_folder_cache_note_folder(physical_uri, CAMEL_FOLDER (folder)); + g_free(physical_uri); + + return (CamelFolder *)folder; } -static void -register_folder_free (struct _mail_msg *mm) +static void +mls_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex) { - struct _register_msg *m = (struct _register_msg *)mm; - - if (m->local_folder) - free_local_folder (m->local_folder); + CamelStore *real_store; + char *metapath, *uri; + CamelException local_ex; + struct _local_meta *meta; + + d(printf("Deleting folder: %s %s\n", ((CamelService *)store)->url->path, folder_name)); + + camel_exception_init(&local_ex); + + /* find the real store for this folder, and proxy the call */ + metapath = g_strdup_printf("%s%s/local-metadata.xml", ((CamelService *)store)->url->path, folder_name); + meta = load_metainfo(metapath); + uri = g_strdup_printf("%s:%s%s", meta->format, ((CamelService *)store)->url->path, folder_name); + real_store = (CamelStore *)camel_session_get_service(session, uri, CAMEL_PROVIDER_STORE, ex); + g_free(uri); + if (real_store == NULL) { + g_free(metapath); + free_metainfo(meta); + return; + } + + camel_store_delete_folder(real_store, meta->name, &local_ex); + if (camel_exception_is_set(&local_ex)) { + camel_exception_xfer(ex, &local_ex); + g_free(metapath); + free_metainfo(meta); + return; + } + + free_metainfo(meta); + + if (unlink(metapath) == -1) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot delete folder metadata %s: %s"), + metapath, strerror(errno)); + } + + g_free(metapath); } -static struct _mail_msg_op register_folder_op = { - register_folder_desc, - register_folder_register, - register_folder_registered, - register_folder_free, -}; +static char * +mls_get_name (CamelService *service, gboolean brief) +{ + if (brief) + return g_strdup("local"); + + return g_strdup("Local mail folders"); +} static void -local_storage_new_folder_cb (EvolutionStorageListener *storage_listener, - const char *path, - const GNOME_Evolution_Folder *folder, - void *data) +mls_class_init (CamelObjectClass *camel_object_class) { - MailLocalStore *local_store = data; - MailLocalFolder *local_folder; - struct _register_msg *m; - int id; - - if (strcmp (folder->type, "mail") != 0 || - strncmp (folder->physicalUri, "file://", 7) != 0 || - strncmp (folder->physicalUri + 7, local_store->local_path, - local_store->local_pathlen) != 0) - return; - - local_folder = g_new0 (MailLocalFolder, 1); - local_folder->name = g_strdup (strrchr (path, '/') + 1); - local_folder->path = g_strdup (path); - local_folder->uri = g_strdup (folder->physicalUri); - local_folder->local_store = local_store; - camel_object_ref ((CamelObject *)local_store); - - m = mail_msg_new (®ister_folder_op, NULL, sizeof (*m)); - - m->local_folder = local_folder; + CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_object_class); + CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_object_class); - /* run synchronous, the shell expects it (I think) */ - id = m->msg.seq; - e_thread_put (mail_thread_queued, (EMsg *)m); - mail_msg_wait (id); + /* virtual method overload -- the bare minimum */ + camel_service_class->get_name = mls_get_name; + camel_store_class->get_folder = mls_get_folder; + camel_store_class->delete_folder = mls_delete_folder; + + local_store_parent_class = camel_type_get_global_classfuncs (CAMEL_STORE_TYPE); } -static void -local_storage_removed_folder_cb (EvolutionStorageListener *storage_listener, - const char *path, - void *data) +static CamelType +mail_local_store_get_type (void) { - MailLocalStore *local_store = data; - MailLocalFolder *local_folder; - char *physical_path; - char *tmpname; - - physical_path = e_path_to_physical (local_store->local_path, path); - - if (strncmp (physical_path, local_store->local_path, - local_store->local_pathlen) != 0) - return; - - tmpname = strchr (physical_path, '/'); - if (tmpname) { - while (*tmpname == '/') - tmpname++; - local_folder = g_hash_table_lookup (local_store->folders, tmpname); - camel_object_ref ((CamelObject *)local_store); /* When we go to free_local_folder() the - local_store will be unref'd */ - } - else - local_folder = NULL; - - if (local_folder) { - g_hash_table_remove (local_store->folders, tmpname); - - free_local_folder (local_folder); + static CamelType mail_local_store_type = CAMEL_INVALID_TYPE; + + if (mail_local_store_type == CAMEL_INVALID_TYPE) { + mail_local_store_type = camel_type_register ( + CAMEL_STORE_TYPE, "MailLocalStore", + sizeof (MailLocalStore), + sizeof (MailLocalStoreClass), + (CamelObjectClassInitFunc) mls_class_init, + NULL, + NULL, + NULL); } - - g_free (physical_path); + + return mail_local_store_type; } +/* ** Local Provider ************************************************************** */ + static CamelProvider local_provider = { "file", "Local mail", NULL, "mail", CAMEL_PROVIDER_IS_STORAGE, CAMEL_URL_NEED_PATH, @@ -633,33 +774,69 @@ non_equal (gconstpointer a, gconstpointer b) return TRUE; } -void -mail_local_storage_startup (EvolutionShellClient *shellclient, - const char *evolution_path) +static void +mail_local_provider_init (void) { - EvolutionStorageListener *local_storage_listener; - GNOME_Evolution_StorageListener corba_local_storage_listener; - CORBA_Environment ev; - /* Register with Camel to handle file: URLs */ - local_provider.object_types[CAMEL_PROVIDER_STORE] = - mail_local_store_get_type(); + local_provider.object_types[CAMEL_PROVIDER_STORE] = MAIL_LOCAL_STORE_TYPE; local_provider.service_cache = g_hash_table_new (non_hash, non_equal); camel_session_register_provider (session, &local_provider); - - /* Now build the storage. */ - local_store = (MailLocalStore *)camel_session_get_service ( - session, "file:/", CAMEL_PROVIDER_STORE, NULL); - if (!local_store) { - g_warning ("No local store!"); +} + +/* ** Local Storage Listener ****************************************************** */ + +static void +local_storage_destroyed_cb (EvolutionStorageListener *storage_listener, + void *data) +{ + CORBA_Environment ev; + + CORBA_exception_init (&ev); + bonobo_object_release_unref (data, &ev); + CORBA_exception_free (&ev); +} + + +static void +local_storage_new_folder_cb (EvolutionStorageListener *storage_listener, + const char *path, + const GNOME_Evolution_Folder *folder, + void *data) +{ + if (strcmp (folder->type, "mail") != 0) return; - } - - local_store->corba_storage = evolution_shell_client_get_local_storage (shellclient); - if (local_store->corba_storage == CORBA_OBJECT_NIL) { - g_warning ("No local storage!"); - camel_object_unref (CAMEL_OBJECT (local_store)); + + mail_folder_cache_set_update_lstorage (folder->physicalUri, + data, + path); + mail_folder_cache_note_name (folder->physicalUri, folder->displayName); +} + +#if 0 +static void +local_storage_removed_folder_cb (EvolutionStorageListener *storage_listener, + const char *path, + void *data) +{ + if (strcmp (folder->type, "mail") != 0) + return; + + /* anything to do? */ +} +#endif + +static void +storage_listener_startup (EvolutionShellClient *shellclient) +{ + EvolutionStorageListener *local_storage_listener; + GNOME_Evolution_StorageListener corba_local_storage_listener; + GNOME_Evolution_Storage corba_storage; + CORBA_Environment ev; + + corba_storage = evolution_shell_client_get_local_storage (shellclient); + if (corba_storage == CORBA_OBJECT_NIL) { + g_warning ("No local storage available from shell client!"); return; } @@ -670,36 +847,47 @@ mail_local_storage_startup (EvolutionShellClient *shellclient, gtk_signal_connect (GTK_OBJECT (local_storage_listener), "destroyed", GTK_SIGNAL_FUNC (local_storage_destroyed_cb), - local_store); + corba_storage); gtk_signal_connect (GTK_OBJECT (local_storage_listener), "new_folder", GTK_SIGNAL_FUNC (local_storage_new_folder_cb), - local_store); - gtk_signal_connect (GTK_OBJECT (local_storage_listener), - "removed_folder", - GTK_SIGNAL_FUNC (local_storage_removed_folder_cb), - local_store); - - local_store->local_storage_listener = local_storage_listener; - - local_store->local_path = g_strdup_printf ("%s/local", - evolution_path); - local_store->local_pathlen = strlen (local_store->local_path); - - local_store->folders = g_hash_table_new (g_str_hash, g_str_equal); + corba_storage); + /*gtk_signal_connect (GTK_OBJECT (local_storage_listener), + * "removed_folder", + * GTK_SIGNAL_FUNC (local_storage_removed_folder_cb), + * corba_storage); + */ CORBA_exception_init (&ev); - GNOME_Evolution_Storage_addListener (local_store->corba_storage, + GNOME_Evolution_Storage_addListener (corba_storage, corba_local_storage_listener, &ev); if (ev._major != CORBA_NO_EXCEPTION) { g_warning ("Cannot add a listener to the Local Storage."); - camel_object_unref (CAMEL_OBJECT (local_store)); CORBA_exception_free (&ev); return; } CORBA_exception_free (&ev); } +/* ** The rest ******************************************************************** */ + +static MailLocalStore *global_local_store; + +void +mail_local_storage_startup (EvolutionShellClient *shellclient, const char *evolution_path) +{ + mail_local_provider_init (); + + global_local_store = MAIL_LOCAL_STORE(camel_session_get_service (session, "file:/", CAMEL_PROVIDER_STORE, NULL)); + + if (!global_local_store) { + g_warning ("No local store!"); + return; + } + + storage_listener_startup (shellclient); +} + /*---------------------------------------------------------------------- * Local folder reconfiguration stuff @@ -724,8 +912,6 @@ mail_local_storage_startup (EvolutionShellClient *shellclient, */ -/* ******************** */ - /* we should have our own progress bar for this */ struct _reconfigure_msg { @@ -737,6 +923,7 @@ struct _reconfigure_msg { GtkWidget *apply; GtkWidget *cancel; GtkOptionMenu *optionlist; + CamelFolder *folder_out; }; static char * @@ -753,174 +940,47 @@ static void reconfigure_folder_reconfigure (struct _mail_msg *mm) { struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm; - MailLocalFolder *local_folder = NULL; - CamelStore *fromstore = NULL, *tostore = NULL; - char *fromurl = NULL, *tourl = NULL; - CamelFolder *fromfolder = NULL, *tofolder = NULL; - GPtrArray *uids; - char *metapath; - char *tmpname; - CamelURL *url = NULL; - struct _local_meta *meta = NULL; - guint32 flags; - + CamelFolder *local_folder = NULL; + d(printf("reconfiguring folder: %s to type %s\n", m->fb->uri, m->newtype)); - /* NOTE: This var is cleared by the folder_browser via the set_uri method */ - m->fb->reconfigure = TRUE; - - /* get the actual location of the mailbox */ - url = camel_url_new (m->fb->uri, &mm->ex); - if (camel_exception_is_set (&mm->ex)) { - g_warning ("%s is not a workable url!", m->fb->uri); - goto cleanup; - } - - tmpname = strchr (m->fb->uri, '/'); - if (tmpname) { - while (*tmpname == '/') - tmpname++; - local_folder = g_hash_table_lookup (local_store->folders, tmpname); - } else - local_folder = NULL; - if (!local_folder) { - g_warning ("%s is not a registered local folder!", m->fb->uri); - goto cleanup; + if (strncmp (m->fb->uri, "file:", 5)) { + camel_exception_setv (&mm->ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + _("%s may not be reconfigured because it is not a local folder"), + m->fb->uri); + return; } - - metapath = g_strdup_printf ("%s/local-metadata.xml", url->path); - meta = load_metainfo (metapath); - g_free (metapath); - - /* first, 'close' the old folder */ - camel_folder_sync (local_folder->folder, FALSE, &mm->ex); - - /* Once for the FolderBrowser, once for the local store */ - camel_object_unref (CAMEL_OBJECT (local_folder->folder)); - camel_object_unref (CAMEL_OBJECT (local_folder->folder)); - local_folder->folder = m->fb->folder = NULL; - - camel_url_set_protocol (url, meta->format); - fromurl = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - camel_url_set_protocol (url, m->newtype); - tourl = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - - d(printf("opening stores %s and %s\n", fromurl, tourl)); - - fromstore = camel_session_get_store (session, fromurl, &mm->ex); - - if (camel_exception_is_set (&mm->ex)) - goto cleanup; - - tostore = camel_session_get_store (session, tourl, &mm->ex); - if (camel_exception_is_set (&mm->ex)) - goto cleanup; - - /* rename the old mbox and open it again, without indexing */ - tmpname = g_strdup_printf ("%s_reconfig", meta->name); - d(printf("renaming %s to %s, and opening it\n", meta->name, tmpname)); - - camel_store_rename_folder (fromstore, meta->name, tmpname, &mm->ex); + + local_folder = mail_tool_uri_to_folder (m->fb->uri, &mm->ex); if (camel_exception_is_set (&mm->ex)) { - goto cleanup; - } - - /* we dont need to set the create flag ... or need an index if it has one */ - fromfolder = camel_store_get_folder (fromstore, tmpname, 0, &mm->ex); - if (fromfolder == NULL || camel_exception_is_set (&mm->ex)) { - /* try and recover ... */ - camel_exception_clear (&mm->ex); - camel_store_rename_folder (fromstore, tmpname, meta->name, &mm->ex); - goto cleanup; - } - - /* create a new mbox */ - d(printf("Creating the destination mbox\n")); - - flags = CAMEL_STORE_FOLDER_CREATE; - if (meta->indexed) - flags |= CAMEL_STORE_FOLDER_BODY_INDEX; - tofolder = camel_store_get_folder (tostore, meta->name, flags, &mm->ex); - if (tofolder == NULL || camel_exception_is_set (&mm->ex)) { - d(printf("cannot open destination folder\n")); - /* try and recover ... */ - camel_exception_clear (&mm->ex); - camel_store_rename_folder (fromstore, tmpname, meta->name, &mm->ex); - goto cleanup; - } - - uids = camel_folder_get_uids (fromfolder); - camel_folder_move_messages_to (fromfolder, uids, tofolder, &mm->ex); - camel_folder_free_uids (fromfolder, uids); - if (camel_exception_is_set (&mm->ex)) - goto cleanup; - - camel_folder_expunge (fromfolder, &mm->ex); - - d(printf("delete old mbox ...\n")); - camel_store_delete_folder (fromstore, tmpname, &mm->ex); - - /* switch format */ - g_free (meta->format); - meta->format = g_strdup (m->newtype); - if (save_metainfo (meta) == -1) { - camel_exception_setv (&mm->ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot save folder metainfo; " - "you'll probably find you can't\n" - "open this folder anymore: %s"), - tourl); - } - - cleanup: - if (local_folder && !local_folder->folder) { - struct _register_msg *rm = mail_msg_new (®ister_folder_op, NULL, sizeof (*m)); - - /* fake the internal part of this operation, nasty hackish thing */ - rm->local_folder = local_folder; - register_folder_register ((struct _mail_msg *)rm); - rm->local_folder = NULL; - mail_msg_free ((struct _mail_msg *)rm); + g_warning ("Can't resolve URI \"%s\" for reconfiguration!", m->fb->uri); + return; } - - if (tofolder) - camel_object_unref (CAMEL_OBJECT (tofolder)); - if (fromfolder) - camel_object_unref (CAMEL_OBJECT (fromfolder)); - if (fromstore) - camel_object_unref (CAMEL_OBJECT (fromstore)); - if (tostore) - camel_object_unref (CAMEL_OBJECT (tostore)); - if (meta) - free_metainfo (meta); - g_free (fromurl); - g_free (tourl); - if (url) - camel_url_free (url); + + mail_local_folder_reconfigure (MAIL_LOCAL_FOLDER (local_folder), m->newtype, &mm->ex); + m->folder_out = local_folder; } static void reconfigure_folder_reconfigured (struct _mail_msg *mm) { struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm; - char *uri; + /*char *uri;*/ if (camel_exception_is_set (&mm->ex)) { gnome_error_dialog (_("If you can no longer open this mailbox, then\n" "you may need to repair it manually.")); } - - /* force a reload of the newly formatted folder */ - d(printf("opening new source\n")); - uri = g_strdup (m->fb->uri); - folder_browser_set_uri (m->fb, uri); - g_free (uri); + + message_list_set_folder (m->fb->message_list, m->folder_out, FALSE); } static void reconfigure_folder_free (struct _mail_msg *mm) { struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm; - + + camel_object_unref (CAMEL_OBJECT (m->folder_out)); gtk_object_unref (GTK_OBJECT (m->fb)); g_free (m->newtype); } @@ -939,48 +999,57 @@ static void reconfigure_clicked (GnomeDialog *dialog, int button, struct _reconfigure_msg *m) { if (button == 0) { - GtkWidget *menu; - int type; - char *types[] = { "mbox", "maildir", "mh" }; + GtkWidget *menu, *item; /* hack to clear the message list during update */ - message_list_set_folder (m->fb->message_list, NULL, FALSE); - - menu = gtk_option_menu_get_menu (m->optionlist); - type = g_list_index (GTK_MENU_SHELL (menu)->children, - gtk_menu_get_active (GTK_MENU (menu))); - if (type < 0 || type > 2) - type = 0; + /* we need to do this because the message list caches + * CamelMessageInfos from the old folder. */ + message_list_set_folder(m->fb->message_list, NULL, FALSE); + menu = gtk_option_menu_get_menu(m->optionlist); + item = gtk_menu_get_active(GTK_MENU(menu)); + m->newtype = g_strdup(gtk_object_get_data((GtkObject *)item, "type")); + gtk_widget_set_sensitive (m->frame, FALSE); gtk_widget_set_sensitive (m->apply, FALSE); gtk_widget_set_sensitive (m->cancel, FALSE); - m->newtype = g_strdup (types[type]); e_thread_put (mail_thread_queued, (EMsg *)m); } else mail_msg_free ((struct _mail_msg *)m); - if (button != -1) + if (button != -1) { + /* remove this folder from our hash since we are done with it */ + g_hash_table_remove (reconfigure_folder_hash, m->fb->folder); + if (g_hash_table_size (reconfigure_folder_hash) == 0) { + /* additional cleanup */ + g_hash_table_destroy (reconfigure_folder_hash); + reconfigure_folder_hash = NULL; + } + gnome_dialog_close (dialog); + } } void mail_local_reconfigure_folder (FolderBrowser *fb) { - CamelStore *store; GladeXML *gui; GnomeDialog *gd; struct _reconfigure_msg *m; char *name, *title; - + GList *p; + GtkWidget *menu; + char *currentformat; + int index=0, history=0; + if (fb->folder == NULL) { g_warning ("Trying to reconfigure nonexistant folder"); return; } if (!reconfigure_folder_hash) - reconfigure_folder_hash = g_hash_table_new (g_direct_hash, g_direct_equal); + reconfigure_folder_hash = g_hash_table_new (NULL, NULL); if ((gd = g_hash_table_lookup (reconfigure_folder_hash, fb->folder))) { gdk_window_raise (GTK_WIDGET (gd)->window); @@ -988,22 +1057,13 @@ mail_local_reconfigure_folder (FolderBrowser *fb) } /* check if we can work on this folder */ - name = strchr (fb->uri, '/'); - if (name) { - while (*name == '/') - name++; - /* we just want to see if it's NULL or not */ - name = (char *) g_hash_table_lookup (local_store->folders, name); - } - - if (name == NULL) { + if (!MAIL_IS_LOCAL_FOLDER (fb->folder)) { e_notice (NULL, GNOME_MESSAGE_BOX_WARNING, _("You cannot change the format of a non-local folder.")); return; } m = mail_msg_new (&reconfigure_folder_op, NULL, sizeof (*m)); - store = camel_folder_get_parent_store (fb->folder); gui = glade_xml_new (EVOLUTION_GLADEDIR "/local-config.glade", "dialog_format"); gd = (GnomeDialog *)glade_xml_get_widget (gui, "dialog_format"); @@ -1020,23 +1080,49 @@ mail_local_reconfigure_folder (FolderBrowser *fb) m->optionlist = (GtkOptionMenu *)glade_xml_get_widget (gui, "option_format"); m->newtype = NULL; m->fb = fb; + m->folder_out = NULL; gtk_object_ref (GTK_OBJECT (fb)); - + + /* dynamically create the folder type list from camel */ + /* we assume the list is static and never freed */ + currentformat = MAIL_LOCAL_FOLDER (fb->folder)->meta->format; + p = camel_session_list_providers(session, TRUE); + menu = gtk_menu_new(); + while (p) { + CamelProvider *cp = p->data; + + /* we only want local storages */ + /* hack it so we also dont see file or spool stores, which aren't really meant for this */ + if ((cp->flags & (CAMEL_PROVIDER_IS_REMOTE|CAMEL_PROVIDER_IS_STORAGE)) == CAMEL_PROVIDER_IS_STORAGE + && strcmp(cp->protocol, "file") + && strcmp(cp->protocol, "spool")) { + GtkWidget *item; + char *label; + + if (strcmp(cp->protocol, currentformat) == 0) + history = index; + + label = g_strdup_printf("%s (%s)", cp->protocol, _(cp->name)); + item = gtk_menu_item_new_with_label(label); + g_free(label); + gtk_object_set_data((GtkObject *)item, "type", cp->protocol); + gtk_widget_show(item); + gtk_menu_append(GTK_MENU(menu), item); + index++; + } + p = p->next; + } + gtk_option_menu_remove_menu (GTK_OPTION_MENU(m->optionlist)); + gtk_option_menu_set_menu (GTK_OPTION_MENU(m->optionlist), menu); + gtk_option_menu_set_history(GTK_OPTION_MENU(m->optionlist), history); + gtk_label_set_text ((GtkLabel *)glade_xml_get_widget (gui, "label_format"), - ((CamelService *)store)->url->protocol); + MAIL_LOCAL_FOLDER (fb->folder)->meta->format); gtk_signal_connect (GTK_OBJECT (gd), "clicked", reconfigure_clicked, m); gtk_object_unref (GTK_OBJECT (gui)); g_hash_table_insert (reconfigure_folder_hash, (gpointer) fb->folder, (gpointer) gd); - gnome_dialog_run_and_close (GNOME_DIALOG (gd)); - - /* remove this folder from our hash since we are done with it */ - g_hash_table_remove (reconfigure_folder_hash, fb->folder); - if (g_hash_table_size (reconfigure_folder_hash) == 0) { - /* additional cleanup */ - g_hash_table_destroy (reconfigure_folder_hash); - reconfigure_folder_hash = NULL; - } + gnome_dialog_run (GNOME_DIALOG (gd)); } diff --git a/mail/mail-ops.c b/mail/mail-ops.c index 87b2905901..a8b05560fd 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -1380,80 +1380,6 @@ mail_get_store (const char *uri, void (*done) (char *uri, CamelStore *store, voi return id; } -/* ** CREATE FOLDER ******************************************************* */ - -/* trying to find a way to remove this entirely and just use get_folder() - to do the same thing. But i dont think it can be done, because one works on - shell uri's (get folder), and the other only works for mail uri's ? */ - -struct _create_folder_msg { - struct _mail_msg msg; - - char *uri; - CamelFolder *folder; - void (*done) (char *uri, CamelFolder *folder, void *data); - void *data; -}; - -static char * -create_folder_desc (struct _mail_msg *mm, int done) -{ - struct _create_folder_msg *m = (struct _create_folder_msg *)mm; - - return g_strdup_printf (_("Creating folder %s"), m->uri); -} - -static void -create_folder_get (struct _mail_msg *mm) -{ - struct _create_folder_msg *m = (struct _create_folder_msg *)mm; - - /* FIXME: supply a way to make indexes optional */ - m->folder = mail_tool_get_folder_from_urlname (m->uri, "mbox", - CAMEL_STORE_FOLDER_CREATE | - CAMEL_STORE_FOLDER_BODY_INDEX, - &mm->ex); -} - -static void -create_folder_got (struct _mail_msg *mm) -{ - struct _create_folder_msg *m = (struct _create_folder_msg *)mm; - - if (m->done) - m->done (m->uri, m->folder, m->data); -} - -static void -create_folder_free (struct _mail_msg *mm) -{ - struct _create_folder_msg *m = (struct _create_folder_msg *)mm; - - g_free (m->uri); - if (m->folder) - camel_object_unref (CAMEL_OBJECT (m->folder)); -} - -static struct _mail_msg_op create_folder_op = { - create_folder_desc, - create_folder_get, - create_folder_got, - create_folder_free, -}; - -void -mail_create_folder (const char *uri, void (*done) (char *uri, CamelFolder *folder, void *data), void *data) -{ - struct _create_folder_msg *m; - - m = mail_msg_new (&create_folder_op, NULL, sizeof(*m)); - m->uri = g_strdup (uri); - m->data = data; - m->done = done; - - e_thread_put (mail_thread_new, (EMsg *)m); -} - /* ** REMOVE FOLDER ******************************************************* */ struct _remove_folder_msg { diff --git a/mail/mail-ops.h b/mail/mail-ops.h index 7d00ec85da..b1f429ba64 100644 --- a/mail/mail-ops.h +++ b/mail/mail-ops.h @@ -91,11 +91,6 @@ int mail_get_folderinfo (CamelStore *store, void (*done)(CamelStore *store, CamelFolderInfo *info, void *data), void *data); -/* create a new mail folder */ -void mail_create_folder (const char *uri, - void (*done) (char *uri, CamelFolder *folder, void *data), - void *data); - /* remove an existing folder */ void mail_remove_folder (const char *uri, void (*done) (char *uri, gboolean removed, void *data), |