aboutsummaryrefslogtreecommitdiffstats
path: root/mail/mail-mt.c
diff options
context:
space:
mode:
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));
+}