aboutsummaryrefslogblamecommitdiffstats
path: root/embed/mozilla/GtkNSSDialogs.cpp
blob: f443abef2094c269906325f50824f99cf85f2ad3 (plain) (tree)


































                                                                              




                                       







                                













                                 






                                    
 
                                

                          
                              
                       
                     


                 


                                                   












                                         


                                          














                                                                      


































                                                                                 
                                                     
















                                                                            
                                                           




















                                                                    









                                                               
                                                  



                                                       
                                                    




                                                              

                                                                                     
        
                                                 
                                                                                    
                                                                             

                                                    

                                                                     

                             

                                                                           
 

                                                                     





                                                
                                                    
                                                

                                                                                   


                          


                                                                              
 




                                                                             





















































                                                                                              
        


                                                                                             


                                                                          







































                                                                                             
 
                                                        

                                                                                          








































                                                                      

                                














                                                          

                                     



                                                                    


            








                                                                                     


                                                                               
                                                                          
                                         
                                                                       



                                                                                
                                                                




                                                                                             
                                                                              
 
                       












                                                                  
                                                                                    
 


                                                                     





                                                                   
                                                                             



                                                              

                                                                        



                                                           
                                                                                

                                                          
                                                                            
 

                                                                           

                                                                                       

                                                               
                                                                                             

                                                                                          

                                                      
 

                           
                     




                                     




                                                               


                     














                                                                   
                                                                             



























































































                                                                                             
                                                                             








                                                                                       
                                                                                


                                                      



                                                               
                                     





































































































                                                                                        
                                                                             











































































































                                                                                        
                                                                             















































































                                                                                        
                                                                             





































                                                                                          


                                                               
 
                                     






































































































































































































































































                                                                                                 












                                                    
                                                                              
                                                        
                                                           



                                                                               
                                                                       































































































































                                                                                                     
 
                                     












                                                                                                    
                                    


                     
      
/*
 *  GtkNSSDialogs.cpp
 *
 *  Copyright (C) 2003 Crispin Flowerday <gnome@flowerday.cx>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  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 General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
 * This file provides Gtk implementations of the mozilla Certificate dialogs
 * such as the ones displayed when connecting to a site with a self-signed
 * or expired certificate.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_MOZILLA_PSM

#include "MozillaPrivate.h"

#include "nsIX509Cert.h"
#include "nsCOMPtr.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIX509CertValidity.h"
#include "nsIX509CertDB.h"
#include "nsIASN1Object.h"
#include "nsIASN1Sequence.h"
#include "nsICRLInfo.h"
#include "nsISimpleEnumerator.h"
#include "nsIArray.h"

#include <gconf/gconf-client.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkcheckbutton.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkalignment.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkimage.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkmessagedialog.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkeditable.h>
#include <gtk/gtktable.h>
#include <gtk/gtktreestore.h>
#include <gtk/gtktreeview.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtktextbuffer.h>
#include <gtk/gtktextview.h>
#include <gtk/gtkprogressbar.h>

#include <libgnome/gnome-i18n.h>

#include "GtkNSSDialogs.h"
#include "ephy-file-helpers.h"
#include "ephy-glade.h"
#include "ephy-gui.h"

#include <time.h>

NS_DEFINE_CID (kX509CertCID, NS_IX509CERT_IID);
NS_DEFINE_CID (kASN1ObjectCID, NS_IASN1OBJECT_IID);

enum
{
    NSSDIALOG_RESPONSE_VIEW_CERT = 10
};

GtkNSSDialogs::GtkNSSDialogs ()
{
}

GtkNSSDialogs::~GtkNSSDialogs ()
{
}

NS_IMPL_ISUPPORTS2 (GtkNSSDialogs, 
            nsICertificateDialogs,
            nsIBadCertListener)

/**
 *  Call the mozilla service to display a certificate
 */
static void
view_certificate (nsIInterfaceRequestor *ctx, nsIX509Cert *cert)
{
    nsresult rv;
    nsCOMPtr<nsICertificateDialogs> certDialogs =
        do_GetService (NS_CERTIFICATEDIALOGS_CONTRACTID, &rv);
    g_return_if_fail (NS_SUCCEEDED (rv));

    certDialogs->ViewCert (ctx, cert);
}

/** 
 *  Indent a widget according the HIG
 * 
 *  @returns: The new indented widget
 */
static GtkWidget*
higgy_indent_widget (GtkWidget *widget)
{
    GtkWidget *hbox;
    GtkWidget *label;

    hbox = gtk_hbox_new (FALSE, 6);

    label = gtk_label_new ("");
    gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, TRUE, 6);
    gtk_widget_show (label);

    gtk_box_pack_start (GTK_BOX(hbox), widget, TRUE, TRUE, 0);

    return hbox;
}

/**
 *  Setup up a dialog with the correct HIG'gy spacings, adding the content_widget
 */
static void
higgy_setup_dialog (GtkDialog *dialog, const gchar *stock_icon, 
            GtkWidget **content_label,
            GtkWidget **content_vbox)
{
    GtkWidget *hbox, *label, *image, *vbox;

    g_return_if_fail (GTK_IS_DIALOG (dialog));
    g_return_if_fail (content_label);

    gtk_dialog_set_has_separator (dialog, FALSE);
    gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
    gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
    
    hbox = gtk_hbox_new (FALSE, 12);
    gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
    gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);

    image = gtk_image_new_from_stock (stock_icon, GTK_ICON_SIZE_DIALOG);
    gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
    gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);

    vbox = gtk_vbox_new (FALSE, 12);
    gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);

    label = gtk_label_new (NULL);
    gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
    gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
    gtk_label_set_selectable (GTK_LABEL (label), TRUE);
    gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);

    gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
    
    gtk_widget_show (image);
    gtk_widget_show (vbox);
    gtk_widget_show (hbox);
    gtk_widget_show (label);

    /* Set up the spacing for the dialog internal widgets */
    gtk_box_set_spacing (GTK_BOX(dialog->action_area), 6);  
    gtk_box_set_spacing (GTK_BOX(dialog->vbox), 12);

    *content_label = label;
    if (content_vbox)
    {
        *content_vbox = vbox;
    }
}


/**
 *  Display a dialog box, showing 'View Certificate', 'Cancel',
 *  and 'Accept' buttons. Optionally a checkbox can be shown,
 *  or the text can be NULL to avoid it being displayed
 * 
 *  @returns: GTK_RESPONSE_ACCEPT if the user clicked Accept
 */
static gint
display_cert_warning_box (nsIInterfaceRequestor *ctx, 
                          nsIX509Cert *cert,
              const char *markup_text,
                          const char *checkbox_text,
                          gboolean *checkbox_value,
              const char *affirmative_text)
{
    GtkWidget *dialog, *label, *checkbox, *vbox;
    int res;

    nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
    GtkWidget *gparent = MozillaFindGtkParent (parent);

        g_return_val_if_fail (markup_text, GTK_RESPONSE_CANCEL);
        g_return_val_if_fail (!checkbox_text || checkbox_value, GTK_RESPONSE_CANCEL);
    
    dialog = gtk_dialog_new_with_buttons ("",
                          gparent ? GTK_WINDOW (gparent) : NULL,
                          GTK_DIALOG_DESTROY_WITH_PARENT,
                          NULL);

    higgy_setup_dialog (GTK_DIALOG (dialog), 
                GTK_STOCK_DIALOG_WARNING, &label, &vbox);

    /* Add the buttons */
    gtk_dialog_add_button (GTK_DIALOG (dialog), _("_View Certificate"),
                   NSSDIALOG_RESPONSE_VIEW_CERT);

    gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL,
                   GTK_RESPONSE_CANCEL);

    if (affirmative_text == NULL)
    {
        affirmative_text = _("_Accept");
    }

    gtk_dialog_add_button (GTK_DIALOG (dialog), 
                   affirmative_text,
                   GTK_RESPONSE_ACCEPT);
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);

        if (checkbox_text)
    {
        checkbox = gtk_check_button_new_with_mnemonic (checkbox_text);
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), 
                          *checkbox_value);

        gtk_box_pack_start (GTK_BOX (vbox), checkbox, TRUE, TRUE, 0);
    }
    else
    {
        checkbox = 0;
    }

    gtk_label_set_markup (GTK_LABEL (label), markup_text);
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
    gtk_widget_show_all (dialog);

    while (1)
    {
        res = gtk_dialog_run (GTK_DIALOG (dialog));
        if (res == NSSDIALOG_RESPONSE_VIEW_CERT)
        {
                      view_certificate (ctx, cert);
              continue;
        }
    
        break;
    }

    if (res == GTK_RESPONSE_ACCEPT && checkbox)
    {
        *checkbox_value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox));
    }

    gtk_widget_destroy (dialog);
        return res;
}


NS_IMETHODIMP
GtkNSSDialogs::ConfirmMismatchDomain (nsIInterfaceRequestor *ctx,
                                      const nsACString &targetURL,
                                      nsIX509Cert *cert, PRBool *_retval)
{
    nsAutoString commonName;
    char *ttTargetUrl, *ttCommonName, *first, *second, *msg;
    int res;

    cert->GetCommonName (commonName);

    ttTargetUrl = g_strdup_printf ("\"<tt>%s</tt>\"", 
                                        PromiseFlatCString(targetURL).get());

    ttCommonName = g_strdup_printf ("\"<tt>%s</tt>\"", 
                                         NS_ConvertUCS2toUTF8(commonName).get());

        first = g_strdup_printf (_("The site %s returned security information for "
                   "%s. It is possible that someone is intercepting "
                   "your communication to obtain your confidential "
                   "information."),
                 ttTargetUrl, ttCommonName);

        second = g_strdup_printf (_("You should only accept the security information if you "
                                    "trust %s and %s."),
                                  ttTargetUrl, ttCommonName);
    
    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
                   _("Accept incorrect security information?"),
                   first, second);
 
    res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL);
 
    g_free (ttTargetUrl);
    g_free (ttCommonName);
        g_free (second);
        g_free (first);
        g_free (msg);

    *_retval = (res == GTK_RESPONSE_ACCEPT);
    return NS_OK;
}


NS_IMETHODIMP
GtkNSSDialogs::ConfirmUnknownIssuer (nsIInterfaceRequestor *ctx,
                                     nsIX509Cert *cert, PRInt16 *outAddType,
                                     PRBool *_retval)
{
    gboolean accept_perm = FALSE;
    nsAutoString commonName;
    char *ttCommonName, *secondary, *tertiary, *msg;
    int res;

    cert->GetCommonName (commonName);

    ttCommonName = g_strdup_printf ("\"<tt>%s</tt>\"", 
                    NS_ConvertUCS2toUTF8(commonName).get());

    secondary = g_strdup_printf
                   (_("Your browser was unable to trust %s. "
                  "It is possible that someone is intercepting your "
                  "communication to obtain your confidential information."),
                  ttCommonName);

        tertiary = g_strdup_printf
                   (_("You should only connect to the site if you are certain "
                  "you are connected to %s."),
                ttCommonName);

    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
                   _("Connect to untrusted site?"),
                   secondary, tertiary);
 
    res = display_cert_warning_box (ctx, cert, msg, 
                    _("_Don't show this message again for this site"),
                    &accept_perm, _("Co_nnect"));
    g_free (ttCommonName);
        g_free (tertiary);
        g_free (secondary);
        g_free (msg);

        if (res != GTK_RESPONSE_ACCEPT)
    {
        *_retval = PR_FALSE;
        *outAddType = UNINIT_ADD_FLAG;
    }
    else
    {
        if (accept_perm)
        {
            *_retval    = PR_TRUE;
            *outAddType = ADD_TRUSTED_PERMANENTLY;
        }
        else
        {
            *_retval    = PR_TRUE;
            *outAddType = ADD_TRUSTED_FOR_SESSION;
        }
    }

    return NS_OK;
}


/* boolean confirmCertExpired (in nsIInterfaceRequestor socketInfo, 
   in nsIX509Cert cert); */
NS_IMETHODIMP 
GtkNSSDialogs::ConfirmCertExpired (nsIInterfaceRequestor *ctx,
                                   nsIX509Cert *cert, PRBool *_retval)
{
    nsresult rv;
    PRTime now = PR_Now();
    PRTime notAfter, notBefore, timeToUse;
    PRInt64 normalizedTime;
    nsAutoString commonName;
    time_t t;
    struct tm tm;
    char formattedDate[128];
    char *fdate;
    const char *primary, *text;
    char *ttCommonName, *secondary, *msg;

    *_retval = PR_FALSE;
    
    nsCOMPtr<nsIX509CertValidity> validity;
    rv = cert->GetValidity (getter_AddRefs(validity));
    if (NS_FAILED(rv)) return rv;
    
    rv = validity->GetNotAfter (&notAfter);
    if (NS_FAILED(rv)) return rv;
    
    rv = validity->GetNotBefore (&notBefore);
    if (NS_FAILED(rv)) return rv;
    
    if (LL_CMP(now, >, notAfter))
    {
        primary = _("Accept expired security information?");
        text    = _("The security information for %s "
                "expired on %s.");
        timeToUse = notAfter;
    } 
    else
    {
        primary = _("Accept not yet valid security information?");
        text    = _("The security information for %s isn't valid until %s.");
        timeToUse = notBefore;
    }
    
    cert->GetCommonName (commonName);

    LL_DIV (normalizedTime, timeToUse, PR_USEC_PER_SEC);
    LL_L2UI (t, normalizedTime);
    /* To translators: this a time format that is used while displaying the
     * expiry or start date of an SSL certificate, for the format see 
     * strftime(3) */
    strftime (formattedDate, sizeof(formattedDate), _("%a %d %b %Y"), 
          localtime_r (&t, &tm));
    fdate = g_locale_to_utf8 (formattedDate, -1, NULL, NULL, NULL);

    ttCommonName = g_strdup_printf ("\"<tt>%s</tt>\"", 
                                        NS_ConvertUCS2toUTF8(commonName).get());

    secondary = g_strdup_printf (text, ttCommonName, fdate);

    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
                   primary, secondary, 
                   _("You should ensure that your computer's time is correct."));

    int res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL);

    g_free (fdate);
    g_free (msg);
    g_free (secondary);
    g_free (ttCommonName);

    *_retval = (res == GTK_RESPONSE_ACCEPT);
    
    return NS_OK;
}

/* void notifyCrlNextupdate (in nsIInterfaceRequestor socketInfo, 
   in AUTF8String targetURL, in nsIX509Cert cert); */
NS_IMETHODIMP 
GtkNSSDialogs::NotifyCrlNextupdate (nsIInterfaceRequestor *ctx,
                    const nsACString & targetURL, nsIX509Cert *cert)
{
    GtkWidget *dialog, *label;
    char *ttCommonName, *ttTargetUrl, *msg, *primary, *secondary;
    nsAutoString commonName;

    nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
    GtkWidget *gparent = MozillaFindGtkParent (parent);

    dialog = gtk_dialog_new_with_buttons ("",
                          GTK_WINDOW (gparent),
                          GTK_DIALOG_DESTROY_WITH_PARENT,
                          GTK_STOCK_OK,
                          GTK_RESPONSE_OK,
                          NULL);

    higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_ERROR,
                &label, NULL);

    cert->GetCommonName (commonName);

    ttCommonName = g_strdup_printf ("\"<tt>%s</tt>\"", 
                    NS_ConvertUCS2toUTF8(commonName).get());

    ttTargetUrl = g_strdup_printf ("\"<tt>%s</tt>\"", 
                       PromiseFlatCString(targetURL).get());

    primary = g_strdup_printf (_("Cannot establish connection to %s."),
                   ttTargetUrl);

    secondary = g_strdup_printf (_("The certificate revocation list (CRL) from %s "
                       "needs to be updated."),
                     ttCommonName);
    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
                   primary, secondary,
                   _("Please ask your system administrator for assistance."));
    
    gtk_label_set_markup (GTK_LABEL (label), msg);

    g_free (primary);
    g_free (secondary);
    g_free (msg);
    g_free (ttCommonName);
    g_free (ttTargetUrl);

    gtk_widget_show_all (dialog);

    g_signal_connect (G_OBJECT (dialog),
              "response",
              (GCallback)gtk_widget_destroy, NULL);

    gtk_widget_show_all (dialog);
    return NS_OK;
}

NS_IMETHODIMP 
GtkNSSDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor *ctx, 
                    nsIX509Cert *cert,
                    PRUint32 *_trust,
                    PRBool *_retval)
{
    GtkWidget *dialog, *label, *content_vbox, *vbox;
    GtkWidget *check_ssl, *check_software;
    char *ttCommonName, *msg, *tertiary;

    nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
    GtkWidget *gparent = MozillaFindGtkParent (parent);

    dialog = gtk_dialog_new_with_buttons ("",
                          GTK_WINDOW (gparent),
                          GTK_DIALOG_DESTROY_WITH_PARENT,
                          _("_View Certificate"),
                          NSSDIALOG_RESPONSE_VIEW_CERT,
                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                          _("_Trust CA"),   GTK_RESPONSE_ACCEPT,
                          NULL);

    higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_WARNING,
                &label, &content_vbox);
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);

    nsAutoString commonName;
    cert->GetCommonName (commonName);
    ttCommonName = g_strdup_printf ("\"<tt>%s</tt>\"", 
                     NS_ConvertUCS2toUTF8(commonName).get());

    tertiary = g_strdup_printf (_("Trust %s to identify:"), ttCommonName );
    g_free (ttCommonName);

    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
                   _("Trust new Certificate Authority?"),
                   _("Before trusting a Certificate Authority (CA) you should "
                 "verify the certificate is authentic."),
                   tertiary);
    gtk_label_set_markup (GTK_LABEL (label), msg);
    g_free (tertiary);
    g_free (msg);

    vbox = gtk_vbox_new (FALSE, 6);

    check_ssl = gtk_check_button_new_with_mnemonic 
                  (_("_Web sites"));
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_ssl), TRUE);
    gtk_box_pack_start (GTK_BOX(vbox), check_ssl, TRUE, TRUE, 0);

    check_software = gtk_check_button_new_with_mnemonic 
                  (_("_Software developers"));
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_software), FALSE);
    gtk_box_pack_start (GTK_BOX(vbox), check_software, TRUE, TRUE, 0);

    gtk_box_pack_start (GTK_BOX (content_vbox), higgy_indent_widget (vbox), 
                FALSE, FALSE, 0);

    gtk_widget_show_all (dialog);
    int ret;

    while (1)
    {
        ret = gtk_dialog_run (GTK_DIALOG (dialog));
        if (ret == NSSDIALOG_RESPONSE_VIEW_CERT)
        {
              view_certificate (ctx, cert);
              continue;
        }
    
        break;
    }

    if (ret != GTK_RESPONSE_ACCEPT)
    {
        *_retval = PR_FALSE;
    }
    else
    {
        *_trust = nsIX509CertDB::UNTRUSTED;
        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_ssl)))
        {
            *_trust |= nsIX509CertDB::TRUSTED_SSL;
        }

        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_software)))
        {
            *_trust |= nsIX509CertDB::TRUSTED_SSL;
        }
        *_retval = PR_TRUE;
    }
    gtk_widget_destroy (dialog);

    return NS_OK;
}


NS_IMETHODIMP 
GtkNSSDialogs::NotifyCACertExists (nsIInterfaceRequestor *ctx)
{
    GtkWidget *dialog, *label;
    char * msg;

    nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
    GtkWidget *gparent = MozillaFindGtkParent (parent);

    dialog = gtk_dialog_new_with_buttons ("",
                          GTK_WINDOW (gparent),
                          GTK_DIALOG_DESTROY_WITH_PARENT,
                          GTK_STOCK_OK,
                          GTK_RESPONSE_OK,
                          NULL);

    higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_ERROR,
                &label, NULL);

    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
                _("Certificate already exists."),
                   _("The certificate has already been imported."));
    gtk_label_set_markup (GTK_LABEL (label), msg);
    g_free (msg);

    g_signal_connect (G_OBJECT (dialog),
              "response",
              (GCallback)gtk_widget_destroy, NULL);

    gtk_widget_show_all (dialog);
    return NS_OK;
}

struct SetPasswordCallback
{
    GtkWidget *entry1;
    GtkWidget *entry2;
    GtkWidget *widget;
};


static void
set_password_entry_changed_cb (GtkEditable *editable, void * _data)
{
    SetPasswordCallback * data = (SetPasswordCallback*)_data;
    gchar * text1 = gtk_editable_get_chars 
                            (GTK_EDITABLE(data->entry1), 0, -1);
    gchar * text2 = gtk_editable_get_chars 
                            (GTK_EDITABLE(data->entry2), 0, -1);

    if (strcmp (text1, text2) == 0)
    {
        gtk_widget_set_sensitive (data->widget, TRUE);
    }
    else
    {
        gtk_widget_set_sensitive (data->widget, FALSE);
    }

    g_free (text1);
    g_free (text2);
}


/**
 *  Calculate the quality of a password. The algorithm used is taken
 *  directly from mozilla in:
 *     $MOZSRC/security/manager/pki/resources/content/password.js
 */
static void
password_quality_meter_cb (GtkEditable *editable, GtkWidget *progress)
{
    gchar * text = gtk_editable_get_chars (editable, 0, -1);

    /* Get the length */
    glong length = g_utf8_strlen (text, -1);

    /* Count the number of number, symbols and uppercase chars */
    gint uppercase = 0;
    gint symbols = 0;
    gint numbers = 0;
    for( const gchar * p = text; *p; p = g_utf8_find_next_char (p, NULL) )
    {
        gunichar uc = g_utf8_get_char(p);
        if (g_unichar_isdigit (uc))
        {
            numbers++;
        }
        else if (g_unichar_isupper (uc))
        {
            uppercase++;
        }
        else if (g_unichar_islower (uc))
        {
            /* Not counted */
        }
        else if (g_unichar_isgraph (uc))
        {
            symbols++;
        }
    }

    if (length    > 5) length = 5;
    if (numbers   > 3) numbers = 3;
    if (symbols   > 3) symbols = 3;
    if (uppercase > 3) uppercase = 3;
    
    gint strength = ((length*10)-20) + (numbers*10) + (symbols*15) + (uppercase*10);
    if (strength < 0)   strength = 0;
    if (strength > 100) strength = 100;

    gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), (strength/100.0));

    g_free (text);
}


NS_IMETHODIMP 
GtkNSSDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor *ctx, 
                    nsAString &_password,
                    PRBool *_retval)
{
    GtkWidget *dialog, *table, *entry1, *entry2, *button, *label, *vbox;
    GtkWidget *progress;
    char *msg;

    nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
    GtkWidget *gparent = MozillaFindGtkParent (parent);


    dialog = gtk_dialog_new_with_buttons ("",
                          GTK_WINDOW (gparent),
                          GTK_DIALOG_DESTROY_WITH_PARENT,
                          GTK_STOCK_CANCEL,
                          GTK_RESPONSE_CANCEL,
                          NULL);

    higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_QUESTION,
                &label, &vbox);

    button = gtk_button_new_with_mnemonic (_("_Backup Certificate"));
    gtk_widget_show (button);
    gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);

    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
                   _("Select password."),
                   _("Select a password to protect this certificate."));
    gtk_label_set_markup (GTK_LABEL (label), msg);
    g_free (msg);

    table = gtk_table_new (3, 3, FALSE);
    gtk_table_set_row_spacings (GTK_TABLE (table), 6);
    gtk_table_set_col_spacings (GTK_TABLE (table), 6);
    gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);

    label = gtk_label_new (NULL);
    entry1 = gtk_entry_new ();
    entry2 = gtk_entry_new ();
    gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Password:"));
    gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry1);
    gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
    gtk_entry_set_visibility (GTK_ENTRY (entry1), FALSE);
    g_signal_connect_swapped (entry1, "activate",
                  (GCallback)gtk_widget_grab_focus,
                  entry2);

    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, 
              GTK_FILL, GTK_FILL, 0, 0 );
    gtk_table_attach (GTK_TABLE (table), entry1, 1, 2, 0, 1,
              GTK_FILL, GTK_FILL, 0, 0 );

    label = gtk_label_new (NULL);
    gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("Con_firm password:"));
    gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry2);
    gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
    gtk_entry_set_visibility (GTK_ENTRY (entry2), FALSE);
    gtk_entry_set_activates_default (GTK_ENTRY (entry2), TRUE);

    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, 
              GTK_FILL, GTK_FILL, 0, 0 );
    gtk_table_attach (GTK_TABLE (table), entry2, 1, 2, 1, 2,
              GTK_FILL, GTK_FILL, 0, 0 );

    /* TODO: We need a better password quality meter */
    label = gtk_label_new (_("Password quality:"));
    gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
    progress = gtk_progress_bar_new ();
    gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), 0.0);

    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, 
              GTK_FILL, GTK_FILL, 0, 0 );
    gtk_table_attach (GTK_TABLE (table), progress, 1, 2, 2, 3,
              GTK_FILL, GTK_FILL, 0, 0 );

    SetPasswordCallback callback_data = { entry1, entry2, button };
    g_signal_connect (entry1, "changed",
              (GCallback)set_password_entry_changed_cb,
              &callback_data);

    g_signal_connect (entry1, "changed",
              (GCallback)password_quality_meter_cb,
              progress);

    g_signal_connect (entry2, "changed",
              (GCallback)set_password_entry_changed_cb,
              &callback_data);


    gtk_widget_show_all (dialog);
    int ret = gtk_dialog_run (GTK_DIALOG (dialog));

    if (ret != GTK_RESPONSE_OK)
    {
        *_retval = PR_FALSE;
    }
    else
    {
        gchar * text = gtk_editable_get_chars (GTK_EDITABLE (entry1), 0, -1);
        _password = NS_ConvertUTF8toUCS2 (text);
        g_free (text);
        *_retval = PR_TRUE;
    }
    gtk_widget_destroy (dialog);
    return NS_OK;
}

NS_IMETHODIMP 
GtkNSSDialogs::GetPKCS12FilePassword(nsIInterfaceRequestor *ctx, 
                     nsAString &_password,
                     PRBool *_retval)
{
    GtkWidget *dialog, *hbox, *label, *entry, *vbox;
    char *msg;

    nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
    GtkWidget *gparent = MozillaFindGtkParent (parent);

    dialog = gtk_dialog_new_with_buttons ("",
                          GTK_WINDOW (gparent),
                          GTK_DIALOG_DESTROY_WITH_PARENT,
                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                          _("I_mport Certificate"), GTK_RESPONSE_OK,
                          NULL);

    higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_QUESTION,
                &label, &vbox);
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);

    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
                   _("Password required."),
                   _("Enter the password for this certificate."));
    gtk_label_set_markup (GTK_LABEL (label), msg);
    g_free (msg);

    hbox = gtk_hbox_new (FALSE, 6);
    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
    
    label = gtk_label_new (NULL);
    entry = gtk_entry_new ();

    gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Password:"));
    gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
    gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
    gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);

    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);

    gtk_widget_show_all (dialog);
    int ret = gtk_dialog_run (GTK_DIALOG (dialog));

    if (ret != GTK_RESPONSE_OK)
    {
        *_retval = PR_FALSE;
    }
    else
    {
        gchar * text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
        _password = NS_ConvertUTF8toUCS2 (text);
        g_free (text);
        *_retval = PR_TRUE;
    }
    gtk_widget_destroy (dialog);

    return NS_OK;
}


static void
set_table_row (GtkWidget *table, int row, const char *title, GtkWidget *label)
{
    GtkWidget *header;
    char buf[64];

    g_snprintf (buf, sizeof(buf), "<b>%s</b>", title);
    header = gtk_label_new (buf);
    gtk_label_set_use_markup (GTK_LABEL(header), TRUE);
    gtk_misc_set_alignment (GTK_MISC(header), 0, 0);
    gtk_widget_show (header);
    gtk_table_attach (GTK_TABLE (table), header, 0, 1, row, row+1,
              GTK_FILL, GTK_FILL, 0, 0);
    
    gtk_misc_set_alignment (GTK_MISC(label), 0, 0);
    gtk_widget_show (label);
    gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, row, row+1);
}

NS_IMETHODIMP 
GtkNSSDialogs::CrlImportStatusDialog(nsIInterfaceRequestor *ctx, nsICRLInfo *crl)
{

    GtkWidget *dialog, *label, *table, *vbox;
    nsresult rv;
    char *msg;

    nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
    GtkWidget *gparent = MozillaFindGtkParent (parent);

    dialog = gtk_dialog_new_with_buttons ("",
                          GTK_WINDOW (gparent),
                          GTK_DIALOG_DESTROY_WITH_PARENT,
                          GTK_STOCK_OK, GTK_RESPONSE_OK,
                          NULL);

    higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_INFO,
                &label, &vbox);

    msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
                   _("Certificate Revocation list successfully imported."),
                   _("Certificate Revocation list (CRL) imported:"));
    gtk_label_set_markup (GTK_LABEL (label), msg);
    g_free (msg);

    table = gtk_table_new (2, 3, FALSE);
    gtk_table_set_row_spacings (GTK_TABLE (table), 6);
    gtk_table_set_col_spacings (GTK_TABLE (table), 6);

    nsAutoString org, orgUnit, nextUpdate;
    rv = crl->GetOrganization (org);
    if (NS_FAILED(rv)) return rv;

    rv = crl->GetOrganizationalUnit (orgUnit);
    if (NS_FAILED(rv)) return rv;

    rv = crl->GetNextUpdateLocale (nextUpdate);
    if (NS_FAILED(rv)) return rv;

    label = gtk_label_new (NS_ConvertUCS2toUTF8(org).get());
    set_table_row (table, 0, _("Organization:"), label);

    label = gtk_label_new (NS_ConvertUCS2toUTF8(orgUnit).get());
    set_table_row (table, 1, _("Unit:"), label);

    label = gtk_label_new (NS_ConvertUCS2toUTF8(nextUpdate).get());
    set_table_row (table, 2, _("Next Update:"), label);

    gtk_box_pack_start (GTK_BOX (vbox), higgy_indent_widget (table), FALSE, FALSE, 0);

    gtk_widget_show_all (dialog);
    g_signal_connect (G_OBJECT (dialog),
              "response",
              (GCallback)gtk_widget_destroy, NULL);

    gtk_widget_show_all (dialog);
    return NS_OK;
}

/** 
 *  Help function to fill in the labels on the General tab
 */
static void
set_label_cert_attribute (GladeXML* gxml, const char* label_id, nsAutoString &value)
{
    GtkWidget *label;
    label = glade_xml_get_widget (gxml, label_id);

    g_return_if_fail (GTK_IS_LABEL (label));

    if (value.IsEmpty()) {
        gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
        char *msg = g_strdup_printf ("<i>&lt;%s&gt;</i>",
                         _("Not part of certificate"));
        gtk_label_set_markup (GTK_LABEL (label), msg);
        g_free (msg);
    }
    else
    {
        gtk_label_set_use_markup (GTK_LABEL (label), FALSE);
        gtk_label_set_text (GTK_LABEL (label),
                    NS_ConvertUCS2toUTF8(value).get());
    }
}


/**
 *  Do that actual filling in of the certificate tree
 */
static gboolean
fill_cert_chain_tree (GtkTreeView *treeview, nsIArray *certChain)
{
    nsresult rv;
    GtkTreeModel * model = gtk_tree_view_get_model (treeview);

    GtkTreeIter parent;
    PRUint32 numCerts;
    rv =  certChain->GetLength (&numCerts);
    if (NS_FAILED(rv) || numCerts < 1) return FALSE;

    for (int i = (int)numCerts-1 ; i >= 0; i--)
    {
        nsCOMPtr<nsIX509Cert> nsCert;
        rv = certChain->QueryElementAt (i, kX509CertCID,
                        getter_AddRefs(nsCert));
        if (NS_FAILED(rv)) return FALSE;

        GtkTreeIter iter;
        gtk_tree_store_append (GTK_TREE_STORE (model), &iter, 
                       (i == (int)numCerts-1) ? NULL : &parent);

        nsAutoString value;
        rv = nsCert->GetCommonName (value);
        if (NS_FAILED(rv)) return FALSE;

        nsIX509Cert *nsCertP = nsCert;
        if (!value.IsEmpty())
        {
            gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
                        0, NS_ConvertUCS2toUTF8(value).get(),
                        1, nsCertP,
                        -1);
        }
        else
        {
            char * title;
            rv = nsCert->GetWindowTitle (&title);
            if (NS_FAILED(rv)) return FALSE;
            
            gtk_tree_store_set (GTK_TREE_STORE(model),
                        &iter, 0, title, 1, nsCertP, -1);
            nsMemory::Free (title);
        }
        parent = iter;
    }
    gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview));

    /* And select the last entry */
    GtkTreeSelection *select = gtk_tree_view_get_selection (treeview);
    GtkTreePath *path = gtk_tree_model_get_path (model, &parent);
    gtk_tree_selection_select_path (select, path);
    gtk_tree_path_free (path);

    return TRUE; 
}

/**
 *  Add an ASN object to the treeview, recursing if the object was a
 *  sequence
 */
static void
add_asn1_object_to_tree(GtkTreeModel *model, nsIASN1Object *object, GtkTreeIter *parent)
{
    nsAutoString dispNameU;
    object->GetDisplayName(dispNameU);

    GtkTreeIter iter;
    gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent);

    gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
                0, NS_ConvertUCS2toUTF8(dispNameU).get(),
                1, object,
                -1);

    nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object));
    if (!sequence) return;

    nsCOMPtr<nsIMutableArray> asn1Objects;
    sequence->GetASN1Objects(getter_AddRefs(asn1Objects));

    PRUint32 numObjects;
    asn1Objects->GetLength(&numObjects);
    if (!asn1Objects) return;

    for (PRUint32 i = 0; i < numObjects ; i++)
    {
        nsCOMPtr<nsIASN1Object> currObject;
        asn1Objects->QueryElementAt (i, kASN1ObjectCID,
                         getter_AddRefs (currObject));
        add_asn1_object_to_tree (model, currObject, &iter);
    }
}


/**
 *  Update the "Certificate Fields" treeview when a different cert
 *  is selected in the hierarchy text view
 */
static void
cert_chain_tree_view_selection_changed_cb (GtkTreeSelection *selection, 
                       GtkWidget* tree_view)
{
    GtkTreeIter iter;
    nsIX509Cert *nsCert;
    nsresult rv;
    GtkTreeModel * model;
        
    if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
        gtk_tree_model_get (model, &iter, 1, &nsCert, -1);

        nsCOMPtr<nsIASN1Object> object;
        rv = nsCert->GetASN1Structure (getter_AddRefs(object));
        if (NS_FAILED(rv)) return;

        model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
        gtk_tree_store_clear (GTK_TREE_STORE (model));
        add_asn1_object_to_tree (model, object, NULL);

        gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
    }
}

/**
 *  When the "Certificate Field" treeview is changed, update the 
 *  text_view to display the value of the currently selected field
 */
static void
field_tree_view_selection_changed_cb (GtkTreeSelection *selection, 
                      GtkWidget* text_view)
{
    GtkTreeIter iter;
    GtkTreeModel *model;
    GtkTextBuffer * text_buffer = 
        gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));

    if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
        nsIASN1Object *object;
        nsAutoString dispValU;

        gtk_tree_model_get (model, &iter, 1, &object, -1);

        object->GetDisplayValue(dispValU);
        gtk_text_buffer_set_text (text_buffer, 
                      NS_ConvertUCS2toUTF8(dispValU).get(),
                      -1);
    }
    else
    {
        gtk_text_buffer_set_text (text_buffer, "", 0);  
    }
}

/**
 *  Setup the various treeviews, the textview, and fill the treeviews
 */
static gboolean
setup_view_cert_tree (GtkWidget *dialog, GladeXML*gxml, nsIArray *certChain)
{
    GtkCellRenderer *renderer;
    GtkWidget *chain_tree_view, *field_tree_view, *text_view;
    PangoFontDescription *monospace_font_desc;
    GConfClient *conf_client;
    char *monospace_font;

    chain_tree_view = glade_xml_get_widget (gxml, "treeview_cert_chain");
    field_tree_view = glade_xml_get_widget (gxml, "treeview_cert_info");
    text_view   = glade_xml_get_widget (gxml, "textview_field_value");

    /* Setup the certificate chain view */
    GtkTreeStore *store = gtk_tree_store_new (2, 
                          G_TYPE_STRING,
                          G_TYPE_POINTER);
    gtk_tree_view_set_model (GTK_TREE_VIEW (chain_tree_view), GTK_TREE_MODEL (store));


    renderer = gtk_cell_renderer_text_new ();
    gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (chain_tree_view),
                             0, "Certificate",
                             renderer,
                             "text", 0,
                             NULL);

    GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (chain_tree_view));
    gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);

    g_signal_connect (G_OBJECT (select), "changed",
              G_CALLBACK (cert_chain_tree_view_selection_changed_cb),
              field_tree_view);

    /* Setup the certificate field view */
    store = gtk_tree_store_new (2, 
                    G_TYPE_STRING,
                    G_TYPE_POINTER);
    gtk_tree_view_set_model (GTK_TREE_VIEW (field_tree_view), GTK_TREE_MODEL (store));


    gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (field_tree_view),
                             0, "Certificate Field",
                             renderer,
                             "text", 0,
                             NULL);

    select = gtk_tree_view_get_selection (GTK_TREE_VIEW (field_tree_view));
    gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);

    g_signal_connect (G_OBJECT (select), "changed",
              G_CALLBACK (field_tree_view_selection_changed_cb),
              text_view);

    /* Get the text_view displaying a propertional font
     *
     * Pick up the monospace font from desktop preferences */
    conf_client = gconf_client_get_default ();
    monospace_font = gconf_client_get_string (conf_client, 
                 "/desktop/gnome/interface/monospace_font_name", NULL);
    if (monospace_font)
    {
        monospace_font_desc = pango_font_description_from_string (monospace_font);
        gtk_widget_modify_font (text_view, monospace_font_desc);
        pango_font_description_free (monospace_font_desc);
    }
    g_object_unref (conf_client);      
    
    /* And fill the certificate chain tree */
    return fill_cert_chain_tree (GTK_TREE_VIEW (chain_tree_view), certChain);
}

/* void viewCert (in nsIX509Cert cert); */
NS_IMETHODIMP 
GtkNSSDialogs::ViewCert(nsIInterfaceRequestor *ctx, 
               nsIX509Cert *cert)
{
    GtkWidget *dialog, *widget;
    GladeXML *gxml;
    nsAutoString value;
    nsresult rv;
    PRUint32 verifystate, count;
    PRUnichar ** usage;
    GtkSizeGroup * sizegroup;

    gxml = ephy_glade_widget_new (ephy_file ("certificate-dialogs.glade"),
                      "viewcert_dialog",
                      &dialog, NULL, NULL);

    nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
    GtkWidget *gparent = MozillaFindGtkParent (parent);
    gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(gparent));
    gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);

    gtk_window_set_title (GTK_WINDOW (dialog), _("Certificate Properties"));
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);

    /* Set up the GtkSizeGroup so that the columns line up */
    sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
    widget = glade_xml_get_widget (gxml, "label_size1");
    gtk_size_group_add_widget (sizegroup, widget);
    widget = glade_xml_get_widget (gxml, "label_size2");
    gtk_size_group_add_widget (sizegroup, widget);
    widget = glade_xml_get_widget (gxml, "label_size3");
    gtk_size_group_add_widget (sizegroup, widget);
    widget = glade_xml_get_widget (gxml, "label_size4");
    gtk_size_group_add_widget (sizegroup, widget);
    g_object_unref (sizegroup);

    rv = cert->GetUsagesArray (FALSE, &verifystate, &count, &usage);
    if (NS_FAILED(rv)) return rv;

    const char * text;
    switch (verifystate)
    {
    case nsIX509Cert::VERIFIED_OK:
        text = _("This certificate has been verified for the following uses:");
        break;
    case nsIX509Cert::CERT_REVOKED:
        text = _("Could not verify this certificate because it has been revoked.");
        break;
    case nsIX509Cert::CERT_EXPIRED:
        text = _("Could not verify this certificate because it has expired.");
        break;
    case nsIX509Cert::CERT_NOT_TRUSTED:
        text = _("Could not verify this certificate because it is not trusted.");
        break;
    case nsIX509Cert::ISSUER_NOT_TRUSTED:
        text = _("Could not verify this certificate because the issuer is not trusted.");
        break;
    case nsIX509Cert::ISSUER_UNKNOWN:
        text = _("Could not verify this certificate because the issuer is unknown.");
        break;
    case nsIX509Cert::INVALID_CA:
        text = _("Could not verify this certificate because the CA certificate is invalid.");
        break;
    case nsIX509Cert::NOT_VERIFIED_UNKNOWN:
    case nsIX509Cert::USAGE_NOT_ALLOWED:
    default:
        text = _("Could not verify this certificate for unknown reasons.");
    }
    
    char *msg = g_strdup_printf ("<b>%s</b>", text);
    widget = glade_xml_get_widget (gxml, "label_verify_text");
    g_return_val_if_fail (GTK_IS_LABEL (widget), NS_ERROR_FAILURE);
    gtk_label_set_markup (GTK_LABEL (widget), msg);
    g_free (msg);

    if (count > 0)
    {
        GtkWidget *vbox = gtk_vbox_new (FALSE, 3);
        GtkWidget *indent;
        for (PRUint32 i = 0 ; i < count ; i++)
        {
            const nsACString &msg = NS_ConvertUCS2toUTF8 (usage[i]);
            GtkWidget *label = gtk_label_new(PromiseFlatCString(msg).get());
            gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
            gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
            nsMemory::Free (usage[i]);
        }
        nsMemory::Free (usage);
        indent = higgy_indent_widget (vbox);
        widget = glade_xml_get_widget (gxml, "vbox_validity");
        g_return_val_if_fail (GTK_IS_BOX (widget), NS_ERROR_FAILURE);
    
        gtk_box_pack_start (GTK_BOX (widget), indent, FALSE, FALSE, 0);
    }


    cert->GetCommonName (value);
    set_label_cert_attribute (gxml, "label_cn", value);

    cert->GetOrganization (value);
    set_label_cert_attribute (gxml, "label_o", value);

    cert->GetOrganizationalUnit (value);
    set_label_cert_attribute (gxml, "label_ou", value);

    cert->GetSerialNumber (value);
    set_label_cert_attribute (gxml, "label_serial", value);

    rv = cert->GetIssuerCommonName (value);
    if (NS_FAILED(rv)) return rv;
    set_label_cert_attribute (gxml, "label_issuer_cn", value);

    cert->GetIssuerOrganization (value);
    set_label_cert_attribute (gxml, "label_issuer_o", value);

    cert->GetIssuerOrganizationUnit (value);
    set_label_cert_attribute (gxml, "label_issuer_ou", value);

    nsCOMPtr<nsIX509CertValidity> validity;
    rv = cert->GetValidity (getter_AddRefs(validity));
    if (NS_FAILED(rv)) return rv;
    
    rv = validity->GetNotAfterLocalDay (value);
    if (NS_FAILED(rv)) return rv;
    set_label_cert_attribute (gxml, "label_notafter", value);
    
    rv = validity->GetNotBeforeLocalDay (value);
    if (NS_FAILED(rv)) return rv;
    set_label_cert_attribute (gxml, "label_notbefore", value);

    cert->GetSha1Fingerprint (value);
    set_label_cert_attribute (gxml, "label_sha_print", value);

    cert->GetMd5Fingerprint (value);
    set_label_cert_attribute (gxml, "label_md5_print", value);

    /* Hold a reference to each certificate in the chain while the
     * dialog is displayed, this holds the reference for the ASN
     * objects as well */

    nsCOMPtr<nsIArray> certChain;
    rv = cert->GetChain (getter_AddRefs(certChain));
    if (NS_FAILED(rv)) return rv;

    gboolean ret = setup_view_cert_tree (dialog, gxml, certChain);
    if (ret == FALSE) return NS_ERROR_FAILURE;

    g_object_unref (gxml);

    gtk_widget_show_all (dialog);

    int res;
    while (1)
    {
        res = gtk_dialog_run (GTK_DIALOG (dialog));
        if (res == GTK_RESPONSE_HELP)
        {
            ephy_gui_help (GTK_WINDOW (dialog), "epiphany", "using-certificate-viewer");
            continue;
        }  
        break;
    }

    gtk_widget_destroy (dialog);
    return NS_OK;
}

#endif