Initial import of ephy (rev# 7126) from svn
[ephy-soc.git] / embed / mozilla / .svn / text-base / GtkNSSDialogs.cpp.svn-base
blob25b99d141257cd8731b371474b2a3a8dc5745460
1 /*
2  *  Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx>
3  *  Copyright © 2006 Christian Persch
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  *  $Id$
20  */
23  * This file provides Gtk implementations of the mozilla Certificate dialogs
24  * such as the ones displayed when connecting to a site with a self-signed
25  * or expired certificate.
26  */
28 #include "mozilla-config.h"
29 #include "config.h"
31 #include <time.h>
33 #include <glib/gi18n.h>
34 #include <gtk/gtkalignment.h>
35 #include <gtk/gtkbutton.h>
36 #include <gtk/gtkcellrenderertext.h>
37 #include <gtk/gtkcheckbutton.h>
38 #include <gtk/gtkdialog.h>
39 #include <gtk/gtkeditable.h>
40 #include <gtk/gtkentry.h>
41 #include <gtk/gtkhbox.h>
42 #include <gtk/gtkimage.h>
43 #include <gtk/gtklabel.h>
44 #include <gtk/gtkmessagedialog.h>
45 #include <gtk/gtkprogressbar.h>
46 #include <gtk/gtksizegroup.h>
47 #include <gtk/gtkstock.h>
48 #include <gtk/gtktable.h>
49 #include <gtk/gtktextbuffer.h>
50 #include <gtk/gtktextview.h>
51 #include <gtk/gtktogglebutton.h>
52 #include <gtk/gtktreeselection.h>
53 #include <gtk/gtktreestore.h>
54 #include <gtk/gtktreeview.h>
55 #include <gtk/gtkvbox.h>
56 #include <gtk/gtkcombobox.h>
57 #include <gconf/gconf-client.h>
58 #include <glade/glade-xml.h>
60 #include <nsStringAPI.h>
62 #include <nsCOMPtr.h>
63 #include <nsIArray.h>
64 #include <nsIASN1Object.h>
65 #include <nsIASN1Sequence.h>
66 #include <nsICRLInfo.h>
67 #include <nsIDOMWindow.h>
68 #include <nsIInterfaceRequestor.h>
69 #include <nsIInterfaceRequestorUtils.h>
70 #include <nsIPKCS11ModuleDB.h>
71 #include <nsIPKCS11Slot.h>
72 #include <nsIPK11Token.h>
73 #include <nsIPK11TokenDB.h>
74 #include <nsIServiceManager.h>
75 #include <nsISimpleEnumerator.h>
76 #include <nsIX509CertDB.h>
77 #include <nsIX509Cert.h>
78 #include <nsIX509CertValidity.h>
79 #include <nsMemory.h>
80 #include <nsServiceManagerUtils.h>
82 #ifdef HAVE_NSIMUTABLEARRAY_H
83 #include <nsIMutableArray.h>
84 #endif
86 #include "ephy-file-helpers.h"
87 #include "ephy-gui.h"
88 #include "ephy-password-dialog.h"
89 #include "ephy-stock-icons.h"
91 #include "AutoJSContextStack.h"
92 #include "AutoWindowModalState.h"
93 #include "EphyUtils.h"
95 #include "GtkNSSDialogs.h"
97 NS_DEFINE_CID (kX509CertCID, NS_IX509CERT_IID);
98 NS_DEFINE_CID (kASN1ObjectCID, NS_IASN1OBJECT_IID);
100 enum
102         NSSDIALOG_RESPONSE_VIEW_CERT = 10
105 GtkNSSDialogs::GtkNSSDialogs ()
109 GtkNSSDialogs::~GtkNSSDialogs ()
113 NS_IMPL_THREADSAFE_ISUPPORTS5 (GtkNSSDialogs, 
114                                nsICertificateDialogs,
115                                nsIBadCertListener,
116                                nsITokenPasswordDialogs,
117                                nsITokenDialogs,
118                                nsIDOMCryptoDialogs)
120 /* There's also nsICertPickDialogs which is implemented in mozilla
121  * but has no callers. So we don't implement it.
122  * Same for nsIUserCertPicker which is only used in mailnews.
123  */
126  *  Call the mozilla service to display a certificate
127  */
128 static void
129 view_certificate (nsIInterfaceRequestor *ctx, nsIX509Cert *cert)
131         nsresult rv;
132         nsCOMPtr<nsICertificateDialogs> certDialogs =
133                 do_GetService (NS_CERTIFICATEDIALOGS_CONTRACTID, &rv);
134         NS_ENSURE_SUCCESS (rv, );
136         certDialogs->ViewCert (ctx, cert);
139 /** 
140  *  Indent a widget according the HIG
141  * 
142  *  @returns: The new indented widget
143  */
144 static GtkWidget*
145 higgy_indent_widget (GtkWidget *widget)
147         GtkWidget *hbox;
148         GtkWidget *label;
150         hbox = gtk_hbox_new (FALSE, 6);
152         label = gtk_label_new (NULL);
153         gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, TRUE, 6);
154         gtk_widget_show (label);
156         gtk_box_pack_start (GTK_BOX(hbox), widget, TRUE, TRUE, 0);
158         return hbox;
162  *  Setup up a dialog with the correct HIG'gy spacings, adding the content_widget
163  */
164 static void
165 higgy_setup_dialog (GtkDialog *dialog, const gchar *stock_icon, 
166                     GtkWidget **content_label,
167                     GtkWidget **content_vbox)
169         GtkWidget *hbox, *label, *image, *vbox;
171         g_return_if_fail (GTK_IS_DIALOG (dialog));
172         g_return_if_fail (content_label);
174         gtk_dialog_set_has_separator (dialog, FALSE);
175         gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
176         gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
177         
178         hbox = gtk_hbox_new (FALSE, 12);
179         gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
180         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
182         image = gtk_image_new_from_stock (stock_icon, GTK_ICON_SIZE_DIALOG);
183         gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
184         gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
186         vbox = gtk_vbox_new (FALSE, 12);
187         gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
189         label = gtk_label_new (NULL);
190         gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
191         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
192         gtk_label_set_selectable (GTK_LABEL (label), TRUE);
193         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
195         gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
196         
197         gtk_widget_show (image);
198         gtk_widget_show (vbox);
199         gtk_widget_show (hbox);
200         gtk_widget_show (label);
202         /* Set up the spacing for the dialog internal widgets */
203         gtk_box_set_spacing (GTK_BOX(dialog->vbox), 14); /* 24 = 2 * 5 + 14 */
205         *content_label = label;
206         if (content_vbox)
207         {
208                 *content_vbox = vbox;
209         }
214  *  Display a dialog box, showing 'View Certificate', 'Cancel',
215  *  and 'Accept' buttons. Optionally a checkbox can be shown,
216  *  or the text can be NULL to avoid it being displayed
217  * 
218  *  @returns: GTK_RESPONSE_ACCEPT if the user clicked Accept
219  */
220 static gint
221 display_cert_warning_box (nsIInterfaceRequestor *ctx, 
222                           nsIX509Cert *cert,
223                           const char *markup_text,
224                           const char *checkbox_text,
225                           gboolean *checkbox_value,
226                           const char *affirmative_text)
228         GtkWidget *dialog, *label, *checkbox, *vbox, *button;
229         int res;
231         g_return_val_if_fail (markup_text, GTK_RESPONSE_CANCEL);
232         g_return_val_if_fail (!checkbox_text || checkbox_value, GTK_RESPONSE_CANCEL);
234         nsresult rv;
235         AutoJSContextStack stack;
236         rv = stack.Init ();
237         if (NS_FAILED (rv)) return rv;
239         /* NOTE: Due to a mozilla bug [https://bugzilla.mozilla.org/show_bug.cgi?id=306288],
240          * we will always end up without a parent!
241          */
242         nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
243         GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
245         AutoWindowModalState modalState (parent);
247         dialog = gtk_dialog_new_with_buttons ("", gparent,
248                                               GTK_DIALOG_DESTROY_WITH_PARENT,
249                                               (char *) NULL);
250         if (gparent)
251         {
252                 gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent),
253                                              GTK_WINDOW (dialog));
254         }
256         gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
257         gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
259         higgy_setup_dialog (GTK_DIALOG (dialog), 
260                             GTK_STOCK_DIALOG_WARNING, &label, &vbox);
262         /* Add the buttons */
263         gtk_dialog_add_button (GTK_DIALOG (dialog), _("_View Certificate"),
264                                NSSDIALOG_RESPONSE_VIEW_CERT);
266         gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL,
267                                GTK_RESPONSE_CANCEL);
269         if (affirmative_text == NULL)
270         {
271                 affirmative_text = _("_Accept");
272         }
274         button = gtk_dialog_add_button (GTK_DIALOG (dialog), 
275                                         affirmative_text,
276                                         GTK_RESPONSE_ACCEPT);
277         gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
279         if (checkbox_text)
280         {
281                 checkbox = gtk_check_button_new_with_mnemonic (checkbox_text);
282                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), 
283                                               *checkbox_value);
285                 gtk_box_pack_start (GTK_BOX (vbox), checkbox, TRUE, TRUE, 0);
286         }
287         else
288         {
289                 checkbox = 0;
290         }
292         /* We don't want focus on the checkbox */
293         gtk_widget_grab_focus (button);
295         gtk_label_set_markup (GTK_LABEL (label), markup_text);
296         gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
297         gtk_widget_show_all (dialog);
299         while (1)
300         {
301                 res = gtk_dialog_run (GTK_DIALOG (dialog));
302                 if (res == NSSDIALOG_RESPONSE_VIEW_CERT)
303                 {
304                       view_certificate (ctx, cert);
305                       continue;
306                 }
307         
308                 break;
309         }
311         if (res == GTK_RESPONSE_ACCEPT && checkbox)
312         {
313                 *checkbox_value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox));
314         }
316         gtk_widget_destroy (dialog);
317         return res;
321 /* Helper functions */
323 nsresult
324 GtkNSSDialogs::GetTokenAndSlotFromName (const PRUnichar *aName,
325                                         nsIPK11Token **aToken,
326                                         nsIPKCS11Slot **aSlot)
328         nsresult rv = NS_ERROR_FAILURE;
329         *aToken = nsnull;
330         *aSlot = nsnull;
332         nsCOMPtr<nsIPK11TokenDB> tokenDB = do_GetService("@mozilla.org/security/pk11tokendb;1");
333         nsCOMPtr<nsIPKCS11ModuleDB> pkcs11DB = do_GetService("@mozilla.org/security/pkcs11moduledb;1");
334         if (!tokenDB || !pkcs11DB) return rv;
336         rv = tokenDB->FindTokenByName (aName, aToken);
337         NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && *aToken, rv);
339         pkcs11DB->FindSlotByName (aName, aSlot);
341         NS_ENSURE_TRUE (*aSlot, NS_ERROR_FAILURE);
343 #ifdef GNOME_ENABLE_DEBUG
344         /* Dump some info about this token */
345         nsIPK11Token *token = *aToken;
346         PRUnichar *tName, *tLabel, *tManID, *tHWVersion, *tFWVersion, *tSN;
347         PRInt32 minPwdLen;
348         PRBool needsInit, isHW, needsLogin, isFriendly;
350         token->GetTokenName(&tName);
351         token->GetTokenLabel(&tLabel);
352         token->GetTokenManID(&tManID);
353         token->GetTokenHWVersion(&tHWVersion);
354         token->GetTokenFWVersion(&tFWVersion);
355         token->GetTokenSerialNumber(&tSN);
356         token->GetMinimumPasswordLength(&minPwdLen);
357         token->GetNeedsUserInit(&needsInit);
358         token->IsHardwareToken(&isHW);
359         token->NeedsLogin(&needsLogin);
360         token->IsFriendly(&isFriendly);
362         g_print ("Token '%s' has \nName: %s\nLabel: %s\nManID: %s\nHWversion: %s\nFWVersion: %s\nSN: %s\n"
363                         "MinPwdLen: %d\nNeedsUserInit: %d\nIsHWToken: %d\nNeedsLogin: %d\nIsFriendly: %d\n\n",
364                 NS_ConvertUTF16toUTF8(aName).get(),
366                 NS_ConvertUTF16toUTF8(tName).get(),
367                 NS_ConvertUTF16toUTF8(tLabel).get(),
368                 NS_ConvertUTF16toUTF8(tManID).get(),
369                 NS_ConvertUTF16toUTF8(tHWVersion).get(),
370                 NS_ConvertUTF16toUTF8(tFWVersion).get(),
371                 NS_ConvertUTF16toUTF8(tSN).get(),
372                 minPwdLen,
373                 needsInit,
374                 isHW,
375                 needsLogin,
376                 isFriendly);
378         nsIPKCS11Slot *slot = *aSlot;
379         PRUnichar*slDesc;
380         slot->GetDesc(&slDesc);
381         g_print ("Slot description: %s\n", NS_ConvertUTF16toUTF8 (slDesc).get());
382 #endif
384         return NS_OK;
386   
387 /* nsICertificateDialogs */
389 NS_IMETHODIMP
390 GtkNSSDialogs::ConfirmMismatchDomain (nsIInterfaceRequestor *ctx,
391                                       const nsACString &targetURL,
392                                       nsIX509Cert *cert, PRBool *_retval)
394         char *first, *second, *msg;
395         int res;
397         nsString commonName;
398         cert->GetCommonName (commonName);
400         NS_ConvertUTF16toUTF8 cCommonName (commonName);
402         nsCString cTargetUrl (targetURL);
404         first = g_markup_printf_escaped (_("The site “%s” returned security information for "
405                                            "“%s”. It is possible that someone is intercepting "
406                                            "your communication to obtain your confidential "
407                                            "information."),
408                                          cTargetUrl.get(), cCommonName.get());
410         second = g_markup_printf_escaped (_("You should only accept the security information if you "
411                                             "trust “%s” and “%s”."),
412                                           cTargetUrl.get(), cCommonName.get());
413         
414         msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
415                                _("Accept incorrect security information?"),
416                                first, second);
418         res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL);
420         g_free (second);
421         g_free (first);
422         g_free (msg);
424         *_retval = (res == GTK_RESPONSE_ACCEPT);
425         return NS_OK;
429 NS_IMETHODIMP
430 GtkNSSDialogs::ConfirmUnknownIssuer (nsIInterfaceRequestor *ctx,
431                                      nsIX509Cert *cert, PRInt16 *outAddType,
432                                      PRBool *_retval)
434         gboolean accept_perm = FALSE;
435         char *secondary, *tertiary, *msg;
436         int res;
438         nsString commonName;
439         cert->GetCommonName (commonName);
441         NS_ConvertUTF16toUTF8 cCommonName (commonName);
443         secondary = g_markup_printf_escaped
444                            (_("It was not possible to automatically trust “%s”. "
445                               "It is possible that someone is intercepting your "
446                               "communication to obtain your confidential information."),
447                               cCommonName.get());
449         tertiary = g_markup_printf_escaped
450                            (_("You should only connect to the site if you are certain "
451                               "you are connected to “%s”."),
452                             cCommonName.get());
454         msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
455                                _("Connect to untrusted site?"),
456                                secondary, tertiary);
458         res = display_cert_warning_box (ctx, cert, msg, 
459                                         _("_Trust this security information from now on"),
460                                         &accept_perm, _("Co_nnect"));
461         g_free (tertiary);
462         g_free (secondary);
463         g_free (msg);
465         if (res != GTK_RESPONSE_ACCEPT)
466         {
467                 *_retval = PR_FALSE;
468                 *outAddType = UNINIT_ADD_FLAG;
469         }
470         else
471         {
472                 if (accept_perm)
473                 {
474                         *_retval    = PR_TRUE;
475                         *outAddType = ADD_TRUSTED_PERMANENTLY;
476                 }
477                 else
478                 {
479                         *_retval    = PR_TRUE;
480                         *outAddType = ADD_TRUSTED_FOR_SESSION;
481                 }
482         }
484         return NS_OK;
488 /* boolean confirmCertExpired (in nsIInterfaceRequestor socketInfo, 
489    in nsIX509Cert cert); */
490 NS_IMETHODIMP 
491 GtkNSSDialogs::ConfirmCertExpired (nsIInterfaceRequestor *ctx,
492                                    nsIX509Cert *cert, PRBool *_retval)
494         nsresult rv;
495         PRTime now = PR_Now();
496         PRTime notAfter, notBefore, timeToUse;
497         PRInt64 normalizedTime;
498         time_t t;
499         struct tm tm;
500         char formattedDate[128];
501         char *fdate;
502         const char *primary, *text;
503         char *secondary, *msg;
505         *_retval = PR_FALSE;
506         
507         nsCOMPtr<nsIX509CertValidity> validity;
508         rv = cert->GetValidity (getter_AddRefs(validity));
509         if (NS_FAILED(rv)) return rv;
510         
511         rv = validity->GetNotAfter (&notAfter);
512         if (NS_FAILED(rv)) return rv;
513         
514         rv = validity->GetNotBefore (&notBefore);
515         if (NS_FAILED(rv)) return rv;
516         
517         if (LL_CMP(now, >, notAfter))
518         {
519                 primary = _("Accept expired security information?");
520                 /* Translators: first %s is a hostname, second %s is a time/date */
521                 text    = _("The security information for “%s” "
522                             "expired on %s.");
523                 timeToUse = notAfter;
524         } 
525         else
526         {
527                 primary = _("Accept not yet valid security information?");
528                 /* Translators: first %s is a hostname, second %s is a time/date */
529                 text    = _("The security information for “%s” isn't valid until %s.");
530                 timeToUse = notBefore;
531         }
532         
533         nsString commonName;
534         cert->GetCommonName (commonName);
536         NS_ConvertUTF16toUTF8 cCommonName (commonName);
538         LL_DIV (normalizedTime, timeToUse, PR_USEC_PER_SEC);
539         LL_L2UI (t, normalizedTime);
540         /* To translators: this a time format that is used while displaying the
541          * expiry or start date of an SSL certificate, for the format see 
542          * strftime(3) */
543         strftime (formattedDate, sizeof(formattedDate), _("%a %d %b %Y"), 
544                   localtime_r (&t, &tm));
545         /* FIXME! this isn't actually correct, LC_CTIME codeset could be different than locale codeset! */
546         fdate = g_locale_to_utf8 (formattedDate, -1, NULL, NULL, NULL);
548         secondary = g_markup_printf_escaped (text, cCommonName.get(), fdate);
550         msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
551                                primary, secondary, 
552                                _("You should ensure that your computer's time is correct."));
554         int res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL);
556         g_free (fdate);
557         g_free (msg);
558         g_free (secondary);
560         *_retval = (res == GTK_RESPONSE_ACCEPT);
561         
562         return NS_OK;
565 /* void notifyCrlNextupdate (in nsIInterfaceRequestor socketInfo, 
566                              in AUTF8String targetURL,
567                              in nsIX509Cert cert); */
568 NS_IMETHODIMP 
569 GtkNSSDialogs::NotifyCrlNextupdate (nsIInterfaceRequestor *ctx,
570                                     const nsACString & targetURL,
571                                     nsIX509Cert *cert)
573         nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
574         GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
576         nsCString cTargetUrl (targetURL);
578         nsString commonName;
579         cert->GetCommonName (commonName);
581         GtkWidget *dialog = gtk_message_dialog_new
582                                 (GTK_WINDOW (gparent),
583                                  GTK_DIALOG_DESTROY_WITH_PARENT,
584                                  GTK_MESSAGE_ERROR,
585                                  GTK_BUTTONS_OK,
586                                  _("Cannot establish connection to “%s”"),
587                                  cTargetUrl.get ());
589         gtk_message_dialog_format_secondary_text
590                         (GTK_MESSAGE_DIALOG (dialog),
591                          _("The certificate revocation list (CRL) from “%s” "
592                            "needs to be updated.\n\n"
593                            "Please ask your system administrator for assistance."),
594                          NS_ConvertUTF16toUTF8 (commonName).get ());
595         gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
597         g_signal_connect (dialog, "response",
598                           (GCallback) gtk_widget_destroy, NULL);
600         gtk_widget_show_all (dialog);
601         return NS_OK;
604 NS_IMETHODIMP 
605 GtkNSSDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor *ctx, 
606                                     nsIX509Cert *cert,
607                                     PRUint32 *_trust,
608                                     PRBool *_retval)
610         GtkWidget *dialog, *label;
611         char *msg, *primary;
613         nsresult rv;
614         AutoJSContextStack stack;
615         rv = stack.Init ();
616         if (NS_FAILED (rv)) return rv;
618         nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
619         GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
621         AutoWindowModalState modalState (parent);
623         dialog = gtk_dialog_new_with_buttons (_("Trust new Certificate Authority?"), gparent,
624                                               GTK_DIALOG_DESTROY_WITH_PARENT,
625                                               _("_View Certificate"),
626                                               NSSDIALOG_RESPONSE_VIEW_CERT,
627                                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
628                                               _("_Trust CA"),   GTK_RESPONSE_ACCEPT,
629                                               (char *) NULL);
631         if (gparent)
632         {
633                 gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent),
634                                              GTK_WINDOW (dialog));
635         }
637         gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
639         higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_WARNING,
640                             &label, NULL);
641         gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
643         nsString commonName;
644         cert->GetCommonName (commonName);
646         NS_ConvertUTF16toUTF8 cCommonName (commonName);
648         primary = g_markup_printf_escaped (_("Trust new Certificate Authority “%s” to identify web sites?"),
649                                            cCommonName.get());
651         msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
652                                primary,
653                                _("Before trusting a Certificate Authority (CA) you should "
654                                  "verify the certificate is authentic."));
655         gtk_label_set_markup (GTK_LABEL (label), msg);
656         g_free (primary);
657         g_free (msg);
659         gtk_widget_show_all (dialog);
660         int ret;
662         while (1)
663         {
664                 ret = gtk_dialog_run (GTK_DIALOG (dialog));
665                 if (ret == NSSDIALOG_RESPONSE_VIEW_CERT)
666                 {
667                       view_certificate (ctx, cert);
668                       continue;
669                 }
670         
671                 break;
672         }
674         if (ret != GTK_RESPONSE_ACCEPT)
675         {
676                 *_retval = PR_FALSE;
677         }
678         else
679         {
680                 if (ret == GTK_RESPONSE_ACCEPT)
681                 {
682                         *_trust |= nsIX509CertDB::TRUSTED_SSL;
683                 }
684                 else
685                 {
686                         *_trust = nsIX509CertDB::UNTRUSTED;
687                 }
689                 *_retval = PR_TRUE;
690         }
691         gtk_widget_destroy (dialog);
693         return NS_OK;
697 NS_IMETHODIMP 
698 GtkNSSDialogs::NotifyCACertExists (nsIInterfaceRequestor *ctx)
700         GtkWidget *dialog, *label;
701         char * msg;
703         nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
704         GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
706         dialog = gtk_dialog_new_with_buttons ("", gparent,
707                                               GTK_DIALOG_DESTROY_WITH_PARENT,
708                                               GTK_STOCK_OK,
709                                               GTK_RESPONSE_OK,
710                                               (char *) NULL);
712         if (gparent)
713         {
714                 gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent),
715                                              GTK_WINDOW (dialog));
716         }
718         gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
720         higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_ERROR,
721                             &label, NULL);
723         msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
724                                 _("Certificate already exists."),
725                                _("The certificate has already been imported."));
726         gtk_label_set_markup (GTK_LABEL (label), msg);
727         g_free (msg);
729         g_signal_connect (G_OBJECT (dialog),
730                           "response",
731                           (GCallback)gtk_widget_destroy, NULL);
733         gtk_widget_show_all (dialog);
734         return NS_OK;
737 /* FIXME: This interface sucks! There is way to know the name of the certificate! */
738 NS_IMETHODIMP 
739 GtkNSSDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor *ctx, 
740                                     nsAString &_password,
741                                     PRBool *_retval)
743         GtkWidget *dialog;
744         char *msg;
746         nsresult rv;
747         AutoJSContextStack stack;
748         rv = stack.Init ();
749         if (NS_FAILED (rv)) return rv;
751         nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
752         GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
754         AutoWindowModalState modalState (parent);
756         dialog = ephy_password_dialog_new (gparent,
757                                            _("Select Password"),
758                                            EphyPasswordDialogFlags(EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD |
759                                                                    EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER));
760         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
761         gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
763         /* FIXME: set accept button text to (_("_Back Up Certificate") ?
764          * That's not actually correct, since this function is also called from other places!
765          */
767         msg = g_markup_printf_escaped (_("Select a password to protect this certificate"));
768         gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), msg);
769         g_free (msg);
771         int response = gtk_dialog_run (GTK_DIALOG (dialog));
772         gtk_widget_hide (dialog);
773         
774         if (response == GTK_RESPONSE_ACCEPT)
775         {
776                 const char *text = ephy_password_dialog_get_new_password (EPHY_PASSWORD_DIALOG (dialog));
777                 g_return_val_if_fail (text != NULL, NS_ERROR_FAILURE);
778                 NS_CStringToUTF16 (nsDependentCString (text),
779                                    NS_CSTRING_ENCODING_UTF8, _password);
780         }
782         *_retval = response == GTK_RESPONSE_ACCEPT;
784         gtk_widget_destroy (dialog);
786         return NS_OK;
789 NS_IMETHODIMP 
790 GtkNSSDialogs::GetPKCS12FilePassword(nsIInterfaceRequestor *ctx, 
791                                      nsAString &_password,
792                                      PRBool *_retval)
794         g_print ("GtkNSSDialogs::GetPKCS12FilePassword\n");
796         nsresult rv;
797         AutoJSContextStack stack;
798         rv = stack.Init ();
799         if (NS_FAILED (rv)) return rv;
801         nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
802         GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
804         AutoWindowModalState modalState (parent);
806         GtkWidget *dialog = ephy_password_dialog_new
807                                 (gparent,
808                                  "",
809                                  EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD));
810         EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog);
811         /* FIXME: set accept button text to _("I_mport Certificate") ? */
813         gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
815         /* FIXME: mozilla sucks, no way to get the name of the certificate / cert file! */
816         char *msg = g_markup_printf_escaped (_("Enter the password for this certificate"));
817         gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), msg);
818         g_free (msg);
819                         
820         int response = gtk_dialog_run (GTK_DIALOG (dialog));
822         if (response == GTK_RESPONSE_ACCEPT)
823         {
824                 const char *pwd = ephy_password_dialog_get_password (password_dialog);
825                 NS_CStringToUTF16 (nsDependentCString (pwd),
826                                    NS_CSTRING_ENCODING_UTF8, _password);
827         }
829         *_retval = response == GTK_RESPONSE_ACCEPT;
831         gtk_widget_destroy (dialog);
833         return NS_OK;
837 static void
838 set_table_row (GtkWidget *table,
839                int& row,
840                const char *title,
841                const char *text)
843         GtkWidget *header, *label;
844         char *bold;
846         if (text == NULL || text[0] == 0) return;
848         bold = g_markup_printf_escaped ("<b>%s</b>", title);
849         header = gtk_label_new (bold);
850         g_free (bold);
852         gtk_label_set_use_markup (GTK_LABEL (header), TRUE);
853         gtk_misc_set_alignment (GTK_MISC (header), 0, 0);
854         gtk_widget_show (header);
855         gtk_table_attach (GTK_TABLE (table), header, 0, 1, row, row+1,
856                           GTK_FILL, GTK_FILL, 0, 0);
858         label = gtk_label_new (text);
859         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
860         gtk_label_set_selectable (GTK_LABEL (label), TRUE);
861         gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
862         gtk_label_set_max_width_chars (GTK_LABEL (label), 48);
863         gtk_widget_show (label);
864         gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, row, row+1);
866         row++;
869 NS_IMETHODIMP 
870 GtkNSSDialogs::CrlImportStatusDialog(nsIInterfaceRequestor *ctx, nsICRLInfo *crl)
873         GtkWidget *dialog, *label, *table, *vbox;
874         nsresult rv;
875         char *msg;
877         nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
878         GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
880         dialog = gtk_dialog_new_with_buttons ("",
881                                               GTK_WINDOW (gparent),
882                                               GTK_DIALOG_DESTROY_WITH_PARENT,
883                                               GTK_STOCK_OK, GTK_RESPONSE_OK,
884                                               (char *) NULL);
886         gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
887         gtk_window_set_title (GTK_WINDOW (dialog), _("Certificate Revocation List Imported"));
889         /* Needed because gparent == NULL always because of mozilla sucks */
890         gtk_window_set_skip_pager_hint (GTK_WINDOW (dialog), TRUE);
891         gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE);
893         higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_INFO,
894                             &label, &vbox);
896         msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>",
897                                _("Certificate Revocation List (CRL) successfully imported"));
898         gtk_label_set_markup (GTK_LABEL (label), msg);
899         g_free (msg);
901         table = gtk_table_new (2, 3, FALSE);
902         gtk_table_set_row_spacings (GTK_TABLE (table), 6);
903         gtk_table_set_col_spacings (GTK_TABLE (table), 12);
905         nsString org, orgUnit, nextUpdate;
906         rv = crl->GetOrganization (org);
907         if (NS_FAILED(rv)) return rv;
909         rv = crl->GetOrganizationalUnit (orgUnit);
910         if (NS_FAILED(rv)) return rv;
912         rv = crl->GetNextUpdateLocale (nextUpdate);
913         if (NS_FAILED(rv)) return rv;
915         int row = 0;
916         set_table_row (table, row, _("Organization:"), NS_ConvertUTF16toUTF8 (org).get ());
918         set_table_row (table, row, _("Unit:"), NS_ConvertUTF16toUTF8 (orgUnit).get ());
920         set_table_row (table, row, _("Next Update:"), NS_ConvertUTF16toUTF8 (nextUpdate).get ());
922         gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
924         gtk_widget_show_all (dialog);
925         g_signal_connect (G_OBJECT (dialog),
926                           "response",
927                           (GCallback)gtk_widget_destroy, NULL);
929         gtk_widget_show_all (dialog);
930         return NS_OK;
933 /** 
934  *  Help function to fill in the labels on the General tab
935  */
936 static void
937 set_label_cert_attribute (GladeXML* gxml, const char* label_id, nsAString &value)
939         GtkWidget *label;
940         label = glade_xml_get_widget (gxml, label_id);
942         g_return_if_fail (GTK_IS_LABEL (label));
944         if (!value.Length()) {
945                 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
946                 char *msg = g_strdup_printf ("<i>&lt;%s&gt;</i>",
947                                              _("Not part of certificate"));
948                 gtk_label_set_markup (GTK_LABEL (label), msg);
949                 g_free (msg);
950         }
951         else
952         {
953                 gtk_label_set_use_markup (GTK_LABEL (label), FALSE);
954                 gtk_label_set_text (GTK_LABEL (label), NS_ConvertUTF16toUTF8 (value).get());
955         }
960  *  Do that actual filling in of the certificate tree
961  */
962 static gboolean
963 fill_cert_chain_tree (GtkTreeView *treeview, nsIArray *certChain)
965         nsresult rv;
966         GtkTreeModel * model = gtk_tree_view_get_model (treeview);
968         GtkTreeIter parent;
969         PRUint32 numCerts;
970         rv =  certChain->GetLength (&numCerts);
971         if (NS_FAILED(rv) || numCerts < 1) return FALSE;
973         for (int i = (int)numCerts-1 ; i >= 0; i--)
974         {
975                 nsCOMPtr<nsIX509Cert> nsCert;
976                 rv = certChain->QueryElementAt (i, kX509CertCID,
977                                                 getter_AddRefs(nsCert));
978                 if (NS_FAILED(rv)) return FALSE;
980                 GtkTreeIter iter;
981                 gtk_tree_store_append (GTK_TREE_STORE (model), &iter, 
982                                        (i == (int)numCerts-1) ? NULL : &parent);
984                 nsString value;
985                 rv = nsCert->GetCommonName (value);
986                 if (NS_FAILED(rv)) return FALSE;
988                 NS_ConvertUTF16toUTF8 cValue (value);
990                 nsIX509Cert *nsCertP = nsCert;
991                 if (value.Length())
992                 {
993                         gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
994                                             0, cValue.get(),
995                                             1, nsCertP,
996                                             -1);
997                 }
998                 else
999                 {
1000                         char * title;
1001                         rv = nsCert->GetWindowTitle (&title);
1002                         if (NS_FAILED(rv)) return FALSE;
1003                         
1004                         gtk_tree_store_set (GTK_TREE_STORE(model),
1005                                             &iter, 0, title, 1, nsCertP, -1);
1006                         nsMemory::Free (title);
1007                 }
1008                 parent = iter;
1009         }
1010         gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview));
1012         /* And select the last entry, and scroll the view so it's visible */
1013         GtkTreeSelection *select = gtk_tree_view_get_selection (treeview);
1014         GtkTreePath *path = gtk_tree_model_get_path (model, &parent);
1015         gtk_tree_selection_select_path (select, path);
1016         gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.5, 0.0);
1017         gtk_tree_path_free (path);
1019         return TRUE; 
1023  *  Add an ASN object to the treeview, recursing if the object was a
1024  *  sequence
1025  */
1026 static void
1027 add_asn1_object_to_tree(GtkTreeModel *model, nsIASN1Object *object, GtkTreeIter *parent)
1029         nsString dispNameU;
1030         object->GetDisplayName(dispNameU);
1032         GtkTreeIter iter;
1033         gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent);
1035         gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
1036                             0, NS_ConvertUTF16toUTF8 (dispNameU).get(),
1037                             1, object,
1038                             -1);
1040         nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object));
1041         if (!sequence) return;
1043         nsCOMPtr<nsIMutableArray> asn1Objects;
1044         sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1046         PRUint32 numObjects;
1047         asn1Objects->GetLength(&numObjects);
1048         if (!asn1Objects) return;
1050         for (PRUint32 i = 0; i < numObjects ; i++)
1051         {
1052                 nsCOMPtr<nsIASN1Object> currObject;
1053                 asn1Objects->QueryElementAt (i, kASN1ObjectCID,
1054                                              getter_AddRefs (currObject));
1055                 add_asn1_object_to_tree (model, currObject, &iter);
1056         }
1061  *  Update the "Certificate Fields" treeview when a different cert
1062  *  is selected in the hierarchy text view
1063  */
1064 static void
1065 cert_chain_tree_view_selection_changed_cb (GtkTreeSelection *selection, 
1066                                            GtkWidget* tree_view)
1068         GtkTreeIter iter;
1069         nsIX509Cert *nsCert;
1070         nsresult rv;
1071         GtkTreeModel * model;
1072                 
1073         if (gtk_tree_selection_get_selected (selection, &model, &iter))
1074         {
1075                 gtk_tree_model_get (model, &iter, 1, &nsCert, -1);
1077                 nsCOMPtr<nsIASN1Object> object;
1078                 rv = nsCert->GetASN1Structure (getter_AddRefs(object));
1079                 if (NS_FAILED(rv)) return;
1081                 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
1082                 gtk_tree_store_clear (GTK_TREE_STORE (model));
1083                 add_asn1_object_to_tree (model, object, NULL);
1085                 gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
1086         }
1090  *  When the "Certificate Field" treeview is changed, update the 
1091  *  text_view to display the value of the currently selected field
1092  */
1093 static void
1094 field_tree_view_selection_changed_cb (GtkTreeSelection *selection, 
1095                                       GtkWidget* text_view)
1097         GtkTreeIter iter;
1098         GtkTreeModel *model;
1099         GtkTextBuffer * text_buffer = 
1100                 gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
1102         if (gtk_tree_selection_get_selected (selection, &model, &iter))
1103         {
1104                 nsIASN1Object *object;
1106                 gtk_tree_model_get (model, &iter, 1, &object, -1);
1108                 nsString dispValU;
1109                 object->GetDisplayValue(dispValU);
1111                 gtk_text_buffer_set_text (text_buffer, NS_ConvertUTF16toUTF8 (dispValU).get(), -1);
1112         }
1113         else
1114         {
1115                 gtk_text_buffer_set_text (text_buffer, "", 0);  
1116         }
1120  *  Setup the various treeviews, the textview, and fill the treeviews
1121  */
1122 static gboolean
1123 setup_view_cert_tree (GtkWidget *dialog, GladeXML*gxml, nsIArray *certChain)
1125         GtkCellRenderer *renderer;
1126         GtkWidget *chain_tree_view, *field_tree_view, *text_view;
1127         PangoFontDescription *monospace_font_desc;
1128         GConfClient *conf_client;
1129         char *monospace_font;
1131         chain_tree_view = glade_xml_get_widget (gxml, "treeview_cert_chain");
1132         field_tree_view = glade_xml_get_widget (gxml, "treeview_cert_info");
1133         text_view       = glade_xml_get_widget (gxml, "textview_field_value");
1135         /* Setup the certificate chain view */
1136         GtkTreeStore *store = gtk_tree_store_new (2, 
1137                                                   G_TYPE_STRING,
1138                                                   G_TYPE_POINTER);
1139         gtk_tree_view_set_model (GTK_TREE_VIEW (chain_tree_view), GTK_TREE_MODEL (store));
1140         g_object_unref (store);
1143         renderer = gtk_cell_renderer_text_new ();
1144         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (chain_tree_view),
1145                                                      0, "Certificate",
1146                                                      renderer,
1147                                                      "text", 0,
1148                                                      (char *) NULL);
1150         GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (chain_tree_view));
1151         gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
1153         g_signal_connect (G_OBJECT (select), "changed",
1154                           G_CALLBACK (cert_chain_tree_view_selection_changed_cb),
1155                           field_tree_view);
1157         /* Setup the certificate field view */
1158         store = gtk_tree_store_new (2, 
1159                                     G_TYPE_STRING,
1160                                     G_TYPE_POINTER);
1161         gtk_tree_view_set_model (GTK_TREE_VIEW (field_tree_view), GTK_TREE_MODEL (store));
1162         g_object_unref (store);
1165         gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (field_tree_view),
1166                                                      0, "Certificate Field",
1167                                                      renderer,
1168                                                      "text", 0,
1169                                                      (char *) NULL);
1171         select = gtk_tree_view_get_selection (GTK_TREE_VIEW (field_tree_view));
1172         gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
1174         g_signal_connect (G_OBJECT (select), "changed",
1175                           G_CALLBACK (field_tree_view_selection_changed_cb),
1176                           text_view);
1178         /* Get the text_view displaying a propertional font
1179          *
1180          * Pick up the monospace font from desktop preferences */
1181         conf_client = gconf_client_get_default ();
1182         monospace_font = gconf_client_get_string (conf_client, 
1183                              "/desktop/gnome/interface/monospace_font_name", NULL);
1184         if (monospace_font)
1185         {
1186                 monospace_font_desc = pango_font_description_from_string (monospace_font);
1187                 gtk_widget_modify_font (text_view, monospace_font_desc);
1188                 pango_font_description_free (monospace_font_desc);
1189         }
1190         g_object_unref (conf_client);      
1191         
1192         /* And fill the certificate chain tree */
1193         return fill_cert_chain_tree (GTK_TREE_VIEW (chain_tree_view), certChain);
1196 /* void viewCert (in nsIX509Cert cert); */
1197 NS_IMETHODIMP 
1198 GtkNSSDialogs::ViewCert(nsIInterfaceRequestor *ctx, 
1199                        nsIX509Cert *cert)
1201         GtkWidget *dialog, *widget;
1202         GladeXML *gxml;
1203         nsString value;
1204         PRUint32 verifystate, count;
1205         PRUnichar ** usage;
1206         GtkSizeGroup * sizegroup;
1208         nsresult rv;
1209         AutoJSContextStack stack;
1210         rv = stack.Init ();
1211         if (NS_FAILED (rv)) return rv;
1213         gxml = glade_xml_new (ephy_file ("certificate-dialogs.glade"),
1214                               "viewcert_dialog", NULL);
1215         g_return_val_if_fail (gxml != NULL, NS_ERROR_FAILURE);
1217         dialog = glade_xml_get_widget (gxml, "viewcert_dialog");
1218         g_return_val_if_fail (dialog != NULL, NS_ERROR_FAILURE);
1220         nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
1221         GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
1223         AutoWindowModalState modalState (parent);
1225         if (gparent)
1226         {
1227                 gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(gparent));
1228                 gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (gparent)),
1229                                              GTK_WINDOW (dialog));
1230                 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
1231         }
1233         gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
1235         gtk_window_set_title (GTK_WINDOW (dialog), _("Certificate Properties"));
1236         gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
1238         /* Set up the GtkSizeGroup so that the columns line up */
1239         sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
1240         widget = glade_xml_get_widget (gxml, "label_size1");
1241         gtk_size_group_add_widget (sizegroup, widget);
1242         widget = glade_xml_get_widget (gxml, "label_size2");
1243         gtk_size_group_add_widget (sizegroup, widget);
1244         widget = glade_xml_get_widget (gxml, "label_size3");
1245         gtk_size_group_add_widget (sizegroup, widget);
1246         widget = glade_xml_get_widget (gxml, "label_size4");
1247         gtk_size_group_add_widget (sizegroup, widget);
1248         g_object_unref (sizegroup);
1250         rv = cert->GetUsagesArray (FALSE, &verifystate, &count, &usage);
1251         if (NS_FAILED(rv)) return rv;
1253         const char * text;
1254         switch (verifystate)
1255         {
1256         case nsIX509Cert::VERIFIED_OK:
1257                 text = _("This certificate has been verified for the following uses:");
1258                 break;
1259         case nsIX509Cert::CERT_REVOKED:
1260                 text = _("Could not verify this certificate because it has been revoked.");
1261                 break;
1262         case nsIX509Cert::CERT_EXPIRED:
1263                 text = _("Could not verify this certificate because it has expired.");
1264                 break;
1265         case nsIX509Cert::CERT_NOT_TRUSTED:
1266                 text = _("Could not verify this certificate because it is not trusted.");
1267                 break;
1268         case nsIX509Cert::ISSUER_NOT_TRUSTED:
1269                 text = _("Could not verify this certificate because the issuer is not trusted.");
1270                 break;
1271         case nsIX509Cert::ISSUER_UNKNOWN:
1272                 text = _("Could not verify this certificate because the issuer is unknown.");
1273                 break;
1274         case nsIX509Cert::INVALID_CA:
1275                 text = _("Could not verify this certificate because the CA certificate is invalid.");
1276                 break;
1277         case nsIX509Cert::NOT_VERIFIED_UNKNOWN:
1278         case nsIX509Cert::USAGE_NOT_ALLOWED:
1279         default:
1280                 text = _("Could not verify this certificate for unknown reasons.");
1281         }
1282         
1283         char *vmsg = g_strdup_printf ("<b>%s</b>", text);
1284         widget = glade_xml_get_widget (gxml, "label_verify_text");
1285         g_return_val_if_fail (GTK_IS_LABEL (widget), NS_ERROR_FAILURE);
1286         gtk_label_set_markup (GTK_LABEL (widget), vmsg);
1287         g_free (vmsg);
1289         if (count > 0)
1290         {
1291                 GtkWidget *vbox = gtk_vbox_new (FALSE, 3);
1292                 GtkWidget *indent;
1293                 for (PRUint32 i = 0 ; i < count ; i++)
1294                 {
1295                         GtkWidget *label = gtk_label_new (NS_ConvertUTF16toUTF8 (usage[i]).get());
1296                         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1297                         gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
1298                         nsMemory::Free (usage[i]);
1299                 }
1300                 nsMemory::Free (usage);
1301                 indent = higgy_indent_widget (vbox);
1302                 widget = glade_xml_get_widget (gxml, "vbox_validity");
1303                 g_return_val_if_fail (GTK_IS_BOX (widget), NS_ERROR_FAILURE);
1304         
1305                 gtk_box_pack_start (GTK_BOX (widget), indent, FALSE, FALSE, 0);
1306         }
1308         cert->GetCommonName (value);
1309         set_label_cert_attribute (gxml, "label_cn", value);
1311         cert->GetOrganization (value);
1312         set_label_cert_attribute (gxml, "label_o", value);
1314         cert->GetOrganizationalUnit (value);
1315         set_label_cert_attribute (gxml, "label_ou", value);
1317         cert->GetSerialNumber (value);
1318         set_label_cert_attribute (gxml, "label_serial", value);
1320         rv = cert->GetIssuerCommonName (value);
1321         if (NS_FAILED(rv)) return rv;
1322         set_label_cert_attribute (gxml, "label_issuer_cn", value);
1324         cert->GetIssuerOrganization (value);
1325         set_label_cert_attribute (gxml, "label_issuer_o", value);
1327         cert->GetIssuerOrganizationUnit (value);
1328         set_label_cert_attribute (gxml, "label_issuer_ou", value);
1330         nsCOMPtr<nsIX509CertValidity> validity;
1331         rv = cert->GetValidity (getter_AddRefs(validity));
1332         if (NS_FAILED(rv)) return rv;
1333         
1334         rv = validity->GetNotAfterLocalDay (value);
1335         if (NS_FAILED(rv)) return rv;
1336         set_label_cert_attribute (gxml, "label_notafter", value);
1337         
1338         rv = validity->GetNotBeforeLocalDay (value);
1339         if (NS_FAILED(rv)) return rv;
1340         set_label_cert_attribute (gxml, "label_notbefore", value);
1342         cert->GetSha1Fingerprint (value);
1343         set_label_cert_attribute (gxml, "label_sha_print", value);
1345         cert->GetMd5Fingerprint (value);
1346         set_label_cert_attribute (gxml, "label_md5_print", value);
1348         /* Hold a reference to each certificate in the chain while the
1349          * dialog is displayed, this holds the reference for the ASN
1350          * objects as well */
1352         nsCOMPtr<nsIArray> certChain;
1353         rv = cert->GetChain (getter_AddRefs(certChain));
1354         if (NS_FAILED(rv)) return rv;
1356         gboolean ret = setup_view_cert_tree (dialog, gxml, certChain);
1357         if (ret == FALSE) return NS_ERROR_FAILURE;
1359         g_object_unref (gxml);
1361         gtk_widget_show_all (dialog);
1363         int res;
1364         while (1)
1365         {
1366                 res = gtk_dialog_run (GTK_DIALOG (dialog));
1367                 if (res == GTK_RESPONSE_HELP)
1368                 {
1369                         ephy_gui_help (GTK_WINDOW (dialog), "epiphany", "using-certificate-viewer");
1370                         continue;
1371                 }  
1372                 break;
1373         }
1375         gtk_widget_destroy (dialog);
1376         return NS_OK;
1379 /* nsITokenPasswordDialogs */
1381 /* NOTE: This interface totally sucks, see https://bugzilla.mozilla.org/show_bug.cgi?id=306993 */
1383 /* void setPassword (in nsIInterfaceRequestor ctx, in wstring tokenName, out boolean canceled); */
1384 NS_IMETHODIMP
1385 GtkNSSDialogs::SetPassword(nsIInterfaceRequestor *aCtx,
1386                            const PRUnichar *aTokenName,
1387                            PRBool *aCancelled)
1389         NS_ENSURE_ARG_POINTER(aCancelled);
1391         nsresult rv;
1392         nsCOMPtr<nsIPK11Token> token;
1393         nsCOMPtr<nsIPKCS11Slot> slot;
1394         rv = GetTokenAndSlotFromName (aTokenName, getter_AddRefs (token),
1395                                       getter_AddRefs (slot));
1396         NS_ENSURE_SUCCESS (rv, rv);
1397         NS_ENSURE_TRUE (token && slot, NS_ERROR_FAILURE);
1399         AutoJSContextStack stack;
1400         rv = stack.Init ();
1401         if (NS_FAILED (rv)) return rv;
1403         PRUint32 status = nsIPKCS11Slot::SLOT_UNINITIALIZED;
1404         slot->GetStatus (&status);
1406         nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aCtx));
1407         GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
1409         AutoWindowModalState modalState (parent);
1411         EphyPasswordDialogFlags flags =
1412                 EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD |
1413                                          EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER);
1414         if (status != nsIPKCS11Slot::SLOT_UNINITIALIZED)
1415                 flags = EphyPasswordDialogFlags (flags | EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD);
1417         GtkWidget *dialog = ephy_password_dialog_new
1418                                 (gparent,
1419                                  _("Change Token Password"),
1420                                  flags);
1421         EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog);
1423         char *message;
1424         if (status == nsIPKCS11Slot::SLOT_UNINITIALIZED) {
1425                 message = g_markup_printf_escaped (_("Choose a password for the “%s” token"),
1426                                                    NS_ConvertUTF16toUTF8 (aTokenName).get ());
1427         } else {
1428                 message = g_markup_printf_escaped (_("Change the password for the “%s” token"),
1429                                                    NS_ConvertUTF16toUTF8 (aTokenName).get ());
1430         }
1432         gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog),
1433                                        message);
1434         g_free (message);
1436         int response;
1437         nsString oldPassword;
1438         PRBool pwdOk, needsLogin;
1439         do {
1440                 response = gtk_dialog_run (GTK_DIALOG (dialog));
1442                 if (status != nsIPKCS11Slot::SLOT_UNINITIALIZED)
1443                 {
1444                         const char *pwd = ephy_password_dialog_get_password (password_dialog);
1445                         oldPassword = NS_ConvertUTF8toUTF16 (pwd);
1446                 }
1447         } while (response == GTK_RESPONSE_OK &&
1448                  status != nsIPKCS11Slot::SLOT_UNINITIALIZED &&
1449                  NS_SUCCEEDED (token->NeedsLogin (&needsLogin)) && needsLogin &&
1450                  NS_SUCCEEDED (token->CheckPassword (oldPassword.get (), &pwdOk) &&
1451                  !pwdOk));
1453         if (response == GTK_RESPONSE_ACCEPT)
1454         {
1455                 const char *pwd = ephy_password_dialog_get_new_password (password_dialog);
1456                         
1457                 NS_ConvertUTF8toUTF16 newPassword (pwd);
1459                 if (status == nsIPKCS11Slot::SLOT_UNINITIALIZED)
1460                 {
1461                         rv = token->InitPassword (newPassword.get ());
1462                 }
1463                 else
1464                 {
1465                         rv = token->ChangePassword (oldPassword.get (),
1466                                                     newPassword.get ());
1467                 }
1468         }
1469         else
1470         {
1471                 rv = NS_OK;
1472         }
1474         gtk_widget_destroy (GTK_WIDGET (dialog));
1476         *aCancelled = response != GTK_RESPONSE_ACCEPT;
1478         return rv;
1481 /* void getPassword (in nsIInterfaceRequestor ctx, in wstring tokenName, out wstring password, out boolean canceled); */
1482 NS_IMETHODIMP
1483 GtkNSSDialogs::GetPassword(nsIInterfaceRequestor *aCtx,
1484                            const PRUnichar *aTokenName,
1485                            PRUnichar **aPassword,
1486                            PRBool *aCancelled)
1488         NS_ENSURE_ARG_POINTER(aCancelled);
1490         nsresult rv;
1491         nsCOMPtr<nsIPK11Token> token;
1492         nsCOMPtr<nsIPKCS11Slot> slot;
1493         rv = GetTokenAndSlotFromName (aTokenName, getter_AddRefs (token),
1494                                       getter_AddRefs (slot));
1495         NS_ENSURE_SUCCESS (rv, rv);
1496         NS_ENSURE_TRUE (token && slot, NS_ERROR_FAILURE);
1498         AutoJSContextStack stack;
1499         rv = stack.Init ();
1500         if (NS_FAILED (rv)) return rv;
1502         nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aCtx));
1503         GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
1505         AutoWindowModalState modalState (parent);
1507         EphyPasswordDialogFlags flags =
1508                 EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD);
1510         GtkWidget *dialog = ephy_password_dialog_new
1511                                 (gparent,
1512                                  _("Get Token Password"), /* FIXME */
1513                                  flags);
1514         EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog);
1516         /* Translators: A "token" is something that enables the user to authenticate himself or
1517          * prove his credentials. This can be either a hardware device (e.g. a smart-card), or
1518          * a data file (e.g. a cryptographic certificate).
1519          */
1520         char *message = g_markup_printf_escaped (_("Please enter the password for the “%s” token"),
1521                                                  NS_ConvertUTF16toUTF8 (aTokenName).get ());
1522         gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog),
1523                                        message);
1524         g_free (message);
1526         int response = gtk_dialog_run (GTK_DIALOG (dialog));
1528         if (response == GTK_RESPONSE_ACCEPT)
1529         {
1530                 const char *pwd = ephy_password_dialog_get_password (password_dialog);
1531                 *aPassword = NS_StringCloneData (NS_ConvertUTF8toUTF16 (pwd));
1532         }
1533         
1534         gtk_widget_destroy (GTK_WIDGET (dialog));
1536         *aCancelled = response != GTK_RESPONSE_ACCEPT;
1538         return NS_OK;
1541 /* nsITokenDialogs */
1543 static void
1544 SelectionChangedCallback (GtkComboBox *combo,
1545                           GtkDialog *dialog)
1547   int active = gtk_combo_box_get_active (combo);
1548   gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_ACCEPT, active >= 0);
1551 /* void ChooseToken (in nsIInterfaceRequestor ctx,
1552                      [array, size_is (count)] in wstring tokenNameList,
1553                      in unsigned long count,
1554                      out wstring tokenName,
1555                      out boolean canceled); */
1556 NS_IMETHODIMP
1557 GtkNSSDialogs::ChooseToken (nsIInterfaceRequestor *aContext,
1558                             const PRUnichar **tokenNameList,
1559                             PRUint32 count,
1560                             PRUnichar **_tokenName,
1561                             PRBool *_cancelled)
1563   NS_ENSURE_ARG (tokenNameList);
1564   NS_ENSURE_ARG (count);
1566   nsresult rv;
1567   AutoJSContextStack stack;
1568   rv = stack.Init ();
1569   if (NS_FAILED (rv)) return rv;
1571   /* Didn't you know it? MOZILLA SUCKS! ChooseToken is always called with |aContext| == NULL! See
1572    * http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/manager/ssl/src/nsKeygenHandler.cpp&rev=1.39&mark=346#346
1573    * Need to investigate if we it's always called directly from code called from JS, in which case we
1574    * can use EphyJSUtils::GetDOMWindowFromCallContext.
1575    */
1576   nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aContext));
1577   GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
1579   AutoWindowModalState modalState (parent);
1581   GtkWidget *dialog = gtk_message_dialog_new
1582                   (GTK_WINDOW (gparent),
1583                    GTK_DIALOG_DESTROY_WITH_PARENT,
1584                    GTK_MESSAGE_OTHER,
1585                    GTK_BUTTONS_CANCEL,
1586                    _("Please select a token:"));
1588   gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
1590   GtkWidget *combo = gtk_combo_box_new_text ();
1591   for (PRUint32 i = 0; i < count; ++i) {
1592     gtk_combo_box_append_text (GTK_COMBO_BOX (combo),
1593                                NS_ConvertUTF16toUTF8 (tokenNameList[i]).get ());
1594   }
1595   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), -1);
1596   g_signal_connect (combo, "changed",
1597                     G_CALLBACK (SelectionChangedCallback), dialog);
1599   /* FIXME: View Cert button? */
1601   GtkWidget *vbox = GTK_MESSAGE_DIALOG (dialog)->label->parent;
1602   gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
1604   gtk_dialog_add_button (GTK_DIALOG (dialog),
1605                          _("_Select"),
1606                          GTK_RESPONSE_ACCEPT);
1608   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
1610   int response = gtk_dialog_run (GTK_DIALOG (dialog));
1611   int selected = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
1613   gtk_widget_destroy (dialog);
1614         
1615   *_cancelled = response != GTK_RESPONSE_ACCEPT;
1617   if (response == GTK_RESPONSE_ACCEPT) {
1618     NS_ENSURE_TRUE (selected >= 0 && selected < (int) count, NS_ERROR_FAILURE);
1619     *_tokenName = NS_StringCloneData (nsDependentString (tokenNameList[selected]));
1620   }
1622   return NS_OK;
1625 /* nsIDOMCryptoDialogs */
1627 /* Note: this interface sucks! See https://bugzilla.mozilla.org/show_bug.cgi?id=341914 */
1629 /* boolean ConfirmKeyEscrow (in nsIX509Cert escrowAuthority); */
1630 NS_IMETHODIMP
1631 GtkNSSDialogs::ConfirmKeyEscrow (nsIX509Cert *aEscrowAuthority,
1632                                  PRBool *_retval)
1634   NS_ENSURE_ARG (aEscrowAuthority);
1636   nsresult rv;
1637   AutoJSContextStack stack;
1638   rv = stack.Init ();
1639   if (NS_FAILED (rv)) return rv;
1641 #if 0
1642   nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aCtx));
1643 #endif
1644   nsCOMPtr<nsIDOMWindow> parent (EphyJSUtils::GetDOMWindowFromCallContext ());
1645   GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
1647   AutoWindowModalState modalState (parent);
1649   /* FIXME: is that guaranteed to be non-empty? */
1650   nsString commonName;
1651   aEscrowAuthority->GetCommonName (commonName);
1653   GtkWidget *dialog = gtk_message_dialog_new
1654                         (GTK_WINDOW (gparent),
1655                          GTK_DIALOG_DESTROY_WITH_PARENT,
1656                          GTK_MESSAGE_WARNING /* QUESTION really but it's also a strong warnings... */,
1657                          GTK_BUTTONS_NONE,
1658                          _("Escrow the secret key?"));
1660   /* FIXME: If I understand the documentation of generateCRMFRequest
1661    * correctly, key escrow is never used for signing keys (if it were,
1662    * we'd have to warn that the cert authority can forge your signature
1663    * too).
1664    */
1665   gtk_message_dialog_format_secondary_text
1666     (GTK_MESSAGE_DIALOG (dialog),
1667      _("The certificate authority “%s” requests that you give it a copy "
1668        "of the newly generated secret key.\n\n"
1669        "This will enable the certificate authority read any "
1670        "communications encrypted with this key "
1671        "without your knowledge or consent.\n\n"
1672        "It is strongly recommended not to allow it."),
1673      NS_ConvertUTF16toUTF8 (commonName).get ());
1675   gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
1677   GtkWidget *button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1678                                              _("_Reject"),
1679                                              GTK_RESPONSE_REJECT);
1680   gtk_dialog_add_button (GTK_DIALOG (dialog),
1681                          _("_Allow"),
1682                          GTK_RESPONSE_ACCEPT);
1683   /* FIXME: View Cert button? */
1685   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
1686   gtk_widget_grab_focus (button);
1688   int response = gtk_dialog_run (GTK_DIALOG (dialog));
1689   gtk_widget_destroy (dialog);
1690         
1691   *_retval = response == GTK_RESPONSE_ACCEPT;
1693   return NS_OK;