[evolution/wip/webkit2] Convert secure button from widget to a native HTML code
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/webkit2] Convert secure button from widget to a native HTML code
- Date: Wed, 18 May 2016 18:02:36 +0000 (UTC)
commit 0b1a78ba9668f3ba0f4ab511c82cd89b1eedaa64
Author: Milan Crha <mcrha redhat com>
Date: Wed May 18 20:00:10 2016 +0200
Convert secure button from widget to a native HTML code
Also provide generic RegisterElementClicked method and ElementClicked
signal for the EWebView's web extension, which are used by
e_web_view_register_element_clicked() function and its
counter part e_web_view_unregister_element_clicked(), even the later
is only for completeness, rather than being meant to be used.
e-util/e-web-view.c | 231 ++++++++++++++++
e-util/e-web-view.h | 16 ++
em-format/Makefile.am | 2 +
em-format/e-mail-formatter-secure-button.c | 358 ++++---------------------
em-format/e-mail-parser-application-smime.c | 2 +-
em-format/e-mail-parser-inlinepgp-encrypted.c | 2 +-
em-format/e-mail-parser-inlinepgp-signed.c | 2 +-
em-format/e-mail-parser-multipart-encrypted.c | 2 +-
em-format/e-mail-parser-multipart-signed.c | 2 +-
em-format/e-mail-parser-secure-button.c | 5 +-
em-format/e-mail-part-secure-button.c | 321 ++++++++++++++++++++++
em-format/e-mail-part-secure-button.h | 61 +++++
em-format/e-mail-part.c | 15 +
em-format/e-mail-part.h | 4 +
mail/e-mail-display.c | 14 +-
po/POTFILES.in | 1 +
web-extensions/e-web-extension.c | 111 ++++++++-
17 files changed, 837 insertions(+), 312 deletions(-)
---
diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c
index 62e6361..d734403 100644
--- a/e-util/e-web-view.c
+++ b/e-util/e-web-view.c
@@ -54,6 +54,11 @@ typedef enum {
typedef struct _AsyncContext AsyncContext;
+typedef struct _ElementClickedData {
+ EWebViewElementClickedFunc callback;
+ gpointer user_data;
+} ElementClickedData;
+
struct _EWebViewPrivate {
GtkUIManager *ui_manager;
gchar *selected_uri;
@@ -94,6 +99,9 @@ struct _EWebViewPrivate {
gboolean has_hover_link;
GSList *content_requests; /* EContentRequest * */
+
+ GHashTable *element_clicked_cbs; /* gchar *element_class ~> GPtrArray {ElementClickedData} */
+ guint web_extension_element_clicked_signal_id;
};
struct _AsyncContext {
@@ -748,6 +756,9 @@ web_view_load_changed_cb (WebKitWebView *webkit_web_view,
}
}
+ if (load_event == WEBKIT_LOAD_STARTED)
+ g_hash_table_remove_all (web_view->priv->element_clicked_cbs);
+
if (load_event != WEBKIT_LOAD_FINISHED)
return;
@@ -999,6 +1010,15 @@ web_view_dispose (GObject *object)
priv->failed_to_find_text_handler_id = 0;
}
+ if (priv->web_extension && priv->web_extension_element_clicked_signal_id) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (priv->web_extension),
+ priv->web_extension_element_clicked_signal_id);
+ priv->web_extension_element_clicked_signal_id = 0;
+ }
+
+ g_hash_table_remove_all (priv->element_clicked_cbs);
+
g_slist_free_full (priv->content_requests, g_object_unref);
priv->content_requests = NULL;
@@ -1032,6 +1052,8 @@ web_view_finalize (GObject *object)
priv->old_settings = NULL;
}
+ g_hash_table_destroy (priv->element_clicked_cbs);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_web_view_parent_class)->finalize (object);
}
@@ -1456,6 +1478,81 @@ web_view_stop_loading (EWebView *web_view)
}
static void
+web_view_register_element_clicked_hfunc (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ const gchar *elem_class = key;
+ EWebView *web_view = user_data;
+
+ g_return_if_fail (elem_class && *elem_class);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (!web_view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ web_view->priv->web_extension,
+ "RegisterElementClicked",
+ g_variant_new (
+ "(ts)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+ elem_class),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+web_view_element_clicked_signal_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ EWebView *web_view = user_data;
+ const gchar *elem_class = NULL, *elem_value = NULL;
+ GtkAllocation elem_position;
+ guint64 page_id = 0;
+ gint position_left = 0, position_top = 0, position_width = 0, position_height = 0;
+ GPtrArray *listeners;
+
+ if (g_strcmp0 (signal_name, "ElementClicked") != 0)
+ return;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (!parameters)
+ return;
+
+ g_variant_get (parameters, "(t&s&siiii)", &page_id, &elem_class, &elem_value, &position_left,
&position_top, &position_width, &position_height);
+
+ if (!elem_class || !*elem_class || page_id != webkit_web_view_get_page_id (WEBKIT_WEB_VIEW
(web_view)))
+ return;
+
+ elem_position.x = position_left;
+ elem_position.y = position_top;
+ elem_position.width = position_width;
+ elem_position.height = position_height;
+
+ listeners = g_hash_table_lookup (web_view->priv->element_clicked_cbs, elem_class);
+ if (listeners) {
+ guint ii;
+
+ for (ii = 0; ii <listeners->len; ii++) {
+ ElementClickedData *ecd = g_ptr_array_index (listeners, ii);
+
+ if (ecd && ecd->callback)
+ ecd->callback (web_view, elem_class, elem_value, &elem_position,
ecd->user_data);
+ }
+ }
+}
+
+static void
web_extension_proxy_created_cb (GDBusProxy *proxy,
GAsyncResult *result,
EWebView *web_view)
@@ -1466,6 +1563,21 @@ web_extension_proxy_created_cb (GDBusProxy *proxy,
if (!web_view->priv->web_extension) {
g_warning ("Error creating web extension proxy: %s\n", error->message);
g_error_free (error);
+ } else {
+ web_view->priv->web_extension_element_clicked_signal_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (web_view->priv->web_extension),
+ g_dbus_proxy_get_name (web_view->priv->web_extension),
+ E_WEB_EXTENSION_INTERFACE,
+ "ElementClicked",
+ E_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ web_view_element_clicked_signal_cb,
+ web_view,
+ NULL);
+
+ g_hash_table_foreach (web_view->priv->element_clicked_cbs,
web_view_register_element_clicked_hfunc, web_view);
}
}
@@ -2307,6 +2419,8 @@ e_web_view_init (EWebView *web_view)
id = "org.gnome.evolution.webview";
e_plugin_ui_register_manager (ui_manager, id, web_view);
e_plugin_ui_enable_manager (ui_manager, id);
+
+ web_view->priv->element_clicked_cbs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_ptr_array_unref);
}
GtkWidget *
@@ -4150,3 +4264,120 @@ e_web_view_set_document_iframe_src (EWebView *web_view,
NULL,
e_web_view_set_document_iframe_src_done_cb, NULL);
}
+
+/**
+ * EWebViewElementClickedFunc:
+ * @web_view: an #EWebView
+ * @element_class: an element class, as set on the element which had been clicked
+ * @element_value: a 'value' attribute content of the clicked element
+ * @element_position: a #GtkAllocation with the position of the clicked element
+ * @user_data: user data as provided in the e_web_view_register_element_clicked() call
+ *
+ * The callback is called whenever an element of class @element_class is clicked.
+ * The @element_value is a content of the 'value' attribute of the clicked element.
+ * The @element_location is the place of the element within the web page.
+ *
+ * See: e_web_view_register_element_clicked, e_web_view_unregister_element_clicked
+ *
+ * Since: 3.22
+ **/
+
+/**
+ * e_web_view_register_element_clicked:
+ * @web_view: an #EWebView
+ * @element_class: an element class on which to listen for clicking
+ * @callback: an #EWebViewElementClickedFunc to call, when the element is clicked
+ * @user_data: user data to pass to @callback
+ *
+ * Registers a @callback to be called when any element of the class @element_class
+ * is clicked. If the element contains a 'value' attribute, then it is passed to
+ * the @callback too. These callback are valid until a new content of the @web_view
+ * is loaded, after which all the registered callbacks are forgotten.
+ *
+ * Since: 3.22
+ **/
+void
+e_web_view_register_element_clicked (EWebView *web_view,
+ const gchar *element_class,
+ EWebViewElementClickedFunc callback,
+ gpointer user_data)
+{
+ ElementClickedData *ecd;
+ GPtrArray *cbs;
+ guint ii;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (element_class != NULL);
+ g_return_if_fail (callback != NULL);
+
+ cbs = g_hash_table_lookup (web_view->priv->element_clicked_cbs, element_class);
+ if (cbs) {
+ for (ii = 0; ii < cbs->len; ii++) {
+ ecd = g_ptr_array_index (cbs, ii);
+
+ if (ecd && ecd->callback == callback && ecd->user_data == user_data) {
+ g_warning ("%s: Callback already registered", G_STRFUNC);
+ return;
+ }
+ }
+ }
+
+ ecd = g_new0 (ElementClickedData, 1);
+ ecd->callback = callback;
+ ecd->user_data = user_data;
+
+ if (!cbs) {
+ web_view_register_element_clicked_hfunc ((gpointer) element_class, NULL, web_view);
+
+ cbs = g_ptr_array_new_full (1, g_free);
+ g_ptr_array_add (cbs, ecd);
+
+ g_hash_table_insert (web_view->priv->element_clicked_cbs, g_strdup (element_class), cbs);
+ } else {
+ g_ptr_array_add (cbs, ecd);
+ }
+}
+
+/**
+ * e_web_view_unregister_element_clicked:
+ * @web_view: an #EWebView
+ * @element_class: an element class on which to listen for clicking
+ * @callback: an #EWebViewElementClickedFunc to call, when the element is clicked
+ * @user_data: user data to pass to @callback
+ *
+ * Unregisters the @callback for the @element_class with the given @user_data, which
+ * should be previously registered with e_web_view_register_element_clicked(). This
+ * unregister is usually not needed, because the @web_view unregisters all callbacks
+ * when a new content is loaded.
+ *
+ * Since: 3.22
+ **/
+void
+e_web_view_unregister_element_clicked (EWebView *web_view,
+ const gchar *element_class,
+ EWebViewElementClickedFunc callback,
+ gpointer user_data)
+{
+ ElementClickedData *ecd;
+ GPtrArray *cbs;
+ guint ii;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (element_class != NULL);
+ g_return_if_fail (callback != NULL);
+
+ cbs = g_hash_table_lookup (web_view->priv->element_clicked_cbs, element_class);
+ if (!cbs)
+ return;
+
+ for (ii = 0; ii < cbs->len; ii++) {
+ ecd = g_ptr_array_index (cbs, ii);
+
+ if (ecd && ecd->callback == callback && ecd->user_data == user_data) {
+ g_ptr_array_remove (cbs, ecd);
+ if (!cbs->len)
+ g_hash_table_remove (web_view->priv->element_clicked_cbs, element_class);
+ break;
+ }
+ }
+}
diff --git a/e-util/e-web-view.h b/e-util/e-web-view.h
index 57714a0..73e3bcc 100644
--- a/e-util/e-web-view.h
+++ b/e-util/e-web-view.h
@@ -66,6 +66,12 @@ typedef enum {
GTK_STOCK_URI_SCHEME
} EURIScheme;
+typedef void (*EWebViewElementClickedFunc) (EWebView *web_view,
+ const gchar *element_class,
+ const gchar *element_value,
+ const GtkAllocation *element_position,
+ gpointer user_data);
+
struct _EWebView {
WebKitWebView parent;
EWebViewPrivate *priv;
@@ -260,6 +266,16 @@ void e_web_view_set_document_iframe_src
(EWebView *web_view,
const gchar *document_uri,
const gchar *new_iframe_src);
+void e_web_view_register_element_clicked
+ (EWebView *web_view,
+ const gchar *element_class,
+ EWebViewElementClickedFunc callback,
+ gpointer user_data);
+void e_web_view_unregister_element_clicked
+ (EWebView *web_view,
+ const gchar *element_class,
+ EWebViewElementClickedFunc callback,
+ gpointer user_data);
G_END_DECLS
#endif /* E_WEB_VIEW_H */
diff --git a/em-format/Makefile.am b/em-format/Makefile.am
index 7827d79..8939280 100644
--- a/em-format/Makefile.am
+++ b/em-format/Makefile.am
@@ -39,6 +39,7 @@ evolution_mail_formatter_include_HEADERS = \
e-mail-part-headers.h \
e-mail-part-image.h \
e-mail-part-list.h \
+ e-mail-part-secure-button.h \
e-mail-part-utils.h \
e-mail-stripsig-filter.h
@@ -121,6 +122,7 @@ libevolution_mail_formatter_la_SOURCES = \
e-mail-part-headers.c \
e-mail-part-image.c \
e-mail-part-list.c \
+ e-mail-part-secure-button.c \
e-mail-part-utils.c \
e-mail-stripsig-filter.c \
$(SMIME_EXTENSIONS)
diff --git a/em-format/e-mail-formatter-secure-button.c b/em-format/e-mail-formatter-secure-button.c
index 0ed0ef4..8269fcc 100644
--- a/em-format/e-mail-formatter-secure-button.c
+++ b/em-format/e-mail-formatter-secure-button.c
@@ -23,11 +23,6 @@
#include <e-util/e-util.h>
-#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
-#include "certificate-manager.h"
-#include "e-cert-db.h"
-#endif
-
#include "e-mail-formatter-extension.h"
typedef EMailFormatterExtension EMailFormatterSecureButton;
@@ -41,7 +36,7 @@ G_DEFINE_TYPE (
E_TYPE_MAIL_FORMATTER_EXTENSION)
static const gchar *formatter_mime_types[] = {
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
NULL
};
@@ -74,139 +69,25 @@ static const GdkRGBA smime_sign_colour[6] = {
{ 0.0, 0.0, 0.0, 1.0 }
};
-static gboolean
-emfe_secure_button_format (EMailFormatterExtension *extension,
- EMailFormatter *formatter,
- EMailFormatterContext *context,
- EMailPart *part,
- GOutputStream *stream,
- GCancellable *cancellable)
-{
- gchar *str;
-
- if ((context->mode != E_MAIL_FORMATTER_MODE_NORMAL) &&
- (context->mode != E_MAIL_FORMATTER_MODE_RAW) &&
- (context->mode != E_MAIL_FORMATTER_MODE_ALL_HEADERS))
- return FALSE;
-
- str = g_strdup_printf (
- "<object type=\"application/vnd.evolution.widget.secure-button\" "
- "height=\"20\" width=\"100%%\" data=\"%s\" id=\"%s\"></object>",
- e_mail_part_get_id (part),
- e_mail_part_get_id (part));
-
- g_output_stream_write_all (
- stream, str, strlen (str), NULL, cancellable, NULL);
-
- g_free (str);
-
- return TRUE;
-}
+/* This is awkward, but there is no header file for it. On the other hand,
+ the functions are meant private, where they really are, being defined this way. */
+const gchar *e_mail_formatter_secure_button_get_encrypt_description (camel_cipher_validity_encrypt_t status);
+const gchar *e_mail_formatter_secure_button_get_sign_description (camel_cipher_validity_sign_t status);
-#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
-static void
-viewcert_clicked (GtkWidget *button,
- GtkWidget *grid)
+const gchar *
+e_mail_formatter_secure_button_get_sign_description (camel_cipher_validity_sign_t status)
{
- CamelCipherCertInfo *info = g_object_get_data ((GObject *) button, "e-cert-info");
- ECert *ec = NULL;
-
- if (info->cert_data)
- ec = e_cert_new (CERT_DupCertificate (info->cert_data));
-
- if (ec != NULL) {
- GtkWidget *dialog, *parent;
-
- parent = gtk_widget_get_toplevel (grid);
- if (!parent || !GTK_IS_WINDOW (parent))
- parent = NULL;
-
- dialog = e_cert_manager_new_certificate_viewer ((GtkWindow *) parent, ec);
-
- gtk_widget_show (dialog);
- g_signal_connect (
- dialog, "response",
- G_CALLBACK (gtk_widget_destroy), NULL);
-
- g_object_unref (ec);
- } else {
- g_warning (
- "can't find certificate for %s <%s>",
- info->name ? info->name : "",
- info->email ? info->email : "");
- }
-}
-#endif
+ g_return_val_if_fail (status >= 0 && status < G_N_ELEMENTS (smime_sign_table), NULL);
-static void
-info_response (GtkWidget *widget,
- guint button,
- gpointer user_data)
-{
- gtk_widget_destroy (widget);
+ return _(smime_sign_table[status].description);
}
-static void
-add_cert_table (GtkWidget *grid,
- GQueue *certlist,
- gpointer user_data)
+const gchar *
+e_mail_formatter_secure_button_get_encrypt_description (camel_cipher_validity_encrypt_t status)
{
- GList *head, *link;
- GtkTable *table;
- gint n = 0;
-
- table = (GtkTable *) gtk_table_new (certlist->length, 2, FALSE);
-
- head = g_queue_peek_head_link (certlist);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelCipherCertInfo *info = link->data;
- gchar *la = NULL;
- const gchar *l = NULL;
-
- if (info->name) {
- if (info->email && strcmp (info->name, info->email) != 0)
- l = la = g_strdup_printf ("%s <%s>", info->name, info->email);
- else
- l = info->name;
- } else {
- if (info->email)
- l = info->email;
- }
+ g_return_val_if_fail (status >= 0 && status < G_N_ELEMENTS (smime_encrypt_table), NULL);
- if (l) {
- GtkWidget *w;
-#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
- ECert *ec = NULL;
-#endif
- w = gtk_label_new (l);
- gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
- g_free (la);
- gtk_table_attach (table, w, 0, 1, n, n + 1, GTK_FILL, GTK_FILL, 3, 3);
-#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
- w = gtk_button_new_with_mnemonic (_("_View Certificate"));
- gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
- g_object_set_data ((GObject *) w, "e-cert-info", info);
- g_signal_connect (
- w, "clicked",
- G_CALLBACK (viewcert_clicked), grid);
-
- if (info->cert_data)
- ec = e_cert_new (CERT_DupCertificate (info->cert_data));
-
- if (ec == NULL)
- gtk_widget_set_sensitive (w, FALSE);
- else
- g_object_unref (ec);
-#else
- w = gtk_label_new (_("This certificate is not viewable"));
- gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
-#endif
- n++;
- }
- }
-
- gtk_container_add (GTK_CONTAINER (grid), GTK_WIDGET (table));
+ return _(smime_encrypt_table[status].description);
}
static void
@@ -244,9 +125,9 @@ format_cert_infos (GQueue *cert_infos,
g_string_append (output_buffer, cinfo->name);
if (cinfo->email != NULL && *cinfo->email != '\0') {
- g_string_append (output_buffer, " <");
+ g_string_append (output_buffer, " <");
g_string_append (output_buffer, cinfo->email);
- g_string_append (output_buffer, ">");
+ g_string_append (output_buffer, ">");
}
} else if (cinfo->email != NULL && *cinfo->email != '\0') {
@@ -261,115 +142,16 @@ format_cert_infos (GQueue *cert_infos,
}
static void
-secure_button_clicked_cb (GtkWidget *widget,
- CamelCipherValidity *validity)
-{
- GtkBuilder *builder;
- GtkWidget *grid, *w;
- GtkWidget *dialog;
-
- g_return_if_fail (validity != NULL);
-
- /* Make sure our custom widget classes are registered with
- * GType before we load the GtkBuilder definition file. */
- g_type_ensure (E_TYPE_DATE_EDIT);
-
- builder = gtk_builder_new ();
- e_load_ui_builder_definition (builder, "mail-dialogs.ui");
-
- dialog = e_builder_get_widget (builder, "message_security_dialog");
-
- grid = e_builder_get_widget (builder, "signature_grid");
- w = gtk_label_new (_(smime_sign_table[validity->sign.status].description));
- gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
- gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
- gtk_container_add (GTK_CONTAINER (grid), w);
- if (validity->sign.description) {
- GtkTextBuffer *buffer;
-
- buffer = gtk_text_buffer_new (NULL);
- gtk_text_buffer_set_text (
- buffer, validity->sign.description,
- strlen (validity->sign.description));
- w = g_object_new (
- gtk_scrolled_window_get_type (),
- "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "shadow_type", GTK_SHADOW_IN,
- "expand", TRUE,
- "child", g_object_new (gtk_text_view_get_type (),
- "buffer", buffer,
- "cursor_visible", FALSE,
- "editable", FALSE,
- NULL),
- "width_request", 500,
- "height_request", 80,
- NULL);
- g_object_unref (buffer);
-
- gtk_container_add (GTK_CONTAINER (grid), w);
- }
-
- if (!g_queue_is_empty (&validity->sign.signers))
- add_cert_table (
- grid, &validity->sign.signers, NULL);
-
- gtk_widget_show_all (grid);
-
- grid = e_builder_get_widget (builder, "encryption_grid");
- w = gtk_label_new (_(smime_encrypt_table[validity->encrypt.status].description));
- gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
- gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
- gtk_container_add (GTK_CONTAINER (grid), w);
- if (validity->encrypt.description) {
- GtkTextBuffer *buffer;
-
- buffer = gtk_text_buffer_new (NULL);
- gtk_text_buffer_set_text (
- buffer, validity->encrypt.description,
- strlen (validity->encrypt.description));
- w = g_object_new (
- gtk_scrolled_window_get_type (),
- "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "shadow_type", GTK_SHADOW_IN,
- "expand", TRUE,
- "child", g_object_new (gtk_text_view_get_type (),
- "buffer", buffer,
- "cursor_visible", FALSE,
- "editable", FALSE,
- NULL),
- "width_request", 500,
- "height_request", 80,
- NULL);
- g_object_unref (buffer);
-
- gtk_container_add (GTK_CONTAINER (grid), w);
- }
-
- if (!g_queue_is_empty (&validity->encrypt.encrypters))
- add_cert_table (grid, &validity->encrypt.encrypters, NULL);
-
- gtk_widget_show_all (grid);
-
- g_object_unref (builder);
-
- g_signal_connect (
- dialog, "response",
- G_CALLBACK (info_response), NULL);
-
- gtk_widget_show (dialog);
-}
-
-static GtkWidget *
-secure_button_get_widget_for_validity (CamelCipherValidity *validity)
+secure_button_format_validity (EMailPart *part,
+ CamelCipherValidity *validity,
+ GString *html)
{
- GtkWidget *box, *button, *layout, *widget;
const gchar *icon_name;
gchar *description;
+ gint icon_width, icon_height;
GString *buffer;
- g_return_val_if_fail (validity != NULL, NULL);
+ g_return_if_fail (validity != NULL);
buffer = g_string_new ("");
@@ -390,7 +172,7 @@ secure_button_get_widget_for_validity (CamelCipherValidity *validity)
gint status;
if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
- g_string_append (buffer, "\n");
+ g_string_append (buffer, "<br>\n");
status = validity->encrypt.status;
desc = smime_encrypt_table[status].shortdesc;
@@ -400,87 +182,66 @@ secure_button_get_widget_for_validity (CamelCipherValidity *validity)
description = g_string_free (buffer, FALSE);
/* FIXME: need to have it based on encryption and signing too */
- if (validity->sign.status != 0)
+ if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
icon_name = smime_sign_table[validity->sign.status].icon;
else
icon_name = smime_encrypt_table[validity->encrypt.status].icon;
- box = gtk_event_box_new ();
- if (validity->sign.status != 0)
- gtk_widget_override_background_color (
- box, GTK_STATE_FLAG_NORMAL,
- &smime_sign_colour[validity->sign.status]);
-
- layout = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
- gtk_container_add (GTK_CONTAINER (box), layout);
-
- button = gtk_button_new ();
- gtk_box_pack_start (GTK_BOX (layout), button, FALSE, FALSE, 0);
- g_signal_connect (
- button, "clicked",
- G_CALLBACK (secure_button_clicked_cb), validity);
-
- widget = gtk_image_new_from_icon_name (
- icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
- gtk_button_set_image (GTK_BUTTON (button), widget);
-
- widget = gtk_label_new (description);
- g_object_set (G_OBJECT (widget),
- "wrap", TRUE,
- "width-chars", 20,
- "max-width-chars", 80,
- "xalign", 0.0,
- "halign", GTK_ALIGN_FILL,
- "hexpand", TRUE,
- NULL);
- /* make sure the text color doesn't change with theme */
- gtk_widget_override_color (widget, GTK_STATE_FLAG_NORMAL, &smime_sign_colour[5]);
- gtk_box_pack_start (GTK_BOX (layout), widget, TRUE, TRUE, 0);
+ if (!gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &icon_width, &icon_height)) {
+ icon_width = 24;
+ icon_height = 24;
+ }
- g_free (description);
+ g_string_append (html, "<table width=\"100%\" style=\"vertical-align:middle;");
+ if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE &&
+ smime_sign_colour[validity->sign.status].alpha > 1e-9)
+ g_string_append_printf (html, " background:#%06x;",
+ e_rgba_to_value (&smime_sign_colour[validity->sign.status]));
+ g_string_append (html, "\"><tr>");
+
+ g_string_append_printf (html,
+ "<td style=\"width:1px;\"><button type=\"button\" class=\"secure-button\"
id=\"secure-button\" value=\"%p:%p\" accesskey=\"\" style=\"vertical-align:middle;\">"
+ "<img src=\"gtk-stock://%s?size=%d\" width=\"%dpx\" height=\"%dpx\"
style=\"vertical-align:middle;\"></button></td><td><span style=\"color:#%06x;
vertical-align:middle;\">%s</span></td>",
+ part, validity, icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR,
+ icon_width, icon_height, e_rgba_to_value (&smime_sign_colour[5]), description);
- return box;
+ g_free (description);
+ g_string_append (html, "</tr></table>\n");
}
-static GtkWidget *
-emfe_secure_button_get_widget (EMailFormatterExtension *extension,
- EMailPartList *context,
- EMailPart *part,
- GHashTable *params)
+static gboolean
+emfe_secure_button_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ GOutputStream *stream,
+ GCancellable *cancellable)
{
- GtkWidget *grid;
GList *head, *link;
+ GString *html;
- g_return_val_if_fail (part != NULL, NULL);
-
- grid = g_object_new (
- GTK_TYPE_GRID,
- "orientation", GTK_ORIENTATION_VERTICAL,
- "row-spacing", 2,
- "halign", GTK_ALIGN_FILL,
- "hexpand", TRUE,
- NULL);
+ if ((context->mode != E_MAIL_FORMATTER_MODE_NORMAL) &&
+ (context->mode != E_MAIL_FORMATTER_MODE_RAW) &&
+ (context->mode != E_MAIL_FORMATTER_MODE_ALL_HEADERS))
+ return FALSE;
+ html = g_string_new ("");
head = g_queue_peek_head_link (&part->validities);
for (link = head; link != NULL; link = g_list_next (link)) {
EMailPartValidityPair *pair = link->data;
- GtkWidget *widget;
- if (pair == NULL)
+ if (!pair)
continue;
- widget = secure_button_get_widget_for_validity (pair->validity);
- if (widget != NULL) {
- gtk_widget_set_halign (widget, GTK_ALIGN_FILL);
- gtk_widget_set_hexpand (widget, TRUE);
- gtk_container_add (GTK_CONTAINER (grid), widget);
- }
+ secure_button_format_validity (part, pair->validity, html);
}
- gtk_widget_show_all (grid);
+ g_output_stream_write_all (stream, html->str, html->len, NULL, cancellable, NULL);
- return grid;
+ g_string_free (html, TRUE);
+
+ return TRUE;
}
static void
@@ -489,7 +250,6 @@ e_mail_formatter_secure_button_class_init (EMailFormatterExtensionClass *class)
class->mime_types = formatter_mime_types;
class->priority = G_PRIORITY_LOW;
class->format = emfe_secure_button_format;
- class->get_widget = emfe_secure_button_get_widget;
}
static void
diff --git a/em-format/e-mail-parser-application-smime.c b/em-format/e-mail-parser-application-smime.c
index 95f07b4..f3673bf 100644
--- a/em-format/e-mail-parser-application-smime.c
+++ b/em-format/e-mail-parser-application-smime.c
@@ -120,7 +120,7 @@ empe_app_smime_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-inlinepgp-encrypted.c b/em-format/e-mail-parser-inlinepgp-encrypted.c
index 56d5fc5..bdabcb8 100644
--- a/em-format/e-mail-parser-inlinepgp-encrypted.c
+++ b/em-format/e-mail-parser-inlinepgp-encrypted.c
@@ -148,7 +148,7 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-inlinepgp-signed.c b/em-format/e-mail-parser-inlinepgp-signed.c
index 9f08583..84f38bd 100644
--- a/em-format/e-mail-parser-inlinepgp-signed.c
+++ b/em-format/e-mail-parser-inlinepgp-signed.c
@@ -160,7 +160,7 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-multipart-encrypted.c b/em-format/e-mail-parser-multipart-encrypted.c
index dff97b3..6c8a65e 100644
--- a/em-format/e-mail-parser-multipart-encrypted.c
+++ b/em-format/e-mail-parser-multipart-encrypted.c
@@ -143,7 +143,7 @@ empe_mp_encrypted_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-multipart-signed.c b/em-format/e-mail-parser-multipart-signed.c
index c467ec7..f90d645 100644
--- a/em-format/e-mail-parser-multipart-signed.c
+++ b/em-format/e-mail-parser-multipart-signed.c
@@ -188,7 +188,7 @@ empe_mp_signed_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-secure-button.c b/em-format/e-mail-parser-secure-button.c
index 61832a0..e458598 100644
--- a/em-format/e-mail-parser-secure-button.c
+++ b/em-format/e-mail-parser-secure-button.c
@@ -23,6 +23,7 @@
#include <e-util/e-util.h>
+#include "e-mail-part-secure-button.h"
#include "e-mail-parser-extension.h"
typedef EMailParserExtension EMailParserSecureButton;
@@ -36,7 +37,7 @@ G_DEFINE_TYPE (
E_TYPE_MAIL_PARSER_EXTENSION)
static const gchar *parser_mime_types[] = {
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
NULL
};
@@ -53,7 +54,7 @@ empe_secure_button_parse (EMailParserExtension *extension,
len = part_id->len;
g_string_append (part_id, ".secure_button");
- mail_part = e_mail_part_new (part, part_id->str);
+ mail_part = e_mail_part_secure_button_new (part, part_id->str);
e_mail_part_set_mime_type (mail_part, parser_mime_types[0]);
g_string_truncate (part_id, len);
diff --git a/em-format/e-mail-part-secure-button.c b/em-format/e-mail-part-secure-button.c
new file mode 100644
index 0000000..c10e718
--- /dev/null
+++ b/em-format/e-mail-part-secure-button.c
@@ -0,0 +1,321 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+#include "certificate-manager.h"
+#include "e-cert-db.h"
+#endif
+
+#include "e-mail-part-secure-button.h"
+
+G_DEFINE_TYPE (EMailPartSecureButton, e_mail_part_secure_button, E_TYPE_MAIL_PART)
+
+const gchar *e_mail_formatter_secure_button_get_encrypt_description (camel_cipher_validity_encrypt_t status);
+const gchar *e_mail_formatter_secure_button_get_sign_description (camel_cipher_validity_sign_t status);
+
+
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+static void
+viewcert_clicked (GtkWidget *button,
+ GtkWidget *grid)
+{
+ CamelCipherCertInfo *info = g_object_get_data ((GObject *) button, "e-cert-info");
+ ECert *ec = NULL;
+
+ if (info->cert_data)
+ ec = e_cert_new (CERT_DupCertificate (info->cert_data));
+
+ if (ec != NULL) {
+ GtkWidget *dialog, *parent;
+
+ parent = gtk_widget_get_toplevel (grid);
+ if (!parent || !GTK_IS_WINDOW (parent))
+ parent = NULL;
+
+ dialog = e_cert_manager_new_certificate_viewer ((GtkWindow *) parent, ec);
+
+ gtk_widget_show (dialog);
+ g_signal_connect (
+ dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ g_object_unref (ec);
+ } else {
+ g_warning (
+ "can't find certificate for %s <%s>",
+ info->name ? info->name : "",
+ info->email ? info->email : "");
+ }
+}
+#endif
+
+static void
+info_response (GtkWidget *widget,
+ guint button,
+ gpointer user_data)
+{
+ gtk_widget_destroy (widget);
+}
+
+static void
+add_cert_table (GtkWidget *grid,
+ GQueue *certlist,
+ gpointer user_data)
+{
+ GList *head, *link;
+ GtkTable *table;
+ gint n = 0;
+
+ table = (GtkTable *) gtk_table_new (certlist->length, 2, FALSE);
+
+ head = g_queue_peek_head_link (certlist);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelCipherCertInfo *info = link->data;
+ gchar *la = NULL;
+ const gchar *l = NULL;
+
+ if (info->name) {
+ if (info->email && strcmp (info->name, info->email) != 0)
+ l = la = g_strdup_printf ("%s <%s>", info->name, info->email);
+ else
+ l = info->name;
+ } else {
+ if (info->email)
+ l = info->email;
+ }
+
+ if (l) {
+ GtkWidget *w;
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+ ECert *ec = NULL;
+#endif
+ w = gtk_label_new (l);
+ gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+ g_free (la);
+ gtk_table_attach (table, w, 0, 1, n, n + 1, GTK_FILL, GTK_FILL, 3, 3);
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+ w = gtk_button_new_with_mnemonic (_("_View Certificate"));
+ gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
+ g_object_set_data ((GObject *) w, "e-cert-info", info);
+ g_signal_connect (
+ w, "clicked",
+ G_CALLBACK (viewcert_clicked), grid);
+
+ if (info->cert_data)
+ ec = e_cert_new (CERT_DupCertificate (info->cert_data));
+
+ if (ec == NULL)
+ gtk_widget_set_sensitive (w, FALSE);
+ else
+ g_object_unref (ec);
+#else
+ w = gtk_label_new (_("This certificate is not viewable"));
+ gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
+#endif
+ n++;
+ }
+ }
+
+ gtk_container_add (GTK_CONTAINER (grid), GTK_WIDGET (table));
+}
+
+static void
+secure_button_show_validity_dialog (EWebView *web_view,
+ CamelCipherValidity *validity)
+{
+ GtkBuilder *builder;
+ GtkWidget *grid, *w;
+ GtkWidget *dialog;
+
+ g_return_if_fail (validity != NULL);
+
+ /* Make sure our custom widget classes are registered with
+ * GType before we load the GtkBuilder definition file. */
+ g_type_ensure (E_TYPE_DATE_EDIT);
+
+ builder = gtk_builder_new ();
+ e_load_ui_builder_definition (builder, "mail-dialogs.ui");
+
+ dialog = e_builder_get_widget (builder, "message_security_dialog");
+
+ w = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
+ if (GTK_IS_WINDOW (w))
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (w));
+
+ grid = e_builder_get_widget (builder, "signature_grid");
+ w = gtk_label_new (e_mail_formatter_secure_button_get_sign_description (validity->sign.status));
+ gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+ gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+ gtk_container_add (GTK_CONTAINER (grid), w);
+ if (validity->sign.description) {
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_set_text (
+ buffer, validity->sign.description,
+ strlen (validity->sign.description));
+ w = g_object_new (
+ gtk_scrolled_window_get_type (),
+ "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "shadow_type", GTK_SHADOW_IN,
+ "expand", TRUE,
+ "child", g_object_new (gtk_text_view_get_type (),
+ "buffer", buffer,
+ "cursor_visible", FALSE,
+ "editable", FALSE,
+ NULL),
+ "width_request", 500,
+ "height_request", 80,
+ NULL);
+ g_object_unref (buffer);
+
+ gtk_container_add (GTK_CONTAINER (grid), w);
+ }
+
+ if (!g_queue_is_empty (&validity->sign.signers))
+ add_cert_table (grid, &validity->sign.signers, NULL);
+
+ gtk_widget_show_all (grid);
+
+ grid = e_builder_get_widget (builder, "encryption_grid");
+ w = gtk_label_new (e_mail_formatter_secure_button_get_encrypt_description (validity->encrypt.status));
+ gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+ gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+ gtk_container_add (GTK_CONTAINER (grid), w);
+ if (validity->encrypt.description) {
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_set_text (
+ buffer, validity->encrypt.description,
+ strlen (validity->encrypt.description));
+ w = g_object_new (
+ gtk_scrolled_window_get_type (),
+ "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "shadow_type", GTK_SHADOW_IN,
+ "expand", TRUE,
+ "child", g_object_new (gtk_text_view_get_type (),
+ "buffer", buffer,
+ "cursor_visible", FALSE,
+ "editable", FALSE,
+ NULL),
+ "width_request", 500,
+ "height_request", 80,
+ NULL);
+ g_object_unref (buffer);
+
+ gtk_container_add (GTK_CONTAINER (grid), w);
+ }
+
+ if (!g_queue_is_empty (&validity->encrypt.encrypters))
+ add_cert_table (grid, &validity->encrypt.encrypters, NULL);
+
+ gtk_widget_show_all (grid);
+
+ g_object_unref (builder);
+
+ g_signal_connect (
+ dialog, "response",
+ G_CALLBACK (info_response), NULL);
+
+ gtk_widget_show (dialog);
+}
+
+static void
+secure_button_clicked_cb (EWebView *web_view,
+ const gchar *element_class,
+ const gchar *element_value,
+ const GtkAllocation *element_position,
+ gpointer user_data)
+{
+ EMailPart *mail_part = user_data;
+ GList *head, *link;
+ gboolean can_use;
+ gchar *tmp;
+
+ g_return_if_fail (E_IS_MAIL_PART_SECURE_BUTTON (mail_part));
+
+ tmp = g_strdup_printf ("%p:", mail_part);
+ can_use = element_value && g_str_has_prefix (element_value, tmp);
+ if (can_use)
+ element_value += strlen (tmp);
+ g_free (tmp);
+
+ if (!can_use)
+ return;
+
+ head = g_queue_peek_head_link (&mail_part->validities);
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+
+ if (!pair)
+ continue;
+
+ tmp = g_strdup_printf ("%p", pair->validity);
+ can_use = g_strcmp0 (element_value, tmp) == 0;
+ g_free (tmp);
+
+ if (can_use) {
+ secure_button_show_validity_dialog (web_view, pair->validity);
+ break;
+ }
+ }
+}
+
+static void
+mail_part_secure_button_web_view_loaded (EMailPart *mail_part,
+ EWebView *web_view)
+{
+ g_return_if_fail (E_IS_MAIL_PART_SECURE_BUTTON (mail_part));
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ e_web_view_register_element_clicked (web_view, "secure-button", secure_button_clicked_cb, mail_part);
+}
+
+static void
+e_mail_part_secure_button_class_init (EMailPartSecureButtonClass *class)
+{
+ EMailPartClass *mail_part_class;
+
+ mail_part_class = E_MAIL_PART_CLASS (class);
+ mail_part_class->web_view_loaded = mail_part_secure_button_web_view_loaded;
+}
+
+static void
+e_mail_part_secure_button_init (EMailPartSecureButton *part)
+{
+}
+
+EMailPart *
+e_mail_part_secure_button_new (CamelMimePart *mime_part,
+ const gchar *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART_SECURE_BUTTON,
+ "id", id, "mime-part", mime_part, NULL);
+}
diff --git a/em-format/e-mail-part-secure-button.h b/em-format/e-mail-part-secure-button.h
new file mode 100644
index 0000000..b40a0d3
--- /dev/null
+++ b/em-format/e-mail-part-secure-button.h
@@ -0,0 +1,61 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef E_MAIL_PART_SECURE_BUTTON_H
+#define E_MAIL_PART_SECURE_BUTTON_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_SECURE_BUTTON \
+ (e_mail_part_secure_button_get_type ())
+#define E_MAIL_PART_SECURE_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PART_SECURE_BUTTON, EMailPartSecureButton))
+#define E_MAIL_PART_SECURE_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PART_SECURE_BUTTON, EMailPartSecureButtonClass))
+#define E_IS_MAIL_PART_SECURE_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PART_SECURE_BUTTON))
+#define E_IS_MAIL_PART_SECURE_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PART_SECURE_BUTTON))
+#define E_MAIL_PART_SECURE_BUTTON_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PART_SECURE_BUTTON, EMailPartSecureButtonClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartSecureButton EMailPartSecureButton;
+typedef struct _EMailPartSecureButtonClass EMailPartSecureButtonClass;
+typedef struct _EMailPartSecureButtonPrivate EMailPartSecureButtonPrivate;
+
+struct _EMailPartSecureButton {
+ EMailPart parent;
+ EMailPartSecureButtonPrivate *priv;
+};
+
+struct _EMailPartSecureButtonClass {
+ EMailPartClass parent_class;
+};
+
+GType e_mail_part_secure_button_get_type (void) G_GNUC_CONST;
+EMailPart * e_mail_part_secure_button_new (CamelMimePart *mime_part,
+ const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_SECURE_BUTTON_H */
diff --git a/em-format/e-mail-part.c b/em-format/e-mail-part.c
index 8795cde..f225126 100644
--- a/em-format/e-mail-part.c
+++ b/em-format/e-mail-part.c
@@ -597,6 +597,21 @@ e_mail_part_bind_dom_element (EMailPart *part,
class->bind_dom_element (part, web_extension, page_id, element_id);
}
+void
+e_mail_part_web_view_loaded (EMailPart *part,
+ EWebView *web_view)
+{
+ EMailPartClass *klass;
+
+ g_return_if_fail (E_IS_MAIL_PART (part));
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ klass = E_MAIL_PART_GET_CLASS (part);
+
+ if (klass->web_view_loaded)
+ klass->web_view_loaded (part, web_view);
+}
+
static EMailPartValidityPair *
mail_part_find_validity_pair (EMailPart *part,
EMailPartValidityFlags validity_type)
diff --git a/em-format/e-mail-part.h b/em-format/e-mail-part.h
index 7ff9163..72e17ad 100644
--- a/em-format/e-mail-part.h
+++ b/em-format/e-mail-part.h
@@ -89,6 +89,8 @@ struct _EMailPartClass {
GDBusProxy *web_extension,
guint64 page_id,
const gchar *element_id);
+ void (*web_view_loaded) (EMailPart *part,
+ EWebView *web_view);
};
GType e_mail_part_get_type (void) G_GNUC_CONST;
@@ -125,6 +127,8 @@ void e_mail_part_bind_dom_element (EMailPart *part,
GDBusProxy *web_extension,
guint64 page_id,
const gchar *element_id);
+void e_mail_part_web_view_loaded (EMailPart *part,
+ EWebView *web_view);
void e_mail_part_update_validity (EMailPart *part,
CamelCipherValidity *validity,
EMailPartValidityFlags validity_type);
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index f00d98a..a7fe93b 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -1133,16 +1133,17 @@ mail_element_exists_cb (GDBusProxy *web_extension,
}
static void
-mail_parts_bind_dom (WebKitWebView *web_view,
+mail_parts_bind_dom (WebKitWebView *wk_web_view,
WebKitLoadEvent load_event,
gpointer user_data)
{
EMailDisplay *display;
+ EWebView *web_view;
GQueue queue = G_QUEUE_INIT;
GList *head, *link;
GDBusProxy *web_extension;
- display = E_MAIL_DISPLAY (web_view);
+ display = E_MAIL_DISPLAY (wk_web_view);
if (load_event == WEBKIT_LOAD_STARTED) {
e_mail_display_cleanup_skipped_uris (display);
@@ -1157,12 +1158,13 @@ mail_parts_bind_dom (WebKitWebView *web_view,
initialize_web_view_colors (display);
- web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
+ web_view = E_WEB_VIEW (display);
+
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
if (!web_extension)
return;
- e_mail_part_list_queue_parts (
- display->priv->part_list, NULL, &queue);
+ e_mail_part_list_queue_parts (display->priv->part_list, NULL, &queue);
head = g_queue_peek_head_link (&queue);
for (link = head; link != NULL; link = g_list_next (link)) {
@@ -1171,6 +1173,8 @@ mail_parts_bind_dom (WebKitWebView *web_view,
part_id = e_mail_part_get_id (part);
+ e_mail_part_web_view_loaded (part, web_view);
+
g_dbus_proxy_call (
web_extension,
"ElementExists",
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 815837e..4d1da85 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -148,6 +148,7 @@ em-format/e-mail-parser-message-external.c
em-format/e-mail-parser-multipart-encrypted.c
em-format/e-mail-parser-multipart-signed.c
em-format/e-mail-part-headers.c
+em-format/e-mail-part-secure-button.c
em-format/e-mail-part-utils.c
e-util/ea-calendar-item.c
e-util/e-action-combo-box.c
diff --git a/web-extensions/e-web-extension.c b/web-extensions/e-web-extension.c
index 0e5ebba..54aaa52 100644
--- a/web-extensions/e-web-extension.c
+++ b/web-extensions/e-web-extension.c
@@ -36,6 +36,8 @@
#define WEBKIT_DOM_USE_UNSTABLE_API
#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#define WEB_EXTENSION_PAGE_ID_KEY "web-extension-page-id"
+
#define E_WEB_EXTENSION_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_WEB_EXTENSION, EWebExtensionPrivate))
@@ -54,6 +56,19 @@ struct _EWebExtensionPrivate {
static const char introspection_xml[] =
"<node>"
" <interface name='" E_WEB_EXTENSION_INTERFACE "'>"
+" <method name='RegisterElementClicked'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_class' direction='in'/>"
+" </method>"
+" <signal name='ElementClicked'>"
+" <arg type='t' name='page_id' direction='out'/>"
+" <arg type='s' name='element_class' direction='out'/>"
+" <arg type='s' name='element_value' direction='out'/>"
+" <arg type='i' name='position_left' direction='out'/>"
+" <arg type='i' name='position_top' direction='out'/>"
+" <arg type='i' name='position_width' direction='out'/>"
+" <arg type='i' name='position_height' direction='out'/>"
+" </signal>"
" <signal name='HeadersCollapsed'>"
" <arg type='b' name='expanded' direction='out'/>"
" </signal>"
@@ -159,6 +174,58 @@ get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
}
static void
+element_clicked_cb (WebKitDOMElement *element,
+ WebKitDOMEvent *event,
+ gpointer user_data)
+{
+ EWebExtension *extension = user_data;
+ WebKitDOMElement *offset_parent;
+ gchar *attr_class, *attr_value;
+ const guint64 *ppage_id;
+ gdouble with_parents_left, with_parents_top;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+ g_return_if_fail (G_IS_OBJECT (element));
+
+ ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
+ g_return_if_fail (ppage_id != NULL);
+
+ with_parents_left = webkit_dom_element_get_offset_left (element);
+ with_parents_top = webkit_dom_element_get_offset_top (element);
+
+ offset_parent = element;
+ while (offset_parent = webkit_dom_element_get_offset_parent (offset_parent), offset_parent) {
+ with_parents_left += webkit_dom_element_get_offset_left (offset_parent);
+ with_parents_top += webkit_dom_element_get_offset_top (offset_parent);
+ }
+
+ attr_class = webkit_dom_element_get_class_name (element);
+ attr_value = webkit_dom_element_get_attribute (element, "value");
+
+ g_dbus_connection_emit_signal (
+ extension->priv->dbus_connection,
+ NULL,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ E_WEB_EXTENSION_INTERFACE,
+ "ElementClicked",
+ g_variant_new ("(tssiiii)", *ppage_id, attr_class ? attr_class : "", attr_value ? attr_value
: "",
+ (gint) with_parents_left,
+ (gint) with_parents_top,
+ (gint) webkit_dom_element_get_offset_width (element),
+ (gint) webkit_dom_element_get_offset_height (element)),
+ &error);
+
+ if (error) {
+ g_warning ("Error emitting signal ElementClicked: %s\n", error->message);
+ g_error_free (error);
+ }
+
+ g_free (attr_class);
+ g_free (attr_value);
+}
+
+static void
handle_method_call (GDBusConnection *connection,
const char *sender,
const char *object_path,
@@ -179,7 +246,49 @@ handle_method_call (GDBusConnection *connection,
if (camel_debug ("wex"))
printf ("EWebExtension - %s - %s\n", G_STRFUNC, method_name);
- if (g_strcmp0 (method_name, "ReplaceLocalImageLinks") == 0) {
+ if (g_strcmp0 (method_name, "RegisterElementClicked") == 0) {
+ const gchar *element_class = NULL;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_class);
+
+ web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ if (!element_class || !*element_class) {
+ g_warn_if_fail (element_class && *element_class);
+ } else {
+ WebKitDOMHTMLCollection *collection;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ collection = webkit_dom_document_get_elements_by_class_name_as_html_collection
(document, element_class);
+ if (collection) {
+ gulong ii, len;
+
+ len = webkit_dom_html_collection_get_length (collection);
+ for (ii = 0; ii < len; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (collection, ii);
+ if (WEBKIT_DOM_IS_EVENT_TARGET (node)) {
+ guint64 *ppage_id;
+
+ ppage_id = g_new0 (guint64, 1);
+ *ppage_id = page_id;
+
+ g_object_set_data_full (G_OBJECT (node),
WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (node), "click",
+ G_CALLBACK (element_clicked_cb), FALSE, extension);
+ }
+ }
+ }
+ g_clear_object (&collection);
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ReplaceLocalImageLinks") == 0) {
g_variant_get (parameters, "(t)", &page_id);
web_page = get_webkit_web_page_or_return_dbus_error (
invocation, web_extension, page_id);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]