From 8cb514d6dd9497893a35a089d07a132d51263ee7 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 10 Aug 2000 17:30:50 +0000 Subject: Merge with camel-async. svn path=/trunk/; revision=4687 --- mail/ChangeLog | 260 ++++- mail/Makefile.am | 12 +- mail/component-factory.c | 177 +-- mail/folder-browser-factory.c | 2 +- mail/folder-browser.c | 153 +-- mail/folder-browser.h | 4 +- mail/local-config.glade | 20 - mail/mail-config-gui.c | 12 +- mail/mail-display.c | 29 +- mail/mail-display.h | 3 +- mail/mail-format.c | 66 +- mail/mail-identify.c | 2 +- mail/mail-local.c | 319 +++--- mail/mail-local.h | 27 +- mail/mail-ops.c | 2454 +++++++++++++++++++++++++++-------------- mail/mail-threads.c | 1016 +++++++++++------ mail/mail-threads.h | 48 +- mail/mail-vfolder.c | 29 +- mail/mail-vfolder.h | 2 +- mail/mail-view.c | 144 ++- mail/mail.h | 12 +- mail/main.c | 6 - mail/message-list.c | 387 ++++--- mail/message-list.h | 1 - mail/message-thread.c | 129 ++- mail/message-thread.h | 12 +- mail/session.c | 92 +- mail/test-thread.c | 149 ++- 28 files changed, 3632 insertions(+), 1935 deletions(-) (limited to 'mail') diff --git a/mail/ChangeLog b/mail/ChangeLog index e734e79217..17591f38f1 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -9,13 +9,17 @@ assigned in the summary. (message_list_init_renderers): Init colour column. +2000-08-09 Peter Williams + + * mail-display.c (part_for_url): Remove a gtk_object_get_data + 2000-08-09 Cody Russell * folder-browser-factory.c, mail-view.c: Make the toolbars honor the user's gnomecc settings for detachable toolbars. 2000-08-09 Jeffrey Stedfast - + * mail-ops.c (composer_send_cb): Get the from address set in the composer, if that fails ONLY THEN get the default from mail config @@ -42,7 +46,7 @@ separator between VFolder and Filter stuff. * mail-ops.c (real_view_msg): Set the UID of the message that is - being displayed + being displayed 2000-08-09 Ettore Perazzoli @@ -50,6 +54,14 @@ `GNOME_STOCK_MENU_*' things instead of `GNOME_STOCK_PIXMAP_*' things, that are too big and look bad. +2000-08-09 Peter Williams + + * mail-view.c (mail_view_create): Save the top window so that on_close + can find it [with set_data]. + (on_close): Recover the top window. + + * mail-threads.c (read_msg): Destroy the window instead of hiding it. + 2000-08-09 Not Zed * mail-autofilter.c (filter_gui_add_from_message): Helper function @@ -144,6 +156,38 @@ * mail-view.c: Lets get rid of the last separator in the toolbar until we add n/p +2000-08-08 Ettore Perazzoli + + * mail-threads.c (queue_window_delete_event_cb): Callback for + "delete_event", just doing nothing. + (create_queue_window): Connect it to the "delete_event" signal of + the progress dialog. + +2000-08-08 Peter Williams + + * mail-threads.c (remove_next_pending): Sanity check for + job queue, which seems to have some issues. + (read_msg): Make sure that the next operation isn't started + before the last one is cleaned up. + + * mail-callbacks.c (fetch_mail): Fix erroneous free. + + * mail-config-gui.c (mail_config_druid): Wrap the gtk_main call. + + * mail-ops.c (do_flag_messages): Allow specification of whether + to set the flags unconditionally or toggle their current state. + + * message-list.c (ml_tree_set_value_at): Toggle the seen status; + don't set it unconditionally. + + * mail-callbacks.c (delete_msg): Toggle the deletion status; + don't set it unconditionally. + + * mail-tools.c (mail_tool_do_movemail): Fix for undeclared tmpfd. + + * mail-local.c (local_reconfigure_folder): Big rewrite; make into + an asynchronous operation. Use some mail tools to make life easy. + 2000-08-08 Dan Winship * main.c (main): Move mail_config_init after session_init, since @@ -226,6 +270,18 @@ (create_imap_storage): Updated. (create_news_storage): Updated. +2000-08-07 Peter Williams + + * mail-ops.c (cleanup_edit_messages): New operation: edit_messages + For continuing draft messages. + (attach_messages): Fix accidental 0 datasize. + (do_setup_draftbox): New operation: setup_draftbox. Soooo hacky. + + * mail-callbacks.c: Move fejj's edit message to the async home. + + * component-factory.c (owner_set_cb): Use mail_do_setup_draftbox. + + 2000-08-07 Jeffrey Stedfast * mail-display.c: @@ -299,9 +355,35 @@ * folder-browser-factory.c (control_activate): Remove bonobo 0.15 vs 0.15-and-a-half ifdef, since we require post-0.16 now. +2000-08-04 Dan Winship + + * mail-threads.c (mail_operation_wait_for_finish): Don't use + "while (gtk_events_pending ()) gtk_main_iteration ();" inside + another tight loop, because it makes the thread spin rather than + blocking and waiting like it should. + 2000-08-04 Peter Williams - * mail-ops.c (move_msg): Fixed a pretty silly uninitialization bug. + * message-thread.c (do_thread_messages): Uninitialized variable + fix. + + * mail-threads.c (read_msg): Small leak fix. + + * component-factory.c (owner_unset_cb): Use mail_operations_ + terminate() instead of wait_for_finish(). + + * mail-threads.c (mail_operation_queue): Centralize the clur + handling functions; fix a race condition where the dispatcher + would overwrite the closure before the main thread could + free the old one. + (mail_operations_terminate): New function, wait for ops to + finished and kill the other thread. + (dispatch): changes to die when terminate is called (abort + on NULL spec). + + * mail-ops.c (cleanup_display_message): Fix improper handling + of displaying a NULL message (which means clear the message + display). 2000-08-04 Ettore Perazzoli @@ -337,6 +419,20 @@ 2000-08-03 Peter Williams + * mail-ops.c (op_forward_messages): Use the new dynamic + operation naming. + + * message-thread.c (describe_thread_messages): Ditto. + + * message-list.c (describe_regenerate_messagelist): Ditto. + + * mail-threads.c (get_password_clicked): Dynamic generation + of descriptive text for mail operations. "Opening a folder" -> + "Opening INBOX". Supported only so far, will be implemented + quickly. + g_strdup() the old_message when changing the queue_window_label's + text. + * main.c (main): One more gconf reference to take out... * mail-ops.c (composer_send_cb): Check for an identity before @@ -366,6 +462,11 @@ * mail-config-druid.glade: Make the icon background dark blue like the surrounding area. +2000-08-02 Peter Williams + + * component-factory.c (owner_unset_cb): Wait for async operations + to finish before exiting. + 2000-08-02 Christopher James Lahey * mail-ops.c, message-list.c: Emit "model_pre_change" where @@ -375,6 +476,12 @@ * mail-config.h: #ifdef _MAIL_CONFIG_H protect the header. +2000-08-01 Peter Williams + + * mail-threads.c: Implement Solaris threads. Attempt + to join to the thread upon exit -- hopefully prevents + all those nasty zombie processes from popping up :-( + 2000-08-01 Dan Winship * mail-crypto.c: New code to spawn off GPG/PGP to do stuff. @@ -591,6 +698,33 @@ (main): More "guess the build mistake" fun, this time for the failure to initialize Bonobo case. +2000-07-24 Peter Williams + + * mail-tools.c (mail_tool_set_uid_flags): Change + function to faithfully pass parameters to + camel_folder_set_message_flags; this function is + somewhat useless now. Other files synced with + API change. + + * mail-ops.c (op_display_message): Change "display + a message" into "retrieve a messsage" in the + description of mail_op_display_message. + + * mail-threads.c (display_timeout): New function. + Only display the progress dialog if the operation + takes more than a second to perform. + (hide_queue_window): New function. Hide the queue + window as an idle function... I'm thinking maybe + the problem with hiding it was due to us not + being in a GTK event sequence? Perhaps it's only + the timeout, which was not being cancelled, which + is now. + + * message-list.c (get_message_uid): New function, + copy of get_message_info, except gets only the + UID, as that's all that most functions want, and + we avoid a Camel call. + 2000-07-23 Ettore Perazzoli * mail-ops.c (create_message_composer): New. @@ -601,6 +735,94 @@ * folder-browser-factory.c (control_activate): Use `_()' instead of `N_()'. +2000-07-21 Peter Williams + + * message-thread.c (setup_thread_messages): New + operation: thread_messages, simple wrapper around + thread_messages () and thread_messages_free(); + + * message-list.c (cleanup_regenerate_messagelist): + Use new thread_messages operation instead of just + calling ... thread_messages :-) + + * folder-browser.c (folder_browser_destroy): Use new + sync_folder operation instead of calling camel_folder_sync + directly. + + * component-factory.c (create_folder): Changed to use + new create_folder operation. + + * mail-ops.c (mail_do_create_folder): New operation: create + folder. New operation: sync folder. + + * mail-format.c (cmm_destroyed): Remove the url hashtable from + the larger hashtable when it gets destroyed. + + * mail-callbacks.c (fetch_mail): Pass a hook function and data + down the chain to pick up the folder_changed and change the view. + + * mail-ops.c: Rename from mail-ops-new.c now that it's a little more + solid. + (fetch_mail): Add new options to hook and unhook an event while the + filter driver runs. A hack, but all of the operations are to some + extent. + (cleanup_fetch_mail): Unref the destination folder if not NULL. + * mail-tools.c (mail_tool_filter_contents_into): Intermediate the + event hook/unhook hack here. + +2000-07-20 Peter Williams + + * mail-ops-new.c (setup_send_mail): Fix silly forgetting-to-ref + problem on some sends (when not replying). Note the early exit + path with a big comment. + + * message-list.c (message_list_set_folder): Don't call + folder_changed, call mail_do_regenerate_messagelist, as + the GDK_THREADS_ENTER in the former can deadlock us! + + * folder-browser.c (folder_browser_set_uri): Ah, screw it. + Make 'load folder' asynchronous and pretend that it always + succeeds. + + * mail-ops-new.c (mail_do_load_folder): New operation, loads + a folder into a FolderBrowser. + + * mail-threads.c (read_msg): Check if the exception is + a user cancel; don't complain if it is. + (mail_operation_queue): Same. + (dispatch_func): Same. + +2000-07-20 Peter Williams + + * mail-ops-new.c (cleanup_send_mail): Fix evil mistaken + unref. + + * test-thread.c: Fit the new mail_operation_spec prototype. + + * mail-callbacks.c (composer_send_cb): Hide the composer upon + start of send operation. + + * folder-browser.c: #include "mail-ops-new.h" + + * mail-threads.h: Change text fields of mail_operation_spec to + provide two forms of the name. + + * mail-threads.c: Use appropriate new string fields. + (dispatch_func): Hide the progressbar by default. + + * message-list.c (op_regenerate_messagelist): Fix the datasize from + 0 -> sizeof (regenerate_messagelist_data_t). Add the new gerund and + infinitive strings. + (do_regenerate_messagelist): Include some code that fell between the + cracks. + + * mail-ops-new.c (op_scan_subfolders): Same datasize fix for + scan_subfolders. + (op_forward_message): Same. + (all): Add new gerund and inifinitive strings for mail_operation_spec. + (cleanup_send_mail): Destroy the composer on success; re-show it on + error. I'm so clever! + 2000-07-20 Ettore Perazzoli * component-factory.c (factory_fn): Updated for the new @@ -610,6 +832,24 @@ * message-thread.c (thread_messages): What if message info is NULL? +2000-07-17 Peter Williams + + * component-factory.c (real_create_{imap,news}_storage): Instead of + directly calling evolution_storage_new_folder, queue up a list of + folders to register so that we don't do our CORBA in The Other Thread. + (create_{imap,news}_storage): Changes ancillary to the above. + (add_new_mailbox): New function to queue up a folder + (cleanup_create_info): New function to dequeue the folders and free mem. + + * test-thread.c: s,ENABLE_BROKEN_THREADS,USE_BROKEN_THREADS -- oops + + * mail-format.c: (mail_lookup_url_table): New function to get the url + table associated with a CamelMimeMessage because we can no longer + gtk_object_get_data on it. + + * mail-display.c: replace 'gtk_object_get_data( message, "urls" )' + with 'mail_lookup_url_table( message )' + 2000-07-16 Jeffrey Stedfast * folder-browser.c, component-factory.c: Initial code to support @@ -622,6 +862,16 @@ Preview]". (real_send_mail): Call it. +2000-07-14 Peter Williams + + * message-list.c (message_list_set_folder): Ported to CamelObject: + GTK_OBJECT->CAMEL_OBJECT; gtk_signal_connect->camel_object_hook_event; + GDK_THREADS_ENTER/LEAVE around "changed" event hooks. + + * folder-browser.c (folder_browser_destroy): likewise. + (mail_uri_to_folder): likewise. + (folder_browser_load_folder): likewise. + 2000-07-14 Ettore Perazzoli * Makefile.am (evolution_mail_LDADD): Add `GCONF_LIBS'. @@ -695,6 +945,10 @@ * mail-display.c (save_data): Change from evolution_dir to g_get_home_dir() for default location of save file. +2000-07-11 Dan Winship + + * Update for CamelFolder API changes + 2000-07-11 Jeffrey Stedfast * mail-ops.c (real_fetch_mail): Changed to use diff --git a/mail/Makefile.am b/mail/Makefile.am index 63c15e7e7e..f8f63885ce 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -44,6 +44,7 @@ evolution_mail_SOURCES = \ folder-browser-factory.c \ mail-autofilter.c \ mail-autofilter.h \ + mail-callbacks.c \ mail-config.c \ mail-config.h \ mail-config-gui.c \ @@ -54,8 +55,11 @@ evolution_mail_SOURCES = \ mail-format.c \ mail-identify.c \ mail-ops.c \ + mail-ops.h \ mail-threads.c \ mail-threads.h \ + mail-tools.c \ + mail-tools.h \ mail-types.h \ mail-vfolder.c \ mail-vfolder.h \ @@ -97,8 +101,12 @@ test_thread_SOURCES = \ mail-threads.h \ test-thread.c -test_thread_LDADD = \ - $(BONOBO_HTML_GNOME_LIBS) \ +test_thread_LDADD = \ + $(top_builddir)/camel/libcamel.la \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/libibex/libibex.la \ + $(BONOBO_HTML_GNOME_LIBS) \ + $(UNICODE_LIBS) \ $(THREADS_LIBS) test_thread_CFLAGS = -g $(THREADS_CFLAGS) diff --git a/mail/component-factory.c b/mail/component-factory.c index e565313901..2a96b11dfe 100644 --- a/mail/component-factory.c +++ b/mail/component-factory.c @@ -35,7 +35,8 @@ #include "evolution-shell-component.h" #include "folder-browser.h" #include "mail.h" /* YUCK FIXME */ -#include "mail-threads.h" +#include "mail-tools.h" +#include "mail-ops.h" #include "e-util/e-gui-utils.h" #include "e-util/e-setup.h" @@ -45,7 +46,6 @@ CamelFolder *drafts_folder = NULL; static void create_vfolder_storage (EvolutionShellComponent *shell_component); static void create_imap_storage (EvolutionShellComponent *shell_component); -static void real_create_generic_storage( gpointer user_data ); static void create_news_storage (EvolutionShellComponent *shell_component); #define COMPONENT_FACTORY_ID "OAFIID:evolution-shell-component-factory:evolution-mail:0ea887d5-622b-4b8c-b525-18aa1cbe18a6" @@ -97,41 +97,7 @@ create_folder (EvolutionShellComponent *shell_component, const Evolution_ShellComponentListener listener, void *closure) { - CORBA_Environment ev; - CamelStore *store; - CamelFolder *folder; - CamelException ex; - Evolution_ShellComponentListener_Result result; - - camel_exception_init (&ex); - if (strcmp (type, "mail") != 0) - result = Evolution_ShellComponentListener_UNSUPPORTED_TYPE; - else { - char *camel_url = g_strdup_printf ("mbox://%s", physical_uri); - - store = camel_session_get_store (session, camel_url, &ex); - g_free (camel_url); - if (!camel_exception_is_set (&ex)) { - folder = camel_store_get_folder (store, "mbox", - TRUE, &ex); - gtk_object_unref (GTK_OBJECT (store)); - } else { - folder = NULL; - } - - if (!camel_exception_is_set (&ex)) { - gtk_object_unref (GTK_OBJECT (folder)); - result = Evolution_ShellComponentListener_OK; - } else { - result = Evolution_ShellComponentListener_INVALID_URI; - } - } - - camel_exception_clear (&ex); - - CORBA_exception_init (&ev); - Evolution_ShellComponentListener_report_result (listener, result, &ev); - CORBA_exception_free (&ev); + mail_do_create_folder (listener, physical_uri, type); } static void @@ -139,27 +105,12 @@ owner_set_cb (EvolutionShellComponent *shell_component, EvolutionShellClient *shell_client, gpointer user_data) { - CamelException *ex; - CamelStore *store; - char *url; - g_print ("evolution-mail: Yeeeh! We have an owner!\n"); /* FIXME */ /* GROSS HACK */ /*global_shell_client = shell_client;*/ - ex = camel_exception_new (); - url = g_strdup_printf ("mbox://%s/local/Drafts", evolution_dir); - store = camel_session_get_store (session, url, ex); - g_free (url); - if (!camel_exception_is_set (ex)) { - drafts_folder = camel_store_get_folder (store, "mbox", TRUE, ex); - gtk_object_unref (GTK_OBJECT (store)); - } else { - drafts_folder = NULL; - } - camel_exception_free (ex); - + mail_do_setup_draftbox (); create_vfolder_storage (shell_component); create_imap_storage (shell_component); create_news_storage (shell_component); @@ -168,6 +119,7 @@ owner_set_cb (EvolutionShellComponent *shell_component, static void owner_unset_cb (EvolutionShellComponent *shell_component, gpointer user_data) { + mail_operations_terminate (); gtk_main_quit (); } @@ -236,11 +188,6 @@ create_vfolder_storage (EvolutionShellComponent *shell_component) vfolder_create_storage(shell_component); } -struct create_info_s { - EvolutionStorage *storage; - char *source; -}; - static void create_imap_storage (EvolutionShellComponent *shell_component) { @@ -249,15 +196,14 @@ create_imap_storage (EvolutionShellComponent *shell_component) Evolution_Shell corba_shell; EvolutionStorage *storage; char *source = NULL, *server, *p; - struct create_info_s *ii; - + config = mail_config_fetch (); if (config->sources) { const MailConfigService *s; s = (MailConfigService *)config->sources->data; source = s->url; } - + if (!source || g_strncasecmp (source, "imap://", 7)) return; @@ -276,106 +222,19 @@ create_imap_storage (EvolutionShellComponent *shell_component) server++; for (p = server; *p && *p != '/'; p++); - + server = g_strndup (server, (gint)(p - server)); storage = evolution_storage_new (server); g_free (server); - + if (evolution_storage_register_on_shell (storage, corba_shell) != EVOLUTION_STORAGE_OK) { g_warning ("Cannot register storage"); g_free (source); return; } - - ii = g_new (struct create_info_s, 1); - ii->storage = storage; - ii->source = g_strdup (source); - -#ifdef USE_BROKEN_THREADS - mail_operation_try ("Create IMAP Storage", real_create_generic_storage, g_free, ii); -#else - real_create_generic_storage (ii); - g_free (ii); -#endif - /* Note the g_free as our cleanup function deleting the ii struct when we're done */ -} -static void -real_create_generic_storage (gpointer user_data) -{ - CamelException *ex; - EvolutionStorage *storage; - char *source; - CamelStore *store; - CamelFolder *folder; - GPtrArray *lsub; - int i, max; - struct create_info_s *ii; - - ii = (struct create_info_s *) user_data; - storage = ii->storage; - source = ii->source; - -#ifdef USE_BROKEN_THREADS - mail_op_hide_progressbar (); - mail_op_set_message ("Connecting to service..."); -#endif - ex = camel_exception_new (); - - store = camel_session_get_store (session, source, ex); - if (!store) { - goto cleanup; - } - - camel_service_connect (CAMEL_SERVICE (store), ex); - if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE) { - goto cleanup; - } - -#ifdef USE_BROKEN_THREADS - mail_op_set_message ("Connected. Examining folders..."); -#endif - - folder = camel_store_get_root_folder (store, ex); - if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE) { - goto cleanup; - } - - lsub = camel_folder_get_subfolder_names (folder); - - max = lsub->len; - for (i = 0; i < max; i++) { - char *path, *buf, *dirname; - -#if 0 - if (strcmp (dir_sep, "/")) { - dirname = e_strreplace ((char *)lsub->pdata[i], dir_sep, "/"); - } else { - dirname = g_strdup ((char *)lsub->pdata[i]); - } -#endif - dirname = g_strdup ((char *)lsub->pdata[i]); - - path = g_strdup_printf ("/%s", dirname); - g_free (dirname); - buf = g_strdup_printf ("%s/%s", source, path + 1); - printf ("buf = %s\n", buf); - -#ifdef USE_BROKEN_THREADS - mail_op_set_message ("Adding %s", path); -#endif - - evolution_storage_new_folder (storage, path, "mail", buf, "description"); - } - - cleanup: - g_free (ii->source); -#ifdef USE_BROKEN_THREADS - if (camel_exception_is_set (ex)) - mail_op_error ("%s", camel_exception_get_description (ex)); -#endif - camel_exception_free (ex); + mail_do_scan_subfolders (source, TRUE, storage); } static void @@ -386,7 +245,6 @@ create_news_storage (EvolutionShellComponent *shell_component) Evolution_Shell corba_shell; EvolutionStorage *storage; char *source=NULL, *server, *p; - struct create_info_s *ni; config = mail_config_fetch (); if (config->news) { @@ -419,16 +277,7 @@ create_news_storage (EvolutionShellComponent *shell_component) g_free (source); return; } - - ni = g_new( struct create_info_s, 1 ); - ni->storage = storage; - ni->source = g_strdup( source ); - -#ifdef USE_BROKEN_THREADS - mail_operation_try( "Create News Storage", real_create_generic_storage, g_free, ni ); -#else - real_create_generic_storage( ni ); - g_free( ni ); -#endif - /* again note the g_free cleanup func */ + + mail_do_scan_subfolders (source, FALSE, storage); } + diff --git a/mail/folder-browser-factory.c b/mail/folder-browser-factory.c index ae170867d1..ba861969e3 100644 --- a/mail/folder-browser-factory.c +++ b/mail/folder-browser-factory.c @@ -117,7 +117,7 @@ control_activate (BonoboControl *control, BonoboUIHandler *uih, NULL, -1, BONOBO_UI_HANDLER_PIXMAP_NONE, 0, - 0, 0, providers_config, NULL); + 0, 0, mail_config, NULL); bonobo_ui_handler_menu_new_item (uih, "/Tools/Forget Passwords", _("Forget _Passwords"), NULL, -1, diff --git a/mail/folder-browser.c b/mail/folder-browser.c index 4eb300214d..60feba556f 100644 --- a/mail/folder-browser.c +++ b/mail/folder-browser.c @@ -14,7 +14,10 @@ #include "e-util/e-sexp.h" #include "folder-browser.h" #include "mail.h" +#include "mail-tools.h" #include "message-list.h" +#include "mail-threads.h" +#include "mail-ops.h" #include #include "mail-vfolder.h" @@ -30,7 +33,6 @@ static GtkObjectClass *folder_browser_parent_class; - static void folder_browser_destroy (GtkObject *object) { @@ -48,10 +50,10 @@ folder_browser_destroy (GtkObject *object) g_free (folder_browser->uri); if (folder_browser->folder) { - camel_folder_sync (folder_browser->folder, FALSE, NULL); - gtk_object_unref (GTK_OBJECT (folder_browser->folder)); + mail_do_sync_folder (folder_browser->folder); + camel_object_unref (CAMEL_OBJECT (folder_browser->folder)); } - + if (folder_browser->message_list) bonobo_object_unref (BONOBO_OBJECT (folder_browser->message_list)); @@ -66,120 +68,31 @@ folder_browser_class_init (GtkObjectClass *object_class) folder_browser_parent_class = gtk_type_class (PARENT_TYPE); } -CamelFolder * -mail_uri_to_folder (const char *name) -{ - char *msg; - CamelStore *store = NULL; - CamelFolder *folder = NULL; - CamelException *ex; - - ex = camel_exception_new (); - - if (!strncmp (name, "vfolder:", 8)) { - folder = vfolder_uri_to_folder(name); - } else if (!strncmp (name, "imap:", 5)) { - char *service, *ptr; - - service = g_strdup_printf ("%s/", name); - for (ptr = service + 7; *ptr && *ptr != '/'; ptr++); - ptr++; - *ptr = '\0'; - - store = camel_session_get_store (session, service, ex); - g_free (service); - - if (store) { - CamelURL *url = CAMEL_SERVICE (store)->url; - char *folder_name; - - /*dir_sep = CAMEL_IMAP_STORE (store)->dir_sep;*/ - - for (ptr = (char *)(name + 7); *ptr && *ptr != '/'; ptr++); - if (*ptr == '/') { - if (url && url->path) { - ptr += strlen (url->path); - if (*ptr == '/') - ptr++; - } - - if (*ptr == '/') - ptr++; - /*for ( ; *ptr && *ptr == '/'; ptr++);*/ - - folder_name = g_strdup (ptr); - /*tree_name = g_strdup (ptr);*/ - /*folder_name = e_strreplace (tree_name, "/", dir_sep);*/ - - folder = camel_store_get_folder (store, folder_name, TRUE, ex); - g_free (folder_name); - } - } - } else if (!strncmp(name, "news:", 5)) { - store = camel_session_get_store (session, name, ex); - if (store) { - const char *folder_name; - - folder_name = name + 5; - - folder = camel_store_get_folder (store, folder_name, FALSE, ex); - } - } else if (!strncmp (name, "file:", 5)) { - folder = local_uri_to_folder(name, ex); - } else { - msg = g_strdup_printf ("Can't open URI %s", name); - gnome_error_dialog (msg); - g_free (msg); - } - - if (camel_exception_get_id (ex)) { - msg = g_strdup_printf ("Unable to get folder %s: %s\n", name, - camel_exception_get_description (ex)); - gnome_error_dialog (msg); - if (folder) { - gtk_object_unref (GTK_OBJECT (folder)); - folder = NULL; - } - } - camel_exception_free (ex); - - if (store) - gtk_object_unref (GTK_OBJECT (store)); - - return folder; -} - -static gboolean -folder_browser_load_folder (FolderBrowser *fb, const char *name) -{ - CamelFolder *new_folder; - - new_folder = mail_uri_to_folder (name); - if (!new_folder) - return FALSE; - - if (fb->folder) - gtk_object_unref (GTK_OBJECT (fb->folder)); - fb->folder = new_folder; - - gtk_widget_set_sensitive (GTK_WIDGET (fb->search_entry), camel_folder_has_search_capability (fb->folder)); - gtk_widget_set_sensitive (GTK_WIDGET (fb->search_menu), camel_folder_has_search_capability (fb->folder)); - - message_list_set_folder (fb->message_list, new_folder); - - return TRUE; -} +/* + * static gboolean + * folder_browser_load_folder (FolderBrowser *fb, const char *name) + * { + * CamelFolder *new_folder; + * + * new_folder = mail_tool_uri_to_folder_noex (name); + * + * if (!new_folder) + * return FALSE; + * + * if (fb->folder) + * camel_object_unref (CAMEL_OBJECT (fb->folder)); + * fb->folder = new_folder; + * message_list_set_folder (fb->message_list, new_folder); + * return TRUE; + * } + */ #define EQUAL(a,b) (strcmp (a,b) == 0) -gboolean -folder_browser_set_uri (FolderBrowser *folder_browser, const char *uri) +gboolean folder_browser_set_uri (FolderBrowser *folder_browser, const char *uri) { - if (folder_browser->uri) - g_free (folder_browser->uri); - - folder_browser->uri = g_strdup (uri); - return folder_browser_load_folder (folder_browser, folder_browser->uri); + mail_do_load_folder (folder_browser, uri); + return TRUE; } void @@ -223,7 +136,7 @@ search_set(FolderBrowser *fb) text = gtk_entry_get_text((GtkEntry *)fb->search_entry); if (text == NULL || text[0] == 0) { - message_list_regenerate (fb->message_list, NULL); + mail_do_regenerate_messagelist (fb->message_list, NULL); return; } @@ -243,7 +156,7 @@ search_set(FolderBrowser *fb) str++; } } - message_list_regenerate (fb->message_list, out->str); + mail_do_regenerate_messagelist (fb->message_list, out->str); g_string_free(out, TRUE); } @@ -358,7 +271,7 @@ folder_browser_clear_search (FolderBrowser *fb) { gtk_entry_set_text (GTK_ENTRY (fb->search_entry), ""); gtk_option_menu_set_history (GTK_OPTION_MENU (fb->search_menu), 0); - message_list_regenerate (fb->message_list, NULL); + mail_do_regenerate_messagelist (fb->message_list, NULL); } static int @@ -481,7 +394,7 @@ my_folder_browser_init (GtkObject *object) * Our instance data */ fb->message_list = MESSAGE_LIST (message_list_new (fb)); - fb->mail_display = MAIL_DISPLAY (mail_display_new (fb)); + fb->mail_display = MAIL_DISPLAY (mail_display_new ()); gtk_signal_connect (GTK_OBJECT (fb->message_list->etable), "key_press", GTK_SIGNAL_FUNC (etable_key), fb); @@ -504,7 +417,3 @@ folder_browser_new (void) E_MAKE_TYPE (folder_browser, "FolderBrowser", FolderBrowser, folder_browser_class_init, folder_browser_init, PARENT_TYPE); - - - - diff --git a/mail/folder-browser.h b/mail/folder-browser.h index 0bc3edf9c8..53bcb5b925 100644 --- a/mail/folder-browser.h +++ b/mail/folder-browser.h @@ -57,8 +57,8 @@ typedef struct { GtkType folder_browser_get_type (void); GtkWidget *folder_browser_new (void); -gboolean folder_browser_set_uri (FolderBrowser *folder_browser, - const char *uri); +gboolean folder_browser_set_uri (FolderBrowser *folder_browser, + const char *uri); void folder_browser_set_message_preview (FolderBrowser *folder_browser, gboolean show_message_preview); void folder_browser_clear_search (FolderBrowser *fb); diff --git a/mail/local-config.glade b/mail/local-config.glade index 3601433d78..3eaadbc833 100644 --- a/mail/local-config.glade +++ b/mail/local-config.glade @@ -214,26 +214,6 @@ recoverable. Please use this feature with care. False - - - GtkProgressBar - progress_format - 0 - 0 - 100 - GTK_PROGRESS_CONTINUOUS - GTK_PROGRESS_LEFT_TO_RIGHT - False - False - %P %% - 0.5 - 0.5 - - 0 - False - False - - diff --git a/mail/mail-config-gui.c b/mail/mail-config-gui.c index 12d944e4e3..7ebcb09c6a 100644 --- a/mail/mail-config-gui.c +++ b/mail/mail-config-gui.c @@ -1259,7 +1259,9 @@ identity_dialog (const MailConfigIdentity *id, GtkWidget *parent) GTK_SIGNAL_FUNC (iddialog_ok_clicked), iddialog); + /*GDK_THREADS_ENTER ();*/ gnome_dialog_run_and_close (GNOME_DIALOG (iddialog->dialog)); + /*GDK_THREADS_LEAVE ();*/ returnid = iddialog->id; g_free (iddialog); @@ -1356,7 +1358,9 @@ source_dialog (MailConfigService *source, GtkWidget *parent) GTK_SIGNAL_FUNC (sdialog_ok_clicked), sdialog); + /*GDK_THREADS_ENTER ();*/ gnome_dialog_run_and_close (GNOME_DIALOG (sdialog->dialog)); + /*GDK_THREADS_LEAVE ();*/ returnsource = sdialog->source; g_free (sdialog); @@ -1452,7 +1456,9 @@ news_dialog (MailConfigService *source, GtkWidget *parent) GTK_SIGNAL_FUNC (ndialog_ok_clicked), ndialog); + /*GDK_THREADS_ENTER ();*/ gnome_dialog_run_and_close (GNOME_DIALOG (ndialog->dialog)); + /*GDK_THREADS_LEAVE ();*/ returnsource = ndialog->source; g_free (ndialog); @@ -1679,8 +1685,10 @@ mail_config_druid (void) gtk_signal_connect (GTK_OBJECT (fpage), "finish", GTK_SIGNAL_FUNC (mail_druid_finish), dialog); - + + GDK_THREADS_ENTER (); gtk_main (); + GDK_THREADS_LEAVE (); } /* Main configuration dialog */ @@ -2131,7 +2139,9 @@ mail_config (void) GTK_SIGNAL_FUNC (mail_config_apply_clicked), dialog); + GDK_THREADS_ENTER (); gnome_dialog_run (GNOME_DIALOG (dialog->dialog)); + GDK_THREADS_LEAVE (); /* Clean up */ gtk_object_unref (GTK_OBJECT (gui)); diff --git a/mail/mail-display.c b/mail/mail-display.c index 9da2dcd4f0..f32887c3de 100644 --- a/mail/mail-display.c +++ b/mail/mail-display.c @@ -30,6 +30,8 @@ static GtkObjectClass *mail_display_parent_class; +/* Sigh... gtk_object_set_data is nice to have... */ +extern GHashTable *mail_lookup_url_table (CamelMimeMessage *mime_message); /*----------------------------------------------------------------------* * Callbacks @@ -61,7 +63,9 @@ write_data_to_file (CamelMimePart *part, const char *name, gboolean unique) gnome_ok_cancel_dialog_modal ( "A file by that name already exists.\nOverwrite it?", save_data_eexist_cb, &ok); + GDK_THREADS_ENTER(); gtk_main (); + GDK_THREADS_LEAVE(); if (!ok) return FALSE; fd = open (name, O_WRONLY | O_TRUNC); @@ -86,11 +90,10 @@ write_data_to_file (CamelMimePart *part, const char *name, gboolean unique) strerror (errno)); gnome_error_dialog (msg); g_free (msg); - gtk_object_unref (GTK_OBJECT (stream_fs)); + camel_object_unref (CAMEL_OBJECT (stream_fs)); return FALSE; } - gtk_object_unref (GTK_OBJECT (stream_fs)); - + camel_object_unref (CAMEL_OBJECT (stream_fs)); return TRUE; } @@ -129,7 +132,7 @@ part_for_url (const char *url, CamelMimeMessage *message) { GHashTable *urls; - urls = gtk_object_get_data (GTK_OBJECT (message), "urls"); + urls = mail_lookup_url_table (message); g_return_val_if_fail (urls != NULL, NULL); return g_hash_table_lookup (urls, url); } @@ -252,7 +255,7 @@ on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data) if (strncmp (eb->classid, "cid:", 4) != 0) return FALSE; message = gtk_object_get_data (GTK_OBJECT (html), "message"); - urls = gtk_object_get_data (GTK_OBJECT (message), "urls"); + urls = mail_lookup_url_table (message); medium = g_hash_table_lookup (urls, eb->classid); g_return_val_if_fail (CAMEL_IS_MEDIUM (medium), FALSE); wrapper = camel_medium_get_content_object (medium); @@ -283,7 +286,7 @@ on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data) /* ...convert the CamelStreamMem to a BonoboStreamMem... */ bstream = bonobo_stream_mem_create (ba->data, ba->len, TRUE, FALSE); - gtk_object_unref (GTK_OBJECT (cstream)); + camel_object_unref (CAMEL_OBJECT (cstream)); /* ...and hydrate the PersistStream from the BonoboStream. */ CORBA_exception_init (&ev); @@ -316,7 +319,7 @@ on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle, GHashTable *urls; message = gtk_object_get_data (GTK_OBJECT (html), "message"); - urls = gtk_object_get_data (GTK_OBJECT (message), "urls"); + urls = mail_lookup_url_table (message); user_data = g_hash_table_lookup (urls, url); if (user_data == NULL) @@ -335,7 +338,7 @@ on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle, stream_mem = camel_stream_mem_new_with_byte_array (ba); camel_data_wrapper_write_to_stream (data, stream_mem); gtk_html_write (html, handle, ba->data, ba->len); - gtk_object_unref (GTK_OBJECT (stream_mem)); + camel_object_unref (CAMEL_OBJECT (stream_mem)); } else if (strncmp (url, "x-evolution-data:", 17) == 0) { GByteArray *ba = user_data; @@ -426,7 +429,7 @@ mail_display_set_message (MailDisplay *mail_display, /* Clean up from previous message. */ if (mail_display->current_message) - gtk_object_unref (GTK_OBJECT (mail_display->current_message)); + camel_object_unref (CAMEL_OBJECT (mail_display->current_message)); mail_display->current_message = (CamelMimeMessage*)medium; @@ -435,7 +438,7 @@ mail_display_set_message (MailDisplay *mail_display, "\n"); if (medium) { - gtk_object_ref (GTK_OBJECT (medium)); + camel_object_ref (CAMEL_OBJECT (medium)); gtk_object_set_data (GTK_OBJECT (mail_display->html), "message", medium); mail_format_mime_message (CAMEL_MIME_MESSAGE (medium), @@ -485,15 +488,11 @@ mail_display_class_init (GtkObjectClass *object_class) } GtkWidget * -mail_display_new (FolderBrowser *parent_folder_browser) +mail_display_new (void) { MailDisplay *mail_display = gtk_type_new (mail_display_get_type ()); GtkWidget *scroll, *html; - g_assert (parent_folder_browser); - - mail_display->parent_folder_browser = parent_folder_browser; - gtk_box_set_homogeneous (GTK_BOX (mail_display), FALSE); gtk_widget_show (GTK_WIDGET (mail_display)); diff --git a/mail/mail-display.h b/mail/mail-display.h index d839978371..129b059612 100644 --- a/mail/mail-display.h +++ b/mail/mail-display.h @@ -25,7 +25,6 @@ struct _MailDisplay { EScrollFrame *scroll; GtkHTML *html; - FolderBrowser *parent_folder_browser; CamelMimeMessage *current_message; }; @@ -34,7 +33,7 @@ typedef struct { } MailDisplayClass; GtkType mail_display_get_type (void); -GtkWidget * mail_display_new (FolderBrowser *parent_folder_browser); +GtkWidget * mail_display_new (void); void mail_display_set_message (MailDisplay *mail_display, CamelMedium *medium); diff --git a/mail/mail-format.c b/mail/mail-format.c index a96619631f..95d595fef9 100644 --- a/mail/mail-format.c +++ b/mail/mail-format.c @@ -104,8 +104,38 @@ static void write_headers (CamelMimeMessage *message, static gboolean call_handler_function (CamelMimePart *part, struct mail_format_data *mfd); -static void free_urls (gpointer data); +/* no gtk_object_set_data, sorry..... */ + +static GHashTable *cmm_to_urls = NULL; + +static void +free_url (gpointer key, gpointer value, gpointer data) +{ + g_free (key); +} + +static void cmm_destroyed (CamelObject *cmm, gpointer event_data, gpointer user_data) +{ + GHashTable *ht; + + g_return_if_fail (cmm); + + ht = g_hash_table_lookup (cmm_to_urls, cmm); + g_hash_table_foreach (ht, free_url, NULL); + g_hash_table_destroy (ht); + g_hash_table_insert (cmm_to_urls, cmm, NULL); +} + +GHashTable *mail_lookup_url_table (CamelMimeMessage *mime_message) +{ + if (!cmm_to_urls) { + cmm_to_urls = g_hash_table_new (g_direct_hash, g_direct_equal); + return NULL; + } + + return g_hash_table_lookup (cmm_to_urls, mime_message); +} /** * mail_format_mime_message: @@ -128,32 +158,21 @@ mail_format_mime_message (CamelMimeMessage *mime_message, mfd.html = html; mfd.stream = stream; mfd.root = root; - mfd.urls = gtk_object_get_data (GTK_OBJECT (root), "urls"); + + if (!cmm_to_urls) + cmm_to_urls = g_hash_table_new (g_direct_hash, g_direct_equal); + mfd.urls = g_hash_table_lookup (cmm_to_urls, root); + if (!mfd.urls) { mfd.urls = g_hash_table_new (g_str_hash, g_str_equal); - gtk_object_set_data_full (GTK_OBJECT (root), "urls", - mfd.urls, free_urls); + g_hash_table_insert (cmm_to_urls, root, mfd.urls); + camel_object_hook_event (CAMEL_OBJECT (root), "finalize", cmm_destroyed, NULL); } write_headers (mime_message, &mfd); call_handler_function (CAMEL_MIME_PART (mime_message), &mfd); } -static void -free_url (gpointer key, gpointer value, gpointer data) -{ - g_free (key); -} - -static void -free_urls (gpointer data) -{ - GHashTable *urls = data; - - g_hash_table_foreach (urls, free_url, NULL); - g_hash_table_destroy (urls); -} - static const char * get_cid (CamelMimePart *part, struct mail_format_data *mfd) { @@ -500,7 +519,7 @@ get_data_wrapper_text (CamelDataWrapper *data) } else text = NULL; - gtk_object_unref (GTK_OBJECT (memstream)); + camel_object_unref (CAMEL_OBJECT (memstream)); return text; } @@ -662,7 +681,7 @@ fake_mime_part_from_data (const char *data, int len, const char *type) return part; } -static void + static void destroy_part (GtkObject *root, GtkObject *part) { gtk_object_unref (part); @@ -787,7 +806,7 @@ try_inline_binhex (char *start, struct mail_format_data *mfd) } static void -free_byte_array (GtkWidget *widget, gpointer user_data) +free_byte_array (CamelObject *obj, gpointer event_data, gpointer user_data) { g_byte_array_free (user_data, TRUE); } @@ -946,8 +965,7 @@ handle_text_enriched (CamelMimePart *part, const char *mime_type, xed = g_strdup_printf ("x-evolution-data:%p", part); g_hash_table_insert (mfd->urls, xed, ba); - gtk_signal_connect (GTK_OBJECT (mfd->root), "destroy", - GTK_SIGNAL_FUNC (free_byte_array), ba); + camel_object_hook_event (CAMEL_OBJECT (mfd->root), "finalize", free_byte_array, ba); mail_html_write (mfd->html, mfd->stream, "", xed); diff --git a/mail/mail-identify.c b/mail/mail-identify.c index ba8a943f38..91c4efd5d7 100644 --- a/mail/mail-identify.c +++ b/mail/mail-identify.c @@ -101,7 +101,7 @@ mail_identify_mime_part (CamelMimePart *part) gnome_vfs_mime_sniff_buffer_free (sniffer); } else type = NULL; - gtk_object_unref (GTK_OBJECT (memstream)); + camel_object_unref (CAMEL_OBJECT (memstream)); if (type) return g_strdup (type); diff --git a/mail/mail-local.c b/mail/mail-local.c index 36ae9770a4..840df79f28 100644 --- a/mail/mail-local.c +++ b/mail/mail-local.c @@ -1,3 +1,29 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* mail-local.c: Local mailbox support. */ + +/* + * Author: + * Michael Zucchi + * Peter Williams + * + * Copyright 2000 Helix Code, Inc. (http://www.helixcode.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + /* code for handling local mail boxes @@ -24,6 +50,8 @@ #include "mail.h" #include "mail-local.h" +#include "mail-tools.h" +#include "mail-threads.h" #define d(x) @@ -105,12 +133,11 @@ save_metainfo(struct _local_meta *meta) } CamelFolder * -local_uri_to_folder(const char *uri, CamelException *ex) +mail_tool_local_uri_to_folder(const char *uri, CamelException *ex) { CamelURL *url; char *metapath; char *storename; - CamelStore *store; CamelFolder *folder = NULL; struct _local_meta *meta; @@ -136,12 +163,7 @@ local_uri_to_folder(const char *uri, CamelException *ex) printf("store name is %s\n", storename); - store = camel_session_get_store(session, storename, ex); - g_free(storename); - if (store) { - folder = camel_store_get_folder(store, meta->name, FALSE, ex); - gtk_object_unref((GtkObject *)store); - } + folder = mail_tool_get_folder_from_urlname (storename, meta->name, ex); camel_url_free(url); free_metainfo(meta); @@ -167,36 +189,86 @@ local_uri_to_folder(const char *uri, CamelException *ex) */ -static void update_progress(GtkProgress *progress, char *fmt, float percent) +static void update_progress(char *fmt, float percent) { if (fmt) - gtk_progress_set_format_string(progress, fmt); - gtk_progress_set_percentage(progress, percent); - while( gtk_events_pending() ) - gtk_main_iteration(); + mail_op_set_message ("%s", fmt); + mail_op_set_percentage (percent); +} + +/* ******************** */ + +typedef struct reconfigure_folder_input_s { + FolderBrowser *fb; + gchar *newtype; + GtkWidget *frame; + GtkWidget *apply; + GtkWidget *cancel; + GtkOptionMenu *optionlist; +} reconfigure_folder_input_t; + +static gchar *describe_reconfigure_folder (gpointer in_data, gboolean gerund); +static void setup_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex); +static void do_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex); +static void cleanup_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex); + +static gchar * +describe_reconfigure_folder (gpointer in_data, gboolean gerund) +{ + reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data; + + if (gerund) + return g_strdup_printf (_("Changing folder \"%s\" to \"%s\" format"), + input->fb->uri, + input->newtype); + else + return g_strdup_printf (_("Change folder \"%s\" to \"%s\" format"), + input->fb->uri, + input->newtype); } static void -do_local_reconfigure_folder(FolderBrowser *fb, char *newtype, GtkProgress *progress, CamelException *ex) +setup_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex) { - CamelStore *fromstore, *tostore; - char *fromurl, *tourl, *uri; - CamelFolder *fromfolder, *tofolder; - GPtrArray *uids; - int i; + reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data; + + if (!IS_FOLDER_BROWSER (input->fb)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "Input has a bad FolderBrowser in reconfigure_folder"); + return; + } + + if (!input->newtype) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No new folder type in reconfigure_folder"); + return; + } + + gtk_object_ref (GTK_OBJECT (input->fb)); +} + +static void +do_reconfigure_folder(gpointer in_data, gpointer op_data, CamelException *ex) +{ + reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data; + + CamelStore *fromstore = NULL, *tostore = NULL; + char *fromurl = NULL, *tourl = NULL; + CamelFolder *fromfolder = NULL, *tofolder = NULL; + char *metapath; char *tmpname; - CamelURL *url; + char *uri; + CamelURL *url = NULL; struct _local_meta *meta; - printf("reconfiguring folder: %s to type %s\n", fb->uri, newtype); + printf("reconfiguring folder: %s to type %s\n", input->fb->uri, input->newtype); /* get the actual location of the mailbox */ - url = camel_url_new(fb->uri, ex); - if (url == NULL || camel_exception_is_set(ex)) { - camel_exception_free(ex); - g_warning("%s is not a workable url!", fb->uri); - return; + url = camel_url_new(input->fb->uri, ex); + if (camel_exception_is_set(ex)) { + g_warning("%s is not a workable url!", input->fb->uri); + goto cleanup; } metapath = g_strdup_printf("%s/local-metadata.xml", url->path); @@ -204,173 +276,158 @@ do_local_reconfigure_folder(FolderBrowser *fb, char *newtype, GtkProgress *progr g_free(metapath); /* first, 'close' the old folder */ - if (fb->folder != NULL) { - update_progress(progress, "Closing current folder", 0.0); - printf("Closing old folder ...\n"); - camel_folder_sync(fb->folder, FALSE, ex); - gtk_object_unref (GTK_OBJECT (fb->folder)); - fb->folder = NULL; + if (input->fb->folder != NULL) { + update_progress("Closing current folder", 0.0); + + mail_tool_camel_lock_up (); + camel_folder_sync(input->fb->folder, FALSE, ex); + mail_tool_camel_lock_down (); + camel_object_unref (CAMEL_OBJECT (input->fb->folder)); + input->fb->folder = NULL; } camel_url_set_protocol(url, meta->format); fromurl = camel_url_to_string(url, TRUE); - camel_url_set_protocol(url, newtype); + camel_url_set_protocol(url, input->newtype); tourl = camel_url_to_string(url, TRUE); printf("opening stores %s and %s\n", fromurl, tourl); + + mail_tool_camel_lock_up (); fromstore = camel_session_get_store(session, fromurl, ex); - if (camel_exception_is_set(ex)) { - return; - } + mail_tool_camel_lock_down (); + + if (camel_exception_is_set(ex)) + goto cleanup; + + mail_tool_camel_lock_up (); tostore = camel_session_get_store(session, tourl, ex); - if (camel_exception_is_set(ex)) { - return; - } + mail_tool_camel_lock_down (); + if (camel_exception_is_set(ex)) + goto cleanup; /* rename the old mbox and open it again */ tmpname = g_strdup_printf("%s_reconfig", meta->name); - printf("renaming mbox to mboxtmp, and opening it\n"); - update_progress(progress, "Renaming old folder and opening", 0.0); + printf("renaming %s to %s, and opening it\n", meta->name, tmpname); + update_progress("Renaming old folder and opening", 0.0); + + mail_tool_camel_lock_up (); camel_store_rename_folder(fromstore, meta->name, tmpname, ex); if (camel_exception_is_set(ex)) { - return; + mail_tool_camel_lock_down (); + goto cleanup; } + fromfolder = camel_store_get_folder(fromstore, tmpname, TRUE, ex); if (fromfolder == NULL || camel_exception_is_set(ex)) { /* try and recover ... */ + camel_exception_clear (ex); camel_store_rename_folder(fromstore, tmpname, meta->name, ex); - return; + mail_tool_camel_lock_down (); + goto cleanup; } /* create a new mbox */ printf("Creating the destination mbox\n"); - update_progress(progress, "Creating new folder", 0.0); + update_progress("Creating new folder", 0.0); + tofolder = camel_store_get_folder(tostore, meta->name, TRUE, ex); if (tofolder == NULL || camel_exception_is_set(ex)) { printf("cannot open destination folder\n"); /* try and recover ... */ + camel_exception_clear (ex); camel_store_rename_folder(fromstore, tmpname, meta->name, ex); - return; + mail_tool_camel_lock_down (); + goto cleanup; } - /* copy the messages across */ - uids = camel_folder_get_uids (fromfolder); - printf("got %d messages in source\n", uids->len); - update_progress(progress, "Copying messages", 0.0); - for (i = 0; i < uids->len; i++) { - CamelMimeMessage *msg; - char *uid = uids->pdata[i]; - const CamelMessageInfo *info; - - update_progress(progress, NULL, i/uids->len); - - printf("copying message %s\n", uid); - msg = camel_folder_get_message(fromfolder, uid, ex); - if (camel_exception_is_set(ex)) { - /* we're fucked a bit ... */ - /* need to: delete new folder - rename old back again */ - g_warning("cannot get message"); - return; - } - info = camel_folder_get_message_info(fromfolder, uid); - camel_folder_append_message(tofolder, msg, info, ex); - if (camel_exception_is_set(ex)) { - /* we're fucked a bit ... */ - /* need to: delete new folder - rename old back again */ - g_warning("cannot append message"); - return; - } - gtk_object_unref((GtkObject *)msg); - } - update_progress(progress, "Synchronising", 0.0); + mail_tool_move_folder_contents (fromfolder, tofolder, FALSE, ex); - /* sync while we're doing i/o, just to make sure */ - camel_folder_sync(tofolder, FALSE, ex); - if (camel_exception_is_set(ex)) { - /* same again */ - } - - /* delete everything in the old mailbox */ - printf("deleting old mbox contents\n"); - for (i = 0; i < uids->len; i++) { - char *uid = uids->pdata[i]; - camel_folder_delete_message(fromfolder, uid); - } - camel_folder_sync(fromfolder, TRUE, ex); - gtk_object_unref((GtkObject *)fromfolder); - printf("and old mbox ...\n"); + printf("delete old mbox ...\n"); camel_store_delete_folder(fromstore, tmpname, ex); + mail_tool_camel_lock_down (); /* switch format */ g_free(meta->format); - meta->format = g_strdup(newtype); + meta->format = g_strdup(input->newtype); if (save_metainfo(meta) == -1) { - g_warning("Cannot save folder metainfo, you'll probably find you can't\n" - "open this folder anymore: %s", tourl); + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, "Cannot save folder metainfo; " + "you'll probably find you can't\n" + "open this folder anymore: %s", tourl); } free_metainfo(meta); /* force a reload of the newly formatted folder */ printf("opening new source\n"); - uri = g_strdup(fb->uri); - folder_browser_set_uri(fb, uri); + uri = g_strdup(input->fb->uri); + folder_browser_set_uri(input->fb, uri); g_free(uri); /* and unref our copy of the new folder ... */ - gtk_object_unref((GtkObject *)tofolder); - g_free(fromurl); - g_free(tourl); + cleanup: + if (tofolder) + camel_object_unref (CAMEL_OBJECT (tofolder)); + if (fromfolder) + camel_object_unref (CAMEL_OBJECT (fromfolder)); + if (fromstore) + camel_object_unref (CAMEL_OBJECT (fromstore)); + if (tostore) + camel_object_unref (CAMEL_OBJECT (tostore)); + if (fromurl) + g_free(fromurl); + if (tourl) + g_free(tourl); + if (url) + camel_url_free (url); } -struct _reconfig_data { - FolderBrowser *fb; - GtkProgress *progress; - GtkWidget *frame; - GtkWidget *apply; - GtkWidget *cancel; - GtkOptionMenu *optionlist; +static void +cleanup_reconfigure_folder (gpointer in_data, gpointer op_data, CamelException *ex) +{ + reconfigure_folder_input_t *input = (reconfigure_folder_input_t *) in_data; + + if (camel_exception_is_set(ex)) { + GtkWidget *win = gtk_widget_get_ancestor((GtkWidget *)input->frame, GTK_TYPE_WINDOW); + gnome_error_dialog_parented ("If you can no longer open this mailbox, then\n" + "you may need to repair it manually.", GTK_WINDOW (win)); + } + + gtk_object_unref (GTK_OBJECT (input->fb)); + g_free (input->newtype); +} + +static const mail_operation_spec op_reconfigure_folder = +{ + describe_reconfigure_folder, + 0, + setup_reconfigure_folder, + do_reconfigure_folder, + cleanup_reconfigure_folder }; static void -reconfigure_clicked(GnomeDialog *d, int button, struct _reconfig_data *data) +reconfigure_clicked(GnomeDialog *d, int button, reconfigure_folder_input_t *data) { if (button == 0) { GtkMenu *menu; int type; char *types[] = { "mh", "mbox" }; - CamelException *ex; - - ex = camel_exception_new(); menu = (GtkMenu *)gtk_option_menu_get_menu(data->optionlist); type = g_list_index(GTK_MENU_SHELL(menu)->children, gtk_menu_get_active(menu)); if (type < 0 || type > 1) type = 1; - gtk_progress_set_percentage(data->progress, 0.0); gtk_widget_set_sensitive(data->frame, FALSE); gtk_widget_set_sensitive(data->apply, FALSE); gtk_widget_set_sensitive(data->cancel, FALSE); - do_local_reconfigure_folder(data->fb, types[type], data->progress, ex); - if (camel_exception_is_set(ex)) { - GtkWidget *win = gtk_widget_get_ancestor((GtkWidget *)d, GTK_TYPE_WINDOW); - char *error; - - error = g_strdup_printf("A failure occured:\n %s\n\n" - "If you can no longer open this mailbox, then\n" - "you may need to repair it manually.", - camel_exception_get_description(ex)); - gnome_error_dialog_parented(error, GTK_WINDOW (win)); - g_free(error); - } - camel_exception_free(ex); + data->newtype = g_strdup (types[type]); + mail_operation_queue (&op_reconfigure_folder, data, TRUE); } - if (button != -1) { + + if (button != -1) gnome_dialog_close(d); - } } void @@ -379,33 +436,31 @@ local_reconfigure_folder(FolderBrowser *fb) CamelStore *store; GladeXML *gui; GnomeDialog *gd; - struct _reconfig_data *data; + reconfigure_folder_input_t *data; if (fb->folder == NULL) { g_warning("Trying to reconfigure nonexistant folder"); return; } - data = g_malloc0(sizeof(*data)); + data = g_new (reconfigure_folder_input_t, 1); store = camel_folder_get_parent_store(fb->folder); gui = glade_xml_new(EVOLUTION_GLADEDIR "/local-config.glade", "dialog_format"); gd = (GnomeDialog *)glade_xml_get_widget (gui, "dialog_format"); - data->progress = (GtkProgress *)glade_xml_get_widget (gui, "progress_format"); - gtk_progress_set_show_text(data->progress, TRUE); data->frame = glade_xml_get_widget (gui, "frame_format"); data->apply = glade_xml_get_widget (gui, "apply_format"); data->cancel = glade_xml_get_widget (gui, "cancel_format"); data->optionlist = (GtkOptionMenu *)glade_xml_get_widget (gui, "option_format"); + data->newtype = NULL; data->fb = fb; gtk_label_set_text((GtkLabel *)glade_xml_get_widget (gui, "label_format"), ((CamelService *)store)->url->protocol); gtk_signal_connect((GtkObject *)gd, "clicked", reconfigure_clicked, data); - gtk_object_set_data_full((GtkObject *)gd, "data", data, g_free); gtk_widget_show((GtkWidget *)gd); gtk_object_unref((GtkObject *)gui); } diff --git a/mail/mail-local.h b/mail/mail-local.h index f24d3c7a2f..331832cfc8 100644 --- a/mail/mail-local.h +++ b/mail/mail-local.h @@ -1,3 +1,28 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* mail-local.h: Local mailbox support. */ + +/* + * Author: + * Michael Zucchi + * + * Copyright 2000 Helix Code, Inc. (http://www.helixcode.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + #ifndef _MAIL_LOCAL_H #define _MAIL_LOCAL_H @@ -5,7 +30,7 @@ #include "folder-browser.h" /* mail-local.c */ -CamelFolder *local_uri_to_folder(const char *uri, CamelException *ex); +CamelFolder *mail_tool_local_uri_to_folder(const char *uri, CamelException *ex); void local_reconfigure_folder(FolderBrowser *fb); #endif diff --git a/mail/mail-ops.c b/mail/mail-ops.c index 77045cb79d..d235c6b2d9 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -2,9 +2,9 @@ /* mail-ops.c: callbacks for the mail toolbar/menus */ /* - * Authors: Dan Winship - * Jeffrey Stedfast - * Peter Williams + * Author : + * Dan Winship + * Peter Williams * * Copyright 2000 Helix Code, Inc. (http://www.helixcode.com) * @@ -25,1115 +25,1863 @@ */ #include -#include -#include #include -#include -#include #include "mail.h" #include "mail-threads.h" -#include "folder-browser.h" +#include "mail-tools.h" +#include "mail-ops.h" #include "e-util/e-setup.h" -#include "filter/filter-editor.h" -#include "filter/filter-driver.h" -#include "widgets/e-table/e-table.h" -#include "mail-local.h" +#include "composer/e-msg-composer.h" -/* FIXME: is there another way to do this? */ -#include "Evolution.h" -#include "evolution-storage.h" +/* ** FETCH MAIL ********************************************************** */ -#include "evolution-shell-client.h" +typedef struct fetch_mail_input_s +{ + gchar *source_url; + gboolean keep_on_server; + CamelFolder *destination; + gpointer hook_func; + gpointer hook_data; +} +fetch_mail_input_t; + +static gchar *describe_fetch_mail (gpointer in_data, gboolean gerund); +static void setup_fetch_mail (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_fetch_mail (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_fetch_mail (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_fetch_mail (gpointer in_data, gboolean gerund) +{ + fetch_mail_input_t *input = (fetch_mail_input_t *) in_data; -#ifndef HAVE_MKSTEMP -#include -#include -#endif + if (gerund) + return g_strdup_printf ("Fetching email from %s", + input->source_url); + else + return g_strdup_printf ("Fetch email from %s", + input->source_url); +} -struct post_send_data { - CamelFolder *folder; - const char *uid; - guint32 flags; +static void +setup_fetch_mail (gpointer in_data, gpointer op_data, CamelException * ex) +{ + fetch_mail_input_t *input = (fetch_mail_input_t *) in_data; + + if (!input->source_url) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "You have no remote mail source configured " + "to fetch mail from."); + return; + } + + if (input->destination == NULL) + return; + + if (!CAMEL_IS_FOLDER (input->destination)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "Bad folder passed to fetch_mail"); + return; + } + + camel_object_ref (CAMEL_OBJECT (input->destination)); +} + +static void +do_fetch_mail (gpointer in_data, gpointer op_data, CamelException * ex) +{ + fetch_mail_input_t *input; + CamelFolder *search_folder = NULL; + + input = (fetch_mail_input_t *) in_data; + + if (input->destination == NULL) { + input->destination = mail_tool_get_local_inbox (ex); + + if (input->destination == NULL) + return; + } + + search_folder = + mail_tool_fetch_mail_into_searchable (input->source_url, + input->keep_on_server, ex); + + if (search_folder == NULL) { + /* This happens with an IMAP source and on error */ + camel_object_unref (CAMEL_OBJECT (input->destination)); + input->destination = NULL; + return; + } + + mail_tool_filter_contents_into (search_folder, input->destination, + input->hook_func, input->hook_data, + ex); + camel_object_unref (CAMEL_OBJECT (search_folder)); +} + +static void +cleanup_fetch_mail (gpointer in_data, gpointer op_data, CamelException * ex) +{ + fetch_mail_input_t *input = (fetch_mail_input_t *) in_data; + + g_free (input->source_url); + if (input->destination) + camel_object_unref (CAMEL_OBJECT (input->destination)); +} + +static const mail_operation_spec op_fetch_mail = { + describe_fetch_mail, + 0, + setup_fetch_mail, + do_fetch_mail, + cleanup_fetch_mail }; -typedef struct rfm_s { - FolderBrowser *fb; - MailConfigService *source; -} rfm_t; +void +mail_do_fetch_mail (const gchar * source_url, gboolean keep_on_server, + CamelFolder * destination, + gpointer hook_func, gpointer hook_data) +{ + fetch_mail_input_t *input; -typedef struct rsm_s { - EMsgComposer *composer; - CamelTransport *transport; + input = g_new (fetch_mail_input_t, 1); + input->source_url = g_strdup (source_url); + input->keep_on_server = keep_on_server; + input->destination = destination; + input->hook_func = hook_func; + input->hook_data = hook_data; + + mail_operation_queue (&op_fetch_mail, input, TRUE); +} + +/* ** SEND MAIL *********************************************************** */ + +typedef struct send_mail_input_s +{ + gchar *xport_uri; CamelMimeMessage *message; - const char *subject; - char *from; - struct post_send_data *psd; - gboolean ok; -} rsm_t; + gchar *from; + + /* If done_folder != NULL, will add done_flags to + * the flags of the message done_uid in done_folder. */ + + CamelFolder *done_folder; + char *done_uid; + guint32 done_flags; + + GtkWidget *composer; +} +send_mail_input_t; + +static gchar *describe_send_mail (gpointer in_data, gboolean gerund); +static void setup_send_mail (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_send_mail (gpointer in_data, gpointer op_data, + + CamelException * ex); +static void cleanup_send_mail (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_send_mail (gpointer in_data, gboolean gerund) +{ + send_mail_input_t *input = (send_mail_input_t *) in_data; + + if (gerund) { + if (input->message->subject && input->message->subject[0]) + return g_strdup_printf ("Sending \"%s\"", + input->message->subject); + else + return + g_strdup + ("Sending a message without a subject"); + } else { + if (input->message->subject && input->message->subject[0]) + return g_strdup_printf ("Send \"%s\"", + input->message->subject); + else + return g_strdup ("Send a message without a subject"); + } +} static void -real_fetch_mail( gpointer user_data ); +setup_send_mail (gpointer in_data, gpointer op_data, CamelException * ex) +{ + send_mail_input_t *input = (send_mail_input_t *) in_data; + + if (!input->xport_uri) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No transport URI specified for send_mail operation."); + return; + } + + if (!CAMEL_IS_MIME_MESSAGE (input->message)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No message specified for send_mail operation."); + return; + } + + if (input->from == NULL) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No from address specified for send_mail operation."); + return; + } + + /* NOTE THE EARLY EXIT!! */ + + if (input->done_folder == NULL) { + camel_object_ref (CAMEL_OBJECT (input->message)); + gtk_object_ref (GTK_OBJECT (input->composer)); + gtk_widget_hide (GTK_WIDGET (input->composer)); + return; + } + + if (!CAMEL_IS_FOLDER (input->done_folder)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "Bad done_folder specified for send_mail operation."); + return; + } + + if (input->done_uid == NULL) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No done_uid specified for send_mail operation."); + return; + } + + if (!GTK_IS_WIDGET (input->composer)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No composer specified for send_mail operation."); + return; + } + + camel_object_ref (CAMEL_OBJECT (input->message)); + camel_object_ref (CAMEL_OBJECT (input->done_folder)); + gtk_object_ref (GTK_OBJECT (input->composer)); + gtk_widget_hide (GTK_WIDGET (input->composer)); +} static void -real_send_mail( gpointer user_data ); +do_send_mail (gpointer in_data, gpointer op_data, CamelException * ex) +{ + send_mail_input_t *input = (send_mail_input_t *) in_data; + CamelTransport *xport; + + mail_tool_camel_lock_up (); + camel_mime_message_set_from (input->message, input->from); + + camel_medium_add_header (CAMEL_MEDIUM (input->message), "X-Mailer", + "Evolution (Developer Preview)"); + camel_mime_message_set_date (input->message, + CAMEL_MESSAGE_DATE_CURRENT, 0); + + xport = camel_session_get_transport (session, input->xport_uri, ex); + mail_tool_camel_lock_down (); + if (camel_exception_is_set (ex)) + return; + + mail_tool_send_via_transport (xport, CAMEL_MEDIUM (input->message), + ex); + + if (camel_exception_is_set (ex)) + return; + + if (input->done_folder) { + guint32 set; + + mail_tool_camel_lock_up (); + set = camel_folder_get_message_flags (input->done_folder, + input->done_uid); + camel_folder_set_message_flags (input->done_folder, + input->done_uid, + input->done_flags, ~set); + mail_tool_camel_lock_down (); + } +} static void -cleanup_send_mail( gpointer userdata ); +cleanup_send_mail (gpointer in_data, gpointer op_data, CamelException * ex) +{ + send_mail_input_t *input = (send_mail_input_t *) in_data; + + camel_object_unref (CAMEL_OBJECT (input->message)); + if (input->done_folder) + camel_object_unref (CAMEL_OBJECT (input->done_folder)); + + g_free (input->from); + g_free (input->xport_uri); + g_free (input->done_uid); + + if (!camel_exception_is_set (ex)) + gtk_widget_destroy (input->composer); + else + gtk_widget_show (input->composer); +} + +static const mail_operation_spec op_send_mail = { + describe_send_mail, + 0, + setup_send_mail, + do_send_mail, + cleanup_send_mail +}; + +void +mail_do_send_mail (const char *xport_uri, + CamelMimeMessage * message, + const char * from, + CamelFolder * done_folder, + const char *done_uid, + guint32 done_flags, GtkWidget * composer) +{ + send_mail_input_t *input; + + input = g_new (send_mail_input_t, 1); + input->xport_uri = g_strdup (xport_uri); + input->message = message; + input->from = g_strdup (from); + input->done_folder = done_folder; + input->done_uid = g_strdup (done_uid); + input->done_flags = done_flags; + input->composer = composer; + + mail_operation_queue (&op_send_mail, input, TRUE); +} + +/* ** EXPUNGE FOLDER ****************************************************** */ + +static gchar *describe_expunge_folder (gpointer in_data, gboolean gerund); +static void setup_expunge_folder (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_expunge_folder (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_expunge_folder (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_expunge_folder (gpointer in_data, gboolean gerund) +{ + CamelFolder *f = CAMEL_FOLDER (in_data); + + if (gerund) + return g_strdup_printf ("Expunging \"%s\"", f->full_name); + else + return g_strdup_printf ("Expunge \"%s\"", f->full_name); +} static void -mail_exception_dialog (char *head, CamelException *ex, gpointer widget) +setup_expunge_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - char *msg; - GtkWindow *window = - GTK_WINDOW (gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW)); + if (!CAMEL_IS_FOLDER (in_data)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No folder is selected to be expunged"); + return; + } - msg = g_strdup_printf ("%s:\n%s", head, - camel_exception_get_description (ex)); - gnome_error_dialog_parented (msg, window); - g_free (msg); + camel_object_ref (CAMEL_OBJECT (in_data)); } -#ifdef USE_BROKEN_THREADS static void -async_mail_exception_dialog (char *head, CamelException *ex, gpointer unused ) +do_expunge_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - mail_op_error( "%s: %s", head, camel_exception_get_description( ex ) ); + mail_tool_camel_lock_up (); + camel_folder_expunge (CAMEL_FOLDER (in_data), ex); + mail_tool_camel_lock_down (); } -#else -#define async_mail_exception_dialog mail_exception_dialog -#endif -static gboolean -check_configured (void) +static void +cleanup_expunge_folder (gpointer in_data, gpointer op_data, + CamelException * ex) { - if (mail_config_is_configured ()) - return TRUE; - - mail_config_druid (); + camel_object_unref (CAMEL_OBJECT (in_data)); +} + +static const mail_operation_spec op_expunge_folder = { + describe_expunge_folder, + 0, + setup_expunge_folder, + do_expunge_folder, + cleanup_expunge_folder +}; - return mail_config_is_configured (); +void +mail_do_expunge_folder (CamelFolder * folder) +{ + mail_operation_queue (&op_expunge_folder, folder, FALSE); +} + +/* ** REFILE MESSAGES ***************************************************** */ + +typedef struct refile_messages_input_s +{ + CamelFolder *source; + GPtrArray *uids; + gchar *dest_uri; +} +refile_messages_input_t; + +static gchar *describe_refile_messages (gpointer in_data, gboolean gerund); +static void setup_refile_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_refile_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_refile_messages (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_refile_messages (gpointer in_data, gboolean gerund) +{ + refile_messages_input_t *input = (refile_messages_input_t *) in_data; + + if (gerund) + return + g_strdup_printf + ("Moving messages from \"%s\" into \"%s\"", + input->source->full_name, input->dest_uri); + else + return + g_strdup_printf + ("Move messages from \"%s\" into \"%s\"", + input->source->full_name, input->dest_uri); } static void -select_first_unread (CamelFolder *folder, int type, gpointer data) +setup_refile_messages (gpointer in_data, gpointer op_data, + CamelException * ex) { - FolderBrowser *fb = data; - ETable *table = E_TABLE_SCROLLED (fb->message_list->etable)->table; - int mrow; + refile_messages_input_t *input = (refile_messages_input_t *) in_data; - mrow = e_table_view_to_model_row (table, 0); - message_list_select (fb->message_list, mrow, MESSAGE_LIST_SELECT_NEXT, - 0, CAMEL_MESSAGE_SEEN); + if (!CAMEL_IS_FOLDER (input->source)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No source folder to refile messages from specified."); + return; + } + + if (input->uids == NULL) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No messages to refile have been specified."); + return; + } + + if (input->dest_uri == NULL) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No URI to refile to has been specified."); + return; + } + + camel_object_ref (CAMEL_OBJECT (input->source)); } -static CamelFolder * -filter_get_folder(FilterDriver *fd, const char *uri, void *data) +static void +do_refile_messages (gpointer in_data, gpointer op_data, CamelException * ex) { - return mail_uri_to_folder(uri); + refile_messages_input_t *input = (refile_messages_input_t *) in_data; + CamelFolder *dest; + gint i; + + dest = mail_tool_uri_to_folder (input->dest_uri, ex); + if (camel_exception_is_set (ex)) + return; + + mail_tool_camel_lock_up (); + for (i = 0; i < input->uids->len; i++) { + camel_folder_move_message_to (input->source, + input->uids->pdata[i], dest, + ex); + g_free (input->uids->pdata[i]); + if (camel_exception_is_set (ex)) + break; + } + + camel_object_unref (CAMEL_OBJECT (dest)); + mail_tool_camel_lock_down (); } static void -fetch_remote_mail (CamelFolder *source, CamelFolder *dest, - gboolean keep_on_server, FolderBrowser *fb, - CamelException *ex) +cleanup_refile_messages (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + refile_messages_input_t *input = (refile_messages_input_t *) in_data; + + camel_object_unref (CAMEL_OBJECT (input->source)); + g_free (input->dest_uri); + g_ptr_array_free (input->uids, TRUE); +} + +static const mail_operation_spec op_refile_messages = { + describe_refile_messages, + 0, + setup_refile_messages, + do_refile_messages, + cleanup_refile_messages +}; + +void +mail_do_refile_messages (CamelFolder * source, GPtrArray * uids, + gchar * dest_uri) +{ + refile_messages_input_t *input; + + input = g_new (refile_messages_input_t, 1); + input->source = source; + input->uids = uids; + input->dest_uri = g_strdup (dest_uri); + + mail_operation_queue (&op_refile_messages, input, TRUE); +} + +/* ** FLAG MESSAGES ******************************************************* */ + +typedef struct flag_messages_input_s { - CamelUIDCache *cache; + CamelFolder *source; GPtrArray *uids; - int i; + gboolean invert; + guint32 mask; + guint32 set; +} +flag_messages_input_t; + +static gchar *describe_flag_messages (gpointer in_data, gboolean gerund); +static void setup_flag_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_flag_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_flag_messages (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_flag_messages (gpointer in_data, gboolean gerund) +{ + flag_messages_input_t *input = (flag_messages_input_t *) in_data; - uids = camel_folder_get_uids (source); - if (keep_on_server) { - GPtrArray *new_uids; - char *url, *p, *filename; - - url = camel_url_to_string ( - CAMEL_SERVICE (source->parent_store)->url, FALSE); - for (p = url; *p; p++) { - if (!isascii ((unsigned char)*p) || - strchr (" /'\"`&();|<>${}!", *p)) - *p = '_'; - } - filename = g_strdup_printf ("%s/config/cache-%s", - evolution_dir, url); - g_free (url); - - cache = camel_uid_cache_new (filename); - g_free (filename); - if (cache) { - new_uids = camel_uid_cache_get_new_uids (cache, uids); - camel_folder_free_uids (source, uids); - uids = new_uids; + /* FIXME: change based on flags being applied? */ + + if (gerund) + return g_strdup_printf ("Marking messages in folder \"%s\"", + input->source->full_name); + else + return g_strdup_printf ("Mark messages in folder \"%s\"", + input->source->full_name); +} + +static void +setup_flag_messages (gpointer in_data, gpointer op_data, CamelException * ex) +{ + flag_messages_input_t *input = (flag_messages_input_t *) in_data; + + if (!CAMEL_IS_FOLDER (input->source)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No source folder to flag messages from specified."); + return; + } + + if (input->uids == NULL) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No messages to flag have been specified."); + return; + } + + camel_object_ref (CAMEL_OBJECT (input->source)); +} + +static void +do_flag_messages (gpointer in_data, gpointer op_data, CamelException * ex) +{ + flag_messages_input_t *input = (flag_messages_input_t *) in_data; + gint i; + + for (i = 0; i < input->uids->len; i++) { + if (input->invert) { + const CamelMessageInfo *info; + + mail_tool_camel_lock_up (); + info = camel_folder_get_message_info (input->source, input->uids->pdata[i]); + camel_folder_set_message_flags (input->source, input->uids->pdata[i], + input->mask, ~info->flags); + mail_tool_camel_lock_down (); } else { - async_mail_exception_dialog ("Could not read UID " - "cache file. You may " - "receive duplicate " - "messages.", NULL, fb); + mail_tool_set_uid_flags (input->source, input->uids->pdata[i], + input->mask, input->set); } - } else - cache = NULL; - printf ("got %d new messages in source\n", uids->len); - for (i = 0; i < uids->len; i++) { - CamelMimeMessage *msg; + g_free (input->uids->pdata[i]); + } +} - msg = camel_folder_get_message (source, uids->pdata[i], ex); - if (camel_exception_is_set (ex)) { - async_mail_exception_dialog ("Unable to get message", - ex, fb); - goto done; - } +static void +cleanup_flag_messages (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + flag_messages_input_t *input = (flag_messages_input_t *) in_data; - /* Append with flags = 0 since this is a new message */ - camel_folder_append_message (dest, msg, 0, ex); - if (camel_exception_is_set (ex)) { - async_mail_exception_dialog ("Unable to write message", - ex, fb); - gtk_object_unref (GTK_OBJECT (msg)); - goto done; - } + camel_object_unref (CAMEL_OBJECT (input->source)); + g_ptr_array_free (input->uids, TRUE); +} + +static const mail_operation_spec op_flag_messages = { + describe_flag_messages, + 0, + setup_flag_messages, + do_flag_messages, + cleanup_flag_messages +}; + +void +mail_do_flag_messages (CamelFolder * source, GPtrArray * uids, + gboolean invert, + guint32 mask, guint32 set) +{ + flag_messages_input_t *input; + + input = g_new (flag_messages_input_t, 1); + input->source = source; + input->uids = uids; + input->invert = invert; + input->mask = mask; + input->set = set; + + mail_operation_queue (&op_flag_messages, input, TRUE); +} + +/* ** SCAN SUBFOLDERS ***************************************************** */ + +typedef struct scan_subfolders_input_s +{ + gchar *source_uri; + gboolean add_INBOX; + EvolutionStorage *storage; +} +scan_subfolders_input_t; + +typedef struct scan_subfolders_folderinfo_s +{ + char *path; + char *uri; +} +scan_subfolders_folderinfo_t; + +typedef struct scan_subfolders_op_s +{ + GPtrArray *new_folders; +} +scan_subfolders_op_t; + +static gchar *describe_scan_subfolders (gpointer in_data, gboolean gerund); +static void setup_scan_subfolders (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_scan_subfolders (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_scan_subfolders (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_scan_subfolders (gpointer in_data, gboolean gerund) +{ + scan_subfolders_input_t *input = (scan_subfolders_input_t *) in_data; + + if (gerund) + return g_strdup_printf ("Scanning folders in \"%s\"", + input->source_uri); + else + return g_strdup_printf ("Scan folders in \"%s\"", + input->source_uri); +} + +static void +setup_scan_subfolders (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + scan_subfolders_input_t *input = (scan_subfolders_input_t *) in_data; + scan_subfolders_op_t *data = (scan_subfolders_op_t *) op_data; + + if (!input->source_uri) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No source uri to scan subfolders from was provided."); + return; + } + + if (!EVOLUTION_IS_STORAGE (input->storage)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No storage to scan subfolders into was provided."); + return; + } + + gtk_object_ref (GTK_OBJECT (input->storage)); + data->new_folders = g_ptr_array_new (); +} + +static void +do_scan_subfolders (gpointer in_data, gpointer op_data, CamelException * ex) +{ + scan_subfolders_input_t *input = (scan_subfolders_input_t *) in_data; + scan_subfolders_op_t *data = (scan_subfolders_op_t *) op_data; + + scan_subfolders_folderinfo_t *info; + GPtrArray *lsub; + CamelFolder *folder; + int i; + char *splice; + + if (input->source_uri[strlen (input->source_uri) - 1] == '/') + splice = ""; + else + splice = "/"; + + folder = mail_tool_get_root_of_store (input->source_uri, ex); + if (camel_exception_is_set (ex)) + return; + + mail_tool_camel_lock_up (); + + /* we need a way to set the namespace */ + lsub = camel_folder_get_subfolder_names (folder); + + mail_tool_camel_lock_down (); + + if (input->add_INBOX) { + info = g_new (scan_subfolders_folderinfo_t, 1); + info->path = g_strdup ("/INBOX"); + info->uri = + g_strdup_printf ("%s%sINBOX", input->source_uri, + splice); + g_ptr_array_add (data->new_folders, info); + } + + for (i = 0; i < lsub->len; i++) { + info = g_new (scan_subfolders_folderinfo_t, 1); + info->path = g_strdup_printf ("/%s", (char *) lsub->pdata[i]); + info->uri = + g_strdup_printf ("%s%s%s", input->source_uri, splice, + info->path); + g_ptr_array_add (data->new_folders, info); + } + + camel_folder_free_subfolder_names (folder, lsub); + camel_object_unref (CAMEL_OBJECT (folder)); +} + +static void +cleanup_scan_subfolders (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + scan_subfolders_input_t *input = (scan_subfolders_input_t *) in_data; + scan_subfolders_op_t *data = (scan_subfolders_op_t *) op_data; + + int i; + + for (i = 0; i < data->new_folders->len; i++) { + scan_subfolders_folderinfo_t *info; + + info = data->new_folders->pdata[i]; + evolution_storage_new_folder (input->storage, + info->path, + "mail", + info->uri, "(No description)"); + g_free (info->path); + g_free (info->uri); + g_free (info); + } + + g_ptr_array_free (data->new_folders, TRUE); + gtk_object_unref (GTK_OBJECT (input->storage)); + g_free (input->source_uri); +} + +static const mail_operation_spec op_scan_subfolders = { + describe_scan_subfolders, + sizeof (scan_subfolders_op_t), + setup_scan_subfolders, + do_scan_subfolders, + cleanup_scan_subfolders +}; + +void +mail_do_scan_subfolders (const gchar * source_uri, gboolean add_INBOX, + EvolutionStorage * storage) +{ + scan_subfolders_input_t *input; + + input = g_new (scan_subfolders_input_t, 1); + input->source_uri = g_strdup (source_uri); + input->add_INBOX = add_INBOX; + input->storage = storage; + + mail_operation_queue (&op_scan_subfolders, input, TRUE); +} + +/* ** ATTACH MESSAGE ****************************************************** */ + +typedef struct attach_message_input_s +{ + EMsgComposer *composer; + CamelFolder *folder; + gchar *uid; +} +attach_message_input_t; + +typedef struct attach_message_data_s +{ + CamelMimePart *part; +} +attach_message_data_t; + +static gchar *describe_attach_message (gpointer in_data, gboolean gerund); +static void setup_attach_message (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_attach_message (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_attach_message (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_attach_message (gpointer in_data, gboolean gerund) +{ + attach_message_input_t *input = (attach_message_input_t *) in_data; + + if (gerund) + return + g_strdup_printf + ("Attaching messages from folder \"%s\"", + input->folder->full_name); + else + return g_strdup_printf ("Attach messages from \"%s\"", + input->folder->full_name); +} - if (!cache) - camel_folder_delete_message (source, uids->pdata[i]); - gtk_object_unref (GTK_OBJECT (msg)); +static void +setup_attach_message (gpointer in_data, gpointer op_data, CamelException * ex) +{ + attach_message_input_t *input = (attach_message_input_t *) in_data; + + if (!input->uid) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No UID specified to attach."); + return; } - camel_folder_sync (source, TRUE, ex); + if (!CAMEL_IS_FOLDER (input->folder)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No folder to fetch the message from specified."); + return; + } - done: - if (cache) { - camel_uid_cache_free_uids (uids); - if (!camel_exception_is_set (ex)) - camel_uid_cache_save (cache); - camel_uid_cache_destroy (cache); - } else - camel_folder_free_uids (source, uids); + if (!E_IS_MSG_COMPOSER (input->composer)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No message composer from specified."); + return; + } + + camel_object_ref (CAMEL_OBJECT (input->folder)); + gtk_object_ref (GTK_OBJECT (input->composer)); } +static void +do_attach_message (gpointer in_data, gpointer op_data, CamelException * ex) +{ + attach_message_input_t *input = (attach_message_input_t *) in_data; + attach_message_data_t *data = (attach_message_data_t *) op_data; + + CamelMimeMessage *message; + CamelMimePart *part; + + mail_tool_camel_lock_up (); + message = camel_folder_get_message (input->folder, input->uid, ex); + if (!message) { + mail_tool_camel_lock_down (); + return; + } + + part = mail_tool_make_message_attachment (message); + camel_object_unref (CAMEL_OBJECT (message)); + mail_tool_camel_lock_down (); + if (!part) + return; + + data->part = part; +} + +static void +cleanup_attach_message (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + attach_message_input_t *input = (attach_message_input_t *) in_data; + attach_message_data_t *data = (attach_message_data_t *) op_data; + + e_msg_composer_attach (input->composer, data->part); + camel_object_unref (CAMEL_OBJECT (data->part)); + camel_object_unref (CAMEL_OBJECT (input->folder)); + gtk_object_unref (GTK_OBJECT (input->composer)); + g_free (input->uid); +} + +static const mail_operation_spec op_attach_message = { + describe_attach_message, + sizeof (attach_message_data_t), + setup_attach_message, + do_attach_message, + cleanup_attach_message +}; + void -real_fetch_mail (gpointer user_data) -{ - rfm_t *info; - FolderBrowser *fb = NULL; - CamelException *ex; - CamelStore *store = NULL, *dest_store = NULL; - CamelFolder *folder = NULL, *dest_folder = NULL; - char *url = NULL, *dest_url; - FilterContext *fc = NULL; - FilterDriver *driver = NULL; - char *userrules, *systemrules; - char *tmp_mbox = NULL, *source; - guint handler_id = 0; - struct stat st; - gboolean keep; - - info = (rfm_t *) user_data; - fb = info->fb; - url = info->source->url; - keep = info->source->keep_on_server; - - /* If using IMAP, don't do anything... */ - if (!strncmp (url, "imap:", 5)) +mail_do_attach_message (CamelFolder * folder, const char *uid, + EMsgComposer * composer) +{ + attach_message_input_t *input; + + input = g_new (attach_message_input_t, 1); + input->folder = folder; + input->uid = g_strdup (uid); + input->composer = composer; + + mail_operation_queue (&op_attach_message, input, TRUE); +} + +/* ** FORWARD MESSAGES **************************************************** */ + +typedef struct forward_messages_input_s +{ + CamelMimeMessage *basis; + CamelFolder *source; + GPtrArray *uids; + EMsgComposer *composer; +} +forward_messages_input_t; + +typedef struct forward_messages_data_s +{ + gchar *subject; + GPtrArray *parts; +} +forward_messages_data_t; + +static gchar *describe_forward_messages (gpointer in_data, gboolean gerund); +static void setup_forward_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_forward_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_forward_messages (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_forward_messages (gpointer in_data, gboolean gerund) +{ + forward_messages_input_t *input = + + (forward_messages_input_t *) in_data; + + if (gerund) { + if (input->basis->subject) + return g_strdup_printf ("Forwarding messages \"%s\"", + input->basis->subject); + else + return + g_strdup_printf + ("Forwarding a message without a subject"); + } else { + if (input->basis->subject) + return g_strdup_printf ("Forward message \"%s\"", + input->basis->subject); + else + return + g_strdup_printf + ("Forward a message without a subject"); + } +} + +static void +setup_forward_messages (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + forward_messages_input_t *input = + + (forward_messages_input_t *) in_data; + + if (!input->uids) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No UIDs specified to attach."); return; + } - ex = camel_exception_new (); + if (!CAMEL_IS_MIME_MESSAGE (input->basis)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No basic message to forward was specified."); + return; + } - dest_url = g_strdup_printf ("mbox://%s/local/Inbox", evolution_dir); - dest_store = camel_session_get_store (session, dest_url, ex); - g_free (dest_url); - if (!dest_store) { - async_mail_exception_dialog ("Unable to get new mail", ex, fb); - goto cleanup; + if (!CAMEL_IS_FOLDER (input->source)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No folder to fetch the messages from specified."); + return; } - - dest_folder = camel_store_get_folder (dest_store, "mbox", FALSE, ex); - if (!dest_folder) { - async_mail_exception_dialog ("Unable to get new mail", ex, fb); - goto cleanup; + + if (!E_IS_MSG_COMPOSER (input->composer)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No message composer from specified."); + return; } - tmp_mbox = g_strdup_printf ("%s/local/Inbox/movemail", evolution_dir); - - /* If fetching mail from an mbox store, safely copy it to a - * temporary store first. - */ - if (!strncmp (url, "mbox:", 5)) { - int tmpfd; + camel_object_ref (CAMEL_OBJECT (input->basis)); + camel_object_ref (CAMEL_OBJECT (input->source)); + gtk_object_ref (GTK_OBJECT (input->composer)); +} - tmpfd = open (tmp_mbox, O_RDWR | O_CREAT | O_APPEND, 0660); +static void +do_forward_messages (gpointer in_data, gpointer op_data, CamelException * ex) +{ + forward_messages_input_t *input = - if (tmpfd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - "Couldn't create temporary " - "mbox: %s", g_strerror (errno)); - async_mail_exception_dialog ("Unable to move mail", ex, fb ); - goto cleanup; - } - close (tmpfd); - - /* Skip over "mbox:" plus host part (if any) of url. */ - source = url + 5; - if (!strncmp (source, "//", 2)) - source = strchr (source + 2, '/'); - - camel_movemail (source, tmp_mbox, ex); - if (camel_exception_is_set (ex)) { - async_mail_exception_dialog ("Unable to move mail", - ex, fb); - goto cleanup; - } + (forward_messages_input_t *) in_data; + forward_messages_data_t *data = (forward_messages_data_t *) op_data; - if (stat (tmp_mbox, &st) == -1 || st.st_size == 0) { - gnome_ok_dialog ("No new messages."); - goto cleanup; - } + CamelMimeMessage *message; + CamelMimePart *part; + int i; - folder = camel_store_get_folder (dest_store, "movemail", - FALSE, ex); - if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE) { - async_mail_exception_dialog ("Unable to move mail", ex, fb); - goto cleanup; - } - } else { - CamelFolder *sourcefolder; - - store = camel_session_get_store(session, url, ex); - if (!store) { - async_mail_exception_dialog("Unable to get new mail", ex, fb); - goto cleanup; - } - - camel_service_connect(CAMEL_SERVICE (store), ex); - if (camel_exception_get_id(ex) != CAMEL_EXCEPTION_NONE) { - if (camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) - async_mail_exception_dialog("Unable to get new mail", ex, fb); - goto cleanup; - } + data->parts = g_ptr_array_new (); - sourcefolder = camel_store_get_folder(store, "inbox", FALSE, ex); - if (camel_exception_get_id(ex) != CAMEL_EXCEPTION_NONE) { - async_mail_exception_dialog("Unable to get new mail", ex, fb); - goto cleanup; + mail_tool_camel_lock_up (); + for (i = 0; i < input->uids->len; i++) { + message = + camel_folder_get_message (input->source, + input->uids->pdata[i], ex); + g_free (input->uids->pdata[i]); + if (!message) { + mail_tool_camel_lock_down (); + return; } - - /* can we perform filtering on this source? */ - if (!(sourcefolder->has_summary_capability - && sourcefolder->has_search_capability)) { - folder = camel_store_get_folder (dest_store, - "movemail", TRUE, ex); - if (camel_exception_is_set (ex)) { - async_mail_exception_dialog ("Unable to move mail", ex, fb); - goto cleanup; - } - - fetch_remote_mail (sourcefolder, folder, keep, fb, ex); - gtk_object_unref (GTK_OBJECT (sourcefolder)); - if (camel_exception_is_set (ex)) - goto cleanup; - } else { - folder = sourcefolder; + part = mail_tool_make_message_attachment (message); + if (!part) { + camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, + "Failed to generate mime part from " + "message while generating forwarded message."); + mail_tool_camel_lock_down (); + return; } + camel_object_unref (CAMEL_OBJECT (message)); + g_ptr_array_add (data->parts, part); } - if (camel_folder_get_message_count (folder) == 0) { - gnome_ok_dialog ("No new messages."); - goto cleanup; - } else if (camel_exception_is_set (ex)) { - async_mail_exception_dialog ("Unable to get new mail", ex, fb); - goto cleanup; - } + mail_tool_camel_lock_down (); - folder_browser_clear_search (fb); + data->subject = mail_tool_generate_forward_subject (input->basis); +} - /* apply filtering rules to this inbox */ - fc = filter_context_new(); - userrules = g_strdup_printf("%s/filters.xml", evolution_dir); - systemrules = g_strdup_printf("%s/evolution/filtertypes.xml", EVOLUTION_DATADIR); - rule_context_load((RuleContext *)fc, systemrules, userrules); - g_free (userrules); - g_free (systemrules); +static void +cleanup_forward_messages (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + forward_messages_input_t *input = - driver = filter_driver_new(fc, filter_get_folder, 0); + (forward_messages_input_t *) in_data; + forward_messages_data_t *data = (forward_messages_data_t *) op_data; - /* Attach a handler to the destination folder to select the first unread - * message iff it changes and iff it's the folder being viewed. - */ - if (dest_folder == fb->folder) - handler_id = gtk_signal_connect (GTK_OBJECT (dest_folder), "folder_changed", - GTK_SIGNAL_FUNC (select_first_unread), fb); + int i; - if (filter_driver_run(driver, folder, dest_folder) == -1) { - async_mail_exception_dialog ("Unable to get new mail", ex, fb); - goto cleanup; + for (i = 0; i < data->parts->len; i++) { + e_msg_composer_attach (input->composer, + data->parts->pdata[i]); + camel_object_unref (CAMEL_OBJECT (data->parts->pdata[i])); } + camel_object_unref (CAMEL_OBJECT (input->source)); + + e_msg_composer_set_headers (input->composer, NULL, NULL, NULL, + data->subject); + + gtk_object_unref (GTK_OBJECT (input->composer)); + g_free (data->subject); + g_ptr_array_free (data->parts, TRUE); + g_ptr_array_free (input->uids, TRUE); + gtk_widget_show (GTK_WIDGET (input->composer)); +} - if (dest_folder == fb->folder) - gtk_signal_disconnect (GTK_OBJECT (dest_folder), handler_id); +static const mail_operation_spec op_forward_messages = { + describe_forward_messages, + sizeof (forward_messages_data_t), + setup_forward_messages, + do_forward_messages, + cleanup_forward_messages +}; - cleanup: - if (stat (tmp_mbox, &st) == 0 && st.st_size == 0) - unlink (tmp_mbox); /* FIXME: should use camel to do this */ - g_free (tmp_mbox); +void +mail_do_forward_message (CamelMimeMessage * basis, + CamelFolder * source, + GPtrArray * uids, EMsgComposer * composer) +{ + forward_messages_input_t *input; - if (driver) - gtk_object_unref((GtkObject *)driver); - if (fc) - gtk_object_unref((GtkObject *)fc); + input = g_new (forward_messages_input_t, 1); + input->basis = basis; + input->source = source; + input->uids = uids; + input->composer = composer; - if (folder) { - camel_folder_sync (folder, TRUE, ex); - gtk_object_unref (GTK_OBJECT (folder)); - } + mail_operation_queue (&op_forward_messages, input, TRUE); +} - if (dest_folder) { - camel_folder_sync (dest_folder, TRUE, ex); - gtk_object_unref (GTK_OBJECT (dest_folder)); - } +/* ** LOAD FOLDER ********************************************************* */ - if (store) { - camel_service_disconnect (CAMEL_SERVICE (store), ex); - gtk_object_unref (GTK_OBJECT (store)); - } +typedef struct load_folder_input_s +{ + FolderBrowser *fb; + gchar *url; +} +load_folder_input_t; + +static gchar *describe_load_folder (gpointer in_data, gboolean gerund); +static void setup_load_folder (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_load_folder (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_load_folder (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_load_folder (gpointer in_data, gboolean gerund) +{ + load_folder_input_t *input = (load_folder_input_t *) in_data; - if (dest_store && dest_store != fb->folder->parent_store) { - camel_service_disconnect (CAMEL_SERVICE (dest_store), ex); - gtk_object_unref (GTK_OBJECT (dest_store)); + if (gerund) { + return g_strdup_printf ("Loading \"%s\"", input->url); + } else { + return g_strdup_printf ("Load \"%s\"", input->url); } - camel_exception_free (ex); } -void -fetch_mail (GtkWidget *button, gpointer user_data) +static void +setup_load_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - MailConfigService *source; - rfm_t *info; + load_folder_input_t *input = (load_folder_input_t *) in_data; - if (!check_configured ()) + if (!IS_FOLDER_BROWSER (input->fb)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No folder browser specified to load into."); return; + } - source = mail_config_get_default_source (); - if (!source || !source->url) { - GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (user_data), - GTK_TYPE_WINDOW); - - gnome_error_dialog_parented ("You have no remote mail source " - "configured", GTK_WINDOW (win)); + if (!input->url) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No URL to load was specified."); return; } - /* This must be dynamically allocated so as not to be clobbered - * when we return. Actually, making it static in the whole file - * would probably work. - */ + gtk_object_ref (GTK_OBJECT (input->fb)); - info = g_new (rfm_t, 1); - info->fb = FOLDER_BROWSER (user_data); - info->source = source; + if (input->fb->uri) + g_free (input->fb->uri); -#ifdef USE_BROKEN_THREADS - mail_operation_try (_("Fetching mail"), real_fetch_mail, NULL, info); -#else - real_fetch_mail (info); -#endif + input->fb->uri = input->url; } -static gboolean -ask_confirm_for_empty_subject (EMsgComposer *composer) +static void +do_load_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - GtkWidget *message_box; - int button; + load_folder_input_t *input = (load_folder_input_t *) in_data; + + CamelFolder *folder; - message_box = gnome_message_box_new (_("This message has no subject.\nReally send?"), - GNOME_MESSAGE_BOX_QUESTION, - GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, - NULL); + folder = mail_tool_uri_to_folder (input->url, ex); + if (!folder) + return; - button = gnome_dialog_run_and_close (GNOME_DIALOG (message_box)); + if (input->fb->folder) { + mail_tool_camel_lock_up (); + camel_object_unref (CAMEL_OBJECT (input->fb->folder)); + mail_tool_camel_lock_down (); + } - if (button == 0) - return TRUE; - else - return FALSE; + input->fb->folder = folder; } static void -set_x_mailer_header (CamelMedium *medium) +cleanup_load_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - char *mailer_string; + load_folder_input_t *input = (load_folder_input_t *) in_data; - mailer_string = g_strdup_printf ("Evolution %s (Developer Preview)", VERSION); + gtk_widget_set_sensitive (GTK_WIDGET (input->fb->search_entry), + camel_folder_has_search_capability (input-> + fb-> + folder)); + gtk_widget_set_sensitive (GTK_WIDGET (input->fb->search_menu), + camel_folder_has_search_capability (input-> + fb-> + folder)); - camel_medium_add_header (medium, "X-Mailer", mailer_string); + message_list_set_folder (input->fb->message_list, input->fb->folder); - g_free (mailer_string); + /*g_free (input->url); = fb->uri now */ } -static void -real_send_mail (gpointer user_data) -{ - rsm_t *info = (rsm_t *) user_data; - EMsgComposer *composer = NULL; - CamelTransport *transport = NULL; - CamelException *ex = NULL; - CamelMimeMessage *message = NULL; - const char *subject = NULL; - char *from = NULL; - struct post_send_data *psd = NULL; - -#ifdef USE_BROKEN_THREADS - mail_op_hide_progressbar (); - mail_op_set_message ("Connecting to transport..."); -#endif - - ex = camel_exception_new (); - composer = info->composer; - transport = info->transport; - message = info->message; - subject = info->subject; - from = info->from; - psd = info->psd; +static const mail_operation_spec op_load_folder = { + describe_load_folder, + 0, + setup_load_folder, + do_load_folder, + cleanup_load_folder +}; - set_x_mailer_header (CAMEL_MEDIUM (message)); +void +mail_do_load_folder (FolderBrowser * fb, const char *url) +{ + load_folder_input_t *input; - camel_mime_message_set_from (message, from); - camel_mime_message_set_date (message, CAMEL_MESSAGE_DATE_CURRENT, 0); + input = g_new (load_folder_input_t, 1); + input->fb = fb; + input->url = g_strdup (url); - camel_service_connect (CAMEL_SERVICE (transport), ex); + mail_operation_queue (&op_load_folder, input, TRUE); +} -#ifdef USE_BROKEN_THREADS - mail_op_set_message ("Connected. Sending..."); -#endif +/* ** CREATE FOLDER ******************************************************* */ - if (!camel_exception_is_set (ex)) - camel_transport_send (transport, CAMEL_MEDIUM (message), ex); +typedef struct create_folder_input_s +{ + Evolution_ShellComponentListener listener; + char *uri; + char *type; +} +create_folder_input_t; - if (!camel_exception_is_set (ex)) { -#ifdef USE_BROKEN_THREADS - mail_op_set_message ("Sent. Disconnecting..."); -#endif - camel_service_disconnect (CAMEL_SERVICE (transport), ex); - } +typedef struct create_folder_data_s +{ + Evolution_ShellComponentListener_Result result; +} +create_folder_data_t; + +static gchar *describe_create_folder (gpointer in_data, gboolean gerund); +static void setup_create_folder (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_create_folder (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_create_folder (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_create_folder (gpointer in_data, gboolean gerund) +{ + create_folder_input_t *input = (create_folder_input_t *) in_data; - if (camel_exception_is_set (ex)) { - async_mail_exception_dialog ("Could not send message", ex, composer); - info->ok = FALSE; + if (gerund) { + return g_strdup_printf ("Creating \"%s\"", input->uri); } else { - if (psd) { - camel_folder_set_message_flags (psd->folder, psd->uid, - psd->flags, psd->flags); - } - info->ok = TRUE; - + return g_strdup_printf ("Create \"%s\"", input->uri); } - - camel_exception_free (ex); } static void -cleanup_send_mail (gpointer userdata) +setup_create_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - rsm_t *info = (rsm_t *) userdata; - - if (info->ok) { - gtk_object_destroy (GTK_OBJECT (info->composer)); - } - - gtk_object_unref (GTK_OBJECT (info->message)); - g_free (info); -} + create_folder_input_t *input = (create_folder_input_t *) in_data; -static void -composer_send_cb (EMsgComposer *composer, gpointer data) -{ - const MailConfigIdentity *id = NULL; - static CamelTransport *transport = NULL; - struct post_send_data *psd = data; - rsm_t *info; - static char *from = NULL; - const char *subject; - CamelException *ex; - CamelMimeMessage *message; - char *name, *addr; - - ex = camel_exception_new (); - - id = mail_config_get_default_identity (); - - if (!check_configured() || !id) { - GtkWidget *message; - - message = gnome_warning_dialog_parented (_("You need to configure an identity\n" - "before you can send mail."), - GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (composer), - GTK_TYPE_WINDOW))); - gnome_dialog_run_and_close (GNOME_DIALOG (message)); + if (input->listener == CORBA_OBJECT_NIL) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "Invalid listener passed to create_folder"); return; } - - from = g_strdup (e_msg_composer_hdrs_get_from (E_MSG_COMPOSER_HDRS (composer->hdrs))); - if (!from) { - CamelInternetAddress *ciaddr; - - g_assert (id); - - name = id->name; - g_assert (name); - - addr = id->address; - g_assert (addr); - - ciaddr = camel_internet_address_new (); - camel_internet_address_add (ciaddr, name, addr); - - from = camel_address_encode (CAMEL_ADDRESS (ciaddr)); - } - - if (!transport) { - MailConfigService *t; - char *url; - - t = mail_config_get_transport (); - url = t->url; - g_assert (url); - - transport = camel_session_get_transport (session, url, ex); - if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE) { - mail_exception_dialog ("Could not load mail transport", - ex, composer); - camel_exception_free (ex); - return; - } + + if (input->uri == NULL) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "Invalid url passed to create_folder"); + return; } - - message = e_msg_composer_get_message (composer); - - subject = camel_mime_message_get_subject (message); - if (!subject || !*subject) { - if (!ask_confirm_for_empty_subject (composer)) { - gtk_object_unref (GTK_OBJECT (message)); - return; - } + + if (input->type == NULL) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No type passed to create_folder"); + return; } - - info = g_new0 (rsm_t, 1); - info->composer = composer; - info->transport = transport; - info->message = message; - info->subject = subject; - info->from = from; - info->psd = psd; - -#ifdef USE_BROKEN_THREADS - mail_operation_try ("Send Message", real_send_mail, cleanup_send_mail, info); -#else - real_send_mail (info); - cleanup_send_mail (info); -#endif + + /* FIXME: reference listener somehow? */ } static void -free_psd (GtkWidget *composer, gpointer user_data) +do_create_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - struct post_send_data *psd = user_data; + create_folder_input_t *input = (create_folder_input_t *) in_data; + create_folder_data_t *data = (create_folder_data_t *) op_data; - gtk_object_unref (GTK_OBJECT (psd->folder)); - g_free (psd); + CamelFolder *folder; + gchar *camel_url; + + if (strcmp (input->type, "mail") != 0) + data->result = + Evolution_ShellComponentListener_UNSUPPORTED_TYPE; + else { + camel_url = g_strdup_printf ("mbox://%s", input->uri); + folder = mail_tool_get_folder_from_urlname (camel_url, + "mbox", ex); + g_free (camel_url); + + if (!camel_exception_is_set (ex)) { + camel_object_unref (CAMEL_OBJECT (folder)); + data->result = Evolution_ShellComponentListener_OK; + } else { + data->result = + Evolution_ShellComponentListener_INVALID_URI; + } + } } -static GtkWidget * -create_msg_composer (const char *url) +static void +cleanup_create_folder (gpointer in_data, gpointer op_data, + CamelException * ex) { - MailConfigIdentity *id; - gboolean send_html; - gchar *sig_file = NULL; - GtkWidget *composer_widget; + create_folder_input_t *input = (create_folder_input_t *) in_data; + create_folder_data_t *data = (create_folder_data_t *) op_data; - id = mail_config_get_default_identity (); - send_html = mail_config_send_html (); - - if (id) { - sig_file = id->sig; - } - - if (url != NULL) - composer_widget = e_msg_composer_new_from_url (url); - else - composer_widget = e_msg_composer_new_with_sig_file (sig_file); + CORBA_Environment ev; + + CORBA_exception_init (&ev); + Evolution_ShellComponentListener_report_result (input->listener, + data->result, &ev); + if (ev._major != CORBA_NO_EXCEPTION) + camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, + "Exception while reporting result to shell " + "component listener."); + CORBA_exception_free (&ev); - e_msg_composer_set_send_html (E_MSG_COMPOSER (composer_widget), - send_html); + /* FIXME: unref listener somehow? */ - return composer_widget; + g_free (input->uri); + g_free (input->type); } +static const mail_operation_spec op_create_folder = { + describe_create_folder, + sizeof (create_folder_data_t), + setup_create_folder, + do_create_folder, + cleanup_create_folder +}; + void -compose_msg (GtkWidget *widget, gpointer user_data) +mail_do_create_folder (const Evolution_ShellComponentListener listener, + const char *uri, const char *type) { - GtkWidget *composer; - - if (!check_configured ()) - return; - - composer = create_msg_composer (NULL); - - gtk_signal_connect (GTK_OBJECT (composer), "send", - GTK_SIGNAL_FUNC (composer_send_cb), NULL); - gtk_widget_show (composer); + create_folder_input_t *input; + + input = g_new (create_folder_input_t, 1); + input->listener = listener; + input->uri = g_strdup (uri); + input->type = g_strdup (type); + + mail_operation_queue (&op_create_folder, input, FALSE); } -/* Send according to a mailto (RFC 2368) URL. */ -void -send_to_url (const char *url) -{ - GtkWidget *composer; +/* ** SYNC FOLDER ********************************************************* */ - if (!check_configured ()) - return; +static gchar *describe_sync_folder (gpointer in_data, gboolean gerund); +static void setup_sync_folder (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_sync_folder (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_sync_folder (gpointer in_data, gpointer op_data, + CamelException * ex); - composer = create_msg_composer (url); +static gchar * +describe_sync_folder (gpointer in_data, gboolean gerund) +{ + CamelFolder *f = CAMEL_FOLDER (in_data); - gtk_signal_connect (GTK_OBJECT (composer), "send", - GTK_SIGNAL_FUNC (composer_send_cb), NULL); - gtk_widget_show (composer); -} + if (gerund) { + return g_strdup_printf ("Synchronizing \"%s\"", f->full_name); + } else { + return g_strdup_printf ("Synchronize \"%s\"", f->full_name); + } +} static void -reply (FolderBrowser *fb, gboolean to_all) +setup_sync_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - EMsgComposer *composer; - struct post_send_data *psd; - - if (!check_configured () || !fb->message_list->cursor_uid || - !fb->mail_display->current_message) + if (!CAMEL_IS_FOLDER (in_data)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No folder is selected to be synced"); return; + } - psd = g_new (struct post_send_data, 1); - psd->folder = fb->folder; - gtk_object_ref (GTK_OBJECT (psd->folder)); - psd->uid = fb->message_list->cursor_uid; - psd->flags = CAMEL_MESSAGE_ANSWERED; - - composer = mail_generate_reply (fb->mail_display->current_message, to_all); - - gtk_signal_connect (GTK_OBJECT (composer), "send", - GTK_SIGNAL_FUNC (composer_send_cb), psd); - gtk_signal_connect (GTK_OBJECT (composer), "destroy", - GTK_SIGNAL_FUNC (free_psd), psd); + camel_object_ref (CAMEL_OBJECT (in_data)); +} - gtk_widget_show (GTK_WIDGET (composer)); +static void +do_sync_folder (gpointer in_data, gpointer op_data, CamelException * ex) +{ + mail_tool_camel_lock_up (); + camel_folder_sync (CAMEL_FOLDER (in_data), FALSE, ex); + mail_tool_camel_lock_down (); } -void -reply_to_sender (GtkWidget *widget, gpointer user_data) +static void +cleanup_sync_folder (gpointer in_data, gpointer op_data, CamelException * ex) { - reply (FOLDER_BROWSER (user_data), FALSE); + camel_object_unref (CAMEL_OBJECT (in_data)); } +static const mail_operation_spec op_sync_folder = { + describe_sync_folder, + 0, + setup_sync_folder, + do_sync_folder, + cleanup_sync_folder +}; + void -reply_to_all (GtkWidget *widget, gpointer user_data) +mail_do_sync_folder (CamelFolder * folder) { - reply (FOLDER_BROWSER (user_data), TRUE); + mail_operation_queue (&op_sync_folder, folder, FALSE); } -static void -attach_msg (MessageList *ml, const char *uid, gpointer data) +/* ** DISPLAY MESSAGE ***************************************************** */ + +typedef struct display_message_input_s { - EMsgComposer *composer = data; - CamelMimeMessage *message; - CamelMimePart *part; - const char *subject; - char *desc; - - message = camel_folder_get_message (ml->folder, uid, NULL); - if (!message) - return; - subject = camel_mime_message_get_subject (message); - if (subject) - desc = g_strdup_printf ("Forwarded message - %s", subject); - else - desc = g_strdup ("Forwarded message"); - - part = camel_mime_part_new (); - camel_mime_part_set_disposition (part, "inline"); - camel_mime_part_set_description (part, desc); - camel_medium_set_content_object (CAMEL_MEDIUM (part), - CAMEL_DATA_WRAPPER (message)); - camel_mime_part_set_content_type (part, "message/rfc822"); - - e_msg_composer_attach (composer, part); - - gtk_object_unref (GTK_OBJECT (part)); - gtk_object_unref (GTK_OBJECT (message)); - g_free (desc); + MessageList *ml; + gchar *uid; + gint (*timeout) (gpointer); } +display_message_input_t; -void -forward_msg (GtkWidget *widget, gpointer user_data) +typedef struct display_message_data_s { - FolderBrowser *fb = FOLDER_BROWSER (user_data); - EMsgComposer *composer; - CamelMimeMessage *cursor_msg; - const char *from, *subject; - char *fwd_subj; - - cursor_msg = fb->mail_display->current_message; - if (!check_configured () || !cursor_msg) - return; - - composer = E_MSG_COMPOSER (create_msg_composer (NULL)); - message_list_foreach (fb->message_list, attach_msg, composer); - - from = camel_mime_message_get_from (cursor_msg); - subject = camel_mime_message_get_subject (cursor_msg); - if (from) { - if (subject && *subject) { - fwd_subj = g_strdup_printf ("[%s] %s", from, subject); - } else { - fwd_subj = g_strdup_printf ("[%s] (forwarded message)", - from); - } + CamelMimeMessage *msg; +} +display_message_data_t; + +static gchar *describe_display_message (gpointer in_data, gboolean gerund); +static void setup_display_message (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_display_message (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_display_message (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_display_message (gpointer in_data, gboolean gerund) +{ + display_message_input_t *input = (display_message_input_t *) in_data; + + if (gerund) { + if (input->uid) + return g_strdup_printf ("Displaying message UID \"%s\"", + input->uid); + else + return g_strdup ("Clearing message display"); } else { - fwd_subj = NULL; + if (input->uid) + return g_strdup_printf ("Display message UID \"%s\"", + input->uid); + else + return g_strdup ("Clear message dispaly"); } +} - e_msg_composer_set_headers (composer, NULL, NULL, NULL, fwd_subj); - g_free (fwd_subj); +static void +setup_display_message (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + display_message_input_t *input = (display_message_input_t *) in_data; + display_message_data_t *data = (display_message_data_t *) op_data; + + if (!IS_MESSAGE_LIST (input->ml)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "Invalid message list passed to display_message"); + return; + } - gtk_signal_connect (GTK_OBJECT (composer), "send", - GTK_SIGNAL_FUNC (composer_send_cb), NULL); + if (!input->timeout) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No timeout callback passed to display_message"); + return; + } - gtk_widget_show (GTK_WIDGET (composer)); + data->msg = NULL; + gtk_object_ref (GTK_OBJECT (input->ml)); } -struct move_data { - CamelFolder *source, *dest; - CamelException *ex; -}; - static void -real_move_msg (MessageList *ml, const char *uid, gpointer user_data) +do_display_message (gpointer in_data, gpointer op_data, CamelException * ex) { - struct move_data *rfd = user_data; + display_message_input_t *input = (display_message_input_t *) in_data; + display_message_data_t *data = (display_message_data_t *) op_data; - if (camel_exception_is_set (rfd->ex)) + if (input->uid == NULL) { + data->msg = NULL; return; + } - camel_folder_move_message_to (rfd->source, uid, rfd->dest, rfd->ex); + data->msg = camel_folder_get_message (input->ml->folder, + input->uid, ex); } -void -move_msg (GtkWidget *widget, gpointer user_data) -{ - FolderBrowser *fb = user_data; - MessageList *ml = fb->message_list; - char *uri, *physical, *path; - struct move_data rfd; - const char *allowed_types[] = { "mail", NULL }; - extern EvolutionShellClient *global_shell_client; - static char *last = NULL; - - if (!last) - last = g_strdup (""); - - evolution_shell_client_user_select_folder (global_shell_client, - _("Move message(s) to"), - last, allowed_types, &uri, &physical); - if (!uri) - return; +static void +cleanup_display_message (gpointer in_data, gpointer op_data, + CamelException * ex) +{ + display_message_input_t *input = (display_message_input_t *) in_data; + display_message_data_t *data = (display_message_data_t *) op_data; + + MailDisplay *md = input->ml->parent_folder_browser->mail_display; + + if (data->msg == NULL) { + mail_display_set_message (md, NULL); + } else { + if (input->ml->seen_id) + gtk_timeout_remove (input->ml->seen_id); + + mail_display_set_message (md, CAMEL_MEDIUM (data->msg)); + camel_object_unref (CAMEL_OBJECT (data->msg)); - path = strchr (uri, '/'); - if (path && strcmp (last, path) != 0) { - g_free (last); - last = g_strdup (path); + input->ml->seen_id = + gtk_timeout_add (1500, input->timeout, input->ml); } - g_free (uri); - rfd.source = ml->folder; - rfd.dest = mail_uri_to_folder (physical); - g_free (physical); - if (!rfd.dest) - return; - rfd.ex = camel_exception_new (); - - message_list_foreach (ml, real_move_msg, &rfd); - gtk_object_unref (GTK_OBJECT (rfd.dest)); - - if (camel_exception_is_set (rfd.ex)) - mail_exception_dialog ("Could not move message", rfd.ex, fb); - camel_exception_free (rfd.ex); + if (input->uid) + g_free (input->uid); + gtk_object_unref (GTK_OBJECT (input->ml)); } +static const mail_operation_spec op_display_message = { + describe_display_message, + sizeof (display_message_data_t), + setup_display_message, + do_display_message, + cleanup_display_message +}; + void -mark_all_seen (BonoboUIHandler *uih, void *user_data, const char *path) +mail_do_display_message (MessageList * ml, const char *uid, + gint (*timeout) (gpointer)) { - FolderBrowser *fb = FOLDER_BROWSER(user_data); - MessageList *ml = fb->message_list; - GPtrArray *uids; - int i; + display_message_input_t *input; - uids = camel_folder_get_uids (ml->folder); - for (i = 0; i < uids->len; i++) { - camel_folder_set_message_flags (ml->folder, uids->pdata[i], - CAMEL_MESSAGE_SEEN, - CAMEL_MESSAGE_SEEN); - } + input = g_new (display_message_input_t, 1); + input->ml = ml; + input->uid = g_strdup (uid); + input->timeout = timeout; + + mail_operation_queue (&op_display_message, input, FALSE); } -static void -real_edit_msg (MessageList *ml, const char *uid, gpointer user_data) +/* ** EDIT MESSAGES ******************************************************* */ + +typedef struct edit_messages_input_s { + CamelFolder *folder; + GPtrArray *uids; + GtkSignalFunc signal; +} edit_messages_input_t; + +typedef struct edit_messages_data_s { + GPtrArray *messages; +} edit_messages_data_t; + +static gchar *describe_edit_messages (gpointer in_data, gboolean gerund); +static void setup_edit_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_edit_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_edit_messages (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_edit_messages (gpointer in_data, gboolean gerund) { - CamelException *ex = user_data; - CamelMimeMessage *msg; - GtkWidget *composer; - - if (camel_exception_is_set (ex)) - return; - - msg = camel_folder_get_message (ml->folder, uid, ex); - - composer = e_msg_composer_new_with_message (msg); - gtk_signal_connect (GTK_OBJECT (composer), "send", - GTK_SIGNAL_FUNC (composer_send_cb), NULL); - gtk_widget_show (composer); + edit_messages_input_t *input = (edit_messages_input_t *) in_data; + + if (gerund) + return g_strdup_printf + ("Opening messages from folder \"%s\"", + input->folder->full_name); + else + return g_strdup_printf ("Open messages from \"%s\"", + input->folder->full_name); } -void -edit_msg (GtkWidget *widget, gpointer user_data) +static void +setup_edit_messages (gpointer in_data, gpointer op_data, CamelException * ex) { - FolderBrowser *fb = FOLDER_BROWSER (user_data); - MessageList *ml = fb->message_list; - CamelException ex; - extern CamelFolder *drafts_folder; - - camel_exception_init (&ex); - - if (fb->folder != drafts_folder) { - camel_exception_setv (&ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION, - "FIXME: some error message about not being in the Drafts folder..."); - mail_exception_dialog ("Could not open message for editing", &ex, fb); + edit_messages_input_t *input = (edit_messages_input_t *) in_data; + + if (!input->uids) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No UIDs specified to edit."); return; } - - message_list_foreach (ml, real_edit_msg, &ex); - if (camel_exception_is_set (&ex)) { - mail_exception_dialog ("Could not open message for editing", &ex, fb); - camel_exception_clear (&ex); + + if (!CAMEL_IS_FOLDER (input->folder)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No folder to fetch the messages from specified."); return; } -} -void -edit_message (BonoboUIHandler *uih, void *user_data, const char *path) -{ - edit_msg (NULL, user_data); + camel_object_ref (CAMEL_OBJECT (input->folder)); } static void -real_delete_msg (MessageList *ml, const char *uid, gpointer user_data) +do_edit_messages (gpointer in_data, gpointer op_data, CamelException * ex) { - CamelException *ex = user_data; - guint32 flags; + edit_messages_input_t *input = (edit_messages_input_t *) in_data; + edit_messages_data_t *data = (edit_messages_data_t *) op_data; - if (camel_exception_is_set (ex)) - return; + int i; - /* Toggle the deleted flag without touching other flags. */ - flags = camel_folder_get_message_flags (ml->folder, uid); - camel_folder_set_message_flags (ml->folder, uid, - CAMEL_MESSAGE_DELETED, ~flags); -} + data->messages = g_ptr_array_new (); -void -delete_msg (GtkWidget *button, gpointer user_data) -{ - FolderBrowser *fb = user_data; - MessageList *ml = fb->message_list; - CamelException ex; - - camel_exception_init (&ex); - message_list_foreach (ml, real_delete_msg, &ex); - if (camel_exception_is_set (&ex)) { - mail_exception_dialog ("Could not toggle deleted flag", - &ex, fb); - camel_exception_clear (&ex); - return; + for (i = 0; i < input->uids->len; i++) { + CamelMimeMessage *message; + + mail_tool_camel_lock_up (); + message = camel_folder_get_message (input->folder, input->uids->pdata[i], ex); + mail_tool_camel_lock_down (); + + if (message) + g_ptr_array_add (data->messages, message); + + g_free (input->uids->pdata[i]); } } -static void real_expunge_folder (gpointer user_data) +static void +cleanup_edit_messages (gpointer in_data, gpointer op_data, + CamelException * ex) { - FolderBrowser *fb = FOLDER_BROWSER (user_data); - CamelException ex; + edit_messages_input_t *input = (edit_messages_input_t *) in_data; + edit_messages_data_t *data = (edit_messages_data_t *) op_data; - e_table_model_pre_change(fb->message_list->table_model); + int i; -#ifdef USE_BROKEN_THREADS - mail_op_hide_progressbar (); - mail_op_set_message ("Expunging %s...", fb->message_list->folder->full_name); -#endif + for (i = 0; i < data->messages->len; i++) { + GtkWidget *composer; - camel_exception_init (&ex); + composer = e_msg_composer_new_with_message (data->messages->pdata[i]); - camel_folder_expunge (fb->message_list->folder, &ex); + if (input->signal) + gtk_signal_connect (GTK_OBJECT (composer), "send", + input->signal, NULL); - /* FIXME: is there a better way to force an update? */ - /* FIXME: Folder should raise a signal to say its contents has changed ... */ - e_table_model_changed (fb->message_list->table_model); + gtk_widget_show (composer); - if (camel_exception_get_id (&ex) != CAMEL_EXCEPTION_NONE) { - async_mail_exception_dialog ("Unable to expunge deleted messages", &ex, fb); + camel_object_unref (CAMEL_OBJECT (data->messages->pdata[i])); } + + g_ptr_array_free (input->uids, TRUE); + g_ptr_array_free (data->messages, TRUE); + camel_object_unref (CAMEL_OBJECT (input->folder)); + } +static const mail_operation_spec op_edit_messages = { + describe_edit_messages, + sizeof (edit_messages_data_t), + setup_edit_messages, + do_edit_messages, + cleanup_edit_messages +}; + void -expunge_folder (BonoboUIHandler *uih, void *user_data, const char *path) +mail_do_edit_messages (CamelFolder * folder, GPtrArray *uids, + GtkSignalFunc signal) { - FolderBrowser *fb = FOLDER_BROWSER(user_data); + edit_messages_input_t *input; - if (fb->message_list->folder) { -#ifdef USE_BROKEN_THREADS - mail_operation_try ("Expunge Folder", real_expunge_folder, NULL, fb); -#else - real_expunge_folder (fb); -#endif - } + input = g_new (edit_messages_input_t, 1); + input->folder = folder; + input->uids = uids; + input->signal = signal; + + mail_operation_queue (&op_edit_messages, input, TRUE); } -static void -filter_druid_clicked(GtkWidget *w, int button, FolderBrowser *fb) -{ - FilterContext *fc; +/* ** SETUP DRAFTBOX ****************************************************** */ - if (button == 0) { - char *user; +static gchar *describe_setup_draftbox (gpointer in_data, gboolean gerund); +static void noop_setup_draftbox (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_setup_draftbox (gpointer in_data, gpointer op_data, + CamelException * ex); - fc = gtk_object_get_data((GtkObject *)w, "context"); - user = g_strdup_printf("%s/filters.xml", evolution_dir); - rule_context_save((RuleContext *)fc, user); - g_free(user); - } - - if (button != -1) { - gnome_dialog_close((GnomeDialog *)w); - } +static gchar * +describe_setup_draftbox (gpointer in_data, gboolean gerund) +{ + if (gerund) + return g_strdup_printf ("Loading Draftbox"); + else + return g_strdup_printf ("Load Draftbox"); } -void -filter_edit (BonoboUIHandler *uih, void *user_data, const char *path) +static void +noop_setup_draftbox (gpointer in_data, gpointer op_data, CamelException * ex) { - FolderBrowser *fb = FOLDER_BROWSER (user_data); - FilterContext *fc; - char *user, *system; - GtkWidget *w; - - fc = filter_context_new(); - user = g_strdup_printf("%s/filters.xml", evolution_dir); - system = g_strdup_printf("%s/evolution/filtertypes.xml", EVOLUTION_DATADIR); - rule_context_load((RuleContext *)fc, system, user); - g_free(user); - g_free(system); - w = filter_editor_construct(fc); - gtk_object_set_data_full((GtkObject *)w, "context", fc, (GtkDestroyNotify)gtk_object_unref); - gtk_signal_connect((GtkObject *)w, "clicked", filter_druid_clicked, fb); - gtk_widget_show(w); } -void -vfolder_edit_vfolders (BonoboUIHandler *uih, void *user_data, const char *path) +static void +do_setup_draftbox (gpointer in_data, gpointer op_data, CamelException * ex) { - void vfolder_edit(void); + extern CamelFolder *drafts_folder; + gchar *url; - vfolder_edit(); + url = g_strdup_printf ("mbox://%s/local/Drafts", evolution_dir); + drafts_folder = mail_tool_get_folder_from_urlname (url, "mbox", ex); + g_free (url); } +/* + *static void + *cleanup_setup_draftbox (gpointer in_data, gpointer op_data, + * CamelException * ex) + *{ + *} + */ + +static const mail_operation_spec op_setup_draftbox = { + describe_setup_draftbox, + 0, + noop_setup_draftbox, + do_setup_draftbox, + noop_setup_draftbox +}; + void -providers_config (BonoboUIHandler *uih, void *user_data, const char *path) +mail_do_setup_draftbox (void) { - mail_config(); + mail_operation_queue (&op_setup_draftbox, NULL, FALSE); } -void -print_msg (GtkWidget *button, gpointer user_data) +/* ** VIEW MESSAGES ******************************************************* */ + +typedef struct view_messages_input_s { + CamelFolder *folder; + GPtrArray *uids; + FolderBrowser *fb; +} view_messages_input_t; + +typedef struct view_messages_data_s { + GPtrArray *messages; +} view_messages_data_t; + +static gchar *describe_view_messages (gpointer in_data, gboolean gerund); +static void setup_view_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void do_view_messages (gpointer in_data, gpointer op_data, + CamelException * ex); +static void cleanup_view_messages (gpointer in_data, gpointer op_data, + CamelException * ex); + +static gchar * +describe_view_messages (gpointer in_data, gboolean gerund) +{ + view_messages_input_t *input = (view_messages_input_t *) in_data; + + if (gerund) + return g_strdup_printf + ("Viewing messages from folder \"%s\"", + input->folder->full_name); + else + return g_strdup_printf ("View messages from \"%s\"", + input->folder->full_name); +} + +static void +setup_view_messages (gpointer in_data, gpointer op_data, CamelException * ex) { - FolderBrowser *fb = user_data; - GnomePrintMaster *print_master; - GnomePrintContext *print_context; - GtkWidget *preview; + view_messages_input_t *input = (view_messages_input_t *) in_data; + + if (!input->uids) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No UIDs specified to view."); + return; + } - print_master = gnome_print_master_new (); + if (!CAMEL_IS_FOLDER (input->folder)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No folder to fetch the messages from specified."); + return; + } - print_context = gnome_print_master_get_context (print_master); - gtk_html_print (fb->mail_display->html, print_context); + if (!IS_FOLDER_BROWSER (input->fb)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No folder browser was specified."); + return; + } - preview = GTK_WIDGET (gnome_print_master_preview_new ( - print_master, "Mail Print Preview")); - gtk_widget_show (preview); - gtk_object_unref (GTK_OBJECT (print_master)); + camel_object_ref (CAMEL_OBJECT (input->folder)); + gtk_object_ref (GTK_OBJECT (input->fb)); } -void -configure_folder(BonoboUIHandler *uih, void *user_data, const char *path) +static void +do_view_messages (gpointer in_data, gpointer op_data, CamelException * ex) { - FolderBrowser *fb = FOLDER_BROWSER(user_data); + view_messages_input_t *input = (view_messages_input_t *) in_data; + view_messages_data_t *data = (view_messages_data_t *) op_data; - local_reconfigure_folder(fb); -} + int i; + data->messages = g_ptr_array_new (); -struct view_msg_data { - FolderBrowser *fb; - CamelException *ex; -}; + for (i = 0; i < input->uids->len; i++) { + CamelMimeMessage *message; -static void -real_view_msg (MessageList *ml, const char *uid, gpointer user_data) -{ - struct view_msg_data *data = user_data; - FolderBrowser *fb; - CamelMimeMessage *msg; - GtkWidget *view; - - if (camel_exception_is_set (data->ex)) - return; - - msg = camel_folder_get_message (ml->folder, uid, data->ex); - - fb = FOLDER_BROWSER (folder_browser_new ()); - folder_browser_set_uri (fb, data->fb->uri); - - fb->message_list->cursor_uid = uid; - fb->mail_display->current_message = msg; - - view = mail_view_create (fb); - - gtk_widget_show (view); + mail_tool_camel_lock_up (); + message = camel_folder_get_message (input->folder, input->uids->pdata[i], ex); + mail_tool_camel_lock_down (); + + g_ptr_array_add (data->messages, message); + } } -void -view_msg (GtkWidget *widget, gpointer user_data) +static void +cleanup_view_messages (gpointer in_data, gpointer op_data, + CamelException * ex) { - struct view_msg_data data; - FolderBrowser *fb = user_data; - FolderBrowser *folder_browser; - CamelException ex; - MessageList *ml; - - camel_exception_init (&ex); - - data.fb = fb; - data.ex = &ex; - - ml = fb->message_list; - message_list_foreach (ml, real_view_msg, &data); - if (camel_exception_is_set (&ex)) { - mail_exception_dialog ("Could not open message for viewing", &ex, fb); - camel_exception_clear (&ex); - return; + view_messages_input_t *input = (view_messages_input_t *) in_data; + view_messages_data_t *data = (view_messages_data_t *) op_data; + + int i; + + for (i = 0; i < data->messages->len; i++) { + CamelMimeMessage *msg; + gchar *uid; + GtkWidget *view; + + if (data->messages->pdata[i] == NULL) + continue; + + msg = data->messages->pdata[i]; + uid = input->uids->pdata[i]; + + view = mail_view_create (input->folder, uid, msg); + gtk_widget_show (view); + + /*Owned by the mail_display now*/ + camel_object_unref (CAMEL_OBJECT (data->messages->pdata[i])); + g_free (uid); } + + g_ptr_array_free (input->uids, TRUE); + g_ptr_array_free (data->messages, TRUE); + camel_object_unref (CAMEL_OBJECT (input->folder)); + gtk_object_unref (GTK_OBJECT (input->fb)); } +static const mail_operation_spec op_view_messages = { + describe_view_messages, + sizeof (view_messages_data_t), + setup_view_messages, + do_view_messages, + cleanup_view_messages +}; + void -view_message (BonoboUIHandler *uih, void *user_data, const char *path) +mail_do_view_messages (CamelFolder * folder, GPtrArray *uids, + FolderBrowser *fb) { - view_msg (NULL, user_data); + view_messages_input_t *input; + + input = g_new (view_messages_input_t, 1); + input->folder = folder; + input->uids = uids; + input->fb = fb; + + mail_operation_queue (&op_view_messages, input, TRUE); } diff --git a/mail/mail-threads.c b/mail/mail-threads.c index a5dbac2427..7f5e796a51 100644 --- a/mail/mail-threads.c +++ b/mail/mail-threads.c @@ -24,8 +24,6 @@ #include -#ifdef USE_BROKEN_THREADS - #include #include #include "mail.h" @@ -35,7 +33,7 @@ /* FIXME TODO: Do we need operations that don't get a progress window because * they're quick, but we still want camel to be locked? We need some kind - * of flag to mail_operation_try, but then we also need some kind of monitor + * of flag to mail_operation_queue, but then we also need some kind of monitor * to open the window if it takes more than a second or something. That would * probably entail another thread.... */ @@ -44,37 +42,56 @@ * A function and its userdata **/ -typedef struct closure_s { - void (*callback)( gpointer ); - void (*cleanup)( gpointer ); - gpointer data; - - gchar *prettyname; - /* gboolean gets_window; */ -} closure_t; +typedef struct closure_s +{ + gpointer in_data; + gboolean free_in_data; + gpointer op_data; + const mail_operation_spec *spec; + CamelException *ex; + gchar *infinitive; + gchar *gerund; +} +closure_t; /** * A command issued through the compipe **/ -typedef struct com_msg_s { - enum com_msg_type_e { STARTING, PERCENTAGE, HIDE_PBAR, SHOW_PBAR, MESSAGE, PASSWORD, ERROR, FINISHED } type; +typedef struct com_msg_s +{ + enum com_msg_type_e { + STARTING, + PERCENTAGE, + HIDE_PBAR, + SHOW_PBAR, + MESSAGE, + PASSWORD, + ERROR, + FINISHED + } type; gfloat percentage; gchar *message; - void (*func)( gpointer ); - gpointer userdata; + closure_t *clur; /* Password stuff */ gchar **reply; gboolean secret; gboolean *success; -} com_msg_t; +} +com_msg_t; + +/** + * @dispatch_thread_started: gboolean that tells us whether + * the dispatch thread has been launched. + **/ + +static gboolean dispatch_thread_started = FALSE; /** - * @mail_operation_in_progress: When true, there's - * another thread executing a major ev-mail operation: - * fetch_mail, etc. + * @queue_len : the number of operations pending + * and being executed. * * Because camel is not thread-safe we work * with the restriction that more than one mailbox @@ -82,7 +99,7 @@ typedef struct com_msg_s { * concurrently check mail and move messages, etc. **/ -static gboolean mail_operation_in_progress; +static gint queue_len = 0; /** * @queue_window: The little window on the screen that @@ -110,27 +127,22 @@ static GtkWidget *queue_window_progress = NULL; static int progress_timeout_handle = -1; /** - * @op_queue: The list of operations the are scheduled - * to proceed after the currently executing one. When - * only one operation is going, this is NULL. - **/ - -static GSList *op_queue = NULL; - -/** - * @compipe: The pipe through which the dispatcher communicates + * @main_compipe: The pipe through which the dispatcher communicates * with the main thread for GTK+ calls * * @chan_reader: the GIOChannel that reads our pipe * - * @READER: the fd in our pipe that.... reads! - * @WRITER: the fd in our pipe that.... writes! + * @MAIN_READER: the fd in our main pipe that.... reads! + * @MAIN_WRITER: the fd in our main pipe that.... writes! */ -#define READER compipe[0] -#define WRITER compipe[1] +#define MAIN_READER main_compipe[0] +#define MAIN_WRITER main_compipe[1] +#define DISPATCH_READER dispatch_compipe[0] +#define DISPATCH_WRITER dispatch_compipe[1] -static int compipe[2] = { -1, -1 }; +static int main_compipe[2] = { -1, -1 }; +static int dispatch_compipe[2] = { -1, -1 }; GIOChannel *chan_reader = NULL; @@ -146,28 +158,50 @@ GIOChannel *chan_reader = NULL; * the dispatch thread may proceed its operations. */ -G_LOCK_DEFINE_STATIC( modal_lock ); +G_LOCK_DEFINE_STATIC (modal_lock); static GCond *modal_cond = NULL; static gboolean modal_may_proceed = FALSE; +/** + * @ready_for_op: A lock that the main thread only releases + * when it is ready for the dispatch thread to do its thing + * + * @ready_cond: A condition for this ... condition + * + * @ready_may_proceed: a gboolean telling the dispatch thread + * when it may proceed. + **/ + +G_LOCK_DEFINE_STATIC (ready_for_op); +static GCond *ready_cond = NULL; +static gboolean ready_may_proceed = FALSE; + /** * Static prototypes **/ -static void create_queue_window( void ); -static void dispatch( closure_t *clur ); -static void *dispatch_func( void *data ); -static void check_compipe( void ); -static void check_cond( void ); -static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer userdata ); -static void remove_next_pending( void ); -static void show_error( com_msg_t *msg ); -static void show_error_clicked( void ); -static void get_password( com_msg_t *msg ); -static void get_password_cb( gchar *string, gpointer data ); -static void get_password_clicked( GnomeDialog *dialog, gint button, gpointer user_data ); -static gboolean progress_timeout( gpointer data ); -static void timeout_toggle( gboolean active ); +static void create_queue_window (void); +static void destroy_queue_window (void); +static void *dispatch (void * data); +static void check_dispatcher (void); +static void check_compipes (void); +static void check_cond (void); +static gboolean read_msg (GIOChannel * source, GIOCondition condition, + gpointer userdata); +static void remove_next_pending (void); +static void show_error (com_msg_t * msg); +static void show_error_clicked (GtkObject * obj); +static void get_password (com_msg_t * msg); +static void get_password_cb (gchar * string, gpointer data); +static void get_password_clicked (GnomeDialog * dialog, gint button, + + gpointer user_data); +static gboolean progress_timeout (gpointer data); +static void timeout_toggle (gboolean active); +static gboolean display_timeout (gpointer data); +static closure_t *new_closure (const mail_operation_spec * spec, gpointer input, + gboolean free_in_data); +static void free_closure (closure_t *clur); /* Pthread code */ /* FIXME: support other thread types!!!! */ @@ -190,17 +224,25 @@ static pthread_t dispatch_thread; * enough. */ -#else /* defined USE_PTHREADS */ -choke on this: no thread type defined +#elif defined( G_THREADS_IMPL_SOLARIS ) + +#include + +static thread_t dispatch_thread; + +#else /* no supported thread impl */ +void +f (void) +{ + Error_No_supported_thread_implementation_recognized (); + choke on this; +} #endif /** - * mail_operation_try: - * @description: A user-friendly string describing the operation. - * @callback: the function to call in another thread to start the operation - * @cleanup: the function to call in the main thread when the callback is finished. - * NULL is allowed. - * @user_data: extra data passed to the callback + * mail_operation_queue: + * @spec: describes the operation to be performed + * @input: input data for the operation. * * Runs a mail operation asynchronously. If no other operation is running, * we start another thread and call the callback in that thread. The function @@ -215,66 +257,75 @@ choke on this: no thread type defined **/ gboolean -mail_operation_try( const gchar *description, void (*callback)( gpointer ), - void (*cleanup)( gpointer ), gpointer user_data ) +mail_operation_queue (const mail_operation_spec * spec, gpointer input, + gboolean free_in_data) { closure_t *clur; - g_assert( callback ); - - clur = g_new( closure_t, 1 ); - clur->callback = callback; - clur->cleanup = cleanup; - clur->data = user_data; - clur->prettyname = g_strdup( description ); - - if( mail_operation_in_progress == FALSE ) { - /* No operations are going on, none are pending. So - * we check to see if we're initialized (create the - * window and the pipes), and send off the operation - * on its merry way. - */ - mail_operation_in_progress = TRUE; + g_assert (spec); + + clur = new_closure (spec, input, free_in_data); + + if (spec->setup) + (spec->setup) (clur->in_data, clur->op_data, clur->ex); + + if (camel_exception_is_set (clur->ex)) { + if (clur->ex->id != CAMEL_EXCEPTION_USER_CANCEL) { + GtkWidget *err_dialog; + gchar *msg; + + msg = + g_strdup_printf + ("Error while preparing to %s:\n" "%s", + clur->infinitive, + camel_exception_get_description (clur->ex)); + err_dialog = gnome_error_dialog (msg); + g_free (msg); + gnome_dialog_set_close (GNOME_DIALOG (err_dialog), + TRUE); + /*gnome_dialog_run_and_close (GNOME_DIALOG (err_dialog)); */ + /*gtk_widget_destroy (err_dialog); */ + gtk_widget_show (GTK_WIDGET (err_dialog)); + + g_warning ("Setup failed for `%s': %s", + clur->infinitive, + camel_exception_get_description (clur-> + ex)); + } - check_compipe(); - create_queue_window(); - gtk_widget_show_all( queue_window ); - gnome_win_hints_set_layer( queue_window, - WIN_LAYER_ONTOP ); - gnome_win_hints_set_state( queue_window, - WIN_STATE_ARRANGE_IGNORE ); - gnome_win_hints_set_hints( queue_window, - WIN_HINTS_SKIP_FOCUS | - WIN_HINTS_SKIP_WINLIST | - WIN_HINTS_SKIP_TASKBAR ); - gtk_widget_hide( queue_window_pending ); + free_closure (clur); + return FALSE; + } - dispatch( clur ); + if (queue_len == 0) { + check_cond (); + check_compipes (); + check_dispatcher (); + create_queue_window (); + /*gtk_widget_show_all (queue_window); */ + gtk_timeout_add (1000, display_timeout, NULL); } else { GtkWidget *label; - /* Zut. We already have an operation running. Well, - * queue ourselves up. - * - * Yes, g_slist_prepend is faster down here.. But we pop - * operations off the beginning of the list later and - * that's a lot faster. + /* We already have an operation running. Well, + * queue ourselves up. (visually) */ - op_queue = g_slist_append( op_queue, clur ); - /* Show us in the pending window. */ - label = gtk_label_new( description ); - gtk_misc_set_alignment( GTK_MISC( label ), 1.0, 0.5 ); - gtk_box_pack_start( GTK_BOX( queue_window_pending ), label, - FALSE, TRUE, 2 ); + label = gtk_label_new (clur->infinitive); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_box_pack_start (GTK_BOX (queue_window_pending), label, + FALSE, TRUE, 2); + gtk_widget_show (label); /* If we want the next op to be on the bottom, uncomment this */ /* 1 = first on list always (0-based) */ /* gtk_box_reorder_child( GTK_BOX( queue_window_pending ), label, 1 ); */ - gtk_widget_show_all( queue_window_pending ); + gtk_widget_show (queue_window_pending); } + write (DISPATCH_WRITER, clur, sizeof (closure_t)); + queue_len++; return TRUE; } @@ -286,13 +337,14 @@ mail_operation_try( const gchar *description, void (*callback)( gpointer ), * Threadsafe for, nay, intended to be called by, the dispatching thread. **/ -void mail_op_set_percentage( gfloat percentage ) +void +mail_op_set_percentage (gfloat percentage) { com_msg_t msg; msg.type = PERCENTAGE; msg.percentage = percentage; - write( WRITER, &msg, sizeof( msg ) ); + write (MAIN_WRITER, &msg, sizeof (msg)); } /** @@ -307,12 +359,13 @@ void mail_op_set_percentage( gfloat percentage ) * that, right? */ -void mail_op_hide_progressbar( void ) +void +mail_op_hide_progressbar (void) { com_msg_t msg; msg.type = HIDE_PBAR; - write( WRITER, &msg, sizeof( msg ) ); + write (MAIN_WRITER, &msg, sizeof (msg)); } /** @@ -322,12 +375,13 @@ void mail_op_hide_progressbar( void ) * Threadsafe for, nay, intended to be called by, the dispatching thread. **/ -void mail_op_show_progressbar( void ) +void +mail_op_show_progressbar (void) { com_msg_t msg; msg.type = SHOW_PBAR; - write( WRITER, &msg, sizeof( msg ) ); + write (MAIN_WRITER, &msg, sizeof (msg)); } /** @@ -340,17 +394,18 @@ void mail_op_show_progressbar( void ) * Threadsafe for, nay, intended to be called by, the dispatching thread. **/ -void mail_op_set_message( gchar *fmt, ... ) +void +mail_op_set_message (gchar * fmt, ...) { com_msg_t msg; va_list val; - va_start( val, fmt ); + va_start (val, fmt); msg.type = MESSAGE; - msg.message = g_strdup_vprintf( fmt, val ); - va_end( val ); + msg.message = g_strdup_vprintf (fmt, val); + va_end (val); - write( WRITER, &msg, sizeof( msg ) ); + write (MAIN_WRITER, &msg, sizeof (msg)); } /** @@ -365,30 +420,31 @@ void mail_op_set_message( gchar *fmt, ... ) * message. **/ -gboolean mail_op_get_password( gchar *prompt, gboolean secret, gchar **dest ) +gboolean +mail_op_get_password (gchar * prompt, gboolean secret, gchar ** dest) { com_msg_t msg; gboolean result; - check_cond(); - msg.type = PASSWORD; msg.secret = secret; msg.message = prompt; msg.reply = dest; msg.success = &result; - + (*dest) = NULL; - G_LOCK( modal_lock ); + G_LOCK (modal_lock); - write( WRITER, &msg, sizeof( msg ) ); + write (MAIN_WRITER, &msg, sizeof (msg)); modal_may_proceed = FALSE; - while( modal_may_proceed == FALSE ) - g_cond_wait( modal_cond, g_static_mutex_get_mutex( &G_LOCK_NAME( modal_lock ) ) ); + while (modal_may_proceed == FALSE) + g_cond_wait (modal_cond, + g_static_mutex_get_mutex (&G_LOCK_NAME + (modal_lock))); - G_UNLOCK( modal_lock ); + G_UNLOCK (modal_lock); return result; } @@ -402,27 +458,28 @@ gboolean mail_op_get_password( gchar *prompt, gboolean secret, gchar **dest ) * Threadsafe for, nay, intended to be called by, the dispatching thread. **/ -void mail_op_error( gchar *fmt, ... ) +void +mail_op_error (gchar * fmt, ...) { com_msg_t msg; va_list val; - check_cond(); - - va_start( val, fmt ); + va_start (val, fmt); msg.type = ERROR; - msg.message = g_strdup_vprintf( fmt, val ); - va_end( val ); + msg.message = g_strdup_vprintf (fmt, val); + va_end (val); - G_LOCK( modal_lock ); + G_LOCK (modal_lock); modal_may_proceed = FALSE; - write( WRITER, &msg, sizeof( msg ) ); + write (MAIN_WRITER, &msg, sizeof (msg)); - while( modal_may_proceed == FALSE ) - g_cond_wait( modal_cond, g_static_mutex_get_mutex( &G_LOCK_NAME( modal_lock ) ) ); + while (modal_may_proceed == FALSE) + g_cond_wait (modal_cond, + g_static_mutex_get_mutex (&G_LOCK_NAME + (modal_lock))); - G_UNLOCK( modal_lock ); + G_UNLOCK (modal_lock); } /** @@ -432,12 +489,13 @@ void mail_op_error( gchar *fmt, ... ) * to finish executing */ -void mail_operation_wait_for_finish( void ) +void +mail_operation_wait_for_finish (void) { - while( mail_operation_in_progress ) { - while( gtk_events_pending() ) - gtk_main_iteration(); - } + while (queue_len) + gtk_main_iteration (); + /* Sigh. Otherwise we deadlock upon exit. */ + GDK_THREADS_LEAVE (); } /** @@ -445,15 +503,82 @@ void mail_operation_wait_for_finish( void ) * * Returns TRUE if operations are being executed asynchronously * when called, FALSE if not. - */ + **/ + +gboolean +mail_operations_are_executing (void) +{ + return (queue_len > 0); +} + +/** + * mail_operations_terminate: + * + * Let the operations finish then terminate the dispatch thread + **/ -gboolean mail_operations_are_executing( void ) +void +mail_operations_terminate (void) { - return mail_operation_in_progress; + closure_t clur; + + mail_operation_wait_for_finish(); + + memset (&clur, 0, sizeof (closure_t)); + clur.spec = NULL; + + write (DISPATCH_WRITER, &clur, sizeof (closure_t)); } /* ** Static functions **************************************************** */ +static void check_dispatcher (void) +{ + int res; + + if (dispatch_thread_started) + return; + +#if defined( G_THREADS_IMPL_POSIX ) + res = pthread_create (&dispatch_thread, NULL, + (void *) &dispatch, NULL); +#elif defined( G_THREADS_IMPL_SOLARIS ) + res = thr_create (NULL, 0, (void *) &dispatch, NULL, 0, &dispatch_thread); +#else /* no known impl */ + Error_No_thread_create_implementation (); + choke on this; +#endif + if (res != 0) { + g_warning ("Error launching dispatch thread!"); + /* FIXME: more error handling */ + } else + dispatch_thread_started = TRUE; +} + +static void +print_hide (GtkWidget * wid) +{ + g_message ("$$$ hide signal emitted"); +} + +static void +print_unmap (GtkWidget * wid) +{ + g_message ("$$$ unmap signal emitted"); +} + +static void +print_map (GtkWidget * wid) +{ + g_message ("$$$ map signal emitted"); +} + +static void +print_show (GtkWidget * wid) +{ + g_message ("$$$ show signal emitted"); +} + /** * create_queue_window: * @@ -462,72 +587,115 @@ gboolean mail_operations_are_executing( void ) */ static void -create_queue_window( void ) +queue_window_delete_event_cb (GtkWindow *window, + void *data) +{ + /* Do nothing. Just prevent GTK+ from destroying the window. */ +} + +static void +create_queue_window (void) { GtkWidget *vbox; GtkWidget *pending_vb, *pending_lb; GtkWidget *progress_lb, *progress_bar; /* Check to see if we've only hidden it */ - if( queue_window != NULL ) + if (queue_window != NULL) return; - queue_window = gtk_window_new( GTK_WINDOW_DIALOG ); - gtk_container_set_border_width( GTK_CONTAINER( queue_window ), 8 ); + queue_window = gtk_window_new (GTK_WINDOW_DIALOG); + gtk_container_set_border_width (GTK_CONTAINER (queue_window), 8); - vbox = gtk_vbox_new( FALSE, 4 ); + gtk_signal_connect (GTK_OBJECT (queue_window), "delete_event", + GTK_SIGNAL_FUNC (queue_window_delete_event_cb), NULL); - pending_vb = gtk_vbox_new( FALSE, 2 ); + vbox = gtk_vbox_new (FALSE, 4); + + pending_vb = gtk_vbox_new (FALSE, 2); queue_window_pending = pending_vb; - pending_lb = gtk_label_new( _("Currently pending operations:") ); - gtk_misc_set_alignment( GTK_MISC( pending_lb ), 0.0, 0.0 ); - gtk_box_pack_start( GTK_BOX( pending_vb ), pending_lb, - FALSE, TRUE, 0 ); + pending_lb = gtk_label_new (_("Currently pending operations:")); + gtk_misc_set_alignment (GTK_MISC (pending_lb), 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (pending_vb), pending_lb, FALSE, TRUE, 0); - gtk_box_pack_start( GTK_BOX( vbox ), pending_vb, - TRUE, TRUE, 4 ); + gtk_box_pack_start (GTK_BOX (vbox), pending_vb, TRUE, TRUE, 4); /* FIXME: 'operation' is not the warmest cuddliest word. */ - progress_lb = gtk_label_new( "" ); + progress_lb = gtk_label_new (""); queue_window_message = progress_lb; - gtk_box_pack_start( GTK_BOX( vbox ), progress_lb, - FALSE, TRUE, 4 ); + gtk_box_pack_start (GTK_BOX (vbox), progress_lb, FALSE, TRUE, 4); - progress_bar = gtk_progress_bar_new(); + progress_bar = gtk_progress_bar_new (); queue_window_progress = progress_bar; /* FIXME: is this fit for l10n? */ - gtk_progress_bar_set_orientation( GTK_PROGRESS_BAR( progress_bar ), - GTK_PROGRESS_LEFT_TO_RIGHT ); - gtk_progress_bar_set_bar_style( GTK_PROGRESS_BAR( progress_bar ), - GTK_PROGRESS_CONTINUOUS ); - gtk_box_pack_start( GTK_BOX( vbox ), progress_bar, - FALSE, TRUE, 4 ); + gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (progress_bar), + GTK_PROGRESS_LEFT_TO_RIGHT); + gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (progress_bar), + GTK_PROGRESS_CONTINUOUS); + gtk_box_pack_start (GTK_BOX (vbox), progress_bar, FALSE, TRUE, 4); + + gtk_container_add (GTK_CONTAINER (queue_window), vbox); + + gtk_widget_show (GTK_WIDGET (progress_bar)); + gtk_widget_show (GTK_WIDGET (progress_lb)); + gtk_widget_show (GTK_WIDGET (pending_lb)); + gtk_widget_show (GTK_WIDGET (pending_vb)); + gtk_widget_show (GTK_WIDGET (vbox)); + + gtk_signal_connect (GTK_OBJECT (queue_window), "hide", print_hide, + NULL); + gtk_signal_connect (GTK_OBJECT (queue_window), "unmap", print_unmap, + NULL); + gtk_signal_connect (GTK_OBJECT (queue_window), "show", print_show, + NULL); + gtk_signal_connect (GTK_OBJECT (queue_window), "map", print_map, + NULL); +} - gtk_container_add( GTK_CONTAINER( queue_window ), vbox ); +static void destroy_queue_window (void) +{ + g_return_if_fail (queue_window); + + timeout_toggle (FALSE); + gtk_widget_destroy (queue_window); + + queue_window = NULL; + queue_window_progress = NULL; + queue_window_pending = NULL; + queue_window_message = NULL; } /** - * check_compipe: + * check_compipes: * * Check and see if our pipe has been opened and open * it if necessary. **/ -static void check_compipe( void ) +static void +check_compipes (void) { - if( READER > 0 ) - return; + if (MAIN_READER < 0) { + if (pipe (main_compipe) < 0) { + g_warning ("Call to pipe(2) failed!"); - if( pipe( compipe ) < 0 ) { - g_warning( "Call to pipe(2) failed!" ); + /* FIXME: better error handling. How do we react? */ + return; + } - /* FIXME: better error handling. How do we react? */ - return; + chan_reader = g_io_channel_unix_new (MAIN_READER); + g_io_add_watch (chan_reader, G_IO_IN, read_msg, NULL); } - chan_reader = g_io_channel_unix_new( READER ); - g_io_add_watch( chan_reader, G_IO_IN, read_msg, NULL ); + if (DISPATCH_READER < 0) { + if (pipe (dispatch_compipe) < 0) { + g_warning ("Call to pipe(2) failed!"); + + /* FIXME: better error handling. How do we react? */ + return; + } + } } /** @@ -536,62 +704,94 @@ static void check_compipe( void ) * See if our condition is initialized and do so if necessary **/ -static void check_cond( void ) +static void +check_cond (void) { - if( modal_cond == NULL ) - modal_cond = g_cond_new(); + if (modal_cond == NULL) + modal_cond = g_cond_new (); + + if (ready_cond == NULL) + ready_cond = g_cond_new (); } /** * dispatch: - * @clur: The function to execute and its userdata + * @clur: The operation to execute and its parameters * * Start a thread that executes the closure and exit * it when done. */ -static void dispatch( closure_t *clur ) +static void * +dispatch (void *unused) { - int res; + size_t len; + closure_t *clur; + com_msg_t msg; - res = pthread_create( &dispatch_thread, NULL, (void *) &dispatch_func, clur ); + /* Let the compipes be created */ + sleep (1); - if( res != 0 ) { - g_warning( "Error launching dispatch thread!" ); - /* FIXME: more error handling */ - } -} + while (1) { + clur = g_new (closure_t, 1); + len = read (DISPATCH_READER, clur, sizeof (closure_t)); -/** - * dispatch_func: - * @data: the closure to run - * - * Runs the closure and exits the thread. - */ + if (len <= 0) + break; -static void *dispatch_func( void *data ) -{ - com_msg_t msg; - closure_t *clur = (closure_t *) data; + if (len != sizeof (closure_t)) { + g_warning ("dispatcher: Didn't read full message!"); + continue; + } + + if (clur->spec == NULL) + break; - msg.type = STARTING; - msg.message = clur->prettyname; - write( WRITER, &msg, sizeof( msg ) ); + msg.type = STARTING; + msg.message = g_strdup (clur->gerund); + write (MAIN_WRITER, &msg, sizeof (msg)); - /*GDK_THREADS_ENTER ();*/ - (clur->callback)( clur->data ); - /*GDK_THREADS_LEAVE ();*/ + mail_op_hide_progressbar (); + + (clur->spec->callback) (clur->in_data, clur->op_data, clur->ex); + + if (camel_exception_is_set (clur->ex)) { + if (clur->ex->id != CAMEL_EXCEPTION_USER_CANCEL) { + g_warning ("Callback failed for `%s': %s", + clur->infinitive, + camel_exception_get_description (clur-> + ex)); + mail_op_error ("Error while `%s':\n" "%s", + clur->gerund, + camel_exception_get_description (clur-> + ex)); + } + } - msg.type = FINISHED; - msg.func = clur->cleanup; /* NULL is ok */ - msg.userdata = clur->data; - write( WRITER, &msg, sizeof( msg ) ); + msg.type = FINISHED; + msg.clur = clur; - g_free( clur->prettyname ); - g_free( data ); + G_LOCK (ready_for_op); + write (MAIN_WRITER, &msg, sizeof (msg)); - pthread_exit( 0 ); - return NULL; /*NOTREACHED*/ + ready_may_proceed = FALSE; + while (ready_may_proceed == FALSE) + g_cond_wait (ready_cond, + g_static_mutex_get_mutex (&G_LOCK_NAME + (ready_for_op))); + G_UNLOCK (ready_for_op); + } + +#ifdef G_THREADS_IMPL_POSIX + pthread_exit (0); +#elif defined( G_THREADS_IMPL_SOLARIS ) + thr_exit (NULL); +#else /* no known impl */ + Error_No_thread_exit_implemented (); + choke on this; +#endif + return NULL; + /*NOTREACHED*/ } /** @@ -604,75 +804,82 @@ static void *dispatch_func( void *data ) * action. **/ -static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer userdata ) +static gboolean +read_msg (GIOChannel * source, GIOCondition condition, gpointer userdata) { com_msg_t *msg; - closure_t *clur; - GSList *temp; guint size; - msg = g_new0( com_msg_t, 1 ); + msg = g_new0 (com_msg_t, 1); - g_io_channel_read( source, (gchar *) msg, - sizeof( com_msg_t ) / sizeof( gchar ), - &size ); + g_io_channel_read (source, (gchar *) msg, + sizeof (com_msg_t) / sizeof (gchar), &size); - if( size != sizeof( com_msg_t ) ) { - g_warning( _("Incomplete message written on pipe!") ); + if (size != sizeof (com_msg_t)) { + g_warning (_("Incomplete message written on pipe!")); msg->type = ERROR; - msg->message = g_strdup( _("Error reading commands from dispatching thread.") ); + msg->message = + g_strdup (_ + ("Error reading commands from dispatching thread.")); } /* This is very important, though I'm not quite sure why * it is as we are in the main thread right now. */ - GDK_THREADS_ENTER(); + GDK_THREADS_ENTER (); - switch( msg->type ) { + switch (msg->type) { case STARTING: - DEBUG (("*** Message -- STARTING\n")); - gtk_label_set_text( GTK_LABEL( queue_window_message ), msg->message ); - gtk_progress_bar_update( GTK_PROGRESS_BAR( queue_window_progress ), 0.0 ); - g_free( msg ); + DEBUG (("*** Message -- STARTING %s\n", msg->message)); + gtk_label_set_text (GTK_LABEL (queue_window_message), + msg->message); + gtk_progress_bar_update (GTK_PROGRESS_BAR + (queue_window_progress), 0.0); + g_free (msg->message); + g_free (msg); break; case PERCENTAGE: DEBUG (("*** Message -- PERCENTAGE\n")); - gtk_progress_bar_update( GTK_PROGRESS_BAR( queue_window_progress ), msg->percentage ); - g_free( msg ); + gtk_progress_bar_update (GTK_PROGRESS_BAR + (queue_window_progress), + msg->percentage); + g_free (msg); break; case HIDE_PBAR: DEBUG (("*** Message -- HIDE_PBAR\n")); - gtk_progress_set_activity_mode( GTK_PROGRESS( queue_window_progress ), TRUE ); - timeout_toggle( TRUE ); - - g_free( msg ); + gtk_progress_set_activity_mode (GTK_PROGRESS + (queue_window_progress), + TRUE); + timeout_toggle (TRUE); + g_free (msg); break; case SHOW_PBAR: DEBUG (("*** Message -- SHOW_PBAR\n")); - timeout_toggle( FALSE ); - gtk_progress_set_activity_mode( GTK_PROGRESS( queue_window_progress ), FALSE ); - - g_free( msg ); + timeout_toggle (FALSE); + gtk_progress_set_activity_mode (GTK_PROGRESS + (queue_window_progress), + FALSE); + g_free (msg); break; case MESSAGE: DEBUG (("*** Message -- MESSAGE\n")); - gtk_label_set_text( GTK_LABEL( queue_window_message ), - msg->message ); - g_free( msg->message ); - g_free( msg ); + gtk_label_set_text (GTK_LABEL (queue_window_message), + msg->message); + g_free (msg->message); + g_free (msg); break; case PASSWORD: DEBUG (("*** Message -- PASSWORD\n")); - g_assert( msg->reply ); - g_assert( msg->success ); - get_password( msg ); + g_assert (msg->reply); + g_assert (msg->success); + get_password (msg); /* don't free msg! done later */ break; case ERROR: DEBUG (("*** Message -- ERROR\n")); - show_error( msg ); - g_free( msg ); + show_error (msg); + g_free (msg); break; /* Don't fall through; dispatch_func does the FINISHED @@ -680,40 +887,58 @@ static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer u */ case FINISHED: - DEBUG (("*** Message -- FINISH\n")); - if( msg->func ) - (msg->func)( msg->userdata ); + DEBUG ( + ("*** Message -- FINISH %s\n", + msg->clur->gerund)); + + if (msg->clur->spec->cleanup) + (msg->clur->spec->cleanup) (msg->clur->in_data, + msg->clur->op_data, + msg->clur->ex); + + G_LOCK (ready_for_op); + ready_may_proceed = TRUE; + g_cond_signal (ready_cond); + G_UNLOCK (ready_for_op); + + if (camel_exception_is_set (msg->clur->ex) && + msg->clur->ex->id != CAMEL_EXCEPTION_USER_CANCEL) { + g_warning ("Error on cleanup of `%s': %s", + msg->clur->infinitive, + camel_exception_get_description (msg-> + clur-> + ex)); + } - if( op_queue == NULL ) { - g_print("\tNo more ops -- hide %p.\n", queue_window); + free_closure (msg->clur); + queue_len--; + + if (queue_len == 0) { + g_print ("\tNo more ops -- hide %p.\n", queue_window); /* All done! */ - gtk_widget_hide( queue_window ); - mail_operation_in_progress = FALSE; + /* gtk_widget_hide seems to have problems sometimes + * here... perhaps because we're in a gsource handler, + * not a GTK event handler? Anyway, we defer the hiding + * til an idle. */ + /*gtk_idle_add (hide_queue_window, NULL);*/ + /*gtk_widget_hide (queue_window); */ + destroy_queue_window (); } else { - g_print("\tOperation left.\n"); - - /* There's another operation left */ - - /* Pop it off the front */ - clur = op_queue->data; - temp = g_slist_next( op_queue ); - g_slist_free_1( op_queue ); - op_queue = temp; + g_print ("\tOperation(s) left.\n"); - /* Clear it out of the 'pending' vbox */ - remove_next_pending(); - - /* Run run run little process */ - dispatch( clur ); + /* There's another operation left : + * Clear it out of the 'pending' vbox + */ + remove_next_pending (); } - g_free( msg ); + g_free (msg); break; default: - g_warning( _("Corrupted message from dispatching thread?") ); + g_warning (_("Corrupted message from dispatching thread?")); break; } - GDK_THREADS_LEAVE(); + GDK_THREADS_LEAVE (); return TRUE; } @@ -725,23 +950,30 @@ static gboolean read_msg( GIOChannel *source, GIOCondition condition, gpointer u * 'pending' message. **/ -static void remove_next_pending( void ) +static void +remove_next_pending (void) { GList *children; - children = gtk_container_children( GTK_CONTAINER( queue_window_pending ) ); + children = + gtk_container_children (GTK_CONTAINER (queue_window_pending)); /* Skip past the header label */ - children = g_list_first( children ); - children = g_list_next( children ); + children = g_list_first (children); + children = g_list_next (children); + + if (!children) { + g_warning ("Mistake in queue window!"); + return; + } /* Nuke the one on top */ - gtk_container_remove( GTK_CONTAINER( queue_window_pending ), - GTK_WIDGET( children->data ) ); + gtk_container_remove (GTK_CONTAINER (queue_window_pending), + GTK_WIDGET (children->data)); /* Hide it? */ - if( g_list_next( children ) == NULL ) - gtk_widget_hide( queue_window_pending ); + if (g_list_next (children) == NULL) + gtk_widget_hide (queue_window_pending); } /** @@ -750,28 +982,36 @@ static void remove_next_pending( void ) * Show the error dialog and wait for user OK **/ -static void show_error( com_msg_t *msg ) +static void +show_error (com_msg_t * msg) { GtkWidget *err_dialog; + gchar *old_message; + + err_dialog = gnome_error_dialog (msg->message); + gnome_dialog_set_close (GNOME_DIALOG (err_dialog), TRUE); + gtk_signal_connect (GTK_OBJECT (err_dialog), "clicked", + (GtkSignalFunc) show_error_clicked, NULL); + g_free (msg->message); - err_dialog = gnome_error_dialog( msg->message ); - gnome_dialog_set_close( GNOME_DIALOG(err_dialog), TRUE ); - gtk_signal_connect( GTK_OBJECT( err_dialog ), "clicked", (GtkSignalFunc) show_error_clicked, NULL ); - g_free( msg->message ); + /* Save the old message, but display a new one right now */ + gtk_label_get (GTK_LABEL (queue_window_message), &old_message); + gtk_object_set_data (GTK_OBJECT (err_dialog), "old_message", + g_strdup (old_message)); + gtk_label_set_text (GTK_LABEL (queue_window_message), + _("Waiting for user to close error dialog")); - G_LOCK( modal_lock ); + G_LOCK (modal_lock); - timeout_toggle( FALSE ); + timeout_toggle (FALSE); modal_may_proceed = FALSE; - gtk_widget_show( GTK_WIDGET( err_dialog ) ); - gnome_win_hints_set_layer( err_dialog, - WIN_LAYER_ONTOP ); - gnome_win_hints_set_state( err_dialog, - WIN_STATE_ARRANGE_IGNORE ); - gnome_win_hints_set_hints( err_dialog, + gtk_widget_show_all (GTK_WIDGET (err_dialog)); + gnome_win_hints_set_layer (err_dialog, WIN_LAYER_ONTOP); + gnome_win_hints_set_state (err_dialog, WIN_STATE_ARRANGE_IGNORE); + gnome_win_hints_set_hints (err_dialog, WIN_HINTS_SKIP_FOCUS | WIN_HINTS_SKIP_WINLIST | - WIN_HINTS_SKIP_TASKBAR ); + WIN_HINTS_SKIP_TASKBAR); } /** @@ -781,12 +1021,21 @@ static void show_error( com_msg_t *msg ) * the dispatch thread is allowed to continue. **/ -static void show_error_clicked( void ) +static void +show_error_clicked (GtkObject * obj) { + gchar *old_message; + + /* Restore the old message */ + old_message = gtk_object_get_data (obj, "old_message"); + gtk_label_set_text (GTK_LABEL (queue_window_message), + old_message); + g_free (old_message); + modal_may_proceed = TRUE; - timeout_toggle( TRUE ); - g_cond_signal( modal_cond ); - G_UNLOCK( modal_lock ); + timeout_toggle (TRUE); + g_cond_signal (modal_cond); + G_UNLOCK (modal_lock); } /** @@ -795,66 +1044,81 @@ static void show_error_clicked( void ) * Ask for a password and put the answer in *(msg->reply) **/ -static void get_password( com_msg_t *msg ) +static void +get_password (com_msg_t * msg) { GtkWidget *dialog; + gchar *old_message; + + dialog = gnome_request_dialog (msg->secret, msg->message, NULL, + 0, get_password_cb, msg, NULL); + gnome_dialog_set_close (GNOME_DIALOG (dialog), TRUE); + gtk_signal_connect (GTK_OBJECT (dialog), "clicked", + get_password_clicked, msg); - dialog = gnome_request_dialog( msg->secret, msg->message, NULL, - 0, get_password_cb, msg, - NULL ); - gnome_dialog_set_close( GNOME_DIALOG(dialog), TRUE ); - gtk_signal_connect( GTK_OBJECT( dialog ), "clicked", get_password_clicked, msg ); + /* Save the old message, but display a new one right now */ + gtk_label_get (GTK_LABEL (queue_window_message), &old_message); + gtk_object_set_data (GTK_OBJECT (dialog), "old_message", g_strdup(old_message)); + gtk_label_set_text (GTK_LABEL (queue_window_message), + _("Waiting for user to enter data")); - G_LOCK( modal_lock ); + G_LOCK (modal_lock); modal_may_proceed = FALSE; - if( dialog == NULL ) { + if (dialog == NULL) { *(msg->success) = FALSE; - *(msg->reply) = g_strdup( _("Could not create dialog box.") ); + *(msg->reply) = g_strdup (_("Could not create dialog box.")); modal_may_proceed = TRUE; - g_cond_signal( modal_cond ); - G_UNLOCK( modal_lock ); + g_cond_signal (modal_cond); + G_UNLOCK (modal_lock); } else { *(msg->reply) = NULL; - timeout_toggle( FALSE ); - gtk_widget_show( GTK_WIDGET( dialog ) ); - gnome_win_hints_set_layer( dialog, - WIN_LAYER_ONTOP ); - gnome_win_hints_set_state( dialog, - WIN_STATE_ARRANGE_IGNORE ); - gnome_win_hints_set_hints( dialog, + timeout_toggle (FALSE); + gtk_widget_show_all (GTK_WIDGET (dialog)); + gnome_win_hints_set_layer (dialog, WIN_LAYER_ONTOP); + gnome_win_hints_set_state (dialog, WIN_STATE_ARRANGE_IGNORE); + gnome_win_hints_set_hints (dialog, WIN_HINTS_SKIP_FOCUS | WIN_HINTS_SKIP_WINLIST | - WIN_HINTS_SKIP_TASKBAR ); + WIN_HINTS_SKIP_TASKBAR); } } -static void get_password_cb( gchar *string, gpointer data ) +static void +get_password_cb (gchar * string, gpointer data) { com_msg_t *msg = (com_msg_t *) data; - if (string) - *(msg->reply) = g_strdup( string ); - else - *(msg->reply) = NULL; + if (string) + *(msg->reply) = g_strdup (string); + else + *(msg->reply) = NULL; } -static void get_password_clicked( GnomeDialog *dialog, gint button, gpointer user_data ) +static void +get_password_clicked (GnomeDialog * dialog, gint button, gpointer user_data) { com_msg_t *msg = (com_msg_t *) user_data; + gchar *old_message; + + /* Restore the old message */ + old_message = gtk_object_get_data (GTK_OBJECT (dialog), "old_message"); + gtk_label_set_text (GTK_LABEL (queue_window_message), + old_message); + g_free (old_message); - if( button == 1 || *(msg->reply) == NULL ) { + if (button == 1 || *(msg->reply) == NULL) { *(msg->success) = FALSE; - *(msg->reply) = g_strdup( _("User cancelled query.") ); + *(msg->reply) = g_strdup (_("User cancelled query.")); } else *(msg->success) = TRUE; - g_free( msg ); + g_free (msg); modal_may_proceed = TRUE; - timeout_toggle( TRUE ); - g_cond_signal( modal_cond ); - G_UNLOCK( modal_lock ); + timeout_toggle (TRUE); + g_cond_signal (modal_cond); + G_UNLOCK (modal_lock); } /* NOT totally copied from gtk+/gtk/testgtk.c, really! */ @@ -865,8 +1129,14 @@ progress_timeout (gpointer data) gfloat new_val; GtkAdjustment *adj; + if (queue_window == NULL) { + gtk_timeout_remove (progress_timeout_handle); + progress_timeout_handle = -1; + return FALSE; + } + adj = GTK_PROGRESS (data)->adjustment; - + new_val = adj->value + 1; if (new_val > adj->upper) new_val = adj->lower; @@ -885,20 +1155,100 @@ progress_timeout (gpointer data) **/ static void -timeout_toggle( gboolean active ) +timeout_toggle (gboolean active) { - if( (GTK_PROGRESS( queue_window_progress ))->activity_mode == 0 ) + if (!queue_window) + return; + + if ((GTK_PROGRESS (queue_window_progress))->activity_mode == 0) return; - if( active ) { - if( progress_timeout_handle < 0 ) - progress_timeout_handle = gtk_timeout_add( 80, progress_timeout, queue_window_progress ); + if (active) { + /* We do this in case queue_window_progress gets reset */ + if (progress_timeout_handle < 0) { + progress_timeout_handle = + gtk_timeout_add (80, progress_timeout, + queue_window_progress); + } else { + gtk_timeout_remove (progress_timeout_handle); + progress_timeout_handle = + gtk_timeout_add (80, progress_timeout, + queue_window_progress); + } } else { - if( progress_timeout_handle >= 0 ) { - gtk_timeout_remove( progress_timeout_handle ); + if (progress_timeout_handle >= 0) { + gtk_timeout_remove (progress_timeout_handle); progress_timeout_handle = -1; } } } -#endif +/* This can theoretically run into problems where if a short operation starts + * and finishes, then another short operation starts and finishes a second + * later, we will see the window prematurely. My response: oh noooooo! + * + * Solution: keep the timeout's handle and remove the timeout upon reception + * of FINISH, and zero out the handle in this function. Whatever. + */ +static gboolean +display_timeout (gpointer data) +{ + if (queue_len > 0 && queue_window) { + gtk_widget_show (queue_window); + gnome_win_hints_set_layer (queue_window, WIN_LAYER_ONTOP); + gnome_win_hints_set_state (queue_window, + WIN_STATE_ARRANGE_IGNORE); + gnome_win_hints_set_hints (queue_window, + WIN_HINTS_SKIP_FOCUS | + WIN_HINTS_SKIP_WINLIST | + WIN_HINTS_SKIP_TASKBAR); + + if (queue_len == 1) + gtk_widget_hide (queue_window_pending); + } + + return FALSE; +} + +static closure_t * +new_closure (const mail_operation_spec * spec, gpointer input, + gboolean free_in_data) +{ + closure_t *clur; + + clur = g_new0 (closure_t, 1); + clur->spec = spec; + clur->in_data = input; + clur->free_in_data = free_in_data; + clur->ex = camel_exception_new (); + + clur->op_data = g_malloc (spec->datasize); + + camel_exception_init (clur->ex); + + clur->infinitive = (spec->describe) (input, FALSE); + clur->gerund = (spec->describe) (input, TRUE); + + return clur; +} + +static void +free_closure (closure_t *clur) +{ + clur->spec = NULL; + + if (clur->free_in_data) + g_free (clur->in_data); + clur->in_data = NULL; + + g_free (clur->op_data); + clur->op_data = NULL; + + camel_exception_free (clur->ex); + clur->ex = NULL; + + g_free (clur->infinitive); + g_free (clur->gerund); + + g_free (clur); +} diff --git a/mail/mail-threads.h b/mail/mail-threads.h index e26acdbb14..1aeb486935 100644 --- a/mail/mail-threads.h +++ b/mail/mail-threads.h @@ -25,28 +25,44 @@ #ifndef _MAIL_THREADS_H_ #define _MAIL_THREADS_H_ -#ifdef USE_BROKEN_THREADS +#include +#include /*size_t */ + +/* Returns a g_strdup'ed string that describes what's going to happen, + * tersely but specifically. + */ +typedef gchar *(*mail_op_describe_func) (gpointer /*input_data*/, gboolean /*gerund*/); +typedef void (*mail_op_func) (gpointer, gpointer, CamelException *); + +typedef struct _mail_operation_spec +{ + mail_op_describe_func describe; + size_t datasize; + mail_op_func setup; + mail_op_func callback; + mail_op_func cleanup; +} +mail_operation_spec; + /* Schedule to operation to happen eventually */ -gboolean mail_operation_try( const gchar *description, - void (*callback)( gpointer ), - void (*cleanup)( gpointer ), - gpointer user_data ); +gboolean mail_operation_queue (const mail_operation_spec * spec, + gpointer input, gboolean free_in_data); /* User interface hooks for the other thread */ -void mail_op_set_percentage( gfloat percentage ); -void mail_op_hide_progressbar( void ); -void mail_op_show_progressbar( void ); -void mail_op_set_message( gchar *fmt, ... ) G_GNUC_PRINTF( 1, 2 ); -void mail_op_error( gchar *fmt, ... ) G_GNUC_PRINTF( 1, 2 ); -gboolean mail_op_get_password( gchar *prompt, gboolean secret, gchar **dest ); +void mail_op_set_percentage (gfloat percentage); +void mail_op_hide_progressbar (void); +void mail_op_show_progressbar (void); +void +mail_op_set_message (gchar * fmt, ...) G_GNUC_PRINTF (1, 2); +void mail_op_error (gchar * fmt, ...) G_GNUC_PRINTF (1, 2); +gboolean mail_op_get_password (gchar * prompt, gboolean secret, + gchar ** dest); /* Wait for the async operations to finish */ -void mail_operation_wait_for_finish( void ); - -gboolean mail_operations_are_executing( void ); - -#endif /* defined USE_BROKEN_THREADS */ +void mail_operation_wait_for_finish (void); +gboolean mail_operations_are_executing (void); +void mail_operations_terminate (void); #endif /* defined _MAIL_THREADS_H_ */ diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c index fab59ef991..1fc5b8b2e3 100644 --- a/mail/mail-vfolder.c +++ b/mail/mail-vfolder.c @@ -19,12 +19,12 @@ #include "evolution-shell-component.h" #include "folder-browser.h" #include "mail-vfolder.h" +#include "mail-tools.h" #include "mail-autofilter.h" #include "camel/camel.h" #include "filter/vfolder-context.h" -#include "filter/vfolder-rule.h" #include "filter/vfolder-editor.h" #define d(x) x @@ -171,19 +171,17 @@ vfolder_create_storage(EvolutionShellComponent *shell_component) vfolder_refresh(); } +/* THIS IS ANALOGOUS TO mail_tool_uri_to_folder. IT IS NOT ASYNCHRONOUS */ /* maps the shell's uri to the real vfolder uri and open the folder */ CamelFolder * -vfolder_uri_to_folder(const char *uri) +vfolder_uri_to_folder(const char *uri, CamelException *ex) { - CamelFolder *mail_uri_to_folder(const char *); void camel_vee_folder_add_folder(CamelFolder *, CamelFolder *); struct _vfolder_info *info; char *storeuri, *foldername; VfolderRule *rule; - CamelStore *store = NULL; CamelFolder *folder = NULL, *sourcefolder; - CamelException *ex; const char *sourceuri; int sources; @@ -202,23 +200,19 @@ vfolder_uri_to_folder(const char *uri) storeuri = g_strdup_printf("vfolder:%s/vfolder/%s", evolution_dir, info->name); foldername = g_strdup_printf("mbox?%s", info->query); - ex = camel_exception_new (); - store = camel_session_get_store (session, storeuri, ex); - if (store == NULL) - goto cleanup; - folder = camel_store_get_folder (store, foldername, TRUE, ex); - if (folder == NULL) - goto cleanup; + folder = mail_tool_get_folder_from_urlname (storeuri, foldername, ex); sourceuri = NULL; sources = 0; while ( (sourceuri = vfolder_rule_next_source(rule, sourceuri)) ) { d(printf("adding vfolder source: %s\n", sourceuri)); - sourcefolder = mail_uri_to_folder(sourceuri); + sourcefolder = mail_tool_uri_to_folder (sourceuri, ex); if (sourcefolder) { sources++; + mail_tool_camel_lock_up (); camel_vee_folder_add_folder(folder, sourcefolder); + mail_tool_camel_lock_down (); } } /* if we didn't have any sources, just use Inbox as the default */ @@ -227,12 +221,15 @@ vfolder_uri_to_folder(const char *uri) defaulturi = g_strdup_printf("file://%s/local/Inbox", evolution_dir); d(printf("No sources configured/found, using default: %s\n", defaulturi)); - sourcefolder = mail_uri_to_folder(defaulturi); + sourcefolder = mail_tool_uri_to_folder (defaulturi, ex); g_free(defaulturi); - if (sourcefolder) + if (sourcefolder) { + mail_tool_camel_lock_up (); camel_vee_folder_add_folder(folder, sourcefolder); + mail_tool_camel_lock_down (); + } } -cleanup: + g_free(foldername); g_free(storeuri); diff --git a/mail/mail-vfolder.h b/mail/mail-vfolder.h index 4e87276322..2ff19cc3ea 100644 --- a/mail/mail-vfolder.h +++ b/mail/mail-vfolder.h @@ -15,7 +15,7 @@ void vfolder_create_storage(EvolutionShellComponent *shell_component); -CamelFolder *vfolder_uri_to_folder(const char *uri); +CamelFolder *vfolder_uri_to_folder(const char *uri, CamelException *ex); void vfolder_edit(void); FilterPart *vfolder_create_part(const char *name); void vfolder_gui_add_rule(VfolderRule *rule); diff --git a/mail/mail-view.c b/mail/mail-view.c index a98cc4d5ca..6c336a47f8 100644 --- a/mail/mail-view.c +++ b/mail/mail-view.c @@ -20,17 +20,111 @@ * */ -#include -#include +#include +#include "mail.h" +#include "mail-ops.h" +#include "camel/camel.h" + +typedef struct mail_view_data_s { + CamelFolder *source; + gchar *uid; + CamelMimeMessage *msg; + MailDisplay *md; +} mail_view_data; + +static void +mail_view_data_free (gpointer mvd) +{ + mail_view_data *data = (mail_view_data *) mvd; + + if (data->uid) + g_free (data->uid); + if (data->msg) + camel_object_unref (CAMEL_OBJECT (data->msg)); + if (data->source) + camel_object_unref (CAMEL_OBJECT (data->source)); + + g_free (data); +} + +static mail_view_data * +mail_view_data_new (CamelFolder *source, const gchar *uid, CamelMimeMessage *msg) +{ + mail_view_data *data; + + data = g_new (mail_view_data, 1); + data->source = source; + camel_object_ref (CAMEL_OBJECT (data->source)); + data->msg = msg; + camel_object_ref (CAMEL_OBJECT (data->msg)); + data->uid = g_strdup (uid); + + return data; +} static void on_close (GtkWidget *menuitem, gpointer user_data) { - GtkWidget *view; - - view = gtk_widget_get_toplevel (menuitem); - - gtk_widget_destroy (view); + GtkWidget *view_window; + + view_window = gtk_object_get_data (GTK_OBJECT (menuitem), "view-window"); + g_return_if_fail (view_window); + gtk_widget_destroy (GTK_WIDGET (view_window)); +} + +static void +view_reply_to_sender (GtkWidget *widget, gpointer user_data) +{ + mail_view_data *data = (mail_view_data *) user_data; + + mail_reply (data->source, data->msg, data->uid, FALSE); +} + +static void +view_reply_to_all (GtkWidget *widget, gpointer user_data) +{ + mail_view_data *data = (mail_view_data *) user_data; + + mail_reply (data->source, data->msg, data->uid, TRUE); +} + +static void +view_forward_msg (GtkWidget *widget, gpointer user_data) +{ + mail_view_data *data = (mail_view_data *) user_data; + + GPtrArray *uids; + EMsgComposer *composer; + + uids = g_ptr_array_new(); + g_ptr_array_add (uids, g_strdup (data->uid)); + + composer = E_MSG_COMPOSER (e_msg_composer_new ()); + gtk_signal_connect (GTK_OBJECT (composer), "send", + GTK_SIGNAL_FUNC (composer_send_cb), NULL); + + mail_do_forward_message (data->msg, data->source, uids, composer); +} + +static void +view_print_msg (GtkWidget *widget, gpointer user_data) +{ + mail_view_data *data = (mail_view_data *) user_data; + + mail_print_msg (data->md); +} + +static void +view_delete_msg (GtkWidget *button, gpointer user_data) +{ + mail_view_data *data = (mail_view_data *) user_data; + + GPtrArray *uids; + + uids = g_ptr_array_new(); + g_ptr_array_add (uids, g_strdup (data->uid)); + mail_do_flag_messages (data->source, uids, TRUE, + CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_DELETED); } static GnomeUIInfo mail_view_toolbar [] = { @@ -39,18 +133,18 @@ static GnomeUIInfo mail_view_toolbar [] = { save_msg, GNOME_STOCK_PIXMAP_SAVE),*/ GNOMEUIINFO_ITEM_STOCK (N_("Reply"), N_("Reply to the sender of this message"), - reply_to_sender, GNOME_STOCK_PIXMAP_MAIL_RPL), + view_reply_to_sender, GNOME_STOCK_PIXMAP_MAIL_RPL), GNOMEUIINFO_ITEM_STOCK (N_("Reply to All"), N_("Reply to all recipients of this message"), - reply_to_all, GNOME_STOCK_PIXMAP_MAIL_RPL), + view_reply_to_all, GNOME_STOCK_PIXMAP_MAIL_RPL), - GNOMEUIINFO_ITEM_STOCK (N_("Forward"), N_("Forward this message"), forward_msg, GNOME_STOCK_PIXMAP_MAIL_FWD), + GNOMEUIINFO_ITEM_STOCK (N_("Forward"), N_("Forward this message"), view_forward_msg, GNOME_STOCK_PIXMAP_MAIL_FWD), GNOMEUIINFO_SEPARATOR, - GNOMEUIINFO_ITEM_STOCK (N_("Print"), N_("Print the selected message"), print_msg, GNOME_STOCK_PIXMAP_PRINT), + GNOMEUIINFO_ITEM_STOCK (N_("Print"), N_("Print the selected message"), view_print_msg, GNOME_STOCK_PIXMAP_PRINT), - GNOMEUIINFO_ITEM_STOCK (N_("Delete"), N_("Delete this message"), delete_msg, GNOME_STOCK_PIXMAP_TRASH), + GNOMEUIINFO_ITEM_STOCK (N_("Delete"), N_("Delete this message"), view_delete_msg, GNOME_STOCK_PIXMAP_TRASH), /*GNOMEUIINFO_SEPARATOR,*/ @@ -82,16 +176,17 @@ static GnomeUIInfo mail_view_menubar[] = }; GtkWidget * -mail_view_create (FolderBrowser *folder_browser) +mail_view_create (CamelFolder *source, const char *uid, CamelMimeMessage *msg) { - CamelMimeMessage *msg; GtkWidget *window; GtkWidget *toolbar; GtkWidget *mail_display; - char *subject; GnomeDockItemBehavior behavior; + char *subject; + mail_view_data *data; + + data = mail_view_data_new (source, uid, msg); - msg = folder_browser->mail_display->current_message; subject = (char *) camel_mime_message_get_subject (msg); if (!subject) subject = ""; @@ -102,26 +197,30 @@ mail_view_create (FolderBrowser *folder_browser) gnome_app_fill_toolbar_with_data (GTK_TOOLBAR (toolbar), mail_view_toolbar, - NULL, folder_browser); + NULL, data); behavior = GNOME_DOCK_ITEM_BEH_NORMAL; if (!gnome_preferences_get_toolbar_detachable ()) behavior |= GNOME_DOCK_ITEM_BEH_LOCKED; - gnome_app_add_toolbar (GNOME_APP (window), + gnome_app_add_toolbar (GNOME_APP (window), GTK_TOOLBAR (toolbar), GNOME_APP_TOOLBAR_NAME, behavior, GNOME_DOCK_TOP, 1, 0, 0); gnome_app_create_menus (GNOME_APP (window), mail_view_menubar); - + + gtk_object_set_data_full (GTK_OBJECT (window), "mvd", data, + mail_view_data_free); + gtk_widget_ref (mail_view_menubar[0].widget); gtk_object_set_data_full (GTK_OBJECT (window), "file", mail_view_menubar[0].widget, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_ref (file_menu[0].widget); + gtk_object_set_data (GTK_OBJECT (file_menu[0].widget), "view-window", window); gtk_object_set_data_full (GTK_OBJECT (window), "close", file_menu[0].widget, (GtkDestroyNotify) gtk_widget_unref); @@ -131,11 +230,14 @@ mail_view_create (FolderBrowser *folder_browser) mail_view_menubar[1].widget, (GtkDestroyNotify) gtk_widget_unref); - mail_display = mail_display_new (folder_browser); + mail_display = mail_display_new (); mail_display_set_message (MAIL_DISPLAY (mail_display), CAMEL_MEDIUM (msg)); gtk_widget_set_usize (mail_display, 600, 600); - + data->md = MAIL_DISPLAY (mail_display); gnome_app_set_contents (GNOME_APP (window), mail_display); return window; } + + + diff --git a/mail/mail.h b/mail/mail.h index 3ff7422370..2bc829dc36 100644 --- a/mail/mail.h +++ b/mail/mail.h @@ -31,8 +31,8 @@ void folder_browser_factory_init (void); BonoboControl *folder_browser_factory_new_control (const char *uri); -/* folder-browser */ -CamelFolder *mail_uri_to_folder (const char *uri); +/* mail-config */ +void mail_config_druid (void); /* mail-crypto */ char *mail_crypto_openpgp_decrypt (const char *ciphertext, @@ -60,7 +60,7 @@ char *mail_get_message_body (CamelDataWrapper *data, gboolean want_plain, /* mail-identify */ char *mail_identify_mime_part (CamelMimePart *part); -/* mail-ops */ +/* mail-callbacks */ void fetch_mail (GtkWidget *widget, gpointer user_data); void compose_msg (GtkWidget *widget, gpointer user_data); void send_to_url (const char *url); @@ -83,8 +83,12 @@ void providers_config (BonoboUIHandler *uih, void *user_data, const char *path); void configure_folder(BonoboUIHandler *uih, void *user_data, const char *path); +void mail_reply (CamelFolder *folder, CamelMimeMessage *msg, const char *uid, gboolean to_all); +void composer_send_cb (EMsgComposer *composer, gpointer data); +void mail_print_msg (MailDisplay *md); + /* mail view */ -GtkWidget *mail_view_create (FolderBrowser *folder_browser); +GtkWidget *mail_view_create (CamelFolder *source, const char *uid, CamelMimeMessage *msg); /* session */ void session_init (void); diff --git a/mail/main.c b/mail/main.c index 8ad567da21..372abf8b8a 100644 --- a/mail/main.c +++ b/mail/main.c @@ -30,9 +30,7 @@ main (int argc, char *argv []) bindtextdomain (PACKAGE, EVOLUTION_LOCALEDIR); textdomain (PACKAGE); -#ifdef USE_BROKEN_THREADS g_thread_init( NULL ); -#endif od_assert_using_oaf (); gnome_init_with_popt_table ("evolution-mail-component", VERSION, @@ -59,13 +57,9 @@ main (int argc, char *argv []) mail_config_init (); component_factory_init (); -#ifdef USE_BROKEN_THREADS GDK_THREADS_ENTER (); -#endif bonobo_main (); -#ifdef USE_BROKEN_THREADS GDK_THREADS_LEAVE (); -#endif mail_config_write_on_exit (); diff --git a/mail/message-list.c b/mail/message-list.c index cdec9b2339..51ca345953 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -9,6 +9,7 @@ * * (C) 2000 Helix Code, Inc. */ + #include #include #include @@ -19,15 +20,17 @@ #include #include "message-list.h" #include "message-thread.h" +#include "mail-threads.h" +#include "mail-tools.h" +#include "mail-ops.h" #include "mail-config.h" +#include "mail-vfolder.h" +#include "mail-autofilter.h" #include "mail.h" #include "Mail.h" #include "widgets/e-table/e-table-header-item.h" #include "widgets/e-table/e-table-item.h" -#include "mail-vfolder.h" -#include "mail-autofilter.h" - #include "art/mail-new.xpm" #include "art/mail-read.xpm" #include "art/mail-replied.xpm" @@ -107,6 +110,44 @@ get_message_info (MessageList *message_list, int row) return camel_folder_get_message_info (message_list->folder, uid); } +/* Gets the uid of the message displayed at a given view row */ +static const char * +get_message_uid (MessageList *message_list, int row) +{ + ETreeModel *model = (ETreeModel *)message_list->table_model; + ETreePath *node; + const char *uid; + + if (row >= e_table_model_row_count (message_list->table_model)) + return NULL; + + node = e_tree_model_node_at_row (model, row); + g_return_val_if_fail (node != NULL, NULL); + uid = e_tree_model_node_get_data (model, node); + + if (strncmp (uid, "uid:", 4) != 0) + return NULL; + uid += 4; + + return uid; +} + +static gint +mark_msg_seen (gpointer data) +{ + MessageList *ml = data; + GPtrArray *uids; + + if (!ml->cursor_uid) + return FALSE; + + uids = g_ptr_array_new (); + g_ptr_array_add (uids, g_strdup (ml->cursor_uid)); + mail_do_flag_messages (ml->folder, uids, FALSE, + CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); + return FALSE; +} + /** * message_list_select: * @message_list: a MessageList @@ -138,66 +179,30 @@ message_list_select (MessageList *message_list, int base_row, last = e_table_model_row_count (message_list->table_model); vrow = e_table_model_to_view_row (ets->table, base_row); + + /* We don't know whether to use < or > due to "direction" */ while (vrow != last) { - vrow += direction; mrow = e_table_view_to_model_row (ets->table, vrow); info = get_message_info (message_list, mrow); if (info && (info->flags & mask) == flags) { e_table_scrolled_set_cursor_row (ets, mrow); + mail_do_display_message (message_list, info->uid, mark_msg_seen); return; } + vrow += direction; } mail_display_set_message (message_list->parent_folder_browser->mail_display, NULL); } -static gint -mark_msg_seen (gpointer data) -{ - MessageList *ml = data; - guint32 flags; - - if (!ml->cursor_uid) - return FALSE; - - flags = camel_folder_get_message_flags (ml->folder, ml->cursor_uid); - camel_folder_set_message_flags (ml->folder, ml->cursor_uid, - CAMEL_MESSAGE_SEEN, - CAMEL_MESSAGE_SEEN); - return FALSE; -} - /* select a message and display it */ static void select_msg (MessageList *message_list, gint row) { - CamelException ex; - CamelMimeMessage *message; - const CamelMessageInfo *msg_info; - MailDisplay *md = message_list->parent_folder_browser->mail_display; - - camel_exception_init (&ex); - - msg_info = get_message_info (message_list, row); - if (msg_info) { - message = camel_folder_get_message (message_list->folder, - msg_info->uid, &ex); - if (camel_exception_get_id (&ex)) { - printf ("Unable to get message: %s\n", - ex.desc?ex.desc:"unknown_reason"); - return; - } - - if (message_list->seen_id) - gtk_timeout_remove (message_list->seen_id); + const char *uid; - mail_display_set_message (md, CAMEL_MEDIUM (message)); - gtk_object_unref (GTK_OBJECT (message)); - - message_list->seen_id = - gtk_timeout_add (1500, mark_msg_seen, message_list); - } else - mail_display_set_message (md, NULL); + uid = get_message_uid (message_list, row); + mail_do_display_message (message_list, uid, mark_msg_seen); } @@ -317,6 +322,7 @@ ml_tree_set_value_at (ETreeModel *etm, ETreePath *path, int col, MessageList *message_list = model_data; const CamelMessageInfo *msg_info; char *uid; + GPtrArray *uids; if (col != COL_MESSAGE_STATUS) return; @@ -330,8 +336,11 @@ ml_tree_set_value_at (ETreeModel *etm, ETreePath *path, int col, if (!msg_info) return; - camel_folder_set_message_flags (message_list->folder, msg_info->uid, - CAMEL_MESSAGE_SEEN, ~msg_info->flags); + uids = g_ptr_array_new (); + g_ptr_array_add (uids, g_strdup (uid)); + mail_do_flag_messages (message_list->folder, uids, TRUE, + CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); + if (message_list->seen_id) { gtk_timeout_remove (message_list->seen_id); message_list->seen_id = 0; @@ -571,38 +580,40 @@ message_list_init (GtkObject *object) { MessageList *message_list = MESSAGE_LIST (object); char *spec; - + message_list->table_model = (ETableModel *) e_tree_simple_new (ml_tree_icon_at, ml_tree_value_at, ml_tree_set_value_at, ml_tree_is_cell_editable, message_list); e_tree_model_root_node_set_visible ((ETreeModel *)message_list->table_model, FALSE); - + message_list_init_renderers (message_list); message_list_init_header (message_list); - + /* * The etable */ - + spec = message_list_get_layout (message_list); message_list->etable = e_table_scrolled_new ( message_list->header_model, message_list->table_model, spec); g_free (spec); - + gtk_object_set(GTK_OBJECT(message_list->etable), "cursor_mode", E_TABLE_CURSOR_LINE, "drawfocus", FALSE, "drawgrid", FALSE, NULL); - - gtk_signal_connect (GTK_OBJECT (message_list->etable), "realize", - GTK_SIGNAL_FUNC (select_row), message_list); - + + /* + *gtk_signal_connect (GTK_OBJECT (message_list->etable), "realize", + * GTK_SIGNAL_FUNC (select_row), message_list); + */ + gtk_signal_connect (GTK_OBJECT (message_list->etable), "cursor_change", - GTK_SIGNAL_FUNC (on_cursor_change_cmd), message_list); - + GTK_SIGNAL_FUNC (on_cursor_change_cmd), message_list); + gtk_signal_connect (GTK_OBJECT (message_list->etable), "right_click", GTK_SIGNAL_FUNC (on_right_click), message_list); @@ -662,7 +673,7 @@ message_list_destroy (GtkObject *object) g_source_remove(message_list->idle_id); if (message_list->folder) - gtk_object_unref (GTK_OBJECT (message_list->folder)); + camel_object_unref (CAMEL_OBJECT (message_list->folder)); GTK_OBJECT_CLASS (message_list_parent_class)->destroy (object); } @@ -820,86 +831,29 @@ build_flat (MessageList *ml, ETreePath *parent, GPtrArray *uids) } } -void -message_list_regenerate (MessageList *message_list, const char *search) -{ - ETreeModel *etm = E_TREE_MODEL (message_list->table_model); - GPtrArray *uids; - int row = 0; - - e_table_model_pre_change(message_list->table_model); - - if (message_list->search) { - g_free (message_list->search); - message_list->search = NULL; - } - - if (message_list->uid_rowmap) { - g_hash_table_foreach (message_list->uid_rowmap, - free_key, NULL); - g_hash_table_destroy (message_list->uid_rowmap); - } - message_list->uid_rowmap = g_hash_table_new (g_str_hash, g_str_equal); - - if (search && camel_folder_has_search_capability (message_list->folder)) { - CamelException ex; - - camel_exception_init (&ex); - uids = camel_folder_search_by_expression (message_list->folder, - search, &ex); - if (camel_exception_is_set (&ex)) { - e_notice (NULL, GNOME_MESSAGE_BOX_ERROR, - "Search failed: %s", - camel_exception_get_description (&ex)); - camel_exception_clear (&ex); - } else - message_list->search = g_strdup (search); - } else - uids = camel_folder_get_uids (message_list->folder); - - /* FIXME: free the old tree data */ - - /* Clear the old contents, build the new */ - if (message_list->tree_root) - e_tree_model_node_remove(etm, message_list->tree_root); - message_list->tree_root = - e_tree_model_node_insert(etm, NULL, 0, message_list); - e_tree_model_node_set_expanded (etm, message_list->tree_root, TRUE); - - if (mail_config_thread_list()) { - struct _container *head; - - head = thread_messages (message_list->folder, uids); - build_tree (message_list, message_list->tree_root, head, &row); - thread_messages_free (head); - } else - build_flat (message_list, message_list->tree_root, uids); - - if (search) { - camel_folder_search_free(message_list->folder, uids); - } else { - camel_folder_free_uids (message_list->folder, uids); - } - - e_table_model_changed (message_list->table_model); - select_msg (message_list, 0); -} - static void -folder_changed (CamelFolder *f, int type, MessageList *message_list) +folder_changed (CamelObject *o, gpointer event_data, gpointer user_data) { - message_list_regenerate (message_list, message_list->search); + MessageList *message_list = MESSAGE_LIST (user_data); + GDK_THREADS_ENTER(); /* Very important!!!! */ + mail_do_regenerate_messagelist (message_list, message_list->search); + GDK_THREADS_LEAVE(); /* Very important!!!! */ } static void -message_changed (CamelFolder *f, const char *uid, MessageList *message_list) +message_changed (CamelObject *o, gpointer uid, gpointer user_data) { + MessageList *message_list = MESSAGE_LIST (user_data); int row; + GDK_THREADS_ENTER(); /* Very important!!!! */ + row = GPOINTER_TO_INT (g_hash_table_lookup (message_list->uid_rowmap, uid)); if (row != -1) e_table_model_row_changed (message_list->table_model, row); + + GDK_THREADS_LEAVE(); /* Very important!!!! */ } void @@ -916,18 +870,20 @@ message_list_set_folder (MessageList *message_list, CamelFolder *camel_folder) camel_exception_init (&ex); if (message_list->folder) - gtk_object_unref (GTK_OBJECT (message_list->folder)); + camel_object_unref (CAMEL_OBJECT (message_list->folder)); message_list->folder = camel_folder; - gtk_signal_connect(GTK_OBJECT (camel_folder), "folder_changed", + camel_object_hook_event(CAMEL_OBJECT (camel_folder), "folder_changed", folder_changed, message_list); - gtk_signal_connect(GTK_OBJECT (camel_folder), "message_changed", + camel_object_hook_event(CAMEL_OBJECT (camel_folder), "message_changed", message_changed, message_list); - gtk_object_ref (GTK_OBJECT (camel_folder)); + camel_object_ref (CAMEL_OBJECT (camel_folder)); - folder_changed (camel_folder, 0, message_list); + /*gtk_idle_add (regen_message_list, message_list);*/ + /*folder_changed (CAMEL_OBJECT (camel_folder), 0, message_list);*/ + mail_do_regenerate_messagelist (message_list, message_list->search); } GtkWidget * @@ -953,13 +909,13 @@ static void on_cursor_change_cmd (ETableScrolled *table, int row, gpointer user_data) { MessageList *message_list; - const CamelMessageInfo *info; + const char *uid; message_list = MESSAGE_LIST (user_data); message_list->cursor_row = row; - info = get_message_info (message_list, row); - message_list->cursor_uid = info ? info->uid : NULL; + uid = get_message_uid (message_list, row); + message_list->cursor_uid = uid; /*NULL ok*/ if (!message_list->idle_id) { message_list->idle_id = @@ -972,10 +928,13 @@ on_cursor_change_cmd (ETableScrolled *table, int row, gpointer user_data) static gint idle_select_row (gpointer user_data) { - ETableScrolled *ets = user_data; - int mrow = e_table_view_to_model_row (ets->table, 0); + MessageList *ml = MESSAGE_LIST (user_data); + ETableScrolled *ets = E_TABLE_SCROLLED (ml->etable); + int mrow; - e_table_scrolled_set_cursor_row (ets, mrow); + mrow = e_table_view_to_model_row (ets->table, 0); + message_list_select (ml, mrow, MESSAGE_LIST_SELECT_NEXT, + 0, CAMEL_MESSAGE_SEEN); return FALSE; } @@ -984,7 +943,7 @@ select_row (ETableScrolled *table, gpointer user_data) { MessageList *message_list = user_data; - gtk_idle_add (idle_select_row, message_list->etable); + gtk_idle_add (idle_select_row, message_list); } static void @@ -1082,12 +1041,12 @@ static void mlfe_callback (int row, gpointer user_data) { struct message_list_foreach_data *mlfe_data = user_data; - const CamelMessageInfo *info; + const char *uid; - info = get_message_info (mlfe_data->message_list, row); - if (info) { + uid = get_message_uid (mlfe_data->message_list, row); + if (uid) { mlfe_data->callback (mlfe_data->message_list, - info->uid, + uid, mlfe_data->user_data); } } @@ -1111,6 +1070,142 @@ message_list_toggle_threads (BonoboUIHandler *uih, void *user_data, const char *path) { MessageList *ml = user_data; - mail_config_set_thread_list(bonobo_ui_handler_menu_get_toggle_state (uih, path)); - message_list_regenerate (ml, ml->search); + + mail_config_set_thread_list (bonobo_ui_handler_menu_get_toggle_state (uih, path)); + mail_do_regenerate_messagelist (ml, ml->search); +} + +/* ** REGENERATE MESSAGELIST ********************************************** */ + +typedef struct regenerate_messagelist_input_s { + MessageList *ml; + char *search; +} regenerate_messagelist_input_t; + +typedef struct regenerate_messagelist_data_s { + GPtrArray *uids; +} regenerate_messagelist_data_t; + +static gchar *describe_regenerate_messagelist (gpointer in_data, gboolean gerund); +static void setup_regenerate_messagelist (gpointer in_data, gpointer op_data, CamelException *ex); +static void do_regenerate_messagelist (gpointer in_data, gpointer op_data, CamelException *ex); +static void cleanup_regenerate_messagelist (gpointer in_data, gpointer op_data, CamelException *ex); + +static gchar *describe_regenerate_messagelist (gpointer in_data, gboolean gerund) +{ + if (gerund) + return g_strdup ("Rebuilding message view"); + else + return g_strdup ("Rebuild message view"); +} + +static void setup_regenerate_messagelist (gpointer in_data, gpointer op_data, CamelException *ex) +{ + regenerate_messagelist_input_t *input = (regenerate_messagelist_input_t *) in_data; + + if (!IS_MESSAGE_LIST (input->ml)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No messagelist specified to regenerate"); + return; + } + + gtk_object_ref (GTK_OBJECT (input->ml)); + e_table_model_pre_change (input->ml->table_model); +} + +static void do_regenerate_messagelist (gpointer in_data, gpointer op_data, CamelException *ex) +{ + regenerate_messagelist_input_t *input = (regenerate_messagelist_input_t *) in_data; + regenerate_messagelist_data_t *data = (regenerate_messagelist_data_t *) op_data; + + if (input->ml->search) { + g_free (input->ml->search); + input->ml->search = NULL; + } + + if (input->ml->uid_rowmap) { + g_hash_table_foreach (input->ml->uid_rowmap, + free_key, NULL); + g_hash_table_destroy (input->ml->uid_rowmap); + } + input->ml->uid_rowmap = g_hash_table_new (g_str_hash, g_str_equal); + + mail_tool_camel_lock_up(); + + if (input->search) { + data->uids = camel_folder_search_by_expression (input->ml->folder, + input->search, ex); + if (camel_exception_is_set (ex)) { + mail_tool_camel_lock_down(); + return; + } + + input->ml->search = g_strdup (input->search); + } else + data->uids = camel_folder_get_uids (input->ml->folder); + + mail_tool_camel_lock_down(); +} + +static void cleanup_regenerate_messagelist (gpointer in_data, gpointer op_data, CamelException *ex) +{ + regenerate_messagelist_input_t *input = (regenerate_messagelist_input_t *) in_data; + regenerate_messagelist_data_t *data = (regenerate_messagelist_data_t *) op_data; + + ETreeModel *etm; + + etm = E_TREE_MODEL (input->ml->table_model); + + /* FIXME: free the old tree data */ + + if (data->uids == NULL) { /*exception*/ + gtk_object_unref (GTK_OBJECT (input->ml)); + return; + } + + /* Clear the old contents, build the new */ + if (input->ml->tree_root) + e_tree_model_node_remove(etm, input->ml->tree_root); + input->ml->tree_root = + e_tree_model_node_insert(etm, NULL, 0, input->ml); + e_tree_model_node_set_expanded (etm, input->ml->tree_root, TRUE); + + if (mail_config_thread_list()) { + mail_do_thread_messages (input->ml, data->uids, + (gboolean) !(input->search), + build_tree); + } else { + build_flat (input->ml, input->ml->tree_root, data->uids); + + if (input->search) { + camel_folder_search_free (input->ml->folder, data->uids); + } else { + camel_folder_free_uids (input->ml->folder, data->uids); + } + } + + e_table_model_changed (input->ml->table_model); + select_row (NULL, input->ml); + g_free (input->search); + gtk_object_unref (GTK_OBJECT (input->ml)); +} + +static const mail_operation_spec op_regenerate_messagelist = +{ + describe_regenerate_messagelist, + sizeof (regenerate_messagelist_data_t), + setup_regenerate_messagelist, + do_regenerate_messagelist, + cleanup_regenerate_messagelist +}; + +void mail_do_regenerate_messagelist (MessageList *list, const gchar *search) +{ + regenerate_messagelist_input_t *input; + + input = g_new (regenerate_messagelist_input_t, 1); + input->ml = list; + input->search = g_strdup (search); + + mail_operation_queue (&op_regenerate_messagelist, input, TRUE); } diff --git a/mail/message-list.h b/mail/message-list.h index 443d92d7f4..4f9719f30b 100644 --- a/mail/message-list.h +++ b/mail/message-list.h @@ -99,7 +99,6 @@ GtkType message_list_get_type (void); BonoboObject *message_list_new (FolderBrowser *parent_folder_browser); void message_list_set_folder (MessageList *message_list, CamelFolder *camel_folder); -void message_list_regenerate (MessageList *message_list, const char *search); GtkWidget *message_list_get_widget (MessageList *message_list); void message_list_foreach (MessageList *message_list, diff --git a/mail/message-thread.c b/mail/message-thread.c index f199c27341..fa362f04ee 100644 --- a/mail/message-thread.c +++ b/mail/message-thread.c @@ -31,9 +31,15 @@ #include #include "message-thread.h" +#include "mail-tools.h" +#include "mail-threads.h" #define d(x) +static struct _container *thread_messages(CamelFolder *folder, GPtrArray *uids); +static void thread_messages_free(struct _container *); + +/* for debug only */ int dump_tree(struct _container *c, int depth); static void @@ -331,7 +337,7 @@ dump_tree(struct _container *c, int depth) return count; } -void thread_messages_free(struct _container *c) +static void thread_messages_free(struct _container *c) { struct _container *n; @@ -407,7 +413,7 @@ sort_thread(struct _container **cp) *cp = head; } -struct _container * +static struct _container * thread_messages(CamelFolder *folder, GPtrArray *uids) { GHashTable *id_table, *no_id_table; @@ -419,13 +425,20 @@ thread_messages(CamelFolder *folder, GPtrArray *uids) no_id_table = g_hash_table_new(NULL, NULL); for (i=0;ilen;i++) { const CamelMessageInfo *mi; + mail_tool_camel_lock_up (); mi = camel_folder_get_message_info (folder, uids->pdata[i]); + mail_tool_camel_lock_down (); if (mi == NULL) { g_warning("Folder doesn't contain uid %s", (char *)uids->pdata[i]); continue; } + if (mi == NULL) { + g_warning("Folder doesn't contain uid %s", uids->pdata[i]); + continue; + } + if (mi->message_id) { d(printf("doing : %s\n", mi->message_id)); c = g_hash_table_lookup(id_table, mi->message_id); @@ -495,6 +508,116 @@ thread_messages(CamelFolder *folder, GPtrArray *uids) return head; } +/* ** THREAD MESSAGES ***************************************************** */ + +typedef struct thread_messages_input_s { + MessageList *ml; + GPtrArray *uids; + gboolean use_camel_uidfree; + void (*build) (MessageList *, ETreePath *, + struct _container *, int *); +} thread_messages_input_t; + +typedef struct thread_messages_data_s { + struct _container *container; + int row; +} thread_messages_data_t; + +static gchar *describe_thread_messages (gpointer in_data, gboolean gerund); +static void setup_thread_messages (gpointer in_data, gpointer op_data, CamelException *ex); +static void do_thread_messages (gpointer in_data, gpointer op_data, CamelException *ex); +static void cleanup_thread_messages (gpointer in_data, gpointer op_data, CamelException *ex); + +static gchar *describe_thread_messages (gpointer in_data, gboolean gerund) +{ + if (gerund) + return g_strdup ("Threading message list"); + else + return g_strdup ("Thread message list"); +} + +static void setup_thread_messages (gpointer in_data, gpointer op_data, CamelException *ex) +{ + thread_messages_input_t *input = (thread_messages_input_t *) in_data; + + if (!IS_MESSAGE_LIST (input->ml)) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No messagelist to thread was provided to thread_messages"); + return; + } + + if (!input->uids) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No uids were provided to thread_messages"); + return; + } + + if (!input->build) { + camel_exception_set (ex, CAMEL_EXCEPTION_INVALID_PARAM, + "No build callback provided to thread_messages"); + return; + } + + gtk_object_ref (GTK_OBJECT (input->ml)); +} + +static void do_thread_messages (gpointer in_data, gpointer op_data, CamelException *ex) +{ + thread_messages_input_t *input = (thread_messages_input_t *) in_data; + thread_messages_data_t *data = (thread_messages_data_t *) op_data; + + data->container = thread_messages (input->ml->folder, input->uids); + data->row = 0; +} + +static void cleanup_thread_messages (gpointer in_data, gpointer op_data, CamelException *ex) +{ + thread_messages_input_t *input = (thread_messages_input_t *) in_data; + thread_messages_data_t *data = (thread_messages_data_t *) op_data; + + (input->build) (input->ml, input->ml->tree_root, + data->container, &(data->row)); + thread_messages_free (data->container); + + if (input->use_camel_uidfree) { + mail_tool_camel_lock_up (); + camel_folder_free_uids (input->ml->folder, input->uids); + mail_tool_camel_lock_down (); + } else { + g_strfreev ((char **)input->uids->pdata); + g_ptr_array_free (input->uids, FALSE); + } + + gtk_object_unref (GTK_OBJECT (input->ml)); +} + +static const mail_operation_spec op_thread_messages = +{ + describe_thread_messages, + sizeof (thread_messages_data_t), + setup_thread_messages, + do_thread_messages, + cleanup_thread_messages +}; + +void mail_do_thread_messages (MessageList *ml, GPtrArray *uids, + gboolean use_camel_uidfree, + void (*build) (MessageList *, ETreePath *, + struct _container *, int *)) +{ + thread_messages_input_t *input; + + input = g_new (thread_messages_input_t, 1); + input->ml = ml; + input->uids = uids; + input->use_camel_uidfree = use_camel_uidfree; + input->build = build; + + mail_operation_queue (&op_thread_messages, input, TRUE); +} + +/* ************************************************************************ */ + #ifdef STANDALONE static char * @@ -546,7 +669,7 @@ main (int argc, char**argv) } #endif - summary = camel_folder_get_summary(folder, ex); + summary = camel_folder_get_summary(folder); thread_messages((CamelMessageInfo **)summary->pdata, summary->len); return 0; diff --git a/mail/message-thread.h b/mail/message-thread.h index d66baacbdd..46a7a36b03 100644 --- a/mail/message-thread.h +++ b/mail/message-thread.h @@ -1,6 +1,9 @@ #ifndef _MESSAGE_THREAD_H #define _MESSAGE_THREAD_H +#include +#include "message-list.h" + struct _container { struct _container *next, *parent, @@ -11,11 +14,10 @@ struct _container { int order; /* the order of this message in the folder */ }; -struct _container *thread_messages(CamelFolder *folder, GPtrArray *uids); -void thread_messages_free(struct _container *); - -/* for debug only */ -int dump_tree(struct _container *c, int depth); +void mail_do_thread_messages (MessageList *ml, GPtrArray *uids, + gboolean use_camel_uidfree, + void (*build) (MessageList *, ETreePath *, + struct _container *, int *)); #endif /* !_MESSAGE_THREAD_H */ diff --git a/mail/session.c b/mail/session.c index 7eaefd390c..3c5d52abb0 100644 --- a/mail/session.c +++ b/mail/session.c @@ -20,9 +20,7 @@ GHashTable *passwords; * we deadlock.... */ -#ifdef USE_BROKEN_THREADS #define ASYNC_AUTH_CALLBACK -#endif #ifndef ASYNC_AUTH_CALLBACK static void @@ -63,7 +61,7 @@ mail_request_dialog (const char *prompt, gboolean secret, const char *key) ans == NULL) return NULL; #else - if (!mail_op_get_password (data, secret, &ans)) + if (!mail_op_get_password (prompt, secret, &ans)) return NULL; #endif @@ -115,13 +113,99 @@ auth_callback (CamelAuthCallbackMode mode, char *data, gboolean secret, return ans; } +/* ******************** */ + +typedef struct _timeout_data_s { + CamelTimeoutCallback cb; + gpointer camel_data; + gboolean result; +} timeout_data_t; + +static gchar * +describe_camel_timeout (gpointer in_data, gboolean gerund) +{ + /* FIXME this is so wrong */ + + if (gerund) + return g_strdup ("Keeping connection alive"); + else + return g_strdup ("Keep connection alive"); +} + +static void +noop_camel_timeout (gpointer in_data, gpointer op_data, CamelException *ex) +{ +} + +static void +do_camel_timeout (gpointer in_data, gpointer op_data, CamelException *ex) +{ + timeout_data_t *td = (timeout_data_t *) in_data; + + td->result = (td->cb) (td->camel_data); +} + +static const mail_operation_spec spec_camel_timeout = +{ + describe_camel_timeout, + 0, + noop_camel_timeout, + do_camel_timeout, + noop_camel_timeout +}; + +static gboolean +camel_timeout (gpointer data) +{ + timeout_data_t *td = (timeout_data_t *) data; + + if (td->result == FALSE) { + g_free (td); + return FALSE; + } + + mail_operation_queue (&spec_camel_timeout, td, FALSE); + return TRUE; +} + +static guint +register_callback (guint32 interval, CamelTimeoutCallback cb, gpointer camel_data) +{ + timeout_data_t *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. + */ + g_return_val_if_fail (interval > 1000, 0); + + td = g_new (timeout_data_t, 1); + td->result = TRUE; + td->cb = cb; + td->camel_data = camel_data; + + return gtk_timeout_add_full (interval, camel_timeout, NULL, + td, g_free); +} + +static gboolean +remove_callback (guint handle) +{ + gtk_timeout_remove (handle); + return TRUE; +} + +/* ******************** */ + void session_init (void) { e_setup_base_dir (); camel_init (); - session = camel_session_new (auth_callback); + session = camel_session_new (auth_callback, register_callback, + remove_callback); } static gboolean diff --git a/mail/test-thread.c b/mail/test-thread.c index b9fb5bb0b2..7a389605ec 100644 --- a/mail/test-thread.c +++ b/mail/test-thread.c @@ -8,30 +8,44 @@ #include #include "mail-threads.h" -#ifdef ENABLE_BROKEN_THREADS - -static void op_1( gpointer userdata ); -static void op_2( gpointer userdata ); -static void op_3( gpointer userdata ); -static void op_4( gpointer userdata ); -static void op_5( gpointer userdata ); -static void done( gpointer userdata ); +static gchar *desc_1 (gpointer in, gboolean gerund); +static void op_1( gpointer in, gpointer op, CamelException *ex ); +static gchar *desc_2 (gpointer in, gboolean gerund); +static void op_2( gpointer in, gpointer op, CamelException *ex ); +static gchar *desc_3 (gpointer in, gboolean gerund); +static void op_3( gpointer in, gpointer op, CamelException *ex ); +static gchar *desc_4 (gpointer in, gboolean gerund); +static void op_4( gpointer in, gpointer op, CamelException *ex ); +static gchar *desc_5 (gpointer in, gboolean gerund); +static void op_5( gpointer in, gpointer op, CamelException *ex ); +static gchar *desc_6 (gpointer in, gboolean gerund); +static gchar *desc_7 (gpointer in, gboolean gerund); +static gchar *desc_8 (gpointer in, gboolean gerund); +static void done( gpointer in, gpointer op, CamelException *ex ); +static void exception( gpointer in, gpointer op, CamelException *ex ); static gboolean queue_ops( void ); +const mail_operation_spec spec1 = { desc_1, 0, NULL, op_1, done }; +const mail_operation_spec spec2 = { desc_2, 0, NULL, op_2, done }; +const mail_operation_spec spec3 = { desc_3, 0, NULL, op_3, done }; +const mail_operation_spec spec4 = { desc_4, 0, NULL, op_4, NULL }; +const mail_operation_spec spec5 = { desc_5, 0, NULL, op_5, done }; +const mail_operation_spec spec6 = { desc_6, 0, exception, op_4, NULL }; +const mail_operation_spec spec7 = { desc_7, 0, NULL, exception, NULL }; +const mail_operation_spec spec8 = { desc_8, 0, NULL, op_4, exception }; + static gboolean queue_ops( void ) { int i; - gchar buf[32]; g_message( "Top of queue_ops" ); - mail_operation_try( "The Crawling Progress Bar of Doom", op_1, done, "op1 finished" ); - mail_operation_try( "The Mysterious Message Setter", op_2, done, "op2 finished" ); - mail_operation_try( "The Error Dialog of No Return", op_3, done, "op3 finished" ); + mail_operation_queue( &spec1, "op1 finished", FALSE ); + mail_operation_queue( &spec2, "op2 finished", FALSE ); + mail_operation_queue( &spec3, "op3 finished", FALSE ); for( i = 0; i < 3; i++ ) { - sprintf( buf, "Queue Filler %d", i ); - mail_operation_try( buf, op_4, NULL, GINT_TO_POINTER( i ) ); + mail_operation_queue( &spec4, GINT_TO_POINTER( i ), FALSE ); } g_message( "Waiting for finish..." ); @@ -39,20 +53,23 @@ static gboolean queue_ops( void ) g_message( "Ops done -- queue some more!" ); - mail_operation_try( "Progress Bar Redux", op_1, NULL, NULL ); + mail_operation_queue( &spec1, "done a second time", FALSE ); g_message( "Waiting for finish again..." ); mail_operation_wait_for_finish(); g_message( "Ops done -- more, more!" ); - mail_operation_try( "Dastardly Password Stealer", op_5, NULL, NULL ); + mail_operation_queue( &spec5, "passwords stolen", FALSE ); for( i = 0; i < 3; i++ ) { - sprintf( buf, "Queue Filler %d", i ); - mail_operation_try( buf, op_4, NULL, GINT_TO_POINTER( i ) ); + mail_operation_queue( &spec4, GINT_TO_POINTER( i ), FALSE ); } + mail_operation_queue( &spec6, NULL, FALSE ); + mail_operation_queue( &spec7, NULL, FALSE ); + mail_operation_queue( &spec8, NULL, FALSE ); + g_message( "Waiting for finish AGAIN..." ); mail_operation_wait_for_finish(); g_message( "Ops done again. Exiting 0" ); @@ -60,7 +77,12 @@ static gboolean queue_ops( void ) return FALSE; } -static void op_1( gpointer userdata ) +static void exception( gpointer in, gpointer op, CamelException *ex ) +{ + camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, "I don't feel like it."); +} + +static void op_1( gpointer in, gpointer op, CamelException *ex ) { gfloat pct; @@ -73,7 +95,7 @@ static void op_1( gpointer userdata ) } } -static void op_2( gpointer userdata ) +static void op_2( gpointer in, gpointer op, CamelException *ex ) { int i; @@ -87,7 +109,7 @@ static void op_2( gpointer userdata ) sleep( 1 ); } -static void op_3( gpointer userdata ) +static void op_3( gpointer in, gpointer op, CamelException *ex ) { gfloat pct; @@ -103,14 +125,14 @@ static void op_3( gpointer userdata ) sleep( 1 ); } -static void op_4( gpointer userdata ) +static void op_4( gpointer in, gpointer op, CamelException *ex ) { mail_op_hide_progressbar(); - mail_op_set_message( "Filler # %d", GPOINTER_TO_INT( userdata ) ); + mail_op_set_message( "Filler # %d", GPOINTER_TO_INT( in ) ); sleep( 1 ); } -static void op_5( gpointer userdata ) +static void op_5( gpointer in, gpointer op, CamelException *ex ) { gchar *pass; gboolean ret; @@ -128,26 +150,81 @@ static void op_5( gpointer userdata ) sleep( 1 ); } -static void done( gpointer userdata ) +static void done( gpointer in, gpointer op, CamelException *ex ) { - g_message( "Operation done: %s", (gchar *) userdata ); + g_message( "Operation done: %s", (gchar *) in ); } -int main( int argc, char **argv ) +static gchar *desc_1 (gpointer in, gboolean gerund) { - g_thread_init( NULL ); - gnome_init( "test-thread", "0.0", argc, argv ); - gtk_idle_add( (GtkFunction) queue_ops, NULL ); - gtk_main(); - return 0; + if (gerund) + return g_strdup ("Showing the Crawling Progress Bar of Doom"); + else + return g_strdup ("Progress Bar"); +} + +static gchar *desc_2 (gpointer in, gboolean gerund) +{ + if (gerund) + return g_strdup ("Exploring the Mysterious Message Setter"); + else + return g_strdup ("Explore"); +} + +static gchar *desc_3 (gpointer in, gboolean gerund) +{ + if (gerund) + return g_strdup ("Dare the Error Dialog of No Return"); + else + return g_strdup ("Dare"); +} + +static gchar *desc_4 (gpointer in, gboolean gerund) +{ + if (gerund) + return g_strdup_printf ("Filling Queue Space -- %d", GPOINTER_TO_INT (in)); + else + return g_strdup_printf ("Filler -- %d", GPOINTER_TO_INT (in)); +} + +static gchar *desc_5 (gpointer in, gboolean gerund) +{ + if (gerund) + return g_strdup ("Stealing your Password"); + else + return g_strdup ("The Dastardly Password Stealer"); +} + +static gchar *desc_6 (gpointer in, gboolean gerund) +{ + if (gerund) + return g_strdup ("Setting exception on setup"); + else + return g_strdup ("Exception on setup"); +} + +static gchar *desc_7 (gpointer in, gboolean gerund) +{ + if (gerund) + return g_strdup ("Setting exception in process"); + else + return g_strdup ("Exception coming soon"); +} + +static gchar *desc_8 (gpointer in, gboolean gerund) +{ + if (gerund) + return g_strdup ("Setting exception in cleanup"); + else + return g_strdup ("Exception in cleanup"); } -#else int main( int argc, char **argv ) { - g_message( "Threads aren't enabled, so they cannot be tested." ); + g_thread_init( NULL ); + gnome_init( "test-thread", "0.0", argc, argv ); + gtk_idle_add( (GtkFunction) queue_ops, NULL ); + gtk_main(); return 0; } - -#endif -- cgit v1.2.3