diff options
-rw-r--r-- | mail/ChangeLog | 23 | ||||
-rw-r--r-- | mail/em-folder-browser.c | 2 | ||||
-rw-r--r-- | mail/em-utils.c | 130 | ||||
-rw-r--r-- | mail/mail-mt.c | 54 | ||||
-rw-r--r-- | mail/mail-mt.h | 5 |
5 files changed, 166 insertions, 48 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index 5baa96fed8..445db01311 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,26 @@ +2004-06-16 Not Zed <NotZed@Ximian.com> + + ** See #56479. + + * em-utils.c (em_utils_in_addressbook): use the main thread to + setup the addressbook list. + (em_utils_in_addressbook): only check against the "completion" + sources, not all of them. + +2004-06-15 Not Zed <NotZed@Ximian.com> + + * em-folder-browser.c (emfb_mail_stop): call mail_cancel_all to + implement the stop button. + + * em-utils.c (emu_addr_sources_refresh): don't unref the group + list, otherwise the sources become broken now (?). + (em_utils_in_addressbook): add some locking. add cancellation. + this is almost certainly going to cause issues. + + * mail-mt.c (mail_cancel_hook_add, mail_cancel_hook_remove) + (mail_cancel_all): new functions to implement a global mailer stop + button. + 2004-06-15 Jeffrey Stedfast <fejj@ximian.com> * mail-ops.c (save_part_save): This code no longer needs to do diff --git a/mail/em-folder-browser.c b/mail/em-folder-browser.c index e09329f733..cb4d25b565 100644 --- a/mail/em-folder-browser.c +++ b/mail/em-folder-browser.c @@ -632,7 +632,7 @@ emfb_mail_compose(BonoboUIComponent *uid, void *data, const char *path) static void emfb_mail_stop(BonoboUIComponent *uid, void *data, const char *path) { - camel_operation_cancel(NULL); + mail_cancel_all(); } static void diff --git a/mail/em-utils.c b/mail/em-utils.c index b0bed74546..82a5d73f4f 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -1663,42 +1663,41 @@ struct _addr_node { #define EMU_ADDR_CACHE_TIME (60*30) /* in seconds */ -static GSList *emu_addr_sources; +static pthread_mutex_t emu_addr_lock = PTHREAD_MUTEX_INITIALIZER; +static ESourceList *emu_addr_list; static GHashTable *emu_addr_cache; -static void -emu_addr_sources_refresh(void) +/* runs sync, in main thread */ +static void * +emu_addr_setup(void *dummy) { GError *err = NULL; - ESourceList *list; - GSList *g, *s, *groups, *sources; - g_slist_foreach(emu_addr_sources, (GFunc)g_object_unref, NULL); - g_slist_free(emu_addr_sources); - emu_addr_sources = NULL; + emu_addr_cache = g_hash_table_new(g_str_hash, g_str_equal); - if (!e_book_get_addressbooks(&list, &err)) { + if (!e_book_get_addressbooks(&emu_addr_list, &err)) g_error_free(err); - return; - } - groups = e_source_list_peek_groups(list); - for (g=groups;g;g=g_slist_next(g)) { - sources = e_source_group_peek_sources((ESourceGroup *)g->data); - for (s=sources;s;s=g_slist_next(s)) { - emu_addr_sources = g_slist_prepend(emu_addr_sources, g_object_ref(s->data)); - } - } + return NULL; +} - g_object_unref(list); +static void +emu_addr_cancel_book(void *data) +{ + EBook *book = data; + GError *err = NULL; + + /* we dunna care if this fails, its just the best we can try */ + e_book_cancel(book, &err); + g_clear_error(&err); } gboolean em_utils_in_addressbook(CamelInternetAddress *iaddr) { GError *err = NULL; - GSList *s; - int found = FALSE; + GSList *s, *g, *addr_sources = NULL; + int stop = FALSE, found = FALSE; EBookQuery *query; const char *addr; struct _addr_node *node; @@ -1708,69 +1707,106 @@ em_utils_in_addressbook(CamelInternetAddress *iaddr) if (!camel_internet_address_get(iaddr, 0, NULL, &addr)) return FALSE; + pthread_mutex_lock(&emu_addr_lock); + if (emu_addr_cache == NULL) { - emu_addr_cache = g_hash_table_new(g_str_hash, g_str_equal); - emu_addr_sources_refresh(); + mail_call_main(MAIL_CALL_p_p, emu_addr_setup, NULL); + } + + if (emu_addr_list == NULL) { + pthread_mutex_unlock(&emu_addr_lock); + return FALSE; } now = time(0); - printf("Checking '%s' is in addressbook", addr); + d(printf("Checking '%s' is in addressbook", addr)); node = g_hash_table_lookup(emu_addr_cache, addr); if (node) { - printf(" -> cached, found %s\n", node->found?"yes":"no"); - if (node->stamp + EMU_ADDR_CACHE_TIME > now) - return node->found; - printf(" but expired!\n"); + d(printf(" -> cached, found %s\n", node->found?"yes":"no")); + if (node->stamp + EMU_ADDR_CACHE_TIME > now) { + found = node->found; + pthread_mutex_unlock(&emu_addr_lock); + return found; + } + d(printf(" but expired!\n")); } else { - printf(" -> not found in cache\n"); + d(printf(" -> not found in cache\n")); node = g_malloc0(sizeof(*node)); node->addr = g_strdup(addr); + g_hash_table_insert(emu_addr_cache, node->addr, node); } query = e_book_query_field_test(E_CONTACT_EMAIL, E_BOOK_QUERY_IS, addr); - for (s = emu_addr_sources;!found && s;s=g_slist_next(s)) { + /* FIXME: this aint threadsafe by any measure, but what can you do eh??? */ + + for (g = e_source_list_peek_groups(emu_addr_list);g;g=g_slist_next(g)) { + for (s = e_source_group_peek_sources((ESourceGroup *)g->data);s;s=g_slist_next(s)) { + ESource *src = s->data; + const char *completion = e_source_get_property (src, "completion"); + + if (completion && !g_ascii_strcasecmp (completion, "true")) { + addr_sources = g_slist_prepend(addr_sources, src); + g_object_ref(src); + } + } + } + + for (s = addr_sources;!stop && !found && s;s=g_slist_next(s)) { ESource *source = s->data; GList *contacts; EBook *book; + void *hook; - printf(" checking '%s'\n", e_source_get_uri(source)); + d(printf(" checking '%s'\n", e_source_get_uri(source))); + /* could this take a while? no way to cancel it? */ book = e_book_new(source, &err); - if (!book - || !e_book_open(book, TRUE, &err)) { - printf("couldn't load source?\n"); + if (book == NULL) { + g_warning("Unable to create addressbook: %s", err->message); g_clear_error(&err); - g_object_unref(book); continue; } - if (!e_book_get_contacts(book, query, &contacts, &err)) { - printf("Can't get contacts?\n"); - g_clear_error(&err); + hook = mail_cancel_hook_add(emu_addr_cancel_book, book); + + /* ignore errors, but cancellation errors we don't try to go further either */ + if (!e_book_open(book, TRUE, &err) + || !e_book_get_contacts(book, query, &contacts, &err)) { + stop = err->domain == E_BOOK_ERROR && err->code == E_BOOK_ERROR_CANCELLED; + mail_cancel_hook_remove(hook); g_object_unref(book); + g_warning("Can't get contacts: %s", err->message); + g_clear_error(&err); continue; } - found = contacts != NULL; + mail_cancel_hook_remove(hook); - printf(" %s\n", found?"found":"not found"); + if (contacts != NULL) { + found = TRUE; + g_list_foreach(contacts, (GFunc)g_object_unref, NULL); + g_list_free(contacts); + } - g_list_foreach(contacts, (GFunc)g_object_unref, NULL); - g_list_free(contacts); + d(printf(" %s\n", stop?"found":"not found")); g_object_unref(book); } - e_book_query_unref(query); + g_slist_free(addr_sources); - node->found = found; - node->stamp = now; + if (!stop) { + node->found = found; + node->stamp = now; + } + + e_book_query_unref(query); - g_hash_table_insert(emu_addr_cache, node->addr, node); + pthread_mutex_unlock(&emu_addr_lock); return found; } @@ -1779,7 +1815,7 @@ em_utils_in_addressbook(CamelInternetAddress *iaddr) * em_utils_snoop_type: * @part: * - * Rries to snoop the mime type of a part. + * Tries to snoop the mime type of a part. * * Return value: NULL if unknown (more likely application/octet-stream). **/ diff --git a/mail/mail-mt.c b/mail/mail-mt.c index 1581d283bb..457fd4c43f 100644 --- a/mail/mail-mt.c +++ b/mail/mail-mt.c @@ -352,6 +352,60 @@ void mail_msg_wait_all(void) } } +/* **************************************** */ +struct _cancel_hook_data { + struct _cancel_hook_data *next; + struct _cancel_hook_data *prev; + + GDestroyNotify func; + void *data; +}; + +static EDList cancel_hook_list = E_DLIST_INITIALISER(cancel_hook_list); + +void *mail_cancel_hook_add(GDestroyNotify func, void *data) +{ + struct _cancel_hook_data *d; + + d = g_malloc0(sizeof(*d)); + d->func = func; + d->data = data; + + MAIL_MT_LOCK(mail_msg_lock); + e_dlist_addtail(&cancel_hook_list, (EDListNode *)d); + MAIL_MT_UNLOCK(mail_msg_lock); + + return (void *)d; +} + +void mail_cancel_hook_remove(void *handle) +{ + struct _cancel_hook_data *d = handle; + + MAIL_MT_LOCK(mail_msg_lock); + e_dlist_remove((EDListNode *)d); + MAIL_MT_UNLOCK(mail_msg_lock); + g_free(d); +} + +void mail_cancel_all(void) +{ + struct _cancel_hook_data *d, *n; + + camel_operation_cancel(NULL); + + /* I can ssee a deadlock coming on ... */ + MAIL_MT_LOCK(mail_msg_lock); + d = (struct _cancel_hook_data *)cancel_hook_list.head; + n = d->next; + while (n) { + d->func(d->data); + d = n; + n = n->next; + } + MAIL_MT_UNLOCK(mail_msg_lock); +} + EMsgPort *mail_gui_port; static GIOChannel *mail_gui_channel; static guint mail_gui_watch; diff --git a/mail/mail-mt.h b/mail/mail-mt.h index b6d402199f..23baf60a56 100644 --- a/mail/mail-mt.h +++ b/mail/mail-mt.h @@ -60,6 +60,11 @@ void mail_msg_wait(unsigned int msgid); void mail_msg_wait_all(void); int mail_msg_active(unsigned int msgid); +/* To implement the stop button */ +void *mail_cancel_hook_add(GDestroyNotify func, void *data); +void mail_cancel_hook_remove(void *handle); +void mail_cancel_all(void); + /* request a string/password */ char *mail_get_password (CamelService *service, const char *prompt, gboolean secret, gboolean *cache); |