aboutsummaryrefslogtreecommitdiffstats
path: root/mail
diff options
context:
space:
mode:
Diffstat (limited to 'mail')
-rw-r--r--mail/ChangeLog87
-rw-r--r--mail/component-factory.c25
-rw-r--r--mail/folder-browser-ui.c25
-rw-r--r--mail/folder-browser.c2
-rw-r--r--mail/mail-folder-cache.c428
-rw-r--r--mail/mail-mt.c83
-rw-r--r--mail/mail-mt.h11
-rw-r--r--mail/mail-session.c5
-rw-r--r--mail/message-list.c4
9 files changed, 450 insertions, 220 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index d581793df4..63ac8b9690 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,90 @@
+2001-10-25 <NotZed@Ximian.com>
+
+ * folder-browser-ui.c (fbui_sensitize_timeout): So apparently the
+ uicomp can just 'vanish' while we're using it. Joy. Take care of
+ that case here, fixes #13482.
+ (fbui_sensitise_item): Check here too just for kicks.
+
+ * mail-folder-cache.c (store_finalised): If we can't destroy our
+ async event, then queue another one to do it.
+ (store_finalised_finish): And handle it here, until we can, then
+ free it.
+ (mail_note_store): Queue an async event to get folderinfo, dont
+ use mail_get_folderinfo.
+ (update_folders_get): thread-async event to retrieve the
+ folderinfo, and build it, then queues gui-async event to update
+ the gui.
+ (add_unmatched_info): Taken from mail-ops, adds unmatched if
+ required.
+ (add_vtrash_info): From mail-ops, add trash if required.
+ (update_folders): Thread async event to update gui.
+ (mail_note_store): Ref the store and storage when created.
+ (update_1folder): Changed to assume we have info_lock, and store
+ updates in an updates list.
+ (setup_folder): Same.
+ (folder_changed): Changed to call update_1folder directly.
+ (real_folder_changed): Removed.
+ (mail_note_folder): Changed to call update_1folder directly.
+ (real_note_folder): Removed.
+ (store_folder_subscribed): Call setup_folder directly.
+ (real_folder_created): Removed.
+ (real_flush_update): Function that actually does the updates in
+ the gui thread.
+ (mail_note_store): Go back to using mail_get_folderinfo.
+ (update_folders): Fixed upf ro changed api's.
+ (unset_folder_info): Changed to queue pending updates.
+ (real_folder_deleted): Removed.
+ (store_folder_unsubscribed): Do the removal work directly.
+ (mail_note_store): Dont link to finalised event of store - we now
+ ref it.
+ (mail_note_store_remove): If we have any pending updates, clear
+ them out. Also cancel any pending folderinfo retrieve operations.
+ (update_folders): Remove our update from the storeinfo list, if it
+ still exists.
+ (update_1folder): Make 'sent folder shows all counts' optional via
+ an environmental variable EVOLUTION_COUNT_SENT for all those
+ bloody whinging lusers out there.
+ (mail_note_store_remove): Unref the storage when done.
+
+ * mail-mt.c (mail_async_event_emit): If we're in main and have a
+ gui task, set it to run via an idle function.
+ (idle_async_event): Wrapper for calling do_async_event from idle
+ function, and freeing the message when done.
+ (idle_async_event): Call mail_msg_free not free on the finished
+ message.
+
+ * component-factory.c (mail_remove_storage): Destroy the storage
+ async.
+ (store_disconnect): This does the work.
+ (free_storage): Un-note the store when we remove it, so the store
+ noting code can unref things properly.
+ (idle_quit): Return false when done, dont loop.
+
+2001-10-24 <NotZed@Ximian.com>
+
+ * component-factory.c (owner_set_cb): Setup an async_event
+ handler.
+ (idle_quit): Try to destroy the async_event, or keep dropping out
+ if it can't (deadlock).
+
+ * mail-mt.c (do_async_event): Set the threadid of the thread we're
+ running in so we know its running/which thread its in.
+ (mail_async_event_emit): Added new argument 'type' which is the
+ type of thread to execute against, gui or another one. Fixed all
+ callers.
+ (mail_async_event_destroy): Return -1 if this operation will fail
+ (deadlock possibility). If we're in the thread of the task
+ we're going to wait for, then return a failure (since we will
+ deadlock).
+ (mail_async_event_emit): Chagned to use MailAsyncFunc type as the
+ function type, which just takes 3 void args, change args to suit.
+
+ * mail-folder-cache.c (mail_note_store): Record the pending update
+ events in a pending list. We should really be able to use an
+ async event for this, but that doesn't return to the gui loop when
+ done :-/
+ (update_folders): Remove from pending update when done.
+
2001-10-25 Jeffrey Stedfast <fejj@ximian.com>
* mail-send-recv.c (get_receive_type): Check for a NULL provider.
diff --git a/mail/component-factory.c b/mail/component-factory.c
index ccd6f81461..e62a313912 100644
--- a/mail/component-factory.c
+++ b/mail/component-factory.c
@@ -66,6 +66,8 @@ EvolutionShellClient *global_shell_client = NULL;
RuleContext *search_context = NULL;
+static MailAsyncEvent *async_event = NULL;
+
static GHashTable *storages_hash;
static EvolutionShellComponent *shell_component;
@@ -697,6 +699,8 @@ owner_set_cb (EvolutionShellComponent *shell_component,
evolution_dir = g_strdup (evolution_homedir);
mail_session_init ();
+ async_event = mail_async_event_new();
+
storages_hash = g_hash_table_new (NULL, NULL);
corba_shell = bonobo_object_corba_objref (BONOBO_OBJECT (shell_client));
@@ -755,6 +759,7 @@ static void
free_storage (gpointer service, gpointer storage, gpointer data)
{
if (service) {
+ mail_note_store_remove((CamelStore *)service);
camel_service_disconnect (CAMEL_SERVICE (service), TRUE, NULL);
camel_object_unref (CAMEL_OBJECT (service));
}
@@ -830,14 +835,18 @@ idle_quit (gpointer user_data)
return TRUE;
}
+ if (mail_async_event_destroy(async_event) == -1)
+ return TRUE;
+
shutdown_shutdown = TRUE;
g_hash_table_foreach (storages_hash, free_storage, NULL);
g_hash_table_destroy (storages_hash);
+ storages_hash = NULL;
}
gtk_main_quit ();
-
- return TRUE;
+
+ return FALSE;
}
static void owner_unset_cb (EvolutionShellComponent *shell_component, gpointer user_data);
@@ -1230,6 +1239,13 @@ mail_lookup_storage (CamelStore *store)
return storage;
}
+static void
+store_disconnect(CamelStore *store, void *event_data, void *data)
+{
+ camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL);
+ camel_object_unref (CAMEL_OBJECT (store));
+}
+
void
mail_remove_storage (CamelStore *store)
{
@@ -1254,9 +1270,8 @@ mail_remove_storage (CamelStore *store)
corba_shell = bonobo_object_corba_objref (BONOBO_OBJECT (shell_client));
evolution_storage_deregister_on_shell (storage, corba_shell);
-
- camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL);
- camel_object_unref (CAMEL_OBJECT (store));
+
+ mail_async_event_emit(async_event, MAIL_ASYNC_THREAD, (MailAsyncFunc)store_disconnect, store, NULL, NULL);
}
void
diff --git a/mail/folder-browser-ui.c b/mail/folder-browser-ui.c
index 514529a9b9..b5b4e853a8 100644
--- a/mail/folder-browser-ui.c
+++ b/mail/folder-browser-ui.c
@@ -438,9 +438,12 @@ fbui_sensitise_item(FolderBrowser *fb, const char *item, int state)
}
g_hash_table_insert(fb->sensitise_state, (char *)item, (void *)state);
- name = alloca(strlen(item) + strlen("/commands/") + 1);
- sprintf(name, "/commands/%s", item);
- bonobo_ui_component_set_prop(fb->uicomp, name, "sensitive", state?"1":"0", NULL);
+
+ if (fb->uicomp) {
+ name = alloca(strlen(item) + strlen("/commands/") + 1);
+ sprintf(name, "/commands/%s", item);
+ bonobo_ui_component_set_prop(fb->uicomp, name, "sensitive", state?"1":"0", NULL);
+ }
}
struct sensitize_data {
@@ -457,19 +460,15 @@ fbui_sensitize_timeout (gpointer data)
struct sensitize_data *sd;
int i;
- if (uic) {
- /*bonobo_ui_component_freeze (uic, NULL);*/
+ /*bonobo_ui_component_freeze (uic, NULL);*/
- for (iter = fb->sensitize_changes; iter; iter = iter->next) {
- sd = (struct sensitize_data *) iter->data;
- for (i=0;sd->items[i];i++)
+ for (iter = fb->sensitize_changes; iter; iter = iter->next) {
+ sd = (struct sensitize_data *) iter->data;
+ for (i=0;sd->items[i];i++) {
+ if (fb->uicomp)
fbui_sensitise_item(fb, sd->items[i], sd->enable);
- g_free(sd);
}
-
- /*bonobo_ui_component_thaw (uic, NULL);*/
- } else {
- g_slist_foreach(fb->sensitize_changes, (GFunc)g_free, NULL);
+ g_free(sd);
}
g_slist_free (fb->sensitize_changes);
diff --git a/mail/folder-browser.c b/mail/folder-browser.c
index 8a1734e222..ff25360f67 100644
--- a/mail/folder-browser.c
+++ b/mail/folder-browser.c
@@ -820,7 +820,7 @@ static void folder_changed(CamelObject *o, void *event_data, void *data)
{
FolderBrowser *fb = data;
- mail_async_event_emit(fb->async_event, main_folder_changed, o, NULL, data);
+ mail_async_event_emit(fb->async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)main_folder_changed, o, NULL, data);
}
static void
diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c
index d91fc1c8e1..337f613ed9 100644
--- a/mail/mail-folder-cache.c
+++ b/mail/mail-folder-cache.c
@@ -36,6 +36,9 @@
#include <camel/camel-store.h>
#include <camel/camel-folder.h>
#include <camel/camel-vtrash-folder.h>
+#include <camel/camel-vee-store.h>
+
+#include "e-util/e-unicode-i18n.h"
#include "mail-mt.h"
#include "mail-folder-cache.h"
@@ -61,6 +64,22 @@ struct _folder_info {
CamelFolder *folder; /* if known */
};
+/* pending list of updates */
+struct _folder_update {
+ struct _folder_update *next;
+ struct _folder_update *prev;
+
+ unsigned int remove:1; /* removing from vfolders */
+ unsigned int delete:1; /* deleting as well? */
+ unsigned int add:1; /* add to vfolder */
+
+ char *path;
+ char *name;
+ char *uri;
+ int unread;
+ CamelStore *store;
+};
+
struct _store_info {
GHashTable *folders; /* by full_name */
GHashTable *folders_uri; /* by uri */
@@ -70,14 +89,141 @@ struct _store_info {
/* only 1 should be set */
EvolutionStorage *storage;
GNOME_Evolution_Storage corba_storage;
- MailAsyncEvent *async_event;
+
+ /* Outstanding folderinfo requests */
+ EDList folderinfo_updates;
};
+static void folder_changed(CamelObject *o, gpointer event_data, gpointer user_data);
+static void folder_deleted(CamelObject *o, gpointer event_data, gpointer user_data);
+static void folder_finalised(CamelObject *o, gpointer event_data, gpointer user_data);
+
+/* Store to storeinfo table, active stores */
static GHashTable *stores;
-static void free_folder_info(char *path, struct _folder_info *mfi, void *data);
-static void unset_folder_info(struct _folder_info *mfi, int delete);
+/* List of folder changes to be executed in gui thread */
+static EDList updates = E_DLIST_INITIALISER(updates);
+static int update_id = -1;
+
+/* hack for people who LIKE to have unsent count */
+static int count_sent = FALSE;
+
+static void
+free_update(struct _folder_update *up)
+{
+ g_free(up->path);
+ g_free(up->name);
+ g_free(up->uri);
+ if (up->store)
+ camel_object_unref((CamelObject *)up->store);
+ g_free(up);
+}
+
+static void
+real_flush_updates(void *o, void *event_data, void *data)
+{
+ struct _folder_update *up;
+ struct _store_info *si;
+ EvolutionStorage *storage;
+ GNOME_Evolution_Storage corba_storage;
+ CORBA_Environment ev;
+
+ LOCK(info_lock);
+ while ((up = (struct _folder_update *)e_dlist_remhead(&updates))) {
+
+ si = g_hash_table_lookup(stores, up->store);
+ if (si) {
+ storage = si->storage;
+ if (storage)
+ bonobo_object_ref((BonoboObject *)storage);
+ corba_storage = si->corba_storage;
+ } else {
+ storage = NULL;
+ corba_storage = CORBA_OBJECT_NIL;
+ }
+
+ UNLOCK(info_lock);
+
+ if (up->remove) {
+ if (up->delete)
+ mail_vfolder_delete_uri(up->store, up->uri);
+ else
+ mail_vfolder_add_uri(up->store, up->uri, TRUE);
+ } else {
+ if (up->name == NULL) {
+ if (storage != NULL) {
+ d(printf("Updating existing folder: %s (%d unread)\n", up->path, up->unread));
+ evolution_storage_update_folder(storage, up->path, up->unread);
+ } else if (corba_storage != CORBA_OBJECT_NIL) {
+ d(printf("Updating existing (local) folder: %s (%d unread)\n", up->path, up->unread));
+ CORBA_exception_init(&ev);
+ GNOME_Evolution_Storage_updateFolder(corba_storage, up->path, up->unread, &ev);
+ CORBA_exception_free(&ev);
+ }
+ } else if (storage != NULL) {
+ char *type = (strncmp(up->uri, "vtrash:", 7)==0)?"vtrash":"mail";
+
+ d(printf("Adding new folder: %s\n", up->path));
+ evolution_storage_new_folder(storage, up->path, up->name, type, up->uri, up->name, up->unread);
+ }
+ if (up->add)
+ mail_vfolder_add_uri(up->store, up->uri, FALSE);
+ }
+
+ free_update(up);
+
+ if (storage)
+ bonobo_object_unref((BonoboObject *)storage);
+
+ LOCK(info_lock);
+ }
+ update_id = -1;
+ UNLOCK(info_lock);
+}
+
+static void
+flush_updates(void)
+{
+ if (update_id == -1 && !e_dlist_empty(&updates))
+ update_id = mail_async_event_emit(mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)real_flush_updates, 0, 0, 0);
+}
+
+static void
+unset_folder_info(struct _folder_info *mfi, int delete)
+{
+ struct _folder_update *up;
+
+ if (mfi->folder) {
+ CamelFolder *folder = mfi->folder;
+
+ camel_object_unhook_event((CamelObject *)folder, "folder_changed", folder_changed, mfi);
+ camel_object_unhook_event((CamelObject *)folder, "message_changed", folder_changed, mfi);
+ camel_object_unhook_event((CamelObject *)folder, "deleted", folder_deleted, mfi);
+ camel_object_unhook_event((CamelObject *)folder, "finalize", folder_finalised, mfi);
+ }
+
+ if (strstr(mfi->uri, ";noselect") == NULL) {
+ up = g_malloc0(sizeof(*up));
+
+ up->remove = TRUE;
+ up->delete = delete;
+ up->store = mfi->store_info->store;
+ camel_object_ref((CamelObject *)up->store);
+ up->uri = g_strdup(mfi->uri);
+
+ e_dlist_addtail(&updates, (EDListNode *)up);
+ flush_updates();
+ }
+}
+static void
+free_folder_info(struct _folder_info *mfi)
+{
+ g_free(mfi->path);
+ g_free(mfi->full_name);
+ g_free(mfi->uri);
+ g_free(mfi);
+}
/* This is how unread counts work (and don't work):
*
@@ -106,17 +252,16 @@ static void
update_1folder(struct _folder_info *mfi, CamelFolderInfo *info)
{
struct _store_info *si;
+ struct _folder_update *up;
CamelFolder *folder;
int unread = -1;
- CORBA_Environment ev;
extern CamelFolder *outbox_folder, *sent_folder;
si = mfi->store_info;
- LOCK(info_lock);
folder = mfi->folder;
if (folder) {
- if (CAMEL_IS_VTRASH_FOLDER (folder) || folder == outbox_folder || folder == sent_folder) {
+ if (CAMEL_IS_VTRASH_FOLDER (folder) || folder == outbox_folder || (count_sent && folder == sent_folder)) {
unread = camel_folder_get_message_count(folder);
} else {
if (info)
@@ -126,36 +271,31 @@ update_1folder(struct _folder_info *mfi, CamelFolderInfo *info)
}
} else if (info)
unread = info->unread_message_count;
- UNLOCK(info_lock);
+
if (unread == -1)
return;
- if (si->storage == NULL) {
- d(printf("Updating existing (local) folder: %s (%d unread) folder=%p\n", mfi->path, unread, folder));
- CORBA_exception_init(&ev);
- GNOME_Evolution_Storage_updateFolder(si->corba_storage, mfi->path, unread, &ev);
- CORBA_exception_free(&ev);
- } else {
- d(printf("Updating existing folder: %s (%d unread)\n", mfi->path, unread));
- evolution_storage_update_folder(si->storage, mfi->path, unread);
- }
+ up = g_malloc0(sizeof(*up));
+ up->path = g_strdup(mfi->path);
+ up->unread = unread;
+ up->store = mfi->store_info->store;
+ camel_object_ref((CamelObject *)up->store);
+ e_dlist_addtail(&updates, (EDListNode *)up);
+ flush_updates();
}
static void
setup_folder(CamelFolderInfo *fi, struct _store_info *si)
{
struct _folder_info *mfi;
- char *type;
- CamelStore *store;
+ struct _folder_update *up;
- LOCK(info_lock);
mfi = g_hash_table_lookup(si->folders, fi->full_name);
if (mfi) {
- UNLOCK(info_lock);
update_1folder(mfi, fi);
} else {
/* always 'add it', but only 'add it' to non-local stores */
- d(printf("Adding new folder: %s (%s) %d unread\n", fi->path, fi->url, fi->unread_message_count));
+ /*d(printf("Adding new folder: %s (%s) %d unread\n", fi->path, fi->url, fi->unread_message_count));*/
mfi = g_malloc0(sizeof(*mfi));
mfi->path = g_strdup(fi->path);
mfi->full_name = g_strdup(fi->full_name);
@@ -163,32 +303,35 @@ setup_folder(CamelFolderInfo *fi, struct _store_info *si)
mfi->store_info = si;
g_hash_table_insert(si->folders, mfi->full_name, mfi);
g_hash_table_insert(si->folders_uri, mfi->uri, mfi);
- store = si->store;
- camel_object_ref((CamelObject *)store);
- UNLOCK(info_lock);
+ up = g_malloc0(sizeof(*up));
+ up->path = g_strdup(mfi->path);
if (si->storage != NULL) {
- int unread = (fi->unread_message_count==-1)?0:fi->unread_message_count;
-
- type = (strncmp(fi->url, "vtrash:", 7)==0)?"vtrash":"mail";
- evolution_storage_new_folder(si->storage, mfi->path, fi->name, type,
- fi->url, fi->name, unread);
+ up->name = g_strdup(fi->name);
}
-
+ up->uri = g_strdup(fi->url);
+ up->unread = (fi->unread_message_count==-1)?0:fi->unread_message_count;
+ up->store = si->store;
+ camel_object_ref((CamelObject *)up->store);
if (strstr(fi->url, ";noselect") == NULL)
- mail_vfolder_add_uri(store, fi->url, FALSE);
+ up->add = TRUE;
- camel_object_unref((CamelObject *)store);
+ e_dlist_addtail(&updates, (EDListNode *)up);
+ flush_updates();
}
}
static void
-real_folder_changed(CamelFolder *folder, void *event_data, void *data)
+create_folders(CamelFolderInfo *fi, struct _store_info *si)
{
- struct _folder_info *mfi = data;
+ d(printf("Setup new folder: %s\n", fi->url));
- update_1folder(mfi, NULL);
- camel_object_unref((CamelObject *)folder);
+ setup_folder(fi, si);
+
+ if (fi->child)
+ create_folders(fi->child, si);
+ if (fi->sibling)
+ create_folders(fi->sibling, si);
}
static void
@@ -199,9 +342,9 @@ folder_changed(CamelObject *o, gpointer event_data, gpointer user_data)
if (mfi->folder != CAMEL_FOLDER(o))
return;
- d(printf("Fodler changed!\n"));
- camel_object_ref((CamelObject *)o);
- mail_async_event_emit(mfi->store_info->async_event, (CamelObjectEventHookFunc)real_folder_changed, o, NULL, mfi);
+ LOCK(info_lock);
+ update_1folder(mfi, NULL);
+ UNLOCK(info_lock);
}
static void
@@ -222,15 +365,6 @@ folder_deleted(CamelObject *o, gpointer event_data, gpointer user_data)
mfi->folder = NULL;
}
-static void
-real_note_folder(CamelFolder *folder, void *event_data, void *data)
-{
- struct _folder_info *mfi = event_data;
-
- update_1folder(mfi, NULL);
- camel_object_unref((CamelObject *)folder);
-}
-
void mail_note_folder(CamelFolder *folder)
{
CamelStore *store = folder->parent_store;
@@ -270,36 +404,22 @@ void mail_note_folder(CamelFolder *folder)
camel_object_hook_event((CamelObject *)folder, "deleted", folder_deleted, mfi);
camel_object_hook_event((CamelObject *)folder, "finalize", folder_finalised, mfi);
- camel_object_ref((CamelObject *)folder);
+ update_1folder(mfi, NULL);
UNLOCK(info_lock);
-
- mail_async_event_emit(si->async_event, (CamelObjectEventHookFunc)real_note_folder, (CamelObject *)folder, (void *)mfi, NULL);
-}
-
-static void
-real_folder_created(CamelStore *store, struct _store_info *si, CamelFolderInfo *fi)
-{
- setup_folder(fi, si);
- camel_object_unref((CamelObject *)store);
- camel_folder_info_free(fi);
}
static void
store_folder_subscribed(CamelObject *o, void *event_data, void *data)
{
struct _store_info *si;
+ CamelFolderInfo *fi = event_data;
LOCK(info_lock);
si = g_hash_table_lookup(stores, o);
if (si)
- camel_object_ref(o);
+ setup_folder(fi, si);
UNLOCK(info_lock);
-
- if (si)
- mail_async_event_emit(si->async_event,
- (CamelObjectEventHookFunc)real_folder_created, o, si,
- camel_folder_info_clone(event_data));
}
static void
@@ -310,43 +430,28 @@ store_folder_created(CamelObject *o, void *event_data, void *data)
store_folder_subscribed(o, event_data, data);
}
-
static void
-real_folder_deleted(CamelStore *store, struct _store_info *si, CamelFolderInfo *fi)
+store_folder_unsubscribed(CamelObject *o, void *event_data, void *data)
{
+ struct _store_info *si;
+ CamelFolderInfo *fi = event_data;
struct _folder_info *mfi;
+ CamelStore *store = (CamelStore *)o;
- d(printf("real_folder_deleted: %s (%s)\n", fi->full_name, fi->url));
+ d(printf("Folder deleted: %s\n", fi->full_name));
LOCK(info_lock);
- mfi = g_hash_table_lookup(si->folders, fi->full_name);
- if (mfi) {
- g_hash_table_remove(si->folders, mfi->full_name);
- g_hash_table_remove(si->folders_uri, mfi->uri);
- unset_folder_info(mfi, TRUE);
- free_folder_info(NULL, mfi, NULL);
+ si = g_hash_table_lookup(stores, store);
+ if (si) {
+ mfi = g_hash_table_lookup(si->folders, fi->full_name);
+ if (mfi) {
+ g_hash_table_remove(si->folders, mfi->full_name);
+ g_hash_table_remove(si->folders_uri, mfi->uri);
+ unset_folder_info(mfi, TRUE);
+ free_folder_info(mfi);
+ }
}
UNLOCK(info_lock);
-
- camel_object_unref((CamelObject *)store);
- camel_folder_info_free(fi);
-}
-
-static void
-store_folder_unsubscribed(CamelObject *o, void *event_data, void *data)
-{
- struct _store_info *si;
-
- LOCK(info_lock);
- si = g_hash_table_lookup(stores, o);
- if (si)
- camel_object_ref(o);
- UNLOCK(info_lock);
-
- if (si)
- mail_async_event_emit(si->async_event,
- (CamelObjectEventHookFunc)real_folder_deleted, o, si,
- camel_folder_info_clone(event_data));
}
static void
@@ -357,25 +462,15 @@ store_folder_deleted(CamelObject *o, void *event_data, void *data)
store_folder_unsubscribed(o, event_data, data);
}
-static void
-unset_folder_info(struct _folder_info *mfi, int delete)
-{
- if (mfi->folder) {
- CamelFolder *folder = mfi->folder;
+struct _update_data {
+ struct _update_data *next;
+ struct _update_data *prev;
- camel_object_unhook_event((CamelObject *)folder, "folder_changed", folder_changed, mfi);
- camel_object_unhook_event((CamelObject *)folder, "message_changed", folder_changed, mfi);
- camel_object_unhook_event((CamelObject *)folder, "deleted", folder_deleted, mfi);
- camel_object_unhook_event((CamelObject *)folder, "finalize", folder_finalised, mfi);
- }
+ int id; /* id for cancellation */
- if (strstr(mfi->uri, ";noselect") == NULL) {
- if (delete)
- mail_vfolder_delete_uri(mfi->store_info->store, mfi->uri);
- else
- mail_vfolder_add_uri(mfi->store_info->store, mfi->uri, TRUE);
- }
-}
+ void (*done)(CamelStore *store, CamelFolderInfo *info, void *data);
+ void *data;
+};
static void
unset_folder_info_hash(char *path, struct _folder_info *mfi, void *data)
@@ -383,22 +478,24 @@ unset_folder_info_hash(char *path, struct _folder_info *mfi, void *data)
unset_folder_info(mfi, FALSE);
}
-
static void
-free_folder_info(char *path, struct _folder_info *mfi, void *data)
+free_folder_info_hash(char *path, struct _folder_info *mfi, void *data)
{
- g_free(mfi->path);
- g_free(mfi->full_name);
- g_free(mfi->uri);
+ free_folder_info(mfi);
}
-static void
-store_finalised(CamelObject *o, void *event_data, void *data)
+void
+mail_note_store_remove(CamelStore *store)
{
- CamelStore *store = (CamelStore *)o;
+ struct _update_data *ud;
struct _store_info *si;
- d(printf("store finalised!!\n"));
+ g_assert(CAMEL_IS_STORE(store));
+
+ if (stores == NULL)
+ return;
+
+ d(printf("store removed!!\n"));
LOCK(info_lock);
si = g_hash_table_lookup(stores, store);
if (si) {
@@ -408,13 +505,20 @@ store_finalised(CamelObject *o, void *event_data, void *data)
camel_object_unhook_event((CamelObject *)store, "folder_deleted", store_folder_deleted, NULL);
camel_object_unhook_event((CamelObject *)store, "folder_subscribed", store_folder_subscribed, NULL);
camel_object_unhook_event((CamelObject *)store, "folder_unsubscribed", store_folder_unsubscribed, NULL);
- camel_object_unhook_event((CamelObject *)store, "finalize", store_finalised, NULL);
-
g_hash_table_foreach(si->folders, (GHFunc)unset_folder_info_hash, NULL);
- UNLOCK(info_lock);
- mail_async_event_destroy(si->async_event);
- LOCK(info_lock);
- g_hash_table_foreach(si->folders, (GHFunc)free_folder_info, NULL);
+
+ ud = (struct _update_data *)si->folderinfo_updates.head;
+ while (ud->next) {
+ (printf("Cancelling outstanding folderinfo update %d\n", ud->id));
+ mail_msg_cancel(ud->id);
+ ud = ud->next;
+ }
+
+ /* This is the only gtk object we need to unref */
+ mail_async_event_emit(mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)bonobo_object_unref, si->storage, 0, 0);
+
+ camel_object_unref((CamelObject *)si->store);
+ g_hash_table_foreach(si->folders, (GHFunc)free_folder_info_hash, NULL);
g_hash_table_destroy(si->folders);
g_hash_table_destroy(si->folders_uri);
g_free(si);
@@ -423,52 +527,34 @@ store_finalised(CamelObject *o, void *event_data, void *data)
}
static void
-create_folders(CamelFolderInfo *fi, struct _store_info *si)
+update_folders(CamelStore *store, CamelFolderInfo *fi, void *data)
{
- d(printf("Setup new folder: %s\n", fi->url));
-
- setup_folder(fi, si);
-
- if (fi->child)
- create_folders(fi->child, si);
- if (fi->sibling)
- create_folders(fi->sibling, si);
-}
-
-struct _update_data {
+ struct _update_data *ud = data;
struct _store_info *si;
- void (*done)(CamelStore *store, CamelFolderInfo *info, void *data);
- void *data;
-};
-static void
-update_folders(CamelStore *store, CamelFolderInfo *info, void *data)
-{
- struct _update_data *ud = data;
+ d(printf("Got folderinfo for store\n"));
- if (info) {
- if (ud->si->storage)
- gtk_object_set_data (GTK_OBJECT (ud->si->storage), "connected", GINT_TO_POINTER (TRUE));
- create_folders(info, ud->si);
+ LOCK(info_lock);
+ si = g_hash_table_lookup(stores, store);
+ if (si) {
+ /* the 'si' is still there, so we can remove ourselves from its list */
+ /* otherwise its not, and we're on our own and free anyway */
+ e_dlist_remove((EDListNode *)ud);
+
+ if (fi) {
+ if (si->storage)
+ gtk_object_set_data (GTK_OBJECT (si->storage), "connected", GINT_TO_POINTER (TRUE));
+ create_folders(fi, si);
+ }
}
+ UNLOCK(info_lock);
+
if (ud->done)
- ud->done(store, info, ud->data);
+ ud->done(store, fi, ud->data);
g_free(ud);
}
void
-mail_note_store_remove(CamelStore *store)
-{
- g_assert(CAMEL_IS_STORE(store));
-
- if (stores == NULL)
- return;
-
- /* same action */
- store_finalised((CamelObject *)store, NULL, NULL);
-}
-
-void
mail_note_store(CamelStore *store, EvolutionStorage *storage, GNOME_Evolution_Storage corba_storage,
void (*done)(CamelStore *store, CamelFolderInfo *info, void *data), void *data)
{
@@ -481,8 +567,10 @@ mail_note_store(CamelStore *store, EvolutionStorage *storage, GNOME_Evolution_St
LOCK(info_lock);
- if (stores == NULL)
+ if (stores == NULL) {
stores = g_hash_table_new(NULL, NULL);
+ count_sent = getenv("EVOLUTION_COUNT_SENT") != NULL;
+ }
si = g_hash_table_lookup(stores, store);
if (si == NULL) {
@@ -496,26 +584,28 @@ mail_note_store(CamelStore *store, EvolutionStorage *storage, GNOME_Evolution_St
si->folders_uri = g_hash_table_new(CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->hash_folder_name,
CAMEL_STORE_CLASS(CAMEL_OBJECT_GET_CLASS(store))->compare_folder_name);
si->storage = storage;
+ if (storage != NULL)
+ bonobo_object_ref((BonoboObject *)storage);
si->corba_storage = corba_storage;
si->store = store;
+ camel_object_ref((CamelObject *)store);
g_hash_table_insert(stores, store, si);
- si->async_event = mail_async_event_new();
+ e_dlist_init(&si->folderinfo_updates);
camel_object_hook_event((CamelObject *)store, "folder_created", store_folder_created, NULL);
camel_object_hook_event((CamelObject *)store, "folder_deleted", store_folder_deleted, NULL);
camel_object_hook_event((CamelObject *)store, "folder_subscribed", store_folder_subscribed, NULL);
camel_object_hook_event((CamelObject *)store, "folder_unsubscribed", store_folder_unsubscribed, NULL);
- camel_object_hook_event((CamelObject *)store, "finalize", store_finalised, NULL);
}
- UNLOCK(info_lock);
-
ud = g_malloc(sizeof(*ud));
- ud->si = si;
ud->done = done;
ud->data = data;
+ ud->id = mail_get_folderinfo(store, update_folders, ud);
+
+ e_dlist_addtail(&si->folderinfo_updates, (EDListNode *)ud);
- mail_get_folderinfo(store, update_folders, ud);
+ UNLOCK(info_lock);
}
struct _find_info {
diff --git a/mail/mail-mt.c b/mail/mail-mt.c
index 9c0c9bb18a..25ff6c632a 100644
--- a/mail/mail-mt.c
+++ b/mail/mail-mt.c
@@ -213,7 +213,7 @@ void mail_msg_free(void *msg)
g_free(m);
if (activity)
- mail_async_event_emit(mail_async_event, destroy_objects, NULL, activity, NULL);
+ mail_async_event_emit(mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)destroy_objects, NULL, activity, NULL);
}
/* hash table of ops->dialogue of active errors */
@@ -566,8 +566,12 @@ static pthread_mutex_t status_lock = PTHREAD_MUTEX_INITIALIZER;
struct _proxy_msg {
struct _mail_msg msg;
MailAsyncEvent *ea;
- CamelObjectEventHookFunc func;
- CamelObject *o;
+ mail_async_event_t type;
+
+ pthread_t thread;
+
+ MailAsyncFunc func;
+ void *o;
void *event_data;
void *data;
};
@@ -577,12 +581,22 @@ do_async_event(struct _mail_msg *mm)
{
struct _proxy_msg *m = (struct _proxy_msg *)mm;
+ m->thread = pthread_self();
m->func(m->o, m->event_data, m->data);
+ m->thread = ~0;
g_mutex_lock(m->ea->lock);
- m->ea->tasks = g_slist_remove(m->ea->tasks, (void *)mm->seq);
+ m->ea->tasks = g_slist_remove(m->ea->tasks, m);
g_mutex_unlock(m->ea->lock);
+}
+static int
+idle_async_event(void *mm)
+{
+ do_async_event(mm);
+ mail_msg_free(mm);
+
+ return FALSE;
}
struct _mail_msg_op async_event_op = {
@@ -602,41 +616,56 @@ MailAsyncEvent *mail_async_event_new(void)
return ea;
}
-int mail_async_event_emit(MailAsyncEvent *ea, CamelObjectEventHookFunc func, CamelObject *o, void *event_data, void *data)
+int mail_async_event_emit(MailAsyncEvent *ea, mail_async_event_t type, MailAsyncFunc func, void *o, void *event_data, void *data)
{
struct _proxy_msg *m;
int id;
int ismain = pthread_self() == mail_gui_thread;
- if (ismain) {
- func(o, event_data, data);
- /* id of -1 is 'always finished' */
- return -1;
- } else {
- /* we dont have a reply port for this, we dont care when/if it gets executed, just queue it */
- m = mail_msg_new(&async_event_op, NULL, sizeof(*m));
- m->func = func;
- m->o = o;
- m->event_data = event_data;
- m->data = data;
- m->ea = ea;
+ /* we dont have a reply port for this, we dont care when/if it gets executed, just queue it */
+ m = mail_msg_new(&async_event_op, NULL, sizeof(*m));
+ m->func = func;
+ m->o = o;
+ m->event_data = event_data;
+ m->data = data;
+ m->ea = ea;
+ m->type = type;
+ m->thread = ~0;
+
+ id = m->msg.seq;
+ g_mutex_lock(ea->lock);
+ ea->tasks = g_slist_prepend(ea->tasks, m);
+ g_mutex_unlock(ea->lock);
- id = m->msg.seq;
- g_mutex_lock(ea->lock);
- ea->tasks = g_slist_prepend(ea->tasks, (void *)id);
- g_mutex_unlock(ea->lock);
- e_msgport_put(mail_gui_port, (EMsg *)m);
- return id;
- }
+ /* We use an idle function instead of our own message port only because the
+ gui message ports's notification buffer might overflow and deadlock us */
+ if (type == MAIL_ASYNC_GUI) {
+ if (ismain)
+ g_idle_add(idle_async_event, m);
+ else
+ e_msgport_put(mail_gui_port, (EMsg *)m);
+ } else
+ e_thread_put(mail_thread_queued, (EMsg *)m);
+
+ return id;
}
-void mail_async_event_destroy(MailAsyncEvent *ea)
+int mail_async_event_destroy(MailAsyncEvent *ea)
{
int id;
+ pthread_t thread = pthread_self();
+ struct _proxy_msg *m;
g_mutex_lock(ea->lock);
while (ea->tasks) {
- id = (int)ea->tasks->data;
+ m = ea->tasks->data;
+ id = m->msg.seq;
+ if (m->thread == thread) {
+ g_warning("Destroying async event from inside an event, returning EDEADLK");
+ g_mutex_unlock(ea->lock);
+ errno = EDEADLK;
+ return -1;
+ }
g_mutex_unlock(ea->lock);
mail_msg_wait(id);
g_mutex_lock(ea->lock);
@@ -645,6 +674,8 @@ void mail_async_event_destroy(MailAsyncEvent *ea)
g_mutex_free(ea->lock);
g_free(ea);
+
+ return 0;
}
/* ********************************************************************** */
diff --git a/mail/mail-mt.h b/mail/mail-mt.h
index 96561d70ee..363b0f9f61 100644
--- a/mail/mail-mt.h
+++ b/mail/mail-mt.h
@@ -75,12 +75,19 @@ typedef struct _MailAsyncEvent {
GSList *tasks;
} MailAsyncEvent;
+typedef enum _mail_async_event_t {
+ MAIL_ASYNC_GUI,
+ MAIL_ASYNC_THREAD,
+} mail_async_event_t;
+
+typedef void (*MailAsyncFunc)(void *, void *, void *);
+
/* create a new async event handler */
MailAsyncEvent *mail_async_event_new(void);
/* forward a camel event (or other call) to the gui thread */
-int mail_async_event_emit(MailAsyncEvent *ea, CamelObjectEventHookFunc func, CamelObject *o, void *event_data, void *data);
+int mail_async_event_emit(MailAsyncEvent *ea, mail_async_event_t type, MailAsyncFunc func, void *, void *, void *);
/* wait for all outstanding async events to complete */
-void mail_async_event_destroy(MailAsyncEvent *ea);
+int mail_async_event_destroy(MailAsyncEvent *ea);
/* Call a function in the gui thread, wait for it to return, type is the marshaller to use */
typedef enum {
diff --git a/mail/mail-session.c b/mail/mail-session.c
index 9f557b05ea..e5ed58c593 100644
--- a/mail/mail-session.c
+++ b/mail/mail-session.c
@@ -741,7 +741,7 @@ register_timeout (CamelSession *session, guint32 interval, CamelTimeoutCallback
MAIL_SESSION_UNLOCK(session, lock);
camel_object_ref((CamelObject *)ms);
- mail_async_event_emit(ms->async, (CamelObjectEventHookFunc)main_register_timeout, (CamelObject *)session, (void *)ret, NULL);
+ mail_async_event_emit(ms->async, MAIL_ASYNC_GUI, (MailAsyncFunc)main_register_timeout, (CamelObject *)session, (void *)ret, NULL);
return ret;
}
@@ -783,7 +783,8 @@ remove_timeout (CamelSession *session, guint handle)
if (remove) {
camel_object_ref((CamelObject *)ms);
- mail_async_event_emit(ms->async, (CamelObjectEventHookFunc)main_remove_timeout, (CamelObject *)session, (void *)handle, NULL);
+ mail_async_event_emit(ms->async, MAIL_ASYNC_GUI,
+ (MailAsyncFunc)main_remove_timeout, (CamelObject *)session, (void *)handle, NULL);
} else
g_warning("Removing a timeout i dont know about (or twice): %d", handle);
diff --git a/mail/message-list.c b/mail/message-list.c
index 9a7ab43bbd..512102bb07 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -1881,7 +1881,7 @@ folder_changed (CamelObject *o, gpointer event_data, gpointer user_data)
changes = NULL;
}
- mail_async_event_emit(ml->async_event, main_folder_changed, o, changes, user_data);
+ mail_async_event_emit(ml->async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)main_folder_changed, o, changes, user_data);
}
static void
@@ -1893,7 +1893,7 @@ message_changed (CamelObject *o, gpointer event_data, gpointer user_data)
changes = camel_folder_change_info_new();
camel_folder_change_info_change_uid(changes, (char *)event_data);
- mail_async_event_emit(ml->async_event, main_folder_changed, o, changes, user_data);
+ mail_async_event_emit(ml->async_event, MAIL_ASYNC_GUI, (MailAsyncFunc)main_folder_changed, o, changes, user_data);
}
void