diff options
-rw-r--r-- | mail/ChangeLog | 35 | ||||
-rw-r--r-- | mail/mail-config.c | 10 | ||||
-rw-r--r-- | mail/mail-mt.c | 320 | ||||
-rw-r--r-- | mail/mail-session.c | 447 |
4 files changed, 414 insertions, 398 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index 89c05dd99f..61738bea97 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,35 @@ +2001-10-23 <NotZed@Ximian.com> + + * mail-mt.c (mail_user_message): + (mail_get_password): Removed, all functionality moved to + mail-session. + + * mail-config.c (mail_config_write_on_exit): Check + threaded/preview hash is null before using it, its setup on demand + so itmight nto be initialised here. + + * mail-session.c (request_password): Remove password_current + stuff. + (alert_user): Redont, similar to get_pass. Do things as async as + possible, and dont even wait for a response if we're not asking + for the cancel button (this may or may not be right behaviour - + need to check). mail_user_message() code replaced from the stuff + in mail-mt.c + (MailSession): Added a lock field. + (init): Setup lock. + (finalise): fRee lock. + (register_timeout): Redone. We now allocate our own 'timeoutid's, + and <> to the real things asynchronously. Use async_event's so we + can make sure we have no outstanding ones after shutdown. + (mail_session_enable_interaction): If interaction has been + disabled, and we have either a message-box open, or a password + request open and/or any pending message boxes/passwords, blow 'em + away. + (main_register_timeout): If we have pending remove of this same + timeout, dont do anything. + (timeout_timeout): Properly honour the result, remove the timout + if it returns false. + 2001-10-23 Jeffrey Stedfast <fejj@ximian.com> * mail-callbacks.c (reply_to_sender): Make sure the fb and it's @@ -34,6 +66,9 @@ * mail-mt.c: Added missing errno.h (mail_msg_new): Fix the logic a bit, dont try to open the log file unless logging is actually requested. + (mail_enable_stop, mail_disable_stop, do_set_busy, + mail_operation_statys): Dont bother propagating events if + global_shell_client isn't up yet. 2001-10-23 Dan Winship <danw@ximian.com> diff --git a/mail/mail-config.c b/mail/mail-config.c index 9e66eea531..772ff76428 100644 --- a/mail/mail-config.c +++ b/mail/mail-config.c @@ -875,12 +875,12 @@ mail_config_write_on_exit (void) bonobo_config_set_string_wrapper (config->db, "/Mail/Filters/log_path", config->filter_log_path, NULL); + + if (config->threaded_hash) + g_hash_table_foreach_remove (config->threaded_hash, hash_save_state, "Threads"); - g_hash_table_foreach_remove (config->threaded_hash, - hash_save_state, "Threads"); - - g_hash_table_foreach_remove (config->preview_hash, - hash_save_state, "Preview"); + if (config->preview_hash) + g_hash_table_foreach_remove (config->preview_hash, hash_save_state, "Preview"); CORBA_exception_init (&ev); Bonobo_ConfigDatabase_sync (config->db, &ev); diff --git a/mail/mail-mt.c b/mail/mail-mt.c index 3f45617b84..9c0c9bb18a 100644 --- a/mail/mail-mt.c +++ b/mail/mail-mt.c @@ -351,6 +351,7 @@ EMsgPort *mail_gui_port; static GIOChannel *mail_gui_channel; static guint mail_gui_watch; +/* TODO: Merge these, gui_port2 doesn't do any mail_msg processing on the request (replies, forwards, frees) */ EMsgPort *mail_gui_port2; static GIOChannel *mail_gui_channel2; static guint mail_gui_watch2; @@ -562,315 +563,6 @@ 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; - gboolean secret; - gboolean *cache; - 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:"<nil>"); - - if (string) { - MailConfigService *service = NULL; - const MailConfigAccount *mca; - gboolean remember; - - 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; - } - } - - 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); - } -} - -static void -do_get_pass (struct _mail_msg *mm) -{ - struct _pass_msg *m = (struct _pass_msg *)mm; - 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->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); - - /* 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 (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 (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; - - /* hrm, we can't run this async since the gui_port from which we're called - will reply to our message for us */ - - 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->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 -do_free_pass(struct _mail_msg *mm) -{ - /*struct _pass_msg *m = (struct _pass_msg *)mm;*/ - - /* the string is passed out so we dont need to free it */ -} - -struct _mail_msg_op get_pass_op = { - NULL, - do_get_pass, - NULL, - do_free_pass, -}; - -/* returns the password, or NULL if cancelled */ -char * -mail_get_password (CamelService *service, const char *prompt, gboolean secret, gboolean *cache) -{ - char *ret; - struct _pass_msg *m, *r; - EMsgPort *pass_reply; - - pass_reply = e_msgport_new (); - - m = mail_msg_new (&get_pass_op, pass_reply, sizeof (struct _pass_msg)); - - 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 (m->inmain) { - do_get_pass ((struct _mail_msg *)m); - r = m; - } else { - e_msgport_put (mail_gui_port2, (EMsg *)m); - e_msgport_wait (pass_reply); - r = (struct _pass_msg *)e_msgport_get (pass_reply); - } - - g_assert (r == m); - - ret = m->result; - - g_free (m->service_url); - mail_msg_free (m); - e_msgport_destroy (pass_reply); - - return ret; -} -#endif - -/* ******************** */ - -/* ********************************************************************** */ - -struct _user_message_msg { - struct _mail_msg msg; - const char *type; - const char *prompt; - gboolean allow_cancel; - gboolean result; -}; - -static void -do_user_message (struct _mail_msg *mm) -{ - struct _user_message_msg *m = (struct _user_message_msg *)mm; - int dialog_result; - GtkWidget *dialog; - - dialog = gnome_message_box_new (m->prompt, m->type, - GNOME_STOCK_BUTTON_OK, - m->allow_cancel ? GNOME_STOCK_BUTTON_CANCEL : NULL, - NULL); - gnome_dialog_set_default (GNOME_DIALOG (dialog), 1); - gtk_window_set_policy (GTK_WINDOW (dialog), TRUE, TRUE, TRUE); - - /* hrm, we can't run this async since the gui_port from which we're called - will reply to our message for us */ - dialog_result = gnome_dialog_run_and_close (GNOME_DIALOG (dialog)); - - if (dialog_result == -1 || dialog_result == 1) - m->result = FALSE; - else - m->result = TRUE; -} - -struct _mail_msg_op user_message_op = { - NULL, - do_user_message, - NULL, - NULL, -}; - -/* prompt the user with a yes/no question and return the response */ -gboolean -mail_user_message (const char *type, const char *prompt, gboolean allow_cancel) -{ - struct _user_message_msg *m, *r; - EMsgPort *user_message_reply; - gboolean accept; - - user_message_reply = e_msgport_new (); - - m = mail_msg_new (&user_message_op, user_message_reply, sizeof (*m)); - - m->type = type; - m->prompt = prompt; - m->allow_cancel = allow_cancel; - - if (pthread_self () == mail_gui_thread) { - do_user_message ((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_wait (user_message_reply); - r = (struct _user_message_msg *)e_msgport_get (user_message_reply); - pthread_mutex_unlock (&lock); - } - - g_assert (r == m); - - accept = m->result; - - mail_msg_free (m); - e_msgport_destroy (user_message_reply); - - return accept; -} - -/* ******************** */ - struct _proxy_msg { struct _mail_msg msg; MailAsyncEvent *ea; @@ -1057,7 +749,8 @@ static int busy_state; static void do_set_busy(struct _mail_msg *mm) { - set_stop(busy_state > 0); + if (global_shell_client) + set_stop(busy_state > 0); } struct _mail_msg_op set_busy_op = { @@ -1073,7 +766,7 @@ static void mail_enable_stop(void) MAIL_MT_LOCK(status_lock); busy_state++; - if (busy_state == 1) { + if (busy_state == 1 && global_shell_client) { m = mail_msg_new(&set_busy_op, NULL, sizeof(*m)); e_msgport_put(mail_gui_port, (EMsg *)m); } @@ -1086,7 +779,7 @@ static void mail_disable_stop(void) MAIL_MT_LOCK(status_lock); busy_state--; - if (busy_state == 0) { + if (busy_state == 0 && global_shell_client) { m = mail_msg_new(&set_busy_op, NULL, sizeof(*m)); e_msgport_put(mail_gui_port, (EMsg *)m); } @@ -1229,6 +922,9 @@ mail_operation_status (struct _CamelOperation *op, const char *what, int pc, voi struct _op_status_msg *m; d(printf("got operation statys: %s %d%%\n", what, pc)); + + if (global_shell_client == NULL) + return; m = mail_msg_new(&op_status_op, NULL, sizeof(*m)); m->op = op; diff --git a/mail/mail-session.c b/mail/mail-session.c index 36dcb1e3be..662d80acb7 100644 --- a/mail/mail-session.c +++ b/mail/mail-session.c @@ -30,6 +30,9 @@ #include <libgnomeui/gnome-dialog-util.h> #include <libgnomeui/gnome-messagebox.h> #include <libgnomeui/gnome-stock.h> + +#include <gal/widgets/e-unicode.h> + #include "camel/camel-filter-driver.h" #include "filter/filter-context.h" #include "filter/filter-filter.h" @@ -38,6 +41,7 @@ #include "mail-tools.h" #include "mail-mt.h" #include "e-util/e-passwords.h" +#include "e-util/e-msgport.h" #define d(x) @@ -49,12 +53,22 @@ CamelSession *session; #define MAIL_SESSION_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_SESSION_TYPE, MailSessionClass)) #define MAIL_IS_SESSION(o) (CAMEL_CHECK_TYPE((o), MAIL_SESSION_TYPE)) +#define MAIL_SESSION_LOCK(s, l) (e_mutex_lock(((MailSession *)s)->l)) +#define MAIL_SESSION_UNLOCK(s, l) (e_mutex_unlock(((MailSession *)s)->l)) typedef struct _MailSession { CamelSession parent_object; gboolean interaction_enabled; FILE *filter_logfile; + + EMutex *lock; + + MailAsyncEvent *async; + + /* must all be accessed with lock held ! */ + unsigned int timeout_id;/* next camel timneout id */ + EDList timeouts; /* list of struct _timeout_data's of current or pending removed timeouts */ } MailSession; typedef struct _MailSessionClass { @@ -62,32 +76,33 @@ typedef struct _MailSessionClass { } MailSessionClass; - -static char *get_password (CamelSession *session, const char *prompt, - gboolean secret, CamelService *service, - const char *item, CamelException *ex); -static void forget_password (CamelSession *session, CamelService *service, - const char *item, CamelException *ex); -static gboolean alert_user (CamelSession *session, CamelSessionAlertType type, - const char *prompt, gboolean cancel); -static guint register_timeout (CamelSession *session, guint32 interval, - CamelTimeoutCallback cb, gpointer camel_data); -static gboolean remove_timeout (CamelSession *session, guint handle); -static CamelFilterDriver *get_filter_driver (CamelSession *session, - const char *type, - CamelException *ex); - +static char *get_password(CamelSession *session, const char *prompt, gboolean secret, CamelService *service, const char *item, CamelException *ex); +static void forget_password(CamelSession *session, CamelService *service, const char *item, CamelException *ex); +static gboolean alert_user(CamelSession *session, CamelSessionAlertType type, const char *prompt, gboolean cancel); +static guint register_timeout(CamelSession *session, guint32 interval, CamelTimeoutCallback cb, gpointer camel_data); +static gboolean remove_timeout(CamelSession *session, guint handle); +static CamelFilterDriver *get_filter_driver(CamelSession *session, const char *type, CamelException *ex); static void init (MailSession *session) { + session->lock = e_mutex_new(E_MUTEX_REC); + session->timeout_id = 1; /* first timeout id */ + session->async = mail_async_event_new(); + e_dlist_init(&session->timeouts); +} + +static void +finalise (MailSession *session) +{ + mail_async_event_destroy(session->async); + e_mutex_destroy(session->lock); } static void class_init (MailSessionClass *mail_session_class) { - CamelSessionClass *camel_session_class = - CAMEL_SESSION_CLASS (mail_session_class); + CamelSessionClass *camel_session_class = CAMEL_SESSION_CLASS (mail_session_class); /* virtual method override */ camel_session_class->get_password = get_password; @@ -112,7 +127,7 @@ mail_session_get_type (void) (CamelObjectClassInitFunc) class_init, NULL, (CamelObjectInitFunc) init, - NULL); + (CamelObjectFinalizeFunc) finalise); } return mail_session_type; @@ -136,7 +151,6 @@ make_key (CamelService *service, const char *item) 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 { @@ -232,12 +246,10 @@ request_password(struct _pass_msg *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); + password_dialogue = (GnomeDialog *)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); @@ -303,12 +315,10 @@ request_password(struct _pass_msg *m) gtk_window_set_title (GTK_WINDOW (dialogue), title); g_free (title); - if (m->ismain) { - password_current = NULL; + if (m->ismain) gnome_dialog_run_and_close ((GnomeDialog *)dialogue); - } else { + else gtk_widget_show(dialogue); - } } static void @@ -377,7 +387,7 @@ get_password (CamelSession *session, const char *prompt, gboolean secret, CamelS m->key = make_key(service, item); if (m->ismain) - do_get_pass(m); + do_get_pass((struct _mail_msg *)m); else { extern EMsgPort *mail_gui_port2; @@ -412,60 +422,249 @@ forget_password (CamelSession *session, CamelService *service, const char *item, session, service, item, ex); } -static gboolean -alert_user (CamelSession *session, CamelSessionAlertType type, - const char *prompt, gboolean cancel) +/* ********************************************************************** */ + +static GnomeDialog *message_dialogue; +static EDList message_list = E_DLIST_INITIALISER(password_list); +static guint message_destroy_id; + +struct _user_message_msg { + struct _mail_msg msg; + + CamelSessionAlertType type; + const char *prompt; + + unsigned int allow_cancel:1; + unsigned int result:1; + unsigned int ismain:1; +}; + +static void do_user_message (struct _mail_msg *mm); + +/* if we dont have to wait for reply, we just check to see if any newly waiting prompts are there */ +static void +user_message_destroy_noreply(GnomeDialog *gd, void *data) { - MailSession *mail_session = MAIL_SESSION (session); - const char *message_type = NULL; - - if (!mail_session->interaction_enabled) - return FALSE; - - switch (type) { + struct _user_message_msg *m; + + message_dialogue = NULL; + if ((m = (struct _user_message_msg *)e_dlist_remhead(&message_list))) + do_user_message((struct _mail_msg *)m); +} + +/* clicked, send back the reply */ +static void +user_message_clicked(GnomeDialog *gd, int button, struct _user_message_msg *m) +{ + message_dialogue = NULL; + + if (message_destroy_id) { + gtk_signal_disconnect((GtkObject *)gd, message_destroy_id); + message_destroy_id = 0; + } + + m->result = button == 0; + e_msgport_reply((EMsg *)m); + + /* check for pendings */ + if ((m = (struct _user_message_msg *)e_dlist_remhead(&message_list))) + do_user_message((struct _mail_msg *)m); +} + +static void +user_message_destroy(GnomeDialog *gd, struct _user_message_msg *m) +{ + message_destroy_id = 0; + user_message_clicked(gd, -1, m); +} + +static void +do_user_message (struct _mail_msg *mm) +{ + struct _user_message_msg *m = (struct _user_message_msg *)mm; + const char *msg_type; + + if (!m->ismain && message_dialogue != NULL) { + e_dlist_addtail(&message_list, (EDListNode *)m); + return; + } + + switch (m->type) { case CAMEL_SESSION_ALERT_INFO: - message_type = GNOME_MESSAGE_BOX_INFO; + msg_type = GNOME_MESSAGE_BOX_INFO; break; case CAMEL_SESSION_ALERT_WARNING: - message_type = GNOME_MESSAGE_BOX_WARNING; + msg_type = GNOME_MESSAGE_BOX_WARNING; break; case CAMEL_SESSION_ALERT_ERROR: - message_type = GNOME_MESSAGE_BOX_ERROR; + msg_type = GNOME_MESSAGE_BOX_ERROR; break; + default: + msg_type = NULL; + } + + message_dialogue = (GnomeDialog *)gnome_message_box_new(m->prompt, msg_type, GNOME_STOCK_BUTTON_OK, + m->allow_cancel ? GNOME_STOCK_BUTTON_CANCEL : NULL, + NULL); + gnome_dialog_set_default(message_dialogue, 1); + gnome_dialog_set_close(message_dialogue, TRUE); + gtk_window_set_policy (GTK_WINDOW (message_dialogue), TRUE, TRUE, TRUE); + + /* We only need to wait for the result if we allow cancel otherwise show but send result back instantly */ + if (m->allow_cancel) { + gtk_signal_connect((GtkObject*)message_dialogue, "clicked", user_message_clicked, m); + gtk_signal_connect((GtkObject*)message_dialogue, "destroy", user_message_destroy, m); + if (m->ismain) + gnome_dialog_run_and_close ((GnomeDialog *)message_dialogue); + else + gtk_widget_show((GtkWidget *)message_dialogue); + } else { + gtk_signal_connect((GtkObject *)message_dialogue, "destroy", user_message_destroy_noreply, NULL); + gtk_widget_show((GtkWidget *)message_dialogue); + m->result = TRUE; + e_msgport_reply((EMsg *)m); } - return mail_user_message (message_type, prompt, cancel); +} + +static struct _mail_msg_op user_message_op = { NULL, do_user_message, NULL, NULL }; + +static gboolean +alert_user(CamelSession *session, CamelSessionAlertType type, const char *prompt, gboolean cancel) +{ + MailSession *mail_session = MAIL_SESSION (session); + struct _user_message_msg *m, *r; + EMsgPort *user_message_reply; + gboolean ret; + + if (!mail_session->interaction_enabled) + return FALSE; + + user_message_reply = e_msgport_new (); + m = mail_msg_new (&user_message_op, user_message_reply, sizeof (*m)); + m->ismain = pthread_self() == mail_gui_thread; + m->type = type; + m->prompt = prompt; + m->allow_cancel = cancel; + + if (m->ismain) + do_user_message((struct _mail_msg *)m); + else { + extern EMsgPort *mail_gui_port2; + + e_msgport_put(mail_gui_port2, (EMsg *)m); + } + + e_msgport_wait(user_message_reply); + r = (struct _user_message_msg *)e_msgport_get(user_message_reply); + g_assert(m == r); + + ret = m->result; + mail_msg_free(m); + e_msgport_destroy(user_message_reply); + + return ret; } /* ******************** */ struct _timeout_data { - CamelTimeoutCallback cb; + struct _timeout_data *next; + struct _timeout_data *prev; + + CamelSession *session; + guint32 interval; + + CamelTimeoutCallback cb; void *camel_data; - int result; + + guint id; /* the camel 'id' */ + guint timeout_id; /* the gtk 'id' */ + + unsigned int busy:1; /* on if its currently running */ + unsigned int removed:1; /* if its been removed since */ }; struct _timeout_msg { struct _mail_msg msg; - - CamelTimeoutCallback cb; - gpointer camel_data; + + CamelSession *session; + unsigned int id; + int result; }; +static struct _timeout_data * +find_timeout(EDList *list, unsigned int id) +{ + struct _timeout_data *td, *tn; + + td = (struct _timeout_data *)list->head; + tn = td->next; + while (tn) { + if (td->id == id) + return td; + td = tn; + tn = tn->next; + } + + return NULL; +} + static void timeout_timeout (struct _mail_msg *mm) { struct _timeout_msg *m = (struct _timeout_msg *)mm; - - /* we ignore the callback result, do we care?? no. */ - m->cb (m->camel_data); + MailSession *ms = (MailSession *)m->session; + struct _timeout_data *td; + + MAIL_SESSION_LOCK(ms, lock); + td = find_timeout(&ms->timeouts, m->id); + if (td && !td->removed) { + if (td->busy) { + g_warning("Timeout event dropped, still busy with last one"); + } else { + td->busy = TRUE; + m->result = td->cb(td->camel_data); + td->busy = FALSE; + td->removed = !m->result; + } + } + MAIL_SESSION_UNLOCK(ms, lock); +} + +static void +timeout_done(struct _mail_msg *mm) +{ + struct _timeout_msg *m = (struct _timeout_msg *)mm; + MailSession *ms = (MailSession *)m->session; + struct _timeout_data *td; + + if (!m->result) { + MAIL_SESSION_LOCK(ms, lock); + td = find_timeout(&ms->timeouts, m->id); + if (td) { + e_dlist_remove((EDListNode *)td); + if (td->timeout_id) + gtk_timeout_remove(td->timeout_id); + g_free(td); + } + MAIL_SESSION_UNLOCK(ms, lock); + } +} + +static void +timeout_free(struct _mail_msg *mm) +{ + struct _timeout_msg *m = (struct _timeout_msg *)mm; + + camel_object_unref((CamelObject *)m->session); } static struct _mail_msg_op timeout_op = { NULL, timeout_timeout, - NULL, - NULL, + timeout_done, + timeout_free, }; static gboolean @@ -473,65 +672,120 @@ camel_timeout (gpointer data) { struct _timeout_data *td = data; struct _timeout_msg *m; + + /* stop if we are removed pending */ + if (td->removed) + return FALSE; - m = mail_msg_new (&timeout_op, NULL, sizeof (*m)); - - m->cb = td->cb; - m->camel_data = td->camel_data; + m = mail_msg_new(&timeout_op, NULL, sizeof (*m)); + + m->session = td->session; + camel_object_ref((CamelObject *)td->session); + m->id = td->id; - e_thread_put (mail_thread_queued, (EMsg *)m); + e_thread_put(mail_thread_queued, (EMsg *)m); return TRUE; } static void -main_register_timeout(struct _timeout_data *td) +main_register_timeout(CamelSession *session, void *event_data, void *data) { - td->result = gtk_timeout_add_full(td->interval, camel_timeout, NULL, td, g_free); + MailSession *ms = (MailSession *)session; + unsigned int handle = (unsigned int)event_data; + struct _timeout_data *td; + + MAIL_SESSION_LOCK(session, lock); + td = find_timeout(&ms->timeouts, handle); + if (td) { + if (td->removed) { + e_dlist_remove((EDListNode *)td); + if (td->timeout_id) + gtk_timeout_remove(td->timeout_id); + g_free(td); + } else { + td->timeout_id = gtk_timeout_add(td->interval, camel_timeout, td); + } + } + MAIL_SESSION_UNLOCK(session, lock); + + camel_object_unref((CamelObject *)ms); } static guint register_timeout (CamelSession *session, guint32 interval, CamelTimeoutCallback cb, gpointer camel_data) { struct _timeout_data *td; - - /* We do this because otherwise the timeout can get called - * more often than the dispatch thread can get rid of it, - * leading to timeout calls piling up, and we don't have a - * good way to watch the return values. It's not cool. - */ - if (interval < 1000) { - g_warning("Timeout %u too small, increased to 1000", interval); - interval = 1000; - } + MailSession *ms = (MailSession *)session; + guint ret; - /* This is extremely messy, we need to proxy to gtk thread for this */ - td = g_malloc (sizeof (*td)); - td->interval = interval; - td->result = 0; + MAIL_SESSION_LOCK(session, lock); + + ret = ms->timeout_id; + ms->timeout_id ++; + + /* just debugging, the timeout code now ignores excessive events anyway */ + if (interval < 100) + g_warning("Timeout requested %d is small, may cause performance problems", interval); + + td = g_malloc(sizeof(*td)); td->cb = cb; td->camel_data = camel_data; + td->interval = interval; + td->id = ret; + td->session = session; + td->removed = FALSE; + td->busy = FALSE; + e_dlist_addhead(&ms->timeouts, (EDListNode *)td); - mail_call_main(MAIL_CALL_p_p, (MailMainFunc)main_register_timeout, td); + MAIL_SESSION_UNLOCK(session, lock); - if (td->result == 0) { - g_free(td); - return 0; - } + camel_object_ref((CamelObject *)ms); + mail_async_event_emit(ms->async, (CamelObjectEventHookFunc)main_register_timeout, (CamelObject *)session, (void *)ret, NULL); - return td->result; + return ret; } static void -main_remove_timeout(guint *edata) +main_remove_timeout(CamelSession *session, void *event_data, void *data) { - gtk_timeout_remove(*edata); + MailSession *ms = (MailSession *)session; + unsigned int handle = (unsigned int)event_data; + struct _timeout_data *td; + + MAIL_SESSION_LOCK(session, lock); + td = find_timeout(&ms->timeouts, handle); + if (td) { + e_dlist_remove((EDListNode *)td); + if (td->timeout_id) + gtk_timeout_remove(td->timeout_id); + g_free(td); + } + MAIL_SESSION_UNLOCK(session, lock); + + camel_object_unref((CamelObject *)ms); } static gboolean remove_timeout (CamelSession *session, guint handle) { - mail_call_main(MAIL_CALL_p_p, (MailMainFunc)main_remove_timeout, &handle); + MailSession *ms = (MailSession *)session; + struct _timeout_data *td; + int remove = FALSE; + + MAIL_SESSION_LOCK(session, lock); + td = find_timeout(&ms->timeouts, handle); + if (td && !td->removed) { + td->removed = TRUE; + remove = TRUE; + } + MAIL_SESSION_UNLOCK(session, lock); + + if (remove) { + camel_object_ref((CamelObject *)ms); + mail_async_event_emit(ms->async, (CamelObjectEventHookFunc)main_remove_timeout, (CamelObject *)session, (void *)handle, NULL); + } else + g_warning("Removing a timeout i dont know about (or twice): %d", handle); return TRUE; } @@ -676,6 +930,37 @@ void mail_session_enable_interaction (gboolean enable) { MAIL_SESSION (session)->interaction_enabled = enable; + + if (!enable) { + struct _pass_msg *pm; + struct _user_message_msg *um; + + printf("Gone non-interactive, checking for outstanding interactive tasks\n"); + + /* clear out pending password requests */ + while ((pm = (struct _pass_msg *)e_dlist_remhead(&password_list))) { + printf("Flushing password request : %s\n", pm->prompt); + e_msgport_reply((EMsg *)pm); + } + + /* destroy the current */ + if (password_dialogue) { + printf("Destroying password dialogue\n"); + gtk_object_destroy((GtkObject *)password_dialogue); + } + + /* same for pending user messages */ + while ((um = (struct _user_message_msg *)e_dlist_remhead(&message_list))) { + printf("Flusing message request: %s\n", um->prompt); + e_msgport_reply((EMsg *)um); + } + + /* and the current */ + if (message_dialogue) { + printf("Destroying message dialogue\n"); + gtk_object_destroy((GtkObject *)message_dialogue); + } + } } void |