diff options
author | Srinivasa Ragavan <sragavan@gnome.org> | 2012-03-02 18:10:34 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2012-03-03 22:02:34 +0800 |
commit | 18593a0fb99e04854f66459972b2c53fca601cda (patch) | |
tree | 3ab1b17fa1b079e1cecc9ff0055bde40f55e588c /mail | |
parent | f2ae5f830dc506e084731111008a8e90c093e97e (diff) | |
download | gsoc2013-evolution-18593a0fb99e04854f66459972b2c53fca601cda.tar.gz gsoc2013-evolution-18593a0fb99e04854f66459972b2c53fca601cda.tar.zst gsoc2013-evolution-18593a0fb99e04854f66459972b2c53fca601cda.zip |
Move vfolders to libemail-engine and rest as mail-vfolder-ui. It all works and
the daemon can now start the vfolder storage without bothering much with the
UI.
Diffstat (limited to 'mail')
-rw-r--r-- | mail/Makefile.am | 8 | ||||
-rw-r--r-- | mail/e-mail-account-store.c | 2 | ||||
-rw-r--r-- | mail/e-mail-backend.c | 18 | ||||
-rw-r--r-- | mail/e-mail-reader-utils.c | 2 | ||||
-rw-r--r-- | mail/e-mail-reader.c | 2 | ||||
-rw-r--r-- | mail/e-mail-ui-session.c | 78 | ||||
-rw-r--r-- | mail/e-mail-ui-session.h | 2 | ||||
-rw-r--r-- | mail/em-folder-properties.c | 2 | ||||
-rw-r--r-- | mail/em-folder-tree.c | 2 | ||||
-rw-r--r-- | mail/em-folder-utils.c | 2 | ||||
-rw-r--r-- | mail/mail-autofilter.c | 2 | ||||
-rw-r--r-- | mail/mail-vfolder-ui.c | 327 | ||||
-rw-r--r-- | mail/mail-vfolder-ui.h (renamed from mail/mail-vfolder.h) | 10 | ||||
-rw-r--r-- | mail/mail-vfolder.c | 1393 |
14 files changed, 368 insertions, 1482 deletions
diff --git a/mail/Makefile.am b/mail/Makefile.am index ebc3f6669f..b30c4d042a 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -92,7 +92,7 @@ mailinclude_HEADERS = \ mail-autofilter.h \ mail-guess-servers.h \ mail-send-recv.h \ - mail-vfolder.h \ + mail-vfolder-ui.h \ message-list.h if ENABLE_CLUTTER @@ -151,13 +151,13 @@ libevolution_mail_la_SOURCES = \ em-subscription-editor.c \ em-sync-stream.c \ em-utils.c \ - em-vfolder-editor-context.c \ - em-vfolder-editor-rule.c \ + em-vfolder-editor-context.c \ + em-vfolder-editor-rule.c \ em-vfolder-editor.c \ mail-autofilter.c \ mail-guess-servers.c \ mail-send-recv.c \ - mail-vfolder.c \ + mail-vfolder-ui.c \ message-list.c if ENABLE_CLUTTER diff --git a/mail/e-mail-account-store.c b/mail/e-mail-account-store.c index f22160cab8..2dac692d82 100644 --- a/mail/e-mail-account-store.c +++ b/mail/e-mail-account-store.c @@ -30,7 +30,7 @@ #include <libemail-utils/e-account-utils.h> #include <libemail-engine/mail-ops.h> -#include <mail/mail-vfolder.h> +#include <mail/mail-vfolder-ui.h> #define E_MAIL_ACCOUNT_STORE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ diff --git a/mail/e-mail-backend.c b/mail/e-mail-backend.c index 75866f3d3c..cc095a39af 100644 --- a/mail/e-mail-backend.c +++ b/mail/e-mail-backend.c @@ -55,7 +55,7 @@ #include <mail/em-utils.h> #include <mail/mail-autofilter.h> #include <mail/mail-send-recv.h> -#include <mail/mail-vfolder.h> +#include <mail/mail-vfolder-ui.h> #define E_MAIL_BACKEND_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -919,6 +919,19 @@ mail_mt_alert_error (GCancellable *cancellable, message, NULL); } +static EAlertSink * +mail_mt_get_alert_sink () +{ + EShell *shell; + EShellBackend *shell_backend; + + shell = e_shell_get_default (); + shell_backend = e_shell_get_backend_by_name ( + shell, "mail"); + + return e_mail_backend_get_alert_sink (E_MAIL_BACKEND(shell_backend)); +} + static void mail_backend_constructed (GObject *object) { @@ -1024,7 +1037,8 @@ mail_backend_constructed (GObject *object) mail_mt_free_activity, mail_mt_complete_acitivity, mail_mt_cancel_activity, - mail_mt_alert_error); + mail_mt_alert_error, + mail_mt_get_alert_sink); /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_backend_parent_class)->constructed (object); diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c index bba721eaf6..bc87295f60 100644 --- a/mail/e-mail-reader-utils.c +++ b/mail/e-mail-reader-utils.c @@ -48,7 +48,7 @@ #include "mail/em-format-html-print.h" #include "mail/em-utils.h" #include "mail/mail-autofilter.h" -#include "mail/mail-vfolder.h" +#include "mail/mail-vfolder-ui.h" #include "mail/message-list.h" typedef struct _AsyncContext AsyncContext; diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c index c7e2c077a8..53d4c31b84 100644 --- a/mail/e-mail-reader.c +++ b/mail/e-mail-reader.c @@ -57,7 +57,7 @@ #include "mail/em-folder-tree.h" #include "mail/em-utils.h" #include "mail/mail-autofilter.h" -#include "mail/mail-vfolder.h" +#include "mail/mail-vfolder-ui.h" #include "mail/message-list.h" #if HAVE_CLUTTER diff --git a/mail/e-mail-ui-session.c b/mail/e-mail-ui-session.c index 90c13492c9..fd9a4a94f2 100644 --- a/mail/e-mail-ui-session.c +++ b/mail/e-mail-ui-session.c @@ -65,6 +65,7 @@ #include "e-mail-ui-session.h" #include "em-composer-utils.h" #include "em-filter-context.h" +#include "em-vfolder-editor-context.h" #include "em-filter-rule.h" #include "em-utils.h" #include "libemail-engine/mail-config.h" @@ -81,7 +82,6 @@ typedef struct _SourceContext SourceContext; struct _EMailUISessionPrivate { FILE *filter_logfile; - CamelStore *vfolder_store; EMailAccountStore *account_store; EMailLabelListStore *label_store; @@ -92,8 +92,7 @@ struct _EMailUISessionPrivate { enum { PROP_0, PROP_ACCOUNT_STORE, - PROP_LABEL_STORE, - PROP_VFOLDER_STORE + PROP_LABEL_STORE }; enum { @@ -493,11 +492,6 @@ mail_ui_session_dispose (GObject *object) priv->label_store = NULL; } - if (priv->vfolder_store != NULL) { - g_object_unref (priv->vfolder_store); - priv->vfolder_store = NULL; - } - if (priv->account_list != NULL) { g_signal_handler_disconnect ( priv->account_list, @@ -511,38 +505,6 @@ mail_ui_session_dispose (GObject *object) } static void -mail_ui_session_add_vfolder_store (EMailUISession *uisession) -{ - CamelSession *camel_session; - CamelService *service; - GError *error = NULL; - - camel_session = CAMEL_SESSION (uisession); - - service = camel_session_add_service ( - camel_session, E_MAIL_SESSION_VFOLDER_UID, - "vfolder", CAMEL_PROVIDER_STORE, &error); - - if (error != NULL) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - return; - } - - g_return_if_fail (CAMEL_IS_SERVICE (service)); - - camel_service_set_display_name (service, _("Search Folders")); - em_utils_connect_service_sync (service, NULL, NULL); - - /* XXX There's more configuration to do in vfolder_load_storage() - * but it requires an EMailBackend, which we don't have access - * to from here, so it has to be called from elsewhere. Kinda - * thinking about reworking that... */ - - uisession->priv->vfolder_store = g_object_ref (service); -} - -static void mail_ui_session_account_changed_cb (EAccountList *account_list, EAccount *account, EMailSession *session) @@ -645,8 +607,6 @@ mail_ui_session_constructed (GObject *object) em_folder_tree_model_set_session (folder_tree_model, session); - mail_ui_session_add_vfolder_store (uisession); - g_idle_add (mail_ui_session_initialize_stores_idle, object); handler_id = g_signal_connect ( @@ -736,13 +696,6 @@ mail_ui_session_get_property (GObject *object, e_mail_ui_session_get_label_store ( E_MAIL_UI_SESSION (object))); return; - - case PROP_VFOLDER_STORE: - g_value_set_object ( - value, - e_mail_ui_session_get_vfolder_store ( - E_MAIL_UI_SESSION (object))); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -791,11 +744,18 @@ mail_ui_session_add_service (CamelSession *session, return service; } +static EMVFolderContext * +mail_ui_session_create_vfolder_context (EMailSession *session) +{ + return (EMVFolderContext *) em_vfolder_editor_context_new (session); +} + static void e_mail_ui_session_class_init (EMailUISessionClass *class) { GObjectClass *object_class; CamelSessionClass *session_class; + EMailSessionClass *emailsession_class; g_type_class_add_private (class, sizeof (EMailUISessionPrivate)); @@ -810,16 +770,8 @@ e_mail_ui_session_class_init (EMailUISessionClass *class) session_class->get_filter_driver = mail_ui_session_get_filter_driver; session_class->add_service = mail_ui_session_add_service; - g_object_class_install_property ( - object_class, - PROP_VFOLDER_STORE, - g_param_spec_object ( - "vfolder-store", - "Search Folder Store", - "Built-in search folder store", - CAMEL_TYPE_STORE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + emailsession_class = E_MAIL_SESSION_CLASS (class); + emailsession_class->create_vfolder_context = mail_ui_session_create_vfolder_context; g_object_class_install_property ( object_class, @@ -874,14 +826,6 @@ e_mail_ui_session_get_account_store (EMailUISession *session) return session->priv->account_store; } -CamelStore * -e_mail_ui_session_get_vfolder_store (EMailUISession *session) -{ - g_return_val_if_fail (E_IS_MAIL_UI_SESSION (session), NULL); - - return session->priv->vfolder_store; -} - void e_mail_ui_session_add_activity (EMailUISession *session, EActivity *activity) diff --git a/mail/e-mail-ui-session.h b/mail/e-mail-ui-session.h index 1a36487757..f6ef4b42d5 100644 --- a/mail/e-mail-ui-session.h +++ b/mail/e-mail-ui-session.h @@ -77,8 +77,6 @@ struct _EMailUISessionClass { GType e_mail_ui_session_get_type (void); EMailSession * e_mail_ui_session_new (void); -CamelStore * e_mail_ui_session_get_vfolder_store - (EMailUISession *session); EMailAccountStore * e_mail_ui_session_get_account_store (EMailUISession *session); diff --git a/mail/em-folder-properties.c b/mail/em-folder-properties.c index 08ed28df59..d6ab5acfcb 100644 --- a/mail/em-folder-properties.c +++ b/mail/em-folder-properties.c @@ -38,7 +38,7 @@ #include "e-mail-backend.h" #include "e-mail-ui-session.h" #include "em-config.h" -#include "mail-vfolder.h" +#include "mail-vfolder-ui.h" typedef struct _AsyncContext AsyncContext; diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index d8234f9498..2d1e28ea58 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -61,7 +61,7 @@ #include "em-folder-properties.h" #include "em-event.h" #include "mail-send-recv.h" -#include "mail-vfolder.h" +#include "mail-vfolder-ui.h" #include "e-mail-ui-session.h" diff --git a/mail/em-folder-utils.c b/mail/em-folder-utils.c index cbf458a799..5d8c258626 100644 --- a/mail/em-folder-utils.c +++ b/mail/em-folder-utils.c @@ -62,7 +62,7 @@ #include "em-folder-utils.h" #include "em-folder-selector.h" #include "em-folder-properties.h" -#include "mail-vfolder.h" +#include "mail-vfolder-ui.h" #define d(x) diff --git a/mail/mail-autofilter.c b/mail/mail-autofilter.c index 4db48df056..f0876a4bdc 100644 --- a/mail/mail-autofilter.c +++ b/mail/mail-autofilter.c @@ -32,7 +32,7 @@ #include <libemail-engine/e-mail-folder-utils.h> #include <libemail-engine/e-mail-session.h> -#include "mail-vfolder.h" +#include "mail-vfolder-ui.h" #include "mail-autofilter.h" #include "em-utils.h" #include "libevolution-utils/e-alert-dialog.h" diff --git a/mail/mail-vfolder-ui.c b/mail/mail-vfolder-ui.c new file mode 100644 index 0000000000..14b55d1d8f --- /dev/null +++ b/mail/mail-vfolder-ui.c @@ -0,0 +1,327 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Michael Zucchi <notzed@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> + +#include <glib/gi18n.h> + +#include "libevolution-utils/e-alert-dialog.h" +#include "e-util/e-util-private.h" + +#include "libemail-utils/mail-mt.h" +#include "libemail-engine/mail-folder-cache.h" +#include "libemail-engine/e-mail-folder-utils.h" +#include "libemail-engine/e-mail-session.h" +#include "libemail-engine/e-mail-utils.h" +#include "libemail-engine/mail-ops.h" +#include "libemail-engine/mail-tools.h" + +#include "e-mail-backend.h" +#include "em-folder-tree-model.h" +#include "em-utils.h" +#include "em-vfolder-editor-context.h" +#include "em-vfolder-editor.h" +#include "em-vfolder-editor-rule.h" +#include "mail-autofilter.h" +#include "mail-vfolder-ui.h" +#include "e-mail-ui-session.h" + +#define d(x) /* (printf("%s:%s: ", G_STRLOC, G_STRFUNC), (x))*/ + +/* NOTE: Once mail is moved to EDS, this context needs to be created ofr Mail UI. */ +extern EMVFolderContext *context; /* context remains open all time */ + +void +vfolder_edit (EMailBackend *backend, + GtkWindow *parent_window) +{ + EShellBackend *shell_backend; + GtkWidget *dialog; + const gchar *config_dir; + gchar *filename; + EMailSession *session; + + g_return_if_fail (E_IS_MAIL_BACKEND (backend)); + g_return_if_fail (GTK_IS_WINDOW (parent_window)); + + shell_backend = E_SHELL_BACKEND (backend); + config_dir = e_shell_backend_get_config_dir (shell_backend); + filename = g_build_filename (config_dir, "vfolders.xml", NULL); + session = e_mail_backend_get_session (backend); + + vfolder_load_storage (session); + + dialog = em_vfolder_editor_new (context); + gtk_window_set_title ( + GTK_WINDOW (dialog), _("Search Folders")); + gtk_window_set_transient_for ( + GTK_WINDOW (dialog), parent_window); + + switch (gtk_dialog_run (GTK_DIALOG (dialog))) { + case GTK_RESPONSE_OK: + e_rule_context_save ((ERuleContext *) context, filename); + break; + default: + e_rule_context_revert ((ERuleContext *) context, filename); + break; + } + + gtk_widget_destroy (dialog); +} + +static void +vfolder_edit_response_cb (GtkWidget *dialog, + gint response_id, + gpointer user_data) +{ + if (response_id == GTK_RESPONSE_OK) { + GObject *object; + EFilterRule *rule; + EFilterRule *newrule; + const gchar *config_dir; + gchar *user; + + object = G_OBJECT (dialog); + rule = g_object_get_data (object, "vfolder-rule"); + newrule = g_object_get_data (object, "vfolder-newrule"); + + e_filter_rule_copy (rule, newrule); + config_dir = mail_session_get_config_dir (); + user = g_build_filename (config_dir, "vfolders.xml", NULL); + e_rule_context_save ((ERuleContext *) context, user); + g_free (user); + } + + gtk_widget_destroy (dialog); +} + +void +vfolder_edit_rule (EMailSession *session, + const gchar *folder_uri, + EAlertSink *alert_sink) +{ + GtkWidget *dialog; + GtkWidget *widget; + GtkWidget *container; + EFilterRule *rule = NULL; + EFilterRule *newrule; + gchar *folder_name = NULL; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (folder_uri != NULL); + g_return_if_fail (E_IS_ALERT_SINK (alert_sink)); + + e_mail_folder_uri_parse ( + CAMEL_SESSION (session), folder_uri, + NULL, &folder_name, NULL); + + if (folder_name != NULL) { + rule = e_rule_context_find_rule ( + (ERuleContext *) context, folder_name, NULL); + g_free (folder_name); + } + + if (rule == NULL) { + /* TODO: we should probably just create it ... */ + e_alert_submit ( + alert_sink, "mail:vfolder-notexist", + folder_uri, NULL); + return; + } + + g_object_ref (rule); + newrule = e_filter_rule_clone (rule); + + dialog = gtk_dialog_new_with_buttons ( + _("Edit Search Folder"), NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + + gtk_container_set_border_width (GTK_CONTAINER (dialog), 6); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + + gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 500); + gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE); + + container = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + gtk_box_set_spacing (GTK_BOX (container), 6); + + widget = e_filter_rule_get_widget ( + (EFilterRule *) newrule, (ERuleContext *) context); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + g_object_set_data_full ( + G_OBJECT (dialog), "vfolder-rule", + rule, (GDestroyNotify) g_object_unref); + g_object_set_data_full ( + G_OBJECT (dialog), "vfolder-newrule", + newrule, (GDestroyNotify) g_object_unref); + + g_signal_connect ( + dialog, "response", + G_CALLBACK (vfolder_edit_response_cb), NULL); + + gtk_widget_show (dialog); +} + +static void +new_rule_clicked (GtkWidget *w, + gint button, + gpointer data) +{ + if (button == GTK_RESPONSE_OK) { + const gchar *config_dir; + gchar *user; + EFilterRule *rule = g_object_get_data((GObject *)w, "rule"); + EAlert *alert = NULL; + + if (!e_filter_rule_validate (rule, &alert)) { + e_alert_run_dialog (GTK_WINDOW (w), alert); + g_object_unref (alert); + return; + } + + if (e_rule_context_find_rule ( + (ERuleContext *) context, rule->name, rule->source)) { + e_alert_run_dialog_for_args ( + GTK_WINDOW (w), "mail:vfolder-notunique", + rule->name, NULL); + return; + } + + g_object_ref (rule); + e_rule_context_add_rule ((ERuleContext *) context, rule); + config_dir = mail_session_get_config_dir (); + user = g_build_filename (config_dir, "vfolders.xml", NULL); + e_rule_context_save ((ERuleContext *) context, user); + g_free (user); + } + + gtk_widget_destroy (w); +} + +static void +new_rule_changed_cb (EFilterRule *rule, + GtkDialog *dialog) +{ + g_return_if_fail (rule != NULL); + g_return_if_fail (dialog != NULL); + + gtk_dialog_set_response_sensitive ( + dialog, GTK_RESPONSE_OK, rule->parts != NULL); +} + +/* clones a filter/search rule into a matching vfolder rule + * (assuming the same system definitions) */ +EFilterRule * +vfolder_clone_rule (EMailSession *session, + EFilterRule *in) +{ + EFilterRule *rule; + xmlNodePtr xml; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + rule = em_vfolder_editor_rule_new (session); + + xml = e_filter_rule_xml_encode (in); + e_filter_rule_xml_decode (rule, xml, (ERuleContext *) context); + xmlFreeNodeList (xml); + + return rule; +} + +/* adds a rule with a gui */ +void +vfolder_gui_add_rule (EMVFolderRule *rule) +{ + GtkWidget *w; + GtkDialog *gd; + GtkWidget *container; + + w = e_filter_rule_get_widget ((EFilterRule *) rule, (ERuleContext *) context); + + gd = (GtkDialog *) gtk_dialog_new_with_buttons ( + _("New Search Folder"), + NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); + + gtk_dialog_set_default_response (gd, GTK_RESPONSE_OK); + gtk_container_set_border_width (GTK_CONTAINER (gd), 6); + + container = gtk_dialog_get_content_area (gd); + gtk_box_set_spacing (GTK_BOX (container), 6); + + g_object_set (gd, "resizable", TRUE, NULL); + gtk_window_set_default_size (GTK_WINDOW (gd), 500, 500); + gtk_box_pack_start (GTK_BOX (container), w, TRUE, TRUE, 0); + gtk_widget_show ((GtkWidget *) gd); + g_object_set_data_full ( + G_OBJECT (gd), "rule", rule, + (GDestroyNotify) g_object_unref); + g_signal_connect ( + rule, "changed", + G_CALLBACK (new_rule_changed_cb), gd); + new_rule_changed_cb ((EFilterRule *) rule, gd); + g_signal_connect ( + gd, "response", + G_CALLBACK (new_rule_clicked), NULL); + gtk_widget_show ((GtkWidget *) gd); +} + +void +vfolder_gui_add_from_message (EMailSession *session, + CamelMimeMessage *message, + gint flags, + CamelFolder *folder) +{ + EMVFolderRule *rule; + + g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); + + rule = (EMVFolderRule *) em_vfolder_rule_from_message ( + context, message, flags, folder); + vfolder_gui_add_rule (rule); +} + +void +vfolder_gui_add_from_address (EMailSession *session, + CamelInternetAddress *addr, + gint flags, + CamelFolder *folder) +{ + EMVFolderRule *rule; + + g_return_if_fail (addr != NULL); + + rule = (EMVFolderRule *) em_vfolder_rule_from_address ( + context, addr, flags, folder); + vfolder_gui_add_rule (rule); +} diff --git a/mail/mail-vfolder.h b/mail/mail-vfolder-ui.h index fc03e881d9..55b838c63b 100644 --- a/mail/mail-vfolder.h +++ b/mail/mail-vfolder-ui.h @@ -19,8 +19,8 @@ * */ -#ifndef _MAIL_VFOLDER_H -#define _MAIL_VFOLDER_H +#ifndef _MAIL_VFOLDER_UI_H +#define _MAIL_VFOLDER_UI_H #include <camel/camel.h> @@ -29,8 +29,8 @@ #include <mail/e-mail-backend.h> #include <libemail-utils/em-vfolder-rule.h> #include <shell/e-shell-view.h> +#include <libemail-engine/mail-vfolder.h> -void vfolder_load_storage (EMailBackend *backend); void vfolder_edit (EMailBackend *backend, GtkWindow *parent_window); void vfolder_edit_rule (EMailSession *session, @@ -47,8 +47,4 @@ void vfolder_gui_add_from_address (EMailSession *session, CamelInternetAddress *addr, gint flags, CamelFolder *folder); - -/* close up, clean up */ -void mail_vfolder_shutdown (void); - #endif diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c deleted file mode 100644 index 1435c39ae5..0000000000 --- a/mail/mail-vfolder.c +++ /dev/null @@ -1,1393 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> - -#include <glib/gi18n.h> - -#include "libevolution-utils/e-alert-dialog.h" -#include "e-util/e-util-private.h" - -#include "libemail-utils/mail-mt.h" -#include "libemail-engine/mail-folder-cache.h" -#include "libemail-engine/e-mail-folder-utils.h" -#include "libemail-engine/e-mail-session.h" -#include "libemail-engine/e-mail-utils.h" -#include "libemail-engine/mail-ops.h" -#include "libemail-engine/mail-tools.h" - -#include "e-mail-backend.h" -#include "em-folder-tree-model.h" -#include "em-utils.h" -#include "em-vfolder-editor-context.h" -#include "em-vfolder-editor.h" -#include "em-vfolder-editor-rule.h" -#include "mail-autofilter.h" -#include "mail-vfolder.h" -#include "e-mail-ui-session.h" - -#define d(x) /* (printf("%s:%s: ", G_STRLOC, G_STRFUNC), (x))*/ - -static EMVFolderContext *context; /* context remains open all time */ - -/* lock for accessing shared resources (below) */ -G_LOCK_DEFINE_STATIC (vfolder); - -static GHashTable *vfolder_hash; -/* This is a slightly hacky solution to shutting down, we poll this variable in various - * loops, and just quit processing if it is set. */ -static volatile gint vfolder_shutdown; /* are we shutting down? */ - -static void rule_changed (EFilterRule *rule, CamelFolder *folder); - -/* ********************************************************************** */ - -struct _setup_msg { - MailMsg base; - - EMailSession *session; - CamelFolder *folder; - gchar *query; - GList *sources_uri; - GList *sources_folder; -}; - -static gchar * -vfolder_setup_desc (struct _setup_msg *m) -{ - return g_strdup_printf ( - _("Setting up Search Folder: %s"), - camel_folder_get_full_name (m->folder)); -} - -static void -vfolder_setup_exec (struct _setup_msg *m, - GCancellable *cancellable, - GError **error) -{ - GList *l, *list = NULL; - CamelFolder *folder; - - camel_vee_folder_set_expression ((CamelVeeFolder *) m->folder, m->query); - - l = m->sources_uri; - while (l && !vfolder_shutdown) { - d(printf(" Adding uri: %s\n", (gchar *)l->data)); - - /* FIXME Not passing a GCancellable or GError here. */ - folder = e_mail_session_uri_to_folder_sync ( - m->session, l->data, 0, NULL, NULL); - if (folder != NULL) - list = g_list_append (list, folder); - l = l->next; - } - - l = m->sources_folder; - while (l && !vfolder_shutdown) { - g_object_ref (l->data); - list = g_list_append (list, l->data); - l = l->next; - } - - if (!vfolder_shutdown) - camel_vee_folder_set_folders ((CamelVeeFolder *) m->folder, list); - - l = list; - while (l) { - g_object_unref (l->data); - l = l->next; - } - g_list_free (list); -} - -static void -vfolder_setup_done (struct _setup_msg *m) -{ -} - -static void -vfolder_setup_free (struct _setup_msg *m) -{ - GList *l; - - g_object_unref (m->session); - g_object_unref (m->folder); - g_free (m->query); - - l = m->sources_uri; - while (l) { - g_free (l->data); - l = l->next; - } - g_list_free (m->sources_uri); - - l = m->sources_folder; - while (l) { - g_object_unref (l->data); - l = l->next; - } - g_list_free (m->sources_folder); -} - -static MailMsgInfo vfolder_setup_info = { - sizeof (struct _setup_msg), - (MailMsgDescFunc) vfolder_setup_desc, - (MailMsgExecFunc) vfolder_setup_exec, - (MailMsgDoneFunc) vfolder_setup_done, - (MailMsgFreeFunc) vfolder_setup_free -}; - -/* sources_uri should be camel uri's */ -static gint -vfolder_setup (EMailSession *session, - CamelFolder *folder, - const gchar *query, - GList *sources_uri, - GList *sources_folder) -{ - struct _setup_msg *m; - gint id; - - m = mail_msg_new (&vfolder_setup_info); - m->session = g_object_ref (session); - m->folder = g_object_ref (folder); - m->query = g_strdup (query); - m->sources_uri = sources_uri; - m->sources_folder = sources_folder; - - id = m->base.seq; - mail_msg_slow_ordered_push (m); - - return id; -} - -/* ********************************************************************** */ - -struct _adduri_msg { - MailMsg base; - - EMailSession *session; - gchar *uri; - GList *folders; - gint remove; -}; - -static gchar * -vfolder_adduri_desc (struct _adduri_msg *m) -{ - CamelStore *store; - CamelService *service; - const gchar *display_name; - gchar *folder_name; - gchar *description; - gboolean success; - - success = e_mail_folder_uri_parse ( - CAMEL_SESSION (m->session), m->uri, - &store, &folder_name, NULL); - - if (!success) - return NULL; - - service = CAMEL_SERVICE (store); - display_name = camel_service_get_display_name (service); - - description = g_strdup_printf ( - _("Updating Search Folders for '%s' - %s"), - display_name, folder_name); - - g_object_unref (store); - g_free (folder_name); - - return description; -} - -static void -vfolder_adduri_exec (struct _adduri_msg *m, - GCancellable *cancellable, - GError **error) -{ - GList *l; - CamelFolder *folder = NULL; - MailFolderCache *folder_cache; - - if (vfolder_shutdown) - return; - - folder_cache = e_mail_session_get_folder_cache (m->session); - - /* we dont try lookup the cache if we are removing it, its no longer there */ - - if (!m->remove && - !mail_folder_cache_get_folder_from_uri (folder_cache, m->uri, NULL)) { - g_warning ( - "Folder '%s' disappeared while I was " - "adding/removing it to/from my vfolder", m->uri); - return; - } - - /* always pick fresh folders - they are - * from CamelStore's folders bag anyway */ - folder = e_mail_session_uri_to_folder_sync ( - m->session, m->uri, 0, cancellable, error); - - if (folder != NULL) { - l = m->folders; - while (l && !vfolder_shutdown) { - if (m->remove) - camel_vee_folder_remove_folder ( - CAMEL_VEE_FOLDER (l->data), folder); - else - camel_vee_folder_add_folder ((CamelVeeFolder *) l->data, folder); - l = l->next; - } - g_object_unref (folder); - } -} - -static void -vfolder_adduri_done (struct _adduri_msg *m) -{ -} - -static void -vfolder_adduri_free (struct _adduri_msg *m) -{ - g_object_unref (m->session); - g_list_foreach (m->folders, (GFunc) g_object_unref, NULL); - g_list_free (m->folders); - g_free (m->uri); -} - -static MailMsgInfo vfolder_adduri_info = { - sizeof (struct _adduri_msg), - (MailMsgDescFunc) vfolder_adduri_desc, - (MailMsgExecFunc) vfolder_adduri_exec, - (MailMsgDoneFunc) vfolder_adduri_done, - (MailMsgFreeFunc) vfolder_adduri_free -}; - -/* uri should be a camel uri */ -static gint -vfolder_adduri (EMailSession *session, - const gchar *uri, - GList *folders, - gint remove) -{ - struct _adduri_msg *m; - gint id; - - m = mail_msg_new (&vfolder_adduri_info); - m->session = g_object_ref (session); - m->folders = folders; - m->uri = g_strdup (uri); - m->remove = remove; - - id = m->base.seq; - mail_msg_slow_ordered_push (m); - - return id; -} - -/* ********************************************************************** */ - -/* so special we never use it */ -static gint -folder_is_spethal (CamelStore *store, - const gchar *folder_name) -{ - /* This is a bit of a hack, but really the only way it can be done - * at the moment. */ - - if (store->flags & CAMEL_STORE_VTRASH) - if (g_strcmp0 (folder_name, CAMEL_VTRASH_NAME) == 0) - return TRUE; - - if (store->flags & CAMEL_STORE_VJUNK) - if (g_strcmp0 (folder_name, CAMEL_VJUNK_NAME) == 0) - return TRUE; - - return FALSE; -} - -/** - * mail_vfolder_add_folder: - * @store: a #CamelStore - * @folder: a folder name - * @remove: whether the folder should be removed or added - * - * Called when a new folder becomes (un)available. If @store is not a - * CamelVeeStore, the folder is added/removed from the list of cached source - * folders. Then each vfolder rule is checked to see if the specified folder - * matches a source of the rule. It builds a list of vfolders that use (or - * would use) the specified folder as a source. It then adds (or removes) - * this folder to (from) those vfolders via camel_vee_folder_add/ - * remove_folder() but does not modify the actual filters or write changes - * to disk. - * - * NOTE: This function must be called from the main thread. - */ -static void -mail_vfolder_add_folder (CamelStore *store, - const gchar *folder_name, - gint remove) -{ - CamelService *service; - CamelSession *session; - EFilterRule *rule; - const gchar *source; - CamelVeeFolder *vf; - CamelProvider *provider; - GList *folders = NULL; - gint remote; - gchar *uri; - - g_return_if_fail (CAMEL_IS_STORE (store)); - g_return_if_fail (folder_name != NULL); - - service = CAMEL_SERVICE (store); - session = camel_service_get_session (service); - provider = camel_service_get_provider (service); - - remote = (provider->flags & CAMEL_PROVIDER_IS_REMOTE) != 0; - - if (folder_is_spethal (store, folder_name)) - return; - - g_return_if_fail (mail_in_main_thread ()); - - uri = e_mail_folder_uri_build (store, folder_name); - - G_LOCK (vfolder); - - if (context == NULL) - goto done; - - rule = NULL; - while ((rule = e_rule_context_next_rule ((ERuleContext *) context, rule, NULL))) { - gint found = FALSE; - - if (!rule->name) { - d(printf("invalid rule (%p): rule->name is set to NULL\n", rule)); - continue; - } - /* Don't auto-add any sent/drafts folders etc, - * they must be explictly listed as a source. */ - if (rule->source - && !CAMEL_IS_VEE_STORE (store) - && ((((EMVFolderRule *) rule)->with == - EM_VFOLDER_RULE_WITH_LOCAL && !remote) - || (((EMVFolderRule *) rule)->with == - EM_VFOLDER_RULE_WITH_REMOTE_ACTIVE && remote) - || (((EMVFolderRule *) rule)->with == - EM_VFOLDER_RULE_WITH_LOCAL_REMOTE_ACTIVE))) - found = TRUE; - - source = NULL; - while (!found && (source = em_vfolder_rule_next_source ( - (EMVFolderRule *) rule, source))) { - found = e_mail_folder_uri_equal (session, uri, source); - } - - if (found) { - vf = g_hash_table_lookup (vfolder_hash, rule->name); - if (!vf) { - g_warning ("vf is NULL for %s\n", rule->name); - continue; - } - g_object_ref (vf); - folders = g_list_prepend (folders, vf); - } - } - -done: - G_UNLOCK (vfolder); - - if (folders != NULL) - vfolder_adduri ( - E_MAIL_SESSION (session), - uri, folders, remove); - - g_free (uri); -} - -/** - * mail_vfolder_delete_folder: - * @backend: an #EMailBackend - * @store: a #CamelStore - * @folder_name: a folder name - * - * Looks through all vfolder rules to see if @folder_name is listed as a - * source for any vfolder rules. If the folder is found in the source for - * any rule, it is removed and the user is alerted to the fact that the - * vfolder rules have been updated. The new vfolder rules are written - * to disk. - * - * XXX: It doesn't appear that the changes to the vfolder rules are sent - * down to the camel level, however. So the actual vfolders will not change - * behavior until evolution is restarted (?) - * - * NOTE: This function must be called from the main thread. - */ -static void -mail_vfolder_delete_folder (EMailBackend *backend, - CamelStore *store, - const gchar *folder_name) -{ - ERuleContext *rule_context; - EFilterRule *rule; - CamelService *service; - CamelSession *session; - const gchar *source; - CamelVeeFolder *vf; - GString *changed; - guint changed_count; - gchar *uri; - - g_return_if_fail (E_IS_MAIL_BACKEND (backend)); - g_return_if_fail (CAMEL_IS_STORE (store)); - g_return_if_fail (folder_name != NULL); - - if (folder_is_spethal (store, folder_name)) - return; - - d(printf ("Deleting uri to check: %s\n", uri)); - - g_return_if_fail (mail_in_main_thread ()); - - service = CAMEL_SERVICE (store); - session = camel_service_get_session (service); - - uri = e_mail_folder_uri_build (store, folder_name); - - changed_count = 0; - changed = g_string_new (""); - - G_LOCK (vfolder); - - if (context == NULL) - goto done; - - rule_context = E_RULE_CONTEXT (context); - - /* see if any rules directly reference this removed uri */ - rule = NULL; - while ((rule = e_rule_context_next_rule (rule_context, rule, NULL))) { - EMVFolderRule *vf_rule = EM_VFOLDER_RULE (rule); - - if (!rule->name) - continue; - - source = NULL; - while ((source = em_vfolder_rule_next_source (vf_rule, source))) { - /* Remove all sources that match, ignore changed events though - * because the adduri call above does the work async */ - if (e_mail_folder_uri_equal (session, uri, source)) { - vf = g_hash_table_lookup ( - vfolder_hash, rule->name); - - if (!vf) { - g_warning ("vf is NULL for %s\n", rule->name); - continue; - } - - g_signal_handlers_disconnect_matched ( - rule, G_SIGNAL_MATCH_FUNC | - G_SIGNAL_MATCH_DATA, 0, 0, NULL, - rule_changed, vf); - - em_vfolder_rule_remove_source (vf_rule, source); - - g_signal_connect ( - rule, "changed", - G_CALLBACK (rule_changed), vf); - - if (changed_count == 0) { - g_string_append (changed, rule->name); - } else { - if (changed_count == 1) { - g_string_prepend (changed, " "); - g_string_append (changed, "\n"); - } - g_string_append_printf ( - changed, " %s\n", - rule->name); - } - - changed_count++; - source = NULL; - } - } - } - -done: - G_UNLOCK (vfolder); - - if (changed_count > 0) { - EAlertSink *alert_sink; - const gchar *config_dir; - gchar *user, *info; - - alert_sink = e_mail_backend_get_alert_sink (backend); - - info = g_strdup_printf (ngettext ( - /* Translators: The first %s is name of the affected - * search folder(s), the second %s is the URI of the - * removed folder. For more than one search folder is - * each of them on a separate line, with four spaces - * in front of its name, without quotes. */ - "The Search Folder \"%s\" has been modified to " - "account for the deleted folder\n\"%s\".", - "The following Search Folders\n%s have been modified " - "to account for the deleted folder\n\"%s\".", - changed_count), changed->str, uri); - e_alert_submit ( - alert_sink, "mail:vfolder-updated", info, NULL); - g_free (info); - - config_dir = mail_session_get_config_dir (); - user = g_build_filename (config_dir, "vfolders.xml", NULL); - e_rule_context_save ((ERuleContext *) context, user); - g_free (user); - } - - g_string_free (changed, TRUE); - - g_free (uri); -} - -/* called when a uri is renamed in a store */ -static void -mail_vfolder_rename_folder (CamelStore *store, - const gchar *old_folder_name, - const gchar *new_folder_name) -{ - ERuleContext *rule_context; - EFilterRule *rule; - const gchar *source; - CamelVeeFolder *vf; - CamelService *service; - CamelSession *session; - gint changed = 0; - gchar *old_uri; - gchar *new_uri; - - d(printf("vfolder rename uri: %s to %s\n", cfrom, cto)); - - if (context == NULL) - return; - - if (folder_is_spethal (store, old_folder_name)) - return; - - if (folder_is_spethal (store, new_folder_name)) - return; - - g_return_if_fail (mail_in_main_thread ()); - - service = CAMEL_SERVICE (store); - session = camel_service_get_session (service); - - old_uri = e_mail_folder_uri_build (store, old_folder_name); - new_uri = e_mail_folder_uri_build (store, new_folder_name); - - G_LOCK (vfolder); - - rule_context = E_RULE_CONTEXT (context); - - /* see if any rules directly reference this removed uri */ - rule = NULL; - while ((rule = e_rule_context_next_rule (rule_context, rule, NULL))) { - EMVFolderRule *vf_rule = EM_VFOLDER_RULE (rule); - - source = NULL; - while ((source = em_vfolder_rule_next_source (vf_rule, source))) { - /* Remove all sources that match, ignore changed events though - * because the adduri call above does the work async */ - if (e_mail_folder_uri_equal (session, old_uri, source)) { - vf = g_hash_table_lookup (vfolder_hash, rule->name); - if (!vf) { - g_warning ("vf is NULL for %s\n", rule->name); - continue; - } - - g_signal_handlers_disconnect_matched ( - rule, G_SIGNAL_MATCH_FUNC | - G_SIGNAL_MATCH_DATA, 0, 0, NULL, - rule_changed, vf); - - em_vfolder_rule_remove_source (vf_rule, source); - em_vfolder_rule_add_source (vf_rule, new_uri); - - g_signal_connect ( - vf_rule, "changed", - G_CALLBACK (rule_changed), vf); - - changed++; - source = NULL; - } - } - } - - G_UNLOCK (vfolder); - - if (changed) { - const gchar *config_dir; - gchar *user; - - d(printf("Vfolders updated from renamed folder\n")); - config_dir = mail_session_get_config_dir (); - user = g_build_filename (config_dir, "vfolders.xml", NULL); - e_rule_context_save ((ERuleContext *) context, user); - g_free (user); - } - - g_free (old_uri); - g_free (new_uri); -} - -/* ********************************************************************** */ - -static void context_rule_added (ERuleContext *ctx, EFilterRule *rule); - -static void -rule_add_sources (EMailSession *session, - GQueue *queue, - GList **sources_folderp, - GList **sources_urip) -{ - GList *sources_folder = *sources_folderp; - GList *sources_uri = *sources_urip; - MailFolderCache *folder_cache; - GList *head, *link; - - folder_cache = e_mail_session_get_folder_cache (session); - - head = g_queue_peek_head_link (queue); - for (link = head; link != NULL; link = g_list_next (link)) { - const gchar *uri = link->data; - - /* always pick fresh folders - they are - * from CamelStore's folders bag anyway */ - if (mail_folder_cache_get_folder_from_uri (folder_cache, uri, NULL)) { - sources_uri = g_list_append (sources_uri, g_strdup (uri)); - } - } - - *sources_folderp = sources_folder; - *sources_urip = sources_uri; -} - -static void -rule_changed (EFilterRule *rule, - CamelFolder *folder) -{ - EMailSession *session; - CamelService *service; - GList *sources_uri = NULL; - GList *sources_folder = NULL; - GString *query; - const gchar *full_name; - - full_name = camel_folder_get_full_name (folder); - session = em_vfolder_editor_rule_get_session (EM_VFOLDER_EDITOR_RULE (rule)); - - service = camel_session_get_service ( - CAMEL_SESSION (session), E_MAIL_SESSION_VFOLDER_UID); - g_return_if_fail (CAMEL_IS_SERVICE (service)); - - /* If the folder has changed name, then - * add it, then remove the old manually. */ - if (strcmp (full_name, rule->name) != 0) { - gchar *oldname; - - gpointer key; - gpointer oldfolder; - - G_LOCK (vfolder); - if (g_hash_table_lookup_extended ( - vfolder_hash, full_name, &key, &oldfolder)) { - g_hash_table_remove (vfolder_hash, key); - g_free (key); - g_hash_table_insert ( - vfolder_hash, g_strdup (rule->name), folder); - G_UNLOCK (vfolder); - } else { - G_UNLOCK (vfolder); - g_warning ( - "couldn't find a vfolder rule " - "in our table? %s", full_name); - } - - oldname = g_strdup (full_name); - /* FIXME Not passing a GCancellable or GError. */ - camel_store_rename_folder_sync ( - CAMEL_STORE (service), - oldname, rule->name, NULL, NULL); - g_free (oldname); - } - - d(printf("Filter rule changed? for folder '%s'!!\n", folder->name)); - - /* find any (currently available) folders, and add them to the ones to open */ - rule_add_sources ( - session, &((EMVFolderRule *) rule)->sources, - &sources_folder, &sources_uri); - - G_LOCK (vfolder); - - if (((EMVFolderRule *) rule)->with == - EM_VFOLDER_RULE_WITH_LOCAL || - ((EMVFolderRule *) rule)->with == - EM_VFOLDER_RULE_WITH_LOCAL_REMOTE_ACTIVE) { - - MailFolderCache *cache; - GQueue queue = G_QUEUE_INIT; - - cache = e_mail_session_get_folder_cache (session); - mail_folder_cache_get_local_folder_uris (cache, &queue); - - rule_add_sources ( - session, &queue, &sources_folder, &sources_uri); - - while (!g_queue_is_empty (&queue)) - g_free (g_queue_pop_head (&queue)); - } - - if (((EMVFolderRule *) rule)->with == - EM_VFOLDER_RULE_WITH_REMOTE_ACTIVE || - ((EMVFolderRule *) rule)->with == - EM_VFOLDER_RULE_WITH_LOCAL_REMOTE_ACTIVE) { - - MailFolderCache *cache; - GQueue queue = G_QUEUE_INIT; - - cache = e_mail_session_get_folder_cache (session); - mail_folder_cache_get_remote_folder_uris (cache, &queue); - - rule_add_sources ( - session, &queue, &sources_folder, &sources_uri); - - while (!g_queue_is_empty (&queue)) - g_free (g_queue_pop_head (&queue)); - } - - G_UNLOCK (vfolder); - - query = g_string_new(""); - e_filter_rule_build_code (rule, query); - - vfolder_setup (session, folder, query->str, sources_uri, sources_folder); - - g_string_free (query, TRUE); -} - -static void -context_rule_added (ERuleContext *ctx, - EFilterRule *rule) -{ - EMailSession *session; - CamelFolder *folder; - CamelService *service; - - d(printf("rule added: %s\n", rule->name)); - - session = em_vfolder_editor_rule_get_session (EM_VFOLDER_EDITOR_RULE (rule)); - - service = camel_session_get_service ( - CAMEL_SESSION (session), E_MAIL_SESSION_VFOLDER_UID); - g_return_if_fail (CAMEL_IS_SERVICE (service)); - - /* this always runs quickly */ - /* FIXME Not passing a GCancellable or GError. */ - folder = camel_store_get_folder_sync ( - CAMEL_STORE (service), rule->name, 0, NULL, NULL); - if (folder) { - g_signal_connect ( - rule, "changed", - G_CALLBACK (rule_changed), folder); - - G_LOCK (vfolder); - g_hash_table_insert (vfolder_hash, g_strdup (rule->name), folder); - G_UNLOCK (vfolder); - - rule_changed (rule, folder); - } -} - -static void -context_rule_removed (ERuleContext *ctx, - EFilterRule *rule) -{ - EMailSession *session; - CamelService *service; - gpointer key, folder = NULL; - - d(printf("rule removed; %s\n", rule->name)); - - session = em_vfolder_editor_rule_get_session (EM_VFOLDER_EDITOR_RULE (rule)); - - service = camel_session_get_service ( - CAMEL_SESSION (session), E_MAIL_SESSION_VFOLDER_UID); - g_return_if_fail (CAMEL_IS_SERVICE (service)); - - /* TODO: remove from folder info cache? */ - - G_LOCK (vfolder); - if (g_hash_table_lookup_extended (vfolder_hash, rule->name, &key, &folder)) { - g_hash_table_remove (vfolder_hash, key); - g_free (key); - } - G_UNLOCK (vfolder); - - /* FIXME Not passing a GCancellable or GError. */ - camel_store_delete_folder_sync ( - CAMEL_STORE (service), rule->name, NULL, NULL); - /* this must be unref'd after its deleted */ - if (folder) - g_object_unref ((CamelFolder *) folder); -} - -static void -store_folder_deleted_cb (CamelStore *store, - CamelFolderInfo *info) -{ - EFilterRule *rule; - gchar *user; - - d(printf("Folder deleted: %s\n", info->name)); - store = store; - - /* Warning not thread safe, but might be enough */ - - G_LOCK (vfolder); - - /* delete it from our list */ - rule = e_rule_context_find_rule ((ERuleContext *) context, info->full_name, NULL); - if (rule) { - const gchar *config_dir; - - /* We need to stop listening to removed events, - * otherwise we'll try and remove it again. */ - g_signal_handlers_disconnect_matched ( - context, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, - 0, 0, NULL, context_rule_removed, context); - e_rule_context_remove_rule ((ERuleContext *) context, rule); - g_object_unref (rule); - g_signal_connect ( - context, "rule_removed", - G_CALLBACK (context_rule_removed), context); - - config_dir = mail_session_get_config_dir (); - user = g_build_filename (config_dir, "vfolders.xml", NULL); - e_rule_context_save ((ERuleContext *) context, user); - g_free (user); - } else { - g_warning ( - "Cannot find rule for deleted vfolder '%s'", - info->display_name); - } - - G_UNLOCK (vfolder); -} - -static void -store_folder_renamed_cb (CamelStore *store, - const gchar *old_name, - CamelFolderInfo *info) -{ - EFilterRule *rule; - gchar *user; - - gpointer key, folder; - - /* This should be more-or-less thread-safe */ - - d(printf("Folder renamed to '%s' from '%s'\n", info->full_name, old_name)); - - /* Folder is already renamed? */ - G_LOCK (vfolder); - d(printf("Changing folder name in hash table to '%s'\n", info->full_name)); - if (g_hash_table_lookup_extended (vfolder_hash, old_name, &key, &folder)) { - const gchar *config_dir; - - g_hash_table_remove (vfolder_hash, key); - g_free (key); - g_hash_table_insert (vfolder_hash, g_strdup (info->full_name), folder); - - rule = e_rule_context_find_rule ((ERuleContext *) context, old_name, NULL); - if (!rule) { - G_UNLOCK (vfolder); - g_warning ("Rule shouldn't be NULL\n"); - return; - } - - g_signal_handlers_disconnect_matched ( - rule, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, - 0, 0, NULL, rule_changed, folder); - e_filter_rule_set_name (rule, info->full_name); - g_signal_connect ( - rule, "changed", - G_CALLBACK (rule_changed), folder); - - config_dir = mail_session_get_config_dir (); - user = g_build_filename (config_dir, "vfolders.xml", NULL); - e_rule_context_save ((ERuleContext *) context, user); - g_free (user); - - G_UNLOCK (vfolder); - } else { - G_UNLOCK (vfolder); - g_warning("couldn't find a vfolder rule in our table? %s", info->full_name); - } -} - -static void -folder_available_cb (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name) -{ - mail_vfolder_add_folder (store, folder_name, FALSE); -} - -static void -folder_unavailable_cb (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name) -{ - mail_vfolder_add_folder (store, folder_name, TRUE); -} - -static void -folder_deleted_cb (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name, - EMailBackend *backend) -{ - mail_vfolder_delete_folder (backend, store, folder_name); -} - -static void -folder_renamed_cb (MailFolderCache *cache, - CamelStore *store, - const gchar *old_folder_name, - const gchar *new_folder_name, - gpointer user_data) -{ - mail_vfolder_rename_folder (store, old_folder_name, new_folder_name); -} - -void -vfolder_load_storage (EMailBackend *backend) -{ - /* lock for loading storage, it is safe to call it more than once */ - G_LOCK_DEFINE_STATIC (vfolder_hash); - - CamelStore *vfolder_store; - const gchar *config_dir; - gchar *user; - EFilterRule *rule; - MailFolderCache *folder_cache; - EMailSession *session; - gchar *xmlfile; - GSettings *settings; - - g_return_if_fail (E_IS_MAIL_BACKEND (backend)); - - G_LOCK (vfolder_hash); - - if (vfolder_hash) { - /* we have already initialized */ - G_UNLOCK (vfolder_hash); - return; - } - - vfolder_hash = g_hash_table_new (g_str_hash, g_str_equal); - - G_UNLOCK (vfolder_hash); - - config_dir = mail_session_get_config_dir (); - session = e_mail_backend_get_session (backend); - vfolder_store = e_mail_ui_session_get_vfolder_store (E_MAIL_UI_SESSION (session)); - - g_signal_connect ( - vfolder_store, "folder-deleted", - G_CALLBACK (store_folder_deleted_cb), NULL); - - g_signal_connect ( - vfolder_store, "folder-renamed", - G_CALLBACK (store_folder_renamed_cb), NULL); - - /* load our rules */ - user = g_build_filename (config_dir, "vfolders.xml", NULL); - context = (EMVFolderContext *) em_vfolder_editor_context_new (session); - - xmlfile = g_build_filename (EVOLUTION_PRIVDATADIR, "vfoldertypes.xml", NULL); - if (e_rule_context_load ((ERuleContext *) context, - xmlfile, user) != 0) { - g_warning("cannot load vfolders: %s\n", ((ERuleContext *)context)->error); - } - g_free (xmlfile); - g_free (user); - - g_signal_connect ( - context, "rule_added", - G_CALLBACK (context_rule_added), context); - g_signal_connect ( - context, "rule_removed", - G_CALLBACK (context_rule_removed), context); - - /* and setup the rules we have */ - rule = NULL; - while ((rule = e_rule_context_next_rule ((ERuleContext *) context, rule, NULL))) { - if (rule->name) { - d(printf("rule added: %s\n", rule->name)); - context_rule_added ((ERuleContext *) context, rule); - } else { - d(printf("invalid rule (%p) encountered: rule->name is NULL\n", rule)); - } - } - - /* reenable the feature if required */ - settings = g_settings_new ("org.gnome.evolution.mail"); - g_settings_set_boolean (settings, "enable-vfolders", TRUE); - g_object_unref (settings); - - folder_cache = e_mail_session_get_folder_cache (session); - - g_signal_connect ( - folder_cache, "folder-available", - G_CALLBACK (folder_available_cb), NULL); - g_signal_connect ( - folder_cache, "folder-unavailable", - G_CALLBACK (folder_unavailable_cb), NULL); - g_signal_connect ( - folder_cache, "folder-deleted", - G_CALLBACK (folder_deleted_cb), backend); - g_signal_connect ( - folder_cache, "folder-renamed", - G_CALLBACK (folder_renamed_cb), NULL); -} - -void -vfolder_edit (EMailBackend *backend, - GtkWindow *parent_window) -{ - EShellBackend *shell_backend; - GtkWidget *dialog; - const gchar *config_dir; - gchar *filename; - - g_return_if_fail (E_IS_MAIL_BACKEND (backend)); - g_return_if_fail (GTK_IS_WINDOW (parent_window)); - - shell_backend = E_SHELL_BACKEND (backend); - config_dir = e_shell_backend_get_config_dir (shell_backend); - filename = g_build_filename (config_dir, "vfolders.xml", NULL); - - vfolder_load_storage (backend); - - dialog = em_vfolder_editor_new (context); - gtk_window_set_title ( - GTK_WINDOW (dialog), _("Search Folders")); - gtk_window_set_transient_for ( - GTK_WINDOW (dialog), parent_window); - - switch (gtk_dialog_run (GTK_DIALOG (dialog))) { - case GTK_RESPONSE_OK: - e_rule_context_save ((ERuleContext *) context, filename); - break; - default: - e_rule_context_revert ((ERuleContext *) context, filename); - break; - } - - gtk_widget_destroy (dialog); -} - -static void -vfolder_edit_response_cb (GtkWidget *dialog, - gint response_id, - gpointer user_data) -{ - if (response_id == GTK_RESPONSE_OK) { - GObject *object; - EFilterRule *rule; - EFilterRule *newrule; - const gchar *config_dir; - gchar *user; - - object = G_OBJECT (dialog); - rule = g_object_get_data (object, "vfolder-rule"); - newrule = g_object_get_data (object, "vfolder-newrule"); - - e_filter_rule_copy (rule, newrule); - config_dir = mail_session_get_config_dir (); - user = g_build_filename (config_dir, "vfolders.xml", NULL); - e_rule_context_save ((ERuleContext *) context, user); - g_free (user); - } - - gtk_widget_destroy (dialog); -} - -void -vfolder_edit_rule (EMailSession *session, - const gchar *folder_uri, - EAlertSink *alert_sink) -{ - GtkWidget *dialog; - GtkWidget *widget; - GtkWidget *container; - EFilterRule *rule = NULL; - EFilterRule *newrule; - gchar *folder_name = NULL; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (folder_uri != NULL); - g_return_if_fail (E_IS_ALERT_SINK (alert_sink)); - - e_mail_folder_uri_parse ( - CAMEL_SESSION (session), folder_uri, - NULL, &folder_name, NULL); - - if (folder_name != NULL) { - rule = e_rule_context_find_rule ( - (ERuleContext *) context, folder_name, NULL); - g_free (folder_name); - } - - if (rule == NULL) { - /* TODO: we should probably just create it ... */ - e_alert_submit ( - alert_sink, "mail:vfolder-notexist", - folder_uri, NULL); - return; - } - - g_object_ref (rule); - newrule = e_filter_rule_clone (rule); - - dialog = gtk_dialog_new_with_buttons ( - _("Edit Search Folder"), NULL, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); - - gtk_container_set_border_width (GTK_CONTAINER (dialog), 6); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 500); - gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE); - - container = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); - gtk_box_set_spacing (GTK_BOX (container), 6); - - widget = e_filter_rule_get_widget ( - (EFilterRule *) newrule, (ERuleContext *) context); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - gtk_widget_show (widget); - - g_object_set_data_full ( - G_OBJECT (dialog), "vfolder-rule", - rule, (GDestroyNotify) g_object_unref); - g_object_set_data_full ( - G_OBJECT (dialog), "vfolder-newrule", - newrule, (GDestroyNotify) g_object_unref); - - g_signal_connect ( - dialog, "response", - G_CALLBACK (vfolder_edit_response_cb), NULL); - - gtk_widget_show (dialog); -} - -static void -new_rule_clicked (GtkWidget *w, - gint button, - gpointer data) -{ - if (button == GTK_RESPONSE_OK) { - const gchar *config_dir; - gchar *user; - EFilterRule *rule = g_object_get_data((GObject *)w, "rule"); - EAlert *alert = NULL; - - if (!e_filter_rule_validate (rule, &alert)) { - e_alert_run_dialog (GTK_WINDOW (w), alert); - g_object_unref (alert); - return; - } - - if (e_rule_context_find_rule ( - (ERuleContext *) context, rule->name, rule->source)) { - e_alert_run_dialog_for_args ( - GTK_WINDOW (w), "mail:vfolder-notunique", - rule->name, NULL); - return; - } - - g_object_ref (rule); - e_rule_context_add_rule ((ERuleContext *) context, rule); - config_dir = mail_session_get_config_dir (); - user = g_build_filename (config_dir, "vfolders.xml", NULL); - e_rule_context_save ((ERuleContext *) context, user); - g_free (user); - } - - gtk_widget_destroy (w); -} - -static void -new_rule_changed_cb (EFilterRule *rule, - GtkDialog *dialog) -{ - g_return_if_fail (rule != NULL); - g_return_if_fail (dialog != NULL); - - gtk_dialog_set_response_sensitive ( - dialog, GTK_RESPONSE_OK, rule->parts != NULL); -} - -/* clones a filter/search rule into a matching vfolder rule - * (assuming the same system definitions) */ -EFilterRule * -vfolder_clone_rule (EMailSession *session, - EFilterRule *in) -{ - EFilterRule *rule; - xmlNodePtr xml; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - rule = em_vfolder_editor_rule_new (session); - - xml = e_filter_rule_xml_encode (in); - e_filter_rule_xml_decode (rule, xml, (ERuleContext *) context); - xmlFreeNodeList (xml); - - return rule; -} - -/* adds a rule with a gui */ -void -vfolder_gui_add_rule (EMVFolderRule *rule) -{ - GtkWidget *w; - GtkDialog *gd; - GtkWidget *container; - - w = e_filter_rule_get_widget ((EFilterRule *) rule, (ERuleContext *) context); - - gd = (GtkDialog *) gtk_dialog_new_with_buttons ( - _("New Search Folder"), - NULL, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); - - gtk_dialog_set_default_response (gd, GTK_RESPONSE_OK); - gtk_container_set_border_width (GTK_CONTAINER (gd), 6); - - container = gtk_dialog_get_content_area (gd); - gtk_box_set_spacing (GTK_BOX (container), 6); - - g_object_set (gd, "resizable", TRUE, NULL); - gtk_window_set_default_size (GTK_WINDOW (gd), 500, 500); - gtk_box_pack_start (GTK_BOX (container), w, TRUE, TRUE, 0); - gtk_widget_show ((GtkWidget *) gd); - g_object_set_data_full ( - G_OBJECT (gd), "rule", rule, - (GDestroyNotify) g_object_unref); - g_signal_connect ( - rule, "changed", - G_CALLBACK (new_rule_changed_cb), gd); - new_rule_changed_cb ((EFilterRule *) rule, gd); - g_signal_connect ( - gd, "response", - G_CALLBACK (new_rule_clicked), NULL); - gtk_widget_show ((GtkWidget *) gd); -} - -void -vfolder_gui_add_from_message (EMailSession *session, - CamelMimeMessage *message, - gint flags, - CamelFolder *folder) -{ - EMVFolderRule *rule; - - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - rule = (EMVFolderRule *) em_vfolder_rule_from_message ( - context, message, flags, folder); - vfolder_gui_add_rule (rule); -} - -void -vfolder_gui_add_from_address (EMailSession *session, - CamelInternetAddress *addr, - gint flags, - CamelFolder *folder) -{ - EMVFolderRule *rule; - - g_return_if_fail (addr != NULL); - - rule = (EMVFolderRule *) em_vfolder_rule_from_address ( - context, addr, flags, folder); - vfolder_gui_add_rule (rule); -} - -static void -vfolder_foreach_cb (gpointer key, - gpointer data, - gpointer user_data) -{ - CamelFolder *folder = CAMEL_FOLDER (data); - - if (folder) - g_object_unref (folder); - - g_free (key); -} - -void -mail_vfolder_shutdown (void) -{ - vfolder_shutdown = 1; - - if (vfolder_hash) { - g_hash_table_foreach (vfolder_hash, vfolder_foreach_cb, NULL); - g_hash_table_destroy (vfolder_hash); - vfolder_hash = NULL; - } - - if (context) { - g_object_unref (context); - context = NULL; - } -} |