[evolution] Bug 236994 - Add option to load remote content for specified site or sender
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] Bug 236994 - Add option to load remote content for specified site or sender
- Date: Mon, 30 Mar 2015 13:16:12 +0000 (UTC)
commit 3c4bfddd0c2690283b1739dbaf80c2df9ed7e03e
Author: Milan Crha <mcrha redhat com>
Date: Mon Mar 30 15:14:02 2015 +0200
Bug 236994 - Add option to load remote content for specified site or sender
e-util/e-alert-bar.c | 24 +-
e-util/e-alert-dialog.c | 34 +-
e-util/e-alert.c | 31 ++-
e-util/e-alert.h | 3 +
mail/Makefile.am | 2 +
mail/e-mail-backend.c | 42 ++-
mail/e-mail-backend.h | 4 +
mail/e-mail-browser.c | 4 +-
mail/e-mail-display.c | 257 +++++++++++++-
mail/e-mail-display.h | 14 +-
mail/e-mail-paned-view.c | 11 +-
mail/e-mail-printer.c | 60 +++-
mail/e-mail-printer.h | 7 +-
mail/e-mail-reader-utils.c | 8 +-
mail/e-mail-reader.c | 421 +++++++++++++++++++++++
mail/e-mail-reader.h | 2 +
mail/e-mail-remote-content.c | 573 +++++++++++++++++++++++++++++++
mail/e-mail-remote-content.h | 79 +++++
mail/em-composer-utils.c | 6 +-
mail/em-utils.c | 6 +-
mail/mail-config.ui | 253 +++++++++++++-
mail/mail.error.xml | 5 +
modules/mail/e-mail-shell-backend.c | 6 +-
modules/mail/em-mailer-prefs.c | 572 ++++++++++++++++++++++++-------
modules/mail/em-mailer-prefs.h | 38 +--
modules/prefer-plain/plugin/config-ui.c | 2 +
26 files changed, 2240 insertions(+), 224 deletions(-)
---
diff --git a/e-util/e-alert-bar.c b/e-util/e-alert-bar.c
index 66fbb34..f5533fd 100644
--- a/e-util/e-alert-bar.c
+++ b/e-util/e-alert-bar.c
@@ -62,7 +62,7 @@ alert_bar_show_alert (EAlertBar *alert_bar)
GtkWidget *action_area;
GtkWidget *widget;
EAlert *alert;
- GList *actions;
+ GList *link;
GList *children;
GtkMessageType message_type;
const gchar *primary_text;
@@ -89,8 +89,10 @@ alert_bar_show_alert (EAlertBar *alert_bar)
}
/* Add alert-specific buttons. */
- actions = e_alert_peek_actions (alert);
- while (actions != NULL) {
+ link = e_alert_peek_actions (alert);
+ while (link != NULL) {
+ GtkAction *action = GTK_ACTION (link->data);
+
/* These actions are already wired to trigger an
* EAlert::response signal when activated, which
* will in turn call gtk_info_bar_response(), so
@@ -99,14 +101,18 @@ alert_bar_show_alert (EAlertBar *alert_bar)
widget = gtk_button_new ();
- gtk_activatable_set_related_action (
- GTK_ACTIVATABLE (widget),
- GTK_ACTION (actions->data));
+ gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action);
+ gtk_box_pack_end (GTK_BOX (action_area), widget, FALSE, FALSE, 0);
+
+ link = g_list_next (link);
+ }
- gtk_box_pack_end (
- GTK_BOX (action_area), widget, FALSE, FALSE, 0);
+ link = e_alert_peek_widgets (alert);
+ while (link != NULL) {
+ widget = link->data;
- actions = g_list_next (actions);
+ gtk_box_pack_end (GTK_BOX (action_area), widget, FALSE, FALSE, 0);
+ link = g_list_next (link);
}
/* Add a dismiss button. */
diff --git a/e-util/e-alert-dialog.c b/e-util/e-alert-dialog.c
index e072775..3225827 100644
--- a/e-util/e-alert-dialog.c
+++ b/e-util/e-alert-dialog.c
@@ -121,7 +121,7 @@ alert_dialog_constructed (GObject *object)
GtkWidget *widget;
PangoAttribute *attr;
PangoAttrList *list;
- GList *actions;
+ GList *link;
const gchar *primary, *secondary;
gint default_response;
@@ -154,8 +154,8 @@ alert_dialog_constructed (GObject *object)
G_CALLBACK (gtk_dialog_response), dialog);
/* Add buttons from actions. */
- actions = e_alert_peek_actions (alert);
- if (!actions) {
+ link = e_alert_peek_actions (alert);
+ if (!link && !e_alert_peek_widgets (alert)) {
GtkAction *action;
/* Make sure there is at least one action,
@@ -165,11 +165,12 @@ alert_dialog_constructed (GObject *object)
e_alert_add_action (alert, action, GTK_RESPONSE_CLOSE);
g_object_unref (action);
- actions = e_alert_peek_actions (alert);
+ link = e_alert_peek_actions (alert);
}
- while (actions != NULL) {
+ while (link != NULL) {
GtkWidget *button;
+ GtkAction *action = GTK_ACTION (link->data);
gpointer data;
/* These actions are already wired to trigger an
@@ -182,18 +183,11 @@ alert_dialog_constructed (GObject *object)
button = gtk_button_new ();
gtk_widget_set_can_default (button, TRUE);
-
- gtk_activatable_set_related_action (
- GTK_ACTIVATABLE (button),
- GTK_ACTION (actions->data));
-
- gtk_box_pack_end (
- GTK_BOX (action_area),
- button, FALSE, FALSE, 0);
+ gtk_activatable_set_related_action (GTK_ACTIVATABLE (button), action);
+ gtk_box_pack_end (GTK_BOX (action_area), button, FALSE, FALSE, 0);
/* This is set in e_alert_add_action(). */
- data = g_object_get_data (
- actions->data, "e-alert-response-id");
+ data = g_object_get_data (G_OBJECT (action), "e-alert-response-id");
/* Normally GtkDialog sets the initial focus widget to
* the button corresponding to the default response, but
@@ -205,7 +199,15 @@ alert_dialog_constructed (GObject *object)
gtk_widget_grab_focus (button);
}
- actions = g_list_next (actions);
+ link = g_list_next (link);
+ }
+
+ link = e_alert_peek_widgets (alert);
+ while (link != NULL) {
+ widget = link->data;
+
+ gtk_box_pack_end (GTK_BOX (action_area), widget, FALSE, FALSE, 0);
+ link = g_list_next (link);
}
widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
diff --git a/e-util/e-alert.c b/e-util/e-alert.c
index 438f523..f83f87c 100644
--- a/e-util/e-alert.c
+++ b/e-util/e-alert.c
@@ -100,6 +100,8 @@ struct _EAlertPrivate {
* but we need to preserve the button order and GtkActionGroup
* uses a hash table, which does not preserve order. */
GQueue actions;
+
+ GQueue widgets;
};
enum {
@@ -543,6 +545,13 @@ alert_dispose (GObject *object)
g_object_unref (action);
}
+ while (!g_queue_is_empty (&alert->priv->widgets)) {
+ GtkWidget *widget;
+
+ widget = g_queue_pop_head (&alert->priv->widgets);
+ g_object_unref (widget);
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_alert_parent_class)->dispose (object);
}
@@ -701,6 +710,7 @@ e_alert_init (EAlert *alert)
alert->priv = E_ALERT_GET_PRIVATE (alert);
g_queue_init (&alert->priv->actions);
+ g_queue_init (&alert->priv->widgets);
}
/**
@@ -912,7 +922,7 @@ e_alert_add_action (EAlert *alert,
gint response_id)
{
g_return_if_fail (E_IS_ALERT (alert));
- g_return_if_fail (GTK_ACTION (action));
+ g_return_if_fail (GTK_IS_ACTION (action));
g_object_set_data (
G_OBJECT (action), "e-alert-response-id",
@@ -933,6 +943,25 @@ e_alert_peek_actions (EAlert *alert)
return g_queue_peek_head_link (&alert->priv->actions);
}
+/* The widget is consumed by this function */
+void
+e_alert_add_widget (EAlert *alert,
+ GtkWidget *widget)
+{
+ g_return_if_fail (E_IS_ALERT (alert));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ g_queue_push_tail (&alert->priv->widgets, g_object_ref_sink (widget));
+}
+
+GList *
+e_alert_peek_widgets (EAlert *alert)
+{
+ g_return_val_if_fail (E_IS_ALERT (alert), NULL);
+
+ return g_queue_peek_head_link (&alert->priv->widgets);
+}
+
GtkWidget *
e_alert_create_image (EAlert *alert,
GtkIconSize size)
diff --git a/e-util/e-alert.h b/e-util/e-alert.h
index 9d7cd3e..375b6f4 100644
--- a/e-util/e-alert.h
+++ b/e-util/e-alert.h
@@ -103,6 +103,9 @@ void e_alert_add_action (EAlert *alert,
GtkAction *action,
gint response_id);
GList * e_alert_peek_actions (EAlert *alert);
+void e_alert_add_widget (EAlert *alert,
+ GtkWidget *widget);
+GList * e_alert_peek_widgets (EAlert *alert);
GtkWidget * e_alert_create_image (EAlert *alert,
GtkIconSize size);
void e_alert_response (EAlert *alert,
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 58cd98d..cc2094c 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -100,6 +100,7 @@ mailinclude_HEADERS = \
e-mail-printer.h \
e-mail-reader-utils.h \
e-mail-reader.h \
+ e-mail-remote-content.h \
e-mail-request.h \
e-mail-send-account-override.h \
e-mail-sidebar.h \
@@ -178,6 +179,7 @@ libevolution_mail_la_SOURCES = \
e-mail-printer.c \
e-mail-reader-utils.c \
e-mail-reader.c \
+ e-mail-remote-content.c \
e-mail-request.c \
e-mail-send-account-override.c \
e-mail-sidebar.c \
diff --git a/mail/e-mail-backend.c b/mail/e-mail-backend.c
index cfe28a6..1ee0a1f 100644
--- a/mail/e-mail-backend.c
+++ b/mail/e-mail-backend.c
@@ -57,12 +57,14 @@ struct _EMailBackendPrivate {
EMailSession *session;
GHashTable *jobs;
EMailSendAccountOverride *send_account_override;
+ EMailRemoteContent *remote_content;
};
enum {
PROP_0,
PROP_SESSION,
- PROP_SEND_ACCOUNT_OVERRIDE
+ PROP_SEND_ACCOUNT_OVERRIDE,
+ PROP_REMOTE_CONTENT
};
G_DEFINE_ABSTRACT_TYPE (
@@ -949,6 +951,13 @@ mail_backend_get_property (GObject *object,
e_mail_backend_get_send_account_override (
E_MAIL_BACKEND (object)));
return;
+
+ case PROP_REMOTE_CONTENT:
+ g_value_set_object (
+ value,
+ e_mail_backend_get_remote_content (
+ E_MAIL_BACKEND (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -989,6 +998,7 @@ mail_backend_finalize (GObject *object)
g_hash_table_destroy (priv->jobs);
g_clear_object (&priv->send_account_override);
+ g_clear_object (&priv->remote_content);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_mail_backend_parent_class)->finalize (object);
@@ -1143,7 +1153,7 @@ mail_backend_constructed (GObject *object)
EShellBackend *shell_backend;
MailFolderCache *folder_cache;
ESourceRegistry *registry;
- gchar *send_overrides_ini;
+ gchar *config_filename;
priv = E_MAIL_BACKEND_GET_PRIVATE (object);
@@ -1241,9 +1251,13 @@ mail_backend_constructed (GObject *object)
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (e_mail_backend_parent_class)->constructed (object);
- send_overrides_ini = g_build_filename (e_shell_backend_get_config_dir (shell_backend),
"send-overrides.ini", NULL);
- priv->send_account_override = e_mail_send_account_override_new (send_overrides_ini);
- g_free (send_overrides_ini);
+ config_filename = g_build_filename (e_shell_backend_get_config_dir (shell_backend),
"send-overrides.ini", NULL);
+ priv->send_account_override = e_mail_send_account_override_new (config_filename);
+ g_free (config_filename);
+
+ config_filename = g_build_filename (e_shell_backend_get_config_dir (shell_backend),
"remote-content.db", NULL);
+ priv->remote_content = e_mail_remote_content_new (config_filename);
+ g_free (config_filename);
}
static void
@@ -1284,6 +1298,16 @@ e_mail_backend_class_init (EMailBackendClass *class)
NULL,
E_TYPE_MAIL_SEND_ACCOUNT_OVERRIDE,
G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REMOTE_CONTENT,
+ g_param_spec_object (
+ "remote-content",
+ NULL,
+ NULL,
+ E_TYPE_MAIL_REMOTE_CONTENT,
+ G_PARAM_READABLE));
}
static void
@@ -1382,3 +1406,11 @@ e_mail_backend_get_send_account_override (EMailBackend *backend)
return backend->priv->send_account_override;
}
+
+EMailRemoteContent *
+e_mail_backend_get_remote_content (EMailBackend *backend)
+{
+ g_return_val_if_fail (E_IS_MAIL_BACKEND (backend), NULL);
+
+ return backend->priv->remote_content;
+}
diff --git a/mail/e-mail-backend.h b/mail/e-mail-backend.h
index ff22c8e..4426abf 100644
--- a/mail/e-mail-backend.h
+++ b/mail/e-mail-backend.h
@@ -27,6 +27,7 @@
#include <shell/e-shell-backend.h>
#include <libemail-engine/libemail-engine.h>
+#include <mail/e-mail-remote-content.h>
#include <mail/e-mail-send-account-override.h>
/* Standard GObject macros */
@@ -79,6 +80,9 @@ gboolean e_mail_backend_empty_trash_policy_decision
EMailSendAccountOverride *
e_mail_backend_get_send_account_override
(EMailBackend *backend);
+EMailRemoteContent *
+ e_mail_backend_get_remote_content
+ (EMailBackend *backend);
G_END_DECLS
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index c281e94..e5d4095 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -619,7 +619,7 @@ mail_browser_constructed (GObject *object)
browser->priv->message_list, "message-list-built",
G_CALLBACK (mail_browser_message_list_built_cb), object);
- display = e_mail_display_new ();
+ display = e_mail_display_new (e_mail_backend_get_remote_content (backend));
e_mail_display_set_mode (
E_MAIL_DISPLAY (display),
@@ -676,6 +676,8 @@ mail_browser_constructed (GObject *object)
ui_manager, "connect-proxy",
G_CALLBACK (mail_browser_connect_proxy_cb), object);
+ e_mail_reader_connect_remote_content (reader);
+
/* Configure an EFocusTracker to manage selection actions. */
focus_tracker = e_focus_tracker_new (GTK_WINDOW (object));
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index c82082d..83087f8 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -22,6 +22,7 @@
#include <config.h>
#include <glib/gi18n.h>
+#include <glib/gstdio.h>
#include <gdk/gdk.h>
#include <camel/camel.h>
@@ -61,6 +62,10 @@ struct _EMailDisplayPrivate {
guint scheduled_reload;
GHashTable *old_settings;
+
+ GMutex remote_content_lock;
+ EMailRemoteContent *remote_content;
+ GHashTable *skipped_remote_content_sites;
};
enum {
@@ -69,7 +74,8 @@ enum {
PROP_HEADERS_COLLAPSABLE,
PROP_HEADERS_COLLAPSED,
PROP_MODE,
- PROP_PART_LIST
+ PROP_PART_LIST,
+ PROP_REMOTE_CONTENT
};
static CamelDataCache *emd_global_http_cache = NULL;
@@ -136,6 +142,102 @@ G_DEFINE_TYPE (
E_TYPE_WEB_VIEW);
static void
+e_mail_display_claim_skipped_uri (EMailDisplay *mail_display,
+ const gchar *uri)
+{
+ SoupURI *soup_uri;
+ const gchar *site;
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (mail_display));
+ g_return_if_fail (uri != NULL);
+
+ soup_uri = soup_uri_new (uri);
+ if (!soup_uri)
+ return;
+
+ site = soup_uri_get_host (soup_uri);
+ if (site && *site) {
+ g_mutex_lock (&mail_display->priv->remote_content_lock);
+
+ if (!g_hash_table_contains (mail_display->priv->skipped_remote_content_sites, site)) {
+ g_hash_table_insert (mail_display->priv->skipped_remote_content_sites, g_strdup
(site), NULL);
+ }
+
+ g_mutex_unlock (&mail_display->priv->remote_content_lock);
+ }
+
+ soup_uri_free (soup_uri);
+}
+
+static void
+e_mail_display_cleanup_skipped_uris (EMailDisplay *mail_display)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (mail_display));
+
+ g_mutex_lock (&mail_display->priv->remote_content_lock);
+ g_hash_table_remove_all (mail_display->priv->skipped_remote_content_sites);
+ g_mutex_unlock (&mail_display->priv->remote_content_lock);
+}
+
+static gboolean
+e_mail_display_can_download_uri (EMailDisplay *mail_display,
+ const gchar *uri)
+{
+ SoupURI *soup_uri;
+ const gchar *site;
+ gboolean can_download = FALSE;
+ EMailRemoteContent *remote_content;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (mail_display), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ remote_content = e_mail_display_ref_remote_content (mail_display);
+ if (!remote_content)
+ return FALSE;
+
+ soup_uri = soup_uri_new (uri);
+ if (!soup_uri) {
+ g_object_unref (remote_content);
+ return FALSE;
+ }
+
+ site = soup_uri_get_host (soup_uri);
+ if (site && *site)
+ can_download = e_mail_remote_content_has_site (remote_content, site);
+
+ soup_uri_free (soup_uri);
+
+ if (!can_download && mail_display->priv->part_list) {
+ CamelMimeMessage *message;
+
+ message = e_mail_part_list_get_message (mail_display->priv->part_list);
+ if (message) {
+ CamelInternetAddress *from;
+
+ from = camel_mime_message_get_from (message);
+ if (from) {
+ gint ii, len;
+
+ len = camel_address_length (CAMEL_ADDRESS (from));
+ for (ii = 0; ii < len && !can_download; ii++) {
+ const gchar *mail = NULL;
+
+ if (!camel_internet_address_get (from, ii, NULL, &mail))
+ break;
+
+ if (mail && *mail)
+ can_download = e_mail_remote_content_has_mail
(remote_content, mail);
+ }
+ }
+ }
+ }
+
+ g_object_unref (remote_content);
+
+ return can_download;
+}
+
+static void
formatter_image_loading_policy_changed_cb (GObject *object,
GParamSpec *pspec,
gpointer user_data)
@@ -166,7 +268,14 @@ mail_display_image_exists_in_cache (const gchar *image_uri)
emd_global_http_cache, "http", hash);
if (filename != NULL) {
+ struct stat st;
+
exists = g_file_test (filename, G_FILE_TEST_EXISTS);
+ if (exists && g_stat (filename, &st) == 0) {
+ exists = st.st_size != 0;
+ } else {
+ exists = FALSE;
+ }
g_free (filename);
}
@@ -1088,11 +1197,18 @@ mail_parts_bind_dom (GObject *object,
frame = WEBKIT_WEB_FRAME (object);
load_status = webkit_web_frame_get_load_status (frame);
+ web_view = webkit_web_frame_get_web_view (frame);
+ display = E_MAIL_DISPLAY (web_view);
+
+ if (load_status == WEBKIT_LOAD_PROVISIONAL) {
+ if (webkit_web_view_get_main_frame (web_view) == frame)
+ e_mail_display_cleanup_skipped_uris (display);
+ return;
+ }
+
if (load_status != WEBKIT_LOAD_FINISHED)
return;
- web_view = webkit_web_frame_get_web_view (frame);
- display = E_MAIL_DISPLAY (web_view);
if (display->priv->part_list == NULL)
return;
@@ -1192,6 +1308,12 @@ mail_display_set_property (GObject *object,
E_MAIL_DISPLAY (object),
g_value_get_pointer (value));
return;
+
+ case PROP_REMOTE_CONTENT:
+ e_mail_display_set_remote_content (
+ E_MAIL_DISPLAY (object),
+ g_value_get_object (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1238,6 +1360,13 @@ mail_display_get_property (GObject *object,
e_mail_display_get_part_list (
E_MAIL_DISPLAY (object)));
return;
+
+ case PROP_REMOTE_CONTENT:
+ g_value_take_object (
+ value,
+ e_mail_display_ref_remote_content (
+ E_MAIL_DISPLAY (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1288,6 +1417,16 @@ mail_display_finalize (GObject *object)
priv->old_settings = NULL;
}
+ g_mutex_lock (&priv->remote_content_lock);
+ if (priv->skipped_remote_content_sites) {
+ g_hash_table_destroy (priv->skipped_remote_content_sites);
+ priv->skipped_remote_content_sites = NULL;
+ }
+
+ g_clear_object (&priv->remote_content);
+ g_mutex_unlock (&priv->remote_content_lock);
+ g_mutex_clear (&priv->remote_content_lock);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_mail_display_parent_class)->finalize (object);
}
@@ -1433,19 +1572,23 @@ mail_display_redirect_uri (EWebView *web_view,
gchar *new_uri, *mail_uri, *enc;
SoupURI *soup_uri;
GHashTable *query;
- gboolean image_exists;
+ gboolean can_download_uri;
EImageLoadingPolicy image_policy;
- /* Check Evolution's cache */
- image_exists = mail_display_image_exists_in_cache (uri);
+ can_download_uri = e_mail_display_can_download_uri (display, uri);
+ if (!can_download_uri) {
+ /* Check Evolution's cache */
+ can_download_uri = mail_display_image_exists_in_cache (uri);
+ }
/* If the URI is not cached and we are not allowed to load it
* then redirect to invalid URI, so that webkit would display
* a native placeholder for it. */
image_policy = e_mail_formatter_get_image_loading_policy (
display->priv->formatter);
- if (!image_exists && !display->priv->force_image_load &&
+ if (!can_download_uri && !display->priv->force_image_load &&
(image_policy == E_IMAGE_LOADING_POLICY_NEVER)) {
+ e_mail_display_claim_skipped_uri (display, uri);
return g_strdup ("about:blank");
}
@@ -1466,11 +1609,13 @@ mail_display_redirect_uri (EWebView *web_view,
enc = soup_uri_encode (mail_uri, NULL);
g_hash_table_insert (query, g_strdup ("__evo-mail"), enc);
- if (display->priv->force_image_load) {
+ if (display->priv->force_image_load || can_download_uri) {
g_hash_table_insert (
query,
g_strdup ("__evo-load-images"),
g_strdup ("true"));
+ } else if (image_policy != E_IMAGE_LOADING_POLICY_ALWAYS) {
+ e_mail_display_claim_skipped_uri (display, uri);
}
g_free (mail_uri);
@@ -1733,6 +1878,17 @@ e_mail_display_class_init (EMailDisplayClass *class)
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REMOTE_CONTENT,
+ g_param_spec_object (
+ "remote-content",
+ "Mail Remote Content",
+ NULL,
+ E_TYPE_MAIL_REMOTE_CONTENT,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
}
static void
@@ -1832,6 +1988,10 @@ e_mail_display_init (EMailDisplay *display)
camel_data_cache_set_expire_access (
emd_global_http_cache, 2 * 60 * 60);
}
+
+ g_mutex_init (&display->priv->remote_content_lock);
+ display->priv->remote_content = NULL;
+ display->priv->skipped_remote_content_sites = g_hash_table_new_full (camel_strcase_hash,
camel_strcase_equal, g_free, NULL);
}
static void
@@ -1859,9 +2019,11 @@ e_mail_display_update_colors (EMailDisplay *display,
}
GtkWidget *
-e_mail_display_new (void)
+e_mail_display_new (EMailRemoteContent *remote_content)
{
- return g_object_new (E_TYPE_MAIL_DISPLAY, NULL);
+ return g_object_new (E_TYPE_MAIL_DISPLAY,
+ "remote-content", remote_content,
+ NULL);
}
EMailFormatterMode
@@ -2310,3 +2472,78 @@ e_mail_display_set_force_load_images (EMailDisplay *display,
display->priv->force_image_load = force_load_images;
}
+gboolean
+e_mail_display_has_skipped_remote_content_sites (EMailDisplay *display)
+{
+ gboolean has_any;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+ g_mutex_lock (&display->priv->remote_content_lock);
+
+ has_any = g_hash_table_size (display->priv->skipped_remote_content_sites) > 0;
+
+ g_mutex_unlock (&display->priv->remote_content_lock);
+
+ return has_any;
+}
+
+/* Free with g_list_free_full (uris, g_free); */
+GList *
+e_mail_display_get_skipped_remote_content_sites (EMailDisplay *display)
+{
+ GList *uris, *link;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ g_mutex_lock (&display->priv->remote_content_lock);
+
+ uris = g_hash_table_get_keys (display->priv->skipped_remote_content_sites);
+
+ for (link = uris; link; link = g_list_next (link)) {
+ link->data = g_strdup (link->data);
+ }
+
+ g_mutex_unlock (&display->priv->remote_content_lock);
+
+ return uris;
+}
+
+EMailRemoteContent *
+e_mail_display_ref_remote_content (EMailDisplay *display)
+{
+ EMailRemoteContent *remote_content;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ g_mutex_lock (&display->priv->remote_content_lock);
+
+ remote_content = display->priv->remote_content;
+ if (remote_content)
+ g_object_ref (remote_content);
+
+ g_mutex_unlock (&display->priv->remote_content_lock);
+
+ return remote_content;
+}
+
+void
+e_mail_display_set_remote_content (EMailDisplay *display,
+ EMailRemoteContent *remote_content)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+ if (remote_content)
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (remote_content));
+
+ g_mutex_lock (&display->priv->remote_content_lock);
+
+ if (display->priv->remote_content == remote_content) {
+ g_mutex_unlock (&display->priv->remote_content_lock);
+ return;
+ }
+
+ g_clear_object (&display->priv->remote_content);
+ display->priv->remote_content = remote_content ? g_object_ref (remote_content) : NULL;
+
+ g_mutex_unlock (&display->priv->remote_content_lock);
+}
diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h
index 25fd338..15e9986 100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@ -24,6 +24,7 @@
#include <e-util/e-util.h>
#include <em-format/e-mail-formatter.h>
+#include <mail/e-mail-remote-content.h>
/* Standard GObject macros */
#define E_TYPE_MAIL_DISPLAY \
@@ -57,11 +58,10 @@ struct _EMailDisplay {
struct _EMailDisplayClass {
EWebViewClass parent_class;
-
};
GType e_mail_display_get_type (void) G_GNUC_CONST;
-GtkWidget * e_mail_display_new (void);
+GtkWidget * e_mail_display_new (EMailRemoteContent *remote_content);
EMailFormatterMode
e_mail_display_get_mode (EMailDisplay *display);
void e_mail_display_set_mode (EMailDisplay *display,
@@ -94,6 +94,16 @@ void e_mail_display_load_images (EMailDisplay *display);
void e_mail_display_set_force_load_images
(EMailDisplay *display,
gboolean force_load_images);
+gboolean e_mail_display_has_skipped_remote_content_sites
+ (EMailDisplay *display);
+GList * e_mail_display_get_skipped_remote_content_sites
+ (EMailDisplay *display);
+EMailRemoteContent *
+ e_mail_display_ref_remote_content
+ (EMailDisplay *display);
+void e_mail_display_set_remote_content
+ (EMailDisplay *display,
+ EMailRemoteContent *remote_content);
G_END_DECLS
diff --git a/mail/e-mail-paned-view.c b/mail/e-mail-paned-view.c
index 3530ad0..bb32db8 100644
--- a/mail/e-mail-paned-view.c
+++ b/mail/e-mail-paned-view.c
@@ -640,10 +640,6 @@ mail_paned_view_constructed (GObject *object)
priv = E_MAIL_PANED_VIEW_GET_PRIVATE (object);
- priv->display = g_object_new (
- E_TYPE_MAIL_DISPLAY,
- "headers-collapsable", TRUE, NULL);
-
view = E_MAIL_VIEW (object);
shell_view = e_mail_view_get_shell_view (view);
shell_window = e_shell_view_get_shell_window (shell_view);
@@ -652,6 +648,11 @@ mail_paned_view_constructed (GObject *object)
backend = E_MAIL_BACKEND (shell_backend);
session = e_mail_backend_get_session (backend);
+ priv->display = g_object_new (E_TYPE_MAIL_DISPLAY,
+ "headers-collapsable", TRUE,
+ "remote-content", e_mail_backend_get_remote_content (backend),
+ NULL);
+
/* FIXME This should be an EMailPanedView property, so
* it can be configured from the settings module. */
@@ -737,6 +738,8 @@ mail_paned_view_constructed (GObject *object)
* set_preview_visible() method relies on it. */
e_mail_view_set_preview_visible (view, TRUE);
+ e_mail_reader_connect_remote_content (reader);
+
e_extensible_load_extensions (E_EXTENSIBLE (object));
/* Chain up to parent's constructed() method. */
diff --git a/mail/e-mail-printer.c b/mail/e-mail-printer.c
index 6205a50..56b8575 100644
--- a/mail/e-mail-printer.c
+++ b/mail/e-mail-printer.c
@@ -55,6 +55,7 @@ typedef struct _AsyncContext AsyncContext;
struct _EMailPrinterPrivate {
EMailFormatter *formatter;
EMailPartList *part_list;
+ EMailRemoteContent *remote_content;
gchar *export_filename;
@@ -80,7 +81,8 @@ struct _AsyncContext {
enum {
PROP_0,
- PROP_PART_LIST
+ PROP_PART_LIST,
+ PROP_REMOTE_CONTENT
};
enum {
@@ -390,6 +392,16 @@ mail_printer_set_part_list (EMailPrinter *printer,
}
static void
+mail_printer_set_remote_content (EMailPrinter *printer,
+ EMailRemoteContent *remote_content)
+{
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (remote_content));
+ g_return_if_fail (printer->priv->remote_content == NULL);
+
+ printer->priv->remote_content = g_object_ref (remote_content);
+}
+
+static void
mail_printer_set_property (GObject *object,
guint property_id,
const GValue *value,
@@ -401,6 +413,12 @@ mail_printer_set_property (GObject *object,
E_MAIL_PRINTER (object),
g_value_get_object (value));
return;
+
+ case PROP_REMOTE_CONTENT:
+ mail_printer_set_remote_content (
+ E_MAIL_PRINTER (object),
+ g_value_get_object (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -419,6 +437,13 @@ mail_printer_get_property (GObject *object,
e_mail_printer_ref_part_list (
E_MAIL_PRINTER (object)));
return;
+
+ case PROP_REMOTE_CONTENT:
+ g_value_take_object (
+ value,
+ e_mail_printer_ref_remote_content (
+ E_MAIL_PRINTER (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -433,6 +458,7 @@ mail_printer_dispose (GObject *object)
g_clear_object (&priv->formatter);
g_clear_object (&priv->part_list);
+ g_clear_object (&priv->remote_content);
g_clear_object (&priv->webview);
g_clear_object (&priv->operation);
@@ -476,6 +502,17 @@ e_mail_printer_class_init (EMailPrinterClass *class)
E_TYPE_MAIL_PART_LIST,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REMOTE_CONTENT,
+ g_param_spec_object (
+ "remote-content",
+ "Remote Content",
+ NULL,
+ E_TYPE_MAIL_REMOTE_CONTENT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
}
static void
@@ -487,13 +524,15 @@ e_mail_printer_init (EMailPrinter *printer)
}
EMailPrinter *
-e_mail_printer_new (EMailPartList *part_list)
+e_mail_printer_new (EMailPartList *part_list,
+ EMailRemoteContent *remote_content)
{
g_return_val_if_fail (E_IS_MAIL_PART_LIST (part_list), NULL);
- return g_object_new (
- E_TYPE_MAIL_PRINTER,
- "part-list", part_list, NULL);
+ return g_object_new (E_TYPE_MAIL_PRINTER,
+ "part-list", part_list,
+ "remote-content", remote_content,
+ NULL);
}
EMailPartList *
@@ -504,6 +543,17 @@ e_mail_printer_ref_part_list (EMailPrinter *printer)
return g_object_ref (printer->priv->part_list);
}
+EMailRemoteContent *
+e_mail_printer_ref_remote_content (EMailPrinter *printer)
+{
+ g_return_val_if_fail (E_IS_MAIL_PRINTER (printer), NULL);
+
+ if (!printer->priv->remote_content)
+ return NULL;
+
+ return g_object_ref (printer->priv->remote_content);
+}
+
void
e_mail_printer_print (EMailPrinter *printer,
GtkPrintOperationAction action,
diff --git a/mail/e-mail-printer.h b/mail/e-mail-printer.h
index 29f48a9..7926fa9 100644
--- a/mail/e-mail-printer.h
+++ b/mail/e-mail-printer.h
@@ -21,6 +21,7 @@
#include <em-format/e-mail-part-list.h>
#include <em-format/e-mail-formatter.h>
+#include <mail/e-mail-remote-content.h>
/* Standard GObject macros */
#define E_TYPE_MAIL_PRINTER \
@@ -57,8 +58,12 @@ struct _EMailPrinterClass {
};
GType e_mail_printer_get_type (void) G_GNUC_CONST;
-EMailPrinter * e_mail_printer_new (EMailPartList *source);
+EMailPrinter * e_mail_printer_new (EMailPartList *source,
+ EMailRemoteContent *remote_content);
EMailPartList * e_mail_printer_ref_part_list (EMailPrinter *printer);
+EMailRemoteContent *
+ e_mail_printer_ref_remote_content
+ (EMailPrinter *printer);
void e_mail_printer_print (EMailPrinter *printer,
GtkPrintOperationAction action,
EMailFormatter *formatter,
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index 0df7af1..857f5bc 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -1261,6 +1261,7 @@ mail_reader_print_parse_message_cb (GObject *source_object,
GCancellable *cancellable;
EMailPrinter *printer;
EMailPartList *part_list;
+ EMailRemoteContent *remote_content;
AsyncContext *async_context;
GError *local_error = NULL;
@@ -1282,10 +1283,13 @@ mail_reader_print_parse_message_cb (GObject *source_object,
return;
}
- printer = e_mail_printer_new (part_list);
-
mail_display = e_mail_reader_get_mail_display (reader);
formatter = e_mail_display_get_formatter (mail_display);
+ remote_content = e_mail_display_ref_remote_content (mail_display);
+
+ printer = e_mail_printer_new (part_list, remote_content);
+
+ g_clear_object (&remote_content);
e_activity_set_text (activity, _("Printing"));
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 7eb1440..cfcd232 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -94,6 +94,8 @@ struct _EMailReaderPrivate {
* the message is loaded into the EMailDisplay */
gboolean schedule_mark_seen;
guint schedule_mark_seen_interval;
+
+ gpointer remote_content_alert; /* EAlert */
};
enum {
@@ -4911,3 +4913,422 @@ e_mail_reader_composer_created (EMailReader *reader,
reader, signals[COMPOSER_CREATED], 0, composer, message);
}
+static void
+e_mail_reader_load_remote_content_clicked_cb (GtkButton *button,
+ EMailReader *reader)
+{
+ EMailDisplay *mail_display;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ mail_display = e_mail_reader_get_mail_display (reader);
+
+ /* This causes reload, thus also alert removal */
+ e_mail_display_load_images (mail_display);
+}
+
+static GList *
+e_mail_reader_get_from_mails (EMailDisplay *mail_display)
+{
+ EMailPartList *part_list;
+ CamelMimeMessage *message;
+ CamelInternetAddress *from;
+ GList *mails = NULL;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (mail_display), NULL);
+
+ part_list = e_mail_display_get_part_list (mail_display);
+ if (!part_list)
+ return NULL;
+
+ message = e_mail_part_list_get_message (part_list);
+ if (!message)
+ return NULL;
+
+ from = camel_mime_message_get_from (message);
+ if (from) {
+ GHashTable *domains;
+ GHashTableIter iter;
+ gpointer key, value;
+ gint ii, len;
+
+ domains = g_hash_table_new (camel_strcase_hash, camel_strcase_equal);
+
+ len = camel_address_length (CAMEL_ADDRESS (from));
+ for (ii = 0; ii < len; ii++) {
+ const gchar *mail = NULL;
+
+ if (!camel_internet_address_get (from, ii, NULL, &mail))
+ break;
+
+ if (mail && *mail) {
+ const gchar *at;
+
+ mails = g_list_prepend (mails, g_strdup (mail));
+
+ at = strchr (mail, '@');
+ if (at && at != mail && at[1])
+ g_hash_table_insert (domains, (gpointer) at, NULL);
+ }
+ }
+
+ g_hash_table_iter_init (&iter, domains);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ const gchar *domain = key;
+
+ mails = g_list_prepend (mails, g_strdup (domain));
+ }
+
+ g_hash_table_destroy (domains);
+ }
+
+ return g_list_reverse (mails);
+}
+
+static void
+e_mail_reader_remote_content_menu_position (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ GtkRequisition menu_requisition;
+ GtkTextDirection direction;
+ GtkAllocation allocation;
+ GdkRectangle monitor;
+ GdkScreen *screen;
+ GdkWindow *window;
+ GtkWidget *widget = user_data;
+ gint monitor_num;
+
+ gtk_widget_get_preferred_size (GTK_WIDGET (menu), &menu_requisition, NULL);
+
+ window = gtk_widget_get_parent_window (widget);
+ screen = gtk_widget_get_screen (GTK_WIDGET (menu));
+ monitor_num = gdk_screen_get_monitor_at_window (screen, window);
+ if (monitor_num < 0)
+ monitor_num = 0;
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ gdk_window_get_origin (window, x, y);
+ *x += allocation.x;
+ *y += allocation.y;
+
+ direction = gtk_widget_get_direction (widget);
+ if (direction == GTK_TEXT_DIR_LTR)
+ *x += MAX (allocation.width - menu_requisition.width, 0);
+ else if (menu_requisition.width > allocation.width)
+ *x -= menu_requisition.width - allocation.width;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ if ((*y + allocation.height +
+ menu_requisition.height) <= monitor.y + monitor.height)
+ *y += allocation.height;
+ else if ((*y - menu_requisition.height) >= monitor.y)
+ *y -= menu_requisition.height;
+ else if (monitor.y + monitor.height -
+ (*y + allocation.height) > *y)
+ *y += allocation.height;
+ else
+ *y -= menu_requisition.height;
+
+ *push_in = FALSE;
+}
+
+static gboolean
+e_mail_reader_destroy_menu_idle_cb (gpointer user_data)
+{
+ gtk_widget_destroy (user_data);
+
+ return FALSE;
+}
+
+static void
+e_mail_reader_remote_content_menu_deactivate_cb (GtkMenuShell *popup_menu,
+ GtkToggleButton *toggle_button)
+{
+ g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
+
+ gtk_toggle_button_set_active (toggle_button, FALSE);
+
+ g_idle_add (e_mail_reader_destroy_menu_idle_cb, popup_menu);
+}
+
+#define REMOTE_CONTENT_KEY_IS_MAIL "remote-content-key-is-mail"
+#define REMOTE_CONTENT_KEY_VALUE "remote-content-key-value"
+
+static void
+e_mail_reader_remote_content_menu_activate_cb (GObject *item,
+ EMailReader *reader)
+{
+ EMailDisplay *mail_display;
+ EMailRemoteContent *remote_content;
+ gboolean is_mail;
+ const gchar *value;
+
+ g_return_if_fail (GTK_IS_MENU_ITEM (item));
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ is_mail = GPOINTER_TO_INT (g_object_get_data (item, REMOTE_CONTENT_KEY_IS_MAIL)) == 1;
+ value = g_object_get_data (item, REMOTE_CONTENT_KEY_VALUE);
+
+ g_return_if_fail (value && *value);
+
+ mail_display = e_mail_reader_get_mail_display (reader);
+ if (!mail_display)
+ return;
+
+ remote_content = e_mail_display_ref_remote_content (mail_display);
+ if (!remote_content)
+ return;
+
+ if (is_mail)
+ e_mail_remote_content_add_mail (remote_content, value);
+ else
+ e_mail_remote_content_add_site (remote_content, value);
+
+ g_clear_object (&remote_content);
+
+ e_mail_display_reload (mail_display);
+}
+
+static void
+e_mail_reader_add_remote_content_menu_item (EMailReader *reader,
+ GtkWidget *popup_menu,
+ const gchar *label,
+ gboolean is_mail,
+ const gchar *value)
+{
+ GtkWidget *item;
+ GObject *object;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (GTK_IS_MENU (popup_menu));
+ g_return_if_fail (label != NULL);
+ g_return_if_fail (value != NULL);
+
+ item = gtk_menu_item_new_with_label (label);
+ object = G_OBJECT (item);
+
+ g_object_set_data (object, REMOTE_CONTENT_KEY_IS_MAIL, is_mail ? GINT_TO_POINTER (1) : NULL);
+ g_object_set_data_full (object, REMOTE_CONTENT_KEY_VALUE, g_strdup (value), g_free);
+
+ g_signal_connect (item, "activate", G_CALLBACK (e_mail_reader_remote_content_menu_activate_cb),
reader);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item);
+}
+
+static void
+e_mail_reader_show_remote_content_popup (EMailReader *reader,
+ GdkEventButton *event,
+ GtkToggleButton *toggle_button)
+{
+ EMailDisplay *mail_display;
+ GList *mails, *sites, *link;
+ GtkWidget *popup_menu = NULL;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ mail_display = e_mail_reader_get_mail_display (reader);
+ mails = e_mail_reader_get_from_mails (mail_display);
+ sites = e_mail_display_get_skipped_remote_content_sites (mail_display);
+
+ for (link = mails; link; link = g_list_next (link)) {
+ const gchar *mail = link->data;
+ gchar *label;
+
+ if (!mail || !*mail)
+ continue;
+
+ if (!popup_menu)
+ popup_menu = gtk_menu_new ();
+
+ if (*mail == '@')
+ label = g_strdup_printf (_("Allow remote content for anyone from %s"), mail);
+ else
+ label = g_strdup_printf (_("Allow remote content for %s"), mail);
+
+ e_mail_reader_add_remote_content_menu_item (reader, popup_menu, label, TRUE, mail);
+
+ g_free (label);
+ }
+
+ for (link = sites; link; link = g_list_next (link)) {
+ const gchar *site = link->data;
+ gchar *label;
+
+ if (!site || !*site)
+ continue;
+
+ if (!popup_menu)
+ popup_menu = gtk_menu_new ();
+
+ label = g_strdup_printf (_("Allow remote content from %s"), site);
+
+ e_mail_reader_add_remote_content_menu_item (reader, popup_menu, label, FALSE, site);
+
+ g_free (label);
+ }
+
+ g_list_free_full (mails, g_free);
+ g_list_free_full (sites, g_free);
+
+ if (popup_menu) {
+ GtkWidget *box = gtk_widget_get_parent (GTK_WIDGET (toggle_button));
+
+ gtk_toggle_button_set_active (toggle_button, TRUE);
+
+ g_signal_connect (
+ popup_menu, "deactivate",
+ G_CALLBACK (e_mail_reader_remote_content_menu_deactivate_cb), toggle_button);
+
+ gtk_widget_show_all (popup_menu);
+
+ if (event)
+ gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL,
+ e_mail_reader_remote_content_menu_position,
+ box, event->button, event->time);
+ else
+ gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL,
+ e_mail_reader_remote_content_menu_position,
+ box, 0, gtk_get_current_event_time ());
+ }
+}
+
+static gboolean
+e_mail_reader_options_remote_content_button_press_cb (GtkToggleButton *toggle_button,
+ GdkEventButton *event,
+ EMailReader *reader)
+{
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
+
+ if (event && event->button == 1) {
+ e_mail_reader_show_remote_content_popup (reader, event, toggle_button);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GtkWidget *
+e_mail_reader_create_remote_content_alert_button (EMailReader *reader)
+{
+ GtkWidget *box, *button, *arrow;
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+
+ gtk_style_context_add_class (gtk_widget_get_style_context (box), "linked");
+
+ button = gtk_button_new_with_label (_("Load remote content"));
+ gtk_container_add (GTK_CONTAINER (box), button);
+
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (e_mail_reader_load_remote_content_clicked_cb), reader);
+
+ button = gtk_toggle_button_new ();
+ gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
+
+ g_signal_connect (button, "button-press-event",
+ G_CALLBACK (e_mail_reader_options_remote_content_button_press_cb), reader);
+
+ arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+ gtk_container_add (GTK_CONTAINER (button), arrow);
+
+ gtk_widget_show_all (box);
+
+ return box;
+}
+
+static void
+e_mail_reader_load_status_notify_cb (WebKitWebFrame *frame,
+ GParamSpec *param,
+ EMailReader *reader)
+{
+ WebKitLoadStatus load_status;
+ EMailDisplay *mail_display;
+ EMailReaderPrivate *priv;
+
+ g_return_if_fail (WEBKIT_IS_WEB_FRAME (frame));
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ priv = E_MAIL_READER_GET_PRIVATE (reader);
+ g_return_if_fail (priv != NULL);
+
+ load_status = webkit_web_frame_get_load_status (frame);
+ if (load_status == WEBKIT_LOAD_PROVISIONAL) {
+ WebKitWebView *web_view;
+
+ web_view = webkit_web_frame_get_web_view (frame);
+
+ if (priv->remote_content_alert && webkit_web_view_get_main_frame (web_view) == frame)
+ e_alert_response (priv->remote_content_alert, GTK_RESPONSE_CLOSE);
+ return;
+ }
+
+ if (load_status != WEBKIT_LOAD_FINISHED)
+ return;
+
+ mail_display = e_mail_reader_get_mail_display (reader);
+ g_return_if_fail (E_IS_MAIL_DISPLAY (mail_display));
+
+ if (!e_mail_display_has_skipped_remote_content_sites (mail_display))
+ return;
+
+ if (!priv->remote_content_alert) {
+ EPreviewPane *preview_pane;
+ GtkWidget *button;
+ EAlert *alert;
+
+ alert = e_alert_new ("mail:remote-content-info", NULL);
+ button = e_mail_reader_create_remote_content_alert_button (reader);
+ e_alert_add_widget (alert, button); /* button is consumed by the alert */
+ preview_pane = e_mail_reader_get_preview_pane (reader);
+ e_alert_sink_submit_alert (E_ALERT_SINK (preview_pane), alert);
+ g_object_unref (alert);
+
+ priv->remote_content_alert = alert;
+ g_object_add_weak_pointer (G_OBJECT (priv->remote_content_alert),
&priv->remote_content_alert);
+ }
+}
+
+static void
+mail_reader_display_frame_created_cb (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ EMailReader *reader)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (web_view));
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ e_signal_connect_notify (frame, "notify::load-status",
+ G_CALLBACK (e_mail_reader_load_status_notify_cb), reader);
+}
+
+/**
+ * e_mail_reader_connect_remote_content:
+ * @reader: an #EMailReader
+ *
+ * Connects signal handlers to manage remote content download around
+ * the internal #EMailDisplay.
+ **/
+void
+e_mail_reader_connect_remote_content (EMailReader *reader)
+{
+ EMailDisplay *mail_display;
+ WebKitWebFrame *frame;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ mail_display = e_mail_reader_get_mail_display (reader);
+ g_return_if_fail (E_IS_MAIL_DISPLAY (mail_display));
+
+ frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (mail_display));
+
+ e_signal_connect_notify (frame, "notify::load-status",
+ G_CALLBACK (e_mail_reader_load_status_notify_cb), reader);
+
+ g_signal_connect (mail_display, "frame-created",
+ G_CALLBACK (mail_reader_display_frame_created_cb), reader);
+}
diff --git a/mail/e-mail-reader.h b/mail/e-mail-reader.h
index baae723..7dab30b 100644
--- a/mail/e-mail-reader.h
+++ b/mail/e-mail-reader.h
@@ -184,6 +184,8 @@ void e_mail_reader_avoid_next_mark_as_seen
void e_mail_reader_composer_created (EMailReader *reader,
EMsgComposer *composer,
CamelMimeMessage *message);
+void e_mail_reader_connect_remote_content
+ (EMailReader *reader);
G_END_DECLS
diff --git a/mail/e-mail-remote-content.c b/mail/e-mail-remote-content.c
new file mode 100644
index 0000000..b1bcd90
--- /dev/null
+++ b/mail/e-mail-remote-content.c
@@ -0,0 +1,573 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2015 Red Hat Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of version 2.1. of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <camel/camel.h>
+
+#include "e-mail-remote-content.h"
+
+#define CURRENT_VERSION 1
+
+#define RECENT_CACHE_SIZE 10
+
+typedef struct _RecentData {
+ gchar *value;
+ gboolean result;
+} RecentData;
+
+struct _EMailRemoteContentPrivate {
+ CamelDB *db;
+
+ GMutex recent_lock;
+ RecentData recent_mails[RECENT_CACHE_SIZE];
+ RecentData recent_sites[RECENT_CACHE_SIZE];
+ guint recent_last_mails;
+ guint recent_last_sites;
+};
+
+G_DEFINE_TYPE (EMailRemoteContent, e_mail_remote_content, G_TYPE_OBJECT)
+
+static void
+e_mail_remote_content_add_to_recent_cache (EMailRemoteContent *content,
+ const gchar *value,
+ gboolean result,
+ RecentData *recent_cache,
+ guint *recent_last)
+{
+ gint ii, first_free = -1, index;
+
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (content));
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (recent_cache != NULL);
+ g_return_if_fail (recent_last != NULL);
+
+ g_mutex_lock (&content->priv->recent_lock);
+
+ for (ii = 0; ii < RECENT_CACHE_SIZE; ii++) {
+ index = (*recent_last + ii) % RECENT_CACHE_SIZE;
+
+ if (!recent_cache[index].value) {
+ if (first_free == -1)
+ first_free = index;
+ } else if (g_ascii_strcasecmp (recent_cache[index].value, value) == 0) {
+ recent_cache[index].result = result;
+ break;
+ }
+ }
+
+ if (ii == RECENT_CACHE_SIZE) {
+ if (first_free != -1) {
+ g_warn_if_fail (recent_cache[first_free].value == NULL);
+ recent_cache[first_free].value = g_strdup (value);
+ recent_cache[first_free].result = result;
+
+ if (first_free == (*recent_last + 1) % RECENT_CACHE_SIZE)
+ *recent_last = first_free;
+ } else {
+ index = (*recent_last + 1) % RECENT_CACHE_SIZE;
+
+ g_free (recent_cache[index].value);
+ recent_cache[index].value = g_strdup (value);
+ recent_cache[index].result = result;
+
+ *recent_last = index;
+ }
+ }
+
+ g_mutex_unlock (&content->priv->recent_lock);
+}
+
+static void
+e_mail_remote_content_add (EMailRemoteContent *content,
+ const gchar *table,
+ const gchar *value,
+ RecentData *recent_cache,
+ guint *recent_last)
+{
+ gchar *stmt;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (content));
+ g_return_if_fail (table != NULL);
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (recent_cache != NULL);
+ g_return_if_fail (recent_last != NULL);
+
+ e_mail_remote_content_add_to_recent_cache (content, value, TRUE, recent_cache, recent_last);
+
+ if (!content->priv->db)
+ return;
+
+ stmt = sqlite3_mprintf ("INSERT OR IGNORE INTO %Q ('value') VALUES (lower(%Q))", table, value);
+ camel_db_command (content->priv->db, stmt, &error);
+ sqlite3_free (stmt);
+
+ if (error) {
+ g_warning ("%s: Failed to add to '%s' value '%s': %s", G_STRFUNC, table, value,
error->message);
+ g_clear_error (&error);
+ }
+}
+
+static void
+e_mail_remote_content_remove (EMailRemoteContent *content,
+ const gchar *table,
+ const gchar *value,
+ RecentData *recent_cache,
+ guint *recent_last)
+{
+ gchar *stmt;
+ gint ii;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (content));
+ g_return_if_fail (table != NULL);
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (recent_cache != NULL);
+ g_return_if_fail (recent_last != NULL);
+
+ g_mutex_lock (&content->priv->recent_lock);
+
+ for (ii = 0; ii < RECENT_CACHE_SIZE; ii++) {
+ gint index = (*recent_last + ii) % RECENT_CACHE_SIZE;
+
+ if (recent_cache[index].value && g_ascii_strcasecmp (recent_cache[index].value, value) == 0) {
+ g_free (recent_cache[index].value);
+ recent_cache[index].value = NULL;
+ break;
+ }
+ }
+
+ g_mutex_unlock (&content->priv->recent_lock);
+
+ if (!content->priv->db)
+ return;
+
+ stmt = sqlite3_mprintf ("DELETE FROM %Q WHERE value=lower(%Q)", table, value);
+ camel_db_command (content->priv->db, stmt, &error);
+ sqlite3_free (stmt);
+
+ if (error) {
+ g_warning ("%s: Failed to remove from '%s' value '%s': %s", G_STRFUNC, table, value,
error->message);
+ g_clear_error (&error);
+ }
+}
+
+static gint
+e_mail_remote_content_check_found_cb (gpointer data,
+ gint ncol,
+ gchar **colvalues,
+ gchar **colnames)
+{
+ gboolean *pfound = data;
+
+ if (pfound)
+ *pfound = TRUE;
+
+ return 0;
+}
+
+static gboolean
+e_mail_remote_content_has (EMailRemoteContent *content,
+ const gchar *table,
+ const GSList *values,
+ RecentData *recent_cache,
+ guint *recent_last)
+{
+ GString *stmt;
+ gint ii;
+ gchar *tmp;
+ const GSList *link;
+ gboolean found = FALSE;
+
+ g_return_val_if_fail (E_IS_MAIL_REMOTE_CONTENT (content), FALSE);
+ g_return_val_if_fail (table != NULL, FALSE);
+ g_return_val_if_fail (values != NULL, FALSE);
+ g_return_val_if_fail (recent_cache != NULL, FALSE);
+ g_return_val_if_fail (recent_last != NULL, FALSE);
+
+ g_mutex_lock (&content->priv->recent_lock);
+
+ for (link = values; link; link = g_slist_next (link)) {
+ const gchar *value = link->data;
+
+ for (ii = 0; ii < RECENT_CACHE_SIZE; ii++) {
+ gint index = (*recent_last + ii) % RECENT_CACHE_SIZE;
+
+ if (recent_cache[index].value && g_ascii_strcasecmp (recent_cache[index].value,
value) == 0) {
+ found = recent_cache[index].result;
+ g_mutex_unlock (&content->priv->recent_lock);
+
+ return found;
+ }
+ }
+ }
+
+ g_mutex_unlock (&content->priv->recent_lock);
+
+ if (!content->priv->db)
+ return FALSE;
+
+ stmt = g_string_new ("");
+
+ for (link = values; link; link = g_slist_next (link)) {
+ const gchar *value = link->data;
+
+ if (!value || !*value)
+ continue;
+
+ if (stmt->len)
+ g_string_append (stmt, " OR ");
+
+ tmp = sqlite3_mprintf ("value=lower(%Q)", value);
+ g_string_append (stmt, tmp);
+ sqlite3_free (tmp);
+ }
+
+ if (stmt->len) {
+ tmp = sqlite3_mprintf ("SELECT value FROM %Q WHERE ", table);
+ g_string_prepend (stmt, tmp);
+ sqlite3_free (tmp);
+
+ g_string_append (stmt, " LIMIT 1");
+
+ camel_db_select (content->priv->db, stmt->str, e_mail_remote_content_check_found_cb, &found,
NULL);
+ }
+
+ g_string_free (stmt, TRUE);
+
+ for (link = values; link; link = g_slist_next (link)) {
+ const gchar *value = link->data;
+
+ e_mail_remote_content_add_to_recent_cache (content, value, found, recent_cache, recent_last);
+ }
+
+ return found;
+}
+
+static gint
+e_mail_remote_content_get_values_cb (gpointer data,
+ gint ncol,
+ gchar **colvalues,
+ gchar **colnames)
+{
+ GHashTable *values_hash = data;
+
+ if (values_hash && colvalues && colvalues[0])
+ g_hash_table_insert (values_hash, g_strdup (colvalues[0]), NULL);
+
+ return 0;
+}
+
+static GSList *
+e_mail_remote_content_get (EMailRemoteContent *content,
+ const gchar *table,
+ RecentData *recent_cache,
+ guint *recent_last)
+{
+ GHashTable *values_hash;
+ GHashTableIter iter;
+ GSList *values = NULL;
+ gpointer itr_key, itr_value;
+ gint ii;
+
+ g_return_val_if_fail (E_IS_MAIL_REMOTE_CONTENT (content), NULL);
+ g_return_val_if_fail (table != NULL, NULL);
+ g_return_val_if_fail (recent_cache != NULL, NULL);
+ g_return_val_if_fail (recent_last != NULL, NULL);
+
+ values_hash = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, NULL);
+
+ g_mutex_lock (&content->priv->recent_lock);
+
+ for (ii = 0; ii < RECENT_CACHE_SIZE; ii++) {
+ gint index = (*recent_last + ii) % RECENT_CACHE_SIZE;
+
+ if (recent_cache[index].value && recent_cache[index].result) {
+ g_hash_table_insert (values_hash, g_strdup (recent_cache[index].value), NULL);
+ }
+ }
+
+ g_mutex_unlock (&content->priv->recent_lock);
+
+ if (content->priv->db) {
+ gchar *stmt;
+
+ stmt = sqlite3_mprintf ("SELECT value FROM %Q ORDER BY value", table);
+ camel_db_select (content->priv->db, stmt, e_mail_remote_content_get_values_cb, values_hash,
NULL);
+ sqlite3_free (stmt);
+ }
+
+ g_hash_table_iter_init (&iter, values_hash);
+
+ while (g_hash_table_iter_next (&iter, &itr_key, &itr_value)) {
+ const gchar *value = itr_key;
+
+ if (value && *value)
+ values = g_slist_prepend (values, g_strdup (value));
+ }
+
+ g_hash_table_destroy (values_hash);
+
+ return g_slist_reverse (values);
+}
+
+static gint
+e_mail_remote_content_get_version_cb (gpointer data,
+ gint ncol,
+ gchar **colvalues,
+ gchar **colnames)
+{
+ gint *pversion = data;
+
+ if (pversion && ncol == 1 && colvalues && colvalues[0])
+ *pversion = (gint) g_ascii_strtoll (colvalues[0], NULL, 10);
+
+ return 0;
+}
+
+static void
+e_mail_remote_content_set_config_filename (EMailRemoteContent *content,
+ const gchar *config_filename)
+{
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (content));
+ g_return_if_fail (config_filename != NULL);
+ g_return_if_fail (content->priv->db == NULL);
+
+ content->priv->db = camel_db_open (config_filename, &error);
+
+ if (error) {
+ g_warning ("%s: Failed to open '%s': %s", G_STRFUNC, config_filename, error->message);
+ g_clear_error (&error);
+ }
+
+ if (content->priv->db) {
+ #define ctb(stmt) G_STMT_START { \
+ if (content->priv->db) { \
+ camel_db_command (content->priv->db, stmt, &error); \
+ if (error) { \
+ g_warning ("%s: Failed to execute '%s' on '%s': %s", \
+ G_STRFUNC, stmt, config_filename, error->message); \
+ g_clear_error (&error); \
+ } \
+ } \
+ } G_STMT_END
+
+ ctb ("CREATE TABLE IF NOT EXISTS version (current INT)");
+ ctb ("CREATE TABLE IF NOT EXISTS sites (value TEXT PRIMARY KEY)");
+ ctb ("CREATE TABLE IF NOT EXISTS mails (value TEXT PRIMARY KEY)");
+
+ #undef ctb
+ }
+
+ if (content->priv->db) {
+ gint version = -1;
+ gchar *stmt;
+
+ camel_db_select (content->priv->db, "SELECT 'current' FROM 'version'",
e_mail_remote_content_get_version_cb, &version, NULL);
+
+ if (version != -1 && version < CURRENT_VERSION) {
+ /* Here will be added migration code, if needed in the future */
+ }
+
+ stmt = sqlite3_mprintf ("DELETE FROM %Q", "version");
+ camel_db_command (content->priv->db, stmt, NULL);
+ sqlite3_free (stmt);
+
+ stmt = sqlite3_mprintf ("INSERT INTO %Q ('current') VALUES (%d);", "version",
CURRENT_VERSION);
+ camel_db_command (content->priv->db, stmt, NULL);
+ sqlite3_free (stmt);
+ }
+}
+
+static void
+mail_remote_content_finalize (GObject *object)
+{
+ EMailRemoteContent *content;
+ gint ii;
+
+ content = E_MAIL_REMOTE_CONTENT (object);
+
+ if (content->priv->db) {
+ GError *error = NULL;
+
+ camel_db_maybe_run_maintenance (content->priv->db, &error);
+
+ if (error) {
+ g_warning ("%s: Failed to tun maintenance: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ }
+
+ camel_db_close (content->priv->db);
+ content->priv->db = NULL;
+ }
+
+ g_mutex_lock (&content->priv->recent_lock);
+
+ for (ii = 0; ii < RECENT_CACHE_SIZE; ii++) {
+ g_free (content->priv->recent_sites[ii].value);
+ g_free (content->priv->recent_mails[ii].value);
+
+ content->priv->recent_sites[ii].value = NULL;
+ content->priv->recent_mails[ii].value = NULL;
+ }
+
+ g_mutex_unlock (&content->priv->recent_lock);
+ g_mutex_clear (&content->priv->recent_lock);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_mail_remote_content_parent_class)->finalize (object);
+}
+
+static void
+e_mail_remote_content_class_init (EMailRemoteContentClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EMailRemoteContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = mail_remote_content_finalize;
+}
+
+static void
+e_mail_remote_content_init (EMailRemoteContent *content)
+{
+ content->priv = G_TYPE_INSTANCE_GET_PRIVATE (content, E_TYPE_MAIL_REMOTE_CONTENT,
EMailRemoteContentPrivate);
+
+ g_mutex_init (&content->priv->recent_lock);
+}
+
+EMailRemoteContent *
+e_mail_remote_content_new (const gchar *config_filename)
+{
+ EMailRemoteContent *content;
+
+ content = g_object_new (E_TYPE_MAIL_REMOTE_CONTENT, NULL);
+
+ if (config_filename != NULL)
+ e_mail_remote_content_set_config_filename (content, config_filename);
+
+ return content;
+}
+
+void
+e_mail_remote_content_add_site (EMailRemoteContent *content,
+ const gchar *site)
+{
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (content));
+ g_return_if_fail (site != NULL);
+
+ e_mail_remote_content_add (content, "sites", site, content->priv->recent_sites,
&content->priv->recent_last_sites);
+}
+
+void
+e_mail_remote_content_remove_site (EMailRemoteContent *content,
+ const gchar *site)
+{
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (content));
+ g_return_if_fail (site != NULL);
+
+ e_mail_remote_content_remove (content, "sites", site, content->priv->recent_sites,
&content->priv->recent_last_sites);
+}
+
+gboolean
+e_mail_remote_content_has_site (EMailRemoteContent *content,
+ const gchar *site)
+{
+ GSList *values = NULL;
+ gboolean result;
+
+ g_return_val_if_fail (E_IS_MAIL_REMOTE_CONTENT (content), FALSE);
+ g_return_val_if_fail (site != NULL, FALSE);
+
+ values = g_slist_prepend (values, (gpointer) site);
+
+ result = e_mail_remote_content_has (content, "sites", values, content->priv->recent_sites,
&content->priv->recent_last_sites);
+
+ g_slist_free (values);
+
+ return result;
+}
+
+/* Free the result with g_slist_free_full (values, g_free); */
+GSList *
+e_mail_remote_content_get_sites (EMailRemoteContent *content)
+{
+ g_return_val_if_fail (E_IS_MAIL_REMOTE_CONTENT (content), NULL);
+
+ return e_mail_remote_content_get (content, "sites", content->priv->recent_sites,
&content->priv->recent_last_sites);
+}
+
+void
+e_mail_remote_content_add_mail (EMailRemoteContent *content,
+ const gchar *mail)
+{
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (content));
+ g_return_if_fail (mail != NULL);
+
+ e_mail_remote_content_add (content, "mails", mail, content->priv->recent_mails,
&content->priv->recent_last_mails);
+}
+
+void
+e_mail_remote_content_remove_mail (EMailRemoteContent *content,
+ const gchar *mail)
+{
+ g_return_if_fail (E_IS_MAIL_REMOTE_CONTENT (content));
+ g_return_if_fail (mail != NULL);
+
+ e_mail_remote_content_remove (content, "mails", mail, content->priv->recent_mails,
&content->priv->recent_last_mails);
+}
+
+gboolean
+e_mail_remote_content_has_mail (EMailRemoteContent *content,
+ const gchar *mail)
+{
+ GSList *values = NULL;
+ const gchar *at;
+ gboolean result;
+
+ g_return_val_if_fail (E_IS_MAIL_REMOTE_CONTENT (content), FALSE);
+ g_return_val_if_fail (mail != NULL, FALSE);
+
+ values = g_slist_append (values, (gpointer) mail);
+ at = strchr (mail, '@');
+ if (at)
+ values = g_slist_prepend (values, (gpointer) at);
+
+ result = e_mail_remote_content_has (content, "mails", values, content->priv->recent_mails,
&content->priv->recent_last_mails);
+
+ g_slist_free (values);
+
+ return result;
+}
+
+/* Free the result with g_slist_free_full (values, g_free); */
+GSList *
+e_mail_remote_content_get_mails (EMailRemoteContent *content)
+{
+ g_return_val_if_fail (E_IS_MAIL_REMOTE_CONTENT (content), NULL);
+
+ return e_mail_remote_content_get (content, "mails", content->priv->recent_mails,
&content->priv->recent_last_mails);
+}
diff --git a/mail/e-mail-remote-content.h b/mail/e-mail-remote-content.h
new file mode 100644
index 0000000..a4fe4d9
--- /dev/null
+++ b/mail/e-mail-remote-content.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2015 Red Hat Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of version 2.1. of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_MAIL_REMOTE_CONTENT_H
+#define E_MAIL_REMOTE_CONTENT_H
+
+#include <glib-object.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_REMOTE_CONTENT \
+ (e_mail_remote_content_get_type ())
+#define E_MAIL_REMOTE_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_REMOTE_CONTENT, EMailRemoteContent))
+#define E_MAIL_REMOTE_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_REMOTE_CONTENT, EMailRemoteContentClass))
+#define E_IS_MAIL_REMOTE_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_REMOTE_CONTENT))
+#define E_IS_MAIL_REMOTE_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_REMOTE_CONTENT))
+#define E_MAIL_REMOTE_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_REMOTE_CONTENT, EMailRemoteContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailRemoteContent EMailRemoteContent;
+typedef struct _EMailRemoteContentClass EMailRemoteContentClass;
+typedef struct _EMailRemoteContentPrivate EMailRemoteContentPrivate;
+
+struct _EMailRemoteContent {
+ GObject parent;
+ EMailRemoteContentPrivate *priv;
+};
+
+struct _EMailRemoteContentClass {
+ GObjectClass parent_class;
+};
+
+GType e_mail_remote_content_get_type (void) G_GNUC_CONST;
+EMailRemoteContent *
+ e_mail_remote_content_new (const gchar *config_filename);
+void e_mail_remote_content_add_site (EMailRemoteContent *content,
+ const gchar *site);
+void e_mail_remote_content_remove_site
+ (EMailRemoteContent *content,
+ const gchar *site);
+gboolean e_mail_remote_content_has_site (EMailRemoteContent *content,
+ const gchar *site);
+GSList * e_mail_remote_content_get_sites (EMailRemoteContent *content);
+void e_mail_remote_content_add_mail (EMailRemoteContent *content,
+ const gchar *mail);
+void e_mail_remote_content_remove_mail
+ (EMailRemoteContent *content,
+ const gchar *mail);
+gboolean e_mail_remote_content_has_mail (EMailRemoteContent *content,
+ const gchar *mail);
+GSList * e_mail_remote_content_get_mails (EMailRemoteContent *content);
+
+G_END_DECLS
+
+#endif /* E_MAIL_REMOTE_CONTENT_H */
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index 4874995..f7180e4 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -1090,12 +1090,16 @@ em_utils_composer_print_cb (EMsgComposer *composer,
EMailParser *parser;
EMailPartList *parts, *reserved_parts;
EMailPrinter *printer;
+ EMailBackend *mail_backend;
const gchar *message_id;
GCancellable *cancellable;
CamelObjectBag *parts_registry;
gchar *mail_uri;
PrintAsyncContext async_context;
+ mail_backend = E_MAIL_BACKEND (e_shell_get_backend_by_name (e_msg_composer_get_shell (composer),
"mail"));
+ g_return_if_fail (mail_backend != NULL);
+
cancellable = e_activity_get_cancellable (activity);
parser = e_mail_parser_new (CAMEL_SESSION (session));
@@ -1114,7 +1118,7 @@ em_utils_composer_print_cb (EMsgComposer *composer,
camel_object_bag_add (parts_registry, mail_uri, parts);
- printer = e_mail_printer_new (parts);
+ printer = e_mail_printer_new (parts, e_mail_backend_get_remote_content (mail_backend));
async_context.error = NULL;
async_context.main_loop = g_main_loop_new (NULL, FALSE);
diff --git a/mail/em-utils.c b/mail/em-utils.c
index 88b845b..30432bb 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -475,12 +475,16 @@ em_utils_print_messages_to_file (CamelFolder *folder,
parts_list = e_mail_parser_parse_sync (
parser, folder, uid, message, NULL);
if (parts_list != NULL) {
+ EMailBackend *mail_backend;
EAsyncClosure *closure;
GAsyncResult *result;
EMailPrinter *printer;
GtkPrintOperationResult print_result;
- printer = e_mail_printer_new (parts_list);
+ mail_backend = E_MAIL_BACKEND (e_shell_get_backend_by_name (e_shell_get_default (), "mail"));
+ g_return_val_if_fail (mail_backend != NULL, FALSE);
+
+ printer = e_mail_printer_new (parts_list, e_mail_backend_get_remote_content (mail_backend));
e_mail_printer_set_export_filename (printer, filename);
closure = e_async_closure_new ();
diff --git a/mail/mail-config.ui b/mail/mail-config.ui
index fff639a..98d2e34 100644
--- a/mail/mail-config.ui
+++ b/mail/mail-config.ui
@@ -1,6 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
<interface>
- <!-- interface-requires gtk+ 3.0 -->
+ <requires lib="gtk+" version="3.0"/>
+ <object class="GtkListStore" id="RCMailsListStore">
+ <columns>
+ <!-- column-name Mails -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkListStore" id="RCSitesListStore">
+ <columns>
+ <!-- column-name Site -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
<object class="GtkDialog" id="add-custom-junk-header">
<property name="width_request">400</property>
<property name="can_focus">False</property>
@@ -2254,7 +2267,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Loading Images</property>
+ <property name="label" translatable="yes">Loading Remote Content</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -2277,7 +2290,7 @@
<property name="spacing">6</property>
<child>
<object class="GtkRadioButton" id="radImagesNever">
- <property name="label" translatable="yes">_Never load images from the
Internet</property>
+ <property name="label" translatable="yes">_Never load remote content from the
Internet</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -2294,7 +2307,7 @@
</child>
<child>
<object class="GtkRadioButton" id="radImagesSometimes">
- <property name="label" translatable="yes">_Load images only in messages from
contacts</property>
+ <property name="label" translatable="yes">_Load remote content only in messages from
contacts</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -2312,7 +2325,7 @@
</child>
<child>
<object class="GtkRadioButton" id="radImagesAlways">
- <property name="label" translatable="yes">_Always load images from the
Internet</property>
+ <property name="label" translatable="yes">_Always load remote content from the
Internet</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -2344,6 +2357,216 @@
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkBox" id="RCAllowBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">12</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="baseline_position">top</property>
+ <child>
+ <object class="GtkGrid" id="RCSitesGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">2</property>
+ <child>
+ <object class="GtkEntry" id="RCSitesEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="RCSitesAddBtn">
+ <property name="label" translatable="yes">Add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="RCSitesRemoveBtn">
+ <property name="label" translatable="yes">Remove</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="RCSitesLbl">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Allow for sites:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="RCSitesScrWnd">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="RCSitesTreeView">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">RCSitesListStore</property>
+ <property name="headers_visible">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection10">
+ <property name="mode">multiple</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="RCAllowSeparator">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">2</property>
+ <property name="margin_right">2</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="RCMailsGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="row_spacing">2</property>
+ <child>
+ <object class="GtkEntry" id="RCMailsEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="RCMailsAddBtn">
+ <property name="label" translatable="yes">Add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">start</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="RCMailsRemoveBtn">
+ <property name="label" translatable="yes">Remove</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="RCMailsLbl">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Allow for senders:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="RCMailsScrWnd">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="RCMailsTreeView">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">RCMailsListStore</property>
+ <property name="headers_visible">False</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection11">
+ <property name="mode">multiple</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="position">1</property>
@@ -2988,13 +3211,13 @@
<property name="position">1</property>
</packing>
</child>
- </object>
- <packing>
- <property name="top_attach">6</property>
- <property name="bottom_attach">7</property>
- <property name="x_padding">12</property>
- </packing>
- </child>
+ </object>
+ <packing>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="x_padding">12</property>
+ </packing>
+ </child>
<child>
<object class="EMailJunkOptions" id="junk-module-options">
<property name="visible">True</property>
@@ -3021,11 +3244,15 @@
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="y_options">GTK_FILL</property>
- <property name="x_padding">0</property>
<property name="y_padding">12</property>
</packing>
</child>
</object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
<packing>
diff --git a/mail/mail.error.xml b/mail/mail.error.xml
index 1535e83..ec81430 100644
--- a/mail/mail.error.xml
+++ b/mail/mail.error.xml
@@ -568,5 +568,10 @@ in the folder will be available in offline mode.</_secondary>
<_primary>Failed to unmark subthread from being ignored in folder '{0}'</_primary>
<secondary>{1}</secondary>
</error>
+
+ <error id="remote-content-info" type="info">
+ <_primary>Remote content download had been blocked for this message.</_primary>
+ <_secondary>You can download remote content manually, or set to remember to download remote content for
this sender or used sites.</_secondary>
+ </error>
</error-list>
diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c
index 32abe63..1878283 100644
--- a/modules/mail/e-mail-shell-backend.c
+++ b/modules/mail/e-mail-shell-backend.c
@@ -81,11 +81,15 @@ mbox_create_preview_cb (GObject *preview,
GtkWidget **preview_widget)
{
EMailDisplay *display;
+ EMailBackend *mail_backend;
g_return_if_fail (preview != NULL);
g_return_if_fail (preview_widget != NULL);
- display = g_object_new (E_TYPE_MAIL_DISPLAY, NULL);
+ mail_backend = E_MAIL_BACKEND (e_shell_get_backend_by_name (e_shell_get_default (), BACKEND_NAME));
+ g_return_if_fail (mail_backend != NULL);
+
+ display = E_MAIL_DISPLAY (e_mail_display_new (e_mail_backend_get_remote_content (mail_backend)));
g_object_set_data_full (
preview, "mbox-imp-display",
g_object_ref (display), g_object_unref);
diff --git a/modules/mail/em-mailer-prefs.c b/modules/mail/em-mailer-prefs.c
index 81284c1..86894e6 100644
--- a/modules/mail/em-mailer-prefs.c
+++ b/modules/mail/em-mailer-prefs.c
@@ -83,6 +83,65 @@ static const struct {
{ N_("Immediately, on folder leave"), -1 }
};
+#define RC_SECTION_KEY "evolution-rc-section-key"
+#define RC_ENTRY_KEY "evolution-rc-entry-key"
+#define RC_TREEVIEW_KEY "evolution-rc-treeview-key"
+
+enum {
+ RC_SECTION_SITES = 1,
+ RC_SECTION_MAILS = 2
+};
+
+struct _EMMailerPrefsPrivate {
+ GtkBuilder *builder;
+ GSettings *settings;
+ EMailBackend *mail_backend;
+
+ /* General tab */
+
+ /* Message Display */
+ GtkSpinButton *timeout;
+
+ /* HTML Mail tab */
+ GtkFontButton *font_variable;
+ GtkFontButton *font_fixed;
+ GtkToggleButton *font_share;
+
+ GtkToggleButton *autodetect_links;
+
+ /* Labels and Colours tab */
+ GtkWidget *label_add;
+ GtkWidget *label_edit;
+ GtkWidget *label_remove;
+ GtkWidget *label_tree;
+ GtkListStore *label_list_store;
+
+ /* Headers tab */
+ GtkButton *add_header;
+ GtkButton *remove_header;
+ GtkEntry *entry_header;
+ GtkTreeView *header_list;
+ GtkListStore *header_list_store;
+
+ GtkToggleButton *junk_header_check;
+ GtkTreeView *junk_header_tree;
+ GtkListStore *junk_header_list_store;
+ GtkButton *junk_header_add;
+ GtkButton *junk_header_remove;
+ GtkToggleButton *junk_book_lookup;
+ GtkToggleButton *junk_lookup_local_only;
+
+ /* Remote Content section */
+ GtkWidget *rc_sites_entry;
+ GtkWidget *rc_sites_add_btn;
+ GtkWidget *rc_sites_tree_view;
+ GtkWidget *rc_sites_remove_btn;
+ GtkWidget *rc_mails_entry;
+ GtkWidget *rc_mails_add_btn;
+ GtkWidget *rc_mails_tree_view;
+ GtkWidget *rc_mails_remove_btn;
+};
+
G_DEFINE_TYPE (
EMMailerPrefs,
em_mailer_prefs,
@@ -93,8 +152,8 @@ em_mailer_prefs_finalize (GObject *object)
{
EMMailerPrefs *prefs = (EMMailerPrefs *) object;
- g_object_unref (prefs->builder);
- g_object_unref (prefs->settings);
+ g_object_unref (prefs->priv->builder);
+ g_object_unref (prefs->priv->settings);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (em_mailer_prefs_parent_class)->finalize (object);
@@ -105,6 +164,8 @@ em_mailer_prefs_class_init (EMMailerPrefsClass *class)
{
GObjectClass *object_class;
+ g_type_class_add_private (class, sizeof (EMMailerPrefsPrivate));
+
object_class = G_OBJECT_CLASS (class);
object_class->finalize = em_mailer_prefs_finalize;
}
@@ -112,7 +173,8 @@ em_mailer_prefs_class_init (EMMailerPrefsClass *class)
static void
em_mailer_prefs_init (EMMailerPrefs *preferences)
{
- preferences->settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ preferences->priv = G_TYPE_INSTANCE_GET_PRIVATE (preferences, EM_TYPE_MAILER_PREFS,
EMMailerPrefsPrivate);
+ preferences->priv->settings = e_util_ref_settings ("org.gnome.evolution.mail");
}
static gboolean
@@ -197,11 +259,11 @@ enum {
static void
jh_tree_refill (EMMailerPrefs *prefs)
{
- GtkListStore *store = prefs->junk_header_list_store;
+ GtkListStore *store = prefs->priv->junk_header_list_store;
gchar **strv;
gint ii;
- strv = g_settings_get_strv (prefs->settings, "junk-custom-header");
+ strv = g_settings_get_strv (prefs->priv->settings, "junk-custom-header");
gtk_list_store_clear (store);
@@ -273,14 +335,14 @@ jh_add_cb (GtkWidget *widget,
name = gtk_entry_get_text (GTK_ENTRY (e_builder_get_widget (builder, "junk-header-name")));
value = gtk_entry_get_text (GTK_ENTRY (e_builder_get_widget (builder,
"junk-header-content")));
- strv = g_settings_get_strv (prefs->settings, "junk-custom-header");
+ strv = g_settings_get_strv (prefs->priv->settings, "junk-custom-header");
array = g_ptr_array_new ();
for (ii = 0; strv[ii] != NULL; ii++)
g_ptr_array_add (array, strv[ii]);
tok = g_strdup_printf ("%s=%s", name, value);
g_ptr_array_add (array, tok);
g_ptr_array_add (array, NULL);
- g_settings_set_strv (prefs->settings, "junk-custom-header", (const gchar * const *)
array->pdata);
+ g_settings_set_strv (prefs->priv->settings, "junk-custom-header", (const gchar * const *)
array->pdata);
g_ptr_array_free (array, TRUE);
g_strfreev (strv);
@@ -303,14 +365,14 @@ jh_remove_cb (GtkWidget *widget,
g_return_if_fail (prefs != NULL);
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->junk_header_tree));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->priv->junk_header_tree));
if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
GPtrArray *array = g_ptr_array_new ();
gchar *name = NULL, *value = NULL;
gchar **strv;
gint ii;
- strv = g_settings_get_strv (prefs->settings, "junk-custom-header");
+ strv = g_settings_get_strv (prefs->priv->settings, "junk-custom-header");
gtk_tree_model_get (model, &iter, JH_LIST_COLUMN_NAME, &name, JH_LIST_COLUMN_VALUE, &value,
-1);
for (ii = 0; strv[ii] != NULL; ii++) {
gchar *test;
@@ -328,7 +390,7 @@ jh_remove_cb (GtkWidget *widget,
g_ptr_array_add (array, NULL);
- g_settings_set_strv (prefs->settings, "junk-custom-header", (const gchar * const *)
array->pdata);
+ g_settings_set_strv (prefs->priv->settings, "junk-custom-header", (const gchar * const *)
array->pdata);
g_strfreev (strv);
g_ptr_array_free (array, TRUE);
@@ -367,7 +429,7 @@ static void
emmp_header_remove_sensitivity (EMMailerPrefs *prefs)
{
GtkTreeIter iter;
- GtkTreeSelection *selection = gtk_tree_view_get_selection (prefs->header_list);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (prefs->priv->header_list);
gboolean is_default;
/* remove button should be sensitive if the currenlty selected entry in the list view
@@ -376,15 +438,15 @@ emmp_header_remove_sensitivity (EMMailerPrefs *prefs)
*/
if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
gtk_tree_model_get (
- GTK_TREE_MODEL (prefs->header_list_store), &iter,
+ GTK_TREE_MODEL (prefs->priv->header_list_store), &iter,
HEADER_LIST_IS_DEFAULT_COLUMN, &is_default,
-1);
if (is_default)
- gtk_widget_set_sensitive (GTK_WIDGET (prefs->remove_header), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->priv->remove_header), FALSE);
else
- gtk_widget_set_sensitive (GTK_WIDGET (prefs->remove_header), TRUE);
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->priv->remove_header), TRUE);
} else {
- gtk_widget_set_sensitive (GTK_WIDGET (prefs->remove_header), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->priv->remove_header), FALSE);
}
}
@@ -412,33 +474,33 @@ emmp_header_add_sensitivity (EMMailerPrefs *prefs)
* a valid header string, that is not a duplicate with something already
* in the list view
*/
- entry_contents = gtk_entry_get_text (GTK_ENTRY (prefs->entry_header));
+ entry_contents = gtk_entry_get_text (GTK_ENTRY (prefs->priv->entry_header));
if (!emmp_header_is_valid (entry_contents)) {
- gtk_widget_set_sensitive (GTK_WIDGET (prefs->add_header), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->priv->add_header), FALSE);
return;
}
/* check if this is a duplicate */
- valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (prefs->header_list_store), &iter);
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (prefs->priv->header_list_store), &iter);
while (valid) {
gchar *header_name;
gtk_tree_model_get (
- GTK_TREE_MODEL (prefs->header_list_store), &iter,
+ GTK_TREE_MODEL (prefs->priv->header_list_store), &iter,
HEADER_LIST_HEADER_COLUMN, &header_name,
-1);
if (g_ascii_strcasecmp (header_name, entry_contents) == 0) {
- gtk_widget_set_sensitive (GTK_WIDGET (prefs->add_header), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->priv->add_header), FALSE);
g_free (header_name);
return;
}
g_free (header_name);
- valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->header_list_store), &iter);
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (prefs->priv->header_list_store), &iter);
}
- gtk_widget_set_sensitive (GTK_WIDGET (prefs->add_header), TRUE);
+ gtk_widget_set_sensitive (GTK_WIDGET (prefs->priv->add_header), TRUE);
}
static void
@@ -452,7 +514,7 @@ emmp_save_headers (EMMailerPrefs *prefs)
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sb)"));
- model = GTK_TREE_MODEL (prefs->header_list_store);
+ model = GTK_TREE_MODEL (prefs->priv->header_list_store);
valid = gtk_tree_model_get_iter_first (model, &iter);
while (valid) {
@@ -475,7 +537,7 @@ emmp_save_headers (EMMailerPrefs *prefs)
}
variant = g_variant_builder_end (&builder);
- g_settings_set_value (prefs->settings, "show-headers", variant);
+ g_settings_set_value (prefs->priv->settings, "show-headers", variant);
}
static void
@@ -483,7 +545,7 @@ emmp_header_list_enabled_toggled (GtkCellRendererToggle *cell,
const gchar *path_string,
EMMailerPrefs *prefs)
{
- GtkTreeModel *model = GTK_TREE_MODEL (prefs->header_list_store);
+ GtkTreeModel *model = GTK_TREE_MODEL (prefs->priv->header_list_store);
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
GtkTreeIter iter;
gint enabled;
@@ -505,9 +567,9 @@ static void
emmp_header_add_header (GtkWidget *widget,
EMMailerPrefs *prefs)
{
- GtkTreeModel *model = GTK_TREE_MODEL (prefs->header_list_store);
+ GtkTreeModel *model = GTK_TREE_MODEL (prefs->priv->header_list_store);
GtkTreeIter iter;
- const gchar *text = gtk_entry_get_text (prefs->entry_header);
+ const gchar *text = gtk_entry_get_text (prefs->priv->entry_header);
g_strstrip ((gchar *) text);
@@ -520,7 +582,7 @@ emmp_header_add_header (GtkWidget *widget,
HEADER_LIST_HEADER_COLUMN, text,
HEADER_LIST_IS_DEFAULT_COLUMN, FALSE,
-1);
- gtk_entry_set_text (prefs->entry_header, "");
+ gtk_entry_set_text (prefs->priv->entry_header, "");
emmp_header_remove_sensitivity (prefs);
emmp_header_add_sensitivity (prefs);
@@ -533,11 +595,11 @@ emmp_header_remove_header (GtkWidget *button,
gpointer user_data)
{
EMMailerPrefs *prefs = (EMMailerPrefs *) user_data;
- GtkTreeModel *model = GTK_TREE_MODEL (prefs->header_list_store);
+ GtkTreeModel *model = GTK_TREE_MODEL (prefs->priv->header_list_store);
GtkTreeSelection *selection;
GtkTreeIter iter;
- selection = gtk_tree_view_get_selection (prefs->header_list);
+ selection = gtk_tree_view_get_selection (prefs->priv->header_list);
if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
return;
@@ -574,7 +636,7 @@ toggle_button_toggled (GtkToggleButton *toggle,
key = g_object_get_data ((GObject *) toggle, "key");
g_settings_set_boolean (
- prefs->settings, key,
+ prefs->priv->settings, key,
gtk_toggle_button_get_active (toggle));
}
@@ -584,7 +646,7 @@ junk_book_lookup_button_toggled (GtkToggleButton *toggle,
{
toggle_button_toggled (toggle, prefs);
gtk_widget_set_sensitive (
- GTK_WIDGET (prefs->junk_lookup_local_only),
+ GTK_WIDGET (prefs->priv->junk_lookup_local_only),
gtk_toggle_button_get_active (toggle));
}
@@ -594,13 +656,13 @@ custom_junk_button_toggled (GtkToggleButton *toggle,
{
toggle_button_toggled (toggle, prefs);
if (gtk_toggle_button_get_active (toggle)) {
- gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_remove, TRUE);
- gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_add, TRUE);
- gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_tree, TRUE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->junk_header_remove, TRUE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->junk_header_add, TRUE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->junk_header_tree, TRUE);
} else {
- gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_tree, FALSE);
- gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_add, FALSE);
- gtk_widget_set_sensitive ((GtkWidget *) prefs->junk_header_remove, FALSE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->junk_header_tree, FALSE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->junk_header_add, FALSE);
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->junk_header_remove, FALSE);
}
}
@@ -614,7 +676,7 @@ toggle_button_init (EMMailerPrefs *prefs,
{
gboolean v_bool;
- v_bool = g_settings_get_boolean (prefs->settings, key);
+ v_bool = g_settings_get_boolean (prefs->priv->settings, key);
gtk_toggle_button_set_active (toggle, not ? !v_bool : v_bool);
if (toggled) {
@@ -623,7 +685,7 @@ toggle_button_init (EMMailerPrefs *prefs,
toggle, "toggled", toggled, prefs);
}
- if (!g_settings_is_writable (prefs->settings, key))
+ if (!g_settings_is_writable (prefs->priv->settings, key))
gtk_widget_set_sensitive (GTK_WIDGET (toggle), FALSE);
}
@@ -638,7 +700,7 @@ trash_days_changed (GtkComboBox *combo_box,
g_return_if_fail (index < G_N_ELEMENTS (empty_trash_frequency));
g_settings_set_int (
- prefs->settings,
+ prefs->priv->settings,
"trash-empty-on-exit-days",
empty_trash_frequency[index].days);
}
@@ -652,7 +714,7 @@ emmp_empty_trash_init (EMMailerPrefs *prefs,
GtkTreeIter iter;
days = g_settings_get_int (
- prefs->settings,
+ prefs->priv->settings,
"trash-empty-on-exit-days");
store = GTK_LIST_STORE (gtk_combo_box_get_model (combo_box));
@@ -688,7 +750,7 @@ junk_days_changed (GtkComboBox *combo_box,
g_return_if_fail (index < G_N_ELEMENTS (empty_trash_frequency));
g_settings_set_int (
- prefs->settings,
+ prefs->priv->settings,
"junk-empty-on-exit-days",
empty_trash_frequency[index].days);
}
@@ -702,7 +764,7 @@ emmp_empty_junk_init (EMMailerPrefs *prefs,
GtkTreeIter iter;
days = g_settings_get_int (
- prefs->settings,
+ prefs->priv->settings,
"junk-empty-on-exit-days");
store = GTK_LIST_STORE (gtk_combo_box_get_model (combo_box));
@@ -785,7 +847,7 @@ emmp_widget_glade (EConfig *ec,
{
EMMailerPrefs *prefs = data;
- return e_builder_get_widget (prefs->builder, item->label);
+ return e_builder_get_widget (prefs->priv->builder, item->label);
}
/* plugin meta-data */
@@ -817,9 +879,262 @@ emmp_free (EConfig *ec,
}
static void
+rc_entry_changed_cb (GtkEntry *entry,
+ GtkWidget *add_btn)
+{
+ const gchar *text;
+
+ text = gtk_entry_get_text (entry);
+
+ if (text && *text) {
+ gint ii;
+
+ for (ii = 0; text[ii]; ii++) {
+ if (text[ii] > 0 && text[ii] <= 32) {
+ /* It contains invalid letter */
+ text = NULL;
+ break;
+ }
+ }
+ }
+
+ gtk_widget_set_sensitive (add_btn, text && *text);
+}
+
+static void
+rc_add_btn_clicked_cb (GObject *button,
+ EMMailerPrefs *prefs)
+{
+ gint rc_section;
+ GtkEntry *entry;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean done, found = FALSE;
+ gchar *text;
+
+ g_return_if_fail (GTK_IS_BUTTON (button));
+ g_return_if_fail (EM_IS_MAILER_PREFS (prefs));
+
+ rc_section = GPOINTER_TO_INT (g_object_get_data (button, RC_SECTION_KEY));
+ entry = g_object_get_data (button, RC_ENTRY_KEY);
+ tree_view = g_object_get_data (button, RC_TREEVIEW_KEY);
+
+ g_return_if_fail (GTK_IS_ENTRY (entry));
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ text = g_strdup (gtk_entry_get_text (entry));
+ if (!text || !*text) {
+ g_free (text);
+ gtk_entry_set_text (entry, "");
+ return;
+ }
+
+ model = gtk_tree_view_get_model (tree_view);
+ done = !gtk_tree_model_get_iter_first (model, &iter);
+ while (!done && !found) {
+ gchar *stored = NULL;
+
+ gtk_tree_model_get (model, &iter, 0, &stored, -1);
+ if (stored && *stored) {
+ found = g_ascii_strcasecmp (stored, text) == 0;
+ }
+
+ g_free (stored);
+
+ done = !gtk_tree_model_iter_next (model, &iter);
+ }
+
+ if (!found) {
+ EMailRemoteContent *remote_content;
+
+ remote_content = e_mail_backend_get_remote_content (prefs->priv->mail_backend);
+
+ if (rc_section == RC_SECTION_SITES)
+ e_mail_remote_content_add_site (remote_content, text);
+ else
+ e_mail_remote_content_add_mail (remote_content, text);
+
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, text, -1);
+ }
+
+ g_free (text);
+ gtk_entry_set_text (entry, "");
+}
+
+static void
+rc_tree_view_selection_changed_cb (GtkTreeSelection *selection,
+ GtkWidget *remove_btn)
+{
+ gtk_widget_set_sensitive (remove_btn, gtk_tree_selection_count_selected_rows (selection) > 0);
+}
+
+static void
+rc_remove_btn_clicked_cb (GObject *button,
+ EMMailerPrefs *prefs)
+{
+ gint rc_section;
+ EMailRemoteContent *remote_content;
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GList *selected, *link, *references = NULL;
+
+ g_return_if_fail (GTK_IS_BUTTON (button));
+ g_return_if_fail (EM_IS_MAILER_PREFS (prefs));
+
+ rc_section = GPOINTER_TO_INT (g_object_get_data (button, RC_SECTION_KEY));
+ tree_view = g_object_get_data (button, RC_TREEVIEW_KEY);
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ model = gtk_tree_view_get_model (tree_view);
+ selection = gtk_tree_view_get_selection (tree_view);
+ remote_content = e_mail_backend_get_remote_content (prefs->priv->mail_backend);
+
+ selected = gtk_tree_selection_get_selected_rows (selection, NULL);
+ for (link = selected; link; link = g_list_next (link)) {
+ GtkTreePath *path = link->data;
+
+ references = g_list_prepend (references, gtk_tree_row_reference_new (model, path));
+ }
+
+ g_list_free_full (selected, (GDestroyNotify) gtk_tree_path_free);
+
+ for (link = references; link; link = g_list_next (link)) {
+ GtkTreeRowReference *reference = link->data;
+ gchar *value = NULL;
+
+ if (!gtk_tree_row_reference_valid (reference) ||
+ !gtk_tree_model_get_iter (model, &iter, gtk_tree_row_reference_get_path (reference)))
+ continue;
+
+ gtk_tree_model_get (model, &iter, 0, &value, -1);
+
+ if (!value)
+ continue;
+
+ if (rc_section == RC_SECTION_SITES)
+ e_mail_remote_content_remove_site (remote_content, value);
+ else
+ e_mail_remote_content_remove_mail (remote_content, value);
+
+ g_free (value);
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ }
+
+ g_list_free_full (references, (GDestroyNotify) gtk_tree_row_reference_free);
+}
+
+static void
+em_mailer_prefs_fill_remote_content_section (EMMailerPrefs *prefs,
+ gint rc_section)
+{
+ EMailRemoteContent *remote_content;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkListStore *list_store;
+ GSList *values, *link;
+
+ g_return_if_fail (EM_IS_MAILER_PREFS (prefs));
+ g_return_if_fail (rc_section == RC_SECTION_SITES || rc_section == RC_SECTION_MAILS);
+
+ remote_content = e_mail_backend_get_remote_content (prefs->priv->mail_backend);
+
+ if (rc_section == RC_SECTION_SITES) {
+ values = e_mail_remote_content_get_sites (remote_content);
+ tree_view = GTK_TREE_VIEW (prefs->priv->rc_sites_tree_view);
+ } else {
+ values = e_mail_remote_content_get_mails (remote_content);
+ tree_view = GTK_TREE_VIEW (prefs->priv->rc_mails_tree_view);
+ }
+
+ model = gtk_tree_view_get_model (tree_view);
+ list_store = GTK_LIST_STORE (model);
+
+ gtk_list_store_clear (list_store);
+
+ for (link = values; link; link = g_slist_next (link)) {
+ const gchar *value = link->data;
+
+ if (!value)
+ continue;
+
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter, 0, value, -1);
+ }
+
+ g_slist_free_full (values, g_free);
+}
+
+static void
+em_mailer_prefs_setup_remote_content_section (EMMailerPrefs *prefs,
+ gint rc_section,
+ GtkWidget *entry,
+ GtkWidget *add_btn,
+ GtkWidget *tree_view,
+ GtkWidget *remove_btn)
+{
+ GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
+
+ g_return_if_fail (EM_IS_MAILER_PREFS (prefs));
+ g_return_if_fail (rc_section == RC_SECTION_SITES || rc_section == RC_SECTION_MAILS);
+ g_return_if_fail (GTK_IS_ENTRY (entry));
+ g_return_if_fail (GTK_IS_BUTTON (add_btn));
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ g_return_if_fail (GTK_IS_BUTTON (remove_btn));
+
+ g_object_set_data (G_OBJECT (add_btn), RC_SECTION_KEY, GINT_TO_POINTER (rc_section));
+ g_object_set_data (G_OBJECT (add_btn), RC_ENTRY_KEY, entry);
+ g_object_set_data (G_OBJECT (add_btn), RC_TREEVIEW_KEY, tree_view);
+ g_object_set_data (G_OBJECT (remove_btn), RC_SECTION_KEY, GINT_TO_POINTER (rc_section));
+ g_object_set_data (G_OBJECT (remove_btn), RC_TREEVIEW_KEY, tree_view);
+
+ em_mailer_prefs_fill_remote_content_section (prefs, rc_section);
+
+ rc_entry_changed_cb (GTK_ENTRY (entry), add_btn);
+ g_signal_connect (entry, "changed", G_CALLBACK (rc_entry_changed_cb), add_btn);
+ g_signal_connect (add_btn, "clicked", G_CALLBACK (rc_add_btn_clicked_cb), prefs);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ rc_tree_view_selection_changed_cb (selection, remove_btn);
+ g_signal_connect (selection, "changed", G_CALLBACK (rc_tree_view_selection_changed_cb), remove_btn);
+ g_signal_connect (remove_btn, "clicked", G_CALLBACK (rc_remove_btn_clicked_cb), prefs);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (
+ GTK_TREE_VIEW (tree_view), -1, "Value", renderer,
+ "text", 0,
+ NULL);
+}
+
+static void
+em_mailer_prefs_window_notify_visible_cb (EPreferencesWindow *preferences,
+ GParamSpec *param,
+ EMMailerPrefs *prefs)
+{
+ g_return_if_fail (EM_IS_MAILER_PREFS (prefs));
+
+ if (!gtk_widget_get_visible (GTK_WIDGET (preferences)))
+ return;
+
+ /* The EMailRemoteContent doesn't have any 'changed' signal, thus update
+ the inner tree view content on the preferences window show. */
+ em_mailer_prefs_fill_remote_content_section (prefs, RC_SECTION_SITES);
+ em_mailer_prefs_fill_remote_content_section (prefs, RC_SECTION_MAILS);
+}
+
+static void
em_mailer_prefs_construct (EMMailerPrefs *prefs,
EMailSession *session,
- EShell *shell)
+ EShell *shell,
+ EMailBackend *backend)
{
GSettings *settings;
GHashTable *default_header_hash;
@@ -845,8 +1160,9 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
* GType before we load the GtkBuilder definition file. */
g_type_ensure (E_TYPE_MAIL_JUNK_OPTIONS);
- prefs->builder = gtk_builder_new ();
- e_load_ui_builder_definition (prefs->builder, "mail-config.ui");
+ prefs->priv->mail_backend = backend;
+ prefs->priv->builder = gtk_builder_new ();
+ e_load_ui_builder_definition (prefs->priv->builder, "mail-config.ui");
/** @HookPoint-EMConfig: Mail Preferences Page
* @Id: org.gnome.evolution.mail.prefs
@@ -863,13 +1179,13 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
/* General tab */
- widget = e_builder_get_widget (prefs->builder, "chkCheckMailOnStart");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkCheckMailOnStart");
g_settings_bind (
settings, "send-recv-on-start",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "chkCheckMailInAllOnStart");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkCheckMailInAllOnStart");
g_settings_bind (
settings, "send-recv-all-on-start",
widget, "active",
@@ -881,7 +1197,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
/* Message Display */
- widget = e_builder_get_widget (prefs->builder, "chkMarkTimeout");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkMarkTimeout");
g_settings_bind (
settings, "mark-seen",
widget, "active",
@@ -890,7 +1206,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
/* The "mark seen" timeout requires special transform functions
* because we display the timeout value to the user in seconds
* but store the settings value in milliseconds. */
- widget = e_builder_get_widget (prefs->builder, "spinMarkTimeout");
+ widget = e_builder_get_widget (prefs->priv->builder, "spinMarkTimeout");
g_settings_bind_with_mapping (
settings, "mark-seen-timeout",
widget, "value",
@@ -903,17 +1219,17 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
widget, "sensitive",
G_SETTINGS_BIND_GET);
- widget = e_builder_get_widget (prefs->builder, "view-check");
+ widget = e_builder_get_widget (prefs->priv->builder, "view-check");
g_settings_bind (
settings, "global-view-setting",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
widget = e_charset_combo_box_new ();
- container = e_builder_get_widget (prefs->builder, "hboxDefaultCharset");
+ container = e_builder_get_widget (prefs->priv->builder, "hboxDefaultCharset");
gtk_label_set_mnemonic_widget (
GTK_LABEL (e_builder_get_widget (
- prefs->builder, "lblDefaultCharset")), widget);
+ prefs->priv->builder, "lblDefaultCharset")), widget);
gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
g_settings_bind (
@@ -921,13 +1237,13 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
widget, "charset",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "chkHighlightCitations");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkHighlightCitations");
g_settings_bind (
settings, "mark-citations",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "colorButtonHighlightCitations");
+ widget = e_builder_get_widget (prefs->priv->builder, "colorButtonHighlightCitations");
g_settings_bind_with_mapping (
settings, "citation-color",
widget, "rgba",
@@ -940,41 +1256,41 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
widget, "sensitive",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "thread-by-subject");
+ widget = e_builder_get_widget (prefs->priv->builder, "thread-by-subject");
g_settings_bind (
settings, "thread-subject",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
/* Deleting Mail */
- widget = e_builder_get_widget (prefs->builder, "chkEmptyTrashOnExit");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkEmptyTrashOnExit");
g_settings_bind (
settings, "trash-empty-on-exit",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "comboboxEmptyTrashDays");
+ widget = e_builder_get_widget (prefs->priv->builder, "comboboxEmptyTrashDays");
g_settings_bind (
settings, "trash-empty-on-exit",
widget, "sensitive",
G_SETTINGS_BIND_GET);
emmp_empty_trash_init (prefs, GTK_COMBO_BOX (widget));
- widget = e_builder_get_widget (prefs->builder, "chkConfirmExpunge");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkConfirmExpunge");
g_settings_bind (
settings, "prompt-on-expunge",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
/* Mail Fonts */
- widget = e_builder_get_widget (prefs->builder, "radFontUseSame");
+ widget = e_builder_get_widget (prefs->priv->builder, "radFontUseSame");
g_settings_bind (
settings, "use-custom-font",
widget, "active",
G_SETTINGS_BIND_DEFAULT |
G_SETTINGS_BIND_INVERT_BOOLEAN);
- widget = e_builder_get_widget (prefs->builder, "FontFixed");
+ widget = e_builder_get_widget (prefs->priv->builder, "FontFixed");
g_settings_bind (
settings, "monospace-font",
widget, "font-name",
@@ -984,7 +1300,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
widget, "sensitive",
G_SETTINGS_BIND_GET);
- widget = e_builder_get_widget (prefs->builder, "FontVariable");
+ widget = e_builder_get_widget (prefs->priv->builder, "FontVariable");
g_settings_bind (
settings, "variable-width-font",
widget, "font-name",
@@ -998,11 +1314,11 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
/* Loading Images */
writable = g_settings_is_writable (
- prefs->settings, "image-loading-policy");
+ prefs->priv->settings, "image-loading-policy");
- val = g_settings_get_enum (prefs->settings, "image-loading-policy");
+ val = g_settings_get_enum (prefs->priv->settings, "image-loading-policy");
widget = e_builder_get_widget (
- prefs->builder, "radImagesNever");
+ prefs->priv->builder, "radImagesNever");
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (widget),
val == E_IMAGE_LOADING_POLICY_NEVER);
@@ -1013,7 +1329,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
G_CALLBACK (image_loading_policy_never_cb), NULL);
widget = e_builder_get_widget (
- prefs->builder, "radImagesSometimes");
+ prefs->priv->builder, "radImagesSometimes");
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (widget),
val == E_IMAGE_LOADING_POLICY_SOMETIMES);
@@ -1024,7 +1340,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
G_CALLBACK (image_loading_policy_sometimes_cb), NULL);
widget = e_builder_get_widget (
- prefs->builder, "radImagesAlways");
+ prefs->priv->builder, "radImagesAlways");
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (widget),
val == E_IMAGE_LOADING_POLICY_ALWAYS);
@@ -1034,19 +1350,19 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
widget, "toggled",
G_CALLBACK (image_loading_policy_always_cb), NULL);
- widget = e_builder_get_widget (prefs->builder, "chkShowAnimatedImages");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkShowAnimatedImages");
g_settings_bind (
settings, "show-animated-images",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "chkPromptWantHTML");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkPromptWantHTML");
g_settings_bind (
settings, "prompt-on-unwanted-html",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
- container = e_builder_get_widget (prefs->builder, "labels-alignment");
+ container = e_builder_get_widget (prefs->priv->builder, "labels-alignment");
widget = e_mail_label_manager_new ();
gtk_container_add (GTK_CONTAINER (container), widget);
gtk_widget_show (widget);
@@ -1057,15 +1373,15 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
G_BINDING_SYNC_CREATE);
/* headers */
- locked = !g_settings_is_writable (prefs->settings, "headers");
+ locked = !g_settings_is_writable (prefs->priv->settings, "headers");
- widget = e_builder_get_widget (prefs->builder, "photo_show");
+ widget = e_builder_get_widget (prefs->priv->builder, "photo_show");
g_settings_bind (
settings, "show-sender-photo",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "search_gravatar");
+ widget = e_builder_get_widget (prefs->priv->builder, "search_gravatar");
g_settings_bind (
settings, "search-gravatar-for-photo",
widget, "active",
@@ -1075,10 +1391,10 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
widget, "sensitive",
G_SETTINGS_BIND_GET);
- container = e_builder_get_widget (prefs->builder, "archive-mail-hbox");
+ container = e_builder_get_widget (prefs->priv->builder, "archive-mail-hbox");
widget = em_folder_selection_button_new (session, "", _("Choose a folder to archive messages to."));
gtk_widget_set_hexpand (widget, FALSE);
- gtk_label_set_mnemonic_widget (GTK_LABEL (e_builder_get_widget (prefs->builder,
"lblArchiveMailFolder")), widget);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (e_builder_get_widget (prefs->priv->builder,
"lblArchiveMailFolder")), widget);
gtk_container_add (GTK_CONTAINER (container), widget);
gtk_widget_show (widget);
@@ -1088,38 +1404,38 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
G_SETTINGS_BIND_DEFAULT);
/* always de-sensitised until the user types something in the entry */
- prefs->add_header = GTK_BUTTON (e_builder_get_widget (prefs->builder, "cmdHeadersAdd"));
- gtk_widget_set_sensitive ((GtkWidget *) prefs->add_header, FALSE);
+ prefs->priv->add_header = GTK_BUTTON (e_builder_get_widget (prefs->priv->builder, "cmdHeadersAdd"));
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->add_header, FALSE);
/* always de-sensitised until the user selects a header in the list */
- prefs->remove_header = GTK_BUTTON (e_builder_get_widget (prefs->builder, "cmdHeadersRemove"));
- gtk_widget_set_sensitive ((GtkWidget *) prefs->remove_header, FALSE);
+ prefs->priv->remove_header = GTK_BUTTON (e_builder_get_widget (prefs->priv->builder,
"cmdHeadersRemove"));
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->remove_header, FALSE);
- prefs->entry_header = GTK_ENTRY (e_builder_get_widget (prefs->builder, "txtHeaders"));
- gtk_widget_set_sensitive ((GtkWidget *) prefs->entry_header, !locked);
+ prefs->priv->entry_header = GTK_ENTRY (e_builder_get_widget (prefs->priv->builder, "txtHeaders"));
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->entry_header, !locked);
- prefs->header_list = GTK_TREE_VIEW (e_builder_get_widget (prefs->builder, "treeHeaders"));
- gtk_widget_set_sensitive ((GtkWidget *) prefs->header_list, !locked);
+ prefs->priv->header_list = GTK_TREE_VIEW (e_builder_get_widget (prefs->priv->builder, "treeHeaders"));
+ gtk_widget_set_sensitive ((GtkWidget *) prefs->priv->header_list, !locked);
- selection = gtk_tree_view_get_selection (prefs->header_list);
+ selection = gtk_tree_view_get_selection (prefs->priv->header_list);
g_signal_connect (
selection, "changed",
G_CALLBACK (emmp_header_list_row_selected), prefs);
g_signal_connect (
- prefs->entry_header, "changed",
+ prefs->priv->entry_header, "changed",
G_CALLBACK (emmp_header_entry_changed), prefs);
g_signal_connect (
- prefs->entry_header,
+ prefs->priv->entry_header,
"activate", G_CALLBACK (emmp_header_add_header), prefs);
/* initialise the tree with appropriate headings */
- prefs->header_list_store = gtk_list_store_newv (HEADER_LIST_N_COLUMNS, col_types);
+ prefs->priv->header_list_store = gtk_list_store_newv (HEADER_LIST_N_COLUMNS, col_types);
g_signal_connect (
- prefs->add_header, "clicked",
+ prefs->priv->add_header, "clicked",
G_CALLBACK (emmp_header_add_header), prefs);
g_signal_connect (
- prefs->remove_header, "clicked",
+ prefs->priv->remove_header, "clicked",
G_CALLBACK (emmp_header_remove_header), prefs);
- gtk_tree_view_set_model (prefs->header_list, GTK_TREE_MODEL (prefs->header_list_store));
+ gtk_tree_view_set_model (prefs->priv->header_list, GTK_TREE_MODEL (prefs->priv->header_list_store));
renderer = gtk_cell_renderer_toggle_new ();
g_object_set (renderer, "activatable", TRUE, NULL);
@@ -1127,13 +1443,13 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
renderer, "toggled",
G_CALLBACK (emmp_header_list_enabled_toggled), prefs);
gtk_tree_view_insert_column_with_attributes (
- GTK_TREE_VIEW (prefs->header_list), -1,
+ GTK_TREE_VIEW (prefs->priv->header_list), -1,
"Enabled", renderer,
"active", HEADER_LIST_ENABLED_COLUMN,
NULL);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (
- GTK_TREE_VIEW (prefs->header_list), -1,
+ GTK_TREE_VIEW (prefs->priv->header_list), -1,
"Name", renderer,
"text", HEADER_LIST_NAME_COLUMN,
NULL);
@@ -1153,7 +1469,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
(GDestroyNotify) g_free,
(GDestroyNotify) gtk_tree_path_free);
- tree_model = GTK_TREE_MODEL (prefs->header_list_store);
+ tree_model = GTK_TREE_MODEL (prefs->priv->header_list_store);
for (ii = 0; ii < G_N_ELEMENTS (default_headers); ii++) {
GtkTreeIter iter;
@@ -1186,7 +1502,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
gtk_tree_model_get_path (tree_model, &iter));
}
- variant = g_settings_get_value (prefs->settings, "show-headers");
+ variant = g_settings_get_value (prefs->priv->settings, "show-headers");
n_children = g_variant_n_children (variant);
for (ii = 0; ii < n_children; ii++) {
@@ -1229,7 +1545,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
g_hash_table_destroy (default_header_hash);
/* date/time format */
- table = e_builder_get_widget (prefs->builder, "datetime-format-table");
+ table = e_builder_get_widget (prefs->priv->builder, "datetime-format-table");
/* To Translators: 'Table column' is a label for configurable date/time format for table columns
showing a date in message list */
e_datetime_format_add_setup_widget (table, 0, "mail", "table", DTFormatKindDateTime, _("_Table
column:"));
/* To Translators: 'Date header' is a label for configurable date/time format for 'Date' header in
mail message window/preview */
@@ -1243,61 +1559,83 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs,
G_SETTINGS_BIND_DEFAULT);
/* Junk prefs */
- widget = e_builder_get_widget (prefs->builder, "chkCheckIncomingMail");
+ widget = e_builder_get_widget (prefs->priv->builder, "chkCheckIncomingMail");
g_settings_bind (
settings, "junk-check-incoming",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "junk_empty_check");
+ widget = e_builder_get_widget (prefs->priv->builder, "junk_empty_check");
g_settings_bind (
settings, "junk-empty-on-exit",
widget, "active",
G_SETTINGS_BIND_DEFAULT);
- widget = e_builder_get_widget (prefs->builder, "junk_empty_combobox");
+ widget = e_builder_get_widget (prefs->priv->builder, "junk_empty_combobox");
emmp_empty_junk_init (prefs, GTK_COMBO_BOX (widget));
g_settings_bind (
settings, "junk-empty-on-exit",
widget, "sensitive",
G_SETTINGS_BIND_GET);
- widget = e_builder_get_widget (prefs->builder, "junk-module-options");
+ widget = e_builder_get_widget (prefs->priv->builder, "junk-module-options");
e_mail_junk_options_set_session (E_MAIL_JUNK_OPTIONS (widget), session);
- prefs->junk_header_check = (GtkToggleButton *) e_builder_get_widget (prefs->builder,
"junk_header_check");
- prefs->junk_header_tree = (GtkTreeView *) e_builder_get_widget (prefs->builder, "junk_header_tree");
- prefs->junk_header_add = (GtkButton *) e_builder_get_widget (prefs->builder, "junk_header_add");
- prefs->junk_header_remove = (GtkButton *) e_builder_get_widget (prefs->builder, "junk_header_remove");
- prefs->junk_book_lookup = (GtkToggleButton *) e_builder_get_widget (prefs->builder, "lookup_book");
- prefs->junk_lookup_local_only = (GtkToggleButton *) e_builder_get_widget (prefs->builder,
"junk_lookup_local_only");
+ prefs->priv->junk_header_check = (GtkToggleButton *) e_builder_get_widget (prefs->priv->builder,
"junk_header_check");
+ prefs->priv->junk_header_tree = (GtkTreeView *) e_builder_get_widget (prefs->priv->builder,
"junk_header_tree");
+ prefs->priv->junk_header_add = (GtkButton *) e_builder_get_widget (prefs->priv->builder,
"junk_header_add");
+ prefs->priv->junk_header_remove = (GtkButton *) e_builder_get_widget (prefs->priv->builder,
"junk_header_remove");
+ prefs->priv->junk_book_lookup = (GtkToggleButton *) e_builder_get_widget (prefs->priv->builder,
"lookup_book");
+ prefs->priv->junk_lookup_local_only = (GtkToggleButton *) e_builder_get_widget (prefs->priv->builder,
"junk_lookup_local_only");
toggle_button_init (
- prefs, prefs->junk_book_lookup,
+ prefs, prefs->priv->junk_book_lookup,
FALSE, "junk-lookup-addressbook",
G_CALLBACK (junk_book_lookup_button_toggled));
toggle_button_init (
- prefs, prefs->junk_lookup_local_only,
+ prefs, prefs->priv->junk_lookup_local_only,
FALSE, "junk-lookup-addressbook-local-only",
G_CALLBACK (toggle_button_toggled));
- junk_book_lookup_button_toggled (prefs->junk_book_lookup, prefs);
+ junk_book_lookup_button_toggled (prefs->priv->junk_book_lookup, prefs);
- prefs->junk_header_list_store = init_junk_tree ((GtkWidget *) prefs->junk_header_tree, prefs);
+ prefs->priv->junk_header_list_store = init_junk_tree ((GtkWidget *) prefs->priv->junk_header_tree,
prefs);
toggle_button_init (
- prefs, prefs->junk_header_check,
+ prefs, prefs->priv->junk_header_check,
FALSE, "junk-check-custom-header",
G_CALLBACK (custom_junk_button_toggled));
- custom_junk_button_toggled (prefs->junk_header_check, prefs);
+ custom_junk_button_toggled (prefs->priv->junk_header_check, prefs);
jh_tree_refill (prefs);
g_signal_connect (
- prefs->junk_header_add, "clicked",
+ prefs->priv->junk_header_add, "clicked",
G_CALLBACK (jh_add_cb), prefs);
g_signal_connect (
- prefs->junk_header_remove, "clicked",
+ prefs->priv->junk_header_remove, "clicked",
G_CALLBACK (jh_remove_cb), prefs);
+ /* Remote Content section */
+ prefs->priv->rc_sites_entry = e_builder_get_widget (prefs->priv->builder, "RCSitesEntry");
+ prefs->priv->rc_sites_add_btn = e_builder_get_widget (prefs->priv->builder, "RCSitesAddBtn");
+ prefs->priv->rc_sites_tree_view = e_builder_get_widget (prefs->priv->builder, "RCSitesTreeView");
+ prefs->priv->rc_sites_remove_btn = e_builder_get_widget (prefs->priv->builder, "RCSitesRemoveBtn");
+ prefs->priv->rc_mails_entry = e_builder_get_widget (prefs->priv->builder, "RCMailsEntry");
+ prefs->priv->rc_mails_add_btn = e_builder_get_widget (prefs->priv->builder, "RCMailsAddBtn");
+ prefs->priv->rc_mails_tree_view = e_builder_get_widget (prefs->priv->builder, "RCMailsTreeView");
+ prefs->priv->rc_mails_remove_btn = e_builder_get_widget (prefs->priv->builder, "RCMailsRemoveBtn");
+
+ em_mailer_prefs_setup_remote_content_section (prefs, RC_SECTION_SITES,
+ prefs->priv->rc_sites_entry,
+ prefs->priv->rc_sites_add_btn,
+ prefs->priv->rc_sites_tree_view,
+ prefs->priv->rc_sites_remove_btn);
+
+ em_mailer_prefs_setup_remote_content_section (prefs, RC_SECTION_MAILS,
+ prefs->priv->rc_mails_entry,
+ prefs->priv->rc_mails_add_btn,
+ prefs->priv->rc_mails_tree_view,
+ prefs->priv->rc_mails_remove_btn);
+
/* get our toplevel widget */
target = em_config_target_new_prefs (ec);
e_config_set_target ((EConfig *) ec, (EConfigTarget *) target);
@@ -1326,7 +1664,9 @@ em_mailer_prefs_new (EPreferencesWindow *window)
new = g_object_new (EM_TYPE_MAILER_PREFS, NULL);
/* FIXME Kill this function. */
- em_mailer_prefs_construct (new, session, shell);
+ em_mailer_prefs_construct (new, session, shell, backend);
+
+ g_signal_connect (window, "notify::visible", G_CALLBACK (em_mailer_prefs_window_notify_visible_cb),
new);
return GTK_WIDGET (new);
}
diff --git a/modules/mail/em-mailer-prefs.h b/modules/mail/em-mailer-prefs.h
index 6aa8b31..9ce6f23 100644
--- a/modules/mail/em-mailer-prefs.h
+++ b/modules/mail/em-mailer-prefs.h
@@ -49,46 +49,12 @@ G_BEGIN_DECLS
typedef struct _EMMailerPrefs EMMailerPrefs;
typedef struct _EMMailerPrefsClass EMMailerPrefsClass;
+typedef struct _EMMailerPrefsPrivate EMMailerPrefsPrivate;
struct _EMMailerPrefs {
GtkBox parent_object;
- GtkBuilder *builder;
- GSettings *settings;
-
- /* General tab */
-
- /* Message Display */
- GtkSpinButton *timeout;
-
- /* HTML Mail tab */
- GtkFontButton *font_variable;
- GtkFontButton *font_fixed;
- GtkToggleButton *font_share;
-
- GtkToggleButton *autodetect_links;
-
- /* Labels and Colours tab */
- GtkWidget *label_add;
- GtkWidget *label_edit;
- GtkWidget *label_remove;
- GtkWidget *label_tree;
- GtkListStore *label_list_store;
-
- /* Headers tab */
- GtkButton *add_header;
- GtkButton *remove_header;
- GtkEntry *entry_header;
- GtkTreeView *header_list;
- GtkListStore *header_list_store;
-
- GtkToggleButton *junk_header_check;
- GtkTreeView *junk_header_tree;
- GtkListStore *junk_header_list_store;
- GtkButton *junk_header_add;
- GtkButton *junk_header_remove;
- GtkToggleButton *junk_book_lookup;
- GtkToggleButton *junk_lookup_local_only;
+ EMMailerPrefsPrivate *priv;
};
struct _EMMailerPrefsClass {
diff --git a/modules/prefer-plain/plugin/config-ui.c b/modules/prefer-plain/plugin/config-ui.c
index 9d8b730..b8424b9 100644
--- a/modules/prefer-plain/plugin/config-ui.c
+++ b/modules/prefer-plain/plugin/config-ui.c
@@ -130,6 +130,8 @@ prefer_plain_page_factory (EPlugin *epl,
info = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (info), 0.0, 0.5);
gtk_label_set_line_wrap (GTK_LABEL (info), TRUE);
+ gtk_label_set_width_chars (GTK_LABEL (info), 40);
+ gtk_label_set_max_width_chars (GTK_LABEL (info), 60);
gtk_widget_show (info);
update_info_label (info, epp_mode);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]