aboutsummaryrefslogtreecommitdiffstats
path: root/mail/mail-mt.c
diff options
context:
space:
mode:
authorNot Zed <NotZed@HelixCode.com>2001-01-03 09:18:21 +0800
committerMichael Zucci <zucchi@src.gnome.org>2001-01-03 09:18:21 +0800
commita16344fff4780b6b1c5d8c2d6531963e1fe07d52 (patch)
tree1f71c805d1f3d27131f68fd744113b2535a3d1ce /mail/mail-mt.c
parentef48c6d6b0f84c1bbc5ce8ec666b0a581c9e3cc8 (diff)
downloadgsoc2013-evolution-a16344fff4780b6b1c5d8c2d6531963e1fe07d52.tar.gz
gsoc2013-evolution-a16344fff4780b6b1c5d8c2d6531963e1fe07d52.tar.zst
gsoc2013-evolution-a16344fff4780b6b1c5d8c2d6531963e1fe07d52.zip
Fix for mail_get_message change, use queue thread.
2001-01-02 Not Zed <NotZed@HelixCode.com> * mail-callbacks.c (view_msg): Fix for mail_get_message change, use queue thread. * folder-browser.c (done_message_selected): Fix mail_Get_message calls, use new thread. (do_message_selected): " * mail-ops.c (mail_get_message): Add a thread argument so callers can specify which queue it executes on. * mail-mt.c (mail_msg_free): Fix a free order problem. (mail_msg_destroy): Call mail_msg_free to do the work. (mail_msgport_replied): " (mail_msgport_replied): Check/display errors if we get them. (mail_msgport_received): If we have a describe function, say what we're doing, also set busy/unbusy. (mail_msgport_replied): Clear busy when we get a reply. (mail_get_password): Unset busy. (mail_msg_received): Set busy as we go. (mail_msg_destroy): Unset busy when done. (mail_status): Blah blah, new status interface, the other wans't workable with the way the shell api works. 2000-12-29 Not Zed <NotZed@HelixCode.com> * folder-browser.c (do_message_selected): If we are reconfiguring, just keep polling till we are done (yeah kinda shitty, but easy). (folder_browser_set_uri): Clear reconfigure flag here. ick. (got_folder): And here too. (on_right_click): Remove locking. (hide_sender): and here too. (hide_subject): And here. (on_right_click): If we are in reconfigure, then the whole menu is disabled. * mail-mt.c (status_busy_timeout): Clear the status_busy_timeout_id. * mail-local.c (local_storage_new_folder_cb): Made getting folders completely synchronous. The shell expects it, and it was only synchronous before by a sideeffect. (do_reconfigure_folder): Remove locking stuff. (do_reconfigure_folder): Use our own much simpler copying routine than that stupid move_folder_contents thing. (update_progress): Use mail_status_message() instead. (do_reconfigure_folder): Set the reconfigure flag during reconfigure & set busy flag. (cleanup_reconfigure_folder): clear busy flag. * mail-tools.c (mail_tool_uri_to_folder): Remove the tool_lock stuff. (mail_tool_uri_to_folder_noex): Clear exception on exit. (mail_tool_move_folder_contents): Get rid of this really stupid function that is only used in one place. * component-factory.c (owner_set_cb): Use direct calls to get the folders, as this code must run synchronous. Remove the event wait stuff. * mail-callbacks.c (edit_msg): Call mail_get_messages, and create the composers ourself. (do_edit_messages): get_messages callback, create the composers and connect to signals we need. (view_msg): Dont call do_view_messages, just call mail_get_messge for each to get them in parallel. (do_view_message): view a single message. * mail-ops.c (mail_edit_messages): Just use mail_get_messages for this operation. Removed the other async operation stuff. Changed my mind, just removed entirely. (mail_do_view_messages): Removed. (mail_do_setup_folder): Removed. (mail_do_scan_subfolders): Make this run synchronously, as every caller expects it to (even if they didn't realise). 2000-12-28 Not Zed <NotZed@HelixCode.com> * mail-callbacks.c (send_queued_mail): Dont expunge the folder here, but in send_queue, otherwise it might execute out of order. (expunge_folder): Remove the talbe prechange stuff, and infact references to the message_list folder, as we have our own folder. Also, dont allow expunge if we're already expunging. (expunged_folder): Clkear the expunging flag if we're finished. * folder-browser-factory.c (control_deactivate): Likewise here. Hrm, i thought this function required a callback, silly me. * mail-tools.c (mail_tool_make_message_attachment): Remov e locking. * folder-browser.c (on_message_selected): Use a timeout handler so we dont select immediately. (folder_browser_set_uri): Changed to use mail_get_folder. (got_folder): New callback called when get_folder is finished. (folder_browser_destroy): Use new sync interface. * mail-ops.c (mail_get_message): New function to asynchrounously get a message. : #define out mail_tool_camel_lock stuff entirely. (mail_get_folder): New function to asynchrounously get a folder. (mail_do_load_folder): Removed, replaced by more generic function above. (mail_do_display_message): Removed, replaced by the more generic funciton get_message. (mail_get_messages): New function to get a list of messages asynchronously. (mail_sync_folder): New interface to sync a folder async. (mail_expunge_folder): New interface for expunging folder, with callback. (do_send_queue): Remove lock stuff, and expunge if (and only if) successful, also sync the sent folder while we're at it. * session.c (mail_session_request_dialog): Changed to use new mail_get_password call. * mail-mt.[ch]: New threading/interthread messaging framework. * main.c (main): Init the message/thread system. svn path=/trunk/; revision=7223
Diffstat (limited to 'mail/mail-mt.c')
-rw-r--r--mail/mail-mt.c517
1 files changed, 517 insertions, 0 deletions
diff --git a/mail/mail-mt.c b/mail/mail-mt.c
new file mode 100644
index 0000000000..3441228ea4
--- /dev/null
+++ b/mail/mail-mt.c
@@ -0,0 +1,517 @@
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "e-util/e-msgport.h"
+#include <glib.h>
+#include <pthread.h>
+
+#include "mail-mt.h"
+
+#include <gtk/gtk.h>
+#include <libgnomeui/gnome-dialog-util.h>
+#include <libgnomeui/gnome-dialog.h>
+#include <libgnome/gnome-i18n.h>
+#include <gal/widgets/e-gui-utils.h>
+
+#include "folder-browser-factory.h"
+
+#define d(x)
+
+static void set_view_data(const char *current_message, int busy);
+
+static unsigned int mail_msg_seq;
+
+void *mail_msg_new(mail_msg_op_t *ops, EMsgPort *reply_port, size_t size)
+{
+ struct _mail_msg *msg;
+
+ msg = g_malloc0(size);
+ msg->ops = ops;
+ msg->seq = mail_msg_seq++;
+ msg->msg.reply_port = reply_port;
+ camel_exception_init(&msg->ex);
+
+ return msg;
+}
+
+void mail_msg_free(void *msg)
+{
+ struct _mail_msg *m = msg;
+
+ if (m->ops->destroy_msg)
+ m->ops->destroy_msg(m);
+ camel_exception_clear(&m->ex);
+ g_free(m);
+}
+
+void mail_msg_check_error(void *msg)
+{
+ struct _mail_msg *m = msg;
+ char *what = NULL;
+ char *text;
+ GnomeDialog *gd;
+
+ if (!camel_exception_is_set(&m->ex))
+ return;
+
+ if (m->ops->describe_msg)
+ what = m->ops->describe_msg(m, FALSE);
+
+ if (what)
+ text = g_strdup_printf(_("Error while '%s':\n%s"), what, camel_exception_get_description(&m->ex));
+ else
+ text = g_strdup_printf(_("Error while performing operation:\n%s"), camel_exception_get_description(&m->ex));
+
+ gd = (GnomeDialog *)gnome_error_dialog(text);
+ gnome_dialog_run_and_close(gd);
+ g_free(text);
+}
+
+EMsgPort *mail_gui_port;
+static GIOChannel *mail_gui_channel;
+EMsgPort *mail_gui_reply_port;
+static GIOChannel *mail_gui_reply_channel;
+
+/* a couple of global threads available */
+EThread *mail_thread_queued; /* for operations that can (or should) be queued */
+EThread *mail_thread_new; /* for operations that should run in a new thread each time */
+
+static gboolean
+mail_msgport_replied(GIOChannel *source, GIOCondition cond, void *d)
+{
+ EMsgPort *port = (EMsgPort *)d;
+ mail_msg_t *m;
+
+ while (( m = (mail_msg_t *)e_msgport_get(port))) {
+ if (m->ops->reply_msg)
+ m->ops->reply_msg(m);
+ mail_msg_check_error(m);
+ if (m->ops->describe_msg)
+ mail_status_end();
+ mail_msg_free(m);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+mail_msgport_received(GIOChannel *source, GIOCondition cond, void *d)
+{
+ EMsgPort *port = (EMsgPort *)d;
+ mail_msg_t *m;
+
+ while (( m = (mail_msg_t *)e_msgport_get(port))) {
+ if (m->ops->describe_msg) {
+ char *text = m->ops->describe_msg(m, FALSE);
+ mail_status_start(text);
+ g_free(text);
+ }
+ if (m->ops->receive_msg)
+ m->ops->receive_msg(m);
+ if (m->msg.reply_port)
+ e_msgport_reply((EMsg *)m);
+ else {
+ if (m->ops->reply_msg)
+ m->ops->reply_msg(m);
+ if (m->ops->describe_msg)
+ mail_status_end();
+ mail_msg_free(m);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+mail_msg_destroy(EThread *e, EMsg *msg, void *data)
+{
+ mail_msg_t *m = (mail_msg_t *)msg;
+
+ if (m->ops->describe_msg)
+ mail_status_end();
+ mail_msg_free(m);
+}
+
+static void
+mail_msg_received(EThread *e, EMsg *msg, void *data)
+{
+ mail_msg_t *m = (mail_msg_t *)msg;
+
+ if (m->ops->describe_msg) {
+ char *text = m->ops->describe_msg(m, FALSE);
+ printf("message received at thread\n");
+ mail_status_start(text);
+ g_free(text);
+ }
+
+ if (m->ops->receive_msg)
+ m->ops->receive_msg(m);
+}
+
+void mail_msg_init(void)
+{
+ mail_gui_reply_port = e_msgport_new();
+ mail_gui_reply_channel = g_io_channel_unix_new(e_msgport_fd(mail_gui_reply_port));
+ g_io_add_watch(mail_gui_reply_channel, G_IO_IN, mail_msgport_replied, mail_gui_reply_port);
+
+ 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_thread_queued = e_thread_new(E_THREAD_QUEUE);
+ e_thread_set_msg_destroy(mail_thread_queued, mail_msg_destroy, 0);
+ e_thread_set_msg_received(mail_thread_queued, mail_msg_received, 0);
+ e_thread_set_reply_port(mail_thread_queued, mail_gui_reply_port);
+
+ mail_thread_new = e_thread_new(E_THREAD_NEW);
+ e_thread_set_msg_destroy(mail_thread_new, mail_msg_destroy, 0);
+ e_thread_set_msg_received(mail_thread_new, mail_msg_received, 0);
+ e_thread_set_reply_port(mail_thread_new, mail_gui_reply_port);
+}
+
+/* ********************************************************************** */
+
+struct _set_msg {
+ struct _mail_msg msg;
+ char *text;
+};
+
+/* locks */
+static pthread_mutex_t status_lock = PTHREAD_MUTEX_INITIALIZER;
+#define STATUS_BUSY_PENDING (2)
+
+#define MAIL_MT_LOCK(x) pthread_mutex_lock(&x)
+#define MAIL_MT_UNLOCK(x) pthread_mutex_unlock(&x)
+
+/* blah blah */
+
+#define STATUS_DELAY (5)
+
+static int status_depth;
+static int status_showing;
+static int status_shown;
+static char *status_message_next;
+static int status_message_clear;
+static int status_timeout_id;
+static int status_busy;
+
+struct _status_msg {
+ struct _mail_msg msg;
+ char *text;
+ int busy;
+};
+
+static gboolean
+status_timeout(void *data)
+{
+ char *msg;
+ int busy = 0;
+
+ d(printf("got status timeout\n"));
+
+ MAIL_MT_LOCK(status_lock);
+ if (status_message_next) {
+ d(printf("setting message to '%s' busy %d\n", status_message_next, status_busy));
+ msg = status_message_next;
+ status_message_next = NULL;
+ busy = status_depth > 0;
+ status_message_clear = 0;
+ MAIL_MT_UNLOCK(status_lock);
+
+ /* copy msg so we can set it outside the lock */
+ /* unset first is a hack to avoid the stack stuff that doesn't and can't work anyway */
+ if (status_shown)
+ set_view_data(NULL, FALSE);
+ status_shown = TRUE;
+ set_view_data(msg, busy);
+ g_free(msg);
+ return TRUE;
+ }
+
+ /* the delay-clear stuff doesn't work yet. Dont care ... */
+
+ status_showing = FALSE;
+ status_message_clear++;
+ if (status_message_clear >= STATUS_DELAY && status_depth==0) {
+ d(printf("clearing message, busy = %d\n", status_depth));
+ } else {
+ d(printf("delaying clear\n"));
+ MAIL_MT_UNLOCK(status_lock);
+ return TRUE;
+ }
+
+ status_timeout_id = 0;
+
+ MAIL_MT_UNLOCK(status_lock);
+
+ if (status_shown)
+ set_view_data(NULL, FALSE);
+ status_shown = FALSE;
+
+ return FALSE;
+}
+
+static void do_set_status(struct _mail_msg *mm)
+{
+ struct _status_msg *m = (struct _status_msg *)mm;
+
+ MAIL_MT_LOCK(status_lock);
+
+ if (status_timeout_id != 0)
+ gtk_timeout_remove(status_timeout_id);
+
+ status_timeout_id = gtk_timeout_add(500, status_timeout, 0);
+ status_message_clear = 0;
+
+ MAIL_MT_UNLOCK(status_lock);
+
+ /* the 'clear' stuff doesn't really work yet, but oh well,
+ this stuff here needs a little changing for it to work */
+ if (status_shown)
+ set_view_data(NULL, status_depth != 0);
+ status_shown = 0;
+
+ if (m->text) {
+ status_shown = 1;
+ set_view_data(m->text, status_depth != 0);
+ }
+}
+
+static void do_del_status(struct _mail_msg *mm)
+{
+ struct _status_msg *m = (struct _status_msg *)mm;
+
+ g_free(m->text);
+}
+
+struct _mail_msg_op set_status_op = {
+ NULL,
+ do_set_status,
+ NULL,
+ do_del_status,
+};
+
+/* start a new operation */
+void mail_status_start(const char *msg)
+{
+ struct _status_msg *m = NULL;
+
+ MAIL_MT_LOCK(status_lock);
+ status_depth++;
+ MAIL_MT_UNLOCK(status_lock);
+
+ if (msg == NULL || msg[0] == 0)
+ msg = _("Working");
+
+ m = mail_msg_new(&set_status_op, NULL, sizeof(*m));
+ m->text = g_strdup(msg);
+ m->busy = TRUE;
+
+ e_msgport_put(mail_gui_port, &m->msg.msg);
+}
+
+/* end it */
+void mail_status_end(void)
+{
+ struct _status_msg *m = NULL;
+
+ m = mail_msg_new(&set_status_op, NULL, sizeof(*m));
+ m->text = NULL;
+
+ MAIL_MT_LOCK(status_lock);
+ status_depth--;
+ m->busy = status_depth = 0;
+ MAIL_MT_UNLOCK(status_lock);
+
+ e_msgport_put(mail_gui_port, &m->msg.msg);
+}
+
+/* message during it */
+void mail_status(const char *msg)
+{
+ if (msg == NULL || msg[0] == 0)
+ msg = _("Working");
+
+ MAIL_MT_LOCK(status_lock);
+
+ g_free(status_message_next);
+ status_message_next = g_strdup(msg);
+
+ MAIL_MT_UNLOCK(status_lock);
+}
+
+void mail_statusf(const char *fmt, ...)
+{
+ va_list ap;
+ char *text;
+
+ va_start(ap, fmt);
+ text = g_strdup_vprintf(fmt, ap);
+ va_end(ap);
+ mail_status(text);
+ g_free(text);
+}
+
+/* ********************************************************************** */
+
+struct _pass_msg {
+ struct _mail_msg msg;
+ char *prompt;
+ int secret;
+ char *result;
+};
+
+/* libgnomeui's idea of an api/gui is very weird ... hence this dumb hack */
+static void focus_on_entry(GtkWidget *widget, void *user_data)
+{
+ if (GTK_IS_ENTRY(widget))
+ gtk_widget_grab_focus(widget);
+}
+
+static void pass_got(char *string, void *data)
+{
+ struct _pass_msg *m = data;
+
+ if (string)
+ m->result = g_strdup (string);
+}
+
+static void
+do_get_pass(struct _mail_msg *mm)
+{
+ struct _pass_msg *m = (struct _pass_msg *)mm;
+ GtkWidget *dialogue;
+
+ /* this api is just awful ... hence the hacks */
+ dialogue = gnome_request_dialog(m->secret, m->prompt, NULL,
+ 0, pass_got, m, NULL);
+ e_container_foreach_leaf((GtkContainer *)dialogue, focus_on_entry, NULL);
+
+ /* hrm, we can't run this async since the gui_port from which we're called
+ will reply to our message for us */
+ gnome_dialog_run_and_close((GnomeDialog *)dialogue);
+
+ /*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(char *prompt, gboolean secret)
+{
+ 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(*m));
+
+ m->prompt = prompt;
+ m->secret = secret;
+
+ e_msgport_put(mail_gui_port, (EMsg *)m);
+ e_msgport_wait(pass_reply);
+ r = (struct _pass_msg *)e_msgport_get(pass_reply);
+
+ g_assert(r == m);
+
+ ret = m->result;
+
+ mail_msg_free(m);
+ e_msgport_destroy(pass_reply);
+
+ return ret;
+}
+
+
+
+/* ******************** */
+
+/* FIXME FIXME FIXME This is a totally evil hack. */
+
+static GNOME_Evolution_ShellView
+retrieve_shell_view_interface_from_control (BonoboControl *control)
+{
+ Bonobo_ControlFrame control_frame;
+ GNOME_Evolution_ShellView shell_view_interface;
+ CORBA_Environment ev;
+
+ control_frame = bonobo_control_get_control_frame (control);
+
+ if (control_frame == NULL)
+ return CORBA_OBJECT_NIL;
+
+ CORBA_exception_init (&ev);
+ shell_view_interface = Bonobo_Unknown_queryInterface (control_frame,
+ "IDL:GNOME/Evolution/ShellView:1.0",
+ &ev);
+ CORBA_exception_free (&ev);
+
+ if (shell_view_interface != CORBA_OBJECT_NIL)
+ gtk_object_set_data (GTK_OBJECT (control),
+ "mail_threads_shell_view_interface",
+ shell_view_interface);
+ else
+ g_warning ("Control frame doesn't have Evolution/ShellView.");
+
+ return shell_view_interface;
+}
+
+static void
+set_view_data(const char *current_message, int busy)
+{
+ EList *controls;
+ EIterator *it;
+
+ controls = folder_browser_factory_get_control_list ();
+ for (it = e_list_get_iterator (controls); e_iterator_is_valid (it); e_iterator_next (it)) {
+ BonoboControl *control;
+ GNOME_Evolution_ShellView shell_view_interface;
+ CORBA_Environment ev;
+
+ control = BONOBO_CONTROL (e_iterator_get (it));
+
+ shell_view_interface = gtk_object_get_data (GTK_OBJECT (control), "mail_threads_shell_view_interface");
+
+ if (shell_view_interface == CORBA_OBJECT_NIL)
+ shell_view_interface = retrieve_shell_view_interface_from_control (control);
+
+ CORBA_exception_init (&ev);
+
+ if (shell_view_interface != CORBA_OBJECT_NIL) {
+ if ((current_message == NULL || current_message[0] == 0) && ! busy) {
+ printf("clearing msg\n");
+ GNOME_Evolution_ShellView_unsetMessage (shell_view_interface, &ev);
+ } else {
+ printf("setting msg %s\n", current_message);
+ GNOME_Evolution_ShellView_setMessage (shell_view_interface,
+ current_message?current_message:"",
+ busy,
+ &ev);
+ }
+ }
+
+ CORBA_exception_free (&ev);
+
+ /* yeah we only set the first one. Why? Because it seems to leave
+ random ones lying around otherwise. Shrug. */
+ break;
+ }
+ gtk_object_unref(GTK_OBJECT(it));
+}