diff options
Diffstat (limited to 'mail/component-factory.c')
-rw-r--r-- | mail/component-factory.c | 1668 |
1 files changed, 1668 insertions, 0 deletions
diff --git a/mail/component-factory.c b/mail/component-factory.c new file mode 100644 index 0000000000..f578cd13d5 --- /dev/null +++ b/mail/component-factory.c @@ -0,0 +1,1668 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* component-factory.c + * + * Authors: Ettore Perazzoli <ettore@ximian.com> + * + * Copyright (C) 2000 Ximian, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <signal.h> + +#include <gconf/gconf.h> +#include <gconf/gconf-client.h> + +#include <camel/camel.h> +#include <camel/camel-vee-store.h> + +#include <bonobo/bonobo-generic-factory.h> +#include <bonobo/bonobo-shlib-factory.h> + +#include <gal/widgets/e-gui-utils.h> + +#include "e-util/e-dialog-utils.h" + +#include "Evolution.h" +#include "evolution-storage.h" +#include "evolution-wizard.h" +#include "evolution-composer.h" + +#include "folder-browser-factory.h" +#include "evolution-shell-component.h" +#include "evolution-shell-component-dnd.h" +#include "folder-info.h" +#include "mail.h" +#include "mail-config.h" +#include "mail-config-factory.h" +#include "mail-preferences.h" +#include "mail-composer-prefs.h" +#include "mail-tools.h" +#include "mail-ops.h" +#include "mail-offline-handler.h" +#include "mail-local.h" +#include "mail-session.h" +#include "mail-mt.h" +#include "mail-importer.h" +#include "mail-folder-cache.h" +#include "em-utils.h" +#include "component-factory.h" + +#include "mail-send-recv.h" + +#include "mail-vfolder.h" +#include "mail-autofilter.h" + +#define d(x) + +char *default_drafts_folder_uri; +CamelFolder *drafts_folder = NULL; +char *default_sent_folder_uri; +CamelFolder *sent_folder = NULL; +char *default_outbox_folder_uri; +CamelFolder *outbox_folder = NULL; +char *evolution_dir; + +EvolutionShellClient *global_shell_client = NULL; + +RuleContext *search_context = NULL; + +static MailAsyncEvent *async_event = NULL; + +static GHashTable *storages_hash; +static EvolutionShellComponent *shell_component; + +enum { + ACCEPTED_DND_TYPE_MESSAGE_RFC822, + ACCEPTED_DND_TYPE_X_EVOLUTION_MESSAGE, + ACCEPTED_DND_TYPE_TEXT_URI_LIST, +}; + +static char *accepted_dnd_types[] = { + "message/rfc822", + "x-evolution-message", /* ...from an evolution message list... */ + "text/uri-list", /* ...from nautilus... */ + NULL +}; + +enum { + EXPORTED_DND_TYPE_TEXT_URI_LIST, +}; + +static char *exported_dnd_types[] = { + "text/uri-list", /* we have to export to nautilus as text/uri-list */ + NULL +}; + +static const EvolutionShellComponentFolderType folder_types[] = { + { "mail", "evolution-inbox.png", N_("Mail"), N_("Folder containing mail"), TRUE, accepted_dnd_types, exported_dnd_types }, + { "mail/public", "evolution-inbox.png", N_("Public Mail"), N_("Public folder containing mail"), FALSE, accepted_dnd_types, exported_dnd_types }, + { "vtrash", "evolution-trash.png", N_("Virtual Trash"), N_("Virtual Trash folder"), FALSE, accepted_dnd_types, exported_dnd_types }, + { "vjunk", "evolution-junk.png", N_("Virtual Junk"), N_("Virtual Junk folder"), FALSE, accepted_dnd_types, exported_dnd_types }, + { NULL, NULL, NULL, NULL, FALSE, NULL, NULL } +}; + +static const char *schema_types[] = { + "mailto", + NULL +}; + +static inline gboolean +type_is_mail (const char *type) +{ + return !strcmp (type, "mail") || !strcmp (type, "mail/public"); +} + +static inline gboolean +type_is_vtrash (const char *type) +{ + return !strcmp (type, "vtrash"); +} + +static inline gboolean +type_is_vjunk (const char *type) +{ + return !strcmp (type, "vjunk"); +} + +/* EvolutionShellComponent methods and signals. */ + +static BonoboControl * +create_noselect_control (void) +{ + GtkWidget *label; + + label = gtk_label_new (_("This folder cannot contain messages.")); + gtk_widget_show (label); + return bonobo_control_new (label); +} + +static EvolutionShellComponentResult +create_view (EvolutionShellComponent *shell_component, + const char *physical_uri, + const char *folder_type, + const char *view_info, + BonoboControl **control_return, + void *closure) +{ + EvolutionShellClient *shell_client; + GNOME_Evolution_Shell corba_shell; + BonoboControl *control; + + shell_client = evolution_shell_component_get_owner (shell_component); + corba_shell = evolution_shell_client_corba_objref(shell_client); + + if (type_is_mail (folder_type)) { + const char *noselect; + CamelURL *url; + + url = camel_url_new (physical_uri, NULL); + noselect = url ? camel_url_get_param (url, "noselect") : NULL; + if (noselect && !strcasecmp (noselect, "yes")) + control = create_noselect_control (); + else + control = folder_browser_factory_new_control (physical_uri, + corba_shell); + camel_url_free (url); + } else if (type_is_vtrash (folder_type)) { + if (!strncasecmp (physical_uri, "file:", 5)) + control = folder_browser_factory_new_control ("vtrash:file:/", corba_shell); + else + control = folder_browser_factory_new_control (physical_uri, corba_shell); + } else if (type_is_vjunk (folder_type)) + if (!strncasecmp (physical_uri, "file:", 5)) + control = folder_browser_factory_new_control ("vjunk:file:/", corba_shell); + else + control = folder_browser_factory_new_control (physical_uri, corba_shell); + else + return EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDTYPE; + + if (!control) + return EVOLUTION_SHELL_COMPONENT_NOTFOUND; + + *control_return = control; + return EVOLUTION_SHELL_COMPONENT_OK; +} + +static void +create_folder_done (char *uri, CamelFolder *folder, void *data) +{ + GNOME_Evolution_ShellComponentListener listener = data; + GNOME_Evolution_ShellComponentListener_Result result; + CORBA_Environment ev; + + if (folder) { + result = GNOME_Evolution_ShellComponentListener_OK; + } else { + result = GNOME_Evolution_ShellComponentListener_INVALID_URI; + } + + CORBA_exception_init (&ev); + GNOME_Evolution_ShellComponentListener_notifyResult (listener, result, &ev); + CORBA_Object_release (listener, &ev); + CORBA_exception_free (&ev); +} + +static void +create_folder (EvolutionShellComponent *shell_component, + const char *physical_uri, + const char *type, + const GNOME_Evolution_ShellComponentListener listener, + void *closure) +{ + CORBA_Environment ev; + + CORBA_exception_init (&ev); + + if (type_is_mail (type)) { + mail_get_folder (physical_uri, CAMEL_STORE_FOLDER_CREATE, create_folder_done, + CORBA_Object_duplicate (listener, &ev), mail_thread_new); + } else { + GNOME_Evolution_ShellComponentListener_notifyResult ( + listener, GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, &ev); + } + + CORBA_exception_free (&ev); +} + +static void +remove_folder_done (char *uri, gboolean removed, void *data) +{ + GNOME_Evolution_ShellComponentListener listener = data; + GNOME_Evolution_ShellComponentListener_Result result; + CORBA_Environment ev; + + if (removed) + result = GNOME_Evolution_ShellComponentListener_OK; + else + result = GNOME_Evolution_ShellComponentListener_INVALID_URI; + + CORBA_exception_init (&ev); + GNOME_Evolution_ShellComponentListener_notifyResult (listener, result, &ev); + CORBA_Object_release (listener, &ev); + CORBA_exception_free (&ev); +} + +static void +remove_folder (EvolutionShellComponent *shell_component, + const char *physical_uri, + const char *type, + const GNOME_Evolution_ShellComponentListener listener, + void *closure) +{ + CORBA_Environment ev; + + CORBA_exception_init (&ev); + + if (!type_is_mail (type)) { + GNOME_Evolution_ShellComponentListener_notifyResult (listener, + GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, &ev); + CORBA_exception_free (&ev); + return; + } + + mail_remove_folder (physical_uri, remove_folder_done, CORBA_Object_duplicate (listener, &ev)); + CORBA_exception_free (&ev); +} + +typedef struct _xfer_folder_data { + GNOME_Evolution_ShellComponentListener listener; + gboolean remove_source; + char *source_uri; +} xfer_folder_data; + +static void +xfer_folder_done (gboolean ok, void *data) +{ + xfer_folder_data *xfd = (xfer_folder_data *)data; + GNOME_Evolution_ShellComponentListener listener = xfd->listener; + GNOME_Evolution_ShellComponentListener_Result result; + CORBA_Environment ev; + + if (xfd->remove_source && ok) { + mail_remove_folder (xfd->source_uri, remove_folder_done, xfd->listener); + } else { + if (ok) + result = GNOME_Evolution_ShellComponentListener_OK; + else + result = GNOME_Evolution_ShellComponentListener_INVALID_URI; + + CORBA_exception_init (&ev); + GNOME_Evolution_ShellComponentListener_notifyResult (listener, result, &ev); + CORBA_Object_release (listener, &ev); + CORBA_exception_free (&ev); + } + + g_free (xfd->source_uri); + g_free (xfd); +} + +static void +xfer_folder (EvolutionShellComponent *shell_component, + const char *source_physical_uri, + const char *destination_physical_uri, + const char *type, + gboolean remove_source, + const GNOME_Evolution_ShellComponentListener listener, + void *closure) +{ + CORBA_Environment ev; + CamelFolder *source; + CamelException ex; + GPtrArray *uids; + CamelURL *src, *dst; + + d(printf("Renaming folder '%s' to dest '%s' type '%s'\n", source_physical_uri, destination_physical_uri, type)); + + CORBA_exception_init (&ev); + + if (!type_is_mail (type)) { + GNOME_Evolution_ShellComponentListener_notifyResult (listener, + GNOME_Evolution_ShellComponentListener_UNSUPPORTED_TYPE, &ev); + return; + } + + src = camel_url_new(source_physical_uri, NULL); + if (src == NULL) { + GNOME_Evolution_ShellComponentListener_notifyResult (listener, GNOME_Evolution_ShellComponentListener_INVALID_URI, &ev); + return; + } + + dst = camel_url_new(destination_physical_uri, NULL); + if (dst == NULL) { + camel_url_free(src); + GNOME_Evolution_ShellComponentListener_notifyResult (listener, GNOME_Evolution_ShellComponentListener_INVALID_URI, &ev); + return; + } + + if (camel_url_get_param(dst, "noselect") != NULL) { + camel_url_free(src); + camel_url_free(dst); + GNOME_Evolution_ShellComponentListener_notifyResult (listener, + GNOME_Evolution_ShellComponentListener_UNSUPPORTED_OPERATION, &ev); + return; + } + + camel_exception_init (&ex); + + /* If we are really doing a rename, implement it as a rename */ + if (remove && strcmp(src->protocol, dst->protocol) == 0) { + char *sname, *dname; + CamelStore *store; + + if (src->fragment) + sname = src->fragment; + else { + if (src->path && *src->path) + sname = src->path+1; + else + sname = ""; + } + + if (dst->fragment) + dname = dst->fragment; + else { + if (dst->path && *dst->path) + dname = dst->path+1; + else + dname = ""; + } + + store = camel_session_get_store(session, source_physical_uri, &ex); + if (store != NULL) + camel_store_rename_folder(store, sname, dname, &ex); + + if (camel_exception_is_set(&ex)) + GNOME_Evolution_ShellComponentListener_notifyResult (listener, GNOME_Evolution_ShellComponentListener_INVALID_URI, &ev); + else { + /* Since the shell doesn't play nice with local folders, we have to do this manually */ + mail_vfolder_rename_uri(store, source_physical_uri, destination_physical_uri); + mail_filter_rename_uri(store, source_physical_uri, destination_physical_uri); + GNOME_Evolution_ShellComponentListener_notifyResult (listener, GNOME_Evolution_ShellComponentListener_OK, &ev); + } + camel_object_unref((CamelObject *)store); + } else { + source = mail_tool_uri_to_folder (source_physical_uri, 0, &ex); + + if (source) { + xfer_folder_data *xfd; + + xfd = g_new0 (xfer_folder_data, 1); + xfd->remove_source = remove_source; + xfd->source_uri = g_strdup (source_physical_uri); + xfd->listener = CORBA_Object_duplicate (listener, &ev); + + uids = camel_folder_get_uids (source); + mail_transfer_messages (source, uids, remove_source, destination_physical_uri, CAMEL_STORE_FOLDER_CREATE, xfer_folder_done, xfd); + camel_object_unref (CAMEL_OBJECT (source)); + } else + GNOME_Evolution_ShellComponentListener_notifyResult (listener, GNOME_Evolution_ShellComponentListener_INVALID_URI, &ev); + } + + CORBA_exception_free (&ev); + camel_exception_clear (&ex); + + camel_url_free(src); + camel_url_free(dst); +} + +static void +configure_folder_popup(BonoboUIComponent *component, void *user_data, const char *cname) +{ + char *uri = user_data; + + /* FIXME: re-implement */ + + if (strncmp(uri, "vfolder:", 8) == 0) + vfolder_edit_rule(uri); +#if 0 + else { + struct _EMFolderBrowser *fb = folder_browser_factory_get_browser(uri); + + if (fb) + configure_folder(component, fb, cname); + else + mail_local_reconfigure_folder(uri, NULL, NULL); + } +#endif +} + +static void +populate_folder_context_menu (EvolutionShellComponent *shell_component, + BonoboUIComponent *uic, + const char *physical_uri, + const char *type, + void *closure) +{ +#ifdef TRANSLATORS_ONLY + static char popup_xml_i18n[] = {N_("Properties..."), N_("Change this folder's properties")}; +#endif + static char popup_xml[] = + "<menuitem name=\"ChangeFolderPropertiesPopUp\" verb=\"ChangeFolderPropertiesPopUp\"" + " _label=\"Properties...\" _tip=\"Change this folder's properties\"/>"; + + if (!type_is_mail (type)) + return; + + /* FIXME: handle other types */ + + /* the unmatched test is a bit of a hack but it works */ + if ((strncmp(physical_uri, "vfolder:", 8) == 0 + && strstr(physical_uri, "#" CAMEL_UNMATCHED_NAME) == NULL) + || strncmp(physical_uri, "file:", 5) == 0) { + bonobo_ui_component_add_verb_full(uic, "ChangeFolderPropertiesPopUp", + g_cclosure_new(G_CALLBACK(configure_folder_popup), + g_strdup(physical_uri), (GClosureNotify)g_free)); + bonobo_ui_component_set_translate (uic, EVOLUTION_SHELL_COMPONENT_POPUP_PLACEHOLDER, popup_xml, NULL); + } +} + +static void +unpopulate_folder_context_menu (EvolutionShellComponent *shell_component, + BonoboUIComponent *uic, + const char *physical_uri, + const char *type, + void *closure) +{ + if (!type_is_mail (type)) + return; + + /* FIXME: handle other types */ + + /* the unmatched test is a bit of a hack but it works */ + if ((strncmp(physical_uri, "vfolder:", 8) == 0 + && strstr(physical_uri, "#" CAMEL_UNMATCHED_NAME) == NULL) + || strncmp(physical_uri, "file:", 5) == 0) { + bonobo_ui_component_rm (uic, EVOLUTION_SHELL_COMPONENT_POPUP_PLACEHOLDER "/ChangeFolderPropertiesPopUp", NULL); + } +} + +static char * +get_dnd_selection (EvolutionShellComponent *shell_component, + const char *physical_uri, + int type, + int *format_return, + const char **selection_return, + int *selection_length_return, + void *closure) +{ + d(printf ("should get dnd selection for %s\n", physical_uri)); + + return NULL; +} + +/* Destination side DnD */ +static CORBA_boolean +destination_folder_handle_motion (EvolutionShellComponentDndDestinationFolder *folder, + const char *physical_uri, + const char *folder_type, + const GNOME_Evolution_ShellComponentDnd_DestinationFolder_Context *destination_context, + GNOME_Evolution_ShellComponentDnd_Action *suggested_action_return, + gpointer user_data) +{ + const char *noselect; + CamelURL *url; + + url = camel_url_new (physical_uri, NULL); + noselect = url ? camel_url_get_param (url, "noselect") : NULL; + + if (noselect && !strcasecmp (noselect, "yes")) + /* uh, no way to say "illegal" */ + *suggested_action_return = GNOME_Evolution_ShellComponentDnd_ACTION_DEFAULT; + else + *suggested_action_return = GNOME_Evolution_ShellComponentDnd_ACTION_MOVE; + + if (url) + camel_url_free (url); + + return TRUE; +} + +static gboolean +message_rfc822_dnd (CamelFolder *dest, CamelStream *stream, CamelException *ex) +{ + CamelMimeParser *mp; + gboolean handled = FALSE; + + mp = camel_mime_parser_new (); + camel_mime_parser_scan_from (mp, TRUE); + camel_mime_parser_init_with_stream (mp, stream); + + while (camel_mime_parser_step (mp, 0, 0) == CAMEL_MIME_PARSER_STATE_FROM) { + CamelMessageInfo *info; + CamelMimeMessage *msg; + + handled = TRUE; + + msg = camel_mime_message_new (); + if (camel_mime_part_construct_from_parser (CAMEL_MIME_PART (msg), mp) == -1) { + camel_object_unref (msg); + handled = FALSE; + break; + } + + /* append the message to the folder... */ + info = g_new0 (CamelMessageInfo, 1); + camel_folder_append_message (dest, msg, info, NULL, ex); + camel_object_unref (msg); + + if (camel_exception_is_set (ex)) { + handled = FALSE; + break; + } + + /* skip over the FROM_END state */ + camel_mime_parser_step (mp, 0, 0); + } + + camel_object_unref (mp); + + return handled; +} + +static CORBA_boolean +destination_folder_handle_drop (EvolutionShellComponentDndDestinationFolder *dest_folder, + const char *physical_uri, + const char *folder_type, + const GNOME_Evolution_ShellComponentDnd_DestinationFolder_Context *destination_context, + const GNOME_Evolution_ShellComponentDnd_Action action, + const GNOME_Evolution_ShellComponentDnd_Data *data, + gpointer user_data) +{ + char *tmp, *url, **urls; + gboolean retval = FALSE; + const char *noselect; + CamelFolder *folder; + CamelStream *stream; + CamelException ex; + GPtrArray *uids; + CamelURL *uri; + int i, type, fd; + + if (action == GNOME_Evolution_ShellComponentDnd_ACTION_LINK) + return FALSE; /* we can't create links */ + + /* this means the drag was cancelled */ + if (!data->bytes._buffer || data->bytes._length == -1) + return FALSE; + + uri = camel_url_new (physical_uri, NULL); + noselect = uri ? camel_url_get_param (uri, "noselect") : NULL; + if (noselect && !strcasecmp (noselect, "yes")) { + camel_url_free (uri); + return FALSE; + } + + if (uri) + camel_url_free (uri); + + d(printf ("in destination_folder_handle_drop (%s)\n", physical_uri)); + + for (type = 0; accepted_dnd_types[type]; type++) + if (!strcmp (destination_context->dndType, accepted_dnd_types[type])) + break; + + camel_exception_init (&ex); + + /* if this is a local vtrash folder, then it's uri is vtrash:file:/ */ + if (type_is_vtrash (folder_type) && !strncmp (physical_uri, "file:", 5)) + physical_uri = "vtrash:file:/"; + + /* if this is a local vjunk folder, then it's uri is vjunk:file:/ */ + if (type_is_vjunk (folder_type) && !strncmp (physical_uri, "file:", 5)) + physical_uri = "vjunk:file:/"; + + switch (type) { + case ACCEPTED_DND_TYPE_TEXT_URI_LIST: + folder = mail_tool_uri_to_folder (physical_uri, 0, &ex); + if (!folder) { + camel_exception_clear (&ex); + return FALSE; + } + + tmp = g_strndup (data->bytes._buffer, data->bytes._length); + urls = g_strsplit (tmp, "\n", 0); + g_free (tmp); + + retval = TRUE; + for (i = 0; urls[i] != NULL && retval; i++) { + /* get the path component */ + url = g_strstrip (urls[i]); + + uri = camel_url_new (url, NULL); + g_free (url); + + if (!uri) + continue; + + url = uri->path; + uri->path = NULL; + camel_url_free (uri); + + fd = open (url, O_RDONLY); + if (fd == -1) { + g_free (url); + /* FIXME: okay, so what do we do in this case? */ + continue; + } + + stream = camel_stream_fs_new_with_fd (fd); + retval = message_rfc822_dnd (folder, stream, &ex); + camel_object_unref (stream); + camel_object_unref (folder); + + if (action == GNOME_Evolution_ShellComponentDnd_ACTION_MOVE && retval) + unlink (url); + + g_free (url); + } + + g_free (urls); + break; + case ACCEPTED_DND_TYPE_MESSAGE_RFC822: + folder = mail_tool_uri_to_folder (physical_uri, 0, &ex); + if (!folder) { + camel_exception_clear (&ex); + return FALSE; + } + + /* write the message(s) out to a CamelStream so we can use it */ + stream = camel_stream_mem_new (); + camel_stream_write (stream, data->bytes._buffer, data->bytes._length); + camel_stream_reset (stream); + + retval = message_rfc822_dnd (folder, stream, &ex); + camel_object_unref (stream); + camel_object_unref (folder); + break; + case ACCEPTED_DND_TYPE_X_EVOLUTION_MESSAGE: + folder = mail_tools_x_evolution_message_parse (data->bytes._buffer, + data->bytes._length, + &uids); + + if (!folder) + return FALSE; + + mail_transfer_messages (folder, uids, + action == GNOME_Evolution_ShellComponentDnd_ACTION_MOVE, + physical_uri, 0, NULL, NULL); + + camel_object_unref (folder); + break; + default: + break; + } + + camel_exception_clear (&ex); + + return retval; +} + + +static struct { + char *name, **uri; + CamelFolder **folder; +} standard_folders[] = { + { "Drafts", &default_drafts_folder_uri, &drafts_folder }, + { "Outbox", &default_outbox_folder_uri, &outbox_folder }, + { "Sent", &default_sent_folder_uri, &sent_folder }, +}; + +static void +unref_standard_folders (void) +{ + int i; + + for (i = 0; i < sizeof (standard_folders) / sizeof (standard_folders[0]); i++) { + if (standard_folders[i].folder) { + CamelFolder *folder = *standard_folders[i].folder; + + *standard_folders[i].folder = NULL; + + if (CAMEL_OBJECT (folder)->ref_count == 1) + d(printf ("About to finalise folder %s\n", folder->full_name)); + else + d(printf ("Folder %s still has %d extra ref%s on it\n", folder->full_name, + CAMEL_OBJECT (folder)->ref_count - 1, + CAMEL_OBJECT (folder)->ref_count - 1 == 1 ? "" : "s")); + + camel_object_unref (CAMEL_OBJECT (folder)); + } + } +} + +static void +got_folder (char *uri, CamelFolder *folder, void *data) +{ + CamelFolder **fp = data; + + *fp = folder; + + if (folder) { + camel_object_ref (CAMEL_OBJECT (folder)); + + /* emit a changed event, this is a little hack so that the folderinfo cache + will update knowing whether this is the outbox_folder or not, etc */ + if (folder == outbox_folder) { + CamelFolderChangeInfo *changes = camel_folder_change_info_new(); + + camel_object_trigger_event((CamelObject *)folder, "folder_changed", changes); + camel_folder_change_info_free(changes); + } + } +} + +static void +shell_client_destroy (GtkObject *object) +{ + global_shell_client = NULL; +} + +static void +owner_set_cb (EvolutionShellComponent *shell_component, + EvolutionShellClient *shell_client, + const char *evolution_homedir, + gpointer user_data) +{ + GNOME_Evolution_Shell corba_shell; + EAccountList *accounts; + int i; + + /* FIXME: should we ref this? */ + global_shell_client = shell_client; + g_object_weak_ref ((GObject *) shell_client, (GWeakNotify) shell_client_destroy, NULL); + + evolution_dir = g_strdup (evolution_homedir); + mail_session_init (); + + async_event = mail_async_event_new(); + + storages_hash = g_hash_table_new (NULL, NULL); + + corba_shell = evolution_shell_client_corba_objref (shell_client); + + for (i = 0; i < sizeof (standard_folders) / sizeof (standard_folders[0]); i++) + *standard_folders[i].uri = g_strdup_printf ("file://%s/local/%s", evolution_dir, standard_folders[i].name); + + vfolder_load_storage(corba_shell); + + accounts = mail_config_get_accounts (); + mail_load_storages (corba_shell, accounts); + + mail_local_storage_startup (shell_client, evolution_dir); + mail_importer_init (shell_client); + + for (i = 0; i < sizeof (standard_folders) / sizeof (standard_folders[0]); i++) { + mail_msg_wait (mail_get_folder (*standard_folders[i].uri, CAMEL_STORE_FOLDER_CREATE, + got_folder, standard_folders[i].folder, mail_thread_new)); + } + + mail_autoreceive_setup (); + + { + /* setup the global quick-search context */ + char *user = g_strdup_printf ("%s/searches.xml", evolution_dir); + char *system = g_strdup (EVOLUTION_PRIVDATADIR "/searchtypes.xml"); + + search_context = rule_context_new (); + g_object_set_data_full(G_OBJECT(search_context), "user", user, g_free); + g_object_set_data_full(G_OBJECT(search_context), "system", system, g_free); + + rule_context_add_part_set (search_context, "partset", filter_part_get_type (), + rule_context_add_part, rule_context_next_part); + + rule_context_add_rule_set (search_context, "ruleset", filter_rule_get_type (), + rule_context_add_rule, rule_context_next_rule); + + rule_context_load (search_context, system, user); + } + + if (mail_config_is_corrupt ()) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, + _("Some of your mail settings seem corrupt, " + "please check that everything is in order.")); + g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); + gtk_widget_show (dialog); + } + + /* Everything should be ready now */ + evolution_folder_info_notify_ready (); +} + +static void +free_storage (gpointer service, gpointer storage, gpointer data) +{ + if (service) { + mail_note_store_remove((CamelStore *)service); + camel_service_disconnect (CAMEL_SERVICE (service), TRUE, NULL); + camel_object_unref (CAMEL_OBJECT (service)); + } + + if (storage) + bonobo_object_unref (BONOBO_OBJECT (storage)); +} + +static void +debug_cb (EvolutionShellComponent *shell_component, gpointer user_data) +{ + extern gboolean camel_verbose_debug; + + camel_verbose_debug = 1; +} + +static void +interactive_cb (EvolutionShellComponent *shell_component, gboolean on, + gulong new_view_xid, gpointer user_data) +{ + mail_session_set_interactive (on); + + if (on) + /* how do we get the parent window? */ + e_msg_composer_check_autosave(NULL); +} + +static void +handle_external_uri_cb (EvolutionShellComponent *shell_component, + const char *uri, + void *data) +{ + if (strncmp (uri, "mailto:", 7) != 0) { + /* FIXME: Exception? The EvolutionShellComponent object should + give me a chance to do so, but currently it doesn't. */ + g_warning ("Invalid URI requested to mail component -- %s", uri); + return; + } + + /* FIXME: Sigh. This shouldn't be here. But the code is messy, so + I'll just put it here anyway. */ + em_utils_compose_new_message_with_mailto(NULL, uri); +} + +static void +user_create_new_item_cb (EvolutionShellComponent *shell_component, + const char *id, + const char *parent_folder_physical_uri, + const char *parent_folder_type, + gpointer data) +{ + if (!strcmp (id, "message")) { + em_utils_compose_new_message_with_mailto(NULL, NULL); + /*send_to_url (NULL, parent_folder_physical_uri);*/ + return; + } else if (!strcmp (id, "post")) { + em_utils_post_to_url (NULL, parent_folder_physical_uri); + return; + } + + g_warning ("Don't know how to create item of type \"%s\"", id); +} + +static void owner_unset_cb (EvolutionShellComponent *shell_component, gpointer user_data); + +/* Table for signal handler setup/cleanup */ +static struct { + char *sig; + GCallback func; + int hand; +} shell_component_handlers[] = { + { "owner_set", G_CALLBACK(owner_set_cb), }, + { "owner_unset", G_CALLBACK(owner_unset_cb), }, + { "debug", G_CALLBACK(debug_cb), }, + { "interactive", G_CALLBACK(interactive_cb) }, + { "destroy", G_CALLBACK(owner_unset_cb), }, + { "handle_external_uri", G_CALLBACK(handle_external_uri_cb), }, + { "user_create_new_item", G_CALLBACK(user_create_new_item_cb) } +}; + +static void +owner_unset_cb (EvolutionShellComponent *shell_component, gpointer user_data) +{ + CORBA_Environment ev; + GConfClient *gconf; + int i; + EIterator *it; + + gconf = mail_config_get_gconf_client (); + + for (i=0;i<sizeof(shell_component_handlers)/sizeof(shell_component_handlers[0]);i++) + g_signal_handler_disconnect((GtkObject *)shell_component, shell_component_handlers[i].hand); + + if (gconf_client_get_bool (gconf, "/apps/evolution/mail/trash/empty_on_exit", NULL)) + em_utils_empty_trash(NULL); + + unref_standard_folders (); + mail_local_storage_shutdown (); + mail_importer_uninit (); + + global_shell_client = NULL; + mail_session_set_interactive (FALSE); + + g_object_unref (search_context); + search_context = NULL; + + /* force de-activate of all controls, tho only one should be active anyway? */ + CORBA_exception_init(&ev); + for (it = e_list_get_iterator(folder_browser_factory_get_control_list()); + e_iterator_is_valid(it); + e_iterator_next(it)) { + Bonobo_Control_activate(bonobo_object_corba_objref((BonoboObject *)e_iterator_get(it)), + FALSE, &ev); + } + CORBA_exception_free(&ev); + + for (i= 0;i<3;i++) { + /* need to flush any outstanding tasks before proceeding */ + + /* NOTE!! This may cause a deadlock situation, if we were + called from a deeper main loop than the top level + - is there a way to detect this? + - is this a very big problem? + FIXME: should use semaphores or something to wait rather than polling */ + while (e_thread_busy(NULL) || mail_msg_active(-1)) { + if (g_main_context_pending(NULL)) + g_main_context_iteration(NULL, TRUE); + else + usleep(100000); + } + + switch(i) { + case 0: + mail_vfolder_shutdown(); + break; + case 1: + if (mail_async_event_destroy(async_event) == -1) { + g_warning("Cannot destroy async event: would deadlock"); + g_warning(" system may be unstable at exit"); + } + break; + case 2: + g_hash_table_foreach (storages_hash, free_storage, NULL); + g_hash_table_destroy (storages_hash); + storages_hash = NULL; + break; + } + } +} + +static void +send_receive_cb (EvolutionShellComponent *shell_component, + gboolean show_dialog, + void *data) +{ + EAccount *account; + GtkWidget *dialog; + + /* FIXME: configure_mail() should be changed to work without a + FolderBrowser, and then we will be able to call configure_mail from + here properly. */ + if (!mail_config_is_configured () /* && !configure_mail (fb) */) + return; + + account = mail_config_get_default_account (); + if (!account || !account->transport->url) { + dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + _("You have not set a mail transport method")); + g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); + gtk_widget_show (dialog); + } else { + dialog = mail_send_receive (); + e_dialog_set_transient_for_xid((GtkWindow *)dialog, evolution_shell_component_get_parent_view_xid(shell_component)); + } +} + +static gboolean +request_quit (EvolutionShellComponent *shell_component, + void *closure) +{ + GtkWidget *dialog; + int resp; + + if (!e_msg_composer_request_close_all ()) + return FALSE; + + if (!outbox_folder || !camel_folder_get_message_count (outbox_folder)) + return TRUE; + + dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_YES_NO, + _("You have unsent messages, do you wish to quit anyway?")); + gtk_dialog_set_default_response((GtkDialog *)dialog, GTK_RESPONSE_NO); + resp = gtk_dialog_run((GtkDialog *)dialog); + gtk_widget_destroy(dialog); + + return resp == GTK_RESPONSE_YES; +} + +static BonoboObject * +create_component (void) +{ + EvolutionShellComponentDndDestinationFolder *destination_interface; + MailOfflineHandler *offline_handler; + GdkPixbuf *icon; + int i; + + shell_component = evolution_shell_component_new (folder_types, + schema_types, + create_view, + create_folder, + remove_folder, + xfer_folder, + populate_folder_context_menu, + unpopulate_folder_context_menu, + get_dnd_selection, + request_quit, + NULL); + + g_signal_connect((shell_component), "send_receive", + G_CALLBACK (send_receive_cb), NULL); + + destination_interface = evolution_shell_component_dnd_destination_folder_new (destination_folder_handle_motion, + destination_folder_handle_drop, + shell_component); + + bonobo_object_add_interface (BONOBO_OBJECT (shell_component), + BONOBO_OBJECT (destination_interface)); + + icon = gdk_pixbuf_new_from_file (EVOLUTION_ICONSDIR "/new-message.xpm", NULL); + evolution_shell_component_add_user_creatable_item (shell_component, "message", + _("New Mail Message"), _("_Mail Message"), + _("Compose a new mail message"), + "mail", 'm', + icon); + if (icon != NULL) + g_object_unref (icon); + + icon = gdk_pixbuf_new_from_file (EVOLUTION_ICONSDIR "/post-message-16.png", NULL); + evolution_shell_component_add_user_creatable_item (shell_component, "post", + _("New Message Post"), _("_Post Message"), + _("Post a new mail message"), + "mail/public", 'p', + icon); + if (icon != NULL) + g_object_unref (icon); + + for (i=0;i<sizeof(shell_component_handlers)/sizeof(shell_component_handlers[0]);i++) { + shell_component_handlers[i].hand = g_signal_connect((shell_component), + shell_component_handlers[i].sig, + shell_component_handlers[i].func, NULL); + } + + offline_handler = mail_offline_handler_new (); + bonobo_object_add_interface (BONOBO_OBJECT (shell_component), BONOBO_OBJECT (offline_handler)); + + return BONOBO_OBJECT (shell_component); +} + +static void +notify_listener (const Bonobo_Listener listener, + GNOME_Evolution_Storage_Result corba_result) +{ + CORBA_any any; + CORBA_Environment ev; + + CORBA_exception_init (&ev); + + any._type = TC_GNOME_Evolution_Storage_Result; + any._value = &corba_result; + + Bonobo_Listener_event (listener, "result", &any, &ev); + + CORBA_exception_free (&ev); +} + +static void +notify_listener_exception(const Bonobo_Listener listener, CamelException *ex) +{ + GNOME_Evolution_Storage_Result result; + + switch(camel_exception_get_id(ex)) { + case CAMEL_EXCEPTION_SERVICE_UNAVAILABLE: + result = GNOME_Evolution_Storage_NOT_ONLINE; + break; + case CAMEL_EXCEPTION_NONE: + result = GNOME_Evolution_Storage_OK; + break; + case CAMEL_EXCEPTION_FOLDER_INVALID_PATH: + case CAMEL_EXCEPTION_SERVICE_URL_INVALID: + result = GNOME_Evolution_Storage_INVALID_URI; + break; + default: + result = GNOME_Evolution_Storage_GENERIC_ERROR; + break; + } + + notify_listener(listener, result); +} + +static void +storage_create_folder (EvolutionStorage *storage, + const Bonobo_Listener listener, + const char *path, + const char *type, + const char *description, + const char *parent_physical_uri, + gpointer user_data) +{ + CamelStore *store = user_data; + CamelFolderInfo *root, *fi; + char *name; + CamelURL *url; + CamelException ex; + + /* We could just use 'path' always here? */ + + if (!type_is_mail (type)) { + notify_listener (listener, GNOME_Evolution_Storage_UNSUPPORTED_TYPE); + return; + } + + name = strrchr (path, '/'); + if (!name) { + notify_listener (listener, GNOME_Evolution_Storage_INVALID_URI); + return; + } + name++; + + /* we can not directly create folders on a vfolder store, so fudge it */ + if (CAMEL_IS_VEE_STORE(store)) { + VfolderRule *rule; + rule = vfolder_rule_new(); + + filter_rule_set_name((FilterRule *)rule, path+1); + vfolder_gui_add_rule(rule); + } else { + camel_exception_init (&ex); + if (*parent_physical_uri) { + url = camel_url_new (parent_physical_uri, NULL); + if (!url) { + notify_listener (listener, GNOME_Evolution_Storage_INVALID_URI); + return; + } + + root = camel_store_create_folder (store, url->fragment?url->fragment:url->path + 1, name, &ex); + camel_url_free (url); + } else + root = camel_store_create_folder (store, NULL, name, &ex); + + if (camel_exception_is_set (&ex)) { + notify_listener_exception(listener, &ex); + camel_exception_clear (&ex); + return; + } + + if (camel_store_supports_subscriptions (store)) { + for (fi = root; fi; fi = fi->child) + camel_store_subscribe_folder (store, fi->full_name, NULL); + } + + camel_store_free_folder_info (store, root); + } + + notify_listener (listener, GNOME_Evolution_Storage_OK); +} + +static void +storage_remove_folder_recursive (EvolutionStorage *storage, CamelStore *store, CamelFolderInfo *root, CamelException *ex) +{ + CamelFolderInfo *fi; + + /* delete all children */ + fi = root->child; + while (fi && !camel_exception_is_set (ex)) { + storage_remove_folder_recursive (storage, store, fi, ex); + fi = fi->sibling; + } + + if (!camel_exception_is_set (ex)) { + if (camel_store_supports_subscriptions (store)) + camel_store_unsubscribe_folder (store, root->full_name, NULL); + + camel_store_delete_folder (store, root->full_name, ex); + + if (!camel_exception_is_set (ex)) + evolution_storage_removed_folder (storage, root->path); + } +} + +static void +storage_remove_folder (EvolutionStorage *storage, + const Bonobo_Listener listener, + const char *path, + const char *physical_uri, + gpointer user_data) +{ + CamelStore *store = user_data; + CamelFolderInfo *root, *fi; + CamelURL *url = NULL; + CamelException ex; + char *name; + + g_warning ("storage_remove_folder: path=\"%s\"; uri=\"%s\"", path, physical_uri); + + if (!path || !*path || !physical_uri || !strncmp (physical_uri, "vtrash:", 7) || !strncmp (physical_uri, "vjunk:", 6)) { + notify_listener (listener, GNOME_Evolution_Storage_INVALID_URI); + return; + } + + url = camel_url_new (physical_uri, NULL); + if (!url) { + notify_listener (listener, GNOME_Evolution_Storage_INVALID_URI); + return; + } + + if (url->fragment) + name = url->fragment; + else if (url->path && url->path[0]) + name = url->path+1; + else + name = ""; + + camel_exception_init (&ex); + + root = camel_store_get_folder_info (store, name, CAMEL_STORE_FOLDER_INFO_FAST | + CAMEL_STORE_FOLDER_INFO_RECURSIVE, &ex); + + if (!root || camel_exception_is_set (&ex)) { + notify_listener_exception (listener, &ex); + camel_exception_clear (&ex); + camel_url_free (url); + return; + } + + /* walk the tree until we find the particular child folder we want to delete */ + fi = root; + while (fi) { + if (!strcmp (fi->full_name, name)) + break; + fi = fi->child; + } + + camel_url_free (url); + + if (!fi) { + notify_listener (listener, GNOME_Evolution_Storage_INVALID_URI); + camel_store_free_folder_info (store, root); + return; + } + + storage_remove_folder_recursive (storage, store, fi, &ex); + camel_store_free_folder_info (store, root); + if (camel_exception_is_set (&ex)) { + notify_listener_exception (listener, &ex); + camel_exception_clear (&ex); + } else { + notify_listener (listener, GNOME_Evolution_Storage_OK); + } +} + +static void +storage_xfer_folder (EvolutionStorage *storage, + const Bonobo_Listener listener, + const char *source_path, + const char *destination_path, + gboolean remove_source, + CamelStore *store) +{ + CamelException ex; + char *src, *dst; + char sep; + + d(printf("Transfer folder on store source = '%s' dest = '%s'\n", source_path, destination_path)); + + /* FIXME: this is totally not gonna work once we have namespaces */ + + /* Remap the 'path' to the camel friendly name based on the store dir separator */ + sep = store->dir_sep; + src = g_strdup(source_path[0]=='/'?source_path+1:source_path); + dst = g_strdup(destination_path[0]=='/'?destination_path+1:destination_path); + camel_exception_init (&ex); + if (remove_source) { + d(printf("trying to rename\n")); + camel_store_rename_folder(store, src, dst, &ex); + notify_listener_exception(listener, &ex); + } else { + d(printf("No remove, can't rename\n")); + /* FIXME: Implement folder 'copy' for remote stores */ + /* This exception never goes anywhere, so it doesn't need translating or using */ + notify_listener (listener, GNOME_Evolution_Storage_UNSUPPORTED_OPERATION); + } + + g_free(src); + g_free(dst); + + camel_exception_clear (&ex); +} + +static void +storage_connected (CamelStore *store, CamelFolderInfo *info, void *listener) +{ + notify_listener (listener, (info ? GNOME_Evolution_Storage_OK : + GNOME_Evolution_Storage_GENERIC_ERROR)); +} + +static void +storage_connect (EvolutionStorage *storage, + const Bonobo_Listener listener, + const char *path, + CamelStore *store) +{ + mail_note_store (CAMEL_STORE (store), NULL, storage, CORBA_OBJECT_NIL, + storage_connected, listener); +} + +static void +add_storage (const char *name, const char *uri, CamelService *store, + GNOME_Evolution_Shell corba_shell, CamelException *ex) +{ + EvolutionStorage *storage; + EvolutionStorageResult res; + + storage = evolution_storage_new (name, FALSE); + g_signal_connect(storage, "open_folder", G_CALLBACK(storage_connect), store); + g_signal_connect(storage, "create_folder", G_CALLBACK(storage_create_folder), store); + g_signal_connect(storage, "remove_folder", G_CALLBACK(storage_remove_folder), store); + g_signal_connect(storage, "xfer_folder", G_CALLBACK(storage_xfer_folder), store); + + res = evolution_storage_register_on_shell (storage, corba_shell); + + switch (res) { + case EVOLUTION_STORAGE_OK: + evolution_storage_has_subfolders (storage, "/", _("Connecting...")); + mail_hash_storage (store, storage); + /*if (auto_connect)*/ + mail_note_store ((CamelStore *) store, NULL, storage, CORBA_OBJECT_NIL, NULL, NULL); + /* falllll */ + case EVOLUTION_STORAGE_ERROR_ALREADYREGISTERED: + case EVOLUTION_STORAGE_ERROR_EXISTS: + bonobo_object_unref (BONOBO_OBJECT (storage)); + return; + default: + camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot register storage with shell")); + break; + } +} + +void +mail_add_storage (CamelStore *store, const char *name, const char *uri) +{ + EvolutionShellClient *shell_client; + GNOME_Evolution_Shell shell; + CamelException ex; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + shell_client = evolution_shell_component_get_owner (shell_component); + shell = evolution_shell_client_corba_objref (shell_client); + + camel_exception_init (&ex); + + if (name == NULL) { + char *service_name; + + service_name = camel_service_get_name ((CamelService *) store, TRUE); + add_storage (service_name, uri, (CamelService *) store, shell, &ex); + g_free (service_name); + } else { + add_storage (name, uri, (CamelService *) store, shell, &ex); + } + + camel_exception_clear (&ex); +} + +void +mail_load_storage_by_uri (GNOME_Evolution_Shell shell, const char *uri, const char *name) +{ + CamelException ex; + CamelService *store; + CamelProvider *prov; + + camel_exception_init (&ex); + + /* Load the service (don't connect!). Check its provider and + * see if this belongs in the shell's folder list. If so, add + * it. + */ + + prov = camel_session_get_provider (session, uri, &ex); + if (prov == NULL) { + /* FIXME: real error dialog */ + g_warning ("couldn't get service %s: %s\n", uri, + camel_exception_get_description (&ex)); + camel_exception_clear (&ex); + return; + } + + if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE) || + (prov->flags & CAMEL_PROVIDER_IS_EXTERNAL)) + return; + + store = camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex); + if (store == NULL) { + /* FIXME: real error dialog */ + g_warning ("couldn't get service %s: %s\n", uri, + camel_exception_get_description (&ex)); + camel_exception_clear (&ex); + return; + } + + if (name == NULL) { + char *service_name; + + service_name = camel_service_get_name (store, TRUE); + add_storage (service_name, uri, store, shell, &ex); + g_free (service_name); + } else + add_storage (name, uri, store, shell, &ex); + + if (camel_exception_is_set (&ex)) { + /* FIXME: real error dialog */ + g_warning ("Cannot load storage: %s", + camel_exception_get_description (&ex)); + camel_exception_clear (&ex); + } + + camel_object_unref (CAMEL_OBJECT (store)); +} + +void +mail_load_storages (GNOME_Evolution_Shell shell, EAccountList *accounts) +{ + CamelException ex; + EIterator *iter; + + camel_exception_init (&ex); + + /* Load each service (don't connect!). Check its provider and + * see if this belongs in the shell's folder list. If so, add + * it. + */ + + iter = e_list_get_iterator ((EList *) accounts); + while (e_iterator_is_valid (iter)) { + EAccountService *service; + EAccount *account; + const char *name; + + account = (EAccount *) e_iterator_get (iter); + service = account->source; + name = account->name; + + if (account->enabled && service->url != NULL) + mail_load_storage_by_uri (shell, service->url, name); + + e_iterator_next (iter); + } + + g_object_unref (iter); +} + +void +mail_hash_storage (CamelService *store, EvolutionStorage *storage) +{ + camel_object_ref (CAMEL_OBJECT (store)); + g_hash_table_insert (storages_hash, store, storage); +} + +EvolutionStorage * +mail_lookup_storage (CamelStore *store) +{ + EvolutionStorage *storage; + + /* Because the storages_hash holds a reference to each store + * used as a key in it, none of them will ever be gc'ed, meaning + * any call to camel_session_get_{service,store} with the same + * URL will always return the same object. So this works. + */ + + storage = g_hash_table_lookup (storages_hash, store); + if (storage) + bonobo_object_ref (BONOBO_OBJECT (storage)); + + return storage; +} + +static void +store_disconnect(CamelStore *store, void *event_data, void *data) +{ + camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL); + camel_object_unref (CAMEL_OBJECT (store)); +} + +void +mail_remove_storage (CamelStore *store) +{ + EvolutionStorage *storage; + EvolutionShellClient *shell_client; + GNOME_Evolution_Shell corba_shell; + + /* Because the storages_hash holds a reference to each store + * used as a key in it, none of them will ever be gc'ed, meaning + * any call to camel_session_get_{service,store} with the same + * URL will always return the same object. So this works. + */ + + storage = g_hash_table_lookup (storages_hash, store); + if (!storage) + return; + + g_hash_table_remove (storages_hash, store); + + /* so i guess potentially we could have a race, add a store while one + being removed. ?? */ + mail_note_store_remove(store); + + shell_client = evolution_shell_component_get_owner (shell_component); + corba_shell = evolution_shell_client_corba_objref(shell_client); + + evolution_storage_deregister_on_shell (storage, corba_shell); + + mail_async_event_emit(async_event, MAIL_ASYNC_THREAD, (MailAsyncFunc)store_disconnect, store, NULL, NULL); +} + +void +mail_remove_storage_by_uri (const char *uri) +{ + CamelProvider *prov; + CamelService *store; + + prov = camel_session_get_provider (session, uri, NULL); + if (!prov) + return; + if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE) || + (prov->flags & CAMEL_PROVIDER_IS_EXTERNAL)) + return; + + store = camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, NULL); + if (store != NULL) { + mail_remove_storage (CAMEL_STORE (store)); + camel_object_unref (CAMEL_OBJECT (store)); + } +} + +int +mail_storages_count (void) +{ + return g_hash_table_size (storages_hash); +} + +void +mail_storages_foreach (GHFunc func, gpointer data) +{ + g_hash_table_foreach (storages_hash, func, data); +} + + +#define FACTORY_ID "OAFIID:GNOME_Evolution_Mail_ControlFactory" + +#define MAIL_CONFIG_IID "OAFIID:GNOME_Evolution_MailConfig" +#define WIZARD_IID "OAFIID:GNOME_Evolution_Mail_Wizard" +#define FOLDER_INFO_IID "OAFIID:GNOME_Evolution_FolderInfo" +#define COMPOSER_IID "OAFIID:GNOME_Evolution_Mail_Composer" + +static BonoboObject * +factory (BonoboGenericFactory *factory, + const char *component_id, + void *closure) +{ + if (strcmp (component_id, COMPONENT_ID) == 0) + return create_component(); + else if (strcmp(component_id, MAIL_CONFIG_IID) == 0) + return (BonoboObject *)g_object_new (evolution_mail_config_get_type (), NULL); + else if (strcmp(component_id, FOLDER_INFO_IID) == 0) + return evolution_folder_info_new(); + else if (strcmp(component_id, WIZARD_IID) == 0) + return evolution_mail_config_wizard_new(); + else if (strcmp (component_id, MAIL_ACCOUNTS_CONTROL_ID) == 0 + || strcmp (component_id, MAIL_PREFERENCES_CONTROL_ID) == 0 + || strcmp (component_id, MAIL_COMPOSER_PREFS_CONTROL_ID) == 0) + return mail_config_control_factory_cb (factory, component_id, evolution_shell_client_corba_objref (global_shell_client)); + else if (strcmp(component_id, COMPOSER_IID) == 0) + return (BonoboObject *)evolution_composer_new(em_utils_composer_send_cb, em_utils_composer_save_draft_cb); + + g_warning (FACTORY_ID ": Don't know what to do with %s", component_id); + return NULL; +} + +static Bonobo_Unknown +make_factory (PortableServer_POA poa, const char *iid, gpointer impl_ptr, CORBA_Environment *ev) +{ + static int init = 0; + + if (!init) { + /* init ? */ + mail_config_init (); + mail_msg_init (); + init = 1; + } + + return bonobo_shlib_factory_std (FACTORY_ID, poa, impl_ptr, factory, NULL, ev); +} + +static BonoboActivationPluginObject plugin_list[] = { + {FACTORY_ID, make_factory}, + { NULL } +}; +const BonoboActivationPlugin Bonobo_Plugin_info = { + plugin_list, "Evolution Mail component factory" +}; + |