Bug 384384. r=bsmedberg, r=mscott for Thunderbird

This commit is contained in:
rob_strong@exchangecode.com 2007-07-10 22:59:56 -07:00
parent 517a4cff6d
commit 97647d2d51
7 changed files with 255 additions and 35 deletions

View File

@ -61,6 +61,7 @@ const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher;
const nsICategoryManager = Components.interfaces.nsICategoryManager;
const nsIWebNavigationInfo = Components.interfaces.nsIWebNavigationInfo;
const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService;
const nsICommandLineValidator = Components.interfaces.nsICommandLineValidator;
const NS_BINDING_ABORTED = 0x804b0002;
const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
@ -301,6 +302,7 @@ var nsBrowserContentHandler = {
!iid.equals(nsICommandLineHandler) &&
!iid.equals(nsIBrowserHandler) &&
!iid.equals(nsIContentHandler) &&
!iid.equals(nsICommandLineValidator) &&
!iid.equals(nsIFactory))
throw Components.results.NS_ERROR_NO_INTERFACE;
@ -604,6 +606,21 @@ var nsBrowserContentHandler = {
request.cancel(NS_BINDING_ABORTED);
},
/* nsICommandLineValidator */
validate : function bch_validate(cmdLine) {
// Other handlers may use osint so only handle the osint flag if the url
// flag is also present and the command line is valid.
var osintFlagIdx = cmdLine.findFlag("osint", false);
var urlFlagIdx = cmdLine.findFlag("url", false);
if (urlFlagIdx > -1 && (osintFlagIdx > -1 ||
cmdLine.state == nsICommandLine.STATE_REMOTE_EXPLICIT)) {
var urlParam = cmdLine.getArgument(urlFlagIdx + 1);
if (cmdLine.length != urlFlagIdx + 2 || /firefoxurl:/.test(urlParam))
throw NS_ERROR_ABORT;
cmdLine.handleFlag("osint", false)
}
},
/* nsIFactory */
createInstance: function bch_CI(outer, iid) {
if (outer != null)
@ -866,6 +883,9 @@ var Module = {
catMan.addCategoryEntry("command-line-handler",
"x-default",
dch_contractID, true, true);
catMan.addCategoryEntry("command-line-validator",
"b-browser",
bch_contractID, true, true);
},
unregisterSelf : function mod_unregself(compMgr, location, type) {
@ -880,6 +900,8 @@ var Module = {
"m-browser", true);
catMan.deleteCategoryEntry("command-line-handler",
"x-default", true);
catMan.deleteCategoryEntry("command-line-validator",
"b-browser", true);
},
canUnload: function(compMgr) {

View File

@ -151,7 +151,7 @@ OpenKeyForWriting(HKEY aStartKey, const char* aKeyName, HKEY* aKey,
//
// HKCU\SOFTWARE\Classes\FirefoxHTML\
// DefaultIcon (default) REG_SZ <apppath>,1
// shell\open\command (default) REG_SZ <apppath> -url "%1" -requestPending
// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
// shell\open\ddeexec NoActivateHandler REG_SZ
// \Application (default) REG_SZ Firefox
@ -163,7 +163,7 @@ OpenKeyForWriting(HKEY aStartKey, const char* aKeyName, HKEY* aKey,
// EditFlags REG_DWORD 2
// FriendlyTypeName REG_SZ <appname> URL
// DefaultIcon (default) REG_SZ <apppath>,1
// shell\open\command (default) REG_SZ <apppath> -url "%1" -requestPending
// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
// shell\open\ddeexec NoActivateHandler REG_SZ
// \Application (default) REG_SZ Firefox
@ -177,7 +177,7 @@ OpenKeyForWriting(HKEY aStartKey, const char* aKeyName, HKEY* aKey,
//
// HKCU\SOFTWARE\Classes\<protocol>\
// DefaultIcon (default) REG_SZ <apppath>,1
// shell\open\command (default) REG_SZ <apppath> -url "%1" -requestPending
// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
// shell\open\ddeexec NoActivateHandler REG_SZ
// \Application (default) REG_SZ Firefox
@ -232,7 +232,7 @@ typedef struct {
#define CLS_HTML "FirefoxHTML"
#define CLS_URL "FirefoxURL"
#define VAL_FILE_ICON "%APPPATH%,1"
#define VAL_OPEN "\"%APPPATH%\" -url \"%1\" -requestPending"
#define VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
#define MAKE_KEY_NAME1(PREFIX, MID) \
PREFIX MID

View File

@ -136,7 +136,7 @@
GetFullPathName $8 "$INSTDIR\${FileMainEXE}"
StrCpy $0 "SOFTWARE\Classes"
StrCpy $2 "$\"$8$\" -url $\"%1$\" -requestPending"
StrCpy $2 "$\"$8$\" -requestPending -osint -url $\"%1$\""
; Associate the file handlers with FirefoxHTML
WriteRegStr SHCTX "$0\.htm" "" "FirefoxHTML"
@ -364,7 +364,7 @@
; Store the command to open the app with an url in a register for easy access.
GetFullPathName $8 "$INSTDIR\${FileMainEXE}"
StrCpy $1 "$\"$8$\" -url $\"%1$\" -requestPending"
StrCpy $1 "$\"$8$\" -requestPending -osint -url $\"%1$\""
; Always set the file and protocol handlers since they may specify a
; different path and the path is used by Vista when setting associations.

View File

@ -49,6 +49,7 @@ XPIDLSRCS = \
nsICommandLine.idl \
nsICommandLineRunner.idl \
nsICommandLineHandler.idl \
nsICommandLineValidator.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,70 @@
/* ***** 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 the Mozilla toolkit.
*
* The Initial Developer of the Original Code is
* Robert Strong <robert.bugzilla@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 ***** */
#include "nsISupports.idl"
interface nsICommandLine;
/**
* Validates arguments on the command line of an XUL application.
*
* Each validator is registered in the category "command-line-validator".
* The entries in this category are read in alphabetical order, and each
* category value is treated as a service contractid implementing this
* interface.
*
* By convention, validator with ordinary priority should begin with "m".
*
* Example:
* Category Entry Value
* command-line-validator b-browser @mozilla.org/browser/clh;1
* command-line-validator m-edit @mozilla.org/composer/clh;1
* command-line-validator m-irc @mozilla.org/chatzilla/clh;1
*
*/
[scriptable, uuid(5ecaa593-7660-4a3a-957a-92d5770671c7)]
interface nsICommandLineValidator : nsISupports
{
/**
* Process the command-line validators in the proper order, calling
* "validate()" on each.
*
* @throws NS_ERROR_ABORT if any validator throws NS_ERROR_ABORT. All other
* errors thrown by validators will be silently ignored.
*/
void validate(in nsICommandLine aCommandLine);
};

View File

@ -39,6 +39,7 @@
#include "nsICategoryManager.h"
#include "nsICommandLineHandler.h"
#include "nsICommandLineValidator.h"
#include "nsIClassInfoImpl.h"
#include "nsIDOMWindow.h"
#include "nsIFile.h"
@ -86,12 +87,16 @@ public:
protected:
~nsCommandLine() { }
typedef nsresult (*EnumerateCallback)(nsICommandLineHandler* aHandler,
typedef nsresult (*EnumerateHandlersCallback)(nsICommandLineHandler* aHandler,
nsICommandLine* aThis,
void *aClosure);
typedef nsresult (*EnumerateValidatorsCallback)(nsICommandLineValidator* aValidator,
nsICommandLine* aThis,
void *aClosure);
void appendArg(const char* arg);
nsresult EnumerateHandlers(EnumerateCallback aCallback, void *aClosure);
nsresult EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure);
nsresult EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure);
nsStringArray mArgs;
PRUint32 mState;
@ -537,7 +542,7 @@ nsCommandLine::Init(PRInt32 argc, char** argv, nsIFile* aWorkingDir,
}
nsresult
nsCommandLine::EnumerateHandlers(EnumerateCallback aCallback, void *aClosure)
nsCommandLine::EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure)
{
nsresult rv;
@ -579,6 +584,55 @@ nsCommandLine::EnumerateHandlers(EnumerateCallback aCallback, void *aClosure)
return rv;
}
nsresult
nsCommandLine::EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure)
{
nsresult rv;
nsCOMPtr<nsICategoryManager> catman
(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
NS_ENSURE_TRUE(catman, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsISimpleEnumerator> entenum;
rv = catman->EnumerateCategory("command-line-validator",
getter_AddRefs(entenum));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIUTF8StringEnumerator> strenum (do_QueryInterface(entenum));
NS_ENSURE_TRUE(strenum, NS_ERROR_UNEXPECTED);
nsCAutoString entry;
PRBool hasMore;
while (NS_SUCCEEDED(strenum->HasMore(&hasMore)) && hasMore) {
strenum->GetNext(entry);
nsXPIDLCString contractID;
rv = catman->GetCategoryEntry("command-line-validator",
entry.get(),
getter_Copies(contractID));
if (!contractID)
continue;
nsCOMPtr<nsICommandLineValidator> clv(do_GetService(contractID.get()));
if (!clv)
continue;
rv = (aCallback)(clv, this, aClosure);
if (rv == NS_ERROR_ABORT)
break;
rv = NS_OK;
}
return rv;
}
static nsresult
EnumValidate(nsICommandLineValidator* aValidator, nsICommandLine* aThis, void*)
{
return aValidator->Validate(aThis);
}
static nsresult
EnumRun(nsICommandLineHandler* aHandler, nsICommandLine* aThis, void*)
{
@ -590,6 +644,10 @@ nsCommandLine::Run()
{
nsresult rv;
rv = EnumerateValidators(EnumValidate, nsnull);
if (rv == NS_ERROR_ABORT)
return rv;
rv = EnumerateHandlers(EnumRun, nsnull);
if (rv == NS_ERROR_ABORT)
return rv;

View File

@ -386,13 +386,16 @@ static void RemoveArg(char **argv)
* --arg (or /arg on win32/OS2).
*
* @param aArg the parameter to check. Must be lowercase.
* @param aCheckOSInt if true returns ARG_BAD if the osint argument is present
* when aArg is also present.
* @param if non-null, the -arg <data> will be stored in this pointer. This is *not*
* allocated, but rather a pointer to the argv data.
*/
static ArgResult
CheckArg(const char* aArg, const char **aParam = nsnull)
CheckArg(const char* aArg, PRBool aCheckOSInt = PR_FALSE, const char **aParam = nsnull)
{
char **curarg = gArgv + 1; // skip argv[0]
ArgResult ar = ARG_NONE;
while (*curarg) {
char *arg = curarg[0];
@ -409,7 +412,8 @@ CheckArg(const char* aArg, const char **aParam = nsnull)
if (strimatch(aArg, arg)) {
RemoveArg(curarg);
if (!aParam) {
return ARG_FOUND;
ar = ARG_FOUND;
break;
}
if (*curarg) {
@ -422,7 +426,8 @@ CheckArg(const char* aArg, const char **aParam = nsnull)
*aParam = *curarg;
RemoveArg(curarg);
return ARG_FOUND;
ar = ARG_FOUND;
break;
}
return ARG_BAD;
}
@ -431,7 +436,15 @@ CheckArg(const char* aArg, const char **aParam = nsnull)
++curarg;
}
return ARG_NONE;
if (aCheckOSInt && ar == ARG_FOUND) {
ArgResult arOSInt = CheckArg("osint");
if (arOSInt == ARG_FOUND) {
ar = ARG_BAD;
PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n");
}
}
return ar;
}
#if defined(XP_WIN)
@ -1163,14 +1176,14 @@ HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
ToLowerCase(program);
const char *username = getenv("LOGNAME");
ar = CheckArg("p", &profile);
ar = CheckArg("p", PR_FALSE, &profile);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
return 1;
}
const char *temp = nsnull;
ar = CheckArg("a", &temp);
ar = CheckArg("a", PR_FALSE, &temp);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
return 1;
@ -1178,7 +1191,7 @@ HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
program.Assign(temp);
}
ar = CheckArg("u", &username);
ar = CheckArg("u", PR_FALSE, &username);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
return 1;
@ -1221,7 +1234,7 @@ RemoteCommandLine(const char* aDesktopStartupID)
const char *username = getenv("LOGNAME");
const char *temp = nsnull;
ar = CheckArg("a", &temp);
ar = CheckArg("a", PR_TRUE, &temp);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
return PR_FALSE;
@ -1229,7 +1242,7 @@ RemoteCommandLine(const char* aDesktopStartupID)
program.Assign(temp);
}
ar = CheckArg("u", &username);
ar = CheckArg("u", PR_TRUE, &username);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
return PR_FALSE;
@ -1697,10 +1710,17 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
*aResult = nsnull;
*aStartOffline = PR_FALSE;
ar = CheckArg("offline", PR_TRUE);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n");
return NS_ERROR_FAILURE;
}
arg = PR_GetEnv("XRE_START_OFFLINE");
if ((arg && *arg) || CheckArg("offline"))
if ((arg && *arg) || ar)
*aStartOffline = PR_TRUE;
arg = PR_GetEnv("XRE_PROFILE_PATH");
if (arg && *arg) {
nsCOMPtr<nsILocalFile> lf;
@ -1725,17 +1745,22 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
// Clear out flags that we handled (or should have handled!) last startup.
const char *dummy;
CheckArg("p", &dummy);
CheckArg("profile", &dummy);
CheckArg("p", PR_FALSE, &dummy);
CheckArg("profile", PR_FALSE, &dummy);
CheckArg("profilemanager");
return NS_LockProfilePath(lf, localDir, nsnull, aResult);
}
if (CheckArg("migration"))
ar = CheckArg("migration", PR_TRUE);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n");
return NS_ERROR_FAILURE;
} else if (ar == ARG_FOUND) {
gDoMigration = PR_TRUE;
}
ar = CheckArg("profile", &arg);
ar = CheckArg("profile", PR_TRUE, &arg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n");
return NS_ERROR_FAILURE;
@ -1760,7 +1785,7 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
rv = NS_NewToolkitProfileService(getter_AddRefs(profileSvc));
NS_ENSURE_SUCCESS(rv, rv);
ar = CheckArg("createprofile", &arg);
ar = CheckArg("createprofile", PR_TRUE, &arg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n");
return NS_ERROR_FAILURE;
@ -1822,11 +1847,21 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
}
}
ar = CheckArg("p", &arg);
ar = CheckArg("p", PR_FALSE, &arg);
if (ar == ARG_BAD) {
ar = CheckArg("osint");
if (ar == ARG_FOUND) {
PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
return NS_ERROR_FAILURE;
}
return ShowProfileManager(profileSvc, aNative);
}
if (ar) {
ar = CheckArg("osint");
if (ar == ARG_FOUND) {
PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIToolkitProfile> profile;
rv = profileSvc->GetProfileByName(nsDependentCString(arg),
getter_AddRefs(profile));
@ -1854,7 +1889,11 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
return ShowProfileManager(profileSvc, aNative);
}
if (CheckArg("profilemanager")) {
ar = CheckArg("profilemanager", PR_TRUE);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n");
return NS_ERROR_FAILURE;
} else if (ar == ARG_FOUND) {
return ShowProfileManager(profileSvc, aNative);
}
@ -2219,6 +2258,7 @@ int
XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
{
nsresult rv;
ArgResult ar;
NS_TIMELINE_MARK("enter main");
#ifdef DEBUG
@ -2448,17 +2488,28 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
ScopedFPHandler handler;
#endif /* XP_OS2 */
#ifdef XP_MACOSX
if (CheckArg("safe-mode") || GetCurrentKeyModifiers() & optionKey)
#else
if (CheckArg("safe-mode"))
#endif
ar = CheckArg("safe-mode", PR_TRUE);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n");
return 1;
} else if (ar == ARG_FOUND) {
gSafeMode = PR_TRUE;
}
#ifdef XP_MACOSX
if (GetCurrentKeyModifiers() & optionKey)
gSafeMode = PR_TRUE;
#endif
// Handle -no-remote command line argument. Setup the environment to
// better accommodate other components and various restart scenarios.
if (CheckArg("no-remote"))
ar = CheckArg("no-remote", PR_TRUE);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
return 1;
} else if (ar == ARG_FOUND) {
PR_SetEnv("MOZ_NO_REMOTE=1");
}
// Handle -help and -version command line arguments.
// They should return quickly, so we deal with them here.
@ -2483,7 +2534,11 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
return 1;
// Check for -register, which registers chrome and then exits immediately.
if (CheckArg("register")) {
ar = CheckArg("register", PR_TRUE);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n");
return 1;
} else if (ar == ARG_FOUND) {
ScopedXPCOMStartup xpcom;
rv = xpcom.Initialize();
NS_ENSURE_SUCCESS(rv, 1);
@ -2584,7 +2639,7 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
// handle -remote now that xpcom is fired up
const char* xremotearg;
ArgResult ar = CheckArg("remote", &xremotearg);
ar = CheckArg("remote", PR_TRUE, &xremotearg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
return 1;
@ -2804,7 +2859,21 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
nsCOMPtr<nsIExtensionManager> em(do_GetService("@mozilla.org/extensions/manager;1"));
NS_ENSURE_TRUE(em, 1);
if (CheckArg("install-global-extension") || CheckArg("install-global-theme")) {
ar = CheckArg("install-global-extension", PR_TRUE);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -install-global-extension is invalid when argument -osint is specified\n");
return 1;
} else if (ar == ARG_FOUND) {
// Do the required processing and then shut down.
em->HandleCommandLineArgs(cmdLine);
return 0;
}
ar = CheckArg("install-global-theme", PR_TRUE);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -install-global-theme is invalid when argument -osint is specified\n");
return 1;
} else if (ar == ARG_FOUND) {
// Do the required processing and then shut down.
em->HandleCommandLineArgs(cmdLine);
return 0;