diff options
Diffstat (limited to 'mail')
-rw-r--r-- | mail/ChangeLog | 87 | ||||
-rw-r--r-- | mail/component-factory.c | 25 | ||||
-rw-r--r-- | mail/folder-browser-ui.c | 25 | ||||
-rw-r--r-- | mail/folder-browser.c | 2 | ||||
-rw-r--r-- | mail/mail-folder-cache.c | 428 | ||||
-rw-r--r-- | mail/mail-mt.c | 83 | ||||
-rw-r--r-- | mail/mail-mt.h | 11 | ||||
-rw-r--r-- | mail/mail-session.c | 5 | ||||
-rw-r--r-- | mail/message-list.c | 4 |
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 |