aboutsummaryrefslogblamecommitdiffstats
path: root/em-format/e-mail-formatter-secure-button.c
blob: 571b90d2206866a7332381e80f5a0d6adacd1dbf (plain) (tree)




















                                                                             


                           


                                                
                                


                      
                                       
 

                                                                     
 

                                                     
               

                                       
                                        
 



                                                         



































                                                                                                                                                                                                                                                        

                                                                 















                                                                                  
                                  
 
                                                                                          





                                                                        
                                           
 






                                                                                          
                                  
                                           

                                                               

                                    

                                                             

































                                                                                 
                                                                                              
















                                                                                              
                                                                                  
                                                                                
                                                                               










































































                                                                                        
                                                        




                            

                                            


                                                                  
                                                                           
 
                                                                
                                                                                   


                                                         
                                         



                                                    

                                                             













                                                                         




                                                            
                                                        
                                
                                                             


                                   
                                                                 
                                                                                         


                                                         
                                            



                                                    

                                                                













                                                                         




                                                            

                                                                           












                                                  
                                                                     




                                                  


                                                      

                                   
                                                                       


                                  
                                               



                                                          
                                                                    

         
                                                                             


                                  
                                                                             

                                                       
                                                  






                                                                        

                                                                         
            
                                                                               

                                   
                                       

                                                      
                                                                   





                                                                       

                                  
                                                                 







                                                                       
                             
 


                   










                                                                  

                              

























                                                                                
           
                                                                               
 
                                                 
                                         

                                                          


           
                                                                        
 
 
/*
 * 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 <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-formatter-extension.h"

typedef EMailFormatterExtension EMailFormatterSecureButton;
typedef EMailFormatterExtensionClass EMailFormatterSecureButtonClass;

GType e_mail_formatter_secure_button_get_type (void);

G_DEFINE_TYPE (
    EMailFormatterSecureButton,
    e_mail_formatter_secure_button,
    E_TYPE_MAIL_FORMATTER_EXTENSION)

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 *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
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,
                          CamelCipherValidity *validity)
{
    GtkBuilder *builder;
    GtkWidget *grid, *w;
    GtkWidget *dialog;

    g_return_if_fail (validity != NULL);

    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,
            "width_request", 500,
            "height_request", 160,
            NULL),
            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,
            "width_request", 500,
            "height_request", 160,
            NULL),
            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)
{
    GtkWidget *box, *button, *layout, *widget;
    const gchar *icon_name;
    gchar *description;
    GString *buffer;

    g_return_val_if_fail (validity != NULL, NULL);

    buffer = g_string_new ("");

    if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE) {
        const gchar *desc;
        gint status;

        status = validity->sign.status;
        desc = smime_sign_table[status].shortdesc;

        g_string_append (buffer, gettext (desc));

        format_cert_infos (&validity->sign.signers, buffer);
    }

    if (validity->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE) {
        const gchar *desc;
        gint status;

        if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
            g_string_append (buffer, "\n");

        status = 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 (validity->sign.status != 0)
        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);
    gtk_box_pack_start (GTK_BOX (layout), widget, FALSE, FALSE, 0);

    g_free (description);

    return box;
}

static GtkWidget *
emfe_secure_button_get_widget (EMailFormatterExtension *extension,
                               EMailPartList *context,
                               EMailPart *part,
                               GHashTable *params)
{
    GtkWidget *grid;
    GSList *lst;

    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);

    for (lst = part->validities; lst; lst = lst->next) {
        EMailPartValidityPair *pair = lst->data;
        GtkWidget *widget;

        if (!pair)
            continue;

        widget = secure_button_get_widget_for_validity (pair->validity);
        if (widget) {
            gtk_widget_set_halign (widget, GTK_ALIGN_FILL);
            gtk_widget_set_hexpand (widget, TRUE);
            gtk_container_add (GTK_CONTAINER (grid), widget);
        }
    }

    gtk_widget_show_all (grid);

    return grid;
}

static void
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
e_mail_formatter_secure_button_init (EMailFormatterExtension *extension)
{
}