/* * Copyright (C) 2001 Matt Aubury, Philip Langdale * Copyright (C) 2004 Crispin Flowerday * Copyright (C) 2005 Christian Persch * Copyright (C) 2005 Adam Hooper * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id$ */ #include "mozilla-config.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "EphyAboutModule.h" #include "EphyUtils.h" #include "ephy-debug.h" #include 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 (), "epiphany", strlen ("epiphany")) == 0) { return Redirect (nsDependentCString ("file://" SHARE_DIR "/epiphany.xhtml"), _retval); } return NS_ERROR_ILLEGAL_VALUE; } /* private functions */ nsresult EphyAboutModule::Redirect(const nsACString &aURL, nsIChannel **_retval) { nsresult rv; nsCOMPtr ioService; rv = EphyUtils::GetIOService (getter_AddRefs (ioService)); NS_ENSURE_SUCCESS (rv, rv); nsCOMPtr tempChannel; rv = ioService->NewChannel(aURL, nsnull, nsnull, getter_AddRefs(tempChannel)); NS_ENSURE_SUCCESS (rv, rv); nsCOMPtr uri; rv = ioService->NewURI(aURL, nsnull, nsnull, getter_AddRefs(uri)); NS_ENSURE_SUCCESS (rv, rv); tempChannel->SetOriginalURI (uri); nsCOMPtr securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS (rv, rv); nsCOMPtr principal; rv = securityManager->GetCodebasePrincipal(uri, getter_AddRefs(principal)); NS_ENSURE_SUCCESS (rv, rv); rv = tempChannel->SetOwner(principal); NS_ENSURE_SUCCESS (rv, rv); NS_ADDREF(*_retval = tempChannel); return rv; } nsresult EphyAboutModule::ParseErrorURL(const char *aURL, nsACString &aError, nsACString &aRawOriginURL, nsACString &aOriginURL, nsACString &aOriginCharset) { /* The error page URL is of the form "epiphany:error?e=&u=&c=&d=" */ 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; for (PRUint32 i = 0; params[i] != NULL; ++i) { char *param = params[i]; if (strlen (param) <= 2) continue; switch (param[0]) { case 'e': aError.Assign (nsUnescape (param + 2)); break; case 'u': aRawOriginURL.Assign (param + 2); aOriginURL.Assign (nsUnescape (param + 2)); break; case 'c': aOriginCharset.Assign (nsUnescape (param + 2)); 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 **aPrimary, char **aSecondary, char **aTertiary, char **aLinkIntro) { if (strcmp (aError, "protocolNotFound") == 0) { nsCAutoString scheme; aURI->GetScheme (scheme); /* 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 = _("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" */ *aPrimary = g_markup_printf_escaped (_("File “%s” not found."), path.get()); *aSecondary = _("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" */ *aPrimary = g_markup_printf_escaped (_("“%s” could not be found."), host.get()); *aSecondary = _("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" */ *aPrimary = g_markup_printf_escaped (_("“%s” refused the connection."), host.get()); *aSecondary = _("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" */ *aPrimary = g_markup_printf_escaped (_("“%s” interrupted the connection."), host.get()); *aSecondary = _("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" */ *aPrimary = g_markup_printf_escaped (_("“%s” is not responding."), host.get()); *aSecondary = _("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) { *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" */ *aPrimary = g_markup_printf_escaped (_("“%s” redirected too many times."), host.get()); *aSecondary = _("The redirection has been stopped for security reasons."); *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" */ *aPrimary = g_markup_printf_escaped (_("“%s” requires an encrypted connection."), host.get()); *aSecondary = _("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" */ *aPrimary = g_markup_printf_escaped (_("“%s” dropped the connection."), host.get()); *aSecondary = _("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) { *aPrimary = g_strdup (_("Cannot load document in offline mode.")); *aSecondary = _("This document cannot be viewed in offline " "mode. Set Epiphany to “online” " "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" */ *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) { *aPrimary = g_strdup (_("Could not connect to proxy server.")); *aSecondary = _("Check your proxy server settings. " "If the connection still fails, there may be " "a problem with your proxy server or your " "network connection."); } else if (strcmp (aError, "contentEncodingError") == 0) { *aPrimary = g_strdup (_("Could not display content.")); *aSecondary = _("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) { /* First parse the arguments */ nsresult rv = NS_ERROR_ILLEGAL_VALUE; nsCAutoString spec; rv = aErrorURI->GetSpec (spec); NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && !spec.IsEmpty(), rv); nsCAutoString error, rawurl, url, charset; rv = ParseErrorURL (spec.get (), error, rawurl, url, charset); if (NS_FAILED (rv) || error.IsEmpty () || url.IsEmpty()) return rv; nsCOMPtr uri; rv = EphyUtils::NewURI(getter_AddRefs (uri), url, charset.get()); /* FIXME can uri be NULL if the original url was invalid? */ NS_ENSURE_TRUE (NS_SUCCEEDED (rv) && uri, rv); char *primary = nsnull, *secondary = nsnull, *tertiary = nsnull, *linkintro = nsnull; rv = GetErrorMessage (uri, error.get(), &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 url(spec); /* remove "about:neterror" part and insert mozilla's error page url */ url.Cut(0, strlen ("about:neterror")); url.Insert("chrome://global/content/netError.xhtml", 0); return Redirect (url, _retval); } NS_ENSURE_TRUE (primary && secondary, NS_ERROR_FAILURE); /* open the rendering stream */ nsCOMPtr storageStream; rv = NS_NewStorageStream(16384, (PRUint32) -1, getter_AddRefs (storageStream)); NS_ENSURE_SUCCESS (rv, rv); nsCOMPtr 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, "\n" "\n" "\n" "\n" ""); Write (stream, primary); /* 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, "\n" "\n" "\n" "\n" "
" "

"); Write (stream, primary); Write (stream, "

\n" "

"); Write (stream, secondary); if (tertiary) { Write (stream, " "); Write (stream, tertiary); } Write (stream, "

\n"); PRBool isHttp = PR_FALSE, isHttps = PR_FALSE; uri->SchemeIs ("http", &isHttp); uri->SchemeIs ("https", &isHttps); if (linkintro && (isHttp || isHttps)) { Write (stream, "

"); Write (stream, linkintro); Write (stream, "

\n" "

"); } Write (stream, "
\n" "\n" "\n"); g_free (language); g_free (primary); /* finish the rendering */ nsCOMPtr inputStream; rv = storageStream->NewInputStream(0, getter_AddRefs (inputStream)); NS_ENSURE_SUCCESS (rv, rv); nsCOMPtr channel (do_CreateInstance ("@mozilla.org/network/input-stream-channel;1", &rv)); NS_ENSURE_SUCCESS (rv, rv); rv |= channel->SetURI (aErrorURI); rv |= channel->SetContentStream (inputStream); rv |= channel->SetContentType (NS_LITERAL_CSTRING ("application/xhtml+xml")); rv |= channel->SetContentCharset (NS_LITERAL_CSTRING ("utf-8")); NS_ENSURE_SUCCESS (rv, rv); nsCOMPtr securityManager (do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); NS_ENSURE_SUCCESS (rv, rv); nsCOMPtr principal; rv = securityManager->GetCodebasePrincipal (aErrorURI, getter_AddRefs (principal)); NS_ENSURE_SUCCESS (rv, rv); rv = channel->SetOwner(principal); NS_ENSURE_SUCCESS (rv, rv); NS_ADDREF(*_retval = channel); return rv; } nsresult EphyAboutModule::Write(nsIOutputStream *aStream, const char *aText) { PRUint32 bytesWritten; return aStream->Write (aText, strlen (aText), &bytesWritten); }