473 lines
14 KiB
C
473 lines
14 KiB
C
/*
|
|
* evolution-secure-button.c
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with the program; if not, see <http://www.gnu.org/licenses/>
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include "e-mail-format-extensions.h"
|
|
|
|
#include <glib/gi18n-lib.h>
|
|
|
|
#include <em-format/e-mail-formatter-extension.h>
|
|
#include <em-format/e-mail-formatter.h>
|
|
#include <e-util/e-util.h>
|
|
|
|
#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
|
|
#include "certificate-viewer.h"
|
|
#include "e-cert-db.h"
|
|
#endif
|
|
|
|
#include <camel/camel.h>
|
|
|
|
typedef struct _EMailFormatterSecureButton {
|
|
GObject parent;
|
|
} EMailFormatterSecureButton;
|
|
|
|
typedef struct _EMailFormatterSecureButtonClass {
|
|
GObjectClass parent_class;
|
|
} EMailFormatterSecureButtonClass;
|
|
|
|
static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface);
|
|
static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface);
|
|
|
|
G_DEFINE_TYPE_EXTENDED (
|
|
EMailFormatterSecureButton,
|
|
e_mail_formatter_secure_button,
|
|
G_TYPE_OBJECT,
|
|
0,
|
|
G_IMPLEMENT_INTERFACE (
|
|
E_TYPE_MAIL_EXTENSION,
|
|
e_mail_formatter_mail_extension_interface_init)
|
|
G_IMPLEMENT_INTERFACE (
|
|
E_TYPE_MAIL_FORMATTER_EXTENSION,
|
|
e_mail_formatter_formatter_extension_interface_init));
|
|
|
|
static const gchar *formatter_mime_types[] = { "application/vnd.evolution.widget.secure-button", NULL };
|
|
|
|
static const struct {
|
|
const gchar *icon, *shortdesc, *description;
|
|
} smime_sign_table[5] = {
|
|
{ "stock_signature-bad", N_("Unsigned"), N_("This message is not signed. There is no guarantee that this message is authentic.") },
|
|
{ "stock_signature-ok", N_("Valid signature"), N_("This message is signed and is valid meaning that it is very likely that this message is authentic.") },
|
|
{ "stock_signature-bad", N_("Invalid signature"), N_("The signature of this message cannot be verified, it may have been altered in transit.") },
|
|
{ "stock_signature", N_("Valid signature, but cannot verify sender"), N_("This message is signed with a valid signature, but the sender of the message cannot be verified.") },
|
|
{ "stock_signature-bad", N_("Signature exists, but need public key"), N_("This message is signed with a signature, but there is no corresponding public key.") },
|
|
|
|
};
|
|
|
|
static const struct {
|
|
const gchar *icon, *shortdesc, *description;
|
|
} smime_encrypt_table[4] = {
|
|
{ "stock_lock-broken", N_("Unencrypted"), N_("This message is not encrypted. Its content may be viewed in transit across the Internet.") },
|
|
{ "stock_lock-ok", N_("Encrypted, weak"), N_("This message is encrypted, but with a weak encryption algorithm. It would be difficult, but not impossible for an outsider to view the content of this message in a practical amount of time.") },
|
|
{ "stock_lock-ok", N_("Encrypted"), N_("This message is encrypted. It would be difficult for an outsider to view the content of this message.") },
|
|
{ "stock_lock-ok", N_("Encrypted, strong"), N_("This message is encrypted, with a strong encryption algorithm. It would be very difficult for an outsider to view the content of this message in a practical amount of time.") },
|
|
};
|
|
|
|
static const GdkRGBA smime_sign_colour[5] = {
|
|
{ 0 }, { 0.53, 0.73, 0.53, 1 }, { 0.73, 0.53, 0.53, 1 }, { 0.91, 0.82, 0.13, 1 }, { 0 },
|
|
};
|
|
|
|
static gboolean
|
|
emfe_secure_button_format (EMailFormatterExtension *extension,
|
|
EMailFormatter *formatter,
|
|
EMailFormatterContext *context,
|
|
EMailPart *part,
|
|
CamelStream *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>",
|
|
part->id, part->id);
|
|
|
|
camel_stream_write_string (stream, str, cancellable, NULL);
|
|
|
|
g_free (str);
|
|
return TRUE;
|
|
}
|
|
|
|
#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
|
|
static void
|
|
viewcert_clicked (GtkWidget *button,
|
|
GtkWidget *parent)
|
|
{
|
|
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 *w = certificate_viewer_show (ec);
|
|
|
|
/* oddly enough certificate_viewer_show doesn't ... */
|
|
gtk_widget_show (w);
|
|
g_signal_connect (
|
|
w, "response",
|
|
G_CALLBACK (gtk_widget_destroy), NULL);
|
|
|
|
if (w && parent)
|
|
gtk_window_set_transient_for (
|
|
(GtkWindow *) w, (GtkWindow *) parent);
|
|
|
|
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
|
|
format_cert_infos (GQueue *cert_infos,
|
|
GString *output_buffer)
|
|
{
|
|
GQueue valid = G_QUEUE_INIT;
|
|
GList *head, *link;
|
|
|
|
head = g_queue_peek_head_link (cert_infos);
|
|
|
|
/* Make sure we have a valid CamelCipherCertInfo before
|
|
* appending anything to the output buffer, so we don't
|
|
* end up with "()". */
|
|
for (link = head; link != NULL; link = g_list_next (link)) {
|
|
CamelCipherCertInfo *cinfo = link->data;
|
|
|
|
if ((cinfo->name != NULL && *cinfo->name != '\0') ||
|
|
(cinfo->email != NULL && *cinfo->email != '\0')) {
|
|
g_queue_push_tail (&valid, cinfo);
|
|
}
|
|
}
|
|
|
|
if (g_queue_is_empty (&valid))
|
|
return;
|
|
|
|
g_string_append (output_buffer, " (");
|
|
|
|
while (!g_queue_is_empty (&valid)) {
|
|
CamelCipherCertInfo *cinfo;
|
|
|
|
cinfo = g_queue_pop_head (&valid);
|
|
|
|
if (cinfo->name != NULL && *cinfo->name != '\0') {
|
|
g_string_append (output_buffer, cinfo->name);
|
|
|
|
if (cinfo->email != NULL && *cinfo->email != '\0') {
|
|
g_string_append (output_buffer, " <");
|
|
g_string_append (output_buffer, cinfo->email);
|
|
g_string_append (output_buffer, ">");
|
|
}
|
|
|
|
} else if (cinfo->email != NULL && *cinfo->email != '\0') {
|
|
g_string_append (output_buffer, cinfo->email);
|
|
}
|
|
|
|
if (!g_queue_is_empty (&valid))
|
|
g_string_append (output_buffer, ", ");
|
|
}
|
|
|
|
g_string_append_c (output_buffer, ')');
|
|
}
|
|
|
|
static void
|
|
secure_button_clicked_cb (GtkWidget *widget,
|
|
EMailPart *part)
|
|
{
|
|
GtkBuilder *builder;
|
|
GtkWidget *grid, *w;
|
|
GtkWidget *dialog;
|
|
|
|
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[part->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 (part->validity->sign.description) {
|
|
GtkTextBuffer *buffer;
|
|
|
|
buffer = gtk_text_buffer_new (NULL);
|
|
gtk_text_buffer_set_text (
|
|
buffer, part->validity->sign.description,
|
|
strlen (part->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,
|
|
"width_request", 500,
|
|
"height_request", 160,
|
|
NULL),
|
|
NULL);
|
|
g_object_unref (buffer);
|
|
|
|
gtk_container_add (GTK_CONTAINER (grid), w);
|
|
}
|
|
|
|
if (!g_queue_is_empty (&part->validity->sign.signers))
|
|
add_cert_table (
|
|
grid, &part->validity->sign.signers, NULL);
|
|
|
|
gtk_widget_show_all (grid);
|
|
|
|
grid = e_builder_get_widget (builder, "encryption_grid");
|
|
w = gtk_label_new (_(smime_encrypt_table[part->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 (part->validity->encrypt.description) {
|
|
GtkTextBuffer *buffer;
|
|
|
|
buffer = gtk_text_buffer_new (NULL);
|
|
gtk_text_buffer_set_text (
|
|
buffer, part->validity->encrypt.description,
|
|
strlen (part->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,
|
|
"width_request", 500,
|
|
"height_request", 160,
|
|
NULL),
|
|
NULL);
|
|
g_object_unref (buffer);
|
|
|
|
gtk_container_add (GTK_CONTAINER (grid), w);
|
|
}
|
|
|
|
if (!g_queue_is_empty (&part->validity->encrypt.encrypters))
|
|
add_cert_table (grid, &part->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 *
|
|
emfe_secure_button_get_widget (EMailFormatterExtension *extension,
|
|
EMailPartList *context,
|
|
EMailPart *part,
|
|
GHashTable *params)
|
|
{
|
|
GtkWidget *box, *button, *layout, *widget;
|
|
const gchar *icon_name;
|
|
gchar *description;
|
|
GString *buffer;
|
|
buffer = g_string_new ("");
|
|
|
|
if (part->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
|
|
const gchar *desc;
|
|
gint status;
|
|
|
|
status = part->validity->sign.status;
|
|
desc = smime_sign_table[status].shortdesc;
|
|
|
|
g_string_append (buffer, gettext (desc));
|
|
|
|
format_cert_infos (&part->validity->sign.signers, buffer);
|
|
}
|
|
|
|
if (part->validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
|
|
const gchar *desc;
|
|
gint status;
|
|
|
|
if (part->validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
|
|
g_string_append (buffer, "\n");
|
|
|
|
status = part->validity->encrypt.status;
|
|
desc = smime_encrypt_table[status].shortdesc;
|
|
g_string_append (buffer, gettext (desc));
|
|
}
|
|
|
|
description = g_string_free (buffer, FALSE);
|
|
|
|
/* FIXME: need to have it based on encryption and signing too */
|
|
if (part->validity->sign.status != 0)
|
|
icon_name = smime_sign_table[part->validity->sign.status].icon;
|
|
else
|
|
icon_name = smime_encrypt_table[part->validity->encrypt.status].icon;
|
|
|
|
box = gtk_event_box_new ();
|
|
if (part->validity->sign.status != 0)
|
|
gtk_widget_override_background_color (box, GTK_STATE_FLAG_NORMAL,
|
|
&smime_sign_colour[part->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), part);
|
|
|
|
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);
|
|
gtk_box_pack_start (GTK_BOX (layout), widget, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show_all (box);
|
|
|
|
g_free (description);
|
|
return box;
|
|
}
|
|
|
|
static const gchar *
|
|
emfe_secure_button_get_display_name (EMailFormatterExtension *extension)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static const gchar *
|
|
emfe_secure_button_get_description (EMailFormatterExtension *extension)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static const gchar **
|
|
emfe_secure_button_mime_types (EMailExtension *extension)
|
|
{
|
|
return formatter_mime_types;
|
|
}
|
|
|
|
static void
|
|
e_mail_formatter_secure_button_class_init (EMailFormatterSecureButtonClass *class)
|
|
{
|
|
}
|
|
|
|
static void
|
|
e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface)
|
|
{
|
|
iface->format = emfe_secure_button_format;
|
|
iface->get_widget = emfe_secure_button_get_widget;
|
|
iface->get_display_name = emfe_secure_button_get_display_name;
|
|
iface->get_description = emfe_secure_button_get_description;
|
|
}
|
|
|
|
static void
|
|
e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface)
|
|
{
|
|
iface->mime_types = emfe_secure_button_mime_types;
|
|
}
|
|
|
|
static void
|
|
e_mail_formatter_secure_button_init (EMailFormatterSecureButton *extension)
|
|
{
|
|
|
|
}
|