aboutsummaryrefslogtreecommitdiffstats
path: root/embed/xulrunner/components
diff options
context:
space:
mode:
Diffstat (limited to 'embed/xulrunner/components')
-rw-r--r--embed/xulrunner/components/ContentHandler.cpp480
-rw-r--r--embed/xulrunner/components/ContentHandler.h81
-rw-r--r--embed/xulrunner/components/EphyAboutModule.cpp724
-rw-r--r--embed/xulrunner/components/EphyAboutModule.h65
-rw-r--r--embed/xulrunner/components/EphyContentPolicy.cpp244
-rw-r--r--embed/xulrunner/components/EphyContentPolicy.h76
-rw-r--r--embed/xulrunner/components/EphyRedirectChannel.cpp32
-rw-r--r--embed/xulrunner/components/EphyRedirectChannel.h50
-rw-r--r--embed/xulrunner/components/EphySidebar.cpp161
-rw-r--r--embed/xulrunner/components/EphySidebar.h66
-rw-r--r--embed/xulrunner/components/FilePicker.cpp492
-rw-r--r--embed/xulrunner/components/FilePicker.h62
-rw-r--r--embed/xulrunner/components/GeckoCookiePromptService.cpp159
-rw-r--r--embed/xulrunner/components/GeckoCookiePromptService.h43
-rw-r--r--embed/xulrunner/components/GeckoFormSigningDialog.cpp158
-rw-r--r--embed/xulrunner/components/GeckoFormSigningDialog.h42
-rw-r--r--embed/xulrunner/components/GeckoPrintService.cpp713
-rw-r--r--embed/xulrunner/components/GeckoPrintService.h54
-rw-r--r--embed/xulrunner/components/GeckoPrintSession.cpp629
-rw-r--r--embed/xulrunner/components/GeckoPrintSession.h94
-rw-r--r--embed/xulrunner/components/GeckoSpellCheckEngine.cpp200
-rw-r--r--embed/xulrunner/components/GeckoSpellCheckEngine.h52
-rw-r--r--embed/xulrunner/components/GlobalHistory.cpp221
-rw-r--r--embed/xulrunner/components/GlobalHistory.h68
-rw-r--r--embed/xulrunner/components/GtkNSSClientAuthDialogs.cpp284
-rw-r--r--embed/xulrunner/components/GtkNSSClientAuthDialogs.h45
-rw-r--r--embed/xulrunner/components/GtkNSSDialogs.cpp1695
-rw-r--r--embed/xulrunner/components/GtkNSSDialogs.h61
-rw-r--r--embed/xulrunner/components/GtkNSSKeyPairDialogs.cpp216
-rw-r--r--embed/xulrunner/components/GtkNSSKeyPairDialogs.h45
-rw-r--r--embed/xulrunner/components/GtkNSSSecurityWarningDialogs.cpp285
-rw-r--r--embed/xulrunner/components/GtkNSSSecurityWarningDialogs.h83
-rw-r--r--embed/xulrunner/components/Makefile.am73
-rw-r--r--embed/xulrunner/components/MozDownload.cpp812
-rw-r--r--embed/xulrunner/components/MozDownload.h153
-rw-r--r--embed/xulrunner/components/MozRegisterComponents.cpp330
-rw-r--r--embed/xulrunner/components/MozRegisterComponents.h28
37 files changed, 9074 insertions, 2 deletions
diff --git a/embed/xulrunner/components/ContentHandler.cpp b/embed/xulrunner/components/ContentHandler.cpp
new file mode 100644
index 000000000..051f5e077
--- /dev/null
+++ b/embed/xulrunner/components/ContentHandler.cpp
@@ -0,0 +1,480 @@
+/*
+ * Copyright © 2001 Philip Langdale
+ * Copyright © 2003 Marco Pesenti Gritti
+ * Copyright © 2003 Xan Lopez
+ * Copyright © 2004 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkstock.h>
+#include <libgnomevfs/gnome-vfs-mime.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+
+#include <nsStringGlue.h>
+
+#include <nsCExternalHandlerService.h>
+#include <nsComponentManagerUtils.h>
+#include <nsIDOMWindow.h>
+#include <nsIInterfaceRequestorUtils.h>
+#include <nsILocalFile.h>
+#include <nsIMIMEInfo.h>
+#include <nsIURL.h>
+#include <nsMemory.h>
+#include <nsNetError.h>
+#include <nsServiceManagerUtils.h>
+
+#include "eel-gconf-extensions.h"
+#include "ephy-debug.h"
+#include "ephy-embed-shell.h"
+#include "ephy-embed-single.h"
+#include "ephy-file-chooser.h"
+#include "ephy-file-helpers.h"
+#include "ephy-gui.h"
+#include "ephy-prefs.h"
+#include "ephy-stock-icons.h"
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+#include "MozDownload.h"
+
+#include "ContentHandler.h"
+
+/* FIXME: we don't generally have a timestamp for the user action which initiated this
+ * content handler.
+ */
+GContentHandler::GContentHandler()
+: mUserTime(0)
+{
+ LOG ("GContentHandler ctor (%p)", this);
+}
+
+GContentHandler::~GContentHandler()
+{
+ LOG ("GContentHandler dtor (%p)", this);
+}
+
+NS_IMPL_ISUPPORTS1(GContentHandler, nsIHelperAppLauncherDialog)
+
+/* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext, in unsigned long aReason); */
+NS_IMETHODIMP
+GContentHandler::Show (nsIHelperAppLauncher *aLauncher,
+ nsISupports *aContext,
+ PRUint32 aReason)
+{
+ nsresult rv;
+ EphyEmbedSingle *single;
+ gboolean handled = FALSE;
+
+ /* FIXME: handle aForced / aReason argument in some way? */
+
+ mContext = aContext;
+
+ /* Check for a potential veto */
+ nsCOMPtr<nsIDOMWindow> window (do_GetInterface (aContext));
+ GtkWidget *embed = EphyUtils::FindEmbed (window);
+ if (EPHY_IS_EMBED (embed))
+ {
+ if (g_object_get_data (G_OBJECT (embed), "content-handler-deny"))
+ {
+ return NS_OK;
+ }
+ }
+
+ mLauncher = aLauncher;
+ rv = Init ();
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell));
+ g_signal_emit_by_name (single, "handle_content", mMimeType.get(),
+ mUrl.get(), &handled);
+
+ if (!handled)
+ {
+ MIMEInitiateAction ();
+ }
+ else
+ {
+ mLauncher->Cancel (NS_BINDING_ABORTED);
+ }
+
+ return NS_OK;
+}
+
+/* nsILocalFile promptForSaveToFile (in nsISupports aWindowContext, in wstring aDefaultFile, in wstring aSuggestedFileExtension); */
+NS_IMETHODIMP GContentHandler::PromptForSaveToFile(
+ nsIHelperAppLauncher *aLauncher,
+ nsISupports *aWindowContext,
+ const PRUnichar *aDefaultFile,
+ const PRUnichar *aSuggestedFileExtension,
+ nsILocalFile **_retval)
+{
+ EphyFileChooser *dialog;
+ int response;
+ char *filename = NULL;
+ nsCString defaultFile;
+
+ NS_UTF16ToCString (nsString (aDefaultFile),
+ NS_CSTRING_ENCODING_UTF8, defaultFile);
+
+ if (mAction != CONTENT_ACTION_SAVEAS)
+ {
+ return BuildDownloadPath (defaultFile.get(), _retval);
+ }
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ nsCOMPtr<nsIDOMWindow> parentDOMWindow (do_GetInterface (aWindowContext));
+ GtkWidget *parentWindow = GTK_WIDGET (EphyUtils::FindGtkParent (parentDOMWindow));
+
+ AutoWindowModalState modalState (parentDOMWindow);
+
+ dialog = ephy_file_chooser_new (_("Save"), parentWindow,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ CONF_STATE_SAVE_DIR,
+ EPHY_FILE_FILTER_ALL);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), defaultFile.get());
+
+ if (parentWindow)
+ {
+ gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (parentWindow)),
+ GTK_WINDOW (dialog));
+ }
+
+ /* FIXME: this will only be the real user time if we came from ::Show */
+ ephy_gui_window_update_user_time (GTK_WIDGET (dialog), (guint32) mUserTime);
+
+ /* FIXME: modal -- mozilla sucks! */
+ do
+ {
+ g_free (filename);
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ } while (response == GTK_RESPONSE_ACCEPT
+ && !ephy_gui_check_location_writable (GTK_WIDGET (dialog), filename));
+
+ if (response == GTK_RESPONSE_ACCEPT)
+ {
+ nsCOMPtr <nsILocalFile> destFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
+ NS_ENSURE_TRUE (destFile, NS_ERROR_FAILURE);
+
+ destFile->InitWithNativePath (nsCString (filename));
+ g_free (filename);
+
+ NS_IF_ADDREF (*_retval = destFile);
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+
+ return NS_OK;
+ }
+ else
+ {
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ g_free (filename);
+
+ return NS_ERROR_FAILURE;
+ }
+}
+
+NS_METHOD GContentHandler::Init ()
+{
+ nsresult rv;
+
+ NS_ENSURE_TRUE (mLauncher, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIMIMEInfo> MIMEInfo;
+ mLauncher->GetMIMEInfo (getter_AddRefs(MIMEInfo));
+ NS_ENSURE_TRUE (MIMEInfo, NS_ERROR_FAILURE);
+
+ rv = MIMEInfo->GetMIMEType (mMimeType);
+
+ nsCOMPtr<nsIURI> uri;
+ mLauncher->GetSource (getter_AddRefs(uri));
+ NS_ENSURE_TRUE (uri, NS_ERROR_FAILURE);
+
+ uri->GetSpec (mUrl);
+
+ return NS_OK;
+}
+
+static void
+response_cb (GtkWidget *dialog,
+ int response,
+ GContentHandler *self)
+{
+ gtk_widget_destroy (dialog);
+
+ if (response > 0)
+ {
+ self->mAction = (ContentAction) response;
+ }
+ else
+ {
+ self->mAction = CONTENT_ACTION_NONE;
+ }
+
+ self->MIMEDoAction ();
+}
+
+static void
+release_cb (GContentHandler *data)
+{
+ NS_RELEASE (data);
+}
+
+NS_METHOD GContentHandler::MIMEConfirmAction ()
+{
+ GtkWidget *dialog, *button, *image;
+ const char *action_label;
+ const char *mime_description;
+ nsCString file_name;
+
+ nsCOMPtr<nsIDOMWindow> parentDOMWindow = do_GetInterface (mContext);
+ GtkWindow *parentWindow = GTK_WINDOW (EphyUtils::FindGtkParent(parentDOMWindow));
+
+ action_label = (mAction == CONTENT_ACTION_OPEN) ||
+ (mAction == CONTENT_ACTION_OPEN_TMP) ?
+ GTK_STOCK_OPEN : STOCK_DOWNLOAD;
+
+ mime_description = gnome_vfs_mime_get_description (mMimeType.get());
+ if (mime_description == NULL)
+ {
+ /* Translators: The text before the "|" is context to help you decide on
+ * the correct translation. You MUST OMIT it in the translated string. */
+ mime_description = Q_("File Type:|Unknown");
+ }
+
+ /* We have one tiny, minor issue, the filename can be empty (""),
+ is that severe enough to be completely fixed ? */
+ nsString suggested;
+
+ mLauncher->GetSuggestedFileName (suggested);
+ NS_UTF16ToCString (suggested,
+ NS_CSTRING_ENCODING_UTF8, file_name);
+
+ if (mPermission != EPHY_MIME_PERMISSION_SAFE && mHelperApp)
+ {
+ dialog = gtk_message_dialog_new
+ (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
+ _("Download this potentially unsafe file?"));
+
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dialog),
+ /* translators: First %s is the file type description,
+ Second %s is the file name */
+ _("File Type: “%s”.\n\nIt is unsafe to open “%s” as "
+ "it could potentially damage your documents or "
+ "invade your privacy. You can download it instead."),
+ mime_description, file_name.get());
+ }
+ else if (mAction == CONTENT_ACTION_OPEN_TMP && mHelperApp)
+ {
+ dialog = gtk_message_dialog_new
+ (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
+ _("Open this file?"));
+
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dialog),
+ /* translators: First %s is the file type description,
+ Second %s is the file name,
+ Third %s is the application used to open the file */
+ _("File Type: “%s”.\n\nYou can open “%s” using “%s” or save it."),
+ mime_description, file_name.get(), mHelperApp->name);
+ }
+ else
+ {
+ dialog = gtk_message_dialog_new
+ (parentWindow, GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
+ _("Download this file?"));
+
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dialog),
+ /* translators: First %s is the file type description,
+ Second %s is the file name */
+ _("File Type: “%s”.\n\nYou have no application able to open “%s”. "
+ "You can download it instead."),
+ mime_description, file_name.get());
+ }
+
+ button = gtk_button_new_with_label (_("_Save As..."));
+ image = gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (button), image);
+ /* don't show the image! see bug #307818 */
+ gtk_widget_show (button);
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, CONTENT_ACTION_SAVEAS);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ action_label, mAction);
+
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
+
+ int defaultResponse = mAction == CONTENT_ACTION_NONE
+ ? (int) GTK_RESPONSE_CANCEL
+ : (int) mAction;
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), defaultResponse);
+
+ NS_ADDREF_THIS();
+ g_signal_connect_data (dialog, "response",
+ G_CALLBACK (response_cb), this,
+ (GClosureNotify) release_cb, (GConnectFlags) 0);
+
+ /* FIXME: should find a way to get the user time of the user action which
+ * initiated this content handler
+ */
+ gtk_window_present (GTK_WINDOW (dialog));
+
+ return NS_OK;
+}
+
+NS_METHOD GContentHandler::MIMEInitiateAction (void)
+{
+ gboolean auto_downloads;
+
+ if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_SAVE_TO_DISK)) return NS_OK;
+
+ auto_downloads = eel_gconf_get_boolean (CONF_AUTO_DOWNLOADS);
+
+ mHelperApp = gnome_vfs_mime_get_default_application (mMimeType.get());
+ mPermission = ephy_file_check_mime (mMimeType.get());
+
+ /* HACK! Check that this 'helper application' isn't Epiphany itself,
+ * see bug #310023.
+ */
+ if (mHelperApp)
+ {
+ const char *id = gnome_vfs_mime_application_get_desktop_id (mHelperApp);
+
+ /* FIXME! menu editing can make this check fail!!!! */
+ if (id && strcmp (id, "epiphany.desktop") == 0)
+ {
+ mHelperApp = nsnull;
+ }
+ }
+
+ if (auto_downloads)
+ {
+ mAction = CONTENT_ACTION_OPEN;
+ }
+ else
+ {
+ mAction = CONTENT_ACTION_OPEN_TMP;
+ }
+
+ if (!mHelperApp || mPermission != EPHY_MIME_PERMISSION_SAFE)
+ {
+ mAction = CONTENT_ACTION_DOWNLOAD;
+ }
+
+ if (!auto_downloads || mAction == CONTENT_ACTION_DOWNLOAD)
+ {
+ MIMEConfirmAction ();
+ }
+ else
+ {
+ MIMEDoAction ();
+ }
+
+ return NS_OK;
+}
+
+NS_METHOD GContentHandler::MIMEDoAction (void)
+{
+ /* This is okay, since we either clicked on a button, or we get 0 */
+ mUserTime = gtk_get_current_event_time ();
+
+ nsCOMPtr<nsIMIMEInfo> mimeInfo;
+ mLauncher->GetMIMEInfo(getter_AddRefs(mimeInfo));
+ NS_ENSURE_TRUE (mimeInfo, NS_ERROR_FAILURE);
+
+ char *info = NULL;
+
+ if (mAction == CONTENT_ACTION_OPEN)
+ {
+ g_return_val_if_fail (mHelperApp, NS_ERROR_FAILURE);
+
+ const char *id;
+ id = gnome_vfs_mime_application_get_desktop_id (mHelperApp);
+
+ /* The current time is fine here as the user has just clicked
+ * a button (it is used as the time for the application opening)
+ */
+ info = g_strdup_printf ("gnome-default:%d:%s", gtk_get_current_event_time(), id);
+ }
+ else if (mAction == CONTENT_ACTION_DOWNLOAD)
+ {
+ info = g_strdup_printf ("gnome-browse-to-file:%d", gtk_get_current_event_time());
+ }
+
+ /* See http://bugzilla.gnome.org/show_bug.cgi?id=456945 */
+ // FIXME convert this properly to 1.9
+#ifdef HAVE_GECKO_1_9
+ if (info != NULL)
+ {
+ nsString desc;
+ NS_CStringToUTF16 (nsCString (info),
+ NS_CSTRING_ENCODING_UTF8, desc);
+ g_free (info);
+
+ /* HACK we use the application description to ask
+ MozDownload to open the file when download
+ is finished */
+ mimeInfo->SetApplicationDescription (desc);
+ }
+ else
+ {
+ mimeInfo->SetApplicationDescription (nsString ());
+ }
+#endif /* HAVE_GECKO_1_9 */
+
+ if (mAction == CONTENT_ACTION_OPEN)
+ {
+ mLauncher->SaveToDisk (nsnull, PR_FALSE);
+ }
+ else if (mAction == CONTENT_ACTION_OPEN_TMP)
+ {
+ mLauncher->LaunchWithApplication (nsnull, PR_FALSE);
+ }
+ else if (mAction == CONTENT_ACTION_NONE)
+ {
+ mLauncher->Cancel (NS_BINDING_ABORTED);
+ }
+ else
+ {
+ mLauncher->SaveToDisk (nsnull, PR_FALSE);
+ }
+
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/ContentHandler.h b/embed/xulrunner/components/ContentHandler.h
new file mode 100644
index 000000000..113e29070
--- /dev/null
+++ b/embed/xulrunner/components/ContentHandler.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2000-2003 Marco Pesenti Gritti,
+ * Copyright © 2003 Xan Lopez
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef CONTENT_HANDLER_H
+#define CONTENT_HANDLER_H
+
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+
+#include <nsCOMPtr.h>
+#include <nsIFile.h>
+#include <nsIHelperAppLauncherDialog.h>
+#include <nsIURI.h>
+
+#include "ephy-file-helpers.h"
+
+
+typedef enum
+{
+ CONTENT_ACTION_OPEN = 1,
+ CONTENT_ACTION_OPEN_TMP,
+ CONTENT_ACTION_DOWNLOAD,
+ CONTENT_ACTION_SAVEAS,
+ CONTENT_ACTION_NONE
+} ContentAction;
+
+#define G_CONTENTHANDLER_CID \
+{ /* 16072c4a-23a6-4996-9beb-9335c06bbeae */ \
+ 0x16072c4a, \
+ 0x23a6, \
+ 0x4996, \
+ {0x9b, 0xeb, 0x93, 0x35, 0xc0, 0x6b, 0xbe, 0xae} \
+}
+
+class GContentHandler : public nsIHelperAppLauncherDialog
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIHELPERAPPLAUNCHERDIALOG
+
+ GContentHandler();
+ virtual ~GContentHandler();
+
+ NS_METHOD MIMEDoAction ();
+ ContentAction mAction;
+ private:
+
+ NS_METHOD Init ();
+
+ NS_METHOD MIMEInitiateAction ();
+ NS_METHOD MIMEConfirmAction ();
+
+ nsCOMPtr<nsIHelperAppLauncher> mLauncher;
+ nsCOMPtr<nsISupports> mContext;
+
+ GnomeVFSMimeApplication *mHelperApp;
+ EphyMimePermission mPermission;
+
+ nsCString mUrl;
+ nsCString mMimeType;
+ PRUint32 mUserTime;
+};
+
+#endif /* CONTENT_HANDLER_H */
diff --git a/embed/xulrunner/components/EphyAboutModule.cpp b/embed/xulrunner/components/EphyAboutModule.cpp
new file mode 100644
index 000000000..78ce93bec
--- /dev/null
+++ b/embed/xulrunner/components/EphyAboutModule.cpp
@@ -0,0 +1,724 @@
+/*
+ * Copyright © 2001 Matt Aubury, Philip Langdale
+ * Copyright © 2004 Crispin Flowerday
+ * Copyright © 2005 Adam Hooper
+ * Copyright © 2005, 2007 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <nsStringGlue.h>
+
+#include <nsAutoPtr.h>
+#include <nsCOMPtr.h>
+#include <nsIChannel.h>
+#include <nsIInputStreamChannel.h>
+#include <nsIInputStream.h>
+#include <nsIIOService.h>
+#include <nsINetUtil.h>
+#include <nsIOutputStream.h>
+#include <nsIScriptSecurityManager.h>
+#include <nsIStorageStream.h>
+#include <nsIURI.h>
+#include <nsNetCID.h>
+#include <nsNetUtil.h>
+#include <nsServiceManagerUtils.h>
+
+#include "ephy-debug.h"
+
+#include "EphyRedirectChannel.h"
+
+#include "EphyAboutModule.h"
+
+EphyAboutModule::EphyAboutModule()
+{
+ LOG ("EphyAboutModule ctor [%p]\n", this);
+}
+
+EphyAboutModule::~EphyAboutModule()
+{
+ LOG ("EphyAboutModule dtor [%p]\n", this);
+}
+
+NS_IMPL_ISUPPORTS1 (EphyAboutModule, nsIAboutModule)
+
+/* nsIChannel newChannel (in nsIURI aURI); */
+NS_IMETHODIMP
+EphyAboutModule::NewChannel(nsIURI *aURI,
+ nsIChannel **_retval)
+{
+ NS_ENSURE_ARG(aURI);
+
+ nsCAutoString path;
+ aURI->GetPath (path);
+
+ if (strncmp (path.get(), "neterror?", strlen ("neterror?")) == 0)
+ {
+ return CreateErrorPage (aURI, _retval);
+ }
+
+ if (strncmp (path.get (), "recover?", strlen ("recover?")) == 0)
+ {
+ return CreateRecoverPage (aURI, _retval);
+ }
+
+ if (strcmp (path.get (), "epiphany") == 0)
+ {
+ return Redirect (nsDependentCString ("file://" SHARE_DIR "/epiphany.xhtml"), _retval);
+ }
+
+ return NS_ERROR_ILLEGAL_VALUE;
+}
+
+/* unsigned long getURIFlags(in nsIURI aURI); */
+NS_IMETHODIMP
+EphyAboutModule::GetURIFlags (nsIURI *aURI,
+ PRUint32 *_result)
+{
+ *_result = 0;
+ return NS_OK;
+}
+
+/* private functions */
+
+nsresult
+EphyAboutModule::Redirect(const nsACString &aURL,
+ nsIChannel **_retval)
+{
+ *_retval = nsnull;
+
+ nsresult rv;
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI (getter_AddRefs (uri), aURL);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIChannel> tempChannel;
+ rv = NS_NewChannel (getter_AddRefs (tempChannel), uri);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ tempChannel->SetOriginalURI (uri);
+
+ nsCOMPtr<nsIScriptSecurityManager> securityManager =
+ do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIPrincipal> principal;
+ rv = securityManager->GetCodebasePrincipal(uri, getter_AddRefs(principal));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = tempChannel->SetOwner(principal);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ tempChannel.swap (*_retval);
+
+ return NS_OK;
+}
+
+nsresult
+EphyAboutModule::ParseURL(const char *aURL,
+ nsACString &aCode,
+ nsACString &aRawOriginURL,
+ nsACString &aOriginURL,
+ nsACString &aOriginCharset,
+ nsACString &aTitle)
+{
+ /* The page URL is of the form "about:neterror?e=<errorcode>&u=<URL>&c=<charset>&d=<description>" */
+ const char *query = strstr (aURL, "?");
+ if (!query) return NS_ERROR_FAILURE;
+
+ /* skip the '?' */
+ ++query;
+
+ char **params = g_strsplit (query, "&", -1);
+ if (!params) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsINetUtil> netUtil (do_GetService (NS_NETUTIL_CONTRACTID));
+ if (!netUtil) return NS_ERROR_FAILURE;
+
+ for (PRUint32 i = 0; params[i] != NULL; ++i)
+ {
+ char *param = params[i];
+
+ if (strlen (param) <= 2) continue;
+
+ switch (param[0])
+ {
+ case 'e':
+ netUtil->UnescapeString (nsDependentCString (param + 2), 0, aCode);
+ break;
+ case 'u':
+ aRawOriginURL.Assign (param + 2);
+ netUtil->UnescapeString (nsDependentCString (param + 2), 0, aOriginURL);
+ break;
+ case 'c':
+ netUtil->UnescapeString (nsDependentCString (param + 2), 0, aOriginCharset);
+ break;
+ /* The next one is not used in neterror but recover: */
+ case 't':
+ netUtil->UnescapeString (nsDependentCString (param + 2), 0, aTitle);
+ break;
+ case 'd':
+ /* we don't need mozilla's description parameter */
+ default:
+ break;
+ }
+ }
+
+ g_strfreev (params);
+
+ return NS_OK;
+}
+
+nsresult
+EphyAboutModule::GetErrorMessage(nsIURI *aURI,
+ const char *aError,
+ char **aStockIcon,
+ char **aTitle,
+ char **aPrimary,
+ char **aSecondary,
+ char **aTertiary,
+ char **aLinkIntro)
+{
+ *aStockIcon = GTK_STOCK_DIALOG_ERROR;
+
+ if (strcmp (aError, "protocolNotFound") == 0)
+ {
+ nsCAutoString scheme;
+ aURI->GetScheme (scheme);
+
+ /* Translators: %s is the name of a protocol, like "http" etc. */
+ *aTitle = g_strdup_printf (_("“%s” Protocol is not Supported"), scheme.get());
+ /* Translators: %s is the name of a protocol, like "http" etc. */
+ *aPrimary = g_strdup_printf (_("“%s” protocol is not supported."), scheme.get());
+ /* FIXME: get the list of supported protocols from necko */
+ *aSecondary = g_strdup (_("Supported protocols are “http”, “https”, “ftp”, “file”, “smb” "
+ "and “sftp”."));
+ }
+ else if (strcmp (aError, "fileNotFound") == 0)
+ {
+ nsCAutoString path;
+ aURI->GetPath (path);
+
+ /* Translators: %s is the path and filename, for example "/home/user/test.html" */
+ *aTitle = g_markup_printf_escaped (_("File “%s” not Found"), path.get());
+ /* Translators: %s is the path and filename, for example "/home/user/test.html" */
+ *aPrimary = g_markup_printf_escaped (_("File “%s” not found."), path.get());
+ *aSecondary = g_strdup (_("Check the location of the file and try again."));
+ }
+ else if (strcmp (aError, "dnsNotFound") == 0)
+ {
+ nsCAutoString host;
+ aURI->GetHost (host);
+
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aTitle = g_markup_printf_escaped (_("“%s” Could not be Found"),
+ host.get());
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aPrimary = g_markup_printf_escaped (_("“%s” could not be found."),
+ host.get());
+ *aSecondary = g_strdup (_("Check that you are connected to the internet, and "
+ "that the address is correct."));
+ *aLinkIntro = _("If this page used to exist, you may find an archived version:");
+ }
+ else if (strcmp (aError, "connectionFailure") == 0)
+ {
+ nsCAutoString host;
+ aURI->GetHost (host);
+
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aTitle = g_markup_printf_escaped
+ (_("“%s” Refused the Connection"),
+ host.get());
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aPrimary = g_markup_printf_escaped
+ (_("“%s” refused the connection."),
+ host.get());
+
+ /* FIXME what about 127.0.0.* ? */
+ if (strcmp (host.get(), "localhost") == 0)
+ {
+ PRInt32 port;
+ aURI->GetPort (&port);
+
+ *aSecondary = g_strdup (_("Likely causes of the problem are"));
+
+ /* Try to get the service name attached to that port */
+ if (port != -1)
+ {
+ struct servent *serv;
+
+ if ((serv = getservbyport (htons (port), NULL)) != NULL)
+ {
+ *aTertiary = g_markup_printf_escaped (
+ _("<ul>"
+ "<li>the service ""%s"" isn't started.</li>"
+ "Try to start it using the Services Configuration Tool in "
+ "System > Control Center, or</ul>"
+ "<ul><li>the port number %d is wrong.</li>"
+ "</ul>"),
+ serv->s_name, port);
+ }
+ else
+ {
+ *aTertiary = g_markup_printf_escaped (
+ _("<ul>"
+ "<li>some service isn't started, or</li>"
+ "<li>the port number %d is wrong.</li>"
+ "</ul>"),
+ port);
+ }
+ }
+ else
+ {
+ *aTertiary = _("<ul>"
+ "<li>some service isn't started, or</li>"
+ "<li>you got the port number wrong.</li>"
+ "</ul>");
+ }
+ }
+ else
+ {
+ *aSecondary = g_strdup (_("The server may be busy or you may have a "
+ "network connection problem. Try again later."));
+ *aLinkIntro = _("There may be an old version of the page you wanted:");
+ }
+ }
+ else if (strcmp (aError, "netInterrupt") == 0)
+ {
+ nsCAutoString host;
+ aURI->GetHost (host);
+
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aTitle = g_markup_printf_escaped
+ (_("“%s” Interrupted the Connection"),
+ host.get());
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aPrimary = g_markup_printf_escaped
+ (_("“%s” interrupted the connection."),
+ host.get());
+ *aSecondary = g_strdup (_("The server may be busy or you may have a "
+ "network connection problem. Try again later."));
+ *aLinkIntro = _("There may be an old version of the page you wanted:");
+ }
+ else if (strcmp (aError, "netTimeout") == 0)
+ {
+ nsCAutoString host;
+ aURI->GetHost (host);
+
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aTitle = g_markup_printf_escaped
+ (_("“%s” is not Responding"),
+ host.get());
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aPrimary = g_markup_printf_escaped
+ (_("“%s” is not responding."),
+ host.get());
+ *aSecondary = g_strdup (_("The connection was lost because the "
+ "server took too long to respond."));
+ *aTertiary = _("The server may be busy or you may have a network "
+ "connection problem. Try again later.");
+ *aLinkIntro = _("There may be an old version of the page you wanted:");
+ }
+ else if (strcmp (aError, "malformedURI") == 0)
+ {
+ *aTitle = g_strdup (_("Invalid Address"));
+ *aPrimary = g_strdup (_("Invalid address."));
+ *aSecondary = g_strdup (_("The address you entered is not valid."));
+ }
+ else if (strcmp (aError, "redirectLoop") == 0)
+ {
+ nsCAutoString host;
+ aURI->GetHost (host);
+
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aTitle = g_markup_printf_escaped
+ (_("“%s” Redirected Too Many Times"),
+ host.get());
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aPrimary = g_strdup (_("This page cannot load because of a problem with the Web site."));
+
+ *aSecondary = g_markup_printf_escaped
+ (_("The server “%s” is redirecting in a way that will never complete."),
+ host.get());
+ *aLinkIntro = _("There may be an old version of the page you wanted:");
+ }
+ else if (strcmp (aError, "unknownSocketType") == 0)
+ {
+ nsCAutoString host;
+ aURI->GetHost (host);
+
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aTitle = g_markup_printf_escaped
+ (_("“%s” Requires an Encrypted Connection"),
+ host.get());
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aPrimary = g_markup_printf_escaped
+ (_("“%s” requires an encrypted connection."),
+ host.get());
+ *aSecondary = g_strdup (_("The document could not be loaded because "
+ "encryption support is not installed."));
+ }
+ else if (strcmp (aError, "netReset") == 0)
+ {
+ nsCAutoString host;
+ aURI->GetHost (host);
+
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aTitle = g_markup_printf_escaped
+ (_("“%s” Dropped the Connection"),
+ host.get());
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aPrimary = g_markup_printf_escaped
+ (_("“%s” dropped the connection."),
+ host.get());
+ *aSecondary = g_strdup (_("The server dropped the connection "
+ "before any data could be read."));
+ *aTertiary = _("The server may be busy or you may have a "
+ "network connection problem. Try again later.");
+ *aLinkIntro = _("There may be an old version of the page you wanted:");
+ }
+ else if (strcmp (aError, "netOffline") == 0)
+ {
+ /* Error is a bit too strong here */
+ *aStockIcon = GTK_STOCK_DIALOG_INFO;
+
+ *aTitle = g_strdup (_("Cannot Load Document Whilst Working Offline"));
+ *aPrimary = g_strdup (_("Cannot load document whilst working offline."));
+ *aSecondary = g_strdup (_("To view this document, disable “Work Offline” and try again."));
+ }
+ else if (strcmp (aError, "deniedPortAccess") == 0)
+ {
+ nsCAutoString host;
+ aURI->GetHost (host);
+
+ PRInt32 port = -1;
+ aURI->GetPort (&port);
+
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aTitle = g_markup_printf_escaped
+ (_("“%s” Denied Access to Port “%d”"),
+ host.get(), port > 0 ? port : 80);
+ /* Translators: %s is the hostname, like "www.example.com" */
+ *aPrimary = g_markup_printf_escaped
+ (_("“%s” denied access to port “%d”."),
+ host.get(), port > 0 ? port : 80);
+ *aSecondary = g_strdup (_("The server dropped the connection "
+ "before any data could be read."));
+ *aTertiary = _("The server may be busy or you may have a "
+ "network connection problem. Try again later.");
+ *aLinkIntro = _("There may be an old version of the page you wanted:");
+ }
+ else if (strcmp (aError, "proxyResolveFailure") == 0 ||
+ strcmp (aError, "proxyConnectFailure") == 0)
+ {
+ *aTitle = g_strdup (_("Could not Connect to Proxy Server"));
+ *aPrimary = g_strdup (_("Could not connect to proxy server."));
+ *aSecondary = g_strdup (_("Check your proxy server settings. "
+ "If the connection still fails, there may be "
+ "a problem with your proxy server or your "
+ "network connection."));
+ }
+ /* This was introduced in gecko 1.9 */
+ else if (strcmp (aError, "contentEncodingError") == 0)
+ {
+ *aTitle = g_strdup (_("Could not Display Content"));
+ *aPrimary = g_strdup (_("Could not display content."));
+ *aSecondary = g_strdup (_("The page uses an unsupported or invalid form of compression."));
+ }
+ else
+ {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+EphyAboutModule::CreateErrorPage(nsIURI *aErrorURI,
+ nsIChannel **_retval)
+{
+ *_retval = nsnull;
+
+ /* First parse the arguments */
+ nsresult rv;
+ nsCAutoString spec;
+ rv = aErrorURI->GetSpec (spec);
+ NS_ENSURE_TRUE (NS_SUCCEEDED (rv), rv);
+
+ nsCAutoString error, rawurl, url, charset, dummy;
+ rv = ParseURL (spec.get (), error, rawurl, url, charset, dummy);
+ if (NS_FAILED (rv)) return rv;
+ if (error.IsEmpty () || rawurl.IsEmpty () || url.IsEmpty()) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI (getter_AddRefs (uri), url, charset.get());
+ /* FIXME can uri be NULL if the original url was invalid? */
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ char *stock_id = nsnull, *title = nsnull, *primary = nsnull,
+ *secondary = nsnull, *tertiary = nsnull, *linkintro = nsnull;
+ rv = GetErrorMessage (uri, error.get(), &stock_id, &title, &primary,
+ &secondary, &tertiary, &linkintro);
+
+ /* we don't know about this error code.
+ * FIXME: We'd like to forward to mozilla's about:neterror handler,
+ * but I don't know how to. So just redirect to the same page that
+ * mozilla's handler redirects to.
+ */
+ if (rv == NS_ERROR_ILLEGAL_VALUE)
+ {
+ nsCAutoString newurl(spec);
+
+ /* remove "about:neterror" part and insert mozilla's error page url */
+ newurl.Cut(0, strlen ("about:neterror"));
+ newurl.Insert("chrome://global/content/netError.xhtml", 0);
+
+ return Redirect (newurl, _retval);
+ }
+ NS_ENSURE_SUCCESS (rv, rv);
+ NS_ENSURE_TRUE (primary && secondary, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIChannel> channel;
+ rv = WritePage (aErrorURI, uri, aErrorURI, rawurl, title, stock_id, primary, secondary, tertiary, linkintro, getter_AddRefs (channel));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ g_free (title);
+ g_free (primary);
+ g_free (secondary);
+
+ channel.swap (*_retval);
+
+ return NS_OK;
+}
+
+nsresult
+EphyAboutModule::CreateRecoverPage(nsIURI *aRecoverURI,
+ nsIChannel **_retval)
+{
+ *_retval = nsnull;
+
+ /* First parse the arguments */
+ nsresult rv;
+ nsCAutoString spec;
+ rv = aRecoverURI->GetSpec (spec);
+ NS_ENSURE_TRUE (NS_SUCCEEDED (rv), rv);
+
+ nsCAutoString error, rawurl, url, charset, title;
+ rv = ParseURL (spec.get (), error, rawurl, url, charset, title);
+ if (NS_FAILED (rv)) return rv;
+ if (rawurl.IsEmpty () || url.IsEmpty()) return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIURI> uri;
+ rv = NS_NewURI(getter_AddRefs (uri), url, charset.get());
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ char *secondary = g_markup_printf_escaped
+ (_("The page “%s” in this tab was not fully loaded yet when "
+ "the web browser crashed; it could have caused the crash."),
+ url.get());
+
+ nsCOMPtr<nsIChannel> channel;
+ rv = WritePage (aRecoverURI, uri, uri, rawurl, title.get(),
+ GTK_STOCK_DIALOG_INFO, title.get() /* as primary */,
+ secondary, nsnull, nsnull, getter_AddRefs (channel));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsRefPtr<EphyRedirectChannel> redirectChannel (new EphyRedirectChannel (channel));
+ if (!redirectChannel) return NS_ERROR_OUT_OF_MEMORY;
+
+ g_free (secondary);
+
+ NS_ADDREF(*_retval = redirectChannel);
+
+ return NS_OK;
+}
+
+nsresult
+EphyAboutModule::WritePage(nsIURI *aOriginalURI,
+ nsIURI *aURI,
+ nsIURI *aChannelURI,
+ const nsACString &aRawURL,
+ const char *aTitle,
+ const char *aStockIcon,
+ const char *aPrimary,
+ const char *aSecondary,
+ const char *aTertiary,
+ const char *aLinkIntro,
+ nsIChannel **_retval)
+{
+ *_retval = nsnull;
+
+ nsresult rv;
+ nsCOMPtr<nsIStorageStream> storageStream;
+ rv = NS_NewStorageStream (16384, (PRUint32) -1, getter_AddRefs (storageStream));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIOutputStream> stream;
+ rv = storageStream->GetOutputStream (0, getter_AddRefs (stream));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ char *language = g_strdup (pango_language_to_string (gtk_get_default_language ()));
+ g_strdelimit (language, "_-@", '\0');
+
+ Write (stream,
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"");
+ Write (stream, language);
+ Write (stream,
+ "\" xml:lang=\"");
+ Write (stream, language);
+ Write (stream,
+ "\">\n"
+ "<head>\n"
+ "<title>");
+ Write (stream, aTitle);
+ /* no favicon for now, it would pollute the favicon cache */
+ /* "<link rel=\"icon\" type=\"image/png\" href=\"moz-icon://stock/gtk-dialog-error?size=16\" />\n" */
+ Write (stream,
+ "</title>\n"
+ "<style type=\"text/css\">\n"
+ "div#body {\n"
+ "top: 12px;\n"
+ "right: 12px;\n"
+ "bottom: 12px;\n"
+ "left: 12px;\n"
+ "overflow: auto;\n"
+
+ "background: -moz-dialog url('moz-icon://stock/");
+ Write (stream, aStockIcon);
+ Write (stream,
+ "?size=dialog') no-repeat 12px 12px;\n"
+ "color: -moz-dialogtext;\n"
+ "font: message-box;\n"
+ "border: 1px solid -moz-dialogtext;\n"
+
+ "padding: 12px 12px 12px 72px;\n"
+ "}\n"
+
+ "h1 {\n"
+ "margin: 0;\n"
+ "font-size: 1.2em;\n"
+ "}\n"
+ "</style>\n"
+ "</head>\n"
+ "<body dir=\"");
+ Write (stream,
+ gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL ? "rtl" : "ltr");
+ Write (stream,
+ "\">\n"
+ "<div id=\"body\">"
+ "<h1>");
+ Write (stream, aPrimary);
+ Write (stream,
+ "</h1>\n");
+ if (aSecondary)
+ {
+ Write (stream, "<p>");
+ Write (stream, aSecondary);
+ if (aTertiary)
+ {
+ Write (stream, " ");
+ Write (stream, aTertiary);
+ }
+ Write (stream, "</p>\n");
+ }
+
+ PRBool isHttp = PR_FALSE, isHttps = PR_FALSE;
+ aURI->SchemeIs ("http", &isHttp);
+ aURI->SchemeIs ("https", &isHttps);
+ if (aLinkIntro && (isHttp || isHttps))
+ {
+ nsCString raw(aRawURL);
+
+ Write (stream, "<p>");
+ Write (stream, aLinkIntro);
+ Write (stream, "<ul>\n");
+ Write (stream, "<li><a href=\"http://www.google.com/search?q=cache:");
+ Write (stream, raw.get());
+ Write (stream, "\">");
+ /* Translators: The text before the "|" is context to help you decide on
+ * the correct translation. You MUST OMIT it in the translated string. */
+ Write (stream, Q_("You may find an old version:|in the Google Cache"));
+ Write (stream, "</a></li>\n");
+
+ Write (stream, "<li><a href=\"http://web.archive.org/web/*/");
+ Write (stream, raw.get());
+ Write (stream, "\">");
+ /* Translators: The text before the "|" is context to help you decide on
+ * the correct translation. You MUST OMIT it in the translated string. */
+ Write (stream, Q_("You may find an old version:|in the Internet Archive"));
+ Write (stream, "</a></li>\n"
+ "</ul>\n"
+ "</p>");
+ }
+
+ Write (stream,
+ "</div>\n"
+ "</body>\n"
+ "</html>\n");
+
+ g_free (language);
+
+ /* finish the rendering */
+ nsCOMPtr<nsIInputStream> inputStream;
+ rv = storageStream->NewInputStream (0, getter_AddRefs (inputStream));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIChannel> channel;
+ rv = NS_NewInputStreamChannel (getter_AddRefs (channel),
+ aChannelURI,
+ inputStream,
+ NS_LITERAL_CSTRING ("application/xhtml+xml"),
+ NS_LITERAL_CSTRING ("utf-8"));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = channel->SetOriginalURI (aOriginalURI);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIScriptSecurityManager> securityManager
+ (do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIPrincipal> principal;
+ rv = securityManager->GetCodebasePrincipal (aOriginalURI, getter_AddRefs (principal));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = channel->SetOwner(principal);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ channel.swap (*_retval);
+
+ return NS_OK;
+}
+
+nsresult
+EphyAboutModule::Write(nsIOutputStream *aStream,
+ const char *aText)
+{
+ PRUint32 bytesWritten;
+ return aStream->Write (aText, strlen (aText), &bytesWritten);
+}
diff --git a/embed/xulrunner/components/EphyAboutModule.h b/embed/xulrunner/components/EphyAboutModule.h
new file mode 100644
index 000000000..21a269c49
--- /dev/null
+++ b/embed/xulrunner/components/EphyAboutModule.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2001 Matt Aubury, Philip Langdale
+ * Copyright © 2004 Crispin Flowerday
+ * Copyright © 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_ABOUT_MODULE_H
+#define EPHY_ABOUT_MODULE_H
+
+#include <nsIAboutModule.h>
+
+/* a9aea13e-21de-4be8-a07e-a05f11658c55 */
+#define EPHY_ABOUT_MODULE_CID \
+{ 0xa9aea13e, 0x21de, 0x4be8, \
+ { 0xa0, 0x7e, 0xa0, 0x5f, 0x11, 0x65, 0x8c, 0x55 } }
+
+#define EPHY_ABOUT_NETERROR_CONTRACTID NS_ABOUT_MODULE_CONTRACTID_PREFIX "neterror"
+#define EPHY_ABOUT_NETERROR_CLASSNAME "Epiphany about:neterror module"
+
+#define EPHY_ABOUT_EPIPHANY_CONTRACTID NS_ABOUT_MODULE_CONTRACTID_PREFIX "epiphany"
+#define EPHY_ABOUT_EPIPHANY_CLASSNAME "Epiphany about:epiphany module"
+#define EPHY_ABOUT_RECOVER_CONTRACTID NS_ABOUT_MODULE_CONTRACTID_PREFIX "recover"
+#define EPHY_ABOUT_RECOVER_CLASSNAME "Epiphany about:recover module"
+
+class nsIChannel;
+class nsIOutputStream;
+class nsIInputStreamChannel;
+class nsIURI;
+
+class EphyAboutModule : public nsIAboutModule
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIABOUTMODULE
+
+ EphyAboutModule();
+ virtual ~EphyAboutModule();
+
+ private:
+ nsresult Redirect(const nsACString&, nsIChannel**);
+ nsresult ParseURL(const char*, nsACString&, nsACString&, nsACString&, nsACString&, nsACString&);
+ nsresult GetErrorMessage(nsIURI*, const char*, char**, char**, char**, char**, char**, char**);
+ nsresult CreateErrorPage(nsIURI*, nsIChannel**);
+ nsresult CreateRecoverPage(nsIURI*, nsIChannel**);
+ nsresult WritePage(nsIURI*, nsIURI*, nsIURI*, const nsACString&, const char*, const char*, const char*, const char*, const char*, const char*, nsIChannel**);
+ nsresult Write(nsIOutputStream*, const char*);
+};
+
+#endif /* EPHY_ABOUT_MODULE_H */
diff --git a/embed/xulrunner/components/EphyContentPolicy.cpp b/embed/xulrunner/components/EphyContentPolicy.cpp
new file mode 100644
index 000000000..7f8943687
--- /dev/null
+++ b/embed/xulrunner/components/EphyContentPolicy.cpp
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright © 2003 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <nsStringGlue.h>
+
+#include <nsCOMPtr.h>
+#include <nsICategoryManager.h>
+#include <nsIDOMAbstractView.h>
+#include <nsIDOMDocument.h>
+#include <nsIDOMDocumentView.h>
+#include <nsIDOMNode.h>
+#include <nsIDOMWindow.h>
+#include <nsIURI.h>
+#include <nsServiceManagerUtils.h>
+#include <nsXPCOMCID.h>
+
+#include "eel-gconf-extensions.h"
+#include "ephy-adblock-manager.h"
+#include "ephy-debug.h"
+#include "ephy-embed-shell.h"
+#include "ephy-embed-single.h"
+
+#include "EphyUtils.h"
+
+#include "EphyContentPolicy.h"
+
+#define CONF_LOCKDOWN_DISABLE_UNSAFE_PROTOCOLS "/apps/epiphany/lockdown/disable_unsafe_protocols"
+#define CONF_LOCKDOWN_ADDITIONAL_SAFE_PROTOCOLS "/apps/epiphany/lockdown/additional_safe_protocols"
+
+NS_IMPL_ISUPPORTS1(EphyContentPolicy, nsIContentPolicy)
+
+EphyContentPolicy::EphyContentPolicy()
+{
+ LOG ("EphyContentPolicy ctor (%p)", this);
+
+ mLocked = eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_UNSAFE_PROTOCOLS);
+
+ mSafeProtocols = eel_gconf_get_string_list (CONF_LOCKDOWN_ADDITIONAL_SAFE_PROTOCOLS);
+}
+
+EphyContentPolicy::~EphyContentPolicy()
+{
+ LOG ("EphyContentPolicy dtor (%p)", this);
+
+ g_slist_foreach (mSafeProtocols, (GFunc) g_free, NULL);
+ g_slist_free (mSafeProtocols);
+}
+
+GtkWidget *
+EphyContentPolicy::GetEmbedFromContext (nsISupports *aContext)
+{
+ /*
+ * aContext is either an nsIDOMWindow, an nsIDOMNode, or NULL. If it's
+ * an nsIDOMNode, we need the nsIDOMWindow to get the EphyEmbed.
+ */
+ if (aContext == NULL) return NULL;
+
+ nsCOMPtr<nsIDOMWindow> window;
+
+ nsCOMPtr<nsIDOMNode> node (do_QueryInterface (aContext));
+ if (node != NULL)
+ {
+ nsCOMPtr<nsIDOMDocument> domDocument;
+
+ node->GetOwnerDocument (getter_AddRefs (domDocument));
+ if (domDocument == NULL) return NULL; /* resource://... */
+
+ nsCOMPtr<nsIDOMDocumentView> docView =
+ do_QueryInterface (domDocument);
+ NS_ENSURE_TRUE (docView, NULL);
+
+ nsCOMPtr<nsIDOMAbstractView> view;
+
+ docView->GetDefaultView (getter_AddRefs (view));
+
+ window = do_QueryInterface (view);
+ }
+ else
+ {
+ window = do_QueryInterface (aContext);
+ }
+ NS_ENSURE_TRUE (window, NULL);
+
+ GtkWidget *embed = EphyUtils::FindEmbed (window);
+ if (!EPHY_IS_EMBED (embed)) return NULL;
+
+ return embed;
+}
+
+NS_IMETHODIMP
+EphyContentPolicy::ShouldLoad(PRUint32 aContentType,
+ nsIURI *aContentLocation,
+ nsIURI *aRequestingLocation,
+ nsISupports *aContext,
+ const nsACString &aMimeTypeGuess,
+ nsISupports *aExtra,
+ PRInt16 *aDecision)
+{
+ NS_ENSURE_ARG (aContentLocation);
+ NS_ENSURE_ARG_POINTER (aDecision);
+
+ *aDecision = nsIContentPolicy::ACCEPT;
+
+ /* We have to always allow these, else forms and scrollbars break */
+ PRBool isChrome = PR_FALSE, isResource = PR_FALSE;
+ aContentLocation->SchemeIs ("chrome", &isChrome);
+ aContentLocation->SchemeIs ("resource", &isResource);
+ if (isChrome || isResource) return NS_OK;
+
+ PRBool isHttps = PR_FALSE;
+ aContentLocation->SchemeIs ("https", &isHttps);
+ if (isHttps) return NS_OK;
+
+ /* is this url allowed ? */
+ nsCString contentSpec;
+ aContentLocation->GetSpec (contentSpec);
+
+ EphyAdBlockManager *adblock_manager =
+ EPHY_ADBLOCK_MANAGER (ephy_embed_shell_get_adblock_manager (embed_shell));
+
+ static PRBool kBlockType[nsIContentPolicy::TYPE_REFRESH + 1] = {
+ PR_FALSE /* unused/unknown, don't block */,
+ PR_TRUE /* TYPE_OTHER */,
+ PR_TRUE /* TYPE_SCRIPT */,
+ PR_TRUE /* TYPE_IMAGE */,
+ PR_FALSE /* TYPE_STYLESHEET */,
+ PR_TRUE /* TYPE_OBJECT */,
+ PR_FALSE /* TYPE_DOCUMENT */,
+ PR_TRUE /* TYPE_SUBDOCUMENT */,
+ PR_TRUE /* TYPE_REFRESH */
+ };
+
+ if (kBlockType[aContentType < G_N_ELEMENTS (kBlockType) ? aContentType : 0])
+ {
+ GtkWidget *embed = GetEmbedFromContext (aContext);
+
+ if (embed &&
+ !ephy_adblock_manager_should_load (adblock_manager,
+ EPHY_EMBED (embed),
+ contentSpec.get (),
+ AdUriCheckType (aContentType)))
+ {
+ *aDecision = nsIContentPolicy::REJECT_REQUEST;
+
+ g_signal_emit_by_name (embed,
+ "content-blocked",
+ contentSpec.get ());
+ return NS_OK;
+ }
+ }
+
+ PRBool isHttp = PR_FALSE;
+ aContentLocation->SchemeIs ("http", &isHttp);
+ if (isHttp) return NS_OK;
+
+ if (strcmp (contentSpec.get(), "about:blank") == 0) return NS_OK;
+
+ nsCString contentScheme;
+ aContentLocation->GetScheme (contentScheme);
+
+ /* first general lockdown check */
+ if (mLocked &&
+ !g_slist_find_custom (mSafeProtocols, contentScheme.get(), (GCompareFunc) strcmp))
+ {
+ *aDecision = nsIContentPolicy::REJECT_REQUEST;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+EphyContentPolicy::ShouldProcess(PRUint32 aContentType,
+ nsIURI *aContentLocation,
+ nsIURI *aRequestingLocation,
+ nsISupports *aContext,
+ const nsACString &aMimeType,
+ nsISupports *aExtra,
+ PRInt16 *aDecision)
+{
+ *aDecision = nsIContentPolicy::ACCEPT;
+ return NS_OK;
+}
+
+
+/* static */ NS_METHOD
+EphyContentPolicy::Register (nsIComponentManager* aComponentManager,
+ nsIFile* aPath,
+ const char* aRegistryLocation,
+ const char* aComponentType,
+ const nsModuleComponentInfo* aInfo)
+{
+ nsresult rv;
+ nsCOMPtr<nsICategoryManager> catMan (do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = catMan->AddCategoryEntry ("content-policy",
+ EPHY_CONTENT_POLICY_CONTRACTID,
+ EPHY_CONTENT_POLICY_CONTRACTID,
+ PR_FALSE /* don't persist */,
+ PR_TRUE /* replace */,
+ nsnull);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ return rv;
+}
+
+/* static */ NS_METHOD
+EphyContentPolicy::Unregister (nsIComponentManager* aComponentManager,
+ nsIFile* aPath,
+ const char* aRegistryLocation,
+ const nsModuleComponentInfo* aInfo)
+{
+ nsresult rv;
+ nsCOMPtr<nsICategoryManager> catMan (do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = catMan->DeleteCategoryEntry ("content-policy",
+ EPHY_CONTENT_POLICY_CONTRACTID,
+ PR_FALSE /* don't persist */);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ return rv;
+}
diff --git a/embed/xulrunner/components/EphyContentPolicy.h b/embed/xulrunner/components/EphyContentPolicy.h
new file mode 100644
index 000000000..0bc68ced7
--- /dev/null
+++ b/embed/xulrunner/components/EphyContentPolicy.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright © 2003 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_CONTENT_POLICY_H
+#define EPHY_CONTENT_POLICY_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtkwidget.h>
+
+#include <nsIContentPolicy.h>
+
+#include "ephy-embed.h"
+
+class nsIComponentManager;
+class nsIFile;
+struct nsModuleComponentInfo;
+
+#define EPHY_CONTENT_POLICY_CONTRACTID "@gnome.org/projects/epiphany/epiphany-content-policy;1"
+#define EPHY_CONTENT_POLICY_CLASSNAME "Epiphany Content Policy Class"
+
+#define EPHY_CONTENT_POLICY_CID \
+{ /* 6bb60b15-b7bd-4023-a19e-ab691bc3fb43 */ \
+ 0x6bb60b15, \
+ 0xb7bd, \
+ 0x4023, \
+ { 0xa1, 0x9e, 0xab, 0x69, 0x1b, 0xc3, 0xfb, 0x43 } \
+}
+
+class EphyContentPolicy : public nsIContentPolicy
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICONTENTPOLICY
+
+ EphyContentPolicy();
+
+ static NS_METHOD Register (nsIComponentManager* aComponentManager,
+ nsIFile* aPath,
+ const char* aRegistryLocation,
+ const char* aComponentType,
+ const nsModuleComponentInfo* aInfo);
+
+ static NS_METHOD Unregister (nsIComponentManager* aComponentManager,
+ nsIFile* aPath,
+ const char* aRegistryLocation,
+ const nsModuleComponentInfo* aInfo);
+
+ private:
+ ~EphyContentPolicy();
+
+ static GtkWidget *GetEmbedFromContext (nsISupports *aContext);
+
+ gboolean mLocked;
+ GSList *mSafeProtocols;
+};
+
+#endif
diff --git a/embed/xulrunner/components/EphyRedirectChannel.cpp b/embed/xulrunner/components/EphyRedirectChannel.cpp
new file mode 100644
index 000000000..af6dd2f91
--- /dev/null
+++ b/embed/xulrunner/components/EphyRedirectChannel.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include "EphyRedirectChannel.h"
+
+NS_IMPL_ISUPPORTS2 (EphyWrappedChannel, nsIRequest, nsIChannel)
+
+NS_IMETHODIMP
+EphyRedirectChannel::SetLoadFlags(nsLoadFlags aFlags)
+{
+ return mChannel->SetLoadFlags (aFlags | LOAD_REPLACE);
+}
diff --git a/embed/xulrunner/components/EphyRedirectChannel.h b/embed/xulrunner/components/EphyRedirectChannel.h
new file mode 100644
index 000000000..bcec1f1e5
--- /dev/null
+++ b/embed/xulrunner/components/EphyRedirectChannel.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_REDIRECT_CHANNEL_H
+#define EPHY_REDIRECT_CHANNEL_H
+
+#include <nsCOMPtr.h>
+#include <nsIChannel.h>
+
+class EphyWrappedChannel : public nsIChannel
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_FORWARD_NSIREQUEST (mChannel->)
+ NS_FORWARD_NSICHANNEL (mChannel->)
+
+ EphyWrappedChannel (nsIChannel *aChannel) : mChannel (aChannel) { }
+ virtual ~EphyWrappedChannel () { }
+
+ protected:
+ nsCOMPtr<nsIChannel> mChannel;
+};
+
+class EphyRedirectChannel : public EphyWrappedChannel
+{
+ public:
+ EphyRedirectChannel (nsIChannel *aChannel) : EphyWrappedChannel (aChannel) { }
+ virtual ~EphyRedirectChannel () { }
+
+ NS_IMETHOD SetLoadFlags (nsLoadFlags aFlags);
+};
+
+#endif /* !EPHY_REDIRECT_CHANNEL_H */
diff --git a/embed/xulrunner/components/EphySidebar.cpp b/embed/xulrunner/components/EphySidebar.cpp
new file mode 100644
index 000000000..1225e2d9a
--- /dev/null
+++ b/embed/xulrunner/components/EphySidebar.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright © 2002 Philip Langdale
+ * Copyright © 2004 Crispin Flowerday
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <nsStringGlue.h>
+
+#include <nsICategoryManager.h>
+#include <nsIClassInfoImpl.h>
+#include <nsIScriptNameSpaceManager.h>
+#include <nsMemory.h>
+#include <nsServiceManagerUtils.h>
+#include <nsXPCOMCID.h>
+
+#include "ephy-debug.h"
+#include "ephy-embed-shell.h"
+#include "ephy-embed-single.h"
+
+#include "EphySidebar.h"
+
+NS_IMPL_ISUPPORTS1_CI(EphySidebar, nsISidebar)
+
+EphySidebar::EphySidebar()
+{
+}
+
+EphySidebar::~EphySidebar()
+{
+}
+
+/* void addPanel (in wstring aTitle, in string aContentURL, in string aCustomizeURL); */
+NS_IMETHODIMP
+EphySidebar::AddPanel (const PRUnichar *aTitle,
+ const char *aContentURL,
+ const char *aCustomizeURL)
+{
+ NS_ENSURE_ARG (aTitle);
+ NS_ENSURE_ARG (aContentURL);
+
+ nsCString title;
+ EphyEmbedSingle *single;
+
+ /* FIXME: length-limit string */
+ NS_UTF16ToCString (nsDependentString(aTitle),
+ NS_CSTRING_ENCODING_UTF8, title);
+
+ LOG ("Adding sidebar, url=%s title=%s", aContentURL, title.get());
+
+ single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell));
+
+ gboolean result = FALSE;
+ g_signal_emit_by_name (single, "add-sidebar",
+ aContentURL, title.get(), &result);
+
+ return NS_OK;
+}
+
+/* void addPersistentPanel (in wstring aTitle, in string aContentURL, in string aCustomizeURL); */
+NS_IMETHODIMP
+EphySidebar::AddPersistentPanel (const PRUnichar *aTitle,
+ const char *aContentURL,
+ const char *aCustomizeURL)
+{
+ return AddPanel (aTitle, aContentURL, aCustomizeURL);
+}
+
+/* void addSearchEngine (in string engineURL, in string iconURL, in wstring suggestedTitle, in wst
+ring suggestedCategory); */
+NS_IMETHODIMP
+EphySidebar::AddSearchEngine (const char *aEngineURL,
+ const char *aIconURL,
+ const PRUnichar *aSuggestedTitle,
+ const PRUnichar *aSuggestedCategory)
+{
+ NS_ENSURE_ARG (aSuggestedTitle);
+ NS_ENSURE_ARG (aIconURL);
+ NS_ENSURE_ARG (aEngineURL);
+
+ nsCString title;
+ EphyEmbedSingle *single;
+
+ /* FIXME: length-limit string */
+ NS_UTF16ToCString (nsDependentString(aSuggestedTitle),
+ NS_CSTRING_ENCODING_UTF8, title);
+
+ LOG ("Adding search engine, engineurl=%s iconurl=%s title=%s", aEngineURL, aIconURL, title.get());
+
+ single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell));
+
+ gboolean result = FALSE;
+ g_signal_emit_by_name (single, "add-search-engine",
+ aEngineURL, aIconURL, title.get(), &result);
+
+ return NS_OK;
+}
+
+/* void addMicrosummaryGenerator (in string generatorURL); */
+NS_IMETHODIMP
+EphySidebar::AddMicrosummaryGenerator (const char *generatorURL)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* static */ NS_METHOD
+EphySidebar::Register (nsIComponentManager* aComponentManager,
+ nsIFile* aPath,
+ const char* aRegistryLocation,
+ const char* aComponentType,
+ const nsModuleComponentInfo* aInfo)
+{
+ nsresult rv;
+ nsCOMPtr<nsICategoryManager> catMan (do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = catMan->AddCategoryEntry (JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY,
+ "sidebar",
+ NS_SIDEBAR_CONTRACTID,
+ PR_FALSE /* don't persist */,
+ PR_TRUE /* replace */,
+ nsnull);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ return rv;
+}
+
+/* static */ NS_METHOD
+EphySidebar::Unregister (nsIComponentManager* aComponentManager,
+ nsIFile* aPath,
+ const char* aRegistryLocation,
+ const nsModuleComponentInfo* aInfo)
+{
+ nsresult rv;
+ nsCOMPtr<nsICategoryManager> catMan (do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = catMan->DeleteCategoryEntry (JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY,
+ "sidebar",
+ PR_FALSE /* don't persist */);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ return rv;
+}
diff --git a/embed/xulrunner/components/EphySidebar.h b/embed/xulrunner/components/EphySidebar.h
new file mode 100644
index 000000000..37efa0bf8
--- /dev/null
+++ b/embed/xulrunner/components/EphySidebar.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2002 Philip Langdale
+ * Copyright © 2004 Crispin Flowerday
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_SIDEBAR_H
+#define EPHY_SIDEBAR_H
+
+#include <nsISidebar.h>
+
+class nsIComponentManager;
+class nsIFile;
+struct nsModuleComponentInfo;
+
+#define EPHY_SIDEBAR_CLASSNAME \
+ "Epiphany's Sidebar Implementation"
+
+#define EPHY_SIDEBAR_CID \
+{ /* {50f13159-f9b9-44b3-b18e-6ee5d85a202a} */ \
+ 0x50f13159, \
+ 0xf9b9, \
+ 0x44b3, \
+ {0xb1, 0x8e, 0x6e, 0xe5, 0xd8, 0x5a, 0x20, 0x2a} \
+}
+
+class EphySidebar : public nsISidebar
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISIDEBAR
+
+ EphySidebar();
+
+ static NS_METHOD Register (nsIComponentManager* aComponentManager,
+ nsIFile* aPath,
+ const char* aRegistryLocation,
+ const char* aComponentType,
+ const nsModuleComponentInfo* aInfo);
+
+ static NS_METHOD Unregister (nsIComponentManager* aComponentManager,
+ nsIFile* aPath,
+ const char* aRegistryLocation,
+ const nsModuleComponentInfo* aInfo);
+
+ private:
+ ~EphySidebar();
+};
+
+#endif /* ! EPHY_SIDEBAR_H */
+
diff --git a/embed/xulrunner/components/FilePicker.cpp b/embed/xulrunner/components/FilePicker.cpp
new file mode 100644
index 000000000..e452dd0a7
--- /dev/null
+++ b/embed/xulrunner/components/FilePicker.cpp
@@ -0,0 +1,492 @@
+/*
+ * Copyright © 2001 Philip Langdale
+ * Copyright © 2003, 2004 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib/gconvert.h>
+#include <glib/gi18n.h>
+#include <gtk/gtkfilefilter.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkstock.h>
+
+#include <nsStringGlue.h>
+
+#include <nsCOMPtr.h>
+#include <nsIDOMWindow.h>
+#include <nsIFileURL.h>
+#include <nsILocalFile.h>
+#include <nsIPromptService.h>
+#include <nsIServiceManager.h>
+#include <nsIURI.h>
+#include <nsNetCID.h>
+
+#include "ephy-debug.h"
+#include "ephy-gui.h"
+#include "ephy-prefs.h"
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+
+#include "FilePicker.h"
+
+NS_IMPL_ISUPPORTS1(GFilePicker, nsIFilePicker)
+
+GFilePicker::GFilePicker()
+: mDialog(nsnull)
+, mMode(nsIFilePicker::modeOpen)
+{
+ LOG ("GFilePicker ctor (%p)", this);
+}
+
+GFilePicker::~GFilePicker()
+{
+ LOG ("GFilePicker dtor (%p)", this);
+
+ if (mDialog)
+ {
+ g_object_remove_weak_pointer (G_OBJECT (mDialog), (gpointer *) &mDialog);
+ gtk_widget_destroy (GTK_WIDGET (mDialog));
+ }
+}
+
+/* void init (in nsIDOMWindow parent, in AString title, in short mode); */
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+NS_IMETHODIMP GFilePicker::Init(nsIDOMWindow *parent, const nsAString& title, PRInt16 mode)
+#else
+NS_IMETHODIMP GFilePicker::Init(nsIDOMWindowInternal *parent, const PRUnichar *title, PRInt16 mode)
+#endif
+{
+ LOG ("GFilePicker::Init");
+
+ mParent = do_QueryInterface (parent);
+
+ GtkWidget *gtkparent = EphyUtils::FindGtkParent (parent);
+#if defined(MOZ_NSIFILEPICKER_NSASTRING_)
+ NS_ENSURE_TRUE (gtkparent, NS_ERROR_FAILURE);
+#endif
+
+ nsCString cTitle;
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+ NS_UTF16ToCString (title, NS_CSTRING_ENCODING_UTF8, cTitle);
+#else
+ NS_UTF16ToCString (nsString(title), NS_CSTRING_ENCODING_UTF8, cTitle);
+#endif
+
+ mMode = mode;
+
+ GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
+ switch (mode)
+ {
+ case nsIFilePicker::modeGetFolder:
+ action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+ break;
+ case nsIFilePicker::modeOpenMultiple:
+ case nsIFilePicker::modeOpen:
+ action = GTK_FILE_CHOOSER_ACTION_OPEN;
+ break;
+ case nsIFilePicker::modeSave:
+ action = GTK_FILE_CHOOSER_ACTION_SAVE;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ mDialog = ephy_file_chooser_new (cTitle.get(), gtkparent, action,
+ CONF_STATE_UPLOAD_DIR,
+ EPHY_FILE_FILTER_NONE);
+
+ if (parent)
+ {
+ gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (gtkparent)),
+ GTK_WINDOW (mDialog));
+ }
+
+ if (mode == nsIFilePicker::modeOpenMultiple)
+ {
+ gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (mDialog), TRUE);
+ }
+ if (mMode == nsIFilePicker::modeSave)
+ {
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (mDialog), TRUE);
+ }
+
+ g_object_add_weak_pointer (G_OBJECT (mDialog), (gpointer *) &mDialog);
+
+ return NS_OK;
+}
+
+/* void appendFilters (in long filterMask); */
+NS_IMETHODIMP GFilePicker::AppendFilters(PRInt32 filterMask)
+{
+ NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE);
+
+ LOG ("GFilePicker::AppendFilters mask=%d", filterMask);
+
+ // http://lxr.mozilla.org/seamonkey/source/xpfe/components/filepicker/res/locale/en-US/filepicker.properties
+ // http://lxr.mozilla.org/seamonkey/source/xpfe/components/filepicker/src/nsFilePicker.js line 131 ff
+
+ if (filterMask & nsIFilePicker::filterAll)
+ {
+ ephy_file_chooser_add_pattern_filter (mDialog, _("All files"),
+ "*", (char*) NULL);
+ }
+ if (filterMask & nsIFilePicker::filterHTML)
+ {
+ ephy_file_chooser_add_mime_filter (mDialog, _("Web pages"),
+ "text/html",
+ "application/xhtml+xml",
+ "text/xml",
+ (char *) NULL);
+ }
+ if (filterMask & nsIFilePicker::filterText)
+ {
+ ephy_file_chooser_add_pattern_filter (mDialog, _("Text files"),
+ "*.txt", "*.text", NULL);
+ }
+ if (filterMask & nsIFilePicker::filterImages)
+ {
+ ephy_file_chooser_add_mime_filter (mDialog, _("Images"),
+ "image/png",
+ "image/jpeg",
+ "image/gif",
+ (char *) NULL);
+ }
+ if (filterMask & nsIFilePicker::filterXML)
+ {
+ ephy_file_chooser_add_pattern_filter (mDialog, _("XML files"),
+ "*.xml", (char *) NULL);
+ }
+ if (filterMask & nsIFilePicker::filterXUL)
+ {
+ ephy_file_chooser_add_pattern_filter (mDialog, _("XUL files"),
+ "*.xul", (char *) NULL);
+ }
+
+ return NS_OK;
+}
+
+/* void appendFilter (in AString title, in AString filter); */
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+NS_IMETHODIMP GFilePicker::AppendFilter(const nsAString& title, const nsAString& filter)
+#else
+NS_IMETHODIMP GFilePicker::AppendFilter(const PRUnichar *title, const PRUnichar *filter)
+#endif
+{
+ NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE);
+
+ LOG ("GFilePicker::AppendFilter");
+
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+ if (!filter.Length()) return NS_ERROR_FAILURE;
+#else
+ if (!filter) return NS_ERROR_FAILURE;
+#endif
+
+ nsCString pattern;
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+ NS_UTF16ToCString (filter, NS_CSTRING_ENCODING_UTF8, pattern);
+#else
+ NS_UTF16ToCString (nsString(filter), NS_CSTRING_ENCODING_UTF8, pattern);
+#endif
+
+ char **patterns;
+ patterns = g_strsplit (pattern.get(), ";", -1);
+ if (!patterns) return NS_ERROR_FAILURE;
+
+ GtkFileFilter *filth;
+ filth = gtk_file_filter_new ();
+
+ for (int i = 0; patterns[i] != NULL; i++)
+ {
+ gtk_file_filter_add_pattern (filth, g_strstrip (patterns[i]));
+ }
+
+ nsCString cTitle;
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+ NS_UTF16ToCString (title, NS_CSTRING_ENCODING_UTF8, cTitle);
+#else
+ NS_UTF16ToCString (nsString(title), NS_CSTRING_ENCODING_UTF8, cTitle);
+#endif
+
+ gtk_file_filter_set_name (filth, cTitle.get());
+
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (mDialog), filth);
+
+ g_strfreev (patterns);
+
+ return NS_OK;
+}
+
+/* attribute AString defaultString; */
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+NS_IMETHODIMP GFilePicker::GetDefaultString(nsAString& aDefaultString)
+#else
+NS_IMETHODIMP GFilePicker::GetDefaultString(PRUnichar **aDefaultString)
+#endif
+{
+ NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE);
+
+ LOG ("GFilePicker::GetDefaultString");
+
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+ aDefaultString = mDefaultString;
+#else
+ *aDefaultString = NS_StringCloneData (mDefaultString);
+#endif
+
+ return NS_OK;
+}
+
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+NS_IMETHODIMP GFilePicker::SetDefaultString(const nsAString& aDefaultString)
+#else
+NS_IMETHODIMP GFilePicker::SetDefaultString(const PRUnichar *aDefaultString)
+#endif
+{
+ NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE);
+
+ mDefaultString.Assign (aDefaultString);
+
+ if (mMode == nsIFilePicker::modeSave)
+ {
+ nsCString defaultString;
+ NS_UTF16ToCString (mDefaultString, NS_CSTRING_ENCODING_UTF8,
+ defaultString);
+
+ LOG ("GFilePicker::SetDefaultString %s", defaultString.get());
+
+ if (!defaultString.Length()) return NS_ERROR_FAILURE;
+
+ /* set_current_name takes UTF-8, not a filename */
+ gtk_file_chooser_set_current_name
+ (GTK_FILE_CHOOSER (mDialog), defaultString.get());
+ }
+
+ return NS_OK;
+}
+
+/* attribute AString defaultExtension; */
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+NS_IMETHODIMP GFilePicker::GetDefaultExtension(nsAString& aDefaultExtension)
+#else
+NS_IMETHODIMP GFilePicker::GetDefaultExtension(PRUnichar **aDefaultExtension)
+#endif
+{
+ LOG ("GFilePicker::GetDefaultExtension");
+
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+#ifdef MOZ_NSIFILEPICKER_NSASTRING_
+NS_IMETHODIMP GFilePicker::SetDefaultExtension(const nsAString& aDefaultExtension)
+#else
+NS_IMETHODIMP GFilePicker::SetDefaultExtension(const PRUnichar *aDefaultExtension)
+#endif
+{
+ LOG ("GFilePicker::SetDefaultExtension");
+
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute long filterIndex; */
+NS_IMETHODIMP GFilePicker::GetFilterIndex(PRInt32 *aFilterIndex)
+{
+ LOG ("GFilePicker::GetFilterIndex");
+
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP GFilePicker::SetFilterIndex(PRInt32 aFilterIndex)
+{
+ LOG ("GFilePicker::SetFilterIndex index=%d", aFilterIndex);
+
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute nsILocalFile displayDirectory; */
+NS_IMETHODIMP GFilePicker::GetDisplayDirectory(nsILocalFile **aDisplayDirectory)
+{
+ NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE);
+
+ LOG ("GFilePicker::GetDisplayDirectory");
+
+ char *dir = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (mDialog));
+
+ if (dir != NULL)
+ {
+ nsCOMPtr<nsILocalFile> file = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID);
+ file->InitWithNativePath (nsCString (dir));
+ NS_IF_ADDREF (*aDisplayDirectory = file);
+
+ g_free (dir);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP GFilePicker::SetDisplayDirectory(nsILocalFile *aDisplayDirectory)
+{
+ NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE);
+
+ nsCString dir;
+ aDisplayDirectory->GetNativePath (dir);
+
+ LOG ("GFilePicker::SetDisplayDirectory to %s", dir.get());
+
+ if (mDefaultString.Length() && mMode != nsIFilePicker::modeSave)
+ {
+ nsCString defaultString;
+ NS_UTF16ToCString (mDefaultString, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM,
+ defaultString);
+
+ char *filename = g_build_filename (dir.get(), defaultString.get(), (char *) NULL);
+ LOG ("Setting filename to %s", filename);
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (mDialog), filename);
+ g_free (filename);
+ }
+ else
+ {
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (mDialog),
+ dir.get());
+ }
+
+ return NS_OK;
+}
+
+/* readonly attribute nsILocalFile file; */
+NS_IMETHODIMP GFilePicker::GetFile(nsILocalFile **aFile)
+{
+ NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE);
+
+ char *filename;
+
+ LOG ("GFilePicker::GetFile");
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (mDialog));
+
+ if (filename != NULL)
+ {
+ nsCOMPtr<nsILocalFile> file = do_CreateInstance (NS_LOCAL_FILE_CONTRACTID);
+ file->InitWithNativePath (nsCString (filename));
+ NS_IF_ADDREF (*aFile = file);
+
+ g_free (filename);
+ }
+
+ return NS_OK;
+}
+
+/* readonly attribute nsIFileURL fileURL; */
+NS_IMETHODIMP GFilePicker::GetFileURL(nsIFileURL **aFileURL)
+{
+ NS_ENSURE_TRUE (mDialog, NS_ERROR_FAILURE);
+
+ LOG ("GFilePicker::GetFileURL");
+
+ nsCOMPtr<nsILocalFile> file;
+ GetFile (getter_AddRefs(file));
+ NS_ENSURE_TRUE (file, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIFileURL> fileURL = do_CreateInstance (NS_STANDARDURL_CONTRACTID);
+ fileURL->SetFile(file);
+ NS_IF_ADDREF(*aFileURL = fileURL);
+
+ return NS_OK;
+}
+
+/* readonly attribute nsISimpleEnumerator files; */
+NS_IMETHODIMP GFilePicker::GetFiles(nsISimpleEnumerator * *aFiles)
+{
+ // Not sure if we need to implement it at all, it's used nowhere
+ // in mozilla, but I guess a javascript might call it?
+
+ LOG ("GFilePicker::GetFiles");
+
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* short show (); */
+NS_IMETHODIMP GFilePicker::Show(PRInt16 *_retval)
+{
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ AutoWindowModalState (mParent);
+ mParent = nsnull;
+
+ LOG ("GFilePicker::Show");
+
+ gtk_window_set_modal (GTK_WINDOW (mDialog), TRUE);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (mDialog), FALSE);
+
+ /* If there's just the "ALL" filter, it's no use showing the filters! */
+ GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (mDialog));
+ if (g_slist_length (filters) == 1)
+ {
+ GtkFileFilter *filter = GTK_FILE_FILTER (filters->data);
+ const char *name = gtk_file_filter_get_name (filter);
+
+ if (!name || strcmp (name, _("All files")) == 0)
+ {
+ gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (mDialog),
+ filter);
+ }
+ }
+ g_slist_free (filters);
+
+ gtk_widget_show (GTK_WIDGET (mDialog));
+
+ int response;
+ char *filename = NULL;
+
+ do
+ {
+ response = gtk_dialog_run (GTK_DIALOG (mDialog));
+
+ g_free (filename);
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (mDialog));
+
+ LOG ("GFilePicker::Show response=%d, filename=%s", response, filename);
+ }
+ while (response == GTK_RESPONSE_ACCEPT &&
+ mMode == nsIFilePicker::modeSave &&
+ !ephy_gui_check_location_writable (GTK_WIDGET (mDialog), filename));
+
+ gtk_widget_hide (GTK_WIDGET (mDialog));
+
+ if (response == GTK_RESPONSE_ACCEPT && filename != NULL)
+ {
+ *_retval = nsIFilePicker::returnOK;
+ }
+ else
+ {
+ *_retval = nsIFilePicker::returnCancel;
+ }
+
+ g_free (filename);
+
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/FilePicker.h b/embed/xulrunner/components/FilePicker.h
new file mode 100644
index 000000000..fa63c56b1
--- /dev/null
+++ b/embed/xulrunner/components/FilePicker.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2001 Philip Langdale
+ * Copyright © 2003 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_FILEPICKER_H
+#define EPHY_FILEPICKER_H
+
+#include <nsIFilePicker.h>
+
+class nsIDOMWindow;
+
+#include "ephy-file-chooser.h"
+
+#define G_FILEPICKER_CID \
+{ /* 3636dc79-0b42-4bad-8a3f-ae15d3671d17 */ \
+ 0x3636dc79, \
+ 0x0b42, \
+ 0x4bad, \
+ {0x8a, 0x3f, 0xae, 0x15, 0xd3, 0x67, 0x1d, 0x17} \
+}
+
+#define G_FILEPICKER_CONTRACTID "@mozilla.org/filepicker;1"
+#define G_FILEPICKER_CLASSNAME "Epiphany File Picker Implementation"
+
+class nsIFactory;
+
+extern nsresult NS_NewFilePickerFactory(nsIFactory** aFactory);
+
+class GFilePicker : public nsIFilePicker
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIFILEPICKER
+
+ GFilePicker();
+ virtual ~GFilePicker();
+
+private:
+ EphyFileChooser *mDialog;
+ PRInt16 mMode;
+ nsString mDefaultString;
+ nsCOMPtr<nsIDOMWindow> mParent;
+};
+
+#endif
diff --git a/embed/xulrunner/components/GeckoCookiePromptService.cpp b/embed/xulrunner/components/GeckoCookiePromptService.cpp
new file mode 100644
index 000000000..4fc7c21a6
--- /dev/null
+++ b/embed/xulrunner/components/GeckoCookiePromptService.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2003 Tommi Komulainen <tommi.komulainen@iki.fi>
+ * Copyright © 2004, 2007 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <gtk/gtkbox.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkwindow.h>
+
+#include <nsStringGlue.h>
+
+#include "ephy-debug.h"
+#include "ephy-gui.h"
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+
+#include "GeckoCookiePromptService.h"
+
+NS_IMPL_ISUPPORTS1 (GeckoCookiePromptService, nsICookiePromptService)
+
+GeckoCookiePromptService::GeckoCookiePromptService()
+{
+ LOG ("GeckoCookiePromptService ctor [%p]", this);
+}
+
+GeckoCookiePromptService::~GeckoCookiePromptService()
+{
+ LOG ("GeckoCookiePromptService dtor [%p]", this);
+}
+
+/* boolean cookieDialog (in nsIDOMWindow parent, in nsICookie cookie, in ACString hostname, in long cookiesFromHost, in boolean changingCookie, inout boolean checkValue); */
+NS_IMETHODIMP
+GeckoCookiePromptService::CookieDialog (nsIDOMWindow *aParent,
+ nsICookie *aCookie,
+ const nsACString &aHostname,
+ PRInt32 aCookiesFromHost,
+ PRBool aChangingCookie,
+ PRBool *_checkValue,
+ PRBool *_retval)
+{
+ NS_ENSURE_ARG (aParent);
+ NS_ENSURE_ARG (aCookie);
+ NS_ENSURE_ARG_POINTER (_checkValue);
+ NS_ENSURE_ARG_POINTER (_retval);
+
+ // TODO short-circuit and accept session cookies as per preference
+ // TODO until mozilla starts supporting it natively?
+
+ GtkWidget *parent = EphyUtils::FindGtkParent (aParent);
+ NS_ENSURE_TRUE(parent, NS_ERROR_INVALID_POINTER);
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) {
+ return rv;
+ }
+
+ AutoWindowModalState modalState (aParent);
+
+ nsCString host(aHostname);
+
+ GtkWidget *dialog = gtk_message_dialog_new
+ (GTK_WINDOW (parent),
+ GTK_DIALOG_MODAL /* FIXME mozilla sucks! */,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("Accept cookie from %s?"),
+ host.get());
+ GtkWindow *window = GTK_WINDOW (dialog);
+ GtkDialog *gdialog = GTK_DIALOG (dialog);
+ GtkMessageDialog *message_dialog = GTK_MESSAGE_DIALOG (dialog);
+
+ gtk_window_set_icon_name (window, "web-browser");
+ gtk_window_set_title (window, _("Accept Cookie?"));
+
+ if (aChangingCookie) {
+ gtk_message_dialog_format_secondary_text
+ (message_dialog,
+ _("The site wants to modify an existing cookie."));
+ } else if (aCookiesFromHost == 0) {
+ gtk_message_dialog_format_secondary_text
+ (message_dialog,
+ _("The site wants to set a cookie."));
+ } else if (aCookiesFromHost == 1) {
+ gtk_message_dialog_format_secondary_text
+ (message_dialog,
+ _("The site wants to set a second cookie."));
+ } else {
+ char *num_text = g_strdup_printf
+ (ngettext ("You already have %d cookie from this site.",
+ "You already have %d cookies from this site.",
+ aCookiesFromHost),
+ aCookiesFromHost);
+
+ gtk_message_dialog_format_secondary_text
+ (message_dialog,
+ "The site %s wants to set another cookie. %s",
+ host.get(), num_text);
+ g_free (num_text);
+ }
+
+ GtkWidget *checkbutton;
+ checkbutton = gtk_check_button_new_with_mnemonic
+ (_("Apply this _decision to all cookies from this site"));
+ gtk_widget_show (checkbutton);
+ gtk_box_pack_start (GTK_BOX (ephy_gui_message_dialog_get_content_box (dialog)),
+ checkbutton, FALSE, FALSE, 0);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), *_checkValue);
+
+ gtk_dialog_add_button (gdialog,
+ _("_Reject"), GTK_RESPONSE_REJECT);
+ gtk_dialog_add_button (gdialog,
+ _("_Accept"), GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_default_response (gdialog, GTK_RESPONSE_ACCEPT);
+
+ int response = gtk_dialog_run (gdialog);
+
+ if (response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_REJECT) {
+ *_retval = (response == GTK_RESPONSE_ACCEPT);
+ *_checkValue = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton));
+ } else {
+ /* if the dialog was closed, but no button was pressed,
+ * consider it as 'Reject' but ignore the checkbutton
+ */
+ *_retval = PR_FALSE;
+ *_checkValue = PR_FALSE;
+ }
+
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/GeckoCookiePromptService.h b/embed/xulrunner/components/GeckoCookiePromptService.h
new file mode 100644
index 000000000..7092a2982
--- /dev/null
+++ b/embed/xulrunner/components/GeckoCookiePromptService.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2003 Tommi Komulainen <tommi.komulainen@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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 COOKIEPROMPTSERVICE_H
+#define COOKIEPROMPTSERVICE_H
+
+#include <nsICookiePromptService.h>
+
+/* 50766a18-0b34-41d9-8f6c-4612200e6556 */
+#define EPHY_COOKIEPROMPTSERVICE_CID \
+ { 0x50766a18, 0x0b34, 0x41d9, { 0x8f, 0x6c, 0x46, 0x12, 0x20, 0x0e, 0x65, 0x56 } }
+
+#define EPHY_COOKIEPROMPTSERVICE_CLASSNAME "Epiphany Cookie Prompt Service"
+#define EPHY_COOKIEPROMPTSERVICE_CONTRACTID "@mozilla.org/embedcomp/cookieprompt-service;1"
+
+class GeckoCookiePromptService : public nsICookiePromptService {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICOOKIEPROMPTSERVICE
+
+ GeckoCookiePromptService();
+
+ private:
+ ~GeckoCookiePromptService();
+};
+
+#endif /* COOKIEPROMPTSERVICE_H */
diff --git a/embed/xulrunner/components/GeckoFormSigningDialog.cpp b/embed/xulrunner/components/GeckoFormSigningDialog.cpp
new file mode 100644
index 000000000..55b9d0d37
--- /dev/null
+++ b/embed/xulrunner/components/GeckoFormSigningDialog.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2006 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade-xml.h>
+
+#include <nsStringGlue.h>
+
+#include <nsCOMPtr.h>
+#include <nsIDOMWindow.h>
+#include <nsIInterfaceRequestor.h>
+#include <nsIInterfaceRequestorUtils.h>
+
+#include "eel-gconf-extensions.h"
+#include "ephy-debug.h"
+#include "ephy-embed-shell.h"
+#include "ephy-file-helpers.h"
+#include "ephy-prefs.h"
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+
+#include "GeckoFormSigningDialog.h"
+
+#define LITERAL(s) reinterpret_cast<const nsAString::char_type*>(NS_L(s))
+
+NS_IMPL_ISUPPORTS1 (GeckoFormSigningDialog,
+ nsIFormSigningDialog)
+
+GeckoFormSigningDialog::GeckoFormSigningDialog()
+{
+ LOG ("GeckoFormSigningDialog ctor [%p]", this);
+}
+
+GeckoFormSigningDialog::~GeckoFormSigningDialog()
+{
+ LOG ("GeckoFormSigningDialog dtor [%p]", this);
+}
+
+/* nsIFormSigningDialog implementation */
+
+/* boolean confirmSignText (in nsIInterfaceRequestor ctxt,
+ in AString host,
+ in AString signText,
+ [array, size_is (count)] in wstring certNickList,
+ [array, size_is (count)] in wstring certDetailsList,
+ in PRUint32 count,
+ out PRInt32 selectedIndex,
+ out AString password); */
+NS_IMETHODIMP
+GeckoFormSigningDialog::ConfirmSignText (nsIInterfaceRequestor *ctx,
+ const nsAString & host,
+ const nsAString & signText,
+ const PRUnichar **certNickList,
+ const PRUnichar **certDetailsList,
+ PRUint32 count,
+ PRInt32 *selectedIndex,
+ nsAString &_password,
+ PRBool *_cancelled)
+{
+ /* FIXME: limit |signText| to a sensitlbe length (maybe 100k)? */
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
+ if (!parent) {
+ parent = EphyJSUtils::GetDOMWindowFromCallContext ();
+ g_print ("Fallback window %p\n", (void*)parent.get());
+ }
+ GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
+
+ AutoWindowModalState modalState (parent);
+
+ GladeXML *gxml = glade_xml_new (ephy_file ("form-signing-dialog.glade"),
+ "form_signing_dialog", NULL);
+ g_return_val_if_fail (gxml, NS_ERROR_FAILURE);
+
+ GtkWidget *dialog = glade_xml_get_widget (gxml, "form_signing_dialog");
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (gparent));
+
+ GtkLabel *primary_label = GTK_LABEL (glade_xml_get_widget (gxml, "primary_label"));
+ char *primary = g_strdup_printf (_("The web site “%s” requests that you sign the following text:"),
+ NS_ConvertUTF16toUTF8 (host).get ());
+ gtk_label_set_text (primary_label, primary);
+ g_free (primary);
+
+ GtkTextView *textview = GTK_TEXT_VIEW (glade_xml_get_widget (gxml, "textview"));
+ NS_ConvertUTF16toUTF8 text (signText);
+ gtk_text_buffer_set_text (gtk_text_view_get_buffer (textview),
+ text.get (), text.Length ());
+
+ GtkTable *table = GTK_TABLE (glade_xml_get_widget (gxml, "table"));
+ GtkComboBox *combo = GTK_COMBO_BOX (gtk_combo_box_new_text ());
+ for (PRUint32 i = 0; i < count; ++i) {
+ gtk_combo_box_append_text (combo, NS_ConvertUTF16toUTF8 (certNickList[i]).get ());
+ }
+
+ gtk_combo_box_set_active (combo, 0);
+ gtk_table_attach (table, GTK_WIDGET (combo), 1, 2, 0, 1,
+ GtkAttachOptions (0), GtkAttachOptions (0), 0, 0);
+ gtk_widget_show (GTK_WIDGET (combo));
+
+ /* FIXME: Add "View Certificate" button */
+
+ GtkEntry *password_entry = GTK_ENTRY (glade_xml_get_widget (gxml, "password_entry"));
+
+ GtkWidget *button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("_Sign text"),
+ GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
+ gtk_widget_grab_focus (button);
+
+ /* FIXME: make Sign insensitive for some time (proportional to text length, with maximum?) */
+
+ g_object_unref (gxml);
+
+ int response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ *_cancelled = response != GTK_RESPONSE_ACCEPT;
+
+ if (response == GTK_RESPONSE_ACCEPT) {
+ _password = NS_ConvertUTF8toUTF16 (gtk_entry_get_text (password_entry));
+ *selectedIndex = gtk_combo_box_get_active (combo);
+ }
+
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/GeckoFormSigningDialog.h b/embed/xulrunner/components/GeckoFormSigningDialog.h
new file mode 100644
index 000000000..a4438e9d1
--- /dev/null
+++ b/embed/xulrunner/components/GeckoFormSigningDialog.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2006 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef GECKO_FORMSIGNINGDIALOGS_H
+#define GECKO_FORMSIGNINGDIALOGS_H
+
+#include <nsIFormSigningDialog.h>
+
+/* 4e42a43e-fbc5-40cc-bcbb-8cbc4e2101eb */
+#define GECKO_FORMSIGNINGDIALOGS_CID \
+{ 0x4e42a43e, 0xfbc5, 0x40cc, { 0xbc, 0xbb, 0x8c, 0xbc, 0x4e, 0x21, 0x01, 0xeb } }
+
+#define GECKO_FORMSIGNINGDIALOGS_CLASSNAME "Gecko Form Signing Dialogs"
+
+class GeckoFormSigningDialog : public nsIFormSigningDialog
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIFORMSIGNINGDIALOG
+
+ GeckoFormSigningDialog();
+ ~GeckoFormSigningDialog();
+};
+
+#endif /* GECKO_FORMSIGNINGDIALOGS_H */
diff --git a/embed/xulrunner/components/GeckoPrintService.cpp b/embed/xulrunner/components/GeckoPrintService.cpp
new file mode 100644
index 000000000..b1d34a960
--- /dev/null
+++ b/embed/xulrunner/components/GeckoPrintService.cpp
@@ -0,0 +1,713 @@
+/*
+ * Copyright © 2006, 2007 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkprintunixdialog.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkwindow.h>
+#include <glade/glade-xml.h>
+
+#include <nsStringGlue.h>
+
+#include <nsCOMPtr.h>
+#include <nsIDOMWindow.h>
+#include <nsIDOMWindowInternal.h>
+
+#include "eel-gconf-extensions.h"
+#include "ephy-debug.h"
+#include "ephy-embed-shell.h"
+#include "ephy-file-helpers.h"
+#include "ephy-gui.h"
+#include "ephy-prefs.h"
+#include "ephy-stock-icons.h"
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+#include "GeckoPrintSession.h"
+
+#include "GeckoPrintService.h"
+
+/* Some printing keys */
+
+#define CONF_PRINT_BG_COLORS "/apps/epiphany/dialogs/print_background_colors"
+#define CONF_PRINT_BG_IMAGES "/apps/epiphany/dialogs/print_background_images"
+#define CONF_PRINT_COLOR "/apps/epiphany/dialogs/print_color"
+#define CONF_PRINT_DATE "/apps/epiphany/dialogs/print_date"
+#define CONF_PRINT_PAGE_NUMBERS "/apps/epiphany/dialogs/print_page_numbers"
+#define CONF_PRINT_PAGE_TITLE "/apps/epiphany/dialogs/print_page_title"
+#define CONF_PRINT_PAGE_URL "/apps/epiphany/dialogs/print_page_url"
+
+#define LITERAL(s) reinterpret_cast<const nsAString::char_type*>(NS_L(s))
+
+/* From nsIDeviceContext.h */
+#define NS_ERROR_GFX_PRINTER_BASE (1) /* adjustable :-) */
+#define NS_ERROR_GFX_PRINTER_ACCESS_DENIED \
+ NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GFX,NS_ERROR_GFX_PRINTER_BASE+5)
+#define NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND \
+ NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GFX,NS_ERROR_GFX_PRINTER_BASE+4)
+
+NS_IMPL_ISUPPORTS1 (GeckoPrintService,
+ nsIPrintingPromptService)
+
+GeckoPrintService::GeckoPrintService()
+{
+ LOG ("GeckoPrintService ctor [%p]", this);
+}
+
+GeckoPrintService::~GeckoPrintService()
+{
+ LOG ("GeckoPrintService dtor [%p]", this);
+}
+
+/* nsIPrintingPromptService implementation */
+
+/* void showPrintDialog (in nsIDOMWindow parent,
+ in nsIWebBrowserPrint webBrowserPrint,
+ in nsIPrintSettings printSettings); */
+NS_IMETHODIMP
+GeckoPrintService::ShowPrintDialog (nsIDOMWindow *aParent,
+ nsIWebBrowserPrint *aWebBrowserPrint,
+ nsIPrintSettings *aSettings)
+{
+ /* Locked down? */
+ if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_PRINTING)) {
+ return NS_ERROR_GFX_PRINTER_ACCESS_DENIED;
+ }
+
+ GeckoPrintSession *session = GeckoPrintSession::FromSettings (aSettings);
+ NS_ENSURE_TRUE (session, NS_ERROR_INVALID_POINTER);
+
+ /* Print settings changes disallowed, just translate the settings */
+ if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_PRINT_SETUP)) {
+ return PrintUnattended (aParent, aSettings);
+ }
+
+ /* Not locked down, show the dialogue */
+
+ nsresult rv;
+#if 0
+ PRBool haveSelection = PR_FALSE;
+ rv = aSettings->GetPrintOptions(nsIPrintSettings::kEnableSelectionRB, &haveSelection);
+ NS_ENSURE_SUCCESS (rv, rv);
+#endif
+
+ PRInt16 frameUI = nsIPrintSettings::kFrameEnableAll;
+ rv = aSettings->GetHowToEnableFrameUI (&frameUI);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ GtkWidget *parent = EphyUtils::FindGtkParent (aParent);
+ NS_ENSURE_TRUE(parent, NS_ERROR_INVALID_POINTER);
+
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) {
+ return rv;
+ }
+
+ AutoWindowModalState modalState (aParent);
+
+ EphyEmbedShell *shell = ephy_embed_shell_get_default ();
+
+ GladeXML *xml = glade_xml_new (ephy_file ("print.glade"),
+ "print_dialog_custom_tab", NULL);
+ if (!xml) {
+ return NS_ERROR_FAILURE;
+ }
+
+ /* Build the custom tab */
+ GtkWidget *custom_tab = glade_xml_get_widget (xml, "custom_tab_container");
+ ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_bg_colors_checkbutton"), CONF_PRINT_BG_COLORS);
+ ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_bg_images_checkbutton"), CONF_PRINT_BG_IMAGES);
+ ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_date_checkbutton"), CONF_PRINT_DATE);
+ ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_page_numbers_checkbutton"), CONF_PRINT_PAGE_NUMBERS);
+ ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_page_title_checkbutton"), CONF_PRINT_PAGE_TITLE);
+ ephy_gui_connect_checkbutton_to_gconf (glade_xml_get_widget (xml, "print_page_url_checkbutton"), CONF_PRINT_PAGE_URL);
+
+ GtkWidget *frame_box = glade_xml_get_widget (xml, "frame_box");
+ GtkWidget *print_frames_normal = glade_xml_get_widget (xml, "print_frames_normal");
+ GtkWidget *print_frames_selected = glade_xml_get_widget (xml, "print_frames_selected");
+ GtkWidget *print_frames_separately = glade_xml_get_widget (xml, "print_frames_separately");
+
+ /* FIXME: store/load from pref */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (print_frames_normal), TRUE);
+
+ if (frameUI == nsIPrintSettings::kFrameEnableAll) {
+ /* Allow all frame options */
+ gtk_widget_set_sensitive (frame_box, TRUE);
+ } else if (frameUI == nsIPrintSettings::kFrameEnableAsIsAndEach) {
+ /* Allow all except "selected frame" */
+ gtk_widget_set_sensitive (frame_box, TRUE);
+ gtk_widget_set_sensitive (print_frames_selected, FALSE);
+ /* Preselect this one, since the default above only prints _one page_ ! */
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (print_frames_separately), TRUE);
+ }
+
+ /* FIXME: this sucks! find some way to do all of this async! */
+ GtkWidget *dialog = gtk_print_unix_dialog_new (NULL /* FIXME title */,
+ GTK_WINDOW (parent));
+ GtkPrintUnixDialog *print_dialog = GTK_PRINT_UNIX_DIALOG (dialog);
+
+ GtkPrintCapabilities capabilities =
+ GtkPrintCapabilities (GTK_PRINT_CAPABILITY_PAGE_SET |
+ GTK_PRINT_CAPABILITY_COPIES |
+ GTK_PRINT_CAPABILITY_COLLATE |
+ GTK_PRINT_CAPABILITY_REVERSE |
+ GTK_PRINT_CAPABILITY_SCALE |
+ GTK_PRINT_CAPABILITY_GENERATE_PS |
+ GTK_PRINT_CAPABILITY_GENERATE_PDF);
+ gtk_print_unix_dialog_set_manual_capabilities (print_dialog, capabilities);
+
+ gtk_print_unix_dialog_set_page_setup (print_dialog,
+ ephy_embed_shell_get_page_setup (shell));
+ gtk_print_unix_dialog_set_settings (print_dialog,
+ ephy_embed_shell_get_print_settings (shell));
+
+ /* Remove custom tab from its dummy window and put it in the print dialogue */
+ g_object_ref_sink (custom_tab);
+ gtk_container_remove (GTK_CONTAINER (custom_tab->parent), custom_tab);
+ gtk_print_unix_dialog_add_custom_tab (print_dialog, custom_tab,
+ gtk_label_new (_("Options"))); /* FIXME better name! */
+ g_object_unref (custom_tab);
+ g_object_unref (xml);
+
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
+
+ int response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_hide (dialog);
+
+ GtkPrinter *printer = gtk_print_unix_dialog_get_selected_printer (print_dialog);
+
+ if (response != GTK_RESPONSE_OK || !printer) {
+ gtk_widget_destroy (dialog);
+
+ return NS_ERROR_ABORT;
+ }
+
+ PRInt16 printFrames = nsIPrintSettings::kNoFrames;
+ if (frameUI != nsIPrintSettings::kFrameEnableNone) {
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print_frames_normal))) {
+ printFrames = nsIPrintSettings::kFramesAsIs;
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print_frames_selected))) {
+ printFrames = nsIPrintSettings::kSelectedFrame;
+ } if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (print_frames_separately))) {
+ printFrames = nsIPrintSettings::kEachFrameSep;
+ }
+ }
+
+ GtkPageSetup *pageSetup = gtk_print_unix_dialog_get_page_setup (print_dialog); /* no reference owned */
+ ephy_embed_shell_set_page_setup (shell, pageSetup);
+
+ GtkPrintSettings *settings = gtk_print_unix_dialog_get_settings (print_dialog);
+ ephy_embed_shell_set_print_settings (shell, settings);
+
+ /* We copy the setup and settings so we can modify them to unset
+ * options handled by gecko.
+ */
+ GtkPageSetup *pageSetupCopy = gtk_page_setup_copy (pageSetup);
+ pageSetup = pageSetupCopy;
+
+ GtkPrintSettings *settingsCopy = gtk_print_settings_copy (settings);
+ g_object_unref (settings);
+ settings = settingsCopy;
+
+ rv = session->SetSettings (aSettings, settings, pageSetup, printer);
+
+ /* Now translate the settings to nsIPrintSettings */
+ if (NS_SUCCEEDED (rv)) {
+ nsCString sourceFile;
+ session->GetSourceFile (sourceFile);
+ if (!sourceFile.IsEmpty ()) {
+ rv = TranslateSettings (settings, pageSetup, printer, sourceFile, printFrames, PR_TRUE, aSettings);
+ } else {
+ rv = NS_ERROR_FAILURE;
+ }
+ }
+
+ gtk_widget_destroy (dialog);
+
+ g_object_unref (settings);
+ g_object_unref (pageSetup);
+
+ return rv;
+}
+
+/* void showProgress (in nsIDOMWindow parent,
+ in nsIWebBrowserPrint webBrowserPrint,
+ in nsIPrintSettings printSettings,
+ in nsIObserver openDialogObserver,
+ in boolean isForPrinting,
+ out nsIWebProgressListener webProgressListener,
+ out nsIPrintProgressParams printProgressParams,
+ out boolean notifyOnOpen); */
+NS_IMETHODIMP
+GeckoPrintService::ShowProgress (nsIDOMWindow *aParent,
+ nsIWebBrowserPrint *aWebBrowserPrint,
+ nsIPrintSettings *aPrintSettings,
+ nsIObserver *aOpenDialogObserver,
+ PRBool aIsForPrinting,
+ nsIWebProgressListener **_webProgressListener,
+ nsIPrintProgressParams **_printProgressParams,
+ PRBool *_notifyOnOpen)
+{
+ /* Print preview */
+ if (!aIsForPrinting) {
+ return NS_OK;
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsIDOMWindowInternal> domWin (do_QueryInterface (aParent, &rv));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIPrintSession> session;
+ rv = aPrintSettings->GetPrintSession (getter_AddRefs (session));
+ NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && session, nsnull);
+
+ nsCOMPtr<nsIPrintProgress> progress (do_QueryInterface (session, &rv));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ /* Our print session implements those interfaces */
+ rv = CallQueryInterface (session, _webProgressListener);
+ rv |= CallQueryInterface (session, _printProgressParams);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ /* Setting this to PR_FALSE will make gecko immediately start printing
+ * when we return from this function.
+ * If we set this to PR_TRUE, we need to call aOpenDialogObserver::Observe
+ * (topic, subject and data don't matter) when we're ready for printing.
+ */
+ *_notifyOnOpen = PR_FALSE;
+
+ return progress->OpenProgressDialog (domWin, nsnull, nsnull, aOpenDialogObserver, _notifyOnOpen);
+}
+
+/* void showPageSetup (in nsIDOMWindow parent,
+ in nsIPrintSettings printSettings,
+ in nsIObserver aObs); */
+NS_IMETHODIMP GeckoPrintService::ShowPageSetup (nsIDOMWindow *aParent,
+ nsIPrintSettings *aPrintSettings,
+ nsIObserver *aObserver)
+{
+ /* This function is never called from gecko code */
+#if 0
+ /* Locked down? */
+ if (eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_PRINTING) ||
+ eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_PRINT_SETUP)) {
+ return NS_ERROR_ABORT;
+ }
+
+ GtkWidget *parent = EphyUtils::FindGtkParent (aParent);
+ NS_ENSURE_TRUE(parent, NS_ERROR_INVALID_POINTER);
+
+ AutoJSContextStack stack;
+ nsresult rv = stack.Init ();
+ if (NS_FAILED (rv)) {
+ return rv;
+ }
+
+ AutoWindowModalState modalState (aParent);
+
+ EphyEmbedShell *shell = ephy_embed_shell_get_default ();
+ GtkPageSetup *new_setup =
+ gtk_print_run_page_setup_dialog (GTK_WINDOW (parent),
+ ephy_embed_shell_get_page_setup (shell),
+ ephy_embed_shell_get_print_settings (shell));
+ if (new_setup) {
+ ephy_embed_shell_set_page_setup (shell, new_setup);
+ g_object_unref (new_setup);
+ }
+
+ /* FIXME do we need to notify aObserver somehow? */
+ return NS_OK;
+#endif
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void showPrinterProperties (in nsIDOMWindow parent,
+ in wstring printerName,
+ in nsIPrintSettings printSettings); */
+NS_IMETHODIMP
+GeckoPrintService::ShowPrinterProperties (nsIDOMWindow *aParent,
+ const PRUnichar *aPrinterName,
+ nsIPrintSettings *aPrintSettings)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* Private methods */
+
+#if 0
+typedef struct
+{
+ GMainLoop *mainLoop;
+ GtkPrinter *mPrinter;
+ guint timeout;
+ int response;
+ guint cancelled : 1;
+} FindPrinterData;
+
+static void
+FreeFindPrinterData (FindPrinterData *data)
+{
+ if (data->printer) {
+ g_object_unref (data->printer);
+ }
+}
+
+static void
+DialogResponseCallback (GtkWidget *aDialog,
+ int aResponse,
+ FindPrinterData *data)
+{
+ data->response = aResponse;
+ g_main_loop_quit (data->mainloop);
+}
+
+static void
+TimeoutCallback (FindPrinterData *data)
+{
+ data->cancelled = TRUE;
+ g_main_loop_quit (data->mainLoop);
+ data->mainLoop = NULL;
+ return FALSE;
+}
+
+static gboolean
+PrinterEnumerateCallback (GtkPrinter *aPrinter,
+ FindPrinterData *data)
+{
+ if (data->cancelled)
+ return TRUE;
+
+ if ((data->printerName &&
+ strcmp (data->printerName, gtk_printer_get_name (aPrinter)) == 0) ||
+ (!data->printerName &&
+ gtk_printer_is_default (aPrinter))) {
+ data->printer = g_object_ref (aPrinter);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+nsresult
+GeckoPrintService::PrintUnattended (nsIDOMWindow *aParent,
+ nsIPrintSettings *aPrintSettings)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+#if 0
+ GtkWidget *parent = EphyUtils::FindGtkParent (aParent);
+ NS_ENSURE_TRUE(parent, NS_ERROR_INVALID_POINTER);
+
+ PRBool isCalledFromScript = EphyJSUtils::IsCalledFromScript ();
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) {
+ return rv;
+ }
+
+ AutoWindowModalState modalState (aParent);
+
+ EphyEmbedShell *shell = ephy_embed_shell_get_default ();
+ GtkPrintSettings *settings = ephy_embed_shell_get_print_settings (shell);
+ NS_ENSURE_TRUE (settings, NS_ERROR_FAILURE);
+
+ const char *printer = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_PRINTER);
+#if 0
+ if (!printer || !printer[0]) {
+ return NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
+ }
+#endif
+ /* We need to find the printer, so we need to run a mainloop.
+ * If called from a script, give the user a way to cancel the print;
+ * otherwise we'll just show a generic progress message.
+ */
+ GtkWidget *dialog;
+ if (isCalledFromScript) {
+ dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
+ GtkDialogFlags (0),
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ "%s", _("Print this page?"));
+ gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_PRINT,
+ GTK_RESPONSE_ACCEPT);
+ } else {
+ dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
+ GtkDialogFlags (0),
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ "%s", _("Preparing to print"));
+ }
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+
+ FindPrinterData *data = g_new0 (PrinterData, 1);
+ data->dialog = dialog;
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (DialogResponseCallback), data);
+
+ /* Don't run forever */
+ data->timeoutId = g_timeout_add (PRINTER_ENUMERATE_TIMEOUT,
+ (GSourceFunc) EnumerateTimoutCallback,
+ data);
+ /* Enumerate printers until we find our printer */
+ gtk_enumerate_printers ((GtkPrinterFunc) PrinterEnumerateCallback,
+ data,
+ (GDestroyNotify) EnumerateDestroyCallback, FALSE);
+
+ /* Now run the mainloop */
+ int response = gtk_dialog_run (GTK_DIALOG (dialog));
+ Printer
+ gtk_widget_destroy (dialog);
+
+ if (response != GTK_RESPONSE_ACCEPT) {
+ return NS_ERROR_ABORT;
+ }
+
+ nsCString sourceFile;
+ session->GetSourceFile (sourceFile);
+ if (!sourceFile.IsEmpty ()) {
+ rv = TranslateSettings (settings,
+ ephy_embed_shell_get_page_setup (shell),
+ sourceFile, PR_TRUE, aSettings);
+ } else {
+ rv = NS_ERROR_FAILURE;
+ }
+
+ return rv;
+ }
+#endif /* if 0 */
+}
+
+/* Static methods */
+
+/* static */ nsresult
+GeckoPrintService::TranslateSettings (GtkPrintSettings *aGtkSettings,
+ GtkPageSetup *aPageSetup,
+ GtkPrinter *aPrinter,
+ const nsACString &aSourceFile,
+ PRInt16 aPrintFrames,
+ PRBool aIsForPrinting,
+ nsIPrintSettings *aSettings)
+{
+ NS_ENSURE_ARG (aPrinter);
+ NS_ENSURE_ARG (aGtkSettings);
+ NS_ENSURE_ARG (aPageSetup);
+
+#if 0
+ /* Locked down? */
+ if (gtk_print_settings_get_print_to_file (aGtkSettings) &&
+ eel_gconf_get_boolean (CONF_LOCKDOWN_DISABLE_SAVE_TO_DISK)) {
+ return NS_ERROR_GFX_PRINTER_ACCESS_DENIED;
+ }
+#endif
+
+ GtkPrintCapabilities capabilities = gtk_printer_get_capabilities (aPrinter);
+
+ /* Initialisation */
+ aSettings->SetIsInitializedFromPrinter (PR_FALSE); /* FIXME: PR_TRUE? */
+ aSettings->SetIsInitializedFromPrefs (PR_FALSE); /* FIXME: PR_TRUE? */
+ aSettings->SetPrintSilent (PR_FALSE);
+ aSettings->SetShowPrintProgress (PR_TRUE);
+
+ /* We always print PS to a file and then hand that off to gtk-print */
+ aSettings->SetPrinterName (LITERAL ("PostScript/default"));
+
+ if (aIsForPrinting) {
+ aSettings->SetPrintToFile (PR_TRUE);
+
+ nsString sourceFile;
+ NS_CStringToUTF16 (aSourceFile,
+ NS_CSTRING_ENCODING_NATIVE_FILESYSTEM,
+ sourceFile);
+
+ aSettings->SetToFileName (sourceFile.get ());
+ } else {
+ /* Otherwise mozilla will create the file nevertheless and
+ * fail since we haven't set a name!
+ */
+ aSettings->SetPrintToFile (PR_FALSE);
+ }
+
+ /* This is the time between printing each page, in ms.
+ * It 'gives the user more time to press cancel' !
+ * We don't want any of this nonsense, so set this to a low value,
+ * just enough to update the print dialogue.
+ */
+ aSettings->SetPrintPageDelay (50);
+
+ if (aIsForPrinting) {
+ NS_ENSURE_TRUE (aPrinter, NS_ERROR_FAILURE);
+
+ const char *format = gtk_print_settings_get (aGtkSettings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
+ if (!format)
+ format = "ps";
+
+ if (strcmp (format, "pdf") == 0 &&
+ gtk_printer_accepts_pdf (aPrinter)) {
+ aSettings->SetOutputFormat (nsIPrintSettings::kOutputFormatPDF);
+ } else if (strcmp (format, "ps") == 0 &&
+ gtk_printer_accepts_ps (aPrinter)) {
+ aSettings->SetOutputFormat (nsIPrintSettings::kOutputFormatPS);
+ } else {
+ g_warning ("Output format '%s' specified, but printer '%s' does not support it!",
+ format, gtk_printer_get_name (aPrinter));
+ return NS_ERROR_FAILURE;
+ }
+
+ int n_copies = gtk_print_settings_get_n_copies (aGtkSettings);
+ if (n_copies <= 0)
+ return NS_ERROR_FAILURE;
+ if (capabilities & GTK_PRINT_CAPABILITY_COPIES) {
+ aSettings->SetNumCopies (1);
+ } else {
+ /* We have to copy them ourself */
+ aSettings->SetNumCopies (n_copies);
+ gtk_print_settings_set_n_copies (aGtkSettings, 1);
+ }
+
+ gboolean reverse = gtk_print_settings_get_reverse (aGtkSettings);
+ if (capabilities & GTK_PRINT_CAPABILITY_REVERSE) {
+ aSettings->SetPrintReversed (PR_FALSE);
+ } else {
+ aSettings->SetPrintReversed (reverse);
+ gtk_print_settings_set_reverse (aGtkSettings, FALSE);
+ }
+
+ GtkPageSet pageSet = gtk_print_settings_get_page_set (aGtkSettings);
+ aSettings->SetPrintOptions (nsIPrintSettings::kPrintEvenPages,
+ pageSet != GTK_PAGE_SET_ODD);
+ aSettings->SetPrintOptions (nsIPrintSettings::kPrintEvenPages,
+ pageSet != GTK_PAGE_SET_EVEN);
+
+ GtkPrintPages printPages = gtk_print_settings_get_print_pages (aGtkSettings);
+ switch (printPages) {
+ case GTK_PRINT_PAGES_RANGES: {
+ int numRanges = 0;
+ GtkPageRange *pageRanges = gtk_print_settings_get_page_ranges (aGtkSettings, &numRanges);
+ if (numRanges > 0) {
+ /* FIXME: We can only support one range, ignore more ranges or raise error? */
+ aSettings->SetPrintRange (nsIPrintSettings::kRangeSpecifiedPageRange);
+ /* Gecko page numbers start at 1, while gtk page numbers start at 0 */
+ aSettings->SetStartPageRange (pageRanges[0].start + 1);
+ aSettings->SetEndPageRange (pageRanges[0].end + 1);
+
+ g_free (pageRanges);
+ break;
+ }
+ /* Fall-through to PAGES_ALL */
+ }
+ case GTK_PRINT_PAGES_CURRENT:
+ /* not supported, fall through */
+ case GTK_PRINT_PAGES_ALL:
+ aSettings->SetPrintRange (nsIPrintSettings::kRangeAllPages);
+ break;
+ /* FIXME: we need some custom ranges here, "Selection" and "Focused Frame" */
+ }
+ } else {
+ aSettings->SetPrintOptions (nsIPrintSettings::kPrintEvenPages, PR_TRUE);
+ aSettings->SetPrintOptions (nsIPrintSettings::kPrintEvenPages, PR_TRUE);
+ aSettings->SetPrintReversed (PR_FALSE);
+ aSettings->SetPrintRange (nsIPrintSettings::kRangeAllPages);
+ }
+
+ /* And clear those in the settings, so the printer doesn't try to apply them too */
+ gtk_print_settings_set_print_pages (aGtkSettings, GTK_PRINT_PAGES_ALL);
+ gtk_print_settings_set_page_ranges (aGtkSettings, NULL, 0);
+ gtk_print_settings_set_page_set (aGtkSettings, GTK_PAGE_SET_ALL);
+
+ switch (gtk_print_settings_get_orientation (aGtkSettings)) {
+ case GTK_PAGE_ORIENTATION_PORTRAIT:
+ case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT: /* not supported */
+ aSettings->SetOrientation (nsIPrintSettings::kPortraitOrientation);
+ break;
+ case GTK_PAGE_ORIENTATION_LANDSCAPE:
+ case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE: /* not supported */
+ aSettings->SetOrientation (nsIPrintSettings::kLandscapeOrientation);
+ break;
+ }
+
+ aSettings->SetPrintInColor (gtk_print_settings_get_use_color (aGtkSettings));
+
+ aSettings->SetPaperSizeUnit(nsIPrintSettings::kPaperSizeMillimeters);
+
+ GtkPaperSize *paperSize = gtk_page_setup_get_paper_size (aPageSetup);
+ if (!paperSize) {
+ return NS_ERROR_FAILURE;
+ }
+
+ aSettings->SetPaperSizeType (nsIPrintSettings::kPaperSizeDefined);
+ aSettings->SetPaperWidth (gtk_paper_size_get_width (paperSize, GTK_UNIT_MM));
+ aSettings->SetPaperHeight (gtk_paper_size_get_height (paperSize, GTK_UNIT_MM));
+ aSettings->SetPaperName (NS_ConvertUTF8toUTF16 (gtk_paper_size_get_name (paperSize)).get ());
+
+ /* Sucky mozilla wants margins in inch! */
+ aSettings->SetMarginTop (gtk_page_setup_get_top_margin (aPageSetup, GTK_UNIT_INCH));
+ aSettings->SetMarginBottom (gtk_page_setup_get_bottom_margin (aPageSetup, GTK_UNIT_INCH));
+ aSettings->SetMarginLeft (gtk_page_setup_get_left_margin (aPageSetup, GTK_UNIT_INCH));
+ aSettings->SetMarginRight (gtk_page_setup_get_right_margin (aPageSetup, GTK_UNIT_INCH));
+
+ aSettings->SetHeaderStrLeft (eel_gconf_get_boolean (CONF_PRINT_PAGE_TITLE) ? LITERAL ("&T") : LITERAL (""));
+ aSettings->SetHeaderStrCenter (LITERAL (""));
+ aSettings->SetHeaderStrRight (eel_gconf_get_boolean (CONF_PRINT_PAGE_URL) ? LITERAL ("&U") : LITERAL (""));
+ aSettings->SetFooterStrLeft (eel_gconf_get_boolean (CONF_PRINT_PAGE_NUMBERS) ? LITERAL ("&PT") : LITERAL (""));
+ aSettings->SetFooterStrCenter (LITERAL (""));
+ aSettings->SetFooterStrRight (eel_gconf_get_boolean (CONF_PRINT_DATE) ? LITERAL ("&D") : LITERAL (""));
+
+ aSettings->SetPrintFrameType (aPrintFrames);
+ aSettings->SetPrintFrameTypeUsage (nsIPrintSettings::kUseSettingWhenPossible);
+
+ /* FIXME: only if GTK_PRINT_CAPABILITY_SCALE is not set? */
+ aSettings->SetScaling (gtk_print_settings_get_scale (aGtkSettings) / 100.0);
+ gtk_print_settings_set_scale (aGtkSettings, 1.0);
+
+ aSettings->SetShrinkToFit (PR_FALSE); /* FIXME setting */
+
+ aSettings->SetPrintBGColors (eel_gconf_get_boolean (CONF_PRINT_BG_COLORS) != FALSE);
+ aSettings->SetPrintBGImages (eel_gconf_get_boolean (CONF_PRINT_BG_IMAGES) != FALSE);
+
+ /* aSettings->SetPlexName (LITERAL ("default")); */
+ /* aSettings->SetColorspace (LITERAL ("default")); */
+ /* aSettings->SetResolutionName (LITERAL ("default")); */
+ /* aSettings->SetDownloadFonts (PR_TRUE); */
+
+ /* Unset those setting that we can handle, so they don't get applied
+ * again for the print job.
+ */
+ /* gtk_print_settings_set_collate (aGtkSettings, FALSE); not yet */
+ /* FIXME: Unset the orientation for the print job? */
+ /* gtk_print_settings_set_orientation (aGtkSettings, GTK_PAGE_ORIENTATION_PORTRAIT); */
+ /* FIXME: unset output format -> "ps" ? */
+
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/GeckoPrintService.h b/embed/xulrunner/components/GeckoPrintService.h
new file mode 100644
index 000000000..c2e21cf3e
--- /dev/null
+++ b/embed/xulrunner/components/GeckoPrintService.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2006 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef GECKO_PRINT_SERVICE_H
+#define GECKO_PRINT_SERVICE_H
+
+#include <gtk/gtkpagesetup.h>
+#include <gtk/gtkprintsettings.h>
+#include <gtk/gtkprinter.h>
+
+#include <nsIPrintingPromptService.h>
+
+class nsIPrintSettings;
+
+/* 6a71ff30-7f4d-4d91-b71a-d5c9764b34be */
+#define GECKO_PRINT_SERVICE_IID \
+{ 0x6a71ff30, 0x7f4d, 0x4d91, \
+ { 0xb7, 0x1a, 0xd5, 0xc9, 0x76, 0x4b, 0x34, 0xbe } }
+
+#define GECKO_PRINT_SERVICE_CLASSNAME "Gecko Print Service"
+
+class GeckoPrintService : public nsIPrintingPromptService
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPRINTINGPROMPTSERVICE
+
+ GeckoPrintService();
+ virtual ~GeckoPrintService();
+
+ static nsresult TranslateSettings (GtkPrintSettings*, GtkPageSetup *, GtkPrinter *, const nsACString&, PRInt16, PRBool, nsIPrintSettings*);
+
+private:
+ nsresult PrintUnattended (nsIDOMWindow *, nsIPrintSettings *);
+};
+
+#endif /* GECKO_PRINT_SERVICE_H */
diff --git a/embed/xulrunner/components/GeckoPrintSession.cpp b/embed/xulrunner/components/GeckoPrintSession.cpp
new file mode 100644
index 000000000..e0c3b89e9
--- /dev/null
+++ b/embed/xulrunner/components/GeckoPrintSession.cpp
@@ -0,0 +1,629 @@
+/*
+ * Copyright © 2006 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <unistd.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <nsStringGlue.h>
+
+#include <nsIDOMWindow.h>
+#include <nsIDOMWindowInternal.h>
+#include <nsIPrintSettings.h>
+
+#include "ephy-debug.h"
+#include "ephy-embed-shell.h"
+#include "ephy-file-helpers.h"
+
+#include "EphyUtils.h"
+
+#include "GeckoPrintSession.h"
+
+#define MAX_STRING_LENGTH 512
+
+GeckoPrintSession::GeckoPrintSession ()
+: mSettings(NULL)
+, mPageSetup(NULL)
+, mPrinter(NULL)
+, mJob(NULL)
+, mProgressDialog(NULL)
+, mTitleLabel(NULL)
+, mProgressBar(NULL)
+, mStartPrintIdleID(0)
+, mSourceFileIsTemp(PR_FALSE)
+, mDone(PR_FALSE)
+, mCancelled(PR_FALSE)
+{
+ LOG ("GeckoPrintSession ctor [%p]", (void*) this);
+
+ /* FIXME: connect to "prepare-close" ? */
+ g_object_ref (ephy_embed_shell_get_default ());
+}
+
+GeckoPrintSession::~GeckoPrintSession ()
+{
+ LOG ("GeckoPrintSession dtor [%p]", (void*) this);
+
+ NS_ASSERTION (mStartPrintIdleID == 0, "Impossible");
+
+ if (!mDone && !mCancelled) {
+ Cancel ();
+ }
+ DestroyJob ();
+
+ if (mSettings) {
+ g_object_unref (mSettings);
+ }
+ if (mPageSetup) {
+ g_object_unref (mPageSetup);
+ }
+ if (mPrinter) {
+ g_object_unref (mPrinter);
+ }
+ if (mProgressDialog) {
+ gtk_widget_destroy (mProgressDialog);
+ }
+ if (mSourceFileIsTemp) {
+ unlink (mSourceFile.get ());
+ }
+
+ g_object_unref (ephy_embed_shell_get_default ());
+}
+
+void
+GeckoPrintSession::GetSourceFile (nsACString &aSource)
+{
+ aSource.Assign (mSourceFile);
+}
+
+nsresult
+GeckoPrintSession::SetSettings (nsIPrintSettings *aPrintSettings,
+ GtkPrintSettings *aSettings,
+ GtkPageSetup *aPageSetup,
+ GtkPrinter *aPrinter)
+{
+ NS_ASSERTION (!mPrintSettings && !mSettings && !mPageSetup && !mPrinter, "Already have settings!");
+
+ NS_ENSURE_ARG (aPrintSettings);
+ NS_ENSURE_ARG (aSettings);
+
+ mPrintSettings = aPrintSettings;
+ mSettings = (GtkPrintSettings *) g_object_ref (aSettings);
+
+ NS_ENSURE_ARG (aPageSetup);
+ NS_ENSURE_ARG (aPrinter);
+
+ mPageSetup = (GtkPageSetup *) g_object_ref (aPageSetup);
+ mPrinter = (GtkPrinter *) g_object_ref (aPrinter);
+
+#if 0
+ /* Compute the source file name */
+ if (gtk_print_settings_get_print_to_file (mSettings)) {
+ /* FIXME: support gnome-VFS uris here! */
+ const char *fileURI = gtk_print_settings_get (aSettings, "export-uri");
+ NS_ENSURE_TRUE (fileURI, NS_ERROR_FAILURE);
+
+ char *fileName = g_filename_from_uri (fileURI, NULL, NULL);
+ NS_ENSURE_TRUE (fileURI, NS_ERROR_FAILURE);
+
+ mSourceFile.Assign (fileName);
+ g_free (fileName);
+ } else
+#endif
+ {
+ char *base, *tmpName;
+
+ /* FIXME: use pure glib here (g_mkstemp)! */
+ base = g_build_filename (ephy_file_tmp_dir (), "print-XXXXXX", (const char *) NULL);
+ tmpName = ephy_file_tmp_filename (base, "ps");
+ g_free (base);
+
+ NS_ENSURE_TRUE (tmpName, NS_ERROR_FAILURE);
+ mSourceFile.Assign (tmpName);
+ g_free (tmpName);
+
+ mSourceFileIsTemp = PR_TRUE;
+ }
+
+ return NS_OK;
+}
+
+/* static methods */
+
+/* static */ GeckoPrintSession *
+GeckoPrintSession::FromSettings (nsIPrintSettings *aSettings)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrintSession> session;
+ rv = aSettings->GetPrintSession (getter_AddRefs (session));
+ NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && session, nsnull);
+
+ /* this is ok since the caller holds a ref to the settings which hold a ref to the session */
+ nsIPrintSession *sessionPtr = session.get();
+ return static_cast<GeckoPrintSession*>(sessionPtr);
+}
+
+/* static functions */
+
+static void
+ReleaseSession (GeckoPrintSession *aSession)
+{
+ NS_RELEASE (aSession);
+}
+
+static gboolean
+ProgressDeleteCallback (GtkDialog *aDialog)
+{
+ gtk_dialog_response (aDialog, GTK_RESPONSE_DELETE_EVENT);
+ return TRUE;
+}
+
+static void
+ProgressResponseCallback (GtkDialog *aDialog,
+ int aResponse,
+ GeckoPrintSession *aSession)
+{
+ aSession->Cancel ();
+}
+
+static gboolean
+StartPrintIdleCallback (GeckoPrintSession *aSession)
+{
+ aSession->StartPrinting ();
+
+ return FALSE;
+}
+
+static void
+JobStatusChangedCallback (GtkPrintJob *aJob,
+ GeckoPrintSession *aSession)
+{
+ aSession->JobStatusChanged ();
+}
+
+static void
+JobCompletedCallback (GtkPrintJob *aJob,
+ GeckoPrintSession *aSession,
+ GError *aError)
+{
+ aSession->JobDone ();
+
+ if (aError) {
+ aSession->JobError (aError->message);
+ }
+}
+
+/* Private methods */
+
+void
+GeckoPrintSession::SetProgress (PRInt32 aCurrent,
+ PRInt32 aMaximum)
+{
+ NS_ENSURE_TRUE (mProgressDialog, );
+
+ if (mCancelled) return;
+
+ /* Mozilla is weird */
+ if (aCurrent > aMaximum || (aCurrent == 100 && aMaximum == 100)) return;
+
+ double fraction = 0.0;
+ if (aMaximum > 0 && aCurrent >= 0) {
+ char *text = g_strdup_printf (_("Page %d of %d"), aCurrent, aMaximum);
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (mProgressBar), text);
+ g_free (text);
+
+ fraction = (double) aCurrent / (double) aMaximum;
+ }
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (mProgressBar), CLAMP (fraction, 0.0, 1.0));
+}
+
+void
+GeckoPrintSession::SetProgressText (const char *aText)
+{
+ NS_ENSURE_TRUE (mProgressDialog, );
+
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (mProgressBar), aText);
+}
+
+void
+GeckoPrintSession::Cancel ()
+{
+ SetProcessCanceledByUser (PR_TRUE);
+
+ if (mProgressDialog) {
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (mProgressDialog),
+ GTK_RESPONSE_CANCEL, FALSE);
+
+ SetProgress (0, 0);
+ SetProgressText (_("Cancelling print")); /* FIXME text! */
+ }
+
+ if (mJob) {
+ /* FIXME: There's no way to cancel mJob! Bug #339323 */
+ }
+}
+
+void
+GeckoPrintSession::StartPrinting ()
+{
+ mStartPrintIdleID = 0;
+
+ GError *error = NULL;
+
+#if 0
+ /* FIXME: this could also be a print job to a file which was
+ * printed to a temp file and now needs to be uploaded to its
+ * final location with gnome-vfs.
+ */
+ if (gtk_print_settings_get_print_to_file (mSettings)) return;
+#endif
+
+ NS_ENSURE_TRUE (mSettings && mPageSetup && mPrinter, );
+
+ mJob = gtk_print_job_new (mTitle.get (),
+ mPrinter,
+ mSettings,
+ mPageSetup);
+ if (!gtk_print_job_set_source_file (mJob, mSourceFile.get (), &error)) {
+ /* FIXME: error dialogue! */
+ g_warning ("Couldn't set print job source: %s", error->message);
+ g_error_free (error);
+
+ g_object_unref (mJob);
+ mJob = NULL;
+
+ return;
+ }
+
+ g_signal_connect (mJob, "status-changed",
+ G_CALLBACK (JobStatusChangedCallback), this);
+
+ /* Keep us alive until the job is done! */
+ NS_ADDREF_THIS ();
+ gtk_print_job_send (mJob,
+ (GtkPrintJobCompleteFunc) JobCompletedCallback,
+ this,
+ (GDestroyNotify) ReleaseSession);
+}
+
+void
+GeckoPrintSession::JobStatusChanged ()
+{
+ NS_ENSURE_TRUE (mProgressDialog, );
+
+ LOG ("print session %p status changed %d\n", this, gtk_print_job_get_status (mJob));
+
+ /* FIXME: are any other status codes relevant info for the user? */
+ if (gtk_print_job_get_status (mJob) == GTK_PRINT_STATUS_SENDING_DATA) {
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (mProgressBar), 0.75);
+ /* FIXME text! */
+ SetProgressText (_("Spooling..."));
+ }
+}
+
+void
+GeckoPrintSession::JobError (const char *aErrorMessage)
+{
+ LOG ("print job error: %s", aErrorMessage);
+
+ /* FIXME better text */
+ GtkWidget *dialog = gtk_message_dialog_new (NULL,
+ GtkDialogFlags (0),
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Print error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", aErrorMessage);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_widget_show (dialog);
+}
+
+void
+GeckoPrintSession::JobDone ()
+{
+ NS_ENSURE_TRUE (mProgressDialog, );
+
+ mDone = PR_TRUE;
+
+ gtk_widget_hide (mProgressDialog);
+
+ DestroyJob ();
+}
+
+void
+GeckoPrintSession::DestroyJob ()
+{
+ if (!mJob) return;
+
+ g_signal_handlers_disconnect_by_func (mJob, (void*) JobStatusChangedCallback, this);
+ g_object_unref (mJob);
+ mJob = NULL;
+}
+
+void
+GeckoPrintSession::LaunchJobOnIdle ()
+{
+ NS_ASSERTION (!mStartPrintIdleID, "Already started printing!");
+
+ /* Don't send the job to the printer if the user cancelled the print */
+ if (mCancelled) return;
+
+ /* Keep us alive until the idle handler runs! */
+ NS_ADDREF_THIS ();
+ mStartPrintIdleID = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ (GSourceFunc) StartPrintIdleCallback,
+ this,
+ (GDestroyNotify) ReleaseSession);
+}
+
+/* XPCOM interfaces */
+
+NS_IMPL_THREADSAFE_ISUPPORTS5 (GeckoPrintSession,
+ nsIPrintSession,
+ nsIWebProgressListener,
+ nsIPrintProgress,
+ nsIPrintProgressParams,
+ nsISupportsWeakReference)
+
+/* nsIPrintSession implementation */
+
+/* nsIWebProgressListener implementation */
+
+/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */
+NS_IMETHODIMP
+GeckoPrintSession::OnStateChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRUint32 aStateFlags,
+ nsresult aStatus)
+{
+ if (NS_SUCCEEDED (aStatus) &&
+ aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
+ if (aStateFlags & nsIWebProgressListener::STATE_START) {
+ /* Printing starts now */
+ SetProgress (0, 0);
+ } else if ((aStateFlags & nsIWebProgressListener::STATE_STOP)) {
+ /* Printing done, upload to printer */
+ LaunchJobOnIdle ();
+ }
+ }
+
+ return NS_OK;
+}
+
+/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
+NS_IMETHODIMP
+GeckoPrintSession::OnProgressChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRInt32 aCurSelfProgress,
+ PRInt32 aMaxSelfProgress,
+ PRInt32 aCurTotalProgress,
+ PRInt32 aMaxTotalProgress)
+{
+ SetProgress (aCurTotalProgress, aMaxTotalProgress);
+
+ return NS_OK;
+}
+
+/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI aLocation); */
+NS_IMETHODIMP
+GeckoPrintSession::OnLocationChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ nsIURI *aLocation)
+{
+ NS_ASSERTION (0, "OnLocationChange reached!");
+ return NS_OK;
+}
+
+/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
+NS_IMETHODIMP
+GeckoPrintSession::OnStatusChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ nsresult aStatus,
+ const PRUnichar *aMessage)
+{
+ NS_ASSERTION (0, "OnStatusChange reached!");
+ return NS_OK;
+}
+
+/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aState); */
+NS_IMETHODIMP
+GeckoPrintSession::OnSecurityChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRUint32 aState)
+{
+ NS_ASSERTION (0, "OnSecurityChange reached!");
+ return NS_OK;
+}
+
+/* nsIPrintProgress implementation */
+
+/* void openProgressDialog (in nsIDOMWindowInternal parent, in string dialogURL, in nsISupports parameters, in nsIObserver openDialogObserver, out boolean notifyOnOpen); */
+NS_IMETHODIMP
+GeckoPrintSession::OpenProgressDialog (nsIDOMWindowInternal *aParent,
+ const char *aDialogURL,
+ nsISupports *aParameters,
+ nsIObserver *aOpenDialogObserver,
+ PRBool *_notifyOnOpen)
+{
+ NS_ENSURE_STATE (!mProgressDialog);
+
+ nsCOMPtr<nsIDOMWindow> domWindow (do_QueryInterface (aParent));
+ GtkWidget *parent = EphyUtils::FindGtkParent (domWindow);
+
+ GtkWidget *vbox, *hbox, *image;
+
+ mProgressDialog = gtk_dialog_new ();
+ GtkDialog *dialog = GTK_DIALOG (mProgressDialog);
+
+ gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+ g_signal_connect (dialog, "delete-event",
+ G_CALLBACK (ProgressDeleteCallback), NULL);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (ProgressResponseCallback), this);
+
+ /* FIXME do we need transient? initially on top should suffice */
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (parent));
+
+ gtk_dialog_set_has_separator (dialog, FALSE);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (dialog->vbox), 14); /* 2 * 5 + 14 = 24 */
+ gtk_box_set_spacing (GTK_BOX (dialog->action_area), 5);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+ gtk_container_add (GTK_CONTAINER (dialog->vbox), hbox);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_PRINT, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+ mTitleLabel = gtk_label_new (NULL);
+ gtk_label_set_line_wrap (GTK_LABEL (mTitleLabel), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (mTitleLabel), 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), mTitleLabel, FALSE, FALSE, 0);
+
+ mProgressBar = gtk_progress_bar_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), mProgressBar, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (hbox);
+ gtk_window_present (GTK_WINDOW (dialog));
+
+ *_notifyOnOpen = PR_FALSE;
+
+ return NS_OK;
+}
+
+/* void closeProgressDialog (in boolean forceClose); */
+NS_IMETHODIMP
+GeckoPrintSession::CloseProgressDialog (PRBool forceClose)
+{
+ return NS_OK;
+}
+
+/* void registerListener (in nsIWebProgressListener listener); */
+NS_IMETHODIMP
+GeckoPrintSession::RegisterListener (nsIWebProgressListener *listener)
+{
+ return NS_OK;
+}
+
+/* void unregisterListener (in nsIWebProgressListener listener); */
+NS_IMETHODIMP
+GeckoPrintSession::UnregisterListener (nsIWebProgressListener *listener)
+{
+ return NS_OK;
+}
+
+/* void doneIniting (); */
+NS_IMETHODIMP
+GeckoPrintSession::DoneIniting()
+{
+ return NS_OK;
+}
+
+/* nsIPrompt getPrompter (); */
+NS_IMETHODIMP
+GeckoPrintSession::GetPrompter (nsIPrompt **_retval)
+{
+ g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED);
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute boolean processCanceledByUser; */
+NS_IMETHODIMP
+GeckoPrintSession::GetProcessCanceledByUser (PRBool *aProcessCanceledByUser)
+{
+ *aProcessCanceledByUser = mCancelled;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GeckoPrintSession::SetProcessCanceledByUser (PRBool aProcessCanceledByUser)
+{
+ mCancelled = aProcessCanceledByUser;
+ if (mPrintSettings) {
+ mPrintSettings->SetIsCancelled (aProcessCanceledByUser);
+ }
+
+ return NS_OK;
+}
+
+/* nsIPrintProgressParams implementation */
+
+/* attribute wstring docTitle; */
+NS_IMETHODIMP
+GeckoPrintSession::GetDocTitle (PRUnichar * *aDocTitle)
+{
+ g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED);
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+GeckoPrintSession::SetDocTitle (const PRUnichar * aDocTitle)
+{
+ NS_ENSURE_STATE (mProgressDialog);
+
+ char *converted = EphyUtils::ConvertUTF16toUTF8 (aDocTitle, MAX_STRING_LENGTH);
+ if (converted) {
+ mTitle.Assign (converted);
+
+ char *title = g_strdup_printf (_("Printing “%s”"), converted);
+ gtk_window_set_title (GTK_WINDOW (mProgressDialog), title);
+ gtk_label_set_text (GTK_LABEL (mTitleLabel), title);
+ g_free (converted);
+ g_free (title);
+ }
+ return NS_OK;
+}
+
+/* attribute wstring docURL; */
+NS_IMETHODIMP
+GeckoPrintSession::GetDocURL (PRUnichar * *aDocURL)
+{
+ g_return_val_if_reached (NS_ERROR_NOT_IMPLEMENTED);
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+GeckoPrintSession::SetDocURL (const PRUnichar * aDocURL)
+{
+#if 0
+ NS_ENSURE_STATE (mJob);
+
+ char *converted = EphyUtils::ConvertUTF16toUTF8 (aDocTitle, MAX_STRING_LENGTH);
+ if (converted) {
+ g_free (converted);
+ }
+#endif
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/GeckoPrintSession.h b/embed/xulrunner/components/GeckoPrintSession.h
new file mode 100644
index 000000000..027f01e23
--- /dev/null
+++ b/embed/xulrunner/components/GeckoPrintSession.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2006 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef GECKO_PRINT_SESSION_H
+#define GECKO_PRINT_SESSION_H
+
+#include <nsCOMPtr.h>
+#include <nsIPrintSession.h>
+#include <nsIWebProgressListener.h>
+#include <nsIPrintProgress.h>
+#include <nsIPrintProgressParams.h>
+#include <nsWeakReference.h>
+
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkprintjob.h>
+#include <gtk/gtkprinter.h>
+#include <gtk/gtkprintjob.h>
+
+class nsIPrintSettings;
+class nsIDOMWindow;
+
+/* 0940c973-97e7-476f-a612-4ed9473a0b36 */
+#define GECKO_PRINT_SESSION_IID \
+{ 0x0940c973, 0x97e7, 0x476f, \
+ { 0xa6, 0x12, 0x4e, 0xd9, 0x47, 0x3a, 0x0b, 0x36 } }
+
+#define GECKO_PRINT_SESSION_CLASSNAME "Gecko Print Session"
+
+class GeckoPrintSession : public nsIPrintSession,
+ public nsIPrintProgress,
+ public nsIPrintProgressParams,
+ public nsSupportsWeakReference
+{
+ public:
+ GeckoPrintSession();
+ virtual ~GeckoPrintSession();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPRINTSESSION
+ NS_DECL_NSIWEBPROGRESSLISTENER
+ NS_DECL_NSIPRINTPROGRESS
+ NS_DECL_NSIPRINTPROGRESSPARAMS
+
+ nsresult SetSettings (nsIPrintSettings *, GtkPrintSettings*, GtkPageSetup*, GtkPrinter*);
+ void GetSourceFile (nsACString&);
+
+ static GeckoPrintSession *FromSettings (nsIPrintSettings *);
+
+ void Cancel ();
+ void StartPrinting ();
+ void JobStatusChanged ();
+ void JobDone ();
+ void JobError (const char *);
+
+ private:
+ nsCOMPtr<nsIPrintSettings> mPrintSettings;
+ GtkPrintSettings *mSettings;
+ GtkPageSetup *mPageSetup;
+ GtkPrinter *mPrinter;
+ GtkPrintJob *mJob;
+ GtkWidget *mProgressDialog;
+ GtkWidget *mTitleLabel;
+ GtkWidget *mProgressBar;
+ nsCString mSourceFile;
+ nsCString mTitle;
+ guint mStartPrintIdleID;
+ PRPackedBool mSourceFileIsTemp;
+ PRPackedBool mDone;
+ PRPackedBool mCancelled;
+
+ void SetProgress (PRInt32, PRInt32);
+ void SetProgressText (const char *);
+ void LaunchJobOnIdle ();
+ void DestroyJob ();
+};
+
+#endif /* GECKO_PRINT_SESSION_H */
diff --git a/embed/xulrunner/components/GeckoSpellCheckEngine.cpp b/embed/xulrunner/components/GeckoSpellCheckEngine.cpp
new file mode 100644
index 000000000..0b1257b41
--- /dev/null
+++ b/embed/xulrunner/components/GeckoSpellCheckEngine.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright © 2006 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <nsStringGlue.h>
+
+#include <mozIPersonalDictionary.h>
+#include <nsMemory.h>
+
+#include "ephy-debug.h"
+
+#include "GeckoSpellCheckEngine.h"
+
+GeckoSpellCheckEngine::GeckoSpellCheckEngine ()
+{
+ LOG ("GeckoSpellCheckEngine ctor [%p]", (void*) this);
+ mSpeller = ephy_spell_check_get_default ();
+}
+
+GeckoSpellCheckEngine::~GeckoSpellCheckEngine ()
+{
+ LOG ("GeckoSpellCheckEngine dtor [%p]", (void*) this);
+ g_object_unref (mSpeller);
+}
+
+NS_IMPL_ISUPPORTS1 (GeckoSpellCheckEngine,
+ mozISpellCheckingEngine)
+
+/* nsISpellCheckEngine implementation */
+
+/* attribute wstring dictionary; */
+NS_IMETHODIMP GeckoSpellCheckEngine::GetDictionary (PRUnichar * *aDictionary)
+{
+ /* Gets the identifier of the current dictionary */
+ char *code = ephy_spell_check_get_language (mSpeller);
+ if (!code) {
+ return NS_ERROR_FAILURE;
+ }
+
+ *aDictionary = ToNewUnicode (NS_ConvertUTF8toUTF16 (code));
+ g_free (code);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP GeckoSpellCheckEngine::SetDictionary (const PRUnichar * aDictionary)
+{
+ return NS_OK;
+}
+
+/* readonly attribute wstring language; */
+NS_IMETHODIMP GeckoSpellCheckEngine::GetLanguage (PRUnichar * *aLanguage)
+{
+ /* Gets the identifier of the current dictionary */
+ char *code = ephy_spell_check_get_language (mSpeller);
+ if (!code) {
+ return NS_ERROR_FAILURE;
+ }
+
+ *aLanguage = ToNewUnicode (NS_ConvertUTF8toUTF16 (code));
+ g_free (code);
+
+ return NS_OK;
+}
+
+/* readonly attribute boolean providesPersonalDictionary; */
+NS_IMETHODIMP GeckoSpellCheckEngine::GetProvidesPersonalDictionary (PRBool *aProvidesPersonalDictionary)
+{
+ *aProvidesPersonalDictionary = PR_FALSE;
+ return NS_OK;
+}
+
+/* readonly attribute boolean providesWordUtils; */
+NS_IMETHODIMP GeckoSpellCheckEngine::GetProvidesWordUtils (PRBool *aProvidesWordUtils)
+{
+ *aProvidesWordUtils = PR_FALSE;
+ return NS_OK;
+}
+
+/* readonly attribute wstring name; */
+NS_IMETHODIMP GeckoSpellCheckEngine::GetName (PRUnichar * *aName)
+{
+ /* It's fine to leave this unimplemented */
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* readonly attribute wstring copyright; */
+NS_IMETHODIMP GeckoSpellCheckEngine::GetCopyright (PRUnichar * *aCopyright)
+{
+ /* It's fine to leave this unimplemented */
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* attribute mozIPersonalDictionary personalDictionary; */
+NS_IMETHODIMP GeckoSpellCheckEngine::GetPersonalDictionary (mozIPersonalDictionary * *aPersonalDictionary)
+{
+ NS_IF_ADDREF (*aPersonalDictionary = mPersonalDictionary);
+ return NS_OK;
+}
+
+NS_IMETHODIMP GeckoSpellCheckEngine::SetPersonalDictionary (mozIPersonalDictionary * aPersonalDictionary)
+{
+ mPersonalDictionary = aPersonalDictionary;
+ return NS_OK;
+}
+
+/* void getDictionaryList ([array, size_is (count)] out wstring dictionaries, out PRUint32 count); */
+NS_IMETHODIMP
+GeckoSpellCheckEngine::GetDictionaryList (PRUnichar ***_dictionaries,
+ PRUint32 *_count)
+{
+ *_count = 1;
+ *_dictionaries = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *)); // only one entry
+ *_dictionaries[0] = ToNewUnicode (NS_LITERAL_STRING ("en"));
+ return NS_OK;
+}
+
+/* boolean check (in wstring word); */
+NS_IMETHODIMP GeckoSpellCheckEngine::Check (const PRUnichar *word,
+ PRBool *_retval)
+{
+ NS_ENSURE_STATE (mSpeller);
+ NS_ENSURE_ARG (word);
+
+ NS_ConvertUTF16toUTF8 converted (word);
+
+ gboolean correct = FALSE;
+ if (!ephy_spell_check_check_word (mSpeller,
+ converted.get (),
+ converted.Length (),
+ &correct))
+ return NS_ERROR_FAILURE;
+
+ *_retval = correct != FALSE;
+
+ return NS_OK;
+}
+
+/* void suggest (in wstring word, [array, size_is (count)] out wstring suggestions, out PRUint32 count); */
+NS_IMETHODIMP GeckoSpellCheckEngine::Suggest (const PRUnichar *word,
+ PRUnichar ***_suggestions,
+ PRUint32 *_count)
+{
+#if 0
+ NS_ENSURE_STATE (mSpeller);
+ NS_ENSURE_ARG (word);
+
+ NS_ConvertUTF16toUTF8 converted (word);
+
+ gsize count;
+ char **suggestions = ephy_spell_check_get_suggestions (mSpeller,
+ converted.get (),
+ converted.Length (),
+ &count);
+
+ *_count = count;
+ *_suggestions = nsnull;
+
+ PRUnichar **array = nsnull;
+ if (count > 0) {
+ NS_ASSERTION (suggestions, "Count > 0 but suggestions are NULL?");
+ array = (PRUnichar **) nsMemory::Alloc (count * sizeof (PRUnichar *));
+ if (array) {
+ *_suggestions = array;
+
+ for (gsize i = 0; i < count; ++i) {
+ NS_ConvertUTF8toUTF16 sugg (suggestions[i]);
+ array[i] = ToNewUnicode (sugg);
+ }
+ }
+
+ ephy_spell_check_free_suggestions (mSpeller, suggestions);
+ }
+
+ return array ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+#endif
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
diff --git a/embed/xulrunner/components/GeckoSpellCheckEngine.h b/embed/xulrunner/components/GeckoSpellCheckEngine.h
new file mode 100644
index 000000000..b70f6c970
--- /dev/null
+++ b/embed/xulrunner/components/GeckoSpellCheckEngine.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2006 Christian Persch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef GECKO_SPELL_CHECK_ENGINE_H
+#define GECKO_SPELL_CHECK_ENGINE_H
+
+#include <nsCOMPtr.h>
+#include <mozISpellCheckingEngine.h>
+
+#include "ephy-spell-check.h"
+
+class mozIPersonalDictionary;
+
+/* 26948b8b-d136-4a78-a9c5-3a145812b649 */
+#define GECKO_SPELL_CHECK_ENGINE_IID \
+{ 0x26948b8b, 0xd136, 0x4a78, { 0xa9, 0xc5, 0x3a, 0x14, 0x58, 0x12, 0xb6, 0x49 } }
+
+#define GECKO_SPELL_CHECK_ENGINE_CONTRACTID "@mozilla.org/spellchecker/myspell;1"
+#define GECKO_SPELL_CHECK_ENGINE_CLASSNAME "Gecko Print Settings"
+
+class GeckoSpellCheckEngine : public mozISpellCheckingEngine
+{
+ public:
+ GeckoSpellCheckEngine();
+ virtual ~GeckoSpellCheckEngine();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_MOZISPELLCHECKINGENGINE
+
+ private:
+ nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
+ EphySpellCheck *mSpeller;
+};
+
+#endif /* GECKO_SPELL_CHECK_ENGINE_H */
diff --git a/embed/xulrunner/components/GlobalHistory.cpp b/embed/xulrunner/components/GlobalHistory.cpp
new file mode 100644
index 000000000..a2fd79960
--- /dev/null
+++ b/embed/xulrunner/components/GlobalHistory.cpp
@@ -0,0 +1,221 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright © 2001, 2004 Philip Langdale
+ * Copyright © 2004 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <nsStringGlue.h>
+
+#include <nsIURI.h>
+
+#include "ephy-embed-shell.h"
+
+#include "GlobalHistory.h"
+
+
+#define MAX_TITLE_LENGTH 2048
+#define MAX_URL_LENGTH 16384
+
+#ifdef HAVE_NSIGLOBALHISTORY3_H
+NS_IMPL_ISUPPORTS2 (MozGlobalHistory, nsIGlobalHistory2, nsIGlobalHistory3)
+#else
+NS_IMPL_ISUPPORTS1 (MozGlobalHistory, nsIGlobalHistory2)
+#endif /* HAVE_NSIGLOBALHISTORY3_H */
+
+MozGlobalHistory::MozGlobalHistory ()
+{
+ mGlobalHistory = EPHY_HISTORY (ephy_embed_shell_get_global_history (embed_shell));
+
+ mHistoryListener = new EphyHistoryListener ();
+ mHistoryListener->Init (mGlobalHistory);
+}
+
+MozGlobalHistory::~MozGlobalHistory ()
+{
+}
+
+/* void addURI (in nsIURI aURI, in boolean aRedirect, in boolean aToplevel, in nsIURI aReferrer); */
+NS_IMETHODIMP MozGlobalHistory::AddURI(nsIURI *aURI,
+ PRBool aRedirect,
+ PRBool aToplevel,
+ nsIURI *aReferrer)
+{
+ nsresult rv;
+
+ NS_ENSURE_ARG (aURI);
+
+ // filter out unwanted URIs such as chrome: etc
+ // The model is really if we don't know differently then add which basically
+ // means we are suppose to try all the things we know not to allow in and
+ // then if we don't bail go on and allow it in. But here lets compare
+ // against the most common case we know to allow in and go on and say yes
+ // to it.
+
+ PRBool isHTTP = PR_FALSE, isHTTPS = PR_FALSE;
+ rv = aURI->SchemeIs("http", &isHTTP);
+ rv |= aURI->SchemeIs("https", &isHTTPS);
+ NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE);
+
+ if (!isHTTP && !isHTTPS)
+ {
+ static const char *schemes[] = { "javascript",
+ "data",
+ "about",
+ "chrome",
+ "resource",
+ "view-source" };
+
+ for (PRUint32 i = 0; i < G_N_ELEMENTS (schemes); ++i)
+ {
+ PRBool result = PR_FALSE;
+ if (NS_SUCCEEDED (aURI->SchemeIs (schemes[i], &result)) && result)
+ {
+ return NS_OK;
+ }
+ }
+ }
+
+ nsCString spec;
+ rv = aURI->GetSpec(spec);
+ NS_ENSURE_TRUE (NS_SUCCEEDED(rv) && spec.Length(), rv);
+
+ if (spec.Length () > MAX_URL_LENGTH) return NS_OK;
+
+ ephy_history_add_page (mGlobalHistory, spec.get(), aRedirect, aToplevel);
+
+ return NS_OK;
+}
+
+/* boolean isVisited (in nsIURI aURI); */
+NS_IMETHODIMP MozGlobalHistory::IsVisited(nsIURI *aURI,
+ PRBool *_retval)
+{
+ NS_ENSURE_ARG (aURI);
+
+ *_retval = PR_FALSE;
+
+ nsCString spec;
+ aURI->GetSpec(spec);
+
+ if (spec.Length () > MAX_URL_LENGTH) return NS_OK;
+
+ *_retval = ephy_history_is_page_visited (mGlobalHistory, spec.get());
+
+ return NS_OK;
+}
+
+/* void setPageTitle (in nsIURI aURI, in AString aTitle); */
+NS_IMETHODIMP MozGlobalHistory::SetPageTitle(nsIURI *aURI,
+ const nsAString & aTitle)
+{
+ NS_ENSURE_ARG (aURI);
+
+ nsCString spec;
+ aURI->GetSpec(spec);
+
+ if (spec.Length () > MAX_URL_LENGTH) return NS_OK;
+
+ nsString uTitle (aTitle);
+
+ /* This depends on the assumption that
+ * typeof(PRUnichar) == typeof (gunichar2) == uint16,
+ * which should be pretty safe.
+ */
+ glong n_read = 0, n_written = 0;
+ char *converted = g_utf16_to_utf8 ((gunichar2*) uTitle.get(), MAX_TITLE_LENGTH,
+ &n_read, &n_written, NULL);
+ /* FIXME loop from the end while !g_unichar_isspace (char)? */
+ if (converted == NULL) return NS_OK;
+
+ ephy_history_set_page_title (mGlobalHistory, spec.get(), converted);
+
+ g_free (converted);
+
+ return NS_OK;
+}
+
+#ifdef HAVE_NSIGLOBALHISTORY3_H
+
+/* unsigned long getURIGeckoFlags(in nsIURI aURI); */
+NS_IMETHODIMP
+MozGlobalHistory::GetURIGeckoFlags(nsIURI *aURI,
+ PRUint32* aFlags)
+{
+ *aFlags = 0;
+
+ nsCString spec;
+ aURI->GetSpec(spec);
+
+ if (spec.Length () > MAX_URL_LENGTH) return NS_OK;
+
+ EphyNode *page = ephy_history_get_page (mGlobalHistory, spec.get());
+
+ GValue value = { 0, };
+ if (page != NULL &&
+ ephy_node_get_property (page, EPHY_NODE_PAGE_PROP_GECKO_FLAGS, &value))
+ {
+ *aFlags = (PRUint32) (gulong) g_value_get_long (&value);
+ g_value_unset (&value);
+
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+/* void setURIGeckoFlags(in nsIURI aURI, in unsigned long aFlags); */
+NS_IMETHODIMP
+MozGlobalHistory::SetURIGeckoFlags(nsIURI *aURI,
+ PRUint32 aFlags)
+{
+ nsCString spec;
+ aURI->GetSpec(spec);
+
+ if (spec.Length () > MAX_URL_LENGTH) return NS_OK;
+
+ EphyNode *page = ephy_history_get_page (mGlobalHistory, spec.get());
+ if (page != NULL)
+ {
+ ephy_node_set_property_long (page,
+ EPHY_NODE_PAGE_PROP_GECKO_FLAGS,
+ aFlags);
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+/* void addDocumentRedirect (in nsIChannel
+ aOldChannel,
+ in nsIChannel aNewChannel,
+ in PRInt32 aFlags,
+ in boolean aTopLevel); */
+NS_IMETHODIMP
+MozGlobalHistory::AddDocumentRedirect(nsIChannel *aOldChannel,
+ nsIChannel *aNewChannel,
+ PRInt32 aFlags,
+ PRBool aTopLevel)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+#endif /* HAVE_NSIGLOBALHISTORY3_H */
diff --git a/embed/xulrunner/components/GlobalHistory.h b/embed/xulrunner/components/GlobalHistory.h
new file mode 100644
index 000000000..8397874a0
--- /dev/null
+++ b/embed/xulrunner/components/GlobalHistory.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2001, 2004 Philip Langdale
+ * Copyright © 2004 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef EPHY_GLOBAL_HISTORY_H
+#define EPHY_GLOBAL_HISTORY_H
+
+#ifdef HAVE_NSIGLOBALHISTORY3_H
+#include <nsIGlobalHistory3.h>
+#else
+#include <nsIGlobalHistory2.h>
+#endif /* HAVE_NSIGLOBALHISTORY3_H */
+
+#include <nsAutoPtr.h>
+#include <nsCOMPtr.h>
+
+#include "ephy-history.h"
+
+#include "EphyHistoryListener.h"
+
+#define EPHY_GLOBALHISTORY_CLASSNAME "Epiphany Global History Implementation"
+
+#define EPHY_GLOBALHISTORY_CID \
+{ 0xbe0c42c1, \
+ 0x39d4, \
+ 0x4271, \
+ { 0xb7, 0x9e, 0xf7, 0xaa, 0x49, 0xeb, 0x6a, 0x15} \
+}
+
+#ifdef HAVE_NSIGLOBALHISTORY3_H
+class MozGlobalHistory: public nsIGlobalHistory3
+#else
+class MozGlobalHistory: public nsIGlobalHistory2
+#endif /* HAVE_NSIGLOBALHISTORY3_H */
+{
+ public:
+ MozGlobalHistory ();
+ virtual ~MozGlobalHistory();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGLOBALHISTORY2
+#ifdef HAVE_NSIGLOBALHISTORY3_H
+ NS_DECL_NSIGLOBALHISTORY3
+#endif /* HAVE_NSIGLOBALHISTORY3_H */
+
+ private:
+ EphyHistory *mGlobalHistory;
+ nsRefPtr<EphyHistoryListener> mHistoryListener;
+};
+
+#endif /* EPHY_GLOBAL_HISTORY_H */
diff --git a/embed/xulrunner/components/GtkNSSClientAuthDialogs.cpp b/embed/xulrunner/components/GtkNSSClientAuthDialogs.cpp
new file mode 100644
index 000000000..12b74573f
--- /dev/null
+++ b/embed/xulrunner/components/GtkNSSClientAuthDialogs.cpp
@@ -0,0 +1,284 @@
+/*
+ * GtkNSSClientAuthDialogs.cpp
+ *
+ * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtkcelllayout.h>
+#include <gtk/gtkcellrenderer.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkcombobox.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkexpander.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtkprogressbar.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtktextbuffer.h>
+#include <gtk/gtktextview.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtkvbox.h>
+
+#include <nsStringGlue.h>
+
+#include <nsIDOMWindow.h>
+#include <nsIInterfaceRequestor.h>
+#include <nsIInterfaceRequestorUtils.h>
+#include <nsIServiceManager.h>
+
+#include "ephy-debug.h"
+#include "ephy-gui.h"
+#include "ephy-state.h"
+#include "ephy-stock-icons.h"
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+
+#include "GtkNSSClientAuthDialogs.h"
+
+GtkNSSClientAuthDialogs::GtkNSSClientAuthDialogs()
+{
+ LOG ("GtkNSSClientAuthDialogs ctor (%p)", this);
+}
+
+
+GtkNSSClientAuthDialogs::~GtkNSSClientAuthDialogs()
+{
+ LOG ("GtkNSSClientAuthDialogs dtor (%p)", this);
+}
+
+NS_IMPL_THREADSAFE_ISUPPORTS1 (GtkNSSClientAuthDialogs,
+ nsIClientAuthDialogs)
+
+/**
+ * Indent a widget according the HIG
+ *
+ * @returns: The new indented widget
+ */
+static GtkWidget*
+higgy_indent_widget (GtkWidget *widget)
+{
+ GtkWidget *hbox;
+ GtkWidget *label;
+
+ hbox = gtk_hbox_new (FALSE, 6);
+
+ label = gtk_label_new ("");
+ gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, TRUE, 6);
+ gtk_widget_show (label);
+
+ gtk_box_pack_start (GTK_BOX(hbox), widget, TRUE, TRUE, 0);
+
+ return hbox;
+}
+
+static void
+combo_changed_cb (GtkComboBox *combo, GtkTextView *textview)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTextBuffer *buffer;
+ int index;
+
+ model = gtk_combo_box_get_model (combo);
+ index = gtk_combo_box_get_active (combo);
+ buffer = gtk_text_view_get_buffer (textview);
+
+ if (gtk_tree_model_iter_nth_child (model, &iter, NULL, index))
+ {
+ char *text;
+
+ gtk_tree_model_get (model, &iter, 1, &text, -1);
+
+ gtk_text_buffer_set_text (buffer, text, -1);
+
+ g_free (text);
+ }
+ else
+ {
+ gtk_text_buffer_set_text (buffer, "", -1);
+ }
+}
+
+NS_IMETHODIMP
+GtkNSSClientAuthDialogs::ChooseCertificate (nsIInterfaceRequestor *ctx,
+ const PRUnichar *cn,
+ const PRUnichar *organization,
+ const PRUnichar *issuer,
+ const PRUnichar **certNickList,
+ const PRUnichar **certDetailsList,
+ PRUint32 count, PRInt32 *selectedIndex,
+ PRBool *canceled)
+{
+ GtkWidget *dialog, *label, *vbox, *textview;
+ GtkWidget *details, *expander, *hbox, *image;
+ GtkWidget *combo;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GtkCellRenderer *renderer;
+ char *msg, *markup_text;
+ PRUint32 i;
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
+ GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
+
+ AutoWindowModalState modalState (parent);
+
+ dialog = gtk_dialog_new_with_buttons ("",
+ GTK_WINDOW (gparent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ _("_Select Certificate"),
+ GTK_RESPONSE_OK,
+ (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), EPHY_STOCK_EPHY);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX(GTK_DIALOG (dialog)->vbox), 14); /* 24 = 2 * 5 + 14 */
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+ gtk_widget_show (image);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+ gtk_widget_show (vbox);
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ msg = g_markup_printf_escaped (_("Choose a certificate to present as identification to “%s”."),
+ 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);
+ gtk_label_set_markup (GTK_LABEL (label), markup_text);
+ g_free (msg);
+ g_free (markup_text);
+
+ /* Create and populate the combo */
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ for (i = 0; i < count; i++)
+ {
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, NS_ConvertUTF16toUTF8 (certNickList[i]).get(),
+ 1, NS_ConvertUTF16toUTF8 (certDetailsList[i]).get(),
+ -1);
+ }
+
+ combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
+ "text", 0,
+ (char *) NULL);
+
+ gtk_widget_show (combo);
+ gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, TRUE, 0);
+
+ expander = gtk_expander_new_with_mnemonic (_("Certificate _Details"));
+ ephy_state_add_expander (GTK_WIDGET (expander), "client-auth-dialog-expander", FALSE);
+
+ gtk_widget_show (expander);
+ gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), expander, FALSE, FALSE, 0);
+
+ /* Create the text box */
+ textview = gtk_text_view_new ();
+ gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), FALSE);
+ gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), FALSE);
+ gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textview), GTK_WRAP_WORD);
+ gtk_widget_set_size_request (GTK_WIDGET (textview), -1, 100);
+ gtk_widget_show (textview);
+
+ details = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (details), GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (details), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (details), textview);
+ gtk_widget_show (details);
+
+ details = higgy_indent_widget (details);
+ gtk_container_set_border_width (GTK_CONTAINER (details), 5);
+ gtk_widget_show (details);
+
+ gtk_container_add (GTK_CONTAINER (expander), details);
+
+ g_signal_connect (G_OBJECT (combo), "changed",
+ G_CALLBACK (combo_changed_cb),
+ textview);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+
+ /* run the dialog */
+ int res = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (res == GTK_RESPONSE_OK)
+ {
+ *canceled = PR_FALSE;
+ *selectedIndex = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+ }
+ else
+ {
+ *canceled = PR_TRUE;
+ }
+
+ gtk_widget_destroy (dialog);
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/GtkNSSClientAuthDialogs.h b/embed/xulrunner/components/GtkNSSClientAuthDialogs.h
new file mode 100644
index 000000000..0aa582700
--- /dev/null
+++ b/embed/xulrunner/components/GtkNSSClientAuthDialogs.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * $Id$
+ */
+
+#ifndef GTKNSSCLIENTAUTHDIALOGS_H
+#define GTKNSSCLIENTAUTHDIALOGS_H 1
+
+#include <nsIClientAuthDialogs.h>
+
+// 55b3837e-dbde-4c24-9247-f328e3012485
+#define GTK_NSSCLIENTAUTHDIALOGS_CID \
+ {0x55b3837e, 0xdbde, 0x4c24, {0x92, 0x47, 0xf3, 0x28, 0xe3, 0x01, 0x24, 0x85}}
+
+#define GTK_NSSCLIENTAUTHDIALOGS_CLASSNAME "Gtk NSS Client Auth Dialogs"
+
+class GtkNSSClientAuthDialogs
+: public nsIClientAuthDialogs
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICLIENTAUTHDIALOGS
+
+ GtkNSSClientAuthDialogs();
+ virtual ~GtkNSSClientAuthDialogs();
+};
+
+
+#endif /* GTKNSSCLIENTAUTHDIALOGS_H */
diff --git a/embed/xulrunner/components/GtkNSSDialogs.cpp b/embed/xulrunner/components/GtkNSSDialogs.cpp
new file mode 100644
index 000000000..51581f8db
--- /dev/null
+++ b/embed/xulrunner/components/GtkNSSDialogs.cpp
@@ -0,0 +1,1695 @@
+/*
+ * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx>
+ * Copyright © 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * This file provides Gtk implementations of the mozilla Certificate dialogs
+ * such as the ones displayed when connecting to a site with a self-signed
+ * or expired certificate.
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <time.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtkalignment.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkmessagedialog.h>
+#include <gtk/gtkprogressbar.h>
+#include <gtk/gtksizegroup.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtktextbuffer.h>
+#include <gtk/gtktextview.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtktreestore.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkcombobox.h>
+#include <gconf/gconf-client.h>
+#include <glade/glade-xml.h>
+
+#include <nsStringGlue.h>
+
+#include <nsCOMPtr.h>
+#include <nsIArray.h>
+#include <nsIASN1Object.h>
+#include <nsIASN1Sequence.h>
+#include <nsICRLInfo.h>
+#include <nsIDOMWindow.h>
+#include <nsIInterfaceRequestor.h>
+#include <nsIInterfaceRequestorUtils.h>
+#include <nsIMutableArray.h>
+#include <nsIPKCS11ModuleDB.h>
+#include <nsIPKCS11Slot.h>
+#include <nsIPK11Token.h>
+#include <nsIPK11TokenDB.h>
+#include <nsIServiceManager.h>
+#include <nsISimpleEnumerator.h>
+#include <nsIX509CertDB.h>
+#include <nsIX509Cert.h>
+#include <nsIX509CertValidity.h>
+#include <nsMemory.h>
+#include <nsServiceManagerUtils.h>
+
+#ifdef HAVE_NSIMUTABLEARRAY_H
+#include <nsIMutableArray.h>
+#endif
+
+#include "ephy-file-helpers.h"
+#include "ephy-gui.h"
+#include "ephy-password-dialog.h"
+#include "ephy-stock-icons.h"
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+
+#include "GtkNSSDialogs.h"
+
+NS_DEFINE_CID (kX509CertCID, NS_IX509CERT_IID);
+NS_DEFINE_CID (kASN1ObjectCID, NS_IASN1OBJECT_IID);
+
+enum
+{
+ NSSDIALOG_RESPONSE_VIEW_CERT = 10
+};
+
+GtkNSSDialogs::GtkNSSDialogs ()
+{
+}
+
+GtkNSSDialogs::~GtkNSSDialogs ()
+{
+}
+
+NS_IMPL_THREADSAFE_ISUPPORTS5 (GtkNSSDialogs,
+ nsICertificateDialogs,
+ 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.
+ */
+
+/**
+ * Call the mozilla service to display a certificate
+ */
+static void
+view_certificate (nsIInterfaceRequestor *ctx, nsIX509Cert *cert)
+{
+ nsresult rv;
+ nsCOMPtr<nsICertificateDialogs> certDialogs =
+ do_GetService (NS_CERTIFICATEDIALOGS_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS (rv, );
+
+ certDialogs->ViewCert (ctx, cert);
+}
+
+/**
+ * Indent a widget according the HIG
+ *
+ * @returns: The new indented widget
+ */
+static GtkWidget*
+higgy_indent_widget (GtkWidget *widget)
+{
+ GtkWidget *hbox;
+ GtkWidget *label;
+
+ hbox = gtk_hbox_new (FALSE, 6);
+
+ label = gtk_label_new (NULL);
+ gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, TRUE, 6);
+ gtk_widget_show (label);
+
+ gtk_box_pack_start (GTK_BOX(hbox), widget, TRUE, TRUE, 0);
+
+ return hbox;
+}
+
+/**
+ * Setup up a dialog with the correct HIG'gy spacings, adding the content_widget
+ */
+static void
+higgy_setup_dialog (GtkDialog *dialog, const gchar *stock_icon,
+ GtkWidget **content_label,
+ GtkWidget **content_vbox)
+{
+ GtkWidget *hbox, *label, *image, *vbox;
+
+ g_return_if_fail (GTK_IS_DIALOG (dialog));
+ g_return_if_fail (content_label);
+
+ gtk_dialog_set_has_separator (dialog, FALSE);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox);
+
+ image = gtk_image_new_from_stock (stock_icon, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ gtk_widget_show (image);
+ gtk_widget_show (vbox);
+ gtk_widget_show (hbox);
+ gtk_widget_show (label);
+
+ /* Set up the spacing for the dialog internal widgets */
+ gtk_box_set_spacing (GTK_BOX(dialog->vbox), 14); /* 24 = 2 * 5 + 14 */
+
+ *content_label = label;
+ if (content_vbox)
+ {
+ *content_vbox = vbox;
+ }
+}
+
+
+/**
+ * Display a dialog box, showing 'View Certificate', 'Cancel',
+ * and 'Accept' buttons. Optionally a checkbox can be shown,
+ * or the text can be NULL to avoid it being displayed
+ *
+ * @returns: GTK_RESPONSE_ACCEPT if the user clicked Accept
+ */
+static gint
+display_cert_warning_box (nsIInterfaceRequestor *ctx,
+ nsIX509Cert *cert,
+ const char *markup_text,
+ const char *checkbox_text,
+ gboolean *checkbox_value,
+ const char *affirmative_text)
+{
+ GtkWidget *dialog, *label, *checkbox, *vbox, *button;
+ int res;
+
+ g_return_val_if_fail (markup_text, GTK_RESPONSE_CANCEL);
+ g_return_val_if_fail (!checkbox_text || checkbox_value, GTK_RESPONSE_CANCEL);
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ /* NOTE: Due to a mozilla bug [https://bugzilla.mozilla.org/show_bug.cgi?id=306288],
+ * we will always end up without a parent!
+ */
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
+ GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
+
+ AutoWindowModalState modalState (parent);
+
+ dialog = gtk_dialog_new_with_buttons ("", gparent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ (char *) NULL);
+ if (gparent)
+ {
+ gtk_window_group_add_window (ephy_gui_ensure_window_group (gparent),
+ GTK_WINDOW (dialog));
+ }
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
+
+ higgy_setup_dialog (GTK_DIALOG (dialog),
+ GTK_STOCK_DIALOG_WARNING, &label, &vbox);
+
+ /* Add the buttons */
+ gtk_dialog_add_button (GTK_DIALOG (dialog), _("_View Certificate"),
+ NSSDIALOG_RESPONSE_VIEW_CERT);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+
+ if (affirmative_text == NULL)
+ {
+ affirmative_text = _("_Accept");
+ }
+
+ button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ affirmative_text,
+ GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+
+ if (checkbox_text)
+ {
+ checkbox = gtk_check_button_new_with_mnemonic (checkbox_text);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox),
+ *checkbox_value);
+
+ gtk_box_pack_start (GTK_BOX (vbox), checkbox, TRUE, TRUE, 0);
+ }
+ else
+ {
+ checkbox = 0;
+ }
+
+ /* We don't want focus on the checkbox */
+ gtk_widget_grab_focus (button);
+
+ gtk_label_set_markup (GTK_LABEL (label), markup_text);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+ gtk_widget_show_all (dialog);
+
+ while (1)
+ {
+ res = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (res == NSSDIALOG_RESPONSE_VIEW_CERT)
+ {
+ view_certificate (ctx, cert);
+ continue;
+ }
+
+ break;
+ }
+
+ if (res == GTK_RESPONSE_ACCEPT && checkbox)
+ {
+ *checkbox_value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox));
+ }
+
+ gtk_widget_destroy (dialog);
+ return res;
+}
+
+
+/* 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,
+ nsIX509Cert *cert, PRBool *_retval)
+{
+ char *first, *second, *msg;
+ int res;
+
+ nsString commonName;
+ cert->GetCommonName (commonName);
+
+ NS_ConvertUTF16toUTF8 cCommonName (commonName);
+
+ nsCString cTargetUrl (targetURL);
+
+ first = g_markup_printf_escaped (_("The site “%s” returned security information for "
+ "“%s”. It is possible that someone is intercepting "
+ "your communication to obtain your confidential "
+ "information."),
+ cTargetUrl.get(), cCommonName.get());
+
+ second = g_markup_printf_escaped (_("You should only accept the security information if you "
+ "trust “%s” and “%s”."),
+ cTargetUrl.get(), cCommonName.get());
+
+ msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
+ _("Accept incorrect security information?"),
+ first, second);
+
+ res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL);
+
+ g_free (second);
+ g_free (first);
+ g_free (msg);
+
+ *_retval = (res == GTK_RESPONSE_ACCEPT);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+GtkNSSDialogs::ConfirmUnknownIssuer (nsIInterfaceRequestor *ctx,
+ nsIX509Cert *cert, PRInt16 *outAddType,
+ PRBool *_retval)
+{
+ gboolean accept_perm = FALSE;
+ char *secondary, *tertiary, *msg;
+ int res;
+
+ nsString commonName;
+ cert->GetCommonName (commonName);
+
+ NS_ConvertUTF16toUTF8 cCommonName (commonName);
+
+ secondary = g_markup_printf_escaped
+ (_("It was not possible to automatically trust “%s”. "
+ "It is possible that someone is intercepting your "
+ "communication to obtain your confidential information."),
+ cCommonName.get());
+
+ tertiary = g_markup_printf_escaped
+ (_("You should only connect to the site if you are certain "
+ "you are connected to “%s”."),
+ cCommonName.get());
+
+ msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
+ _("Connect to untrusted site?"),
+ secondary, tertiary);
+
+ res = display_cert_warning_box (ctx, cert, msg,
+ _("_Trust this security information from now on"),
+ &accept_perm, _("Co_nnect"));
+ g_free (tertiary);
+ g_free (secondary);
+ g_free (msg);
+
+ if (res != GTK_RESPONSE_ACCEPT)
+ {
+ *_retval = PR_FALSE;
+ *outAddType = UNINIT_ADD_FLAG;
+ }
+ else
+ {
+ if (accept_perm)
+ {
+ *_retval = PR_TRUE;
+ *outAddType = ADD_TRUSTED_PERMANENTLY;
+ }
+ else
+ {
+ *_retval = PR_TRUE;
+ *outAddType = ADD_TRUSTED_FOR_SESSION;
+ }
+ }
+
+ return NS_OK;
+}
+
+
+/* boolean confirmCertExpired (in nsIInterfaceRequestor socketInfo,
+ in nsIX509Cert cert); */
+NS_IMETHODIMP
+GtkNSSDialogs::ConfirmCertExpired (nsIInterfaceRequestor *ctx,
+ nsIX509Cert *cert, PRBool *_retval)
+{
+ nsresult rv;
+ PRTime now = PR_Now();
+ PRTime notAfter, notBefore, timeToUse;
+ PRInt64 normalizedTime;
+ time_t t;
+ struct tm tm;
+ char formattedDate[128];
+ char *fdate;
+ const char *primary, *text;
+ char *secondary, *msg;
+
+ *_retval = PR_FALSE;
+
+ nsCOMPtr<nsIX509CertValidity> validity;
+ rv = cert->GetValidity (getter_AddRefs(validity));
+ if (NS_FAILED(rv)) return rv;
+
+ rv = validity->GetNotAfter (&notAfter);
+ if (NS_FAILED(rv)) return rv;
+
+ rv = validity->GetNotBefore (&notBefore);
+ if (NS_FAILED(rv)) return rv;
+
+ if (LL_CMP(now, >, notAfter))
+ {
+ primary = _("Accept expired security information?");
+ /* Translators: first %s is a hostname, second %s is a time/date */
+ text = _("The security information for “%s” "
+ "expired on %s.");
+ timeToUse = notAfter;
+ }
+ else
+ {
+ primary = _("Accept not yet valid security information?");
+ /* Translators: first %s is a hostname, second %s is a time/date */
+ text = _("The security information for “%s” isn't valid until %s.");
+ timeToUse = notBefore;
+ }
+
+ nsString commonName;
+ cert->GetCommonName (commonName);
+
+ NS_ConvertUTF16toUTF8 cCommonName (commonName);
+
+ LL_DIV (normalizedTime, timeToUse, PR_USEC_PER_SEC);
+ LL_L2UI (t, normalizedTime);
+ /* To translators: this a time format that is used while displaying the
+ * expiry or start date of an SSL certificate, for the format see
+ * strftime(3) */
+ strftime (formattedDate, sizeof(formattedDate), _("%a %d %b %Y"),
+ localtime_r (&t, &tm));
+ /* 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);
+
+ msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n\n%s",
+ primary, secondary,
+ _("You should ensure that your computer's time is correct."));
+
+ int res = display_cert_warning_box (ctx, cert, msg, NULL, NULL, NULL);
+
+ g_free (fdate);
+ g_free (msg);
+ g_free (secondary);
+
+ *_retval = (res == GTK_RESPONSE_ACCEPT);
+
+ return NS_OK;
+}
+
+/* void notifyCrlNextupdate (in nsIInterfaceRequestor socketInfo,
+ in AUTF8String targetURL,
+ in nsIX509Cert cert); */
+NS_IMETHODIMP
+GtkNSSDialogs::NotifyCrlNextupdate (nsIInterfaceRequestor *ctx,
+ const nsACString & targetURL,
+ nsIX509Cert *cert)
+{
+ nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
+ GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
+
+ nsCString cTargetUrl (targetURL);
+
+ nsString commonName;
+ cert->GetCommonName (commonName);
+
+ 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), EPHY_STOCK_EPHY);
+
+ g_signal_connect (dialog, "response",
+ (GCallback) gtk_widget_destroy, NULL);
+
+ gtk_widget_show_all (dialog);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GtkNSSDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor *ctx,
+ nsIX509Cert *cert,
+ PRUint32 *_trust,
+ PRBool *_retval)
+{
+ GtkWidget *dialog, *label;
+ char *msg, *primary;
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
+ GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
+
+ AutoWindowModalState modalState (parent);
+
+ dialog = gtk_dialog_new_with_buttons (_("Trust new Certificate Authority?"), gparent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ _("_View Certificate"),
+ NSSDIALOG_RESPONSE_VIEW_CERT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("_Trust CA"), GTK_RESPONSE_ACCEPT,
+ (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), EPHY_STOCK_EPHY);
+
+ higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_WARNING,
+ &label, NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+
+ nsString commonName;
+ cert->GetCommonName (commonName);
+
+ NS_ConvertUTF16toUTF8 cCommonName (commonName);
+
+ primary = g_markup_printf_escaped (_("Trust new Certificate Authority “%s” to identify web sites?"),
+ cCommonName.get());
+
+ msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
+ primary,
+ _("Before trusting a Certificate Authority (CA) you should "
+ "verify the certificate is authentic."));
+ gtk_label_set_markup (GTK_LABEL (label), msg);
+ g_free (primary);
+ g_free (msg);
+
+ gtk_widget_show_all (dialog);
+ int ret;
+
+ while (1)
+ {
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (ret == NSSDIALOG_RESPONSE_VIEW_CERT)
+ {
+ view_certificate (ctx, cert);
+ continue;
+ }
+
+ break;
+ }
+
+ if (ret != GTK_RESPONSE_ACCEPT)
+ {
+ *_retval = PR_FALSE;
+ }
+ else
+ {
+ if (ret == GTK_RESPONSE_ACCEPT)
+ {
+ *_trust |= nsIX509CertDB::TRUSTED_SSL;
+ }
+ else
+ {
+ *_trust = nsIX509CertDB::UNTRUSTED;
+ }
+
+ *_retval = PR_TRUE;
+ }
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+GtkNSSDialogs::NotifyCACertExists (nsIInterfaceRequestor *ctx)
+{
+ GtkWidget *dialog, *label;
+ char * msg;
+
+ nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
+ GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
+
+ dialog = gtk_dialog_new_with_buttons ("", gparent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK,
+ (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), EPHY_STOCK_EPHY);
+
+ higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_ERROR,
+ &label, NULL);
+
+ msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
+ _("Certificate already exists."),
+ _("The certificate has already been imported."));
+ gtk_label_set_markup (GTK_LABEL (label), msg);
+ g_free (msg);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ (GCallback)gtk_widget_destroy, NULL);
+
+ gtk_widget_show_all (dialog);
+ return NS_OK;
+}
+
+/* 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;
+ char *msg;
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
+ GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
+
+ AutoWindowModalState modalState (parent);
+
+ 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);
+
+ /* 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_markup_printf_escaped (_("Select a password to protect this certificate"));
+ gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), msg);
+ g_free (msg);
+
+ int response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_hide (dialog);
+
+ if (response == GTK_RESPONSE_ACCEPT)
+ {
+ 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);
+ }
+
+ *_retval = response == GTK_RESPONSE_ACCEPT;
+
+ gtk_widget_destroy (dialog);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GtkNSSDialogs::GetPKCS12FilePassword(nsIInterfaceRequestor *ctx,
+ nsAString &_password,
+ PRBool *_retval)
+{
+ g_print ("GtkNSSDialogs::GetPKCS12FilePassword\n");
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
+ GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
+
+ AutoWindowModalState modalState (parent);
+
+ 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") ? */
+
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+
+ /* 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));
+
+ if (response == GTK_RESPONSE_ACCEPT)
+ {
+ 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;
+}
+
+
+static void
+set_table_row (GtkWidget *table,
+ int& row,
+ const char *title,
+ const char *text)
+{
+ GtkWidget *header, *label;
+ char *bold;
+
+ if (text == NULL || text[0] == 0) return;
+
+ bold = g_markup_printf_escaped ("<b>%s</b>", title);
+ header = gtk_label_new (bold);
+ g_free (bold);
+
+ gtk_label_set_use_markup (GTK_LABEL (header), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (header), 0, 0);
+ gtk_widget_show (header);
+ gtk_table_attach (GTK_TABLE (table), header, 0, 1, row, row+1,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new (text);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_label_set_max_width_chars (GTK_LABEL (label), 48);
+ gtk_widget_show (label);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, row, row+1);
+
+ row++;
+}
+
+NS_IMETHODIMP
+GtkNSSDialogs::CrlImportStatusDialog(nsIInterfaceRequestor *ctx, nsICRLInfo *crl)
+{
+
+ GtkWidget *dialog, *label, *table, *vbox;
+ nsresult rv;
+ char *msg;
+
+ nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
+ GtkWidget *gparent = 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), EPHY_STOCK_EPHY);
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Certificate Revocation List Imported"));
+
+ /* Needed because gparent == NULL always because of mozilla sucks */
+ gtk_window_set_skip_pager_hint (GTK_WINDOW (dialog), TRUE);
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE);
+
+ higgy_setup_dialog (GTK_DIALOG (dialog), GTK_STOCK_DIALOG_INFO,
+ &label, &vbox);
+
+ msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>",
+ _("Certificate Revocation List (CRL) successfully imported"));
+ gtk_label_set_markup (GTK_LABEL (label), msg);
+ g_free (msg);
+
+ table = gtk_table_new (2, 3, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+
+ nsString org, orgUnit, nextUpdate;
+ rv = crl->GetOrganization (org);
+ if (NS_FAILED(rv)) return rv;
+
+ rv = crl->GetOrganizationalUnit (orgUnit);
+ if (NS_FAILED(rv)) return rv;
+
+ rv = crl->GetNextUpdateLocale (nextUpdate);
+ if (NS_FAILED(rv)) return rv;
+
+ int row = 0;
+ set_table_row (table, row, _("Organization:"), NS_ConvertUTF16toUTF8 (org).get ());
+
+ set_table_row (table, row, _("Unit:"), NS_ConvertUTF16toUTF8 (orgUnit).get ());
+
+ set_table_row (table, row, _("Next Update:"), NS_ConvertUTF16toUTF8 (nextUpdate).get ());
+
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (dialog);
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ (GCallback)gtk_widget_destroy, NULL);
+
+ gtk_widget_show_all (dialog);
+ return NS_OK;
+}
+
+/**
+ * Help function to fill in the labels on the General tab
+ */
+static void
+set_label_cert_attribute (GladeXML* gxml, const char* label_id, nsAString &value)
+{
+ GtkWidget *label;
+ label = glade_xml_get_widget (gxml, label_id);
+
+ g_return_if_fail (GTK_IS_LABEL (label));
+
+ if (!value.Length()) {
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ char *msg = g_strdup_printf ("<i>&lt;%s&gt;</i>",
+ _("Not part of certificate"));
+ gtk_label_set_markup (GTK_LABEL (label), msg);
+ g_free (msg);
+ }
+ else
+ {
+ gtk_label_set_use_markup (GTK_LABEL (label), FALSE);
+ gtk_label_set_text (GTK_LABEL (label), NS_ConvertUTF16toUTF8 (value).get());
+ }
+}
+
+
+/**
+ * Do that actual filling in of the certificate tree
+ */
+static gboolean
+fill_cert_chain_tree (GtkTreeView *treeview, nsIArray *certChain)
+{
+ nsresult rv;
+ GtkTreeModel * model = gtk_tree_view_get_model (treeview);
+
+ GtkTreeIter parent;
+ PRUint32 numCerts;
+ rv = certChain->GetLength (&numCerts);
+ if (NS_FAILED(rv) || numCerts < 1) return FALSE;
+
+ for (int i = (int)numCerts-1 ; i >= 0; i--)
+ {
+ nsCOMPtr<nsIX509Cert> nsCert;
+ rv = certChain->QueryElementAt (i, kX509CertCID,
+ getter_AddRefs(nsCert));
+ if (NS_FAILED(rv)) return FALSE;
+
+ GtkTreeIter iter;
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter,
+ (i == (int)numCerts-1) ? NULL : &parent);
+
+ nsString value;
+ rv = nsCert->GetCommonName (value);
+ if (NS_FAILED(rv)) return FALSE;
+
+ NS_ConvertUTF16toUTF8 cValue (value);
+
+ nsIX509Cert *nsCertP = nsCert;
+ if (value.Length())
+ {
+ gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
+ 0, cValue.get(),
+ 1, nsCertP,
+ -1);
+ }
+ else
+ {
+ char * title;
+ rv = nsCert->GetWindowTitle (&title);
+ if (NS_FAILED(rv)) return FALSE;
+
+ gtk_tree_store_set (GTK_TREE_STORE(model),
+ &iter, 0, title, 1, nsCertP, -1);
+ nsMemory::Free (title);
+ }
+ parent = iter;
+ }
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview));
+
+ /* And select the last entry, and scroll the view so it's visible */
+ GtkTreeSelection *select = gtk_tree_view_get_selection (treeview);
+ GtkTreePath *path = gtk_tree_model_get_path (model, &parent);
+ gtk_tree_selection_select_path (select, path);
+ gtk_tree_view_scroll_to_cell (treeview, path, NULL, TRUE, 0.5, 0.0);
+ gtk_tree_path_free (path);
+
+ return TRUE;
+}
+
+/**
+ * Add an ASN object to the treeview, recursing if the object was a
+ * sequence
+ */
+static void
+add_asn1_object_to_tree(GtkTreeModel *model, nsIASN1Object *object, GtkTreeIter *parent)
+{
+ nsString dispNameU;
+ object->GetDisplayName(dispNameU);
+
+ GtkTreeIter iter;
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent);
+
+ gtk_tree_store_set (GTK_TREE_STORE(model), &iter,
+ 0, NS_ConvertUTF16toUTF8 (dispNameU).get(),
+ 1, object,
+ -1);
+
+ nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object));
+ if (!sequence) return;
+
+ nsCOMPtr<nsIMutableArray> asn1Objects;
+ sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
+
+ PRUint32 numObjects;
+ asn1Objects->GetLength(&numObjects);
+ if (!asn1Objects) return;
+
+ for (PRUint32 i = 0; i < numObjects ; i++)
+ {
+ nsCOMPtr<nsIASN1Object> currObject;
+ asn1Objects->QueryElementAt (i, kASN1ObjectCID,
+ getter_AddRefs (currObject));
+ add_asn1_object_to_tree (model, currObject, &iter);
+ }
+}
+
+
+/**
+ * Update the "Certificate Fields" treeview when a different cert
+ * is selected in the hierarchy text view
+ */
+static void
+cert_chain_tree_view_selection_changed_cb (GtkTreeSelection *selection,
+ GtkWidget* tree_view)
+{
+ GtkTreeIter iter;
+ nsIX509Cert *nsCert;
+ nsresult rv;
+ GtkTreeModel * model;
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ gtk_tree_model_get (model, &iter, 1, &nsCert, -1);
+
+ nsCOMPtr<nsIASN1Object> object;
+ rv = nsCert->GetASN1Structure (getter_AddRefs(object));
+ if (NS_FAILED(rv)) return;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ gtk_tree_store_clear (GTK_TREE_STORE (model));
+ add_asn1_object_to_tree (model, object, NULL);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+ }
+}
+
+/**
+ * When the "Certificate Field" treeview is changed, update the
+ * text_view to display the value of the currently selected field
+ */
+static void
+field_tree_view_selection_changed_cb (GtkTreeSelection *selection,
+ GtkWidget* text_view)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTextBuffer * text_buffer =
+ gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ nsIASN1Object *object;
+
+ gtk_tree_model_get (model, &iter, 1, &object, -1);
+
+ nsString dispValU;
+ object->GetDisplayValue(dispValU);
+
+ gtk_text_buffer_set_text (text_buffer, NS_ConvertUTF16toUTF8 (dispValU).get(), -1);
+ }
+ else
+ {
+ gtk_text_buffer_set_text (text_buffer, "", 0);
+ }
+}
+
+/**
+ * Setup the various treeviews, the textview, and fill the treeviews
+ */
+static gboolean
+setup_view_cert_tree (GtkWidget *dialog, GladeXML*gxml, nsIArray *certChain)
+{
+ GtkCellRenderer *renderer;
+ GtkWidget *chain_tree_view, *field_tree_view, *text_view;
+ PangoFontDescription *monospace_font_desc;
+ GConfClient *conf_client;
+ char *monospace_font;
+
+ chain_tree_view = glade_xml_get_widget (gxml, "treeview_cert_chain");
+ field_tree_view = glade_xml_get_widget (gxml, "treeview_cert_info");
+ text_view = glade_xml_get_widget (gxml, "textview_field_value");
+
+ /* Setup the certificate chain view */
+ GtkTreeStore *store = gtk_tree_store_new (2,
+ G_TYPE_STRING,
+ G_TYPE_POINTER);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (chain_tree_view), GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (chain_tree_view),
+ 0, "Certificate",
+ renderer,
+ "text", 0,
+ (char *) NULL);
+
+ GtkTreeSelection *select = gtk_tree_view_get_selection (GTK_TREE_VIEW (chain_tree_view));
+ gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
+
+ g_signal_connect (G_OBJECT (select), "changed",
+ G_CALLBACK (cert_chain_tree_view_selection_changed_cb),
+ field_tree_view);
+
+ /* Setup the certificate field view */
+ store = gtk_tree_store_new (2,
+ G_TYPE_STRING,
+ G_TYPE_POINTER);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (field_tree_view), GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (field_tree_view),
+ 0, "Certificate Field",
+ renderer,
+ "text", 0,
+ (char *) NULL);
+
+ select = gtk_tree_view_get_selection (GTK_TREE_VIEW (field_tree_view));
+ gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
+
+ g_signal_connect (G_OBJECT (select), "changed",
+ G_CALLBACK (field_tree_view_selection_changed_cb),
+ text_view);
+
+ /* Get the text_view displaying a propertional font
+ *
+ * Pick up the monospace font from desktop preferences */
+ conf_client = gconf_client_get_default ();
+ monospace_font = gconf_client_get_string (conf_client,
+ "/desktop/gnome/interface/monospace_font_name", NULL);
+ if (monospace_font)
+ {
+ monospace_font_desc = pango_font_description_from_string (monospace_font);
+ gtk_widget_modify_font (text_view, monospace_font_desc);
+ pango_font_description_free (monospace_font_desc);
+ }
+ g_object_unref (conf_client);
+
+ /* And fill the certificate chain tree */
+ return fill_cert_chain_tree (GTK_TREE_VIEW (chain_tree_view), certChain);
+}
+
+/* void viewCert (in nsIX509Cert cert); */
+NS_IMETHODIMP
+GtkNSSDialogs::ViewCert(nsIInterfaceRequestor *ctx,
+ nsIX509Cert *cert)
+{
+ GtkWidget *dialog, *widget;
+ GladeXML *gxml;
+ nsString value;
+ PRUint32 verifystate, count;
+ PRUnichar ** usage;
+ GtkSizeGroup * sizegroup;
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ gxml = glade_xml_new (ephy_file ("certificate-dialogs.glade"),
+ "viewcert_dialog", NULL);
+ g_return_val_if_fail (gxml != NULL, NS_ERROR_FAILURE);
+
+ dialog = glade_xml_get_widget (gxml, "viewcert_dialog");
+ g_return_val_if_fail (dialog != NULL, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (ctx));
+ GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
+
+ AutoWindowModalState modalState (parent);
+
+ if (gparent)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(gparent));
+ gtk_window_group_add_window (ephy_gui_ensure_window_group (GTK_WINDOW (gparent)),
+ GTK_WINDOW (dialog));
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+ }
+
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Certificate Properties"));
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+
+ /* Set up the GtkSizeGroup so that the columns line up */
+ sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ widget = glade_xml_get_widget (gxml, "label_size1");
+ gtk_size_group_add_widget (sizegroup, widget);
+ widget = glade_xml_get_widget (gxml, "label_size2");
+ gtk_size_group_add_widget (sizegroup, widget);
+ widget = glade_xml_get_widget (gxml, "label_size3");
+ gtk_size_group_add_widget (sizegroup, widget);
+ widget = glade_xml_get_widget (gxml, "label_size4");
+ gtk_size_group_add_widget (sizegroup, widget);
+ g_object_unref (sizegroup);
+
+ rv = cert->GetUsagesArray (FALSE, &verifystate, &count, &usage);
+ if (NS_FAILED(rv)) return rv;
+
+ const char * text;
+ switch (verifystate)
+ {
+ case nsIX509Cert::VERIFIED_OK:
+ text = _("This certificate has been verified for the following uses:");
+ break;
+ case nsIX509Cert::CERT_REVOKED:
+ text = _("Could not verify this certificate because it has been revoked.");
+ break;
+ case nsIX509Cert::CERT_EXPIRED:
+ text = _("Could not verify this certificate because it has expired.");
+ break;
+ case nsIX509Cert::CERT_NOT_TRUSTED:
+ text = _("Could not verify this certificate because it is not trusted.");
+ break;
+ case nsIX509Cert::ISSUER_NOT_TRUSTED:
+ text = _("Could not verify this certificate because the issuer is not trusted.");
+ break;
+ case nsIX509Cert::ISSUER_UNKNOWN:
+ text = _("Could not verify this certificate because the issuer is unknown.");
+ break;
+ case nsIX509Cert::INVALID_CA:
+ text = _("Could not verify this certificate because the CA certificate is invalid.");
+ break;
+ case nsIX509Cert::NOT_VERIFIED_UNKNOWN:
+ case nsIX509Cert::USAGE_NOT_ALLOWED:
+ default:
+ text = _("Could not verify this certificate for unknown reasons.");
+ }
+
+ char *vmsg = g_strdup_printf ("<b>%s</b>", text);
+ widget = glade_xml_get_widget (gxml, "label_verify_text");
+ g_return_val_if_fail (GTK_IS_LABEL (widget), NS_ERROR_FAILURE);
+ gtk_label_set_markup (GTK_LABEL (widget), vmsg);
+ g_free (vmsg);
+
+ if (count > 0)
+ {
+ GtkWidget *vbox = gtk_vbox_new (FALSE, 3);
+ GtkWidget *indent;
+ for (PRUint32 i = 0 ; i < count ; i++)
+ {
+ 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]);
+ }
+ nsMemory::Free (usage);
+ indent = higgy_indent_widget (vbox);
+ widget = glade_xml_get_widget (gxml, "vbox_validity");
+ g_return_val_if_fail (GTK_IS_BOX (widget), NS_ERROR_FAILURE);
+
+ gtk_box_pack_start (GTK_BOX (widget), indent, FALSE, FALSE, 0);
+ }
+
+ cert->GetCommonName (value);
+ set_label_cert_attribute (gxml, "label_cn", value);
+
+ cert->GetOrganization (value);
+ set_label_cert_attribute (gxml, "label_o", value);
+
+ cert->GetOrganizationalUnit (value);
+ set_label_cert_attribute (gxml, "label_ou", value);
+
+ cert->GetSerialNumber (value);
+ set_label_cert_attribute (gxml, "label_serial", value);
+
+ rv = cert->GetIssuerCommonName (value);
+ if (NS_FAILED(rv)) return rv;
+ set_label_cert_attribute (gxml, "label_issuer_cn", value);
+
+ cert->GetIssuerOrganization (value);
+ set_label_cert_attribute (gxml, "label_issuer_o", value);
+
+ cert->GetIssuerOrganizationUnit (value);
+ set_label_cert_attribute (gxml, "label_issuer_ou", value);
+
+ nsCOMPtr<nsIX509CertValidity> validity;
+ rv = cert->GetValidity (getter_AddRefs(validity));
+ if (NS_FAILED(rv)) return rv;
+
+ rv = validity->GetNotAfterLocalDay (value);
+ if (NS_FAILED(rv)) return rv;
+ set_label_cert_attribute (gxml, "label_notafter", value);
+
+ rv = validity->GetNotBeforeLocalDay (value);
+ if (NS_FAILED(rv)) return rv;
+ set_label_cert_attribute (gxml, "label_notbefore", value);
+
+ cert->GetSha1Fingerprint (value);
+ set_label_cert_attribute (gxml, "label_sha_print", value);
+
+ cert->GetMd5Fingerprint (value);
+ set_label_cert_attribute (gxml, "label_md5_print", value);
+
+ /* Hold a reference to each certificate in the chain while the
+ * dialog is displayed, this holds the reference for the ASN
+ * objects as well */
+
+ nsCOMPtr<nsIArray> certChain;
+ rv = cert->GetChain (getter_AddRefs(certChain));
+ if (NS_FAILED(rv)) return rv;
+
+ gboolean ret = setup_view_cert_tree (dialog, gxml, certChain);
+ if (ret == FALSE) return NS_ERROR_FAILURE;
+
+ g_object_unref (gxml);
+
+ gtk_widget_show_all (dialog);
+
+ int res;
+ while (1)
+ {
+ res = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (res == GTK_RESPONSE_HELP)
+ {
+ ephy_gui_help (GTK_WINDOW (dialog), "epiphany", "using-certificate-viewer");
+ continue;
+ }
+ break;
+ }
+
+ gtk_widget_destroy (dialog);
+ return NS_OK;
+}
+
+/* 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);
+
+ AutoWindowModalState modalState (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;
+ if (status == nsIPKCS11Slot::SLOT_UNINITIALIZED) {
+ message = g_markup_printf_escaped (_("Choose a password for the “%s” token"),
+ NS_ConvertUTF16toUTF8 (aTokenName).get ());
+ } else {
+ 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);
+
+ AutoWindowModalState modalState (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);
+
+ /* Translators: A "token" is something that enables the user to authenticate himself or
+ * prove his credentials. This can be either a hardware device (e.g. a smart-card), or
+ * a data file (e.g. a cryptographic certificate).
+ */
+ 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 */
+
+static void
+SelectionChangedCallback (GtkComboBox *combo,
+ GtkDialog *dialog)
+{
+ int active = gtk_combo_box_get_active (combo);
+ gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_ACCEPT, active >= 0);
+}
+
+/* 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 *aContext,
+ const PRUnichar **tokenNameList,
+ PRUint32 count,
+ PRUnichar **_tokenName,
+ PRBool *_cancelled)
+{
+ NS_ENSURE_ARG (tokenNameList);
+ NS_ENSURE_ARG (count);
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ /* Didn't you know it? MOZILLA SUCKS! ChooseToken is always called with |aContext| == NULL! See
+ * http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/manager/ssl/src/nsKeygenHandler.cpp&rev=1.39&mark=346#346
+ * Need to investigate if we it's always called directly from code called from JS, in which case we
+ * can use EphyJSUtils::GetDOMWindowFromCallContext.
+ */
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aContext));
+ GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
+
+ AutoWindowModalState modalState (parent);
+
+ GtkWidget *dialog = gtk_message_dialog_new
+ (GTK_WINDOW (gparent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_OTHER,
+ GTK_BUTTONS_CANCEL,
+ _("Please select a token:"));
+
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
+
+ GtkWidget *combo = gtk_combo_box_new_text ();
+ for (PRUint32 i = 0; i < count; ++i) {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (combo),
+ NS_ConvertUTF16toUTF8 (tokenNameList[i]).get ());
+ }
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo), -1);
+ g_signal_connect (combo, "changed",
+ G_CALLBACK (SelectionChangedCallback), dialog);
+
+ /* FIXME: View Cert button? */
+
+ GtkWidget *vbox = GTK_MESSAGE_DIALOG (dialog)->label->parent;
+ gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("_Select"),
+ GTK_RESPONSE_ACCEPT);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
+
+ int response = gtk_dialog_run (GTK_DIALOG (dialog));
+ int selected = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+
+ gtk_widget_destroy (dialog);
+
+ *_cancelled = response != GTK_RESPONSE_ACCEPT;
+
+ if (response == GTK_RESPONSE_ACCEPT) {
+ NS_ENSURE_TRUE (selected >= 0 && selected < (int) count, NS_ERROR_FAILURE);
+ *_tokenName = NS_StringCloneData (nsDependentString (tokenNameList[selected]));
+ }
+
+ return NS_OK;
+}
+
+/* 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)
+{
+ NS_ENSURE_ARG (aEscrowAuthority);
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+#if 0
+ nsCOMPtr<nsIDOMWindow> parent (do_GetInterface (aCtx));
+#endif
+ nsCOMPtr<nsIDOMWindow> parent (EphyJSUtils::GetDOMWindowFromCallContext ());
+ GtkWidget *gparent = EphyUtils::FindGtkParent (parent);
+
+ AutoWindowModalState modalState (parent);
+
+ /* FIXME: is that guaranteed to be non-empty? */
+ nsString commonName;
+ aEscrowAuthority->GetCommonName (commonName);
+
+ GtkWidget *dialog = gtk_message_dialog_new
+ (GTK_WINDOW (gparent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING /* QUESTION really but it's also a strong warnings... */,
+ GTK_BUTTONS_NONE,
+ _("Escrow the secret key?"));
+
+ /* FIXME: If I understand the documentation of generateCRMFRequest
+ * correctly, key escrow is never used for signing keys (if it were,
+ * we'd have to warn that the cert authority can forge your signature
+ * too).
+ */
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dialog),
+ _("The certificate authority “%s” requests that you give it a copy "
+ "of the newly generated secret key.\n\n"
+ "This will enable the certificate authority read any "
+ "communications encrypted with this key "
+ "without your knowledge or consent.\n\n"
+ "It is strongly recommended not to allow it."),
+ NS_ConvertUTF16toUTF8 (commonName).get ());
+
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
+
+ GtkWidget *button = gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("_Reject"),
+ GTK_RESPONSE_REJECT);
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("_Allow"),
+ GTK_RESPONSE_ACCEPT);
+ /* FIXME: View Cert button? */
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
+ gtk_widget_grab_focus (button);
+
+ int response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ *_retval = response == GTK_RESPONSE_ACCEPT;
+
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/GtkNSSDialogs.h b/embed/xulrunner/components/GtkNSSDialogs.h
new file mode 100644
index 000000000..2edd1ffbe
--- /dev/null
+++ b/embed/xulrunner/components/GtkNSSDialogs.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx>
+ * Copyright © 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef GTKNSSDIALOGS_H
+#define GTKNSSDIALOGS_H 1
+
+#include <nsIBadCertListener.h>
+#include <nsICertificateDialogs.h>
+#include <nsITokenPasswordDialogs.h>
+#include <nsITokenDialogs.h>
+#include <nsIDOMCryptoDialogs.h>
+
+class nsIPK11Token;
+class nsIPKCS11Slot;
+
+/* 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,
+ public nsITokenPasswordDialogs,
+ public nsITokenDialogs,
+ public nsIDOMCryptoDialogs
+{
+ 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/xulrunner/components/GtkNSSKeyPairDialogs.cpp b/embed/xulrunner/components/GtkNSSKeyPairDialogs.cpp
new file mode 100644
index 000000000..ac3afdfde
--- /dev/null
+++ b/embed/xulrunner/components/GtkNSSKeyPairDialogs.cpp
@@ -0,0 +1,216 @@
+/*
+ * GtkNSSKeyPairDialogs.cpp
+ *
+ * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * This file provides Gtk implementations of the mozilla Generating Key Pair
+ * dialogs.
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkprogressbar.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkvbox.h>
+
+#include <nsIDOMWindow.h>
+#include <nsIInterfaceRequestor.h>
+#include <nsIInterfaceRequestorUtils.h>
+#include <nsIKeygenThread.h>
+#include <nsIObserver.h>
+#include <nsIServiceManager.h>
+
+#include "ephy-debug.h"
+#include "ephy-gui.h"
+#include "ephy-stock-icons.h"
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+
+#include "GtkNSSKeyPairDialogs.h"
+
+GtkNSSKeyPairDialogs::GtkNSSKeyPairDialogs ()
+{
+ LOG ("GtkNSSKeyPairDialogs ctor (%p)", this);
+}
+
+GtkNSSKeyPairDialogs::~GtkNSSKeyPairDialogs ()
+{
+ LOG ("GtkNSSKeyPairDialogs dtor (%p)", this);
+}
+
+NS_IMPL_THREADSAFE_ISUPPORTS1 (GtkNSSKeyPairDialogs,
+ nsIGeneratingKeypairInfoDialogs)
+
+class KeyPairObserver : public nsIObserver
+{
+public:
+ NS_DECL_NSIOBSERVER
+ NS_DECL_ISUPPORTS
+
+ KeyPairObserver() : close_called (FALSE) {};
+ virtual ~KeyPairObserver() {};
+
+ gboolean close_called;
+};
+
+NS_IMPL_ISUPPORTS1 (KeyPairObserver, nsIObserver);
+
+NS_IMETHODIMP KeyPairObserver::Observe (nsISupports *aSubject, const char *aTopic,
+ const PRUnichar *aData)
+{
+ close_called = TRUE;
+ return NS_OK;
+}
+
+/* ------------------------------------------------------------ */
+static void
+begin_busy (GtkWidget *widget)
+{
+ static GdkCursor *cursor = NULL;
+
+ if (cursor == NULL) cursor = gdk_cursor_new (GDK_WATCH);
+
+ 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 ();
+}
+
+static void
+end_busy (GtkWidget *widget)
+{
+ gdk_window_set_cursor (GTK_WIDGET(widget)->window, NULL);
+}
+
+
+struct KeyPairInfo
+{
+ GtkWidget *progress;
+ GtkWidget *dialog;
+ KeyPairObserver *helper;
+};
+
+
+static gboolean
+generating_timeout_cb (KeyPairInfo *info)
+{
+ gtk_progress_bar_pulse (GTK_PROGRESS_BAR (info->progress));
+
+ if (info->helper->close_called)
+ {
+ gtk_dialog_response (GTK_DIALOG (info->dialog), GTK_RESPONSE_OK);
+ }
+ return TRUE;
+}
+
+
+/* void displayGeneratingKeypairInfo (in nsIInterfaceRequestor ctx,
+ in nsIKeygenThread runnable); */
+NS_IMETHODIMP
+GtkNSSKeyPairDialogs::DisplayGeneratingKeypairInfo (nsIInterfaceRequestor *ctx,
+ nsIKeygenThread *runnable)
+{
+ GtkWidget *dialog, *progress, *label, *vbox;
+ gint timeout_id;
+
+ nsresult rv;
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return rv;
+
+ nsCOMPtr<nsIDOMWindow> parent = do_GetInterface (ctx);
+ GtkWindow *gparent = GTK_WINDOW (EphyUtils::FindGtkParent (parent));
+
+ AutoWindowModalState modalState (parent);
+
+ dialog = gtk_dialog_new_with_buttons ("", gparent,
+ GTK_DIALOG_DESTROY_WITH_PARENT, (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), EPHY_STOCK_EPHY);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
+ gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), vbox, TRUE, TRUE, 0);
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
+
+ char *msg = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s",
+ _("Generating Private Key."),
+ _("Please wait while a new private key is "
+ "generated. This process could take a few minutes." ));
+ gtk_label_set_markup (GTK_LABEL(label), msg);
+ g_free (msg);
+
+ progress = gtk_progress_bar_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), progress, TRUE, TRUE, 0);
+
+ /* Create a helper class that just waits for close events
+ * from the other thread */
+ nsCOMPtr<KeyPairObserver> helper = new KeyPairObserver;
+
+ KeyPairInfo callback_data = { progress, dialog, helper };
+ timeout_id = g_timeout_add (100, (GSourceFunc)generating_timeout_cb, &callback_data);
+
+ gtk_widget_show_all (dialog);
+ gtk_widget_hide (GTK_DIALOG (dialog)->action_area);
+
+ begin_busy (dialog);
+ runnable->StartKeyGeneration (helper);
+ int res = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (res != GTK_RESPONSE_OK && helper->close_called == FALSE)
+ {
+ /* Ignore the already_closed flag, our nsIDOMWindowInterna::Close
+ * function just sets a flag, it doesn't close the window, so we
+ * dont have a race condition */
+ PRBool already_closed = FALSE;
+ runnable->UserCanceled (&already_closed);
+ }
+
+ g_source_remove (timeout_id);
+ end_busy (dialog);
+ gtk_widget_destroy (dialog);
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/GtkNSSKeyPairDialogs.h b/embed/xulrunner/components/GtkNSSKeyPairDialogs.h
new file mode 100644
index 000000000..f4b92d9e1
--- /dev/null
+++ b/embed/xulrunner/components/GtkNSSKeyPairDialogs.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2003 Crispin Flowerday <gnome@flowerday.cx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * $Id$
+ */
+
+#ifndef GTKNSSKEYPAIRDIALOGS_H
+#define GTKNSSKEYPAIRDIALOGS_H 1
+
+#include <nsIGenKeypairInfoDlg.h>
+
+// 6a8b1aff-ae8b-4751-982e-4ce5ad544100
+#define GTK_NSSKEYPAIRDIALOGS_CID \
+ {0x6a8b1aff, 0xae8b, 0x4751, {0x98, 0x2e, 0x4c, 0xe5, 0xad, 0x54, 0x41, 0x10}}
+
+#define GTK_NSSKEYPAIRDIALOGS_CLASSNAME "Gtk NSS Key Pair Dialogs"
+
+class GtkNSSKeyPairDialogs
+: public nsIGeneratingKeypairInfoDialogs
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGENERATINGKEYPAIRINFODIALOGS
+
+ GtkNSSKeyPairDialogs();
+ virtual ~GtkNSSKeyPairDialogs();
+};
+
+
+#endif /* GTKNSSKEYPAIRDIALOGS_H */
diff --git a/embed/xulrunner/components/GtkNSSSecurityWarningDialogs.cpp b/embed/xulrunner/components/GtkNSSSecurityWarningDialogs.cpp
new file mode 100644
index 000000000..08f5e664a
--- /dev/null
+++ b/embed/xulrunner/components/GtkNSSSecurityWarningDialogs.cpp
@@ -0,0 +1,285 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright © 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Terry Hayes <thayes@netscape.com>
+ * Javier Delgadillo <javi@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****
+ *
+ * Copyright © 2005 Christian Persch
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtkbox.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkvbox.h>
+
+#include "ephy-stock-icons.h"
+
+#include <nsCOMPtr.h>
+#include <nsIDOMWindow.h>
+#include <nsIInterfaceRequestor.h>
+#include <nsIInterfaceRequestorUtils.h>
+#include <nsIPrefBranch.h>
+#include <nsIPrefService.h>
+#include <nsIServiceManager.h>
+#include <nsServiceManagerUtils.h>
+
+#include "AutoJSContextStack.h"
+#include "AutoWindowModalState.h"
+#include "EphyUtils.h"
+
+#include "GtkNSSSecurityWarningDialogs.h"
+
+NS_IMPL_THREADSAFE_ISUPPORTS1 (GtkNSSSecurityWarningDialogs, nsISecurityWarningDialogs)
+
+#define ENTER_SITE_PREF "security.warn_entering_secure"
+#define WEAK_SITE_PREF "security.warn_entering_weak"
+#define MIXEDCONTENT_PREF "security.warn_viewing_mixed"
+#define INSECURE_SUBMIT_PREF "security.warn_submit_insecure"
+
+GtkNSSSecurityWarningDialogs::GtkNSSSecurityWarningDialogs()
+{
+}
+
+GtkNSSSecurityWarningDialogs::~GtkNSSSecurityWarningDialogs()
+{
+}
+
+NS_IMETHODIMP
+GtkNSSSecurityWarningDialogs::ConfirmEnteringSecure (nsIInterfaceRequestor *aContext,
+ PRBool *_retval)
+{
+ DoDialog (aContext,
+ ENTER_SITE_PREF,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ GTK_RESPONSE_OK,
+ _("Security Notice"),
+ _("This page is loaded over a secure connection"),
+ _("For secure pages, the address entry has a distinct "
+ "color and a locked padlock icon is displayed.\n\n"
+ "The padlock icon in the statusbar also indicates "
+ "whether a page is secure."),
+ nsnull, _retval);
+
+ *_retval = PR_TRUE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GtkNSSSecurityWarningDialogs::ConfirmEnteringWeak (nsIInterfaceRequestor *aContext,
+ PRBool *_retval)
+{
+ DoDialog (aContext,
+ WEAK_SITE_PREF,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ GTK_RESPONSE_OK,
+ _("Security Warning"),
+ _("This page is loaded over a low security connection"),
+ _("Any information you see or enter on this page could "
+ "easily be intercepted by a third party."),
+ nsnull, _retval);
+
+ *_retval = PR_TRUE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GtkNSSSecurityWarningDialogs::ConfirmLeavingSecure (nsIInterfaceRequestor *aContext,
+ PRBool *_retval)
+{
+ /* don't prompt */
+ *_retval = PR_TRUE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GtkNSSSecurityWarningDialogs::ConfirmMixedMode (nsIInterfaceRequestor *aContext,
+ PRBool *_retval)
+{
+ DoDialog (aContext,
+ MIXEDCONTENT_PREF,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ GTK_RESPONSE_OK,
+ _("Security Warning"),
+ _("Some parts of this page are loaded over an insecure connection"),
+ _("Some information you see or enter will be sent over an insecure "
+ "connection, and could easily be intercepted by a third party."),
+ nsnull, _retval);
+
+ *_retval = PR_TRUE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GtkNSSSecurityWarningDialogs::ConfirmPostToInsecure (nsIInterfaceRequestor *aContext,
+ PRBool* _retval)
+{
+ DoDialog (aContext,
+ INSECURE_SUBMIT_PREF,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CANCEL,
+ GTK_RESPONSE_ACCEPT,
+ _("Security Warning"),
+ _("Send this information over an insecure connection?"),
+ _("The information you have entered will be sent over an "
+ "insecure connection, and could easily be intercepted "
+ "by a third party."),
+ _("_Send"),
+ _retval);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GtkNSSSecurityWarningDialogs::ConfirmPostToInsecureFromSecure (nsIInterfaceRequestor *aContext,
+ PRBool* _retval)
+{
+ DoDialog (aContext,
+ nsnull, /* No preference for this one - it's too important */
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ _("Security Warning"),
+ _("Send this information over an insecure connection?"),
+ _("Although this page was loaded over a secure connection, "
+ "the information you have entered will be sent over an "
+ "insecure connection, and could easily be intercepted by "
+ "a third party."),
+ _("_Send"),
+ _retval);
+
+ return NS_OK;
+}
+
+void
+GtkNSSSecurityWarningDialogs::DoDialog (nsIInterfaceRequestor *aContext,
+ const char *aPrefName,
+ GtkMessageType aType,
+ GtkButtonsType aButtons,
+ int aDefaultResponse,
+ const char *aTitle,
+ const char *aPrimary,
+ const char *aSecondary,
+ const char *aButtonText,
+ PRBool *_retval)
+{
+ *_retval = PR_FALSE;
+
+ nsresult rv;
+ PRBool show = PR_TRUE;
+ nsCOMPtr<nsIPrefBranch> prefBranch
+ (do_GetService (NS_PREFSERVICE_CONTRACTID));
+ if (prefBranch && aPrefName)
+ {
+ rv = prefBranch->GetBoolPref (aPrefName, &show);
+ if (NS_FAILED(rv)) show = PR_TRUE;
+ }
+
+ char *showOncePref = NULL;
+ PRBool showOnce = PR_FALSE;
+ if (!show && prefBranch && aPrefName)
+ {
+ showOncePref = g_strconcat (aPrefName, ".show_once", (char *) NULL);
+ rv = prefBranch->GetBoolPref (showOncePref, &showOnce);
+ if (NS_FAILED (rv)) showOnce = PR_FALSE;
+ }
+
+ if (!show && !showOnce)
+ {
+ g_free (showOncePref);
+ *_retval = PR_TRUE;
+ return;
+ }
+
+ /* On 1.8.0, domWin will be always nsnull, because of
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=277587
+ */
+ nsCOMPtr<nsIDOMWindow> domWin (do_GetInterface (aContext));
+ GtkWidget *parent = EphyUtils::FindGtkParent (domWin);
+
+ AutoJSContextStack stack;
+ rv = stack.Init ();
+ if (NS_FAILED (rv)) return;
+
+ AutoWindowModalState modalState (domWin);
+
+ GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
+ GTK_DIALOG_MODAL, aType,
+ aButtons, aPrimary);
+
+ if (parent && GTK_WINDOW (parent)->group)
+ {
+ gtk_window_group_add_window (GTK_WINDOW (parent)->group,
+ GTK_WINDOW (dialog));
+ }
+
+ if (aSecondary)
+ {
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dialog), aSecondary);
+ }
+
+ if (aButtonText)
+ {
+ gtk_dialog_add_button (GTK_DIALOG (dialog), aButtonText,
+ GTK_RESPONSE_ACCEPT);
+ }
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), aDefaultResponse);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), aTitle);
+ gtk_window_set_icon_name (GTK_WINDOW (dialog), EPHY_STOCK_EPHY);
+
+ int response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ *_retval = (response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_OK);
+
+ if (prefBranch && showOncePref && showOnce && *_retval)
+ {
+ prefBranch->SetBoolPref (showOncePref, PR_FALSE);
+ }
+
+ g_free (showOncePref);
+}
diff --git a/embed/xulrunner/components/GtkNSSSecurityWarningDialogs.h b/embed/xulrunner/components/GtkNSSSecurityWarningDialogs.h
new file mode 100644
index 000000000..a84ea6585
--- /dev/null
+++ b/embed/xulrunner/components/GtkNSSSecurityWarningDialogs.h
@@ -0,0 +1,83 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright © 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Terry Hayes <thayes@netscape.com>
+ * Javier Delgadillo <javi@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****
+ *
+ * Copyright © 2005 Christian Persch
+ *
+ * $Id$
+ */
+
+#ifndef GTK_NSSSECURITYDIALOGS_H
+#define GTK_NSSSECURITYDIALOGS_H
+
+#include <gtk/gtkmessagedialog.h>
+
+#include <nsISecurityWarningDialogs.h>
+
+#define GTK_NSSSECURITYWARNINGDIALOGS_CLASSNAME "Epiphany Security Warning Dialogs Class"
+#define GTK_NSSSECURITYWARNINGDIALOGS_CID \
+{ \
+ /* 1f5eac0a-d7e3-4f8e-b4d5-7240f7cba269 */ \
+ 0x1f5eac0a, \
+ 0xd7e3, \
+ 0x4f8e, \
+ { 0xb4, 0xd5, 0x72, 0x40, 0xf7, 0xcb, 0xa2, 0x69 } \
+}
+
+class GtkNSSSecurityWarningDialogs : public nsISecurityWarningDialogs
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISECURITYWARNINGDIALOGS
+
+ GtkNSSSecurityWarningDialogs();
+ virtual ~GtkNSSSecurityWarningDialogs();
+
+protected:
+ void DoDialog (nsIInterfaceRequestor *aContext,
+ const char *aPrefName,
+ GtkMessageType aType,
+ GtkButtonsType aButtons,
+ int aDefaultResponse,
+ const char *aTitle,
+ const char *aPrimary,
+ const char *aSecondary,
+ const char *aButtonText,
+ PRBool *_retval);
+};
+
+#endif /* !GTK_NSSSECURITYDIALOGS_H */
diff --git a/embed/xulrunner/components/Makefile.am b/embed/xulrunner/components/Makefile.am
index 53796b169..ad9b5f348 100644
--- a/embed/xulrunner/components/Makefile.am
+++ b/embed/xulrunner/components/Makefile.am
@@ -3,11 +3,75 @@ NULL =
noinst_LTLIBRARIES = libephycomponents.la
libephycomponents_la_SOURCES = \
- GeckoPromptService.cpp \
- GeckoPromptService.h \
+ ContentHandler.cpp \
+ ContentHandler.h \
+ EphyAboutModule.cpp \
+ EphyAboutModule.h \
+ EphyContentPolicy.cpp \
+ EphyContentPolicy.h \
+ EphyRedirectChannel.cpp \
+ EphyRedirectChannel.h \
+ EphySidebar.cpp \
+ EphySidebar.h \
+ GeckoCookiePromptService.cpp \
+ GeckoCookiePromptService.h \
+ GeckoFormSigningDialog.cpp \
+ GeckoFormSigningDialog.h \
+ GeckoPrintService.cpp \
+ GeckoPrintService.h \
+ GeckoPrintSession.cpp \
+ GeckoPrintSession.h \
+ GeckoPromptService.cpp \
+ GeckoPromptService.h \
+ GlobalHistory.cpp \
+ GlobalHistory.h \
+ MozDownload.cpp \
+ MozDownload.h \
+ MozRegisterComponents.cpp \
+ MozRegisterComponents.h \
$(NULL)
+# if ENABLE_FILEPICKER
+# libephycomponents_la_SOURCES += \
+# FilePicker.cpp \
+# FilePicker.h
+# endif
+
+# NOTE & FIXME: Most of these are GPL not LGPL
+# if HAVE_MOZILLA_PSM
+libephycomponents_la_SOURCES += \
+ GtkNSSClientAuthDialogs.cpp \
+ GtkNSSClientAuthDialogs.h \
+ GtkNSSDialogs.cpp \
+ GtkNSSDialogs.h \
+ GtkNSSKeyPairDialogs.cpp \
+ GtkNSSKeyPairDialogs.h \
+ GtkNSSSecurityWarningDialogs.cpp\
+ GtkNSSSecurityWarningDialogs.h
+# endif
+
+# if ENABLE_SPELLCHECKER
+libephycomponents_la_SOURCES += \
+ GeckoSpellCheckEngine.cpp \
+ GeckoSpellCheckEngine.h
+# endif
+
libephycomponents_la_CPPFLAGS = \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/embed \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/embed/xulrunner/src \
+ -I$(top_srcdir)/embed/xulrunner/embed \
+ -I$(top_srcdir)/embed/xulrunner/utils \
+ -I$(top_builddir)/embed/xulrunner/src \
+ -I$(top_builddir)/embed/xulrunner/embed \
+ -DSHARE_DIR=\"$(pkgdatadir)\" \
+ -DPLUGINDIR=\"$(libdir)/epiphany/$(EPIPHANY_MAJOR)/plugins\" \
+ -DMOZILLA_HOME=\"$(LIBXUL_LIBDIR)\" \
+ -DMOZILLA_PREFIX=\"$(LIBXUL_PREFIX)\" \
+ -DMOZILLA_NATIVE_PLUGINSDIR=\"$(libdir)/mozilla/plugins\" \
+ -DUA_VERSION=\"$(EPIPHANY_UA_VERSION)\" \
+ -DALLOW_PRIVATE_API \
$(LIBXUL_CXXCPPFLAGS) \
$(LIBXUL_INCLUDES) \
$(AM_CPPFLAGS)
@@ -15,6 +79,11 @@ libephycomponents_la_CPPFLAGS = \
libephycomponents_la_CXXFLAGS = \
$(LIBXUL_CXXFLAGS) \
$(GTK_CFLAGS) \
+ $(GTKPRINT_CFLAGS) \
+ $(GNOMEVFS_CFLAGS) \
+ $(GCONF_CFLAGS) \
+ $(GLADE_CFLAGS) \
+ $(GNOME_CFLAGS) \
$(AM_CXXFLAGS)
libephycomponents_la_LDFLAGS = \
diff --git a/embed/xulrunner/components/MozDownload.cpp b/embed/xulrunner/components/MozDownload.cpp
new file mode 100644
index 000000000..d6d28ec59
--- /dev/null
+++ b/embed/xulrunner/components/MozDownload.cpp
@@ -0,0 +1,812 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright © 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Conrad Carlen <ccarlen@netscape.com>
+ *
+ * Adapted for epiphany by Marco Pesenti Gritti <marco@gnome.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#include <nsStringGlue.h>
+
+#include <nsComponentManagerUtils.h>
+#include <nsICancelable.h>
+#include <nsIChannel.h>
+#include <nsIDOMDocument.h>
+#include <nsIFileURL.h>
+#include <nsIIOService.h>
+#include <nsILocalFile.h>
+#include <nsIMIMEInfo.h>
+#include <nsIMIMEService.h>
+#include <nsIObserver.h>
+#include <nsIRequest.h>
+#include <nsIURI.h>
+#include <nsIWritablePropertyBag2.h>
+#include <nsIWebBrowserPersist.h>
+
+#include <nsMemory.h>
+#include <nsNetError.h>
+#include <nsServiceManagerUtils.h>
+
+#include "EphyBadCertRejector.h"
+#include "EphyUtils.h"
+
+#include "eel-gconf-extensions.h"
+#include "ephy-debug.h"
+#include "ephy-file-helpers.h"
+#include "ephy-prefs.h"
+#include "mozilla-download.h"
+
+#include "MozDownload.h"
+
+/* Minimum time between progress updates */
+#define PROGRESS_RATE 500000 /* microsec */
+
+const char* const persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1";
+
+MozDownload::MozDownload() :
+ mTotalProgress(-1),
+ mCurrentProgress(0),
+ mMaxSize(-1),
+ mAddToRecent(PR_TRUE),
+ mStatus(NS_OK),
+ mEmbedPersist(nsnull),
+ mDownloadState(EPHY_DOWNLOAD_INITIALISING)
+{
+ LOG ("MozDownload ctor (%p)", (void *) this);
+}
+
+MozDownload::~MozDownload()
+{
+ LOG ("MozDownload dtor (%p)", (void *) this);
+
+ NS_ASSERTION (!mEphyDownload, "MozillaDownload still alive!");
+}
+
+NS_IMPL_ISUPPORTS4 (MozDownload,
+ nsIWebProgressListener,
+ nsIWebProgressListener2,
+ nsITransfer,
+ nsIInterfaceRequestor)
+
+nsresult
+MozDownload::InitForEmbed (nsIURI *aSource, nsIURI *aTarget, const nsAString &aDisplayName,
+ nsIMIMEInfo *aMIMEInfo, PRTime aStartTime, nsILocalFile *aTempFile,
+ nsICancelable *aCancelable, MozillaEmbedPersist *aEmbedPersist,
+ PRInt64 aMaxSize)
+{
+ mEmbedPersist = aEmbedPersist;
+ mMaxSize = aMaxSize;
+ return Init (aSource, aTarget, aDisplayName, aMIMEInfo, aStartTime, aTempFile, aCancelable);
+}
+
+/* void init (in nsIURI aSource, in nsIURI aTarget, in AString aDisplayName, in nsIMIMEInfo aMIMEInfo, in PRTime startTime, in nsILocalFile aTempFile, in nsICancelable aCancelable); */
+NS_IMETHODIMP
+MozDownload::Init (nsIURI *aSource,
+ nsIURI *aTarget,
+ const nsAString &aDisplayName,
+ nsIMIMEInfo *aMIMEInfo,
+ PRTime aStartTime,
+ nsILocalFile *aTempFile,
+ nsICancelable *aCancelable)
+{
+ PRBool addToView = PR_TRUE;
+
+ if (mEmbedPersist)
+ {
+ EphyEmbedPersistFlags flags;
+
+ flags = ephy_embed_persist_get_flags (EPHY_EMBED_PERSIST (mEmbedPersist));
+
+ addToView = !(flags & EPHY_EMBED_PERSIST_NO_VIEW);
+ }
+
+ mSource = aSource;
+ mDestination = aTarget;
+ mStartTime = aStartTime;
+ mTotalProgress = 0;
+ mCurrentProgress = 0;
+ mPercentComplete = 0;
+ mInterval = PROGRESS_RATE;
+ mLastUpdate = mStartTime;
+ mMIMEInfo = aMIMEInfo;
+ mAddToRecent = addToView;
+
+ /* This will create a refcount cycle, which needs to be broken in ::OnStateChange */
+ mCancelable = aCancelable;
+
+ if (addToView)
+ {
+ DownloaderView *dview;
+ dview = EPHY_DOWNLOADER_VIEW
+ (ephy_embed_shell_get_downloader_view (embed_shell));
+ mEphyDownload = mozilla_download_new (this);
+ g_object_add_weak_pointer (G_OBJECT (mEphyDownload),
+ (gpointer *) &mEphyDownload);
+ downloader_view_add_download (dview, mEphyDownload);
+ g_object_unref (mEphyDownload);
+ }
+ else
+ {
+ mEphyDownload = nsnull;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::GetSource(nsIURI **aSource)
+{
+ NS_ENSURE_ARG_POINTER(aSource);
+ NS_IF_ADDREF(*aSource = mSource);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::GetTargetFile (nsILocalFile** aTargetFile)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mDestination, &rv);
+ if (NS_FAILED(rv)) return rv;
+
+ nsCOMPtr<nsIFile> file;
+ rv = fileURL->GetFile(getter_AddRefs(file));
+ if (NS_SUCCEEDED(rv))
+ rv = CallQueryInterface(file, aTargetFile);
+ return rv;
+}
+
+NS_IMETHODIMP
+MozDownload::GetPercentComplete(PRInt32 *aPercentComplete)
+{
+ NS_ENSURE_ARG_POINTER(aPercentComplete);
+ *aPercentComplete = mPercentComplete;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::GetTotalProgress(PRInt64 *aTotalProgress)
+{
+ NS_ENSURE_ARG_POINTER(aTotalProgress);
+ *aTotalProgress = mTotalProgress;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::GetCurrentProgress(PRInt64 *aCurrentProgress)
+{
+ NS_ENSURE_ARG_POINTER(aCurrentProgress);
+ *aCurrentProgress = mCurrentProgress;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::GetState(EphyDownloadState *aDownloadState)
+{
+ NS_ENSURE_ARG_POINTER(aDownloadState);
+ *aDownloadState = mDownloadState;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::GetElapsedTime(PRInt64 *aElapsedTime)
+{
+ NS_ENSURE_ARG_POINTER(aElapsedTime);
+ *aElapsedTime = PR_Now() - mStartTime;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::GetMIMEInfo(nsIMIMEInfo **aMIMEInfo)
+{
+ NS_ENSURE_ARG_POINTER(aMIMEInfo);
+ NS_IF_ADDREF(*aMIMEInfo = mMIMEInfo);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::OnStateChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest,
+ PRUint32 aStateFlags, nsresult aStatus)
+{
+ nsresult rv;
+
+ if (NS_FAILED(aStatus) && NS_SUCCEEDED(mStatus))
+ mStatus = aStatus;
+
+ if (aStateFlags & STATE_START)
+ {
+ mDownloadState = EPHY_DOWNLOAD_DOWNLOADING;
+
+ if (mEphyDownload)
+ {
+ g_signal_emit_by_name (mEphyDownload, "changed");
+ }
+ }
+
+ /* We will get this even in the event of a cancel */
+ /* Due to a mozilla bug [https://bugzilla.mozilla.org/show_bug.cgi?id=304353],
+ * we'll only get STATE_STOP if we're driven from external app handler; elsewhere
+ * we get STATE_STOP | STATE_IS_NETWORK | STATE_IS_REQUEST. So check first if
+ * STATE_IS_REQUEST is set.
+ */
+ /* Be careful that download is only completed when STATE_IS_NETWORK is set
+ * and many lonely STOP events may be triggered before.
+ */
+#ifdef GNOME_ENABLE_DEBUG
+{
+ nsCString spec;
+ if (mSource) mSource->GetSpec(spec);
+
+ LOG ("url %s, status %x, state %x (is-stop:%s, is-network:%s, is-request:%s)",
+ spec.get(), aStatus, aStateFlags,
+ aStateFlags & STATE_STOP ? "t" : "f",
+ aStateFlags & STATE_IS_NETWORK ? "t" : "f",
+ aStateFlags & STATE_IS_REQUEST ? "t" : "f");
+}
+#endif
+
+ if (((aStateFlags & STATE_IS_REQUEST) &&
+ (aStateFlags & STATE_IS_NETWORK) &&
+ (aStateFlags & STATE_STOP)) ||
+ aStateFlags == STATE_STOP)
+ {
+ LOG ("STATE_STOP");
+
+ /* Keep us alive */
+ nsCOMPtr<nsITransfer> kungFuDeathGrip(this);
+
+ mDownloadState = NS_SUCCEEDED (aStatus) ? EPHY_DOWNLOAD_COMPLETED : EPHY_DOWNLOAD_FAILED;
+ if (mEphyDownload)
+ {
+ g_signal_emit_by_name (mEphyDownload, "changed");
+ }
+
+ /* break refcount cycle */
+ mCancelable = nsnull;
+
+ nsCString destSpec;
+ nsCString mimeType;
+
+ mDestination->GetSpec (destSpec);
+
+ if (NS_SUCCEEDED (aStatus) && mMIMEInfo)
+ {
+ rv = mMIMEInfo->GetMIMEType (mimeType);
+ NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE);
+ }
+
+ if (mAddToRecent)
+ {
+ ephy_file_add_recent_item (destSpec.get(), mimeType.get());
+ }
+
+ if (mEmbedPersist)
+ {
+ if (NS_SUCCEEDED (aStatus))
+ {
+ mozilla_embed_persist_completed (mEmbedPersist);
+ }
+ else
+ {
+ mozilla_embed_persist_cancelled (mEmbedPersist);
+ }
+ }
+ else if (NS_SUCCEEDED (aStatus))
+ {
+ /* see http://bugzilla.gnome.org/show_bug.cgi?id=456945 */
+#if 1 //def HAVE_GECKO_1_9
+ // FIXMEchpe fix this!
+ return NS_OK;
+#else
+ GnomeVFSMimeApplication *helperApp;
+ NS_ENSURE_TRUE (mMIMEInfo, NS_ERROR_FAILURE);
+
+ nsString description;
+ mMIMEInfo->GetApplicationDescription (description);
+
+ nsCString cDesc;
+ NS_UTF16ToCString (description, NS_CSTRING_ENCODING_UTF8, cDesc);
+
+ /* HACK we use the application description to decide
+ if we have to open the saved file */
+ if (g_str_has_prefix (cDesc.get(), "gnome-default:"))
+ {
+ /* Format gnome-default:<usertime>:<helperapp id> */
+ char **str = g_strsplit (cDesc.get(), ":", -1);
+ g_return_val_if_fail (g_strv_length (str) == 3, NS_ERROR_FAILURE);
+
+ char *end;
+ guint32 user_time = strtoul (str[1], &end, 0);
+
+ helperApp = gnome_vfs_mime_application_new_from_desktop_id (str[2]);
+ if (!helperApp) return NS_ERROR_FAILURE;
+
+ nsCString aDest;
+ rv = mDestination->GetSpec (aDest);
+ NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE);
+
+ ephy_file_launch_application (helperApp, destSpec.get (), user_time);
+
+ gnome_vfs_mime_application_free (helperApp);
+ g_strfreev (str);
+ }
+ else if (g_str_has_prefix (cDesc.get(), "gnome-browse-to-file:"))
+ {
+ /* Format gnome-browse-to-file:<usertime> */
+ char **str = g_strsplit (cDesc.get(), ":", -1);
+ g_return_val_if_fail (g_strv_length (str) == 2, NS_ERROR_FAILURE);
+
+ char *end;
+ guint32 user_time = strtoul (str[1], &end, 0);
+
+ nsCString aDest;
+ rv = mDestination->GetSpec (aDest);
+ NS_ENSURE_SUCCESS (rv, NS_ERROR_FAILURE);
+
+ ephy_file_browse_to (aDest.get (), user_time);
+
+ g_strfreev (str);
+ }
+#endif /* HAVE_GECKO_1_9 */
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::OnProgressChange (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRInt32 aCurSelfProgress,
+ PRInt32 aMaxSelfProgress,
+ PRInt32 aCurTotalProgress,
+ PRInt32 aMaxTotalProgress)
+{
+ return OnProgressChange64 (aWebProgress, aRequest,
+ aCurSelfProgress, aMaxSelfProgress,
+ aCurTotalProgress, aMaxTotalProgress);
+}
+
+/* void onProgressChange64 (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long long aCurSelfProgress, in long long aMaxSelfProgress, in long long aCurTotalProgress,
+ in long long aMaxTotalProgress); */
+NS_IMETHODIMP
+MozDownload::OnProgressChange64 (nsIWebProgress *aWebProgress,
+ nsIRequest *aRequest,
+ PRInt64 aCurSelfProgress,
+ PRInt64 aMaxSelfProgress,
+ PRInt64 aCurTotalProgress,
+ PRInt64 aMaxTotalProgress)
+{
+ if (mMaxSize >= 0 &&
+ ((aMaxTotalProgress > 0 && mMaxSize < aMaxTotalProgress) ||
+ mMaxSize < aCurTotalProgress))
+ {
+ Cancel ();
+ }
+
+ if (!mRequest)
+ mRequest = aRequest;
+
+ PRInt64 now = PR_Now ();
+
+ if ((now - mLastUpdate < mInterval) &&
+ (aMaxTotalProgress == -1 || aCurTotalProgress < aMaxTotalProgress))
+ return NS_OK;
+
+ mLastUpdate = now;
+
+ if (aMaxTotalProgress <= 0)
+ {
+ mPercentComplete = -1;
+ }
+ else
+ {
+ /* Make sure not to round up, so we don't display 100% unless
+ * it's really finished!
+ */
+ mPercentComplete = (PRInt32)(((float)aCurTotalProgress / (float)aMaxTotalProgress) * 100.0);
+ }
+
+ mTotalProgress = aMaxTotalProgress;
+ mCurrentProgress = aCurTotalProgress;
+
+ if (mEphyDownload)
+ {
+ g_signal_emit_by_name (mEphyDownload, "changed");
+ }
+
+ return NS_OK;
+}
+
+/* boolean onRefreshAttempted (in nsIWebProgress aWebProgress, in nsIURI aRefreshURI, in long aDelay, in boolean aSameURI); */
+NS_IMETHODIMP
+MozDownload::OnRefreshAttempted(nsIWebProgress *aWebProgress,
+ nsIURI *aUri,
+ PRInt32 aDelay,
+ PRBool aSameUri,
+ PRBool *allowRefresh)
+{
+ *allowRefresh = PR_TRUE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::OnLocationChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::OnStatusChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest,
+ nsresult aStatus, const PRUnichar *aMessage)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MozDownload::OnSecurityChange (nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
+{
+ return NS_OK;
+}
+
+/* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
+NS_IMETHODIMP
+MozDownload::GetInterface(const nsIID & uuid, void * *result)
+{
+ if (uuid.Equals (NS_GET_IID (nsIBadCertListener)) &&
+ mEmbedPersist)
+ {
+ EphyEmbedPersistFlags flags;
+
+ g_object_get (mEmbedPersist, "flags", &flags, (char *) NULL);
+
+ if (flags & EPHY_EMBED_PERSIST_NO_CERTDIALOGS)
+ {
+ nsIBadCertListener *badCertRejector = new EphyBadCertRejector ();
+ if (!badCertRejector) return NS_ERROR_OUT_OF_MEMORY;
+
+ *result = badCertRejector;
+ NS_ADDREF (badCertRejector);
+
+ return NS_OK;
+ }
+ }
+
+ return NS_ERROR_NO_INTERFACE;
+}
+
+void
+MozDownload::Cancel()
+{
+ if (mDownloadState != EPHY_DOWNLOAD_DOWNLOADING &&
+ mDownloadState != EPHY_DOWNLOAD_PAUSED)
+ {
+ return;
+ }
+
+ if (mCancelable)
+ {
+ /* FIXME: error code? */
+ mCancelable->Cancel (NS_BINDING_ABORTED);
+ }
+}
+
+void
+MozDownload::Pause()
+{
+ if (mRequest)
+ {
+ mRequest->Suspend ();
+ mDownloadState = EPHY_DOWNLOAD_PAUSED;
+ }
+}
+
+void
+MozDownload::Resume()
+{
+ if (mRequest)
+ {
+ mRequest->Resume ();
+ mDownloadState = EPHY_DOWNLOAD_DOWNLOADING;
+ }
+}
+
+nsresult InitiateMozillaDownload (nsIDOMDocument *domDocument, nsIURI *sourceURI,
+ nsILocalFile* inDestFile, const char *contentType,
+ nsIURI* inOriginalURI, MozillaEmbedPersist *embedPersist,
+ nsIInputStream *postData, nsISupports *aCacheKey,
+ PRInt64 aMaxSize)
+{
+ nsresult rv = NS_OK;
+
+ EphyEmbedPersistFlags ephy_flags;
+ ephy_flags = ephy_embed_persist_get_flags (EPHY_EMBED_PERSIST (embedPersist));
+
+ if (!ephy_embed_persist_get_dest (EPHY_EMBED_PERSIST (embedPersist)))
+ {
+ nsCString cPath;
+ inDestFile->GetNativePath (cPath);
+
+ ephy_embed_persist_set_dest (EPHY_EMBED_PERSIST (embedPersist),
+ cPath.get());
+ }
+
+ nsCOMPtr<nsIMIMEService> mimeService (do_GetService ("@mozilla.org/mime;1"));
+ nsCOMPtr<nsIMIMEInfo> mimeInfo;
+ if (mimeService)
+ {
+ mimeService->GetFromTypeAndExtension (nsCString(contentType),
+ nsCString(),
+ getter_AddRefs (mimeInfo));
+ }
+
+ PRBool isHTML = (contentType &&
+ (strcmp (contentType, "text/html") == 0 ||
+ strcmp (contentType, "text/xml") == 0 ||
+ strcmp (contentType, "application/xhtml+xml") == 0));
+
+ nsCOMPtr<nsIWebBrowserPersist> webPersist (do_CreateInstance(persistContractID, &rv));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ PRInt64 timeNow = PR_Now();
+
+ nsString fileDisplayName;
+ inDestFile->GetLeafName(fileDisplayName);
+
+ nsCOMPtr<nsIIOService> ioService;
+ rv = EphyUtils::GetIOService (getter_AddRefs (ioService));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIURI> destURI;
+ ioService->NewFileURI (inDestFile, getter_AddRefs(destURI));
+
+ MozDownload *downloader = new MozDownload ();
+ /* dlListener attaches to its progress dialog here, which gains ownership */
+ /* FIXME is that still true? */
+ rv = downloader->InitForEmbed (inOriginalURI, destURI, fileDisplayName,
+ mimeInfo, timeNow, nsnull, webPersist, embedPersist, aMaxSize);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = webPersist->SetProgressListener (downloader);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ PRInt32 flags = nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES;
+
+ if (!domDocument && !isHTML && !(ephy_flags & EPHY_EMBED_PERSIST_COPY_PAGE) &&
+ !(ephy_flags & EPHY_EMBED_PERSIST_DO_CONVERSION))
+ {
+ flags |= nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION;
+ }
+ if (ephy_flags & EPHY_EMBED_PERSIST_COPY_PAGE)
+ {
+ flags |= nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
+ }
+ webPersist->SetPersistFlags(flags);
+
+ /* Create a new tagged channel if we need to block cookies from server */
+ if (ephy_flags & EPHY_EMBED_PERSIST_NO_COOKIES)
+ {
+ nsCOMPtr<nsIChannel> tmpChannel;
+ rv = ioService->NewChannelFromURI (sourceURI, getter_AddRefs (tmpChannel));
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(tmpChannel);
+ rv = props->SetPropertyAsBool (NS_LITERAL_STRING("epiphany-blocking-cookies"), PR_TRUE);
+ NS_ENSURE_SUCCESS (rv, rv);
+
+ rv = webPersist->SaveChannel (tmpChannel, inDestFile);
+ }
+ else if (!domDocument || !isHTML || ephy_flags & EPHY_EMBED_PERSIST_COPY_PAGE)
+ {
+ rv = webPersist->SaveURI (sourceURI, aCacheKey, nsnull,
+ postData, nsnull, inDestFile);
+ }
+ else
+ {
+ PRInt32 encodingFlags = 0;
+ nsCOMPtr<nsILocalFile> filesFolder;
+
+ /**
+ * Construct a directory path to hold the associated files; mozilla
+ * will create the directory as needed.
+ */
+
+ nsCString cPath;
+ inDestFile->GetNativePath (cPath);
+
+ char *basename = g_path_get_basename (cPath.get());
+ char *dirname = g_path_get_dirname (cPath.get());
+ char *dot_pos = strchr (basename, '.');
+ if (dot_pos)
+ {
+ *dot_pos = 0;
+ }
+ /* translators: this is the directory name to store auxilary files when saving html files */
+ char *new_basename = g_strdup_printf (_("%s Files"), basename);
+ char *new_path = g_build_filename (dirname, new_basename, NULL);
+ g_free (new_basename);
+ g_free (basename);
+ g_free (dirname);
+
+ filesFolder = do_CreateInstance ("@mozilla.org/file/local;1");
+ filesFolder->InitWithNativePath (nsCString(new_path));
+
+ g_free (new_path);
+
+ rv = webPersist->SaveDocument (domDocument, inDestFile, filesFolder,
+ contentType, encodingFlags, 80);
+ }
+
+ return rv;
+}
+
+static char*
+GetFilePath (const char *filename)
+{
+ const char *home_dir;
+ char *download_dir, *path;
+
+ download_dir = ephy_file_get_downloads_dir ();
+
+ if (ephy_ensure_dir_exists (download_dir, NULL))
+ {
+ path = g_build_filename (download_dir, filename, (char *) NULL);
+ }
+ else
+ {
+ home_dir = g_get_home_dir ();
+ path = g_build_filename (home_dir ? home_dir : "/", filename, (char *) NULL);
+ }
+ g_free (download_dir);
+
+ return path;
+}
+
+static const char*
+file_is_compressed (const char *filename)
+{
+ int i;
+ static const char * const compression[] = {".gz", ".bz2", ".Z", ".lz", NULL};
+
+ for (i = 0; compression[i] != NULL; i++)
+ {
+ if (g_str_has_suffix (filename, compression[i]))
+ return compression[i];
+ }
+
+ return NULL;
+}
+
+static const char*
+parse_extension (const char *filename)
+{
+ const char *compression;
+
+ compression = file_is_compressed (filename);
+
+ /* If the file is compressed we might have a double extension */
+ if (compression != NULL)
+ {
+ int i;
+ static const char * const extensions[] = {"tar", "ps", "xcf", "dvi", "txt", "text", NULL};
+
+ for (i = 0; extensions[i] != NULL; i++)
+ {
+ char *suffix;
+ suffix = g_strdup_printf (".%s%s", extensions[i],
+ compression);
+
+ if (g_str_has_suffix (filename, suffix))
+ {
+ char *p;
+
+ p = g_strrstr (filename, suffix);
+ g_free (suffix);
+
+ return p;
+ }
+
+ g_free (suffix);
+ }
+ }
+
+ /* default case */
+ return g_strrstr (filename, ".");
+}
+
+nsresult BuildDownloadPath (const char *defaultFileName, nsILocalFile **_retval)
+{
+ char *path;
+
+ path = GetFilePath (defaultFileName);
+
+ if (g_file_test (path, G_FILE_TEST_EXISTS))
+ {
+ int i = 1;
+ const char *dot_pos;
+ char *serial = NULL;
+ GString *tmp_path;
+ gssize position;
+
+ dot_pos = parse_extension (defaultFileName);
+ if (dot_pos)
+ {
+ position = dot_pos - defaultFileName;
+ }
+ else
+ {
+ position = strlen (defaultFileName);
+ }
+ tmp_path = g_string_new (NULL);
+
+ do {
+ g_free (path);
+ g_string_assign (tmp_path, defaultFileName);
+ serial = g_strdup_printf ("(%d)", i++);
+ g_string_insert (tmp_path, position, serial);
+ g_free (serial);
+ path = GetFilePath (tmp_path->str);
+
+ } while (g_file_test (path, G_FILE_TEST_EXISTS));
+
+ g_string_free (tmp_path, TRUE);
+ }
+
+ nsCOMPtr <nsILocalFile> destFile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
+ NS_ENSURE_TRUE (destFile, NS_ERROR_FAILURE);
+
+ destFile->InitWithNativePath (nsCString (path));
+ g_free (path);
+
+ NS_IF_ADDREF (*_retval = destFile);
+ return NS_OK;
+}
diff --git a/embed/xulrunner/components/MozDownload.h b/embed/xulrunner/components/MozDownload.h
new file mode 100644
index 000000000..27fef41c7
--- /dev/null
+++ b/embed/xulrunner/components/MozDownload.h
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright © 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Conrad Carlen <ccarlen@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****
+ *
+ * $Id$
+ */
+
+#ifndef MozDownload_h__
+#define MozDownload_h__
+
+#include <libgnomevfs/gnome-vfs-mime-handlers.h>
+
+#include <nsCOMPtr.h>
+#include <nsIInterfaceRequestor.h>
+#include <nsITransfer.h>
+#include <nsIWebProgressListener.h>
+
+#include "mozilla-embed-persist.h"
+#include "downloader-view.h"
+#include "ephy-download.h"
+#include "ephy-embed-shell.h"
+
+class nsICancelable;
+class nsIDOMDocument;
+class nsIInputStream;
+class nsILocalFile;
+class nsIMIMEInfo;
+class nsIObserver;
+class nsIRequest;
+class nsIURI;
+class nsIWebBrowserPersist;
+
+/* MozDownload
+ Holds information used to display a single download in the UI. This object is
+ created in one of two ways:
+ (1) By nsExternalHelperAppHandler when Gecko encounters a MIME type which
+ it doesn't itself handle. In this case, the notifications sent to
+ nsIDownload are controlled by nsExternalHelperAppHandler.
+ (2) By the embedding app's file saving code when saving a web page or a link
+ target. See CHeaderSniffer.cpp. In this case, the notifications sent to
+ nsIDownload are controlled by the implementation of nsIWebBrowserPersist.
+*/
+
+#define MOZ_DOWNLOAD_CID \
+{ /* d2a2f743-f126-4f1f-1234-d4e50490f112 */ \
+ 0xd2a2f743, \
+ 0xf126, \
+ 0x4f1f, \
+ {0x12, 0x34, 0xd4, 0xe5, 0x04, 0x90, 0xf1, 0x12} \
+}
+
+#define MOZ_DOWNLOAD_CLASSNAME "Ephy's Download Progress Dialog"
+
+nsresult InitiateMozillaDownload (nsIDOMDocument *domDocument, nsIURI *sourceUri,
+ nsILocalFile* inDestFile, const char *contentType,
+ nsIURI* inOriginalURI, MozillaEmbedPersist *embedPersist,
+ nsIInputStream *postData, nsISupports *aCacheKey,
+ PRInt64 aMaxSize);
+nsresult BuildDownloadPath (const char *defaultFileName, nsILocalFile **_retval);
+
+class MozDownload : public nsITransfer,
+ public nsIInterfaceRequestor
+{
+public:
+ MozDownload();
+ virtual ~MozDownload();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIWEBPROGRESSLISTENER
+ NS_DECL_NSIWEBPROGRESSLISTENER2
+ NS_DECL_NSITRANSFER
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+ nsresult GetMIMEInfo (nsIMIMEInfo **aMIMEInfo);
+ nsresult GetTargetFile (nsILocalFile **aFile);
+ nsresult GetSource(nsIURI * *aSource);
+ nsresult GetPercentComplete(PRInt32 *aPercentComplete);
+
+ virtual void Cancel();
+ virtual void Pause();
+ virtual void Resume();
+
+ nsresult GetState (EphyDownloadState *aDownloadState);
+ nsresult GetCurrentProgress (PRInt64 *aCurrentProgress);
+ nsresult GetTotalProgress (PRInt64 *aTProgress);
+ nsresult GetElapsedTime (PRInt64 *aTProgress);
+
+ nsresult InitForEmbed (nsIURI *aSource, nsIURI *aTarget,
+ const nsAString &aDisplayName, nsIMIMEInfo *aMIMEInfo,
+ PRTime aStartTime, nsILocalFile *aTempFile,
+ nsICancelable *aCancelable, MozillaEmbedPersist *aEmbedPersist,
+ PRInt64 aMaxSize);
+
+protected:
+ nsCOMPtr<nsIURI> mSource;
+ nsCOMPtr<nsIURI> mDestination;
+
+ nsCOMPtr<nsIMIMEInfo> mMIMEInfo;
+ PRTime mStartTime;
+ PRTime mLastUpdate;
+ PRInt64 mElapsed;
+ PRInt32 mInterval;
+ PRInt32 mPercentComplete;
+ PRInt64 mTotalProgress;
+ PRInt64 mCurrentProgress;
+ PRInt64 mMaxSize;
+ PRBool mAddToRecent;
+
+ nsresult mStatus;
+
+ nsCOMPtr<nsICancelable> mCancelable;
+ nsCOMPtr<nsIRequest> mRequest;
+ EphyDownload *mEphyDownload;
+ DownloaderView *mDownloaderView;
+ MozillaEmbedPersist *mEmbedPersist;
+ EphyDownloadState mDownloadState;
+};
+
+#endif // MozDownload_h__
diff --git a/embed/xulrunner/components/MozRegisterComponents.cpp b/embed/xulrunner/components/MozRegisterComponents.cpp
new file mode 100644
index 000000000..0ff0014d7
--- /dev/null
+++ b/embed/xulrunner/components/MozRegisterComponents.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright © 2001,2002,2003 Philip Langdale
+ * Copyright © 2003 Marco Pesenti Gritti
+ * Copyright © 2004, 2005, 2006, 2007 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <xpcom-config.h>
+#include "config.h"
+
+#include <glib/gmessages.h>
+
+#include <nsStringGlue.h>
+
+#include <nsComponentManagerUtils.h>
+#include <nsCOMPtr.h>
+#include <nsCURILoader.h>
+#include <nsDocShellCID.h>
+#include <nsICategoryManager.h>
+#include <nsIClassInfoImpl.h>
+#include <nsIComponentManager.h>
+#include <nsIComponentRegistrar.h>
+#include <nsIGenericFactory.h>
+#include <nsILocalFile.h>
+#include <nsIScriptNameSpaceManager.h>
+#include <nsIServiceManager.h>
+#include <nsMemory.h>
+#include <nsNetCID.h>
+#include <nsServiceManagerUtils.h>
+
+#define HAVE_MOZILLA_PSM
+
+#ifdef HAVE_MOZILLA_PSM
+#include <nsISecureBrowserUI.h>
+#endif
+
+#include "ContentHandler.h"
+#include "EphyAboutModule.h"
+#include "EphyContentPolicy.h"
+#include "EphySidebar.h"
+#include "GeckoCookiePromptService.h"
+#include "GeckoPrintService.h"
+#include "GeckoPrintSession.h"
+#include "GeckoPromptService.h"
+#include "GlobalHistory.h"
+#include "MozDownload.h"
+
+#ifdef ENABLE_FILEPICKER
+#include "FilePicker.h"
+#endif
+
+#ifdef ENABLE_SPELLCHECKER
+#include "GeckoSpellCheckEngine.h"
+#endif
+
+#ifdef HAVE_MOZILLA_PSM
+#include "GtkNSSClientAuthDialogs.h"
+#include "GtkNSSDialogs.h"
+#include "GtkNSSKeyPairDialogs.h"
+#include "GtkNSSSecurityWarningDialogs.h"
+#include "GeckoFormSigningDialog.h"
+#endif
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(EphyAboutModule)
+NS_GENERIC_FACTORY_CONSTRUCTOR(EphyContentPolicy)
+NS_GENERIC_FACTORY_CONSTRUCTOR(EphySidebar)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GContentHandler)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoCookiePromptService)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoPrintService)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoPrintSession)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoPromptService)
+NS_GENERIC_FACTORY_CONSTRUCTOR(MozDownload)
+NS_GENERIC_FACTORY_CONSTRUCTOR(MozGlobalHistory)
+
+#ifdef ENABLE_FILEPICKER
+NS_GENERIC_FACTORY_CONSTRUCTOR(GFilePicker)
+#endif
+
+#ifdef ENABLE_SPELLCHECKER
+NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoSpellCheckEngine)
+#endif
+
+#ifdef HAVE_MOZILLA_PSM
+NS_GENERIC_FACTORY_CONSTRUCTOR(GtkNSSClientAuthDialogs)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GtkNSSDialogs)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GtkNSSKeyPairDialogs)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GtkNSSSecurityWarningDialogs)
+NS_GENERIC_FACTORY_CONSTRUCTOR(GeckoFormSigningDialog)
+#endif
+
+#define XPINSTALL_CONTRACTID NS_CONTENT_HANDLER_CONTRACTID_PREFIX "application/x-xpinstall"
+
+/* class information */
+NS_DECL_CLASSINFO(EphySidebar)
+
+/* FIXME: uninstall XPI handler */
+
+static const nsModuleComponentInfo sAppComps[] = {
+ {
+ MOZ_DOWNLOAD_CLASSNAME,
+ MOZ_DOWNLOAD_CID,
+#ifdef NS_TRANSFER_CONTRACTID
+ NS_TRANSFER_CONTRACTID,
+#else
+ NS_DOWNLOAD_CONTRACTID,
+#endif
+ MozDownloadConstructor
+ },
+#ifdef ENABLE_FILEPICKER
+ {
+ G_FILEPICKER_CLASSNAME,
+ G_FILEPICKER_CID,
+ G_FILEPICKER_CONTRACTID,
+ GFilePickerConstructor
+ },
+#endif
+#ifdef HAVE_MOZILLA_PSM
+ {
+ GTK_NSSCLIENTAUTHDIALOGS_CLASSNAME,
+ GTK_NSSCLIENTAUTHDIALOGS_CID,
+ NS_CLIENTAUTHDIALOGS_CONTRACTID,
+ GtkNSSClientAuthDialogsConstructor
+ },
+ {
+ GTK_NSSDIALOGS_CLASSNAME,
+ GTK_NSSDIALOGS_CID,
+ NS_BADCERTLISTENER_CONTRACTID,
+ GtkNSSDialogsConstructor
+ },
+ {
+ GTK_NSSDIALOGS_CLASSNAME,
+ GTK_NSSDIALOGS_CID,
+ NS_CERTIFICATEDIALOGS_CONTRACTID,
+ GtkNSSDialogsConstructor
+ },
+ {
+ GTK_NSSDIALOGS_CLASSNAME,
+ GTK_NSSDIALOGS_CID,
+ NS_DOMCRYPTODIALOGS_CONTRACTID,
+ GtkNSSDialogsConstructor
+ },
+ {
+ GTK_NSSDIALOGS_CLASSNAME,
+ GTK_NSSDIALOGS_CID,
+ NS_TOKENDIALOGS_CONTRACTID,
+ GtkNSSDialogsConstructor
+ },
+ {
+ GTK_NSSDIALOGS_CLASSNAME,
+ GTK_NSSDIALOGS_CID,
+ NS_TOKENPASSWORDSDIALOG_CONTRACTID,
+ GtkNSSDialogsConstructor
+ },
+ {
+ GTK_NSSKEYPAIRDIALOGS_CLASSNAME,
+ GTK_NSSKEYPAIRDIALOGS_CID,
+ NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID,
+ GtkNSSKeyPairDialogsConstructor
+ },
+ {
+ GTK_NSSSECURITYWARNINGDIALOGS_CLASSNAME,
+ GTK_NSSSECURITYWARNINGDIALOGS_CID,
+ NS_SECURITYWARNINGDIALOGS_CONTRACTID,
+ GtkNSSSecurityWarningDialogsConstructor
+ },
+ {
+ GECKO_FORMSIGNINGDIALOGS_CLASSNAME,
+ GECKO_FORMSIGNINGDIALOGS_CID,
+ NS_FORMSIGNINGDIALOG_CONTRACTID,
+ GeckoFormSigningDialogConstructor
+ },
+#endif /* HAVE_MOZILLA_PSM */
+ {
+ NS_IHELPERAPPLAUNCHERDLG_CLASSNAME,
+ G_CONTENTHANDLER_CID,
+ NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
+ GContentHandlerConstructor
+ },
+ {
+ EPHY_GLOBALHISTORY_CLASSNAME,
+ EPHY_GLOBALHISTORY_CID,
+ NS_GLOBALHISTORY2_CONTRACTID,
+ MozGlobalHistoryConstructor
+ },
+ {
+ GECKO_PRINT_SERVICE_CLASSNAME,
+ GECKO_PRINT_SERVICE_IID,
+ "@mozilla.org/embedcomp/printingprompt-service;1",
+ GeckoPrintServiceConstructor
+ },
+ {
+ GECKO_PRINT_SESSION_CLASSNAME,
+ GECKO_PRINT_SESSION_IID,
+ "@mozilla.org/gfx/printsession;1",
+ GeckoPrintSessionConstructor
+ },
+ {
+ EPHY_CONTENT_POLICY_CLASSNAME,
+ EPHY_CONTENT_POLICY_CID,
+ EPHY_CONTENT_POLICY_CONTRACTID,
+ EphyContentPolicyConstructor,
+ EphyContentPolicy::Register,
+ EphyContentPolicy::Unregister
+ },
+ {
+ EPHY_SIDEBAR_CLASSNAME,
+ EPHY_SIDEBAR_CID,
+ NS_SIDEBAR_CONTRACTID,
+ EphySidebarConstructor,
+ EphySidebar::Register,
+ EphySidebar::Unregister,
+ nsnull /* no factory destructor */,
+ NS_CI_INTERFACE_GETTER_NAME(EphySidebar),
+ nsnull /* no language helper */,
+ &NS_CLASSINFO_NAME(EphySidebar),
+ nsIClassInfo::DOM_OBJECT
+ },
+ {
+ EPHY_ABOUT_EPIPHANY_CLASSNAME,
+ EPHY_ABOUT_MODULE_CID,
+ EPHY_ABOUT_EPIPHANY_CONTRACTID,
+ EphyAboutModuleConstructor
+ },
+ {
+ EPHY_ABOUT_RECOVER_CLASSNAME,
+ EPHY_ABOUT_MODULE_CID,
+ EPHY_ABOUT_RECOVER_CONTRACTID,
+ EphyAboutModuleConstructor
+ },
+ {
+ EPHY_ABOUT_NETERROR_CLASSNAME,
+ EPHY_ABOUT_MODULE_CID,
+ EPHY_ABOUT_NETERROR_CONTRACTID,
+ EphyAboutModuleConstructor
+ },
+ {
+ GECKO_PROMPT_SERVICE_CLASSNAME,
+ GECKO_PROMPT_SERVICE_CID,
+ "@mozilla.org/embedcomp/prompt-service;1",
+ GeckoPromptServiceConstructor
+ },
+ {
+ GECKO_PROMPT_SERVICE_CLASSNAME,
+ GECKO_PROMPT_SERVICE_CID,
+ "@mozilla.org/embedcomp/nbalert-service;1",
+ GeckoPromptServiceConstructor
+ },
+#ifdef ENABLE_SPELLCHECKER
+ {
+ GECKO_SPELL_CHECK_ENGINE_CLASSNAME,
+ GECKO_SPELL_CHECK_ENGINE_IID,
+ GECKO_SPELL_CHECK_ENGINE_CONTRACTID,
+ GeckoSpellCheckEngineConstructor
+ },
+#endif /* ENABLE_SPELLCHECK */
+ {
+ EPHY_COOKIEPROMPTSERVICE_CLASSNAME,
+ EPHY_COOKIEPROMPTSERVICE_CID,
+ EPHY_COOKIEPROMPTSERVICE_CONTRACTID,
+ GeckoCookiePromptServiceConstructor
+ }
+};
+
+gboolean
+mozilla_register_components (void)
+{
+ gboolean ret = TRUE;
+ nsresult rv;
+
+ nsCOMPtr<nsIComponentRegistrar> cr;
+ NS_GetComponentRegistrar(getter_AddRefs(cr));
+ NS_ENSURE_TRUE (cr, FALSE);
+
+ nsCOMPtr<nsIComponentManager> cm;
+ NS_GetComponentManager (getter_AddRefs (cm));
+ NS_ENSURE_TRUE (cm, FALSE);
+
+ for (guint i = 0; i < G_N_ELEMENTS (sAppComps); i++)
+ {
+ nsCOMPtr<nsIGenericFactory> componentFactory;
+ rv = NS_NewGenericFactory(getter_AddRefs(componentFactory),
+ &(sAppComps[i]));
+ if (NS_FAILED(rv) || !componentFactory)
+ {
+ g_warning ("Failed to make a factory for %s\n", sAppComps[i].mDescription);
+
+ ret = FALSE;
+ continue; // don't abort registering other components
+ }
+
+ rv = cr->RegisterFactory(sAppComps[i].mCID,
+ sAppComps[i].mDescription,
+ sAppComps[i].mContractID,
+ componentFactory);
+ if (NS_FAILED(rv))
+ {
+ g_warning ("Failed to register %s\n", sAppComps[i].mDescription);
+
+ ret = FALSE;
+ }
+
+ if (sAppComps[i].mRegisterSelfProc)
+ {
+ rv = sAppComps[i].mRegisterSelfProc (cm, nsnull, nsnull, nsnull, &sAppComps[i]);
+
+ if (NS_FAILED (rv))
+ {
+ g_warning ("Failed to register-self for %s\n", sAppComps[i].mDescription);
+ ret = FALSE;
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/embed/xulrunner/components/MozRegisterComponents.h b/embed/xulrunner/components/MozRegisterComponents.h
new file mode 100644
index 000000000..e8e086f3b
--- /dev/null
+++ b/embed/xulrunner/components/MozRegisterComponents.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2001 Philip Langdale
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef MOZREGISTERCOMPONENTS_H
+#define MOZREGISTERCOMPONENTS_H
+
+#include <glib.h>
+
+gboolean mozilla_register_components (void);
+
+#endif /* MOZREGISTERCOMPONENTS_H */