From 343f36cffe95db2943ba897b83bbb88a6c25c366 Mon Sep 17 00:00:00 2001 From: 3 Date: Tue, 23 Oct 2001 06:28:27 +0000 Subject: Completely re-done. We now hae a completely async dialogue when requested 2001-10-23 * mail-session.c (get_password): Completely re-done. We now hae a completely async dialogue when requested from antoehr thread, and dont use gtk_main() if we can avoid it (which is normally the case). This stuff is only partially finished, and will mena the removal of the same from mail-mt.c, and the mail_user_message() code will be moved here and changed to work in a similar way. * mail-callbacks.c (empty_trash): Dont try and connect to remote stores just to get the trash. Also, always run empty trash async, and make sure we unref the trash. (empty_trash): Hmm, dont unref the trash, causes a problem on exit, i suspect something else is doing funky unrefs on it. * mail-tools.c (mail_tool_get_trash): Pass a 'connect' arg, tell it whether it should tryand connect or not to the parent service, if it isn't already connected. * component-factory.c (owner_unset_cb): Dont try wait_all here, could potentially deadlock. (idle_quit): Keep returning TRUE if we have outstanding processing. Note that this may busy-wait during exit processign with busy tasks :( (idle_quit): Keep calling ourselves till we no longer get called (i.e. gtk_main really quits). * mail-mt.c (mail_msg_active): New function, returns TRUE if events are still active/outstanding. (do_op_status): @$@$#@@!#@!! didn't unlock the mail_msg_lock if data->activity was NULL and we had no global_shell_client anymore! Also shortcut processing if this is going to be the case. (mail_msg_init): Setup a temporary other gui_port for redoing with new semantics password, user message and progress reporting. (mail_get_password): #ifdef'd out all this code temporarily, till it gets fully moved to mail-session.c 2001-10-22 * component-factory.c (owner_set_cb): Dont call enable_interaction here. (interactive_cb): But here instead, let the shell tell us when its ok to go interactive. svn path=/trunk/; revision=13933 --- mail/ChangeLog | 44 ++++++++ mail/component-factory.c | 46 +++++--- mail/mail-callbacks.c | 18 +-- mail/mail-mt.c | 192 ++++++++++++++++++++++++-------- mail/mail-mt.h | 1 + mail/mail-session.c | 284 +++++++++++++++++++++++++++++++++++++++++------ mail/mail-tools.c | 16 ++- mail/mail-tools.h | 2 +- 8 files changed, 487 insertions(+), 116 deletions(-) (limited to 'mail') diff --git a/mail/ChangeLog b/mail/ChangeLog index 1bef9ae40d..f4745073ea 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,47 @@ +2001-10-23 + + * mail-session.c (get_password): Completely re-done. We now hae a + completely async dialogue when requested from antoehr thread, and + dont use gtk_main() if we can avoid it (which is normally the + case). This stuff is only partially finished, and will mena the + removal of the same from mail-mt.c, and the mail_user_message() + code will be moved here and changed to work in a similar way. + + * mail-callbacks.c (empty_trash): Dont try and connect to remote + stores just to get the trash. Also, always run empty trash async, + and make sure we unref the trash. + (empty_trash): Hmm, dont unref the trash, causes a problem on + exit, i suspect something else is doing funky unrefs on it. + + * mail-tools.c (mail_tool_get_trash): Pass a 'connect' arg, tell + it whether it should tryand connect or not to the parent service, + if it isn't already connected. + + * component-factory.c (owner_unset_cb): Dont try wait_all here, + could potentially deadlock. + (idle_quit): Keep returning TRUE if we have outstanding + processing. Note that this may busy-wait during exit processign + with busy tasks :( + (idle_quit): Keep calling ourselves till we no longer get called + (i.e. gtk_main really quits). + + * mail-mt.c (mail_msg_active): New function, returns TRUE if + events are still active/outstanding. + (do_op_status): @$@$#@@!#@!! didn't unlock the mail_msg_lock if + data->activity was NULL and we had no global_shell_client anymore! + Also shortcut processing if this is going to be the case. + (mail_msg_init): Setup a temporary other gui_port for redoing with + new semantics password, user message and progress reporting. + (mail_get_password): #ifdef'd out all this code temporarily, till + it gets fully moved to mail-session.c + +2001-10-22 + + * component-factory.c (owner_set_cb): Dont call enable_interaction + here. + (interactive_cb): But here instead, let the shell tell us when its + ok to go interactive. + 2001-10-22 Jeffrey Stedfast * mail-format.c (write_one_text_plain_chunk): Oops, revert my diff --git a/mail/component-factory.c b/mail/component-factory.c index d6603cb9cc..c4be75f94d 100644 --- a/mail/component-factory.c +++ b/mail/component-factory.c @@ -718,8 +718,6 @@ owner_set_cb (EvolutionShellComponent *shell_component, got_folder, standard_folders[i].folder, mail_thread_new)); } - mail_session_enable_interaction (TRUE); - mail_autoreceive_setup (); if (mail_config_is_corrupt ()) { @@ -753,6 +751,12 @@ debug_cb (EvolutionShellComponent *shell_component, gpointer user_data) camel_verbose_debug = 1; } +static void +interactive_cb (EvolutionShellComponent *shell_component, gboolean on, gpointer user_data) +{ + mail_session_enable_interaction(on); +} + static void handle_external_uri_cb (EvolutionShellComponent *shell_component, const char *uri, @@ -788,19 +792,32 @@ user_create_new_item_cb (EvolutionShellComponent *shell_component, static gboolean idle_quit (gpointer user_data) { - mail_msg_wait_all(); - - if (e_list_length (folder_browser_factory_get_control_list ())) - return TRUE; - - g_hash_table_foreach (storages_hash, free_storage, NULL); - g_hash_table_destroy (storages_hash); - - mail_vfolder_shutdown (); + static int shutdown_vfolder = FALSE; + static int shutdown_shutdown = FALSE; + if (!shutdown_shutdown) { + if (e_list_length (folder_browser_factory_get_control_list ())) + return TRUE; + + if (mail_msg_active(-1)) { + /* short sleep? */ + return TRUE; + } + + if (!shutdown_vfolder) { + shutdown_vfolder = TRUE; + mail_vfolder_shutdown(); + return TRUE; + } + + shutdown_shutdown = TRUE; + g_hash_table_foreach (storages_hash, free_storage, NULL); + g_hash_table_destroy (storages_hash); + } + gtk_main_quit (); - return FALSE; + return TRUE; } static void owner_unset_cb (EvolutionShellComponent *shell_component, gpointer user_data); @@ -814,6 +831,7 @@ static struct { { "owner_set", owner_set_cb, }, { "owner_unset", owner_unset_cb, }, { "debug", debug_cb, }, + { "interactive", interactive_cb }, { "destroy", owner_unset_cb, }, { "handle_external_uri", handle_external_uri_cb, }, { "user_create_new_item", user_create_new_item_cb } @@ -830,14 +848,12 @@ owner_unset_cb (EvolutionShellComponent *shell_component, gpointer user_data) if (mail_config_get_empty_trash_on_exit ()) empty_trash (NULL, NULL, NULL); - mail_msg_wait_all(); - unref_standard_folders (); mail_importer_uninit (); global_shell_client = NULL; - mail_session_enable_interaction (FALSE); + g_idle_add_full (G_PRIORITY_LOW, idle_quit, NULL, NULL); } diff --git a/mail/mail-callbacks.c b/mail/mail-callbacks.c index 2b7176aef3..f2e9db08fe 100644 --- a/mail/mail-callbacks.c +++ b/mail/mail-callbacks.c @@ -2391,13 +2391,9 @@ empty_trash (BonoboUIComponent *uih, void *user_data, const char *path) CamelFolder *vtrash; FolderBrowser *fb; CamelException ex; - gboolean async; fb = user_data ? FOLDER_BROWSER (user_data) : NULL; - /* the only time all three args are NULL is for empty-on-exit */ - async = !(uih == NULL && fb == NULL && path == NULL); - if (fb && !confirm_expunge (fb)) return; @@ -2415,13 +2411,10 @@ empty_trash (BonoboUIComponent *uih, void *user_data, const char *path) /* make sure this store is a remote store */ if (provider->flags & CAMEL_PROVIDER_IS_STORAGE && provider->flags & CAMEL_PROVIDER_IS_REMOTE) { - vtrash = mail_tool_get_trash (account->source->url, &ex); + vtrash = mail_tool_get_trash (account->source->url, FALSE, &ex); if (vtrash) { - if (async) - mail_expunge_folder (vtrash, empty_trash_expunged_cb, NULL); - else - camel_folder_sync (vtrash, TRUE, NULL); + mail_expunge_folder (vtrash, empty_trash_expunged_cb, NULL); } } } @@ -2433,12 +2426,9 @@ empty_trash (BonoboUIComponent *uih, void *user_data, const char *path) } /* Now empty the local trash folder */ - vtrash = mail_tool_get_trash ("file:/", &ex); + vtrash = mail_tool_get_trash ("file:/", TRUE, &ex); if (vtrash) { - if (async) - mail_expunge_folder (vtrash, empty_trash_expunged_cb, NULL); - else - camel_folder_sync (vtrash, TRUE, NULL); + mail_expunge_folder (vtrash, empty_trash_expunged_cb, NULL); } camel_exception_clear (&ex); diff --git a/mail/mail-mt.c b/mail/mail-mt.c index 2dd4109047..ab240d595f 100644 --- a/mail/mail-mt.c +++ b/mail/mail-mt.c @@ -35,6 +35,7 @@ /*#define MALLOC_CHECK*/ #define LOG_OPS +#define LOG_LOCKS #define d(x) static void set_stop(int sensitive); @@ -42,9 +43,13 @@ static void mail_enable_stop(void); static void mail_disable_stop(void); static void mail_operation_status(struct _CamelOperation *op, const char *what, int pc, void *data); +#ifdef LOG_LOCKS +#define MAIL_MT_LOCK(x) (log_locks?fprintf(log, "%ld: lock " # x "\n", pthread_self()):0, pthread_mutex_lock(&x)) +#define MAIL_MT_UNLOCK(x) (log_locks?fprintf(log, "%ld: unlock " # x "\n", pthread_self()): 0, pthread_mutex_unlock(&x)) +#else #define MAIL_MT_LOCK(x) pthread_mutex_lock(&x) #define MAIL_MT_UNLOCK(x) pthread_mutex_unlock(&x) - +#endif extern EvolutionShellClient *global_shell_client; /* background operation status stuff */ @@ -62,10 +67,11 @@ static GdkPixbuf *progress_icon[2] = { NULL, NULL }; /* mail_msg stuff */ #ifdef LOG_OPS static FILE *log; +static int log_ops, log_locks, log_init; #endif static unsigned int mail_msg_seq; /* sequence number of each message */ -static GHashTable *mail_msg_active; /* table of active messages, must hold mail_msg_lock to access */ +static GHashTable *mail_msg_active_table; /* table of active messages, must hold mail_msg_lock to access */ static pthread_mutex_t mail_msg_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t mail_msg_cond = PTHREAD_COND_INITIALIZER; @@ -81,13 +87,26 @@ void *mail_msg_new(mail_msg_op_t *ops, EMsgPort *reply_port, size_t size) MAIL_MT_LOCK(mail_msg_lock); -#ifdef LOG_OPS - if (log == NULL && getenv("EVOLUTION_MAIL_LOG_OPS") != NULL) { +#if defined(LOG_OPS) || defined(LOG_LOCKS) + if (!log_init) { time_t now = time(0); + log_init = TRUE; + log_ops = getenv("EVOLUTION_MAIL_LOG_OPS") != NULL; + log_locks = getenv("EVOLUTION_MAIL_LOG_LOCKS") != NULL; log = fopen("evolution-mail-ops.log", "w+"); setvbuf(log, NULL, _IOLBF, 0); fprintf(log, "Started evolution-mail: %s\n", ctime(&now)); +#ifdef LOG_OPS + if (log_ops) + fprintf(log, "Logging async operations\n"); +#endif +#ifdef LOG_LOCKS + if (log_locks) { + fprintf(log, "Logging lock operations, mail_gui_thread = %ld\n\n", mail_gui_thread); + fprintf(log, "%ld: lock mail_msg_lock\n", pthread_self()); + } +#endif g_warning("Logging mail operations to evolution-mail-ops.log"); } #endif @@ -99,12 +118,12 @@ void *mail_msg_new(mail_msg_op_t *ops, EMsgPort *reply_port, size_t size) camel_exception_init(&msg->ex); msg->priv = g_malloc0(sizeof(*msg->priv)); - g_hash_table_insert(mail_msg_active, (void *)msg->seq, msg); + g_hash_table_insert(mail_msg_active_table, (void *)msg->seq, msg); d(printf("New message %p\n", msg)); #ifdef LOG_OPS - if (log) + if (log_ops) fprintf(log, "%p: New\n", msg); #endif MAIL_MT_UNLOCK(mail_msg_lock); @@ -161,10 +180,10 @@ void mail_msg_free(void *msg) MAIL_MT_LOCK(mail_msg_lock); #ifdef LOG_OPS - if (log) + if (log_ops) fprintf(log, "%p: Free\n", msg); #endif - g_hash_table_remove(mail_msg_active, (void *)m->seq); + g_hash_table_remove(mail_msg_active_table, (void *)m->seq); pthread_cond_broadcast(&mail_msg_cond); /* We need to make sure we dont lose a reference here YUCK YUCK */ @@ -250,7 +269,7 @@ void mail_msg_cancel(unsigned int msgid) struct _mail_msg *m; MAIL_MT_LOCK(mail_msg_lock); - m = g_hash_table_lookup(mail_msg_active, (void *)msgid); + m = g_hash_table_lookup(mail_msg_active_table, (void *)msgid); if (m) camel_operation_cancel(m->cancel); @@ -268,32 +287,46 @@ void mail_msg_wait(unsigned int msgid) if (ismain) { MAIL_MT_LOCK(mail_msg_lock); - m = g_hash_table_lookup(mail_msg_active, (void *)msgid); + m = g_hash_table_lookup(mail_msg_active_table, (void *)msgid); while (m) { MAIL_MT_UNLOCK(mail_msg_lock); gtk_main_iteration(); MAIL_MT_LOCK(mail_msg_lock); - m = g_hash_table_lookup(mail_msg_active, (void *)msgid); + m = g_hash_table_lookup(mail_msg_active_table, (void *)msgid); } MAIL_MT_UNLOCK(mail_msg_lock); } else { MAIL_MT_LOCK(mail_msg_lock); - m = g_hash_table_lookup(mail_msg_active, (void *)msgid); + m = g_hash_table_lookup(mail_msg_active_table, (void *)msgid); while (m) { pthread_cond_wait(&mail_msg_cond, &mail_msg_lock); - m = g_hash_table_lookup(mail_msg_active, (void *)msgid); + m = g_hash_table_lookup(mail_msg_active_table, (void *)msgid); } MAIL_MT_UNLOCK(mail_msg_lock); } } +int mail_msg_active(unsigned int msgid) +{ + int active; + + MAIL_MT_LOCK(mail_msg_lock); + if (msgid == (unsigned int)-1) + active = g_hash_table_size(mail_msg_active_table) > 0; + else + active = g_hash_table_lookup(mail_msg_active_table, (void *)msgid) != NULL; + MAIL_MT_UNLOCK(mail_msg_lock); + + return active; +} + void mail_msg_wait_all(void) { int ismain = pthread_self() == mail_gui_thread; if (ismain) { MAIL_MT_LOCK(mail_msg_lock); - while (g_hash_table_size(mail_msg_active) > 0) { + while (g_hash_table_size(mail_msg_active_table) > 0) { MAIL_MT_UNLOCK(mail_msg_lock); gtk_main_iteration(); MAIL_MT_LOCK(mail_msg_lock); @@ -301,7 +334,7 @@ void mail_msg_wait_all(void) MAIL_MT_UNLOCK(mail_msg_lock); } else { MAIL_MT_LOCK(mail_msg_lock); - while (g_hash_table_size(mail_msg_active) > 0) { + while (g_hash_table_size(mail_msg_active_table) > 0) { pthread_cond_wait(&mail_msg_cond, &mail_msg_lock); } MAIL_MT_UNLOCK(mail_msg_lock); @@ -310,6 +343,12 @@ void mail_msg_wait_all(void) EMsgPort *mail_gui_port; static GIOChannel *mail_gui_channel; +static guint mail_gui_watch; + +EMsgPort *mail_gui_port2; +static GIOChannel *mail_gui_channel2; +static guint mail_gui_watch2; + EMsgPort *mail_gui_reply_port; static GIOChannel *mail_gui_reply_channel; @@ -333,7 +372,7 @@ mail_msgport_replied(GIOChannel *source, GIOCondition cond, void *d) #endif #ifdef LOG_OPS - if (log) + if (log_ops) fprintf(log, "%p: Replied to GUI thread\n", m); #endif @@ -360,7 +399,7 @@ mail_msgport_received(GIOChannel *source, GIOCondition cond, void *d) #endif #ifdef LOG_OPS - if (log) + if (log_ops) fprintf(log, "%p: Received at GUI thread\n", m); #endif @@ -378,6 +417,29 @@ mail_msgport_received(GIOChannel *source, GIOCondition cond, void *d) return TRUE; } +/* Test code, lighterwight, more configurable calls */ +static gboolean +mail_msgport_received2(GIOChannel *source, GIOCondition cond, void *d) +{ + EMsgPort *port = (EMsgPort *)d; + mail_msg_t *m; + + while (( m = (mail_msg_t *)e_msgport_get(port))) { +#ifdef LOG_OPS + if (log_ops) + fprintf(log, "%p: Received at GUI2 thread\n", m); +#endif + + if (m->ops->receive_msg) + m->ops->receive_msg(m); + else + mail_msg_free(m); + } + + return TRUE; +} + + static void mail_msg_destroy(EThread *e, EMsg *msg, void *data) { @@ -407,7 +469,7 @@ mail_msg_received(EThread *e, EMsg *msg, void *data) char *text = m->ops->describe_msg(m, FALSE); #ifdef LOG_OPS - if (log) + if (log_ops) fprintf(log, "%p: Received at thread %ld: '%s'\n", m, pthread_self(), text); #endif @@ -418,7 +480,7 @@ mail_msg_received(EThread *e, EMsg *msg, void *data) } #ifdef LOG_OPS else - if (log) + if (log_ops) fprintf(log, "%p: Received at thread %ld\n", m, pthread_self()); #endif @@ -457,7 +519,13 @@ void mail_msg_init(void) mail_gui_port = e_msgport_new(); mail_gui_channel = g_io_channel_unix_new(e_msgport_fd(mail_gui_port)); - g_io_add_watch(mail_gui_channel, G_IO_IN, mail_msgport_received, mail_gui_port); + mail_gui_watch = g_io_add_watch(mail_gui_channel, G_IO_IN, mail_msgport_received, mail_gui_port); + + /* experimental temporary */ + mail_gui_port2 = e_msgport_new(); + mail_gui_channel2 = g_io_channel_unix_new(e_msgport_fd(mail_gui_port2)); + mail_gui_watch2 = g_io_add_watch(mail_gui_channel2, G_IO_IN, mail_msgport_received2, mail_gui_port2); + mail_thread_queued = e_thread_new(E_THREAD_QUEUE); e_thread_set_msg_destroy(mail_thread_queued, mail_msg_destroy, 0); @@ -475,7 +543,7 @@ void mail_msg_init(void) e_thread_set_reply_port(mail_thread_new, mail_gui_reply_port); e_thread_set_queue_limit(mail_thread_new, 10); - mail_msg_active = g_hash_table_new(NULL, NULL); + mail_msg_active_table = g_hash_table_new(NULL, NULL); mail_gui_thread = pthread_self(); mail_async_event = mail_async_event_new(); @@ -488,6 +556,13 @@ static pthread_mutex_t status_lock = PTHREAD_MUTEX_INITIALIZER; /* ********************************************************************** */ +#if 0 +static GnomeDialog *password_dialogue = NULL; +static EDList password_list = E_DLIST_INITIALISER(password_list); +static struct _pass_msg *password_current = NULL; + +static void do_get_pass (struct _mail_msg *mm); + struct _pass_msg { struct _mail_msg msg; const char *prompt; @@ -496,12 +571,15 @@ struct _pass_msg { char *result; char *service_url; GtkWidget *check; + int inmain; }; static void pass_got (char *string, void *data) { struct _pass_msg *m = data; + + printf("password got! string = '%s'\n", string?string:""); if (string) { MailConfigService *service = NULL; @@ -533,6 +611,18 @@ pass_got (char *string, void *data) if (m->cache) *(m->cache) = remember; + + } + + if (!m->inmain) + e_msgport_reply((EMsg *)m); + + password_dialogue = NULL; + + m = e_dlist_remhead(&password_list); + if (m) { + printf("Have queued password request, showing now the other is finished\n"); + do_get_pass(m); } } @@ -546,10 +636,17 @@ do_get_pass (struct _mail_msg *mm) GList *children, *iter; gboolean show; char *title; - + + /* If we already have a password_dialogue up, save this request till later */ + if (!m->inmain && password_dialogue) { + e_dlist_addtail(&password_list, (EDListNode *)mm); + return; + } + + password_current = m; + /* this api is just awful ... hence the hacks */ - dialogue = gnome_request_dialog (m->secret, m->prompt, NULL, - 0, pass_got, m, NULL); + dialogue = gnome_request_dialog (m->secret, m->prompt, NULL, 0, pass_got, m, NULL); /* Remember the password? */ check = gtk_check_button_new_with_label (m->service_url ? _("Remember this password") : @@ -577,14 +674,12 @@ do_get_pass (struct _mail_msg *mm) /* do some dirty stuff to put the checkbutton after the entry */ entry = NULL; children = gtk_container_children (GTK_CONTAINER (GNOME_DIALOG (dialogue)->vbox)); - for (iter = children; iter; iter = iter->next) { if (GTK_IS_ENTRY (iter->data)) { entry = GTK_WIDGET (iter->data); break; } } - g_list_free (children); if (entry) { @@ -592,8 +687,7 @@ do_get_pass (struct _mail_msg *mm) gtk_container_remove (GTK_CONTAINER (GNOME_DIALOG (dialogue)->vbox), entry); } - gtk_box_pack_end (GTK_BOX (GNOME_DIALOG (dialogue)->vbox), - check, TRUE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (GNOME_DIALOG (dialogue)->vbox), check, TRUE, FALSE, 0); if (entry) { gtk_box_pack_end (GTK_BOX (GNOME_DIALOG (dialogue)->vbox), entry, TRUE, FALSE, 0); @@ -617,10 +711,16 @@ do_get_pass (struct _mail_msg *mm) gtk_window_set_title (GTK_WINDOW (dialogue), title); g_free (title); - - gnome_dialog_run_and_close ((GnomeDialog *)dialogue); - - /*gtk_widget_show(dialogue);*/ + + if (m->inmain) { + printf("showing dialogue in main\n"); + password_current = NULL; + gnome_dialog_run_and_close ((GnomeDialog *)dialogue); + e_msgport_reply((EMsg *)m); + } else { + printf("showing dialogue async\n"); + gtk_widget_show(dialogue); + } } static void @@ -653,23 +753,19 @@ mail_get_password (CamelService *service, const char *prompt, gboolean secret, g m->prompt = prompt; m->secret = secret; m->cache = cache; + m->inmain = pthread_self() == mail_gui_thread; if (service) { m->service_url = camel_url_to_string (service->url, CAMEL_URL_HIDE_ALL); } else m->service_url = NULL; - if (pthread_self () == mail_gui_thread) { + if (m->inmain) { do_get_pass ((struct _mail_msg *)m); r = m; } else { - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - - /* we want this single-threaded, this is the easiest way to do it without blocking ? */ - pthread_mutex_lock (&lock); - e_msgport_put (mail_gui_port, (EMsg *)m); + e_msgport_put (mail_gui_port2, (EMsg *)m); e_msgport_wait (pass_reply); r = (struct _pass_msg *)e_msgport_get (pass_reply); - pthread_mutex_unlock (&lock); } g_assert (r == m); @@ -682,6 +778,7 @@ mail_get_password (CamelService *service, const char *prompt, gboolean secret, g return ret; } +#endif /* ******************** */ @@ -948,7 +1045,6 @@ void *mail_call_main(mail_call_t type, MailMainFunc func, ...) return ret; } - /* ********************************************************************** */ /* locked via status_lock */ static int busy_state; @@ -1015,8 +1111,10 @@ static void do_op_status(struct _mail_msg *mm) MAIL_MT_LOCK (mail_msg_lock); - msg = g_hash_table_lookup (mail_msg_active, m->data); - if (msg == NULL) { + msg = g_hash_table_lookup (mail_msg_active_table, m->data); + + /* shortcut processing, i.e. if we have no global_shell_client and no activity, we can't create one */ + if (msg == NULL || (msg->priv->activity == NULL && global_shell_client == NULL)) { MAIL_MT_UNLOCK (mail_msg_lock); return; } @@ -1092,15 +1190,15 @@ static void do_op_status(struct _mail_msg *mm) } return; } - } - - activity = data->activity; - if (activity) { + } else if (data->activity) { + activity = data->activity; gtk_object_ref (GTK_OBJECT (activity)); MAIL_MT_UNLOCK (mail_msg_lock); - + evolution_activity_client_update (activity, out, (double)(pc/100.0)); gtk_object_unref (GTK_OBJECT (activity)); + } else { + MAIL_MT_UNLOCK (mail_msg_lock); } } diff --git a/mail/mail-mt.h b/mail/mail-mt.h index e3aebab7c5..96561d70ee 100644 --- a/mail/mail-mt.h +++ b/mail/mail-mt.h @@ -58,6 +58,7 @@ void mail_msg_check_error(void *msg); void mail_msg_cancel(unsigned int msgid); void mail_msg_wait(unsigned int msgid); void mail_msg_wait_all(void); +int mail_msg_active(unsigned int msgid); /* request a string/password */ char *mail_get_password (CamelService *service, const char *prompt, diff --git a/mail/mail-session.c b/mail/mail-session.c index 0101845f74..36dcb1e3be 100644 --- a/mail/mail-session.c +++ b/mail/mail-session.c @@ -39,6 +39,8 @@ #include "mail-mt.h" #include "e-util/e-passwords.h" +#define d(x) + CamelSession *session; @@ -130,55 +132,267 @@ make_key (CamelService *service, const char *item) return key; } -static char * -main_get_password (CamelSession *session, const char *prompt, gboolean secret, - CamelService *service, const char *item, CamelException *ex) +/* ********************************************************************** */ + +static GnomeDialog *password_dialogue = NULL; +static EDList password_list = E_DLIST_INITIALISER(password_list); +static struct _pass_msg *password_current = NULL; +static int password_destroy_id; + +struct _pass_msg { + struct _mail_msg msg; + + CamelSession *session; + const char *prompt; + gboolean secret; + CamelService *service; + const char *item; + CamelException *ex; + + char *service_url; + char *key; + + GtkWidget *check; + char *result; + int ismain; +}; + +static void do_get_pass(struct _mail_msg *mm); + +static void +pass_got (char *string, void *data) { - MailSession *mail_session = MAIL_SESSION (session); - gboolean cache = TRUE; - char *key, *ans; - - if (!strcmp (item, "popb4smtp_uri")) { - char *url = camel_url_to_string(service->url, 0); - const MailConfigAccount *account = mail_config_get_account_by_transport_url(url); + struct _pass_msg *m = data; + + if (string) { + MailConfigService *service = NULL; + const MailConfigAccount *mca; + gboolean remember; - g_free(url); - if (account == NULL) - return NULL; + m->result = g_strdup (string); + remember = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (m->check)); + if (m->service_url) { + mca = mail_config_get_account_by_source_url (m->service_url); + if (mca) { + service = mca->source; + } else { + mca = mail_config_get_account_by_transport_url (m->service_url); + if (mca) + service = mca->transport; + } + + if (service) { + mail_config_service_set_save_passwd (service, remember); + + /* set `remember' to TRUE because people don't want to have to + re-enter their passwords for this session even if they told + us not to cache their passwords in the dialog...*sigh* */ + remember = TRUE; + } + } - return g_strdup(account->source->url); + if (remember) + e_passwords_add_password(m->key, m->result); + } else { + camel_exception_set(m->ex, CAMEL_EXCEPTION_USER_CANCEL, _("User canceled operation.")); } - - key = make_key (service, item); - if (!key) - return NULL; - ans = e_passwords_get_password (key); - if (ans) { - g_free (key); - return ans; + if (password_destroy_id) { + gtk_signal_disconnect((GtkObject *)password_dialogue, password_destroy_id); + password_destroy_id = 0; } + + password_dialogue = NULL; + e_msgport_reply((EMsg *)m); + + if ((m = (struct _pass_msg *)e_dlist_remhead(&password_list))) + do_get_pass((struct _mail_msg *)m); +} + +static void +request_password_deleted(GtkWidget *w, struct _pass_msg *m) +{ + password_destroy_id = 0; + pass_got(NULL, m); +} + +static void +request_password(struct _pass_msg *m) +{ + const MailConfigAccount *mca = NULL; + GtkWidget *dialogue; + GtkWidget *check, *entry; + GList *children, *iter; + gboolean show; + char *title; + + /* If we already have a password_dialogue up, save this request till later */ + if (!m->ismain && password_dialogue) { + e_dlist_addtail(&password_list, (EDListNode *)m); + return; + } + + password_current = m; + + /* FIXME: Remove this total snot */ + + /* this api is just awful ... hence the major hacks */ + password_dialogue = dialogue = gnome_request_dialog (m->secret, m->prompt, NULL, 0, pass_got, m, NULL); + + /* cant bleieve how @!@#!@# 5this api is, it doesn't handle this for you, BLAH! */ + password_destroy_id = gtk_signal_connect((GtkObject *)dialogue, "destroy", request_password_deleted, m); + + /* Remember the password? */ + check = gtk_check_button_new_with_label (m->service_url ? _("Remember this password") : + _("Remember this password for the remainder of this session")); + show = TRUE; - if (!mail_session->interaction_enabled || - !(ans = mail_get_password (service, prompt, secret, &cache))) { - g_free (key); - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - _("User canceled operation.")); - return NULL; + if (m->service_url) { + mca = mail_config_get_account_by_source_url(m->service_url); + if (mca) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), mca->source->save_passwd); + else { + mca = mail_config_get_account_by_transport_url (m->service_url); + if (mca) + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), mca->transport->save_passwd); + else { + d(printf ("Cannot figure out which account owns URL \"%s\"\n", m->service_url)); + show = FALSE; + } + } } - if (cache) - e_passwords_add_password (key, ans); + if (show) + gtk_widget_show (check); + + /* do some dirty stuff to put the checkbutton after the entry */ + entry = NULL; + children = gtk_container_children (GTK_CONTAINER (GNOME_DIALOG (dialogue)->vbox)); + for (iter = children; iter; iter = iter->next) { + if (GTK_IS_ENTRY (iter->data)) { + entry = GTK_WIDGET (iter->data); + break; + } + } + g_list_free (children); + + if (entry) { + gtk_object_ref (GTK_OBJECT (entry)); + gtk_container_remove (GTK_CONTAINER (GNOME_DIALOG (dialogue)->vbox), entry); + } + + gtk_box_pack_end (GTK_BOX (GNOME_DIALOG (dialogue)->vbox), check, TRUE, FALSE, 0); + + if (entry) { + gtk_box_pack_end (GTK_BOX (GNOME_DIALOG (dialogue)->vbox), entry, TRUE, FALSE, 0); + gtk_widget_grab_focus (entry); + gtk_object_unref (GTK_OBJECT (entry)); + } + + m->check = check; + + if (mca) { + char *name; + + name = e_utf8_to_gtk_string (GTK_WIDGET (dialogue), mca->name); + title = g_strdup_printf (_("Enter Password for %s"), name); + g_free (name); + } else + title = g_strdup (_("Enter Password")); + + gtk_window_set_title (GTK_WINDOW (dialogue), title); + g_free (title); + + if (m->ismain) { + password_current = NULL; + gnome_dialog_run_and_close ((GnomeDialog *)dialogue); + } else { + gtk_widget_show(dialogue); + } +} + +static void +do_get_pass(struct _mail_msg *mm) +{ + struct _pass_msg *m = (struct _pass_msg *)mm; + MailSession *mail_session = MAIL_SESSION (m->session); + + if (!strcmp (m->item, "popb4smtp_uri")) { + char *url = camel_url_to_string(m->service->url, 0); + const MailConfigAccount *account = mail_config_get_account_by_transport_url(url); + + g_free(url); + if (account) + m->result = g_strdup(account->source->url); + } else if (m->key) { + m->result = e_passwords_get_password(m->key); + if (m->result == NULL) { + if (mail_session->interaction_enabled) { + request_password(m); + return; + } + } + } + + e_msgport_reply((EMsg *)mm); +} - return ans; +static void +do_free_pass(struct _mail_msg *mm) +{ + struct _pass_msg *m = (struct _pass_msg *)mm; + + g_free(m->service_url); + g_free(m->key); } +static struct _mail_msg_op get_pass_op = { + NULL, + do_get_pass, + NULL, + do_free_pass, +}; + static char * -get_password (CamelSession *session, const char *prompt, gboolean secret, - CamelService *service, const char *item, CamelException *ex) +get_password (CamelSession *session, const char *prompt, gboolean secret, CamelService *service, const char *item, CamelException *ex) { - return (char *)mail_call_main(MAIL_CALL_p_ppippp, (MailMainFunc)main_get_password, - session, prompt, secret, service, item, ex); + struct _pass_msg *m, *r; + EMsgPort *pass_reply; + char *ret; + + /* We setup an async request and send it off, and wait for it to return */ + /* If we're really in main, we dont of course ... + ... but this shouldn't be allowed because of locking issues */ + pass_reply = e_msgport_new (); + m = mail_msg_new(&get_pass_op, pass_reply, sizeof(struct _pass_msg)); + m->ismain = pthread_self() == mail_gui_thread; + m->session = session; + m->prompt = prompt; + m->secret = secret; + m->service = service; + m->item = item; + m->ex = ex; + if (service) + m->service_url = camel_url_to_string (service->url, CAMEL_URL_HIDE_ALL); + m->key = make_key(service, item); + + if (m->ismain) + do_get_pass(m); + else { + extern EMsgPort *mail_gui_port2; + + e_msgport_put(mail_gui_port2, (EMsg *)m); + } + + e_msgport_wait(pass_reply); + r = (struct _pass_msg *)e_msgport_get(pass_reply); + g_assert(m == r); + + ret = m->result; + mail_msg_free(m); + e_msgport_destroy(pass_reply); + + return ret; } static void diff --git a/mail/mail-tools.c b/mail/mail-tools.c index 96ef278567..383060d2b8 100644 --- a/mail/mail-tools.c +++ b/mail/mail-tools.c @@ -93,16 +93,24 @@ mail_tool_get_inbox (const gchar *url, CamelException *ex) } CamelFolder * -mail_tool_get_trash (const gchar *url, CamelException *ex) +mail_tool_get_trash (const gchar *url, int connect, CamelException *ex) { CamelStore *store; CamelFolder *trash; - - store = camel_session_get_store (session, url, ex); + + if (connect) + store = camel_session_get_store (session, url, ex); + else + store = (CamelStore *)camel_session_get_service(session, url, CAMEL_PROVIDER_STORE, ex); + if (!store) return NULL; - trash = camel_store_get_trash (store, ex); + if (connect || ((CamelService *)store)->status == CAMEL_SERVICE_CONNECTED) + trash = camel_store_get_trash (store, ex); + else + trash = NULL; + camel_object_unref (CAMEL_OBJECT (store)); return trash; diff --git a/mail/mail-tools.h b/mail/mail-tools.h index d19d6553ca..37afb8666c 100644 --- a/mail/mail-tools.h +++ b/mail/mail-tools.h @@ -47,7 +47,7 @@ CamelFolder *mail_tool_get_local_inbox (CamelException *ex); CamelFolder *mail_tool_get_inbox (const gchar *url, CamelException *ex); /* Get the "trash" for a url (uses global session) */ -CamelFolder *mail_tool_get_trash (const gchar *url, CamelException *ex); +CamelFolder *mail_tool_get_trash (const gchar *url, int connect, CamelException *ex); /* Does a camel_movemail into the local movemail folder * and returns the path to the new movemail folder that was created. which shoudl be freed later */ -- cgit v1.2.3