diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | embed/mozilla/GtkNSSClientAuthDialogs.cpp | 19 | ||||
-rw-r--r-- | embed/mozilla/GtkNSSDialogs.cpp | 664 | ||||
-rw-r--r-- | embed/mozilla/GtkNSSDialogs.h | 55 | ||||
-rw-r--r-- | embed/mozilla/GtkNSSKeyPairDialogs.cpp | 16 | ||||
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/ephy-password-dialog.c | 707 | ||||
-rw-r--r-- | lib/ephy-password-dialog.h | 102 |
8 files changed, 1218 insertions, 362 deletions
@@ -1,5 +1,19 @@ 2006-06-22 Christian Persch <chpe@cvs.gnome.org> + * embed/mozilla/GtkNSSClientAuthDialogs.cpp: + * embed/mozilla/GtkNSSDialogs.cpp: + * embed/mozilla/GtkNSSDialogs.h: + * embed/mozilla/GtkNSSKeyPairDialogs.cpp: + * embed/mozilla/MozRegisterComponents.cpp: + * lib/Makefile.am: + A lib/ephy-password-dialog.c: + A lib/ephy-password-dialog.h: + + Implement nsITokenPasswordDialogs. Misc cleanups and mozilla string + simplification now that we depend on gecko 1.8. + +2006-06-22 Christian Persch <chpe@cvs.gnome.org> + * m4/gecko.m4: Fix 'unknown gecko' error output. diff --git a/embed/mozilla/GtkNSSClientAuthDialogs.cpp b/embed/mozilla/GtkNSSClientAuthDialogs.cpp index 26ed934d9..d6765c15e 100644 --- a/embed/mozilla/GtkNSSClientAuthDialogs.cpp +++ b/embed/mozilla/GtkNSSClientAuthDialogs.cpp @@ -197,14 +197,9 @@ GtkNSSClientAuthDialogs::ChooseCertificate (nsIInterfaceRequestor *ctx, gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - - - nsCString utf8_cn; - NS_UTF16ToCString (nsString (cn), - NS_CSTRING_ENCODING_UTF8, utf8_cn); msg = g_markup_printf_escaped (_("Choose a certificate to present as identification to “%s”."), - utf8_cn.get()); + NS_ConvertUTF16toUTF8 (cn).get()); markup_text = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s", _("Select a certificate to identify yourself."), msg); @@ -216,18 +211,10 @@ GtkNSSClientAuthDialogs::ChooseCertificate (nsIInterfaceRequestor *ctx, store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); for (i = 0; i < count; i++) { - nsCString certnick; - nsCString certdetail; - - NS_UTF16ToCString (nsString (certNickList[i]), - NS_CSTRING_ENCODING_UTF8, certnick); - NS_UTF16ToCString (nsString (certDetailsList[i]), - NS_CSTRING_ENCODING_UTF8, certdetail); - gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, - 0, certnick.get(), - 1, certdetail.get(), + 0, NS_ConvertUTF16toUTF8 (certNickList[i]).get(), + 1, NS_ConvertUTF16toUTF8 (certDetailsList[i]).get(), -1); } diff --git a/embed/mozilla/GtkNSSDialogs.cpp b/embed/mozilla/GtkNSSDialogs.cpp index 8bae2e8e8..e3c9b5bcc 100644 --- a/embed/mozilla/GtkNSSDialogs.cpp +++ b/embed/mozilla/GtkNSSDialogs.cpp @@ -1,7 +1,6 @@ /* - * GtkNSSDialogs.cpp - * * Copyright (C) 2003 Crispin Flowerday <gnome@flowerday.cx> + * Copyright (C) 2006 Christian Persch * * 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 @@ -67,6 +66,10 @@ #include <nsIDOMWindow.h> #include <nsIInterfaceRequestor.h> #include <nsIInterfaceRequestorUtils.h> +#include <nsIPKCS11ModuleDB.h> +#include <nsIPKCS11Slot.h> +#include <nsIPK11Token.h> +#include <nsIPK11TokenDB.h> #include <nsIServiceManager.h> #include <nsISimpleEnumerator.h> #include <nsIX509CertDB.h> @@ -81,6 +84,7 @@ #include "ephy-file-helpers.h" #include "ephy-gui.h" +#include "ephy-password-dialog.h" #include "AutoJSContextStack.h" #include "EphyUtils.h" @@ -103,9 +107,19 @@ GtkNSSDialogs::~GtkNSSDialogs () { } -NS_IMPL_THREADSAFE_ISUPPORTS2 (GtkNSSDialogs, +NS_IMPL_THREADSAFE_ISUPPORTS5 (GtkNSSDialogs, nsICertificateDialogs, - nsIBadCertListener) + nsIBadCertListener, + nsITokenPasswordDialogs, + nsITokenDialogs, + nsIDOMCryptoDialogs) + +/* There's also nsICertPickDialogs which is implemented in mozilla + * but has no callers. So we don't implement it. + * Same for nsIUserCertPicker which is only used in mailnews. + * + * We should implement nsIFormSigningDialog, however. + */ /** * Call the mozilla service to display a certificate @@ -301,6 +315,74 @@ display_cert_warning_box (nsIInterfaceRequestor *ctx, } +/* Helper functions */ + +nsresult +GtkNSSDialogs::GetTokenAndSlotFromName (const PRUnichar *aName, + nsIPK11Token **aToken, + nsIPKCS11Slot **aSlot) +{ + nsresult rv = NS_ERROR_FAILURE; + *aToken = nsnull; + *aSlot = nsnull; + + nsCOMPtr<nsIPK11TokenDB> tokenDB = do_GetService("@mozilla.org/security/pk11tokendb;1"); + nsCOMPtr<nsIPKCS11ModuleDB> pkcs11DB = do_GetService("@mozilla.org/security/pkcs11moduledb;1"); + if (!tokenDB || !pkcs11DB) return rv; + + rv = tokenDB->FindTokenByName (aName, aToken); + NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && *aToken, rv); + + pkcs11DB->FindSlotByName (aName, aSlot); + + NS_ENSURE_TRUE (*aSlot, NS_ERROR_FAILURE); + +#ifdef GNOME_ENABLE_DEBUG + /* Dump some info about this token */ + nsIPK11Token *token = *aToken; + PRUnichar *tName, *tLabel, *tManID, *tHWVersion, *tFWVersion, *tSN; + PRInt32 minPwdLen; + PRBool needsInit, isHW, needsLogin, isFriendly; + + token->GetTokenName(&tName); + token->GetTokenLabel(&tLabel); + token->GetTokenManID(&tManID); + token->GetTokenHWVersion(&tHWVersion); + token->GetTokenFWVersion(&tFWVersion); + token->GetTokenSerialNumber(&tSN); + token->GetMinimumPasswordLength(&minPwdLen); + token->GetNeedsUserInit(&needsInit); + token->IsHardwareToken(&isHW); + token->NeedsLogin(&needsLogin); + token->IsFriendly(&isFriendly); + + g_print ("Token '%s' has \nName: %s\nLabel: %s\nManID: %s\nHWversion: %s\nFWVersion: %s\nSN: %s\n" + "MinPwdLen: %d\nNeedsUserInit: %d\nIsHWToken: %d\nNeedsLogin: %d\nIsFriendly: %d\n\n", + NS_ConvertUTF16toUTF8(aName).get(), + + NS_ConvertUTF16toUTF8(tName).get(), + NS_ConvertUTF16toUTF8(tLabel).get(), + NS_ConvertUTF16toUTF8(tManID).get(), + NS_ConvertUTF16toUTF8(tHWVersion).get(), + NS_ConvertUTF16toUTF8(tFWVersion).get(), + NS_ConvertUTF16toUTF8(tSN).get(), + minPwdLen, + needsInit, + isHW, + needsLogin, + isFriendly); + + nsIPKCS11Slot *slot = *aSlot; + PRUnichar*slDesc; + slot->GetDesc(&slDesc); + g_print ("Slot description: %s\n", NS_ConvertUTF16toUTF8 (slDesc).get()); +#endif + + return NS_OK; +} + +/* nsICertificateDialogs */ + NS_IMETHODIMP GtkNSSDialogs::ConfirmMismatchDomain (nsIInterfaceRequestor *ctx, const nsACString &targetURL, @@ -312,9 +394,7 @@ GtkNSSDialogs::ConfirmMismatchDomain (nsIInterfaceRequestor *ctx, nsString commonName; cert->GetCommonName (commonName); - nsCString cCommonName; - NS_UTF16ToCString (commonName, - NS_CSTRING_ENCODING_UTF8, cCommonName); + NS_ConvertUTF16toUTF8 cCommonName (commonName); nsCString cTargetUrl (targetURL); @@ -355,9 +435,7 @@ GtkNSSDialogs::ConfirmUnknownIssuer (nsIInterfaceRequestor *ctx, nsString commonName; cert->GetCommonName (commonName); - nsCString cCommonName; - NS_UTF16ToCString (commonName, - NS_CSTRING_ENCODING_UTF8, cCommonName); + NS_ConvertUTF16toUTF8 cCommonName (commonName); secondary = g_markup_printf_escaped (_("It was not possible to automatically trust “%s”. " @@ -452,9 +530,7 @@ GtkNSSDialogs::ConfirmCertExpired (nsIInterfaceRequestor *ctx, nsString commonName; cert->GetCommonName (commonName); - nsCString cCommonName; - NS_UTF16ToCString (commonName, - NS_CSTRING_ENCODING_UTF8, cCommonName); + NS_ConvertUTF16toUTF8 cCommonName (commonName); LL_DIV (normalizedTime, timeToUse, PR_USEC_PER_SEC); LL_L2UI (t, normalizedTime); @@ -463,6 +539,7 @@ GtkNSSDialogs::ConfirmCertExpired (nsIInterfaceRequestor *ctx, * strftime(3) */ strftime (formattedDate, sizeof(formattedDate), _("%a %d %b %Y"), localtime_r (&t, &tm)); + /* FIXME! this isn't actually correct, LC_CTIME codeset could be different than locale codeset! */ fdate = g_locale_to_utf8 (formattedDate, -1, NULL, NULL, NULL); secondary = g_markup_printf_escaped (text, cCommonName.get(), fdate); @@ -483,59 +560,39 @@ GtkNSSDialogs::ConfirmCertExpired (nsIInterfaceRequestor *ctx, } /* void notifyCrlNextupdate (in nsIInterfaceRequestor socketInfo, - in AUTF8String targetURL, in nsIX509Cert cert); */ + in AUTF8String targetURL, + in nsIX509Cert cert); */ NS_IMETHODIMP GtkNSSDialogs::NotifyCrlNextupdate (nsIInterfaceRequestor *ctx, - const nsACString & targetURL, nsIX509Cert *cert) + const nsACString & targetURL, + nsIX509Cert *cert) { - GtkWidget *dialog, *label; - char *msg, *primary, *secondary; - nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx); GtkWidget *gparent = EphyUtils::FindGtkParent (parent); - dialog = gtk_dialog_new_with_buttons ("", - GTK_WINDOW (gparent), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, - GTK_RESPONSE_OK, - (char *) NULL); - - gtk_window_set_icon_name (GTK_WINDOW (dialog), "web-browser"); - - higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_ERROR, - &label, NULL); + nsCString cTargetUrl (targetURL); nsString commonName; cert->GetCommonName (commonName); - nsCString cCommonName; - NS_UTF16ToCString (commonName, - NS_CSTRING_ENCODING_UTF8, cCommonName); - - nsCString cTargetUrl (targetURL); - - primary = g_markup_printf_escaped (_("Cannot establish connection to “%s”."), - cTargetUrl.get()); - - secondary = g_markup_printf_escaped (_("The certificate revocation list (CRL) from “%s” " - "needs to be updated."), - cCommonName.get()); - 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); - - gtk_widget_show_all (dialog); + GtkWidget *dialog = gtk_message_dialog_new + (GTK_WINDOW (gparent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + _("Cannot establish connection to “%s”"), + cTargetUrl.get ()); + + gtk_message_dialog_format_secondary_text + (GTK_MESSAGE_DIALOG (dialog), + _("The certificate revocation list (CRL) from “%s” " + "needs to be updated.\n\n" + "Please ask your system administrator for assistance."), + NS_ConvertUTF16toUTF8 (commonName).get ()); + gtk_window_set_icon_name (GTK_WINDOW (dialog), "web-browser"); - g_signal_connect (G_OBJECT (dialog), - "response", - (GCallback)gtk_widget_destroy, NULL); + g_signal_connect (dialog, "response", + (GCallback) gtk_widget_destroy, NULL); gtk_widget_show_all (dialog); return NS_OK; @@ -581,9 +638,7 @@ GtkNSSDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor *ctx, nsString commonName; cert->GetCommonName (commonName); - nsCString cCommonName; - NS_UTF16ToCString (commonName, - NS_CSTRING_ENCODING_UTF8, cCommonName); + NS_ConvertUTF16toUTF8 cCommonName (commonName); primary = g_markup_printf_escaped (_("Trust new Certificate Authority “%s” to identify web sites?"), cCommonName.get()); @@ -674,97 +729,13 @@ GtkNSSDialogs::NotifyCACertExists (nsIInterfaceRequestor *ctx) 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); -} - - +/* FIXME: This interface sucks! There is way to know the name of the certificate! */ NS_IMETHODIMP GtkNSSDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor *ctx, nsAString &_password, PRBool *_retval) { - GtkWidget *dialog, *table, *entry1, *entry2, *button, *label, *vbox; - GtkWidget *progress; + GtkWidget *dialog; char *msg; nsresult rv; @@ -773,112 +744,38 @@ GtkNSSDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor *ctx, if (NS_FAILED (rv)) return rv; nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx); - GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent)); - - dialog = gtk_dialog_new_with_buttons ("", gparent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - (char *) NULL); - - if (gparent) - { - gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent), - GTK_WINDOW (dialog)); - } - - gtk_window_set_icon_name (GTK_WINDOW (dialog), "web-browser"); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); - higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_QUESTION, - &label, &vbox); + dialog = ephy_password_dialog_new (gparent, + _("Select Password"), + EphyPasswordDialogFlags(EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD | + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER)); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); - /* Translators: this is the action of the certificate being exported to a backup file */ - button = gtk_button_new_with_mnemonic (_("_Back Up 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); + /* FIXME: set accept button text to (_("_Back Up Certificate") ? + * That's not actually correct, since this function is also called from other places! + */ - 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); + msg = g_markup_printf_escaped (_("Select a password to protect this certificate")); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), 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), 12); - 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 + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_hide (dialog); + + if (response == GTK_RESPONSE_ACCEPT) { - gchar *text = gtk_editable_get_chars (GTK_EDITABLE (entry1), 0, -1); - NS_CStringToUTF16 (nsCString (text), + const char *text = ephy_password_dialog_get_new_password (EPHY_PASSWORD_DIALOG (dialog)); + g_return_val_if_fail (text != NULL, NS_ERROR_FAILURE); + NS_CStringToUTF16 (nsDependentCString (text), NS_CSTRING_ENCODING_UTF8, _password); - g_free (text); - *_retval = PR_TRUE; } + + *_retval = response == GTK_RESPONSE_ACCEPT; + gtk_widget_destroy (dialog); + return NS_OK; } @@ -887,8 +784,7 @@ GtkNSSDialogs::GetPKCS12FilePassword(nsIInterfaceRequestor *ctx, nsAString &_password, PRBool *_retval) { - GtkWidget *dialog, *hbox, *label, *entry, *vbox; - char *msg; + g_print ("GtkNSSDialogs::GetPKCS12FilePassword\n"); nsresult rv; AutoJSContextStack stack; @@ -896,61 +792,33 @@ GtkNSSDialogs::GetPKCS12FilePassword(nsIInterfaceRequestor *ctx, if (NS_FAILED (rv)) return rv; nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx); - GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent)); - - dialog = gtk_dialog_new_with_buttons ("", gparent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - _("I_mport Certificate"), GTK_RESPONSE_OK, - (char *) NULL); - - if (gparent) - { - gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent), - GTK_WINDOW (dialog)); - } + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); - gtk_window_set_icon_name (GTK_WINDOW (dialog), "web-browser"); + GtkWidget *dialog = ephy_password_dialog_new + (gparent, + "", + EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD)); + EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog); + /* FIXME: set accept button text to _("I_mport Certificate") ? */ - higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_QUESTION, - &label, &vbox); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); - 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); + /* FIXME: mozilla sucks, no way to get the name of the certificate / cert file! */ + char *msg = g_markup_printf_escaped (_("Enter the password for this certificate")); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), msg); g_free (msg); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); - 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) + if (response == GTK_RESPONSE_ACCEPT) { - *_retval = PR_FALSE; - } - else - { - gchar * text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); - NS_CStringToUTF16 (nsCString (text), - NS_CSTRING_ENCODING_UTF8, _password); - g_free (text); - *_retval = PR_TRUE; + const char *pwd = ephy_password_dialog_get_password (password_dialog); + NS_CStringToUTF16 (nsDependentCString (pwd), + NS_CSTRING_ENCODING_UTF8, _password); } + + *_retval = response == GTK_RESPONSE_ACCEPT; + gtk_widget_destroy (dialog); return NS_OK; @@ -1036,17 +904,11 @@ GtkNSSDialogs::CrlImportStatusDialog(nsIInterfaceRequestor *ctx, nsICRLInfo *crl if (NS_FAILED(rv)) return rv; int row = 0; - nsCString cOrg; - NS_UTF16ToCString (org, NS_CSTRING_ENCODING_UTF8, cOrg); - set_table_row (table, row, _("Organization:"), cOrg.get ()); + set_table_row (table, row, _("Organization:"), NS_ConvertUTF16toUTF8 (org).get ()); - nsCString cOrgUnit; - NS_UTF16ToCString (orgUnit, NS_CSTRING_ENCODING_UTF8, cOrgUnit); - set_table_row (table, row, _("Unit:"), cOrgUnit.get ()); + set_table_row (table, row, _("Unit:"), NS_ConvertUTF16toUTF8 (orgUnit).get ()); - nsCString cNextUpdate; - NS_UTF16ToCString (nextUpdate, NS_CSTRING_ENCODING_UTF8, cNextUpdate); - set_table_row (table, row, _("Next Update:"), cNextUpdate.get ()); + set_table_row (table, row, _("Next Update:"), NS_ConvertUTF16toUTF8 (nextUpdate).get ()); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); @@ -1079,10 +941,8 @@ set_label_cert_attribute (GladeXML* gxml, const char* label_id, nsAString &value } else { - nsCString cValue; - NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); gtk_label_set_use_markup (GTK_LABEL (label), FALSE); - gtk_label_set_text (GTK_LABEL (label), cValue.get()); + gtk_label_set_text (GTK_LABEL (label), NS_ConvertUTF16toUTF8 (value).get()); } } @@ -1116,8 +976,7 @@ fill_cert_chain_tree (GtkTreeView *treeview, nsIArray *certChain) rv = nsCert->GetCommonName (value); if (NS_FAILED(rv)) return FALSE; - nsCString cValue; - NS_UTF16ToCString (value, NS_CSTRING_ENCODING_UTF8, cValue); + NS_ConvertUTF16toUTF8 cValue (value); nsIX509Cert *nsCertP = nsCert; if (value.Length()) @@ -1161,14 +1020,11 @@ add_asn1_object_to_tree(GtkTreeModel *model, nsIASN1Object *object, GtkTreeIter nsString dispNameU; object->GetDisplayName(dispNameU); - nsCString cDispNameU; - NS_UTF16ToCString (dispNameU, NS_CSTRING_ENCODING_UTF8, cDispNameU); - GtkTreeIter iter; gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent); gtk_tree_store_set (GTK_TREE_STORE(model), &iter, - 0, cDispNameU.get(), + 0, NS_ConvertUTF16toUTF8 (dispNameU).get(), 1, object, -1); @@ -1243,10 +1099,7 @@ field_tree_view_selection_changed_cb (GtkTreeSelection *selection, nsString dispValU; object->GetDisplayValue(dispValU); - nsCString cDispValU; - NS_UTF16ToCString (dispValU, NS_CSTRING_ENCODING_UTF8, cDispValU); - - gtk_text_buffer_set_text (text_buffer, cDispValU.get(), -1); + gtk_text_buffer_set_text (text_buffer, NS_ConvertUTF16toUTF8 (dispValU).get(), -1); } else { @@ -1427,11 +1280,7 @@ GtkNSSDialogs::ViewCert(nsIInterfaceRequestor *ctx, GtkWidget *indent; for (PRUint32 i = 0 ; i < count ; i++) { - nsCString msg; - NS_UTF16ToCString (nsString(usage[i]), - NS_CSTRING_ENCODING_UTF8, msg); - - GtkWidget *label = gtk_label_new(msg.get()); + GtkWidget *label = gtk_label_new (NS_ConvertUTF16toUTF8 (usage[i]).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]); @@ -1444,7 +1293,6 @@ GtkNSSDialogs::ViewCert(nsIInterfaceRequestor *ctx, gtk_box_pack_start (GTK_BOX (widget), indent, FALSE, FALSE, 0); } - cert->GetCommonName (value); set_label_cert_attribute (gxml, "label_cn", value); @@ -1515,3 +1363,181 @@ GtkNSSDialogs::ViewCert(nsIInterfaceRequestor *ctx, gtk_widget_destroy (dialog); return NS_OK; } + +/* nsITokenPasswordDialogs */ + +/* NOTE: This interface totally sucks, see https://bugzilla.mozilla.org/show_bug.cgi?id=306993 */ + +/* void setPassword (in nsIInterfaceRequestor ctx, in wstring tokenName, out boolean canceled); */ +NS_IMETHODIMP +GtkNSSDialogs::SetPassword(nsIInterfaceRequestor *aCtx, + const PRUnichar *aTokenName, + PRBool *aCancelled) +{ + NS_ENSURE_ARG_POINTER(aCancelled); + + nsresult rv; + nsCOMPtr<nsIPK11Token> token; + nsCOMPtr<nsIPKCS11Slot> slot; + rv = GetTokenAndSlotFromName (aTokenName, getter_AddRefs (token), + getter_AddRefs (slot)); + NS_ENSURE_SUCCESS (rv, rv); + NS_ENSURE_TRUE (token && slot, NS_ERROR_FAILURE); + + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + PRUint32 status = nsIPKCS11Slot::SLOT_UNINITIALIZED; + slot->GetStatus (&status); + + nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (aCtx); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + EphyPasswordDialogFlags flags = + EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD | + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER); + if (status != nsIPKCS11Slot::SLOT_UNINITIALIZED) + flags = EphyPasswordDialogFlags (flags | EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD); + + GtkWidget *dialog = ephy_password_dialog_new + (gparent, + _("Change Token Password"), + flags); + EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog); + + char *message = g_markup_printf_escaped (_("Change the password for the “%s” token"), + NS_ConvertUTF16toUTF8 (aTokenName).get ()); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), + message); + g_free (message); + + int response; + nsString oldPassword; + PRBool pwdOk, needsLogin; + do { + response = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (status != nsIPKCS11Slot::SLOT_UNINITIALIZED) + { + const char *pwd = ephy_password_dialog_get_password (password_dialog); + oldPassword = NS_ConvertUTF8toUTF16 (pwd); + } + } while (response == GTK_RESPONSE_OK && + status != nsIPKCS11Slot::SLOT_UNINITIALIZED && + NS_SUCCEEDED (token->NeedsLogin (&needsLogin)) && needsLogin && + NS_SUCCEEDED (token->CheckPassword (oldPassword.get (), &pwdOk) && + !pwdOk)); + + if (response == GTK_RESPONSE_ACCEPT) + { + const char *pwd = ephy_password_dialog_get_new_password (password_dialog); + + NS_ConvertUTF8toUTF16 newPassword (pwd); + + if (status == nsIPKCS11Slot::SLOT_UNINITIALIZED) + { + rv = token->InitPassword (newPassword.get ()); + } + else + { + rv = token->ChangePassword (oldPassword.get (), + newPassword.get ()); + } + } + else + { + rv = NS_OK; + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + *aCancelled = response != GTK_RESPONSE_ACCEPT; + + return rv; +} + +/* void getPassword (in nsIInterfaceRequestor ctx, in wstring tokenName, out wstring password, out boolean canceled); */ +NS_IMETHODIMP +GtkNSSDialogs::GetPassword(nsIInterfaceRequestor *aCtx, + const PRUnichar *aTokenName, + PRUnichar **aPassword, + PRBool *aCancelled) +{ + NS_ENSURE_ARG_POINTER(aCancelled); + + nsresult rv; + nsCOMPtr<nsIPK11Token> token; + nsCOMPtr<nsIPKCS11Slot> slot; + rv = GetTokenAndSlotFromName (aTokenName, getter_AddRefs (token), + getter_AddRefs (slot)); + NS_ENSURE_SUCCESS (rv, rv); + NS_ENSURE_TRUE (token && slot, NS_ERROR_FAILURE); + + AutoJSContextStack stack; + rv = stack.Init (); + if (NS_FAILED (rv)) return rv; + + nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (aCtx); + GtkWidget *gparent = EphyUtils::FindGtkParent (parent); + + EphyPasswordDialogFlags flags = + EphyPasswordDialogFlags (EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD); + + GtkWidget *dialog = ephy_password_dialog_new + (gparent, + _("Get Token Password"), /* FIXME */ + flags); + EphyPasswordDialog *password_dialog = EPHY_PASSWORD_DIALOG (dialog); + + char *message = g_markup_printf_escaped (_("Please enter the password for the “%s” token"), + NS_ConvertUTF16toUTF8 (aTokenName).get ()); + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), + message); + g_free (message); + + int response = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (response == GTK_RESPONSE_ACCEPT) + { + const char *pwd = ephy_password_dialog_get_password (password_dialog); + *aPassword = NS_StringCloneData (NS_ConvertUTF8toUTF16 (pwd)); + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + *aCancelled = response != GTK_RESPONSE_ACCEPT; + + return NS_OK; +} + +/* nsITokenDialogs */ + +/* void ChooseToken (in nsIInterfaceRequestor ctx, [array, size_is (count)] in wstring tokenNameList, in unsigned long count, out wstring tokenName, out boolean canceled); */ +NS_IMETHODIMP +GtkNSSDialogs::ChooseToken (nsIInterfaceRequestor *ctx, + const PRUnichar **tokenNameList, + PRUint32 count, + PRUnichar **tokenName, + PRBool *canceled) +{ + /* FIXME: implement me! The only caller is from nsKeygenHandler */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsIDOMCryptoDialogs */ + +/* Note: this interface sucks! See https://bugzilla.mozilla.org/show_bug.cgi?id=341914 */ + +/* boolean ConfirmKeyEscrow (in nsIX509Cert escrowAuthority); */ +NS_IMETHODIMP +GtkNSSDialogs::ConfirmKeyEscrow (nsIX509Cert *aEscrowAuthority, + PRBool *_retval) +{ + /* FIXME: show a dialogue to warn the user! */ + + /* Escrow is evil, don't allow it. */ + *_retval = PR_FALSE; + + return NS_OK; +} diff --git a/embed/mozilla/GtkNSSDialogs.h b/embed/mozilla/GtkNSSDialogs.h index 8825e3ed5..162817850 100644 --- a/embed/mozilla/GtkNSSDialogs.h +++ b/embed/mozilla/GtkNSSDialogs.h @@ -1,8 +1,20 @@ /* - * GtkNSSDialogs.h + * Copyright (C) 2003 Crispin Flowerday <gnome@flowerday.cx> + * Copyright (C) 2006 Christian Persch * - * Copyright (C) 2003 Crispin Flowerday <gnome@flowerday.cx> - * Available under the terms of the GNU General Public License version 2. + * 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. * * $Id$ */ @@ -12,25 +24,38 @@ #include <nsIBadCertListener.h> #include <nsICertificateDialogs.h> +#include <nsITokenPasswordDialogs.h> +#include <nsITokenDialogs.h> +#include <nsIDOMCryptoDialogs.h> + +class nsIPK11Token; +class nsIPKCS11Slot; -// 7a50a10d-9425-4e12-84b1-5822edacd8ce +/* 7a50a10d-9425-4e12-84b1-5822edacd8ce */ #define GTK_NSSDIALOGS_CID \ {0x7a50a10d, 0x9425, 0x4e12, {0x84, 0xb1, 0x58, 0x22, 0xed, 0xac, 0xd8, 0xce}} #define GTK_NSSDIALOGS_CLASSNAME "Gtk NSS Dialogs" -class GtkNSSDialogs -: public nsIBadCertListener, - public nsICertificateDialogs +class GtkNSSDialogs : public nsIBadCertListener, + public nsICertificateDialogs, + public nsITokenPasswordDialogs, + public nsITokenDialogs, + public nsIDOMCryptoDialogs { -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIBADCERTLISTENER - NS_DECL_NSICERTIFICATEDIALOGS - - GtkNSSDialogs(); - virtual ~GtkNSSDialogs(); + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIBADCERTLISTENER + NS_DECL_NSICERTIFICATEDIALOGS + NS_DECL_NSITOKENPASSWORDDIALOGS + NS_DECL_NSITOKENDIALOGS + NS_DECL_NSIDOMCRYPTODIALOGS + + GtkNSSDialogs(); + virtual ~GtkNSSDialogs(); + + private: + nsresult GetTokenAndSlotFromName(const PRUnichar*, nsIPK11Token**, nsIPKCS11Slot**); }; - #endif /* GTKNSSDIALOGS_H */ diff --git a/embed/mozilla/GtkNSSKeyPairDialogs.cpp b/embed/mozilla/GtkNSSKeyPairDialogs.cpp index f7f1e5eb3..238e183c7 100644 --- a/embed/mozilla/GtkNSSKeyPairDialogs.cpp +++ b/embed/mozilla/GtkNSSKeyPairDialogs.cpp @@ -23,16 +23,6 @@ /* * This file provides Gtk implementations of the mozilla Generating Key Pair * dialogs. - * - * This implementation takes some liberties with the mozilla API. Although the - * API requires a nsIDomWindowInternal, it only actually calls the Close() - * function on that class. Therefore we provide a dummy class that only - * implements that function (it just sets a flag). - * - * Periodically we check to see whether the dialog should have been closed. If - * it should be closed, then the key generation has finished, so close the dialog - * (using gtk_dialog_response), and return. - * */ #include "mozilla-config.h" @@ -108,6 +98,8 @@ begin_busy (GtkWidget *widget) if (!GTK_WIDGET_REALIZED (widget)) gtk_widget_realize (GTK_WIDGET(widget)); gdk_window_set_cursor (GTK_WIDGET (widget)->window, cursor); + + /* Eek! FIXME: AutoJSContextStack! */ while (gtk_events_pending ()) gtk_main_iteration (); } @@ -139,8 +131,8 @@ generating_timeout_cb (KeyPairInfo *info) } -/* void displayGeneratingKeypairInfo (in nsIInterfaceRequestor ctx, in nsIKeygenTh -read runnable); */ +/* void displayGeneratingKeypairInfo (in nsIInterfaceRequestor ctx, + in nsIKeygenThread runnable); */ NS_IMETHODIMP GtkNSSKeyPairDialogs::DisplayGeneratingKeypairInfo (nsIInterfaceRequestor *ctx, nsIKeygenThread *runnable) diff --git a/lib/Makefile.am b/lib/Makefile.am index 439c356bb..e6d4bf638 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -19,6 +19,7 @@ NOINST_H_FILES = \ ephy-node-filter.h \ ephy-node-common.h \ ephy-object-helpers.h \ + ephy-password-dialog.h \ ephy-prefs.h \ ephy-shlib-loader.h \ ephy-signal-accumulator.h \ @@ -29,6 +30,7 @@ NOINST_H_FILES = \ TYPES_H_FILES = \ ephy-adblock.h \ ephy-node.h \ + ephy-password-dialog.h \ ephy-state.h INST_H_FILES = \ @@ -57,6 +59,7 @@ libephymisc_la_SOURCES = \ ephy-node-common.h \ ephy-node-db.c \ ephy-object-helpers.c \ + ephy-password-dialog.c \ ephy-prefs.h \ ephy-shlib-loader.c \ ephy-signal-accumulator.c \ diff --git a/lib/ephy-password-dialog.c b/lib/ephy-password-dialog.c new file mode 100644 index 000000000..165d7a3ff --- /dev/null +++ b/lib/ephy-password-dialog.c @@ -0,0 +1,707 @@ +/* + * Copyright (C) 2003 Crispin Flowerday <gnome@flowerday.cx> + * Copyright (C) 2005, 2006 Christian Persch + * + * 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 of the License, 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. + * + * $Id$ + */ + +#ifndef DONT_HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#ifdef ENABLE_KEYRING +#include <gnome-keyring.h> +#endif + +#include "ephy-gui.h" +#include "ephy-lib-type-builtins.h" +#include "ephy-state.h" + +#include "ephy-password-dialog.h" + +enum +{ + CHECK_USER = 1 << 0, + CHECK_DOMAIN = 1 << 1, + CHECK_PWD = 1 << 2, + CHECK_PWD_MATCH = 1 << 3, + CHECK_PWD_QUALITY = 1 << 4, + CHECK_MASK = 0x1f +}; + +enum +{ + USERNAME_ENTRY, + DOMAIN_ENTRY, + PASSWORD_ENTRY, + NEW_PASSWORD_ENTRY, + CONFIRM_PASSWORD_ENTRY, + N_ENTRIES +}; + +#define EPHY_PASSWORD_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_PASSWORD_DIALOG, EphyPasswordDialogPrivate)) + +struct _EphyPasswordDialogPrivate +{ + GtkWidget *entry[N_ENTRIES]; + GtkWidget *quality_meter; + GtkWidget *remember_button[3]; + gdouble quality_minimum; +#if 0 + char *realm; + char *keyring; + + gpointer lookup_op; + + guint keyring_enabled : 1; +#endif + EphyPasswordDialogFlags flags; + guint checks : 5; +}; + +enum +{ + PROP_0, + PROP_FLAGS, + PROP_DOMAIN, + PROP_KEYRING, + PROP_KEYRING_ENABLED +}; + +G_DEFINE_TYPE (EphyPasswordDialog, ephy_password_dialog, GTK_TYPE_MESSAGE_DIALOG) + +/** + * Calculate the quality of a password. The algorithm used is taken + * directly from mozilla: + * mozilla/security/manager/pki/resources/content/password.js + */ +static gdouble +password_quality (const char *text) +{ + const char *p; + gsize length; + int uppercase = 0, symbols = 0, numbers = 0, strength; + gunichar uc; + + if (text == NULL) return 0.0; + + /* Get the length */ + length = g_utf8_strlen (text, -1); + + /* Count the number of number, symbols and uppercase chars */ + for (p = text; *p; p = g_utf8_find_next_char (p, NULL)) + { + 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; + + strength = (length * 10 - 20) + (numbers * 10) + (symbols * 15) + (uppercase * 10); + strength = CLAMP (strength, 0, 100); + + return ((gdouble) strength) / 100.0; +} + +static void +update_responses (EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv = dialog->priv; + + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), + GTK_RESPONSE_ACCEPT, + priv->checks == 0); +} + +static void +entry_changed_cb (GtkWidget *entry, + EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv = dialog->priv; + guint flag = 0; + const char *text; + + if (entry == priv->entry[USERNAME_ENTRY]) + { + flag = CHECK_USER; + } + else if (entry == priv->entry[DOMAIN_ENTRY]) + { + flag = CHECK_DOMAIN; + } + else if (entry == priv->entry[PASSWORD_ENTRY]) + { + flag = CHECK_PWD; + } + + text = gtk_entry_get_text (GTK_ENTRY (entry)); + if (text != NULL && text[0] != '\0') + { + priv->checks &= ~flag; + } + else + { + priv->checks |= flag; + } + + update_responses (dialog); +} + +static void +password_entry_changed_cb (GtkWidget *entry, + EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv = dialog->priv; + const char *text1, *text2; + + text1 = gtk_entry_get_text (GTK_ENTRY (priv->entry[NEW_PASSWORD_ENTRY])); + text2 = gtk_entry_get_text (GTK_ENTRY (priv->entry[CONFIRM_PASSWORD_ENTRY])); + + if (text1 != NULL && text2 != NULL && strcmp (text1, text2) == 0) + { + priv->checks &= ~CHECK_PWD_MATCH; + } + else + { + priv->checks |= CHECK_PWD_MATCH; + } + + if ((priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER) && + (entry == priv->entry[NEW_PASSWORD_ENTRY])) + { + gdouble quality; + + quality = password_quality (text1); + + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->quality_meter), + quality); + + if (quality >= priv->quality_minimum) + { + priv->checks &= ~CHECK_PWD_QUALITY; + } + else + { + priv->checks |= CHECK_PWD_QUALITY; + } + } + + update_responses (dialog); +} + +/* Focuses the next entry */ +static void +entry_activate_cb (GtkWidget *entry, + EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv = dialog->priv; + int i; + + for (i = 0; i < N_ENTRIES; ++i) + if (entry == priv->entry[i]) break; + g_assert (i < N_ENTRIES); + + for ( ; i < N_ENTRIES; ++i) + if (priv->entry[i] != NULL && + GTK_WIDGET_IS_SENSITIVE (priv->entry[i])) break; + + if (i < N_ENTRIES) + gtk_widget_grab_focus (priv->entry[i]); + else + gtk_window_activate_default (GTK_WINDOW (dialog)); +} + +static void +ephy_password_dialog_init (EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv; + + priv = dialog->priv = EPHY_PASSWORD_DIALOG_GET_PRIVATE (dialog); + + priv->checks = 0; + priv->quality_minimum = 0.0; +} + +static void +add_row (GtkTable *table, + int row, + const char *text, + GtkWidget *widget) +{ + GtkWidget *label; + + label = gtk_label_new_with_mnemonic (text); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + + gtk_table_attach (table, label, + 0, 1, row, row + 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach (table, widget, + 1, 2, row, row + 1, + GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); + + gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); +} + +static GtkWidget * +new_entry (EphyPasswordDialog *dialog, + GtkTable *table, + int row, + const char *text, + gboolean editable, + gboolean password, + GCallback changed_cb) +{ + GtkWidget *entry; + + entry = gtk_entry_new (); + gtk_entry_set_visibility (GTK_ENTRY (entry), !password); + gtk_widget_set_sensitive (entry, editable); + g_signal_connect (entry, "changed", changed_cb, dialog); + g_signal_connect (entry, "activate", + G_CALLBACK (entry_activate_cb), dialog); + + add_row (table, row, text, entry); + + return entry; +} + +#if 0 +static void +update_capslock_warning (GtkWidget *widget, + gboolean show) +{ + //EphyPasswordDialog *dialog = EPHY_PASSWORD_DIALOG (dialog); + //EphyPasswordDialogPrivate *priv = dialog->priv; + + g_print ("CapsLock is now %s\n", show?"on": "off"); +} + +static gboolean +ephy_password_dialog_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + /* The documentation says that LOCK_MASK may be either the + * Shift or the CapsLock key, but I've only ever seen this set + * with CapsLock on. So hopefully this code works ok :) + */ + /* Pressing CapsLock when it was off: state-bit 0 keyval GDK_Caps_Lock + * Pressing CapsLock when it was on: state-bit 1 keyval GDK_Caps_Lock + * Pressing any key while CapsLock on: state-bit 1 + */ + if ((event->state & GDK_LOCK_MASK && + event->keyval != GDK_Caps_Lock) || + event->keyval == GDK_Caps_Lock) + { + update_capslock_warning (widget, TRUE); + } + else if ((event->state & GDK_LOCK_MASK) == 0 || + ((event->state & GDK_LOCK_MASK) && + event->keyval == GDK_Caps_Lock)) + { + update_capslock_warning (widget, FALSE); + } + + return GTK_WIDGET_CLASS (ephy_password_dialog_parent_class)->key_press_event (widget, event); +} +#endif + +static GObject * +ephy_password_dialog_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) + +{ + GObject *object; + GtkWindow *window; + GtkDialog *dialog; + GtkMessageDialog *message_dialog; + EphyPasswordDialog *password_dialog; + EphyPasswordDialogPrivate *priv; + GtkWidget *vbox; + GtkTable *table; + int row = 0; + + object = G_OBJECT_CLASS (ephy_password_dialog_parent_class)->constructor + (type, n_construct_properties, construct_params); + + priv = EPHY_PASSWORD_DIALOG (object)->priv; + window = GTK_WINDOW (object); + dialog = GTK_DIALOG (object); + message_dialog = GTK_MESSAGE_DIALOG (object); + password_dialog = EPHY_PASSWORD_DIALOG (object); + + gtk_window_set_resizable (window, FALSE); + gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* Message has 24, we want 12 = 2 + 2 * 5 */ + + // gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + gtk_window_set_icon_name (window, "web-browser"); + + gtk_image_set_from_icon_name (GTK_IMAGE (message_dialog->image), + GTK_STOCK_DIALOG_AUTHENTICATION, + GTK_ICON_SIZE_DIALOG); + + vbox = message_dialog->label->parent; + + // fixme resize later + table = GTK_TABLE (gtk_table_new (6, 2, FALSE)); + gtk_table_set_row_spacings (table, 6); + gtk_table_set_col_spacings (table, 12); + gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (table), FALSE, FALSE, 0); + + if (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_USERNAME) + { + priv->entry[USERNAME_ENTRY] = + new_entry (password_dialog, + table, + row++, + _("_Username:"), + priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_EDIT_USERNAME, + FALSE, + G_CALLBACK (entry_changed_cb)); + + priv->checks |= CHECK_USER; + } + + if (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_DOMAIN) + { + priv->entry[DOMAIN_ENTRY] = + new_entry (password_dialog, + table, + row++, + _("_Domain:"), + priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_EDIT_DOMAIN, + FALSE, + G_CALLBACK (entry_changed_cb)); + + priv->checks |= CHECK_DOMAIN; + } + + if (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD) + { + priv->entry[PASSWORD_ENTRY] = + new_entry (password_dialog, + table, + row++, + _("_Password:"), + TRUE, + TRUE, + G_CALLBACK (entry_changed_cb)); + + priv->checks |= CHECK_PWD; + } + + if (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD) + { + priv->entry[NEW_PASSWORD_ENTRY] = + new_entry (password_dialog, + table, + row++, + priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD ? + _("_New password:") : + _("_Password:"), + TRUE, + TRUE, + G_CALLBACK (password_entry_changed_cb)); + + priv->entry[CONFIRM_PASSWORD_ENTRY] = + new_entry (password_dialog, + table, + row++, + _("Con_firm password:"), + TRUE, + TRUE, + G_CALLBACK (password_entry_changed_cb)); + + priv->checks |= CHECK_PWD_MATCH; + } + + /* Password quality meter */ + /* TODO: We need a better password quality meter */ + if (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD && + priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER) + { + priv->quality_meter = gtk_progress_bar_new (); + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->quality_meter), 0.0); + + add_row (table, row++, _("Password quality:"), priv->quality_meter); + + priv->checks |= CHECK_PWD_QUALITY; + } + + /* Removed unused table rows */ + gtk_table_resize (table, row, 2); + + if (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_REMEMBER) + { + GSList *group = NULL; + GtkWidget *rbox; + + rbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (vbox), rbox, FALSE, FALSE, 0); + + priv->remember_button[0] = gtk_radio_button_new_with_mnemonic (group, _("Do not remember this password")); + gtk_box_pack_start (GTK_BOX (rbox), priv->remember_button[0], FALSE, FALSE, 0); + group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (priv->remember_button[0])); + + priv->remember_button[1] = gtk_radio_button_new_with_mnemonic (group, _("_Remember password for this session")); + gtk_box_pack_start (GTK_BOX (rbox), priv->remember_button[1], FALSE, FALSE, 0); + group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (priv->remember_button[1])); + + priv->remember_button[2] = gtk_radio_button_new_with_mnemonic (group, _("Save password in _keyring")); + gtk_box_pack_start (GTK_BOX (rbox), priv->remember_button[2], FALSE, FALSE, 0); + } + + gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + gtk_dialog_add_button (dialog, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT); + gtk_dialog_set_default_response (dialog, GTK_RESPONSE_ACCEPT); + update_responses (password_dialog); + + gtk_widget_show_all (vbox); + + return object; +} + +static void +ephy_password_dialog_finalize (GObject *object) +{ +// EphyPasswordDialog *dialog = EPHY_PASSWORD_DIALOG (object); +// EphyPasswordDialogPrivate *priv = dialog->priv; + + G_OBJECT_CLASS (ephy_password_dialog_parent_class)->finalize (object); +} + +static void +ephy_password_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + /* no readable properties */ + g_assert_not_reached (); +} + +static void +ephy_password_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyPasswordDialogPrivate *priv = EPHY_PASSWORD_DIALOG (object)->priv; + + switch (prop_id) + { + case PROP_FLAGS: + priv->flags = g_value_get_flags (value); + break; +#if 0 + case PROP_DOMAIN: + priv->realm = g_value_dup_string (value); + break; + case PROP_KEYRING: + priv->keyring = g_value_dup_string (value); + break; + case PROP_KEYRING_ENABLED: + priv->keyring_enabeld = g_value_get_boolean (value) != FALSE; + break; +#endif + } +} + +static void +ephy_password_dialog_class_init (EphyPasswordDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); +// GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); +// GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass); + + object_class->constructor = ephy_password_dialog_constructor; + object_class->finalize = ephy_password_dialog_finalize; + object_class->get_property = ephy_password_dialog_get_property; + object_class->set_property = ephy_password_dialog_set_property; + +// widget_class->key_press_event = ephy_password_dialog_key_press; + +// dialog_class->response = ephy_password_dialog_response; + + g_type_class_add_private (object_class, sizeof (EphyPasswordDialogPrivate)); + + g_object_class_install_property + (object_class, + PROP_FLAGS, + g_param_spec_flags ("flags", + "flags", + "flags", + EPHY_TYPE_PASSWORD_DIALOG_FLAGS, + EPHY_PASSWORD_DIALOG_FLAGS_DEFAULT, + G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_CONSTRUCT_ONLY)); +#if 0 + g_object_class_install_property (object_class, + PROP_DOMAIN, + g_param_spec_string ("realm", + "realm", + "realm", + NULL, + G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_KEYRING, + g_param_spec_string ("keyring", + "keyring", + "keyring", + NULL, + G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_KEYRING_ENABLED, + g_param_spec_boolean ("keyring-enabled", + "keyring-enabled", + "keyring-enabled", + TRUE, + G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_CONSTRUCT_ONLY)); +#endif +} + +GtkWidget * +ephy_password_dialog_new (GtkWidget *parent, + const char *title, + EphyPasswordDialogFlags flags) +{ + return g_object_new (EPHY_TYPE_PASSWORD_DIALOG, + "transient-for", parent, + "title", title, + "message-type", GTK_MESSAGE_OTHER, + "flags", flags, + (gpointer) NULL); +} + +void +ephy_password_dialog_set_remember (EphyPasswordDialog *dialog, + GnomePasswordDialogRemember remember) +{ + EphyPasswordDialogPrivate *priv; + + g_return_if_fail (EPHY_IS_PASSWORD_DIALOG (dialog)); + g_return_if_fail (remember < GNOME_PASSWORD_DIALOG_REMEMBER_NOTHING || + remember > GNOME_PASSWORD_DIALOG_REMEMBER_FOREVER); + + priv = dialog->priv; + g_return_if_fail (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_REMEMBER); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->remember_button[remember]), TRUE); +} + +GnomePasswordDialogRemember +ephy_password_dialog_get_remember (EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv; + GnomePasswordDialogRemember remember = GNOME_PASSWORD_DIALOG_REMEMBER_NOTHING; + + g_return_val_if_fail (EPHY_IS_PASSWORD_DIALOG (dialog), remember); + + priv = dialog->priv; + g_return_val_if_fail (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_REMEMBER, remember); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->remember_button[0]))) + remember = GNOME_PASSWORD_DIALOG_REMEMBER_NOTHING; + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->remember_button[1]))) + remember = GNOME_PASSWORD_DIALOG_REMEMBER_SESSION; + else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->remember_button[2]))) + remember = GNOME_PASSWORD_DIALOG_REMEMBER_FOREVER; + + return remember; +} + +const char * +ephy_password_dialog_get_username (EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv; + + g_return_val_if_fail (EPHY_IS_PASSWORD_DIALOG (dialog), NULL); + + priv = dialog->priv; + g_return_val_if_fail (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_USERNAME, NULL); + + return gtk_entry_get_text (GTK_ENTRY (priv->entry[USERNAME_ENTRY])); +} + +const char * +ephy_password_dialog_get_domain (EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv; + + g_return_val_if_fail (EPHY_IS_PASSWORD_DIALOG (dialog), NULL); + + priv = dialog->priv; + g_return_val_if_fail (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_DOMAIN, NULL); + + return gtk_entry_get_text (GTK_ENTRY (priv->entry[DOMAIN_ENTRY])); +} + +const char * +ephy_password_dialog_get_password (EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv; + + g_return_val_if_fail (EPHY_IS_PASSWORD_DIALOG (dialog), NULL); + + priv = dialog->priv; + g_return_val_if_fail (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD, NULL); + + return gtk_entry_get_text (GTK_ENTRY (priv->entry[PASSWORD_ENTRY])); +} + +const char * +ephy_password_dialog_get_new_password (EphyPasswordDialog *dialog) +{ + EphyPasswordDialogPrivate *priv; + + g_return_val_if_fail (EPHY_IS_PASSWORD_DIALOG (dialog), NULL); + + priv = dialog->priv; + g_return_val_if_fail (priv->flags & EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD, NULL); + + return gtk_entry_get_text (GTK_ENTRY (priv->entry[NEW_PASSWORD_ENTRY])); +} diff --git a/lib/ephy-password-dialog.h b/lib/ephy-password-dialog.h new file mode 100644 index 000000000..6da76f12b --- /dev/null +++ b/lib/ephy-password-dialog.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005 Christian Persch + * + * 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 of the License, 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. + * + * $Id$ + */ + +#ifndef EPHY_PASSWORD_DIALOG_H +#define EPHY_PASSWORD_DIALOG_H + +#include <gtk/gtkmessagedialog.h> +#include <libgnomeui/gnome-password-dialog.h> + +G_BEGIN_DECLS + +#define EPHY_TYPE_PASSWORD_DIALOG (ephy_password_dialog_get_type ()) +#define EPHY_PASSWORD_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_PASSWORD_DIALOG, EphyPasswordDialog)) +#define EPHY_PASSWORD_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_PASSWORD_DIALOG, EphyPasswordDialogClass)) +#define EPHY_IS_PASSWORD_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_PASSWORD_DIALOG)) +#define EPHY_IS_PASSWORD_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_PASSWORD_DIALOG)) +#define EPHY_PASSWORD_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_PASSWORD_DIALOG, EphyPasswordDialogClass)) + +typedef struct _EphyPasswordDialog EphyPasswordDialog; +typedef struct _EphyPasswordDialogPrivate EphyPasswordDialogPrivate; +typedef struct _EphyPasswordDialogClass EphyPasswordDialogClass; + +struct _EphyPasswordDialog +{ + GtkMessageDialog parent_instance; + + /*< private >*/ + EphyPasswordDialogPrivate *priv; +}; + +struct _EphyPasswordDialogClass +{ + GtkMessageDialogClass parent_class; +}; + +typedef enum +{ + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_USERNAME = 1 << 0, + EPHY_PASSWORD_DIALOG_FLAGS_EDIT_USERNAME = 1 << 1, + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_DOMAIN = 1 << 2, + EPHY_PASSWORD_DIALOG_FLAGS_EDIT_DOMAIN = 1 << 3, + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_PASSWORD = 1 << 4, + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_NEW_PASSWORD = 1 << 5, + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_QUALITY_METER = 1 << 6, + EPHY_PASSWORD_DIALOG_FLAGS_SHOW_REMEMBER = 1 << 7, +} EphyPasswordDialogFlags; + +#define EPHY_PASSWORD_DIALOG_FLAGS_DEFAULT 0 + +GType ephy_password_dialog_get_type (void); + +GtkWidget *ephy_password_dialog_new (GtkWidget *parent, + const char *title, + EphyPasswordDialogFlags flags); + +void ephy_password_dialog_set_remember (EphyPasswordDialog *dialog, + GnomePasswordDialogRemember remember); + +GnomePasswordDialogRemember ephy_password_dialog_get_remember (EphyPasswordDialog *dialog); + +void ephy_password_dialog_set_label (EphyPasswordDialog *dialog, + const char *markup); + +GtkWidget *ephy_password_dialog_get_username_entry (EphyPasswordDialog *dialog); + +const char *ephy_password_dialog_get_username (EphyPasswordDialog *dialog); + +void ephy_password_dialog_set_username (EphyPasswordDialog *dialog, + const char *text); + +const char *ephy_password_dialog_get_domain (EphyPasswordDialog *dialog); + +void ephy_password_dialog_set_domain (EphyPasswordDialog *dialog, + const char *text); + +const char *ephy_password_dialog_get_password (EphyPasswordDialog *dialog); + +void ephy_password_dialog_set_password (EphyPasswordDialog *dialog, + const char *text); + +const char *ephy_password_dialog_get_new_password (EphyPasswordDialog *dialog); + +G_END_DECLS + +#endif /* !EPHY_PASSWORD_DIALOG_H */ |