[evolution/mail-mt-cleanup: 4/7] Remove use of em_utils_show_error_silent() from MailSession



commit 277247d0512e5ee0034ba34e79eadc0aacd4ef38
Author: Jonathon Jongsma <jonathon quotidian org>
Date:   Wed Jan 6 17:04:19 2010 -0600

    Remove use of em_utils_show_error_silent() from MailSession
    
    em_utils_show_error_silent() depends on EShell, which means that we can't use it
    in the backend.  So I needed to refactor the alert_user vfunc of MailSession to
    do things a bit differently.  The user-visible behavior should be the same as
    before, since we now use the new "error-response" signal of EMailMsg to pass the
    error to the shell to be displayed quietly.  Detailed summary of changes:
    
     - None of the file-scope static variables were protected from being accessed by
       multiple threads (even though the code was clearly written under the
       assumption that it was going to be called from multiple threads), so I added
       locking on all shared data.
     - previously, there were seemingly about 3 or 4 different code paths for a user
       message, depending on whether the callback was called from a main thread,
       whether the user message required a response, etc.  After factoring, I
       reduced it to two code paths (depending only on whether a response is
       required), which makes things significantly easier to understand, I think.
       Essentially, we push the user message to the main loop via the task manager
       regardless of whether it's currently running in the mainloop or not.  In
       theory, this adds some latency, but I really don't think it will make any
       practical difference to the user.
     - em-utils.[ch] was split in two.  The utilities that can be used by the
       backend were moved into mail-utils.h for now.  This way, we don't have to
       pull in extra dependencies (EShell, etc) via including em-utils.h.
       em-utils.h includes mail-utils.h, so users of em-utils should not be
       affected.

 mail/Makefile.am         |    2 +
 mail/em-utils.c          | 1182 -------------------------------------------
 mail/em-utils.h          |   39 +--
 mail/mail-folder-cache.c |    2 +-
 mail/mail-ops.c          |    3 +-
 mail/mail-session.c      |  208 ++++-----
 mail/mail-tools.c        |    2 +-
 mail/mail-utils.c        | 1258 ++++++++++++++++++++++++++++++++++++++++++++++
 mail/mail-utils.h        |   75 +++
 9 files changed, 1435 insertions(+), 1336 deletions(-)
---
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 032983c..5503de8 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -93,6 +93,7 @@ mailinclude_HEADERS =					\
 	mail-session.h					\
 	mail-tools.h					\
 	mail-vfolder.h					\
+	mail-utils.h					\
 	message-list.h
 
 libevolution_mail_la_SOURCES =				\
@@ -154,6 +155,7 @@ libevolution_mail_la_SOURCES =				\
 	mail-session.c					\
 	mail-tools.c					\
 	mail-vfolder.c					\
+	mail-utils.c					\
 	message-list.c
 
 if ENABLE_SMIME
diff --git a/mail/em-utils.c b/mail/em-utils.c
index 94fee19..a2dfe5b 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -57,7 +57,6 @@
 
 #include <libedataserver/e-data-server-util.h>
 #include <libedataserver/e-flag.h>
-#include <libedataserver/e-proxy.h>
 #include "e-util/e-util.h"
 #include "e-util/e-util-private.h"
 #include "e-util/e-binding.h"
@@ -162,75 +161,6 @@ em_utils_prompt_user(GtkWindow *parent, const gchar *promptkey, const gchar *tag
 	return button == GTK_RESPONSE_YES;
 }
 
-/**
- * em_utils_uids_copy:
- * @uids: array of uids
- *
- * Duplicates the array of uids held by @uids into a new
- * GPtrArray. Use em_utils_uids_free() to free the resultant uid
- * array.
- *
- * Returns a duplicate copy of @uids.
- **/
-GPtrArray *
-em_utils_uids_copy (GPtrArray *uids)
-{
-	GPtrArray *copy;
-	gint i;
-
-	copy = g_ptr_array_new ();
-	g_ptr_array_set_size (copy, uids->len);
-
-	for (i = 0; i < uids->len; i++)
-		copy->pdata[i] = g_strdup (uids->pdata[i]);
-
-	return copy;
-}
-
-/**
- * em_utils_uids_free:
- * @uids: array of uids
- *
- * Frees the array of uids pointed to by @uids back to the system.
- **/
-void
-em_utils_uids_free (GPtrArray *uids)
-{
-	gint i;
-
-	for (i = 0; i < uids->len; i++)
-		g_free (uids->pdata[i]);
-
-	g_ptr_array_free (uids, TRUE);
-}
-
-/**
- * em_utils_check_user_can_send_mail:
- *
- * Returns %TRUE if the user has an account configured (to send mail)
- * or %FALSE otherwise.
- **/
-gboolean
-em_utils_check_user_can_send_mail (void)
-{
-	EAccountList *account_list;
-	EAccount *account;
-
-	account_list = e_get_account_list ();
-
-	if (e_list_length ((EList *) account_list) == 0)
-		return FALSE;
-
-	if (!(account = e_get_default_account ()))
-		return FALSE;
-
-	/* Check for a transport */
-	if (!account->transport->url)
-		return FALSE;
-
-	return TRUE;
-}
-
 /* Editing Filters/Search Folders... */
 
 static GtkWidget *filter_editor = NULL;
@@ -314,39 +244,6 @@ em_utils_edit_filters (GtkWidget *parent)
 	gtk_widget_show (GTK_WIDGET (filter_editor));
 }
 
-/*
- * Picked this from e-d-s/libedataserver/e-data.
- * But it allows more characters to occur in filenames, especially when saving attachment.
- */
-void
-em_filename_make_safe (gchar *string)
-{
-	gchar *p, *ts;
-	gunichar c;
-#ifdef G_OS_WIN32
-	const gchar *unsafe_chars = "/\":*?<>|\\#";
-#else
-	const gchar *unsafe_chars = "/#";
-#endif
-
-	g_return_if_fail (string != NULL);
-	p = string;
-
-	while (p && *p) {
-		c = g_utf8_get_char (p);
-		ts = p;
-		p = g_utf8_next_char (p);
-		/* I wonder what this code is supposed to actually
-		 * achieve, and whether it does that as currently
-		 * written?
-		 */
-		if (!g_unichar_isprint(c) || ( c < 0xff && strchr (unsafe_chars, c&0xff ))) {
-			while (ts<p)
-				*ts++ = '_';
-		}
-	}
-}
-
 /* ********************************************************************** */
 /* Flag-for-Followup... */
 
@@ -959,231 +856,6 @@ em_utils_temp_save_part(GtkWidget *parent, CamelMimePart *part, gboolean mode)
 	return path;
 }
 
-/** em_utils_folder_is_templates:
- * @folder: folder
- * @uri: uri for this folder, if known
- *
- * Decides if @folder is a Templates folder.
- *
- * Returns %TRUE if this is a Drafts folder or %FALSE otherwise.
- **/
-
-gboolean
-em_utils_folder_is_templates (CamelFolder *folder, const gchar *uri)
-{
-	CamelFolder *local_templates_folder;
-	EAccountList *accounts;
-	EAccount *account;
-	EIterator *iter;
-	gint is = FALSE;
-	gchar *templates_uri;
-
-	local_templates_folder =
-		e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES);
-
-	if (folder == local_templates_folder)
-		return TRUE;
-
-	if (folder == NULL || uri == NULL)
-		return FALSE;
-
-	accounts = e_get_account_list ();
-	iter = e_list_get_iterator ((EList *)accounts);
-	while (e_iterator_is_valid (iter)) {
-		account = (EAccount *)e_iterator_get (iter);
-
-		if (account->templates_folder_uri) {
-			templates_uri = em_uri_to_camel (account->templates_folder_uri);
-			if (camel_store_folder_uri_equal (folder->parent_store, templates_uri, uri)) {
-				g_free (templates_uri);
-				is = TRUE;
-				break;
-			}
-			g_free (templates_uri);
-		}
-
-		e_iterator_next (iter);
-	}
-
-	g_object_unref (iter);
-
-	return is;
-}
-
-/**
- * em_utils_folder_is_drafts:
- * @folder: folder
- * @uri: uri for this folder, if known
- *
- * Decides if @folder is a Drafts folder.
- *
- * Returns %TRUE if this is a Drafts folder or %FALSE otherwise.
- **/
-gboolean
-em_utils_folder_is_drafts(CamelFolder *folder, const gchar *uri)
-{
-	CamelFolder *local_drafts_folder;
-	EAccountList *accounts;
-	EAccount *account;
-	EIterator *iter;
-	gint is = FALSE;
-	gchar *drafts_uri;
-
-	local_drafts_folder =
-		e_mail_local_get_folder (E_MAIL_FOLDER_DRAFTS);
-
-	if (folder == local_drafts_folder)
-		return TRUE;
-
-	if (folder == NULL || uri == NULL)
-		return FALSE;
-
-	accounts = e_get_account_list ();
-	iter = e_list_get_iterator((EList *)accounts);
-	while (e_iterator_is_valid(iter)) {
-		account = (EAccount *)e_iterator_get(iter);
-
-		if (account->drafts_folder_uri) {
-			drafts_uri = em_uri_to_camel (account->drafts_folder_uri);
-			if (camel_store_folder_uri_equal (folder->parent_store, drafts_uri, uri)) {
-				g_free (drafts_uri);
-				is = TRUE;
-				break;
-			}
-			g_free (drafts_uri);
-		}
-
-		e_iterator_next(iter);
-	}
-
-	g_object_unref(iter);
-
-	return is;
-}
-
-/**
- * em_utils_folder_is_sent:
- * @folder: folder
- * @uri: uri for this folder, if known
- *
- * Decides if @folder is a Sent folder
- *
- * Returns %TRUE if this is a Sent folder or %FALSE otherwise.
- **/
-gboolean
-em_utils_folder_is_sent(CamelFolder *folder, const gchar *uri)
-{
-	CamelFolder *local_sent_folder;
-	EAccountList *accounts;
-	EAccount *account;
-	EIterator *iter;
-	gint is = FALSE;
-	gchar *sent_uri;
-
-	local_sent_folder = e_mail_local_get_folder (E_MAIL_FOLDER_SENT);
-
-	if (folder == local_sent_folder)
-		return TRUE;
-
-	if (folder == NULL || uri == NULL)
-		return FALSE;
-
-	accounts = e_get_account_list ();
-	iter = e_list_get_iterator((EList *)accounts);
-	while (e_iterator_is_valid(iter)) {
-		account = (EAccount *)e_iterator_get(iter);
-
-		if (account->sent_folder_uri) {
-			sent_uri = em_uri_to_camel (account->sent_folder_uri);
-			if (camel_store_folder_uri_equal (folder->parent_store, sent_uri, uri)) {
-				g_free (sent_uri);
-				is = TRUE;
-				break;
-			}
-			g_free (sent_uri);
-		}
-
-		e_iterator_next(iter);
-	}
-
-	g_object_unref(iter);
-
-	return is;
-}
-
-/**
- * em_utils_folder_is_outbox:
- * @folder: folder
- * @uri: uri for this folder, if known
- *
- * Decides if @folder is an Outbox folder
- *
- * Returns %TRUE if this is an Outbox folder or %FALSE otherwise.
- **/
-gboolean
-em_utils_folder_is_outbox(CamelFolder *folder, const gchar *uri)
-{
-	CamelFolder *local_outbox_folder;
-	const gchar *local_outbox_folder_uri;
-
-	local_outbox_folder =
-		e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
-	local_outbox_folder_uri =
-		e_mail_local_get_folder_uri (E_MAIL_FOLDER_OUTBOX);
-
-	if (folder == local_outbox_folder)
-		return TRUE;
-
-	if (uri == NULL)
-		return FALSE;
-
-	return camel_store_folder_uri_equal (
-		local_outbox_folder->parent_store,
-		local_outbox_folder_uri, uri);
-}
-
-/* ********************************************************************** */
-static EProxy *emu_proxy = NULL;
-static GStaticMutex emu_proxy_lock = G_STATIC_MUTEX_INIT;
-
-static gpointer
-emu_proxy_setup (gpointer data)
-{
-	if (!emu_proxy) {
-		emu_proxy = e_proxy_new ();
-		e_proxy_setup_proxy (emu_proxy);
-		/* not necessary to listen for changes here */
-	}
-
-	return NULL;
-}
-
-/**
- * em_utils_get_proxy_uri:
- *
- * Get the system proxy uri for 'pUri'.
- *
- * Return value: Must be freed when finished with.
- **/
-gchar *
-em_utils_get_proxy_uri (const gchar *pUri)
-{
-	gchar *uri = NULL;
-
-	g_static_mutex_lock (&emu_proxy_lock);
-
-	if (!emu_proxy) {
-		mail_call_main (MAIL_CALL_p_p, (MailMainFunc)emu_proxy_setup, NULL);
-	}
-
-	if (e_proxy_require_proxy_for_uri (emu_proxy, pUri))
-		uri = soup_uri_to_string (e_proxy_peek_uri_for (emu_proxy, pUri), FALSE);
-
-	g_static_mutex_unlock (&emu_proxy_lock);
-
-	return uri;
-}
-
 /**
  * em_utils_message_to_html:
  * @message:
@@ -1317,706 +989,8 @@ em_utils_empty_trash (GtkWidget *parent)
 	mail_empty_trash (NULL, NULL, NULL);
 }
 
-gchar *
-em_utils_folder_name_from_uri (const gchar *uri)
-{
-	CamelURL *url;
-	gchar *folder_name = NULL;
-
-	if (uri == NULL || (url = camel_url_new (uri, NULL)) == NULL)
-		return NULL;
-
-	if (url->fragment)
-		folder_name = url->fragment;
-	else if (url->path)
-		folder_name = url->path + 1;
-
-	if (folder_name == NULL) {
-		camel_url_free (url);
-		return NULL;
-	}
-
-	folder_name = g_strdup (folder_name);
-	camel_url_free (url);
-
-	return folder_name;
-}
-
-/* email: uri's are based on the account, with special cases for local
- * stores, vfolder and local mail.
- * e.g.
- *  imap account imap://user host/ -> email://accountid accountid host/
- *  vfolder      vfolder:/storage/path#folder -> email://vfolder local/folder
- *  local        local:/storage/path#folder   -> email://local local/folder
- */
-
-gchar *em_uri_from_camel(const gchar *curi)
-{
-	CamelURL *curl;
-	EAccount *account;
-	const gchar *uid, *path;
-	gchar *euri, *tmp;
-	CamelProvider *provider;
-	CamelException ex;
-
-	/* Easiest solution to code that shouldnt be calling us */
-	if (!strncmp(curi, "email:", 6))
-		return g_strdup(curi);
-
-	camel_exception_init(&ex);
-	provider = camel_provider_get(curi, &ex);
-	if (provider == NULL) {
-		camel_exception_clear(&ex);
-		d(printf("em uri from camel failed '%s'\n", curi));
-		return g_strdup(curi);
-	}
-
-	curl = camel_url_new(curi, &ex);
-	camel_exception_clear(&ex);
-	if (curl == NULL)
-		return g_strdup(curi);
-
-	if (strcmp(curl->protocol, "vfolder") == 0)
-		uid = "vfolder local";
-	else if ((account = mail_config_get_account_by_source_url(curi)) == NULL)
-		uid = "local local";
-	else
-		uid = account->uid;
-	path = (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)?curl->fragment:curl->path;
-	if (path) {
-		if (path[0] == '/')
-			path++;
-
-		tmp = camel_url_encode(path, ";?");
-		euri = g_strdup_printf("email://%s/%s", uid, tmp);
-		g_free(tmp);
-	} else {
-		euri = g_strdup_printf("email://%s/", uid);
-	}
-
-	d(printf("em uri from camel '%s' -> '%s'\n", curi, euri));
-
-	camel_url_free(curl);
-
-	return euri;
-}
-
-gchar *em_uri_to_camel(const gchar *euri)
-{
-	EAccountList *accounts;
-	const EAccount *account;
-	EAccountService *service;
-	CamelProvider *provider;
-	CamelURL *eurl, *curl;
-	gchar *uid, *curi;
-
-	if (strncmp(euri, "email:", 6) != 0) {
-		d(printf("em uri to camel not euri '%s'\n", euri));
-		return g_strdup(euri);
-	}
-
-	eurl = camel_url_new(euri, NULL);
-	if (eurl == NULL)
-		return g_strdup(euri);
-
-	g_return_val_if_fail (eurl->host != NULL, g_strdup(euri));
-
-	if (eurl->user != NULL) {
-		/* Sigh, shoul'dve used mbox local for mailboxes, not local local */
-		if (strcmp(eurl->host, "local") == 0
-		    && (strcmp(eurl->user, "local") == 0 || strcmp(eurl->user, "vfolder") == 0)) {
-			gchar *base;
-
-			if (strcmp(eurl->user, "vfolder") == 0)
-				curl = camel_url_new("vfolder:", NULL);
-			else
-				curl = camel_url_new("mbox:", NULL);
-
-			base = g_strdup_printf("%s/.evolution/mail/%s", g_get_home_dir(), eurl->user);
-#ifdef G_OS_WIN32
-			/* Turn backslashes into slashes to avoid URI encoding */
-			{
-				gchar *p = base;
-				while ((p = strchr (p, '\\')))
-					*p++ = '/';
-			}
-#endif
-			camel_url_set_path(curl, base);
-			g_free(base);
-			camel_url_set_fragment(curl, eurl->path[0]=='/'?eurl->path+1:eurl->path);
-			curi = camel_url_to_string(curl, 0);
-			camel_url_free(curl);
-			camel_url_free(eurl);
-
-			d(printf("em uri to camel local '%s' -> '%s'\n", euri, curi));
-			return curi;
-		}
-
-		uid = g_strdup_printf("%s %s", eurl->user, eurl->host);
-	} else {
-		uid = g_strdup(eurl->host);
-	}
-
-	accounts = e_get_account_list ();
-	account = e_account_list_find(accounts, E_ACCOUNT_FIND_UID, uid);
-	g_free(uid);
-
-	if (account == NULL) {
-		camel_url_free(eurl);
-		d(printf("em uri to camel no account '%s' -> '%s'\n", euri, euri));
-		return g_strdup(euri);
-	}
-
-	service = account->source;
-	if (!(provider = camel_provider_get (service->url, NULL)))
-		return g_strdup (euri);
-
-	curl = camel_url_new(service->url, NULL);
-	if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
-		camel_url_set_fragment(curl, eurl->path[0]=='/'?eurl->path+1:eurl->path);
-	else
-		camel_url_set_path(curl, eurl->path);
-
-	curi = camel_url_to_string(curl, 0);
-
-	camel_url_free(eurl);
-	camel_url_free(curl);
-
-	d(printf("em uri to camel '%s' -> '%s'\n", euri, curi));
-
-	return curi;
-}
-
 /* ********************************************************************** */
 
-/* runs sync, in main thread */
-static gpointer
-emu_addr_setup (gpointer user_data)
-{
-	GError *err = NULL;
-	ESourceList **psource_list = user_data;
-
-	if (!e_book_get_addressbooks (psource_list, &err))
-		g_error_free (err);
-
-	return NULL;
-}
-
-static void
-emu_addr_cancel_book (gpointer 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);
-}
-
-static void
-emu_addr_cancel_stop (gpointer data)
-{
-	gboolean *stop = data;
-
-	g_return_if_fail (stop != NULL);
-
-	*stop = TRUE;
-}
-
-struct TryOpenEBookStruct {
-	GError **error;
-	EFlag *flag;
-	gboolean result;
-};
-
-static void
-try_open_e_book_cb (EBook *book, EBookStatus status, gpointer closure)
-{
-	struct TryOpenEBookStruct *data = (struct TryOpenEBookStruct *)closure;
-
-	if (!data)
-		return;
-
-	data->result = status == E_BOOK_ERROR_OK;
-
-	if (!data->result) {
-		g_clear_error (data->error);
-		g_set_error (data->error, E_BOOK_ERROR, status, "EBookStatus returned %d", status);
-	}
-
-	e_flag_set (data->flag);
-}
-
-/**
- * try_open_e_book:
- * Tries to open address book asynchronously, but acts as synchronous.
- * The advantage is it checks periodically whether the camel_operation
- * has been canceled or not, and if so, then stops immediately, with
- * result FALSE. Otherwise returns same as e_book_open
- **/
-static gboolean
-try_open_e_book (EBook *book, gboolean only_if_exists, GError **error)
-{
-	struct TryOpenEBookStruct data;
-	gboolean canceled = FALSE;
-	EFlag *flag = e_flag_new ();
-
-	data.error = error;
-	data.flag = flag;
-	data.result = FALSE;
-
-	if (e_book_async_open (book, only_if_exists, try_open_e_book_cb, &data) != FALSE) {
-		e_flag_free (flag);
-		g_clear_error (error);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR, "Failed to call e_book_async_open.");
-		return FALSE;
-	}
-
-	while (canceled = camel_operation_cancel_check (NULL), !canceled && !e_flag_is_set (flag)) {
-		GTimeVal wait;
-
-		g_get_current_time (&wait);
-		g_time_val_add (&wait, 250000); /* waits 250ms */
-
-		e_flag_timed_wait (flag, &wait);
-	}
-
-	if (canceled) {
-		g_clear_error (error);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED, "Operation has been canceled.");
-		/* if the operation is cancelled sucessfully set the flag else wait. file, groupwise,.. backend's operations
-		   are not cancellable */
-		if (e_book_cancel_async_op (book, NULL))
-			e_flag_set (flag);
-	}
-
-	e_flag_wait (flag);
-	e_flag_free (flag);
-
-	return data.result && (!error || !*error);
-}
-
-#define NOT_FOUND_BOOK (GINT_TO_POINTER (1))
-
-G_LOCK_DEFINE_STATIC (contact_cache);
-static GHashTable *contact_cache = NULL; /* key is lowercased contact email; value is EBook pointer (just for comparison) where it comes from */
-static GHashTable *emu_books_hash = NULL; /* key is source ID; value is pointer to EBook */
-static GHashTable *emu_broken_books_hash = NULL; /* key is source ID; value is same pointer as key; this is hash of broken books, which failed to open for some reason */
-static ESourceList *emu_books_source_list = NULL;
-
-static gboolean
-search_address_in_addressbooks (const gchar *address, gboolean local_only, gboolean (*check_contact) (EContact *contact, gpointer user_data), gpointer user_data)
-{
-	gboolean found = FALSE, stop = FALSE, found_any = FALSE;
-	gchar *lowercase_addr;
-	gpointer ptr;
-	EBookQuery *query;
-	GSList *s, *g, *addr_sources = NULL;
-
-	if (!address || !*address)
-		return FALSE;
-
-	G_LOCK (contact_cache);
-
-	if (!emu_books_source_list) {
-		mail_call_main (MAIL_CALL_p_p, (MailMainFunc)emu_addr_setup, &emu_books_source_list);
-		emu_books_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-		emu_broken_books_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-		contact_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-	}
-
-	if (!emu_books_source_list) {
-		G_UNLOCK (contact_cache);
-		return FALSE;
-	}
-
-	lowercase_addr = g_utf8_strdown (address, -1);
-	ptr = g_hash_table_lookup (contact_cache, lowercase_addr);
-	if (ptr != NULL && (check_contact == NULL || ptr == NOT_FOUND_BOOK)) {
-		g_free (lowercase_addr);
-		G_UNLOCK (contact_cache);
-		return ptr != NOT_FOUND_BOOK;
-	}
-
-	query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_IS, address);
-
-	for (g = e_source_list_peek_groups (emu_books_source_list); g; g = g_slist_next (g)) {
-		ESourceGroup *group = g->data;
-
-		if (!group)
-			continue;
-
-		if (local_only && !(e_source_group_peek_base_uri (group) && g_str_has_prefix (e_source_group_peek_base_uri (group), "file://")))
-			continue;
-
-		for (s = e_source_group_peek_sources (group); s; s = g_slist_next (s)) {
-			ESource *source = s->data;
-			const gchar *completion = e_source_get_property (source, "completion");
-
-			if (completion && g_ascii_strcasecmp (completion, "true") == 0) {
-				addr_sources = g_slist_prepend (addr_sources, g_object_ref (source));
-			}
-		}
-	}
-
-	for (s = addr_sources; !stop && !found && s; s = g_slist_next (s)) {
-		ESource *source = s->data;
-		GList *contacts;
-		EBook *book = NULL;
-		GHook *hook_book, *hook_stop;
-		gboolean cached_book = FALSE;
-		GError *err = NULL;
-
-		/* failed to load this book last time, skip it now */
-		if (g_hash_table_lookup (emu_broken_books_hash, e_source_peek_uid (source)) != NULL) {
-			d(printf ("%s: skipping broken book '%s'\n", G_STRFUNC, e_source_peek_name (source)));
-			continue;
-		}
-
-		d(printf(" checking '%s'\n", e_source_get_uri(source)));
-
-		hook_book = e_mail_task_manager_cancel_hook_add (emu_addr_cancel_book, book);
-		hook_stop = e_mail_task_manager_cancel_hook_add (emu_addr_cancel_stop, &stop);
-
-		book = g_hash_table_lookup (emu_books_hash, e_source_peek_uid (source));
-		if (!book) {
-			book = e_book_new (source, &err);
-
-			if (book == NULL) {
-				if (err && g_error_matches (err, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED)) {
-					stop = TRUE;
-				} else if (err) {
-					gchar *source_uid = g_strdup (e_source_peek_uid (source));
-
-					g_hash_table_insert (emu_broken_books_hash, source_uid, source_uid);
-
-					g_warning ("%s: Unable to create addressbook '%s': %s", G_STRFUNC, e_source_peek_name (source), err->message);
-				}
-				g_clear_error (&err);
-			} else if (!stop && !try_open_e_book (book, TRUE, &err)) {
-				g_object_unref (book);
-				book = NULL;
-
-				if (err && g_error_matches (err, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED)) {
-					stop = TRUE;
-				} else if (err) {
-					gchar *source_uid = g_strdup (e_source_peek_uid (source));
-
-					g_hash_table_insert (emu_broken_books_hash, source_uid, source_uid);
-
-					g_warning ("%s: Unable to open addressbook '%s': %s", G_STRFUNC, e_source_peek_name (source), err->message);
-				}
-				g_clear_error (&err);
-			}
-		} else {
-			cached_book = TRUE;
-		}
-
-		if (book && !stop && e_book_get_contacts (book, query, &contacts, &err)) {
-			if (contacts != NULL) {
-				if (!found_any) {
-					g_hash_table_insert (contact_cache, g_strdup (lowercase_addr), book);
-				}
-				found_any = TRUE;
-
-				if (check_contact) {
-					GList *l;
-
-					for (l = contacts; l && !found; l = l->next) {
-						EContact *contact = l->data;
-
-						found = check_contact (contact, user_data);
-					}
-				} else {
-					found = TRUE;
-				}
-
-				g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
-				g_list_free (contacts);
-			}
-		} else if (book) {
-			stop = stop || (err && g_error_matches (err, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED));
-			if (err && !stop) {
-				gchar *source_uid = g_strdup (e_source_peek_uid (source));
-
-				g_hash_table_insert (emu_broken_books_hash, source_uid, source_uid);
-
-				g_warning ("%s: Can't get contacts from '%s': %s", G_STRFUNC, e_source_peek_name (source), err->message);
-			}
-			g_clear_error (&err);
-		}
-
-		e_mail_task_manager_cancel_hook_remove (hook_book);
-		e_mail_task_manager_cancel_hook_remove (hook_stop);
-
-		stop = stop || camel_operation_cancel_check (NULL);
-
-		if (stop && !cached_book && book) {
-			g_object_unref (book);
-		} else if (!stop && book && !cached_book) {
-			g_hash_table_insert (emu_books_hash, g_strdup (e_source_peek_uid (source)), book);
-		}
-	}
-
-	g_slist_foreach (addr_sources, (GFunc) g_object_unref, NULL);
-	g_slist_free (addr_sources);
-
-	e_book_query_unref (query);
-
-	if (!found_any) {
-		g_hash_table_insert (contact_cache, lowercase_addr, NOT_FOUND_BOOK);
-		lowercase_addr = NULL;
-	}
-
-	G_UNLOCK (contact_cache);
-
-	g_free (lowercase_addr);
-
-	return found_any;
-}
-
-gboolean
-em_utils_in_addressbook (CamelInternetAddress *iaddr, gboolean local_only)
-{
-	const gchar *addr;
-
-	/* TODO: check all addresses? */
-	if (iaddr == NULL || !camel_internet_address_get (iaddr, 0, NULL, &addr))
-		return FALSE;
-
-	return search_address_in_addressbooks (addr, local_only, NULL, NULL);
-}
-
-static gboolean
-extract_photo_data (EContact *contact, gpointer user_data)
-{
-	EContactPhoto **photo = user_data;
-
-	g_return_val_if_fail (contact != NULL, FALSE);
-	g_return_val_if_fail (user_data != NULL, FALSE);
-
-	*photo = e_contact_get (contact, E_CONTACT_PHOTO);
-	if (!*photo)
-		*photo = e_contact_get (contact, E_CONTACT_LOGO);
-
-	return *photo != NULL;
-}
-
-typedef struct _PhotoInfo {
-	gchar *address;
-	EContactPhoto *photo;
-} PhotoInfo;
-
-static void
-emu_free_photo_info (PhotoInfo *pi)
-{
-	if (!pi)
-		return;
-
-	if (pi->address)
-		g_free (pi->address);
-	if (pi->photo)
-		e_contact_photo_free (pi->photo);
-	g_free (pi);
-}
-
-G_LOCK_DEFINE_STATIC (photos_cache);
-static GSList *photos_cache = NULL; /* list of PhotoInfo-s */
-
-CamelMimePart *
-em_utils_contact_photo (CamelInternetAddress *cia, gboolean local_only)
-{
-	const gchar *addr = NULL;
-	CamelMimePart *part = NULL;
-	EContactPhoto *photo = NULL;
-	GSList *p, *first_not_null = NULL;
-	gint count_not_null = 0;
-
-	if (cia == NULL || !camel_internet_address_get (cia, 0, NULL, &addr) || !addr) {
-		return NULL;
-	}
-
-	G_LOCK (photos_cache);
-
-	/* search a cache first */
-	for (p = photos_cache; p; p = p->next) {
-		PhotoInfo *pi = p->data;
-
-		if (!pi)
-			continue;
-
-		if (pi->photo) {
-			if (!first_not_null)
-				first_not_null = p;
-			count_not_null++;
-		}
-
-		if (g_ascii_strcasecmp (addr, pi->address) == 0) {
-			photo = pi->photo;
-			break;
-		}
-	}
-
-	/* !p means the address had not been found in the cache */
-	if (!p && search_address_in_addressbooks (addr, local_only, extract_photo_data, &photo)) {
-		PhotoInfo *pi;
-
-		if (photo && photo->type != E_CONTACT_PHOTO_TYPE_INLINED) {
-			e_contact_photo_free (photo);
-			photo = NULL;
-		}
-
-		/* keep only up to 10 photos in memory */
-		if (photo && count_not_null >= 10 && first_not_null) {
-			pi = first_not_null->data;
-
-			photos_cache = g_slist_remove (photos_cache, pi);
-
-			emu_free_photo_info (pi);
-		}
-
-		pi = g_new0 (PhotoInfo, 1);
-		pi->address = g_strdup (addr);
-		pi->photo = photo;
-
-		photos_cache = g_slist_append (photos_cache, pi);
-	}
-
-	/* some photo found, use it */
-	if (photo) {
-		/* Form a mime part out of the photo */
-		part = camel_mime_part_new ();
-		camel_mime_part_set_content(part,
-				    (const gchar *) photo->data.inlined.data,
-				    photo->data.inlined.length, "image/jpeg");
-	}
-
-	G_UNLOCK (photos_cache);
-
-	return part;
-}
-
-/* list of email addresses (strings) to remove from local cache of photos and contacts,
-   but only if the photo doesn't exist or is an not-found contact */
-void
-emu_remove_from_mail_cache (const GSList *addresses)
-{
-	const GSList *a;
-	GSList *p;
-	CamelInternetAddress *cia;
-
-	cia = camel_internet_address_new ();
-
-	for (a = addresses; a; a = a->next) {
-		const gchar *addr = NULL;
-
-		if (!a->data)
-			continue;
-
-		if (camel_address_decode ((CamelAddress *) cia, a->data) != -1 &&
-		    camel_internet_address_get (cia, 0, NULL, &addr) && addr) {
-			gchar *lowercase_addr = g_utf8_strdown (addr, -1);
-
-			G_LOCK (contact_cache);
-			if (g_hash_table_lookup (contact_cache, lowercase_addr) == NOT_FOUND_BOOK)
-				g_hash_table_remove (contact_cache, lowercase_addr);
-			G_UNLOCK (contact_cache);
-
-			g_free (lowercase_addr);
-
-			G_LOCK (photos_cache);
-			for (p = photos_cache; p; p = p->next) {
-				PhotoInfo *pi = p->data;
-
-				if (pi && !pi->photo && g_ascii_strcasecmp (pi->address, addr) == 0) {
-					photos_cache = g_slist_remove (photos_cache, pi);
-					emu_free_photo_info (pi);
-					break;
-				}
-			}
-			G_UNLOCK (photos_cache);
-		}
-	}
-
-	camel_object_unref (cia);
-}
-
-void
-emu_remove_from_mail_cache_1 (const gchar *address)
-{
-	GSList *l;
-
-	g_return_if_fail (address != NULL);
-
-	l = g_slist_append (NULL, (gpointer) address);
-
-	emu_remove_from_mail_cache (l);
-
-	g_slist_free (l);
-}
-
-/* frees all data created by call of em_utils_in_addressbook or em_utils_contact_photo */
-void
-emu_free_mail_cache (void)
-{
-	G_LOCK (contact_cache);
-
-	if (emu_books_hash) {
-		g_hash_table_destroy (emu_books_hash);
-		emu_books_hash = NULL;
-	}
-
-	if (emu_broken_books_hash) {
-		g_hash_table_destroy (emu_broken_books_hash);
-		emu_broken_books_hash = NULL;
-	}
-
-	if (emu_books_source_list) {
-		g_object_unref (emu_books_source_list);
-		emu_books_source_list = NULL;
-	}
-
-	if (contact_cache) {
-		g_hash_table_destroy (contact_cache);
-		contact_cache = NULL;
-	}
-
-	G_UNLOCK (contact_cache);
-
-	G_LOCK (photos_cache);
-
-	g_slist_foreach (photos_cache, (GFunc) emu_free_photo_info, NULL);
-	g_slist_free (photos_cache);
-	photos_cache = NULL;
-
-	G_UNLOCK (photos_cache);
-}
-
-void
-em_utils_clear_get_password_canceled_accounts_flag (void)
-{
-	EAccountList *accounts;
-
-	accounts = e_get_account_list ();
-	if (accounts) {
-		EIterator *iter;
-
-		for (iter = e_list_get_iterator ((EList *) accounts);
-		     e_iterator_is_valid (iter);
-		     e_iterator_next (iter)) {
-			EAccount *account = (EAccount *) e_iterator_get (iter);
-
-			if (account && account->source)
-				account->source->get_password_canceled = FALSE;
-
-			if (account && account->transport)
-				account->transport->get_password_canceled = FALSE;
-		}
-
-		g_object_unref (iter);
-	}
-}
-
 void
 em_utils_show_error_silent (GtkWidget *widget)
 {
@@ -2058,159 +1032,3 @@ em_utils_show_info_silent (GtkWidget *widget)
 			widget, "response",
 			G_CALLBACK (gtk_widget_destroy), NULL);
 }
-
-gchar *
-em_utils_url_unescape_amp (const gchar *url)
-{
-	gchar *buff;
-	gint i, j, amps;
-
-	if (!url)
-		return NULL;
-
-	amps = 0;
-	for (i = 0; url [i]; i++) {
-		if (url [i] == '&' && strncmp (url + i, "&amp;", 5) == 0)
-			amps++;
-	}
-
-	buff = g_strdup (url);
-
-	if (!amps)
-		return buff;
-
-	for (i = 0, j = 0; url [i]; i++, j++) {
-		buff [j] = url [i];
-
-		if (url [i] == '&' && strncmp (url + i, "&amp;", 5) == 0)
-			i += 4;
-	}
-	buff [j] = 0;
-
-	return buff;
-}
-
-static EAccount *
-guess_account_folder (CamelFolder *folder)
-{
-	EAccount *account;
-	gchar *tmp;
-
-	tmp = camel_url_to_string (CAMEL_SERVICE (folder->parent_store)->url, CAMEL_URL_HIDE_ALL);
-	account = mail_config_get_account_by_source_url (tmp);
-	g_free (tmp);
-
-	return account;
-}
-
-GHashTable *
-em_utils_generate_account_hash (void)
-{
-	GHashTable *account_hash;
-	EAccount *account, *def;
-	EAccountList *accounts;
-	EIterator *iter;
-
-	accounts = e_get_account_list ();
-	account_hash = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
-
-	def = e_get_default_account ();
-
-	iter = e_list_get_iterator ((EList *) accounts);
-	while (e_iterator_is_valid (iter)) {
-		account = (EAccount *) e_iterator_get (iter);
-
-		if (account->id->address) {
-			EAccount *acnt;
-
-			/* Accounts with identical email addresses that are enabled
-			 * take precedence over the accounts that aren't. If all
-			 * accounts with matching email addresses are disabled, then
-			 * the first one in the list takes precedence. The default
-			 * account always takes precedence no matter what.
-			 */
-			acnt = g_hash_table_lookup (account_hash, account->id->address);
-			if (acnt && acnt != def && !acnt->enabled && account->enabled) {
-				g_hash_table_remove (account_hash, acnt->id->address);
-				acnt = NULL;
-			}
-
-			if (!acnt)
-				g_hash_table_insert (account_hash, (gchar *) account->id->address, (gpointer) account);
-		}
-
-		e_iterator_next (iter);
-	}
-
-	g_object_unref (iter);
-
-	/* The default account has to be there if none of the enabled accounts are present */
-	if (g_hash_table_size (account_hash) == 0 && def && def->id->address)
-		g_hash_table_insert (account_hash, (gchar *) def->id->address, (gpointer) def);
-
-	return account_hash;
-}
-
-EAccount *
-em_utils_guess_account_with_recipients (CamelMimeMessage *message, CamelFolder *folder)
-{
-	GHashTable *account_hash = NULL;
-	EAccount *account = NULL;
-	const gchar *tmp;
-	gint i;
-	GList *l, *recipients = NULL;
-	const CamelInternetAddress *addr;
-
-	account = em_utils_guess_account (message, folder);
-	if (account)
-		return account;
-	addr = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_TO);
-	if (addr)
-		recipients = g_list_append (recipients, (gpointer) addr);
-	addr = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_CC);
-	if (addr)
-		recipients = g_list_append (recipients, (gpointer) addr);
-
-	/* finally recipient (to/cc) in account table */
-	account_hash = em_utils_generate_account_hash ();
-	for (l = recipients; l == NULL; l = l->next) {
-		const CamelInternetAddress *to;
-
-		to = (CamelInternetAddress*)l->data;
-		if (to) {
-			for (i = 0; camel_internet_address_get(to, i, NULL, &tmp); i++) {
-				account = g_hash_table_lookup(account_hash, tmp);
-				if (account && account->enabled)
-					break;
-			}
-		}
-	}
-	g_hash_table_destroy(account_hash);
-
-	return account;
-}
-
-EAccount *
-em_utils_guess_account (CamelMimeMessage *message, CamelFolder *folder)
-{
-	EAccount *account = NULL;
-	const gchar *tmp;
-
-	/* check for newsgroup header */
-	if (folder
-	    && camel_medium_get_header ((CamelMedium *)message, "Newsgroups")
-	    && (account = guess_account_folder (folder)))
-		return account;
-
-	/* check for source folder */
-	if (folder)
-		account = guess_account_folder (folder);
-
-	/* then message source */
-	if (account == NULL
-	    && (tmp = camel_mime_message_get_source (message))) {
-		account = mail_config_get_account_by_source_url (tmp);
-	}
-
-	return account;
-}
diff --git a/mail/em-utils.h b/mail/em-utils.h
index 2293dfa..a4ebd96 100644
--- a/mail/em-utils.h
+++ b/mail/em-utils.h
@@ -33,6 +33,7 @@
 #include <camel/camel-stream.h>
 
 #include <mail/e-mail-reader.h>
+#include <mail/mail-utils.h>
 
 G_BEGIN_DECLS
 
@@ -41,13 +42,7 @@ struct _EMFormat;
 gboolean em_utils_ask_open_many (GtkWindow *parent, gint how_many);
 gboolean em_utils_prompt_user(GtkWindow *parent, const gchar *promptkey, const gchar *tag, const gchar *arg0, ...);
 
-GPtrArray *em_utils_uids_copy (GPtrArray *uids);
-void em_utils_uids_free (GPtrArray *uids);
-
-gboolean em_utils_check_user_can_send_mail (void);
-
 void em_utils_edit_filters (GtkWidget *parent);
-void em_filename_make_safe (gchar *string);
 void em_utils_edit_vfolders (GtkWidget *parent);
 
 void em_utils_flag_for_followup (EMailReader *reader, CamelFolder *folder, GPtrArray *uids);
@@ -67,48 +62,16 @@ void em_utils_selection_get_urilist(GtkSelectionData *data, CamelFolder *folder)
 
 gchar *em_utils_temp_save_part(GtkWidget *parent, CamelMimePart *part, gboolean mode);
 
-gboolean em_utils_folder_is_drafts(CamelFolder *folder, const gchar *uri);
-gboolean em_utils_folder_is_templates(CamelFolder *folder, const gchar *uri);
-gboolean em_utils_folder_is_sent(CamelFolder *folder, const gchar *uri);
-gboolean em_utils_folder_is_outbox(CamelFolder *folder, const gchar *uri);
-
-gchar *em_utils_get_proxy_uri (const gchar *uri);
-
 /* FIXME: should this have an override charset? */
 gchar *em_utils_message_to_html (CamelMimeMessage *msg, const gchar *credits, guint32 flags, gssize *len, struct _EMFormat *source, const gchar *append, guint32 *validity_found);
 
 void em_utils_expunge_folder (GtkWidget *parent, CamelFolder *folder);
 void em_utils_empty_trash (GtkWidget *parent);
 
-/* returns the folder name portion of an URI */
-gchar *em_utils_folder_name_from_uri (const gchar *uri);
-
-/* internal/camel uri translation */
-gchar *em_uri_from_camel (const gchar *curi);
-gchar *em_uri_to_camel (const gchar *euri);
-
 /* Run errors silently on the status bar */
 void em_utils_show_error_silent (GtkWidget *widget);
 void em_utils_show_info_silent (GtkWidget *widget);
 
-/* is this address in the addressbook?  caches results */
-gboolean em_utils_in_addressbook (CamelInternetAddress *addr, gboolean local_only);
-CamelMimePart *em_utils_contact_photo (CamelInternetAddress *addr, gboolean local);
-
-/* clears flag 'get_password_canceled' at every known accounts, so if needed, get_password will show dialog */
-void em_utils_clear_get_password_canceled_accounts_flag (void);
-
-/* Unescapes &amp; back to a real & in URIs */
-gchar *em_utils_url_unescape_amp (const gchar *url);
-
-GHashTable * em_utils_generate_account_hash (void);
-struct _EAccount *em_utils_guess_account (CamelMimeMessage *message, CamelFolder *folder);
-struct _EAccount *em_utils_guess_account_with_recipients (CamelMimeMessage *message, CamelFolder *folder);
-
-void emu_remove_from_mail_cache (const GSList *addresses);
-void emu_remove_from_mail_cache_1 (const gchar *address);
-void emu_free_mail_cache (void);
-
 G_END_DECLS
 
 #endif /* __EM_UTILS_H__ */
diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c
index 9094357..f3fb5a0 100644
--- a/mail/mail-folder-cache.c
+++ b/mail/mail-folder-cache.c
@@ -54,7 +54,7 @@
 
 #include "e-mail-local.h"
 #include "e-mail-task-manager.h"
-#include "em-utils.h"
+#include "mail-utils.h"
 #include "mail-folder-cache.h"
 #include "mail-mt.h"
 #include "mail-ops.h"
diff --git a/mail/mail-ops.c b/mail/mail-ops.c
index 63d42c3..5244cf2 100644
--- a/mail/mail-ops.c
+++ b/mail/mail-ops.c
@@ -38,6 +38,7 @@
 #include <camel/camel-disco-folder.h>
 #include <camel/camel-disco-store.h>
 #include <camel/camel-mime-filter-from.h>
+#include <camel/camel-multipart.h>
 #include <camel/camel-offline-folder.h>
 #include <camel/camel-offline-store.h>
 #include <camel/camel-stream-filter.h>
@@ -52,11 +53,11 @@
 #include "e-mail-local.h"
 #include "e-mail-task-manager.h"
 #include "em-filter-rule.h"
-#include "em-utils.h"
 #include "mail-mt.h"
 #include "mail-ops.h"
 #include "mail-session.h"
 #include "mail-tools.h"
+#include "mail-utils.h"
 
 #define w(x)
 #define d(x)
diff --git a/mail/mail-session.c b/mail/mail-session.c
index afd0200..6f6da41 100644
--- a/mail/mail-session.c
+++ b/mail/mail-session.c
@@ -52,10 +52,9 @@
 
 #include "e-mail-local.h"
 #include "e-mail-task-manager.h"
-#include "em-composer-utils.h"
 #include "em-filter-context.h"
 #include "em-filter-rule.h"
-#include "em-utils.h"
+#include "mail-utils.h"
 #include "mail-config.h"
 #include "mail-mt.h"
 #include "mail-ops.h"
@@ -282,20 +281,15 @@ forget_password (CamelSession *session, CamelService *service, const gchar *doma
 
 /* ********************************************************************** */
 
-static gpointer user_message_dialog;
-static GQueue user_message_queue = { NULL, NULL, 0 };
-
 typedef struct _user_message_msg UserMessageMsg;
 struct _user_message_msg {
 	EMailMsg base;
 
-	CamelSessionAlertType type;
-	gchar *prompt;
 	EFlag *done;
+	EAlert *alert;
 
-	guint allow_cancel:1;
+	guint needs_response:1;
 	guint result:1;
-	guint ismain:1;
 };
 typedef struct _UserMessageMsgClass UserMessageMsgClass;
 struct _UserMessageMsgClass {
@@ -304,112 +298,63 @@ struct _UserMessageMsgClass {
 static GType user_message_msg_get_type ();
 G_DEFINE_TYPE (UserMessageMsg, user_message_msg, E_TYPE_MAIL_MSG);
 
-static void user_message_exec (UserMessageMsg *m);
-
-static void
-user_message_response_free (GtkDialog *dialog, gint button, UserMessageMsg *m)
-{
-	gtk_widget_destroy ((GtkWidget *) dialog);
-
-	user_message_dialog = NULL;
-
-	/* check for pendings */
-	if (!g_queue_is_empty (&user_message_queue)) {
-		m = g_queue_pop_head (&user_message_queue);
-		user_message_exec (m);
-		g_object_unref (m);
-	}
-}
+G_LOCK_DEFINE_STATIC(user_message);
+static UserMessageMsg *current_user_msg = NULL;
+static GQueue user_message_queue = G_QUEUE_INIT;
 
 /* clicked, send back the reply */
 static void
 user_message_response (GtkDialog *dialog, gint button, UserMessageMsg *m)
 {
-	/* if !allow_cancel, then we've already replied */
-	if (m->allow_cancel) {
-		m->result = button == GTK_RESPONSE_OK;
-		e_flag_set (m->done);
-	}
+	m->result = button == GTK_RESPONSE_OK;
+	e_flag_set (m->done);
 
-	user_message_response_free (dialog, button, m);
+	gtk_widget_destroy ((GtkWidget *) dialog);
+	g_object_unref (m);
+
+	G_LOCK (user_message);
+	current_user_msg = g_queue_pop_head (&user_message_queue);
+	if (current_user_msg)
+		e_mail_task_manager_main_loop_push
+			(e_mail_task_manager_get_default (),
+			 (EMailMsg*) current_user_msg);
+	G_UNLOCK (user_message);
 }
 
 static void
 user_message_exec (UserMessageMsg *m)
 {
-	const gchar *error_type;
-
-	if (!m->ismain && user_message_dialog != NULL) {
-		g_queue_push_tail (&user_message_queue, g_object_ref (m));
-		return;
-	}
-
-	switch (m->type) {
-		case CAMEL_SESSION_ALERT_INFO:
-			error_type = m->allow_cancel ?
-				"mail:session-message-info-cancel" :
-				"mail:session-message-info";
-			break;
-		case CAMEL_SESSION_ALERT_WARNING:
-			error_type = m->allow_cancel ?
-				"mail:session-message-warning-cancel" :
-				"mail:session-message-warning";
-			break;
-		case CAMEL_SESSION_ALERT_ERROR:
-			error_type = m->allow_cancel ?
-				"mail:session-message-error-cancel" :
-				"mail:session-message-error";
-			break;
-		default:
-			error_type = NULL;
-			g_return_if_reached ();
-	}
-
-	/* The mail daemon won't have a window here, so there's nothing to set
-	 * as the parent */
-	user_message_dialog =
-		e_alert_dialog_new_for_args (NULL, error_type, m->prompt, NULL);
-	g_object_set (
-		user_message_dialog, "allow_shrink", TRUE,
-		"allow_grow", TRUE, NULL);
+	g_return_if_fail (e_in_main_thread ());
 
-	/* Use the number of dialog buttons as a heuristic for whether to
-	 * emit a status bar message or present the dialog immediately, the
-	 * thought being if there's more than one button then something is
-	 * probably blocked until the user responds. */
-	if (e_alert_dialog_count_buttons (user_message_dialog) > 1) {
-		if (m->ismain) {
-			gint response;
-
-			response = gtk_dialog_run (user_message_dialog);
-			user_message_response (
-				user_message_dialog, response, m);
-		} else {
-			g_signal_connect (
-				user_message_dialog, "response",
-				G_CALLBACK (user_message_response), m);
-			gtk_widget_show (user_message_dialog);
-		}
+	if (m->needs_response) {
+		/* The mail daemon won't have a window here, so there's nothing to set
+		 * as the parent */
+		GtkWidget *dialog = e_alert_dialog_new (NULL, m->alert);
+		g_object_set (dialog, "allow_shrink", TRUE, "allow_grow", TRUE, NULL);
+		g_signal_connect (dialog, "response",
+				  G_CALLBACK (user_message_response), g_object_ref (m));
+		gtk_widget_show (dialog);
 	} else {
-		g_signal_connect (
-			user_message_dialog, "response",
-			G_CALLBACK (user_message_response_free), m);
-		g_object_set_data (
-			user_message_dialog, "response-handled",
-			GINT_TO_POINTER (TRUE));
-		em_utils_show_error_silent (user_message_dialog);
+		g_signal_emit_by_name (m, "error-response", m->alert);
 	}
 }
 
 static void
-user_message_msg_finalize (GObject *object)
+user_message_msg_dispose (GObject *object)
 {
 	UserMessageMsg *m = (UserMessageMsg*) object;
 
-	g_free (m->prompt);
-	e_flag_free (m->done);
+	if (m->done) {
+		e_flag_free (m->done);
+		m->done = NULL;
+	}
 
-	G_OBJECT_CLASS (user_message_msg_parent_class)->finalize (object);
+	if (m->alert) {
+		g_object_unref (m->alert);
+		m->alert = NULL;
+	}
+
+	G_OBJECT_CLASS (user_message_msg_parent_class)->dispose (object);
 }
 
 static void
@@ -417,7 +362,7 @@ user_message_msg_class_init (UserMessageMsgClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-	object_class->finalize = user_message_msg_finalize;
+	object_class->dispose = user_message_msg_dispose;
 
 	E_MAIL_MSG_CLASS (klass)->exec = (MailMsgExecFunc) user_message_exec;
 }
@@ -444,37 +389,74 @@ lookup_addressbook(CamelSession *session, const gchar *name)
 	return ret;
 }
 
+static void
+queue_user_message (UserMessageMsg *msg)
+{
+	G_LOCK (user_message);
+	/* if there's a message requiring a response being currently processed,
+	 * just push the message into the back of the queue.  The response
+	 * handler of the current msg will process messages from the queue when
+	 * it is finished */
+	if (current_user_msg) {
+		g_queue_push_tail (&user_message_queue, msg);
+	} else {
+		current_user_msg = msg;
+		e_mail_task_manager_main_loop_push
+			(e_mail_task_manager_get_default (), (EMailMsg*) msg);
+	}
+	G_UNLOCK (user_message);
+}
+
 static gboolean
 alert_user(CamelSession *session, CamelSessionAlertType type, const gchar *prompt, gboolean cancel)
 {
 	UserMessageMsg *m;
 	gboolean result = TRUE;
+	const gchar *error_type;
+	struct _e_alert_button *buttons = NULL;
 
 	m = g_object_new (user_message_msg_get_type (), NULL);
-	m->ismain = e_in_main_thread ();
-	m->type = type;
-	m->prompt = g_strdup (prompt);
 	m->done = e_flag_new ();
-	m->allow_cancel = cancel;
-
-	if (cancel)
-		g_object_ref (m);
+	switch (type) {
+		case CAMEL_SESSION_ALERT_INFO:
+			error_type = cancel ?
+				"mail:session-message-info-cancel" :
+				"mail:session-message-info";
+			break;
+		case CAMEL_SESSION_ALERT_WARNING:
+			error_type = cancel ?
+				"mail:session-message-warning-cancel" :
+				"mail:session-message-warning";
+			break;
+		case CAMEL_SESSION_ALERT_ERROR:
+			error_type = cancel ?
+				"mail:session-message-error-cancel" :
+				"mail:session-message-error";
+			break;
+		default:
+			error_type = NULL;
+			g_return_val_if_reached (FALSE);
+	}
+	m->alert = e_alert_new (error_type, prompt, NULL);
 
-	if (m->ismain)
-		user_message_exec (m);
-	else
-		e_mail_task_manager_main_loop_push
-			(e_mail_task_manager_get_default (), (EMailMsg*) m);
+	/* Use the number of dialog buttons as a heuristic for whether to
+	 * emit a status bar message or present the dialog immediately, the
+	 * thought being if there's more than one button then something is
+	 * probably blocked until the user responds. */
+	buttons = e_alert_peek_buttons (m->alert);
+	m->needs_response = buttons && buttons->next;
 
-	if (cancel) {
+	if (m->needs_response) {
+		/* only one message should be processed at a time,
+		 * so we pass it to a helper that will ensure this */
+		queue_user_message (m);
 		e_flag_wait (m->done);
 		result = m->result;
-		g_object_ref (m);
+	} else {
+		e_mail_task_manager_main_loop_push
+			(e_mail_task_manager_get_default (), (EMailMsg*) m);
 	}
 
-	if (m->ismain)
-		g_object_unref (m);
-
 	return result;
 }
 
diff --git a/mail/mail-tools.c b/mail/mail-tools.c
index 8259abd..a318490 100644
--- a/mail/mail-tools.c
+++ b/mail/mail-tools.c
@@ -40,7 +40,7 @@
 #include <camel/camel-mime-message.h>
 #include <camel/camel-movemail.h>
 
-#include "em-utils.h"
+#include "mail-utils.h"
 #include "mail-folder-cache.h"
 #include "mail-session.h"
 #include "mail-tools.h"
diff --git a/mail/mail-utils.c b/mail/mail-utils.c
new file mode 100644
index 0000000..2a8d693
--- /dev/null
+++ b/mail/mail-utils.c
@@ -0,0 +1,1258 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <time.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#ifdef G_OS_WIN32
+/* Work around namespace clobbage in <windows.h> */
+#define DATADIR windows_DATADIR
+#include <windows.h>
+#undef DATADIR
+#undef interface
+#endif
+
+#include <camel/camel-url-scanner.h>
+#include <camel/camel-file-utils.h>
+#include <camel/camel-string-utils.h>
+
+#include <libebook/e-book.h>
+
+#include <glib/gi18n.h>
+
+#include <gio/gio.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-flag.h>
+#include <libedataserver/e-proxy.h>
+
+#include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
+#include "e-util/e-binding.h"
+#include "e-util/e-account-utils.h"
+
+#include "e-mail-local.h"
+#include "e-mail-task-manager.h"
+#include "mail-config.h"
+#include "mail-mt.h"
+#include "mail-ops.h"
+#include "mail-session.h"
+#include "mail-tools.h"
+#include "mail-utils.h"
+
+#define d(x)
+
+/**
+ * em_utils_uids_copy:
+ * @uids: array of uids
+ *
+ * Duplicates the array of uids held by @uids into a new
+ * GPtrArray. Use em_utils_uids_free() to free the resultant uid
+ * array.
+ *
+ * Returns a duplicate copy of @uids.
+ **/
+GPtrArray *
+em_utils_uids_copy (GPtrArray *uids)
+{
+	GPtrArray *copy;
+	gint i;
+
+	copy = g_ptr_array_new ();
+	g_ptr_array_set_size (copy, uids->len);
+
+	for (i = 0; i < uids->len; i++)
+		copy->pdata[i] = g_strdup (uids->pdata[i]);
+
+	return copy;
+}
+
+/**
+ * em_utils_uids_free:
+ * @uids: array of uids
+ *
+ * Frees the array of uids pointed to by @uids back to the system.
+ **/
+void
+em_utils_uids_free (GPtrArray *uids)
+{
+	gint i;
+
+	for (i = 0; i < uids->len; i++)
+		g_free (uids->pdata[i]);
+
+	g_ptr_array_free (uids, TRUE);
+}
+
+/**
+ * em_utils_check_user_can_send_mail:
+ *
+ * Returns %TRUE if the user has an account configured (to send mail)
+ * or %FALSE otherwise.
+ **/
+gboolean
+em_utils_check_user_can_send_mail (void)
+{
+	EAccountList *account_list;
+	EAccount *account;
+
+	account_list = e_get_account_list ();
+
+	if (e_list_length ((EList *) account_list) == 0)
+		return FALSE;
+
+	if (!(account = e_get_default_account ()))
+		return FALSE;
+
+	/* Check for a transport */
+	if (!account->transport->url)
+		return FALSE;
+
+	return TRUE;
+}
+
+/*
+ * Picked this from e-d-s/libedataserver/e-data.
+ * But it allows more characters to occur in filenames, especially when saving attachment.
+ */
+void
+em_filename_make_safe (gchar *string)
+{
+	gchar *p, *ts;
+	gunichar c;
+#ifdef G_OS_WIN32
+	const gchar *unsafe_chars = "/\":*?<>|\\#";
+#else
+	const gchar *unsafe_chars = "/#";
+#endif
+
+	g_return_if_fail (string != NULL);
+	p = string;
+
+	while (p && *p) {
+		c = g_utf8_get_char (p);
+		ts = p;
+		p = g_utf8_next_char (p);
+		/* I wonder what this code is supposed to actually
+		 * achieve, and whether it does that as currently
+		 * written?
+		 */
+		if (!g_unichar_isprint(c) || ( c < 0xff && strchr (unsafe_chars, c&0xff ))) {
+			while (ts<p)
+				*ts++ = '_';
+		}
+	}
+}
+
+/** em_utils_folder_is_templates:
+ * @folder: folder
+ * @uri: uri for this folder, if known
+ *
+ * Decides if @folder is a Templates folder.
+ *
+ * Returns %TRUE if this is a Drafts folder or %FALSE otherwise.
+ **/
+
+gboolean
+em_utils_folder_is_templates (CamelFolder *folder, const gchar *uri)
+{
+	CamelFolder *local_templates_folder;
+	EAccountList *accounts;
+	EAccount *account;
+	EIterator *iter;
+	gint is = FALSE;
+	gchar *templates_uri;
+
+	local_templates_folder =
+		e_mail_local_get_folder (E_MAIL_FOLDER_TEMPLATES);
+
+	if (folder == local_templates_folder)
+		return TRUE;
+
+	if (folder == NULL || uri == NULL)
+		return FALSE;
+
+	accounts = e_get_account_list ();
+	iter = e_list_get_iterator ((EList *)accounts);
+	while (e_iterator_is_valid (iter)) {
+		account = (EAccount *)e_iterator_get (iter);
+
+		if (account->templates_folder_uri) {
+			templates_uri = em_uri_to_camel (account->templates_folder_uri);
+			if (camel_store_folder_uri_equal (folder->parent_store, templates_uri, uri)) {
+				g_free (templates_uri);
+				is = TRUE;
+				break;
+			}
+			g_free (templates_uri);
+		}
+
+		e_iterator_next (iter);
+	}
+
+	g_object_unref (iter);
+
+	return is;
+}
+
+/**
+ * em_utils_folder_is_drafts:
+ * @folder: folder
+ * @uri: uri for this folder, if known
+ *
+ * Decides if @folder is a Drafts folder.
+ *
+ * Returns %TRUE if this is a Drafts folder or %FALSE otherwise.
+ **/
+gboolean
+em_utils_folder_is_drafts(CamelFolder *folder, const gchar *uri)
+{
+	CamelFolder *local_drafts_folder;
+	EAccountList *accounts;
+	EAccount *account;
+	EIterator *iter;
+	gint is = FALSE;
+	gchar *drafts_uri;
+
+	local_drafts_folder =
+		e_mail_local_get_folder (E_MAIL_FOLDER_DRAFTS);
+
+	if (folder == local_drafts_folder)
+		return TRUE;
+
+	if (folder == NULL || uri == NULL)
+		return FALSE;
+
+	accounts = e_get_account_list ();
+	iter = e_list_get_iterator((EList *)accounts);
+	while (e_iterator_is_valid(iter)) {
+		account = (EAccount *)e_iterator_get(iter);
+
+		if (account->drafts_folder_uri) {
+			drafts_uri = em_uri_to_camel (account->drafts_folder_uri);
+			if (camel_store_folder_uri_equal (folder->parent_store, drafts_uri, uri)) {
+				g_free (drafts_uri);
+				is = TRUE;
+				break;
+			}
+			g_free (drafts_uri);
+		}
+
+		e_iterator_next(iter);
+	}
+
+	g_object_unref(iter);
+
+	return is;
+}
+
+/**
+ * em_utils_folder_is_sent:
+ * @folder: folder
+ * @uri: uri for this folder, if known
+ *
+ * Decides if @folder is a Sent folder
+ *
+ * Returns %TRUE if this is a Sent folder or %FALSE otherwise.
+ **/
+gboolean
+em_utils_folder_is_sent(CamelFolder *folder, const gchar *uri)
+{
+	CamelFolder *local_sent_folder;
+	EAccountList *accounts;
+	EAccount *account;
+	EIterator *iter;
+	gint is = FALSE;
+	gchar *sent_uri;
+
+	local_sent_folder = e_mail_local_get_folder (E_MAIL_FOLDER_SENT);
+
+	if (folder == local_sent_folder)
+		return TRUE;
+
+	if (folder == NULL || uri == NULL)
+		return FALSE;
+
+	accounts = e_get_account_list ();
+	iter = e_list_get_iterator((EList *)accounts);
+	while (e_iterator_is_valid(iter)) {
+		account = (EAccount *)e_iterator_get(iter);
+
+		if (account->sent_folder_uri) {
+			sent_uri = em_uri_to_camel (account->sent_folder_uri);
+			if (camel_store_folder_uri_equal (folder->parent_store, sent_uri, uri)) {
+				g_free (sent_uri);
+				is = TRUE;
+				break;
+			}
+			g_free (sent_uri);
+		}
+
+		e_iterator_next(iter);
+	}
+
+	g_object_unref(iter);
+
+	return is;
+}
+
+/**
+ * em_utils_folder_is_outbox:
+ * @folder: folder
+ * @uri: uri for this folder, if known
+ *
+ * Decides if @folder is an Outbox folder
+ *
+ * Returns %TRUE if this is an Outbox folder or %FALSE otherwise.
+ **/
+gboolean
+em_utils_folder_is_outbox(CamelFolder *folder, const gchar *uri)
+{
+	CamelFolder *local_outbox_folder;
+	const gchar *local_outbox_folder_uri;
+
+	local_outbox_folder =
+		e_mail_local_get_folder (E_MAIL_FOLDER_OUTBOX);
+	local_outbox_folder_uri =
+		e_mail_local_get_folder_uri (E_MAIL_FOLDER_OUTBOX);
+
+	if (folder == local_outbox_folder)
+		return TRUE;
+
+	if (uri == NULL)
+		return FALSE;
+
+	return camel_store_folder_uri_equal (
+		local_outbox_folder->parent_store,
+		local_outbox_folder_uri, uri);
+}
+
+/* ********************************************************************** */
+static EProxy *emu_proxy = NULL;
+static GStaticMutex emu_proxy_lock = G_STATIC_MUTEX_INIT;
+
+static gpointer
+emu_proxy_setup (gpointer data)
+{
+	if (!emu_proxy) {
+		emu_proxy = e_proxy_new ();
+		e_proxy_setup_proxy (emu_proxy);
+		/* not necessary to listen for changes here */
+	}
+
+	return NULL;
+}
+
+/**
+ * em_utils_get_proxy_uri:
+ *
+ * Get the system proxy uri for 'pUri'.
+ *
+ * Return value: Must be freed when finished with.
+ **/
+gchar *
+em_utils_get_proxy_uri (const gchar *pUri)
+{
+	gchar *uri = NULL;
+
+	g_static_mutex_lock (&emu_proxy_lock);
+
+	if (!emu_proxy) {
+		mail_call_main (MAIL_CALL_p_p, (MailMainFunc)emu_proxy_setup, NULL);
+	}
+
+	if (e_proxy_require_proxy_for_uri (emu_proxy, pUri))
+		uri = soup_uri_to_string (e_proxy_peek_uri_for (emu_proxy, pUri), FALSE);
+
+	g_static_mutex_unlock (&emu_proxy_lock);
+
+	return uri;
+}
+
+/* ********************************************************************** */
+
+gchar *
+em_utils_folder_name_from_uri (const gchar *uri)
+{
+	CamelURL *url;
+	gchar *folder_name = NULL;
+
+	if (uri == NULL || (url = camel_url_new (uri, NULL)) == NULL)
+		return NULL;
+
+	if (url->fragment)
+		folder_name = url->fragment;
+	else if (url->path)
+		folder_name = url->path + 1;
+
+	if (folder_name == NULL) {
+		camel_url_free (url);
+		return NULL;
+	}
+
+	folder_name = g_strdup (folder_name);
+	camel_url_free (url);
+
+	return folder_name;
+}
+
+/* email: uri's are based on the account, with special cases for local
+ * stores, vfolder and local mail.
+ * e.g.
+ *  imap account imap://user host/ -> email://accountid accountid host/
+ *  vfolder      vfolder:/storage/path#folder -> email://vfolder local/folder
+ *  local        local:/storage/path#folder   -> email://local local/folder
+ */
+
+gchar *em_uri_from_camel(const gchar *curi)
+{
+	CamelURL *curl;
+	EAccount *account;
+	const gchar *uid, *path;
+	gchar *euri, *tmp;
+	CamelProvider *provider;
+	CamelException ex;
+
+	/* Easiest solution to code that shouldnt be calling us */
+	if (!strncmp(curi, "email:", 6))
+		return g_strdup(curi);
+
+	camel_exception_init(&ex);
+	provider = camel_provider_get(curi, &ex);
+	if (provider == NULL) {
+		camel_exception_clear(&ex);
+		d(printf("em uri from camel failed '%s'\n", curi));
+		return g_strdup(curi);
+	}
+
+	curl = camel_url_new(curi, &ex);
+	camel_exception_clear(&ex);
+	if (curl == NULL)
+		return g_strdup(curi);
+
+	if (strcmp(curl->protocol, "vfolder") == 0)
+		uid = "vfolder local";
+	else if ((account = mail_config_get_account_by_source_url(curi)) == NULL)
+		uid = "local local";
+	else
+		uid = account->uid;
+	path = (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)?curl->fragment:curl->path;
+	if (path) {
+		if (path[0] == '/')
+			path++;
+
+		tmp = camel_url_encode(path, ";?");
+		euri = g_strdup_printf("email://%s/%s", uid, tmp);
+		g_free(tmp);
+	} else {
+		euri = g_strdup_printf("email://%s/", uid);
+	}
+
+	d(printf("em uri from camel '%s' -> '%s'\n", curi, euri));
+
+	camel_url_free(curl);
+
+	return euri;
+}
+
+gchar *em_uri_to_camel(const gchar *euri)
+{
+	EAccountList *accounts;
+	const EAccount *account;
+	EAccountService *service;
+	CamelProvider *provider;
+	CamelURL *eurl, *curl;
+	gchar *uid, *curi;
+
+	if (strncmp(euri, "email:", 6) != 0) {
+		d(printf("em uri to camel not euri '%s'\n", euri));
+		return g_strdup(euri);
+	}
+
+	eurl = camel_url_new(euri, NULL);
+	if (eurl == NULL)
+		return g_strdup(euri);
+
+	g_return_val_if_fail (eurl->host != NULL, g_strdup(euri));
+
+	if (eurl->user != NULL) {
+		/* Sigh, shoul'dve used mbox local for mailboxes, not local local */
+		if (strcmp(eurl->host, "local") == 0
+		    && (strcmp(eurl->user, "local") == 0 || strcmp(eurl->user, "vfolder") == 0)) {
+			gchar *base;
+
+			if (strcmp(eurl->user, "vfolder") == 0)
+				curl = camel_url_new("vfolder:", NULL);
+			else
+				curl = camel_url_new("mbox:", NULL);
+
+			base = g_strdup_printf("%s/.evolution/mail/%s", g_get_home_dir(), eurl->user);
+#ifdef G_OS_WIN32
+			/* Turn backslashes into slashes to avoid URI encoding */
+			{
+				gchar *p = base;
+				while ((p = strchr (p, '\\')))
+					*p++ = '/';
+			}
+#endif
+			camel_url_set_path(curl, base);
+			g_free(base);
+			camel_url_set_fragment(curl, eurl->path[0]=='/'?eurl->path+1:eurl->path);
+			curi = camel_url_to_string(curl, 0);
+			camel_url_free(curl);
+			camel_url_free(eurl);
+
+			d(printf("em uri to camel local '%s' -> '%s'\n", euri, curi));
+			return curi;
+		}
+
+		uid = g_strdup_printf("%s %s", eurl->user, eurl->host);
+	} else {
+		uid = g_strdup(eurl->host);
+	}
+
+	accounts = e_get_account_list ();
+	account = e_account_list_find(accounts, E_ACCOUNT_FIND_UID, uid);
+	g_free(uid);
+
+	if (account == NULL) {
+		camel_url_free(eurl);
+		d(printf("em uri to camel no account '%s' -> '%s'\n", euri, euri));
+		return g_strdup(euri);
+	}
+
+	service = account->source;
+	if (!(provider = camel_provider_get (service->url, NULL)))
+		return g_strdup (euri);
+
+	curl = camel_url_new(service->url, NULL);
+	if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
+		camel_url_set_fragment(curl, eurl->path[0]=='/'?eurl->path+1:eurl->path);
+	else
+		camel_url_set_path(curl, eurl->path);
+
+	curi = camel_url_to_string(curl, 0);
+
+	camel_url_free(eurl);
+	camel_url_free(curl);
+
+	d(printf("em uri to camel '%s' -> '%s'\n", euri, curi));
+
+	return curi;
+}
+
+/* ********************************************************************** */
+
+/* runs sync, in main thread */
+static gpointer
+emu_addr_setup (gpointer user_data)
+{
+	GError *err = NULL;
+	ESourceList **psource_list = user_data;
+
+	if (!e_book_get_addressbooks (psource_list, &err))
+		g_error_free (err);
+
+	return NULL;
+}
+
+static void
+emu_addr_cancel_book (gpointer 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);
+}
+
+static void
+emu_addr_cancel_stop (gpointer data)
+{
+	gboolean *stop = data;
+
+	g_return_if_fail (stop != NULL);
+
+	*stop = TRUE;
+}
+
+struct TryOpenEBookStruct {
+	GError **error;
+	EFlag *flag;
+	gboolean result;
+};
+
+static void
+try_open_e_book_cb (EBook *book, EBookStatus status, gpointer closure)
+{
+	struct TryOpenEBookStruct *data = (struct TryOpenEBookStruct *)closure;
+
+	if (!data)
+		return;
+
+	data->result = status == E_BOOK_ERROR_OK;
+
+	if (!data->result) {
+		g_clear_error (data->error);
+		g_set_error (data->error, E_BOOK_ERROR, status, "EBookStatus returned %d", status);
+	}
+
+	e_flag_set (data->flag);
+}
+
+/**
+ * try_open_e_book:
+ * Tries to open address book asynchronously, but acts as synchronous.
+ * The advantage is it checks periodically whether the camel_operation
+ * has been canceled or not, and if so, then stops immediately, with
+ * result FALSE. Otherwise returns same as e_book_open
+ **/
+static gboolean
+try_open_e_book (EBook *book, gboolean only_if_exists, GError **error)
+{
+	struct TryOpenEBookStruct data;
+	gboolean canceled = FALSE;
+	EFlag *flag = e_flag_new ();
+
+	data.error = error;
+	data.flag = flag;
+	data.result = FALSE;
+
+	if (e_book_async_open (book, only_if_exists, try_open_e_book_cb, &data) != FALSE) {
+		e_flag_free (flag);
+		g_clear_error (error);
+		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR, "Failed to call e_book_async_open.");
+		return FALSE;
+	}
+
+	while (canceled = camel_operation_cancel_check (NULL), !canceled && !e_flag_is_set (flag)) {
+		GTimeVal wait;
+
+		g_get_current_time (&wait);
+		g_time_val_add (&wait, 250000); /* waits 250ms */
+
+		e_flag_timed_wait (flag, &wait);
+	}
+
+	if (canceled) {
+		g_clear_error (error);
+		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED, "Operation has been canceled.");
+		/* if the operation is cancelled sucessfully set the flag else wait. file, groupwise,.. backend's operations
+		   are not cancellable */
+		if (e_book_cancel_async_op (book, NULL))
+			e_flag_set (flag);
+	}
+
+	e_flag_wait (flag);
+	e_flag_free (flag);
+
+	return data.result && (!error || !*error);
+}
+
+#define NOT_FOUND_BOOK (GINT_TO_POINTER (1))
+
+G_LOCK_DEFINE_STATIC (contact_cache);
+static GHashTable *contact_cache = NULL; /* key is lowercased contact email; value is EBook pointer (just for comparison) where it comes from */
+static GHashTable *emu_books_hash = NULL; /* key is source ID; value is pointer to EBook */
+static GHashTable *emu_broken_books_hash = NULL; /* key is source ID; value is same pointer as key; this is hash of broken books, which failed to open for some reason */
+static ESourceList *emu_books_source_list = NULL;
+
+static gboolean
+search_address_in_addressbooks (const gchar *address, gboolean local_only, gboolean (*check_contact) (EContact *contact, gpointer user_data), gpointer user_data)
+{
+	gboolean found = FALSE, stop = FALSE, found_any = FALSE;
+	gchar *lowercase_addr;
+	gpointer ptr;
+	EBookQuery *query;
+	GSList *s, *g, *addr_sources = NULL;
+
+	if (!address || !*address)
+		return FALSE;
+
+	G_LOCK (contact_cache);
+
+	if (!emu_books_source_list) {
+		mail_call_main (MAIL_CALL_p_p, (MailMainFunc)emu_addr_setup, &emu_books_source_list);
+		emu_books_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+		emu_broken_books_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+		contact_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	}
+
+	if (!emu_books_source_list) {
+		G_UNLOCK (contact_cache);
+		return FALSE;
+	}
+
+	lowercase_addr = g_utf8_strdown (address, -1);
+	ptr = g_hash_table_lookup (contact_cache, lowercase_addr);
+	if (ptr != NULL && (check_contact == NULL || ptr == NOT_FOUND_BOOK)) {
+		g_free (lowercase_addr);
+		G_UNLOCK (contact_cache);
+		return ptr != NOT_FOUND_BOOK;
+	}
+
+	query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_IS, address);
+
+	for (g = e_source_list_peek_groups (emu_books_source_list); g; g = g_slist_next (g)) {
+		ESourceGroup *group = g->data;
+
+		if (!group)
+			continue;
+
+		if (local_only && !(e_source_group_peek_base_uri (group) && g_str_has_prefix (e_source_group_peek_base_uri (group), "file://")))
+			continue;
+
+		for (s = e_source_group_peek_sources (group); s; s = g_slist_next (s)) {
+			ESource *source = s->data;
+			const gchar *completion = e_source_get_property (source, "completion");
+
+			if (completion && g_ascii_strcasecmp (completion, "true") == 0) {
+				addr_sources = g_slist_prepend (addr_sources, g_object_ref (source));
+			}
+		}
+	}
+
+	for (s = addr_sources; !stop && !found && s; s = g_slist_next (s)) {
+		ESource *source = s->data;
+		GList *contacts;
+		EBook *book = NULL;
+		GHook *hook_book, *hook_stop;
+		gboolean cached_book = FALSE;
+		GError *err = NULL;
+
+		/* failed to load this book last time, skip it now */
+		if (g_hash_table_lookup (emu_broken_books_hash, e_source_peek_uid (source)) != NULL) {
+			d(printf ("%s: skipping broken book '%s'\n", G_STRFUNC, e_source_peek_name (source)));
+			continue;
+		}
+
+		d(printf(" checking '%s'\n", e_source_get_uri(source)));
+
+		hook_book = e_mail_task_manager_cancel_hook_add (emu_addr_cancel_book, book);
+		hook_stop = e_mail_task_manager_cancel_hook_add (emu_addr_cancel_stop, &stop);
+
+		book = g_hash_table_lookup (emu_books_hash, e_source_peek_uid (source));
+		if (!book) {
+			book = e_book_new (source, &err);
+
+			if (book == NULL) {
+				if (err && g_error_matches (err, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED)) {
+					stop = TRUE;
+				} else if (err) {
+					gchar *source_uid = g_strdup (e_source_peek_uid (source));
+
+					g_hash_table_insert (emu_broken_books_hash, source_uid, source_uid);
+
+					g_warning ("%s: Unable to create addressbook '%s': %s", G_STRFUNC, e_source_peek_name (source), err->message);
+				}
+				g_clear_error (&err);
+			} else if (!stop && !try_open_e_book (book, TRUE, &err)) {
+				g_object_unref (book);
+				book = NULL;
+
+				if (err && g_error_matches (err, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED)) {
+					stop = TRUE;
+				} else if (err) {
+					gchar *source_uid = g_strdup (e_source_peek_uid (source));
+
+					g_hash_table_insert (emu_broken_books_hash, source_uid, source_uid);
+
+					g_warning ("%s: Unable to open addressbook '%s': %s", G_STRFUNC, e_source_peek_name (source), err->message);
+				}
+				g_clear_error (&err);
+			}
+		} else {
+			cached_book = TRUE;
+		}
+
+		if (book && !stop && e_book_get_contacts (book, query, &contacts, &err)) {
+			if (contacts != NULL) {
+				if (!found_any) {
+					g_hash_table_insert (contact_cache, g_strdup (lowercase_addr), book);
+				}
+				found_any = TRUE;
+
+				if (check_contact) {
+					GList *l;
+
+					for (l = contacts; l && !found; l = l->next) {
+						EContact *contact = l->data;
+
+						found = check_contact (contact, user_data);
+					}
+				} else {
+					found = TRUE;
+				}
+
+				g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
+				g_list_free (contacts);
+			}
+		} else if (book) {
+			stop = stop || (err && g_error_matches (err, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED));
+			if (err && !stop) {
+				gchar *source_uid = g_strdup (e_source_peek_uid (source));
+
+				g_hash_table_insert (emu_broken_books_hash, source_uid, source_uid);
+
+				g_warning ("%s: Can't get contacts from '%s': %s", G_STRFUNC, e_source_peek_name (source), err->message);
+			}
+			g_clear_error (&err);
+		}
+
+		e_mail_task_manager_cancel_hook_remove (hook_book);
+		e_mail_task_manager_cancel_hook_remove (hook_stop);
+
+		stop = stop || camel_operation_cancel_check (NULL);
+
+		if (stop && !cached_book && book) {
+			g_object_unref (book);
+		} else if (!stop && book && !cached_book) {
+			g_hash_table_insert (emu_books_hash, g_strdup (e_source_peek_uid (source)), book);
+		}
+	}
+
+	g_slist_foreach (addr_sources, (GFunc) g_object_unref, NULL);
+	g_slist_free (addr_sources);
+
+	e_book_query_unref (query);
+
+	if (!found_any) {
+		g_hash_table_insert (contact_cache, lowercase_addr, NOT_FOUND_BOOK);
+		lowercase_addr = NULL;
+	}
+
+	G_UNLOCK (contact_cache);
+
+	g_free (lowercase_addr);
+
+	return found_any;
+}
+
+gboolean
+em_utils_in_addressbook (CamelInternetAddress *iaddr, gboolean local_only)
+{
+	const gchar *addr;
+
+	/* TODO: check all addresses? */
+	if (iaddr == NULL || !camel_internet_address_get (iaddr, 0, NULL, &addr))
+		return FALSE;
+
+	return search_address_in_addressbooks (addr, local_only, NULL, NULL);
+}
+
+static gboolean
+extract_photo_data (EContact *contact, gpointer user_data)
+{
+	EContactPhoto **photo = user_data;
+
+	g_return_val_if_fail (contact != NULL, FALSE);
+	g_return_val_if_fail (user_data != NULL, FALSE);
+
+	*photo = e_contact_get (contact, E_CONTACT_PHOTO);
+	if (!*photo)
+		*photo = e_contact_get (contact, E_CONTACT_LOGO);
+
+	return *photo != NULL;
+}
+
+typedef struct _PhotoInfo {
+	gchar *address;
+	EContactPhoto *photo;
+} PhotoInfo;
+
+static void
+emu_free_photo_info (PhotoInfo *pi)
+{
+	if (!pi)
+		return;
+
+	if (pi->address)
+		g_free (pi->address);
+	if (pi->photo)
+		e_contact_photo_free (pi->photo);
+	g_free (pi);
+}
+
+G_LOCK_DEFINE_STATIC (photos_cache);
+static GSList *photos_cache = NULL; /* list of PhotoInfo-s */
+
+CamelMimePart *
+em_utils_contact_photo (CamelInternetAddress *cia, gboolean local_only)
+{
+	const gchar *addr = NULL;
+	CamelMimePart *part = NULL;
+	EContactPhoto *photo = NULL;
+	GSList *p, *first_not_null = NULL;
+	gint count_not_null = 0;
+
+	if (cia == NULL || !camel_internet_address_get (cia, 0, NULL, &addr) || !addr) {
+		return NULL;
+	}
+
+	G_LOCK (photos_cache);
+
+	/* search a cache first */
+	for (p = photos_cache; p; p = p->next) {
+		PhotoInfo *pi = p->data;
+
+		if (!pi)
+			continue;
+
+		if (pi->photo) {
+			if (!first_not_null)
+				first_not_null = p;
+			count_not_null++;
+		}
+
+		if (g_ascii_strcasecmp (addr, pi->address) == 0) {
+			photo = pi->photo;
+			break;
+		}
+	}
+
+	/* !p means the address had not been found in the cache */
+	if (!p && search_address_in_addressbooks (addr, local_only, extract_photo_data, &photo)) {
+		PhotoInfo *pi;
+
+		if (photo && photo->type != E_CONTACT_PHOTO_TYPE_INLINED) {
+			e_contact_photo_free (photo);
+			photo = NULL;
+		}
+
+		/* keep only up to 10 photos in memory */
+		if (photo && count_not_null >= 10 && first_not_null) {
+			pi = first_not_null->data;
+
+			photos_cache = g_slist_remove (photos_cache, pi);
+
+			emu_free_photo_info (pi);
+		}
+
+		pi = g_new0 (PhotoInfo, 1);
+		pi->address = g_strdup (addr);
+		pi->photo = photo;
+
+		photos_cache = g_slist_append (photos_cache, pi);
+	}
+
+	/* some photo found, use it */
+	if (photo) {
+		/* Form a mime part out of the photo */
+		part = camel_mime_part_new ();
+		camel_mime_part_set_content(part,
+				    (const gchar *) photo->data.inlined.data,
+				    photo->data.inlined.length, "image/jpeg");
+	}
+
+	G_UNLOCK (photos_cache);
+
+	return part;
+}
+
+/* list of email addresses (strings) to remove from local cache of photos and contacts,
+   but only if the photo doesn't exist or is an not-found contact */
+void
+emu_remove_from_mail_cache (const GSList *addresses)
+{
+	const GSList *a;
+	GSList *p;
+	CamelInternetAddress *cia;
+
+	cia = camel_internet_address_new ();
+
+	for (a = addresses; a; a = a->next) {
+		const gchar *addr = NULL;
+
+		if (!a->data)
+			continue;
+
+		if (camel_address_decode ((CamelAddress *) cia, a->data) != -1 &&
+		    camel_internet_address_get (cia, 0, NULL, &addr) && addr) {
+			gchar *lowercase_addr = g_utf8_strdown (addr, -1);
+
+			G_LOCK (contact_cache);
+			if (g_hash_table_lookup (contact_cache, lowercase_addr) == NOT_FOUND_BOOK)
+				g_hash_table_remove (contact_cache, lowercase_addr);
+			G_UNLOCK (contact_cache);
+
+			g_free (lowercase_addr);
+
+			G_LOCK (photos_cache);
+			for (p = photos_cache; p; p = p->next) {
+				PhotoInfo *pi = p->data;
+
+				if (pi && !pi->photo && g_ascii_strcasecmp (pi->address, addr) == 0) {
+					photos_cache = g_slist_remove (photos_cache, pi);
+					emu_free_photo_info (pi);
+					break;
+				}
+			}
+			G_UNLOCK (photos_cache);
+		}
+	}
+
+	camel_object_unref (cia);
+}
+
+void
+emu_remove_from_mail_cache_1 (const gchar *address)
+{
+	GSList *l;
+
+	g_return_if_fail (address != NULL);
+
+	l = g_slist_append (NULL, (gpointer) address);
+
+	emu_remove_from_mail_cache (l);
+
+	g_slist_free (l);
+}
+
+/* frees all data created by call of em_utils_in_addressbook or em_utils_contact_photo */
+void
+emu_free_mail_cache (void)
+{
+	G_LOCK (contact_cache);
+
+	if (emu_books_hash) {
+		g_hash_table_destroy (emu_books_hash);
+		emu_books_hash = NULL;
+	}
+
+	if (emu_broken_books_hash) {
+		g_hash_table_destroy (emu_broken_books_hash);
+		emu_broken_books_hash = NULL;
+	}
+
+	if (emu_books_source_list) {
+		g_object_unref (emu_books_source_list);
+		emu_books_source_list = NULL;
+	}
+
+	if (contact_cache) {
+		g_hash_table_destroy (contact_cache);
+		contact_cache = NULL;
+	}
+
+	G_UNLOCK (contact_cache);
+
+	G_LOCK (photos_cache);
+
+	g_slist_foreach (photos_cache, (GFunc) emu_free_photo_info, NULL);
+	g_slist_free (photos_cache);
+	photos_cache = NULL;
+
+	G_UNLOCK (photos_cache);
+}
+
+void
+em_utils_clear_get_password_canceled_accounts_flag (void)
+{
+	EAccountList *accounts;
+
+	accounts = e_get_account_list ();
+	if (accounts) {
+		EIterator *iter;
+
+		for (iter = e_list_get_iterator ((EList *) accounts);
+		     e_iterator_is_valid (iter);
+		     e_iterator_next (iter)) {
+			EAccount *account = (EAccount *) e_iterator_get (iter);
+
+			if (account && account->source)
+				account->source->get_password_canceled = FALSE;
+
+			if (account && account->transport)
+				account->transport->get_password_canceled = FALSE;
+		}
+
+		g_object_unref (iter);
+	}
+}
+
+gchar *
+em_utils_url_unescape_amp (const gchar *url)
+{
+	gchar *buff;
+	gint i, j, amps;
+
+	if (!url)
+		return NULL;
+
+	amps = 0;
+	for (i = 0; url [i]; i++) {
+		if (url [i] == '&' && strncmp (url + i, "&amp;", 5) == 0)
+			amps++;
+	}
+
+	buff = g_strdup (url);
+
+	if (!amps)
+		return buff;
+
+	for (i = 0, j = 0; url [i]; i++, j++) {
+		buff [j] = url [i];
+
+		if (url [i] == '&' && strncmp (url + i, "&amp;", 5) == 0)
+			i += 4;
+	}
+	buff [j] = 0;
+
+	return buff;
+}
+
+static EAccount *
+guess_account_folder (CamelFolder *folder)
+{
+	EAccount *account;
+	gchar *tmp;
+
+	tmp = camel_url_to_string (CAMEL_SERVICE (folder->parent_store)->url, CAMEL_URL_HIDE_ALL);
+	account = mail_config_get_account_by_source_url (tmp);
+	g_free (tmp);
+
+	return account;
+}
+
+GHashTable *
+em_utils_generate_account_hash (void)
+{
+	GHashTable *account_hash;
+	EAccount *account, *def;
+	EAccountList *accounts;
+	EIterator *iter;
+
+	accounts = e_get_account_list ();
+	account_hash = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
+
+	def = e_get_default_account ();
+
+	iter = e_list_get_iterator ((EList *) accounts);
+	while (e_iterator_is_valid (iter)) {
+		account = (EAccount *) e_iterator_get (iter);
+
+		if (account->id->address) {
+			EAccount *acnt;
+
+			/* Accounts with identical email addresses that are enabled
+			 * take precedence over the accounts that aren't. If all
+			 * accounts with matching email addresses are disabled, then
+			 * the first one in the list takes precedence. The default
+			 * account always takes precedence no matter what.
+			 */
+			acnt = g_hash_table_lookup (account_hash, account->id->address);
+			if (acnt && acnt != def && !acnt->enabled && account->enabled) {
+				g_hash_table_remove (account_hash, acnt->id->address);
+				acnt = NULL;
+			}
+
+			if (!acnt)
+				g_hash_table_insert (account_hash, (gchar *) account->id->address, (gpointer) account);
+		}
+
+		e_iterator_next (iter);
+	}
+
+	g_object_unref (iter);
+
+	/* The default account has to be there if none of the enabled accounts are present */
+	if (g_hash_table_size (account_hash) == 0 && def && def->id->address)
+		g_hash_table_insert (account_hash, (gchar *) def->id->address, (gpointer) def);
+
+	return account_hash;
+}
+
+EAccount *
+em_utils_guess_account_with_recipients (CamelMimeMessage *message, CamelFolder *folder)
+{
+	GHashTable *account_hash = NULL;
+	EAccount *account = NULL;
+	const gchar *tmp;
+	gint i;
+	GList *l, *recipients = NULL;
+	const CamelInternetAddress *addr;
+
+	account = em_utils_guess_account (message, folder);
+	if (account)
+		return account;
+	addr = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_TO);
+	if (addr)
+		recipients = g_list_append (recipients, (gpointer) addr);
+	addr = camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_CC);
+	if (addr)
+		recipients = g_list_append (recipients, (gpointer) addr);
+
+	/* finally recipient (to/cc) in account table */
+	account_hash = em_utils_generate_account_hash ();
+	for (l = recipients; l == NULL; l = l->next) {
+		const CamelInternetAddress *to;
+
+		to = (CamelInternetAddress*)l->data;
+		if (to) {
+			for (i = 0; camel_internet_address_get(to, i, NULL, &tmp); i++) {
+				account = g_hash_table_lookup(account_hash, tmp);
+				if (account && account->enabled)
+					break;
+			}
+		}
+	}
+	g_hash_table_destroy(account_hash);
+
+	return account;
+}
+
+EAccount *
+em_utils_guess_account (CamelMimeMessage *message, CamelFolder *folder)
+{
+	EAccount *account = NULL;
+	const gchar *tmp;
+
+	/* check for newsgroup header */
+	if (folder
+	    && camel_medium_get_header ((CamelMedium *)message, "Newsgroups")
+	    && (account = guess_account_folder (folder)))
+		return account;
+
+	/* check for source folder */
+	if (folder)
+		account = guess_account_folder (folder);
+
+	/* then message source */
+	if (account == NULL
+	    && (tmp = camel_mime_message_get_source (message))) {
+		account = mail_config_get_account_by_source_url (tmp);
+	}
+
+	return account;
+}
diff --git a/mail/mail-utils.h b/mail/mail-utils.h
new file mode 100644
index 0000000..0d0fe3e
--- /dev/null
+++ b/mail/mail-utils.h
@@ -0,0 +1,75 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __MAIL_UTILS_H__
+#define __MAIL_UTILS_H__
+
+#include <sys/types.h>
+#include <camel/camel-exception.h>
+#include <camel/camel-folder.h>
+#include <camel/camel-internet-address.h>
+#include <camel/camel-mime-message.h>
+
+G_BEGIN_DECLS
+
+GPtrArray *em_utils_uids_copy (GPtrArray *uids);
+void em_utils_uids_free (GPtrArray *uids);
+
+gboolean em_utils_check_user_can_send_mail (void);
+
+void em_filename_make_safe (gchar *string);
+
+gboolean em_utils_folder_is_drafts(CamelFolder *folder, const gchar *uri);
+gboolean em_utils_folder_is_templates(CamelFolder *folder, const gchar *uri);
+gboolean em_utils_folder_is_sent(CamelFolder *folder, const gchar *uri);
+gboolean em_utils_folder_is_outbox(CamelFolder *folder, const gchar *uri);
+
+gchar *em_utils_get_proxy_uri (const gchar *uri);
+
+/* returns the folder name portion of an URI */
+gchar *em_utils_folder_name_from_uri (const gchar *uri);
+
+/* internal/camel uri translation */
+gchar *em_uri_from_camel (const gchar *curi);
+gchar *em_uri_to_camel (const gchar *euri);
+
+/* is this address in the addressbook?  caches results */
+gboolean em_utils_in_addressbook (CamelInternetAddress *addr, gboolean local_only);
+CamelMimePart *em_utils_contact_photo (CamelInternetAddress *addr, gboolean local);
+
+/* clears flag 'get_password_canceled' at every known accounts, so if needed, get_password will show dialog */
+void em_utils_clear_get_password_canceled_accounts_flag (void);
+
+/* Unescapes &amp; back to a real & in URIs */
+gchar *em_utils_url_unescape_amp (const gchar *url);
+
+GHashTable * em_utils_generate_account_hash (void);
+struct _EAccount *em_utils_guess_account (CamelMimeMessage *message, CamelFolder *folder);
+struct _EAccount *em_utils_guess_account_with_recipients (CamelMimeMessage *message, CamelFolder *folder);
+
+void emu_remove_from_mail_cache (const GSList *addresses);
+void emu_remove_from_mail_cache_1 (const gchar *address);
+void emu_free_mail_cache (void);
+
+G_END_DECLS
+
+#endif /* __MAIL_UTILS_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]