diff options
author | Dan Winship <danw@src.gnome.org> | 2000-11-07 06:03:24 +0800 |
---|---|---|
committer | Dan Winship <danw@src.gnome.org> | 2000-11-07 06:03:24 +0800 |
commit | dbc4e091133eee525a8b7c0fd449dcca6a5c719f (patch) | |
tree | b14c23e70bfc1ef0d49eec19d4600632cca00624 /mail/mail-local.c | |
parent | 9c651d480e354610f80f18b9af73bb3401745f59 (diff) | |
download | gsoc2013-evolution-dbc4e091133eee525a8b7c0fd449dcca6a5c719f.tar.gz gsoc2013-evolution-dbc4e091133eee525a8b7c0fd449dcca6a5c719f.tar.zst gsoc2013-evolution-dbc4e091133eee525a8b7c0fd449dcca6a5c719f.zip |
First draft of folder tree unread message indication for /local
mail folders.
* mail-local.c: Add a new CamelStore subclass, MailLocalStore,
which attaches to an Evolution_LocalStorage on one side and
CamelSession on the other, and keeps track of local folders. Some
of this code was previously in mail-local-storage.c, which no
longer exists.
(local_reconfigure_folder, etc): Various mail_op-related cleanups,
and wrap d() around a bunch of printfs.
* mail-tools.c (mail_tool_get_local_inbox_url,
mail_tool_get_local_movemail_url): Removed
(mail_tool_get_local_inbox): Simplified.
(mail_tool_do_movemail): Remove unused dest_url variable.
(mail_tool_uri_to_folder): Simplify. Now down to two cases
(vfolder, and everything else).
* component-factory.c (owner_set_cb): Pass evolution_dir to
mail_local_storage_startup.
* Makefile.am (evolution_mail_SOURCES): Remove
mail-local-storage.[ch]
svn path=/trunk/; revision=6456
Diffstat (limited to 'mail/mail-local.c')
-rw-r--r-- | mail/mail-local.c | 542 |
1 files changed, 438 insertions, 104 deletions
diff --git a/mail/mail-local.c b/mail/mail-local.c index 82f0ef3e18..ab2c4eba09 100644 --- a/mail/mail-local.c +++ b/mail/mail-local.c @@ -2,9 +2,11 @@ /* mail-local.c: Local mailbox support. */ /* - * Author: + * Authors: * Michael Zucchi <NotZed@helixcode.com> * Peter Williams <peterw@helixcode.com> + * Ettore Perazzoli <ettore@helixcode.com> + * Dan Winship <danw@helixcode.com> * * Copyright 2000 Helix Code, Inc. (http://www.helixcode.com) * @@ -24,14 +26,10 @@ * USA */ - -/* - code for handling local mail boxes -*/ - #ifdef HAVE_CONFIG_H #include <config.h> #endif + #include <bonobo.h> #include <libgnomeui/gnome-dialog.h> #include <glade/glade.h> @@ -39,9 +37,8 @@ #include "Evolution.h" #include "evolution-storage.h" - #include "evolution-shell-component.h" -#include "folder-browser.h" +#include "evolution-storage-listener.h" #include "camel/camel.h" @@ -53,9 +50,13 @@ #include "mail-local.h" #include "mail-tools.h" #include "mail-threads.h" +#include "folder-browser.h" #define d(x) + +/* Local folder metainfo */ + struct _local_meta { char *path; /* path of metainfo file */ @@ -74,7 +75,7 @@ load_metainfo(const char *path) meta = g_malloc0(sizeof(*meta)); meta->path = g_strdup(path); - printf("Loading folder metainfo from : %s\n", meta->path); + d(printf("Loading folder metainfo from : %s\n", meta->path)); doc = xmlParseFile(meta->path); if (doc == NULL) { @@ -128,7 +129,7 @@ save_metainfo(struct _local_meta *meta) xmlNodePtr root, node; int ret; - printf("Saving folder metainfo to : %s\n", meta->path); + d(printf("Saving folder metainfo to : %s\n", meta->path)); doc = xmlNewDoc("1.0"); root = xmlNewDocNode(doc, NULL, "folderinfo", NULL); @@ -144,89 +145,8 @@ save_metainfo(struct _local_meta *meta) return ret; } -/* maps a local uri to the real type */ -char * -mail_local_map_uri(const char *uri, int *index) -{ - CamelURL *url; - char *metapath; - char *storename; - struct _local_meta *meta; - CamelException *ex; - - if (index) - *index = TRUE; - - if (strncmp(uri, "file:", 5)) { - g_warning("Trying to map non-local uri: %s", uri); - return g_strdup(uri); - } - - ex = camel_exception_new(); - url = camel_url_new(uri, ex); - if (camel_exception_is_set(ex)) { - camel_exception_free(ex); - return g_strdup(uri); - } - camel_exception_free(ex); - - metapath = g_strdup_printf("%s/local-metadata.xml", url->path); - meta = load_metainfo(metapath); - g_free(metapath); - - if (index) - *index = meta->indexed; - - /* change file: to format: */ - camel_url_set_protocol(url, meta->format); - storename = camel_url_to_string (url, FALSE); - camel_url_free(url); - return storename; -} - -CamelFolder * -mail_tool_local_uri_to_folder(const char *uri, CamelException *ex) -{ - CamelURL *url; - char *metapath; - char *storename; - CamelFolder *folder = NULL; - struct _local_meta *meta; - int flags; - - if (strncmp(uri, "file:", 5)) { - return NULL; - } - - printf("opening local folder %s\n", uri); - - /* get the actual location of the mailbox */ - url = camel_url_new(uri, ex); - if (camel_exception_is_set(ex)) { - return NULL; - } - - metapath = g_strdup_printf("%s/local-metadata.xml", url->path); - meta = load_metainfo(metapath); - g_free(metapath); - - /* change file: to format: */ - camel_url_set_protocol(url, meta->format); - storename = camel_url_to_string (url, FALSE); - - printf("store name is %s\n", storename); - flags = 0; - if (meta->indexed) - flags |= CAMEL_STORE_FOLDER_BODY_INDEX; - - folder = mail_tool_get_folder_from_urlname (storename, meta->name, flags, ex); - camel_url_free(url); - g_free (storename); - free_metainfo(meta); - - return folder; -} +/* Local folder reconfiguration stuff */ /* open new @@ -265,11 +185,6 @@ typedef struct reconfigure_folder_input_s { GtkOptionMenu *optionlist; } reconfigure_folder_input_t; -static gchar *describe_reconfigure_folder (gpointer in_data, gboolean gerund); -static void setup_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex); -static void do_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex); -static void cleanup_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex); - static gchar * describe_reconfigure_folder (gpointer in_data, gboolean gerund) { @@ -290,6 +205,18 @@ setup_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex { reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data; + if (!IS_FOLDER_BROWSER (input->fb)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "Input has a bad FolderBrowser in reconfigure_folder"); + return; + } + + if (!input->newtype) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No new folder type in reconfigure_folder"); + return; + } + gtk_object_ref (GTK_OBJECT (input->fb)); } @@ -309,7 +236,7 @@ do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex) struct _local_meta *meta; guint32 flags; - printf("reconfiguring folder: %s to type %s\n", input->fb->uri, input->newtype); + d(printf("reconfiguring folder: %s to type %s\n", input->fb->uri, input->newtype)); /* get the actual location of the mailbox */ url = camel_url_new(input->fb->uri, ex); @@ -338,7 +265,7 @@ do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex) camel_url_set_protocol (url, input->newtype); tourl = camel_url_to_string (url, FALSE); - printf("opening stores %s and %s\n", fromurl, tourl); + d(printf("opening stores %s and %s\n", fromurl, tourl)); mail_tool_camel_lock_up (); fromstore = camel_session_get_store(session, fromurl, ex); @@ -355,7 +282,7 @@ do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex) /* rename the old mbox and open it again, without indexing */ tmpname = g_strdup_printf("%s_reconfig", meta->name); - printf("renaming %s to %s, and opening it\n", meta->name, tmpname); + d(printf("renaming %s to %s, and opening it\n", meta->name, tmpname)); update_progress(_("Renaming old folder and opening"), 0.0); mail_tool_camel_lock_up (); @@ -376,7 +303,7 @@ do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex) } /* create a new mbox */ - printf("Creating the destination mbox\n"); + d(printf("Creating the destination mbox\n")); update_progress(_("Creating new folder"), 0.0); flags = CAMEL_STORE_FOLDER_CREATE; @@ -384,7 +311,7 @@ do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex) flags |= CAMEL_STORE_FOLDER_BODY_INDEX; tofolder = camel_store_get_folder(tostore, meta->name, flags, ex); if (tofolder == NULL || camel_exception_is_set(ex)) { - printf("cannot open destination folder\n"); + d(printf("cannot open destination folder\n")); /* try and recover ... */ camel_exception_clear (ex); camel_store_rename_folder(fromstore, tmpname, meta->name, ex); @@ -395,7 +322,7 @@ do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex) update_progress(_("Copying messages"), 0.0); mail_tool_move_folder_contents (fromfolder, tofolder, FALSE, ex); - printf("delete old mbox ...\n"); + d(printf("delete old mbox ...\n")); camel_store_delete_folder(fromstore, tmpname, ex); mail_tool_camel_lock_down (); @@ -412,7 +339,7 @@ do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex) free_metainfo(meta); /* force a reload of the newly formatted folder */ - printf("opening new source\n"); + d(printf("opening new source\n")); uri = g_strdup(input->fb->uri); folder_browser_set_uri(input->fb, uri); g_free(uri); @@ -517,3 +444,410 @@ local_reconfigure_folder(FolderBrowser *fb) gnome_dialog_run_and_close (GNOME_DIALOG (gd)); } + + + +/* 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; + + Evolution_LocalStorage corba_local_storage; + EvolutionStorageListener *local_storage_listener; + + char *local_path; + int local_pathlen; + GHashTable *folders, *unread; +} MailLocalStore; + +typedef struct { + CamelStoreClass parent_class; +} MailLocalStoreClass; + +typedef struct { + CamelFolder *folder; + MailLocalStore *local_store; + char *path, *name; + int last_unread; +} MailLocalFolder; + +CamelType mail_local_store_get_type (void); + +static char *get_name (CamelService *service, gboolean brief); +static CamelFolder *get_folder (CamelStore *store, const char *folder_name, + 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 char *get_folder_name (CamelStore *store, const char *folder_name, + CamelException *ex); + +static void +mail_local_store_class_init (MailLocalStoreClass *mail_local_store_class) +{ + 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; + + camel_store_class->get_folder = get_folder; + camel_store_class->delete_folder = delete_folder; + camel_store_class->rename_folder = rename_folder; + camel_store_class->get_folder_name = get_folder_name; +} + +static void +mail_local_store_init (gpointer object, gpointer klass) +{ + MailLocalStore *local_store = MAIL_LOCAL_STORE (object); + + local_store->corba_local_storage = CORBA_OBJECT_NIL; +} + +static void +free_folder (gpointer key, gpointer data, gpointer user_data) +{ + MailLocalFolder *lf = data; + + g_free (key); + camel_object_unref (CAMEL_OBJECT (lf->folder)); + g_free (lf->path); +} + +static void +mail_local_store_finalize (gpointer object) +{ + MailLocalStore *local_store = MAIL_LOCAL_STORE (object); + CORBA_Environment ev; + + CORBA_exception_init (&ev); + if (!CORBA_Object_is_nil (local_store->corba_local_storage, &ev)) { + Bonobo_Unknown_unref (local_store->corba_local_storage, &ev); + CORBA_Object_release (local_store->corba_local_storage, &ev); + } + CORBA_exception_free (&ev); + + if (local_store->local_storage_listener) + gtk_object_unref (GTK_OBJECT (local_store->local_storage_listener)); + + g_hash_table_foreach (local_store->folders, free_folder, NULL); + g_hash_table_destroy (local_store->folders); + + g_free (local_store->local_path); +} + +CamelType +mail_local_store_get_type (void) +{ + 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) mail_local_store_class_init, + NULL, + (CamelObjectInitFunc) mail_local_store_init, + (CamelObjectFinalizeFunc) mail_local_store_finalize); + } + + return mail_local_store_type; +} + +static CamelFolder * +get_folder (CamelStore *store, const char *folder_name, + guint32 flags, CamelException *ex) +{ + MailLocalStore *local_store = (MailLocalStore *)store; + CamelFolder *folder; + + folder = g_hash_table_lookup (local_store->folders, folder_name); + if (folder) + camel_object_ref (CAMEL_OBJECT (folder)); + else { + camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + "No such folder %s", folder_name); + } + return folder; +} + +static void +delete_folder (CamelStore *store, const char *folder_name, CamelException *ex) +{ + /* No-op. The shell local storage deals with this. */ +} + +static void +rename_folder (CamelStore *store, const char *old, const char *new, + CamelException *ex) +{ + /* Probable no-op... */ +} + +static char * +get_folder_name (CamelStore *store, const char *folder_name, + CamelException *ex) +{ + return g_strdup (folder_name); +} + +static char * +get_name (CamelService *service, gboolean brief) +{ + return g_strdup ("Local mail folders"); +} + + +/* Callbacks for the EvolutionStorageListner signals. */ + +static void +local_storage_destroyed_cb (EvolutionStorageListener *storage_listener, + void *data) +{ + /* FIXME: Dunno how to handle this yet. */ + g_warning ("%s -- The LocalStorage has gone?!", __FILE__); +} + + +static void +local_folder_changed (CamelObject *object, gpointer event_data, + gpointer user_data) +{ + CamelFolder *folder = CAMEL_FOLDER (object); + MailLocalFolder *local_folder = user_data; + int unread; + char *display; + + unread = camel_folder_get_unread_message_count (folder); + if (unread != local_folder->last_unread) { + CORBA_Environment ev; + + CORBA_exception_init (&ev); + if (unread > 0) { + display = g_strdup_printf ("%s (%d)", + local_folder->name, unread); + Evolution_LocalStorage_update_folder ( + local_folder->local_store->corba_local_storage, + local_folder->path, display, TRUE, &ev); + g_free (display); + } else { + Evolution_LocalStorage_update_folder ( + local_folder->local_store->corba_local_storage, + local_folder->path, local_folder->name, + FALSE, &ev); + } + CORBA_exception_free (&ev); + + local_folder->last_unread = unread; + } +} + +static char * +describe_register_folder (gpointer in_data, gboolean gerund) +{ + if (gerund) + return g_strdup (_("Registering local folder")); + else + return g_strdup (_("Register local folder")); +} + +static void +do_register_folder (gpointer in_data, gpointer op_data, CamelException *ex) +{ + MailLocalFolder *local_folder = in_data; + char *name; + struct _local_meta *meta; + CamelStore *store; + guint32 flags; + + name = g_strdup_printf ("%s/local-metadata.xml", local_folder->path); + meta = load_metainfo (name); + g_free (name); + + name = g_strdup_printf ("%s:%s", meta->format, local_folder->path); + store = camel_session_get_store (session, name, ex); + g_free (name); + if (!store) { + free_metainfo (meta); + return; + } + + 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, ex); + camel_object_unref (CAMEL_OBJECT (store)); + free_metainfo (meta); +} + +static const mail_operation_spec op_register_folder = +{ + describe_register_folder, + 0, + NULL, + do_register_folder, + NULL +}; + +static void +local_storage_new_folder_cb (EvolutionStorageListener *storage_listener, + const char *path, + const Evolution_Folder *folder, + void *data) +{ + MailLocalStore *local_store = data; + MailLocalFolder *local_folder; + + if (strcmp (folder->type, "mail") != 0 || + strncmp (folder->physical_uri, "file://", 7) != 0 || + strncmp (folder->physical_uri + 7, local_store->local_path, + local_store->local_pathlen) != 0) + return; + + /* We don't need to deal with locking/reffing/copying + * issues because we don't return from the function + * until this is finished. + */ + local_folder = g_new0 (MailLocalFolder, 1); + local_folder->path = folder->physical_uri + 7; + local_folder->local_store = local_store; + mail_operation_queue (&op_register_folder, local_folder, FALSE); + mail_operation_wait_for_finish (); + + if (!local_folder->folder) { + g_free (local_folder); + return; + } + + local_folder->path = g_strdup (path); + local_folder->name = strrchr (local_folder->path, '/') + 1; + local_folder->last_unread = 0; + + g_hash_table_insert (local_store->folders, + g_strdup (folder->physical_uri + 8), + local_folder->folder); + camel_object_hook_event (CAMEL_OBJECT (local_folder->folder), + "folder_changed", local_folder_changed, + local_folder); + local_folder_changed (CAMEL_OBJECT (local_folder->folder), + NULL, local_folder); +} + +static void +local_storage_removed_folder_cb (EvolutionStorageListener *storage_listener, + const char *path, + void *data) +{ + MailLocalStore *local_store = data; + CamelFolder *folder; + + if (strncmp (path, "file://", 7) != 0 || + strncmp (path + 7, local_store->local_path, + local_store->local_pathlen) != 0) + return; + + path += 7 + local_store->local_pathlen; + + folder = g_hash_table_lookup (local_store->folders, path); + if (folder) { + camel_object_unref (CAMEL_OBJECT (folder)); + g_hash_table_remove (local_store->folders, path); + } +} + +static CamelProvider local_provider = { + "file", "Local mail", NULL, "mail", + CAMEL_PROVIDER_IS_STORAGE, CAMEL_URL_NEED_PATH, + { 0, 0 }, NULL +}; + +/* There's only one "file:" store. */ +static guint +non_hash (gconstpointer key) +{ + return 0; +} + +static gint +non_equal (gconstpointer a, gconstpointer b) +{ + return TRUE; +} + +void +mail_local_storage_startup (EvolutionShellClient *shellclient, + const char *evolution_path) +{ + MailLocalStore *local_store; + 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.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!"); + return; + } + local_store->corba_local_storage = + evolution_shell_client_get_local_storage (shellclient); + if (local_store->corba_local_storage == CORBA_OBJECT_NIL) { + g_warning ("No local storage!"); + camel_object_unref (CAMEL_OBJECT (local_store)); + return; + } + + local_store->local_storage_listener = + evolution_storage_listener_new (); + corba_local_storage_listener = + evolution_storage_listener_corba_objref ( + local_store->local_storage_listener); + + gtk_signal_connect (GTK_OBJECT (local_store->local_storage_listener), + "destroyed", + GTK_SIGNAL_FUNC (local_storage_destroyed_cb), + local_store); + gtk_signal_connect (GTK_OBJECT (local_store->local_storage_listener), + "new_folder", + GTK_SIGNAL_FUNC (local_storage_new_folder_cb), + local_store); + gtk_signal_connect (GTK_OBJECT (local_store->local_storage_listener), + "removed_folder", + GTK_SIGNAL_FUNC (local_storage_removed_folder_cb), + local_store); + + 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_exception_init (&ev); + Evolution_Storage_add_listener (local_store->corba_local_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); +} |