fixes bug 226071 "xremote: openURL doesn't work well when multiple apps with different capabilities are present" r=bz,blizzard sr=bryner a=asa
git-svn-id: svn://10.0.0.236/trunk@149593 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
101b4e2a07
commit
a34389b0de
@ -637,6 +637,12 @@ pref("signon.SignonFileName", "signons.txt");
|
||||
pref("network.protocol-handler.external.mailto", true); // for mail
|
||||
pref("network.protocol-handler.external.news" , true); // for news
|
||||
|
||||
// By default, all protocol handlers are exposed. This means that
|
||||
// the browser will respond to openURL commands for all URL types.
|
||||
// It will also try to open link clicks inside the browser before
|
||||
// failing over to the system handlers.
|
||||
pref("network.protocol-handler.expose-all", true);
|
||||
|
||||
// Default security warning dialogs to off
|
||||
pref("security.warn_entering_secure", false);
|
||||
pref("security.warn_entering_weak", false);
|
||||
|
||||
@ -637,6 +637,12 @@ pref("signon.SignonFileName", "signons.txt");
|
||||
pref("network.protocol-handler.external.mailto", true); // for mail
|
||||
pref("network.protocol-handler.external.news" , true); // for news
|
||||
|
||||
// By default, all protocol handlers are exposed. This means that
|
||||
// the browser will respond to openURL commands for all URL types.
|
||||
// It will also try to open link clicks inside the browser before
|
||||
// failing over to the system handlers.
|
||||
pref("network.protocol-handler.expose-all", true);
|
||||
|
||||
// Default security warning dialogs to off
|
||||
pref("security.warn_entering_secure", false);
|
||||
pref("security.warn_entering_weak", false);
|
||||
|
||||
@ -635,6 +635,11 @@ pref("signon.expireMasterPassword", false);
|
||||
pref("network.protocol-handler.external.mailto", true); // for mail
|
||||
pref("network.protocol-handler.external.news" , true); // for news
|
||||
|
||||
// By default, all protocol handlers are hidden. This means
|
||||
// that calendar will not respond to X-remote openURL commands
|
||||
// and it will also defer all link clicks to the user's browser.
|
||||
pref("network.protocol-handler.expose-all", false);
|
||||
|
||||
// Default security warning dialogs to off
|
||||
pref("security.warn_entering_secure", false);
|
||||
pref("security.warn_entering_weak", false);
|
||||
|
||||
@ -483,6 +483,11 @@ pref("network.protocol-handler.external.javascript", false);
|
||||
pref("network.protocol-handler.external.ms-help", false);
|
||||
pref("network.protocol-handler.external.vnd.ms.radio", false);
|
||||
|
||||
// By default, all protocol handlers are hidden. This means
|
||||
// that composer will not respond to X-remote openURL commands
|
||||
// and it will also defer all link clicks to the user's browser.
|
||||
pref("network.protocol-handler.expose-all", false);
|
||||
|
||||
pref("network.hosts.smtp_server", "mail");
|
||||
pref("network.hosts.pop_server", "mail");
|
||||
pref("network.protocols.useSystemDefaults", false); // set to true if user links should use system default handlers
|
||||
|
||||
@ -118,10 +118,8 @@
|
||||
#include "nsIDocument.h"
|
||||
#include "nsITextToSubURI.h"
|
||||
|
||||
#ifdef MOZ_THUNDERBIRD
|
||||
#include "nsIExternalProtocolService.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#endif
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
/**
|
||||
@ -561,39 +559,30 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent,
|
||||
nsIDocShell** aDocShell,
|
||||
nsIRequest** aRequest)
|
||||
{
|
||||
#ifdef MOZ_THUNDERBIRD
|
||||
// XXX ugly thunderbird hack to force all url clicks to go to the system default app
|
||||
// I promise this will be removed once we figure out a better way.
|
||||
nsCAutoString scheme;
|
||||
aURI->GetScheme(scheme);
|
||||
|
||||
nsCAutoString spec;
|
||||
aURI->GetSpec(spec);
|
||||
|
||||
static const char kMailToURI[] = "mailto";
|
||||
static const char kNewsURI[] = "news";
|
||||
static const char kSnewsURI[] = "snews";
|
||||
static const char kNntpURI[] = "nntp";
|
||||
static const char kImapURI[] = "imap";
|
||||
static const char kAddbookURI[] = "addbook";
|
||||
static const char kPopURI[] = "pop";
|
||||
static const char kMailboxURI[] = "mailbox";
|
||||
|
||||
|
||||
if (scheme.EqualsIgnoreCase(kMailToURI) || scheme.EqualsIgnoreCase(kNewsURI) || scheme.EqualsIgnoreCase(kSnewsURI) ||
|
||||
scheme.EqualsIgnoreCase(kNntpURI) || scheme.EqualsIgnoreCase(kImapURI) || scheme.EqualsIgnoreCase(kAddbookURI) ||
|
||||
scheme.EqualsIgnoreCase(kPopURI) || scheme.EqualsIgnoreCase(kMailboxURI))
|
||||
{
|
||||
// we can handle all mail schemes
|
||||
} else
|
||||
PRBool earlyReturn = PR_FALSE;
|
||||
{
|
||||
// we don't handle this type, the the registered handler take it
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
return extProtService->LoadUrl(aURI);
|
||||
}
|
||||
#endif
|
||||
// defer to an external protocol handler if necessary...
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
|
||||
if (extProtService) {
|
||||
nsCAutoString scheme;
|
||||
aURI->GetScheme(scheme);
|
||||
if (!scheme.IsEmpty()) {
|
||||
// if the URL scheme does not correspond to an exposed protocol, then we
|
||||
// need to hand this link click over to the external protocol handler.
|
||||
PRBool isExposed;
|
||||
nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
|
||||
if (NS_SUCCEEDED(rv) && !isExposed) {
|
||||
rv = extProtService->LoadUrl(aURI);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
earlyReturn = PR_TRUE;
|
||||
else
|
||||
NS_WARNING("failed to launch external protocol handler");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (earlyReturn)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
|
||||
NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
|
||||
|
||||
@ -230,6 +230,18 @@ function messagePaneOnClick(event)
|
||||
if (href.search(needABrowser) == -1)
|
||||
return;
|
||||
|
||||
// however, if the protocol should not be loaded internally, then we should
|
||||
// not put up a new browser window. we should just let the usual processing
|
||||
// take place.
|
||||
try {
|
||||
var extProtService = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"].getService();
|
||||
extProtService = extProtService.QueryInterface(Components.interfaces.nsIExternalProtocolService);
|
||||
var scheme = href.substring(0, href.indexOf(":"));
|
||||
if (!extProtService.isExposedProtocol(scheme))
|
||||
return;
|
||||
}
|
||||
catch (ex) {} // ignore errors, and just assume that we can proceed.
|
||||
|
||||
// if you get here, the user did a simple left click on a link
|
||||
// that we know should be in a browser window.
|
||||
// since we are in the message pane, send it to the top most browser window
|
||||
|
||||
@ -504,9 +504,22 @@ pref("network.protocol-handler.external.javascript", false);
|
||||
pref("network.protocol-handler.external.ms-help", false);
|
||||
pref("network.protocol-handler.external.vnd.ms.radio", false);
|
||||
|
||||
// An exposed protocol handler is one that can be used in all contexts. A
|
||||
// non-exposed protocol handler is one that can only be used internally by the
|
||||
// application. For example, a non-exposed protocol would not be loaded by the
|
||||
// application in response to a link click or a X-remote openURL command.
|
||||
// Instead, it would be deferred to the system's external protocol handler.
|
||||
// Only internal/built-in protocol handlers can be marked as exposed.
|
||||
|
||||
// This pref controls the default settings. Per protocol settings can be used
|
||||
// to override this value.
|
||||
pref("network.protocol-handler.expose-all", true);
|
||||
|
||||
// Example: make IMAP an exposed protocol
|
||||
// pref("network.protocol-handler.expose.imap", true);
|
||||
|
||||
pref("network.hosts.smtp_server", "mail");
|
||||
pref("network.hosts.pop_server", "mail");
|
||||
pref("network.protocols.useSystemDefaults", false); // set to true if user links should use system default handlers
|
||||
|
||||
// <http>
|
||||
pref("network.http.version", "1.1"); // default
|
||||
|
||||
@ -910,6 +910,40 @@ NS_IMETHODIMP nsExternalHelperAppService::ExternalProtocolHandlerExists(const ch
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExternalHelperAppService::IsExposedProtocol(const char * aProtocolScheme, PRBool * aResult)
|
||||
{
|
||||
// by default, no protocol is exposed. i.e., by default all link clicks must
|
||||
// go through the external protocol service. most applications override this
|
||||
// default behavior.
|
||||
*aResult = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs)
|
||||
{
|
||||
PRBool val;
|
||||
nsresult rv;
|
||||
|
||||
// check the per protocol setting first. it always takes precidence.
|
||||
// if not set, then use the global setting.
|
||||
|
||||
nsCAutoString name;
|
||||
name = NS_LITERAL_CSTRING("network.protocol-handler.expose.")
|
||||
+ nsDependentCString(aProtocolScheme);
|
||||
rv = prefs->GetBoolPref(name.get(), &val);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
*aResult = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = prefs->GetBoolPref("network.protocol-handler.expose-all", &val);
|
||||
if (NS_SUCCEEDED(rv) && val)
|
||||
*aResult = PR_TRUE;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsExternalHelperAppService::LoadUrl(nsIURI * aURL)
|
||||
{
|
||||
// this method should only be implemented by each OS specific implementation of this service.
|
||||
|
||||
@ -43,6 +43,18 @@ interface nsIExternalProtocolService : nsISupports
|
||||
*/
|
||||
boolean externalProtocolHandlerExists(in string aProtocolScheme);
|
||||
|
||||
/**
|
||||
* Check whether a handler for a specific protocol is "exposed" as a visible
|
||||
* feature of the current application.
|
||||
*
|
||||
* An exposed protocol handler is one that can be used in all contexts. A
|
||||
* non-exposed protocol handler is one that can only be used internally by the
|
||||
* application. For example, a non-exposed protocol would not be loaded by the
|
||||
* application in response to a link click or a X-remote openURL command.
|
||||
* Instead, it would be deferred to the system's external protocol handler.
|
||||
*/
|
||||
boolean isExposedProtocol(in string aProtocolScheme);
|
||||
|
||||
/**
|
||||
* Used to load a url via an external protocol handler (if one exists)
|
||||
* @param aURL The url to load
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
/* vim:set ts=8 sw=2 et cindent: */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
@ -98,54 +99,6 @@ XRemoteClient::Init (void)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
XRemoteClient::SendCommand (const char *aCommand, PRBool *aWindowFound)
|
||||
{
|
||||
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommand"));
|
||||
|
||||
*aWindowFound = PR_TRUE;
|
||||
|
||||
// find the remote window
|
||||
Window window = FindWindow();
|
||||
|
||||
// no window? let the caller know.
|
||||
if (!window) {
|
||||
*aWindowFound = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// make sure we get the right events on that window
|
||||
XSelectInput(mDisplay, window,
|
||||
(PropertyChangeMask|StructureNotifyMask));
|
||||
|
||||
nsresult rv;
|
||||
PRBool destroyed = PR_FALSE;
|
||||
|
||||
// get the lock on the window
|
||||
rv = GetLock(window, &destroyed);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// send our command
|
||||
rv = DoSendCommand(window, aCommand, &destroyed);
|
||||
|
||||
// if the window was destroyed, don't bother trying to free the
|
||||
// lock.
|
||||
if (destroyed)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// doesn't really matter what this returns
|
||||
FreeLock(window);
|
||||
|
||||
// if we failed above we had to free the lock - return the error
|
||||
// now.
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
XRemoteClient::Shutdown (void)
|
||||
{
|
||||
@ -164,32 +117,36 @@ XRemoteClient::Shutdown (void)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Window
|
||||
XRemoteClient::FindWindow(void)
|
||||
NS_IMETHODIMP
|
||||
XRemoteClient::SendCommand (const char *aCommand, PRBool *aWindowFound)
|
||||
{
|
||||
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommand"));
|
||||
|
||||
Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mDisplay));
|
||||
Window root2, parent, *kids;
|
||||
unsigned int nkids;
|
||||
Window result = 0;
|
||||
int i;
|
||||
|
||||
*aWindowFound = PR_FALSE;
|
||||
|
||||
if (!XQueryTree(mDisplay, root, &root2, &parent, &kids, &nkids)) {
|
||||
PR_LOG(sRemoteLm, PR_LOG_DEBUG,
|
||||
("XQueryTree failed in XRemoteClient::FindWindow"));
|
||||
return 0;
|
||||
("XQueryTree failed in XRemoteClient::SendCommand"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!(kids && nkids)) {
|
||||
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("root window has no children"));
|
||||
return 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
for (i=nkids-1; i >= 0; i--) {
|
||||
Atom type;
|
||||
int format;
|
||||
unsigned long nitems, bytesafter;
|
||||
unsigned char *data_return = 0;
|
||||
Window w;
|
||||
Window w, result = 0;
|
||||
w = kids[i];
|
||||
// find the inner window with WM_STATE on it
|
||||
w = CheckWindow(w);
|
||||
@ -224,11 +181,8 @@ XRemoteClient::FindWindow(void)
|
||||
|
||||
// if the IDs are equal then this is the window we want. if
|
||||
// they aren't fall through to the next loop iteration.
|
||||
if (!strcmp(logname, (const char *)data_return)) {
|
||||
XFree(data_return);
|
||||
if (!strcmp(logname, (const char *)data_return))
|
||||
result = w;
|
||||
break;
|
||||
}
|
||||
|
||||
XFree(data_return);
|
||||
}
|
||||
@ -238,14 +192,40 @@ XRemoteClient::FindWindow(void)
|
||||
// it.
|
||||
else {
|
||||
result = w;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
// ok, let the caller know that we at least found a window.
|
||||
*aWindowFound = PR_TRUE;
|
||||
|
||||
// make sure we get the right events on that window
|
||||
XSelectInput(mDisplay, result,
|
||||
(PropertyChangeMask|StructureNotifyMask));
|
||||
|
||||
PRBool destroyed = PR_FALSE;
|
||||
|
||||
// get the lock on the window
|
||||
rv = GetLock(result, &destroyed);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// send our command
|
||||
rv = DoSendCommand(result, aCommand, &destroyed);
|
||||
|
||||
// if the window was destroyed, don't bother trying to free the
|
||||
// lock.
|
||||
if (!destroyed)
|
||||
FreeLock(result); // doesn't really matter what this returns
|
||||
|
||||
// if accepted then we're done...
|
||||
if (NS_SUCCEEDED(rv))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("FindWindow returning 0x%lx\n", result));
|
||||
|
||||
return result;
|
||||
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("SendCommand returning 0x%x\n", rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
Window
|
||||
|
||||
@ -42,7 +42,6 @@ class XRemoteClient
|
||||
|
||||
private:
|
||||
|
||||
Window FindWindow (void);
|
||||
Window CheckWindow (Window aWindow);
|
||||
Window CheckChildren (Window aWindow);
|
||||
nsresult GetLock (Window aWindow, PRBool *aDestroyed);
|
||||
@ -63,5 +62,4 @@ private:
|
||||
char *mLockData;
|
||||
|
||||
PRBool mInitialized;
|
||||
|
||||
};
|
||||
|
||||
@ -42,6 +42,7 @@ REQUIRES = xpcom \
|
||||
necko \
|
||||
appshell \
|
||||
rdf \
|
||||
exthandler \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
||||
@ -47,6 +47,8 @@
|
||||
#include <nsIURI.h>
|
||||
#include <nsNetUtil.h>
|
||||
#include <nsIWindowMediator.h>
|
||||
#include <nsCExternalHandlerService.h>
|
||||
#include <nsIExternalProtocolService.h>
|
||||
|
||||
NS_DEFINE_CID(kWindowCID, NS_WINDOW_CID);
|
||||
|
||||
@ -649,11 +651,41 @@ XRemoteService::GetComposeLocation(const char **_retval)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
XRemoteService::MayOpenURL(const nsCString &aURL)
|
||||
{
|
||||
// by default, we assume nothing can be loaded.
|
||||
PRBool allowURL= PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService();
|
||||
if (ios) {
|
||||
nsCAutoString scheme;
|
||||
ios->ExtractScheme(aURL, scheme);
|
||||
if (!scheme.IsEmpty()) {
|
||||
nsCOMPtr<nsIExternalProtocolService> extProtService =
|
||||
do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
|
||||
if (extProtService) {
|
||||
// if the given URL scheme corresponds to an exposed protocol, then we
|
||||
// can try to load it. otherwise, we must not.
|
||||
PRBool isExposed;
|
||||
nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
|
||||
if (NS_SUCCEEDED(rv) && isExposed)
|
||||
allowURL = PR_TRUE; // ok, we can load this URL.
|
||||
}
|
||||
}
|
||||
}
|
||||
return allowURL;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XRemoteService::OpenURL(nsCString &aArgument,
|
||||
nsIDOMWindowInternal *aParent,
|
||||
PRBool aOpenBrowser)
|
||||
{
|
||||
// check if we can handle this type of URL
|
||||
if (!MayOpenURL(aArgument))
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
// the eventual toplevel target of the load
|
||||
nsCOMPtr<nsIDOMWindowInternal> finalWindow = aParent;
|
||||
|
||||
|
||||
@ -72,6 +72,9 @@ class XRemoteService : public nsIXRemoteService, public nsIObserver {
|
||||
nsresult GetMailLocation(char **_retval);
|
||||
nsresult GetComposeLocation(const char **_retval);
|
||||
|
||||
// returns true if the URL may be loaded.
|
||||
PRBool MayOpenURL(const nsCString &aURL);
|
||||
|
||||
// remote command handlers
|
||||
nsresult OpenURL(nsCString &aArgument,
|
||||
nsIDOMWindowInternal *aParent,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user