diff options
Diffstat (limited to 'toolkit/components/commandlines')
18 files changed, 1078 insertions, 0 deletions
diff --git a/toolkit/components/commandlines/moz.build b/toolkit/components/commandlines/moz.build new file mode 100644 index 000000000..5798ccfcc --- /dev/null +++ b/toolkit/components/commandlines/moz.build @@ -0,0 +1,30 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini'] + +if CONFIG['OS_ARCH'] == 'WINNT': + XPCSHELL_TESTS_MANIFESTS += ['test/unit_win/xpcshell.ini'] +elif CONFIG['OS_ARCH'] != 'Darwin': + XPCSHELL_TESTS_MANIFESTS += ['test/unit_unix/xpcshell.ini'] + +XPIDL_SOURCES += [ + 'nsICommandLine.idl', + 'nsICommandLineHandler.idl', + 'nsICommandLineRunner.idl', + 'nsICommandLineValidator.idl', +] + +XPIDL_MODULE = 'commandlines' + +SOURCES += [ + 'nsCommandLine.cpp', +] + +FINAL_LIBRARY = 'xul' + +with Files('**'): + BUG_COMPONENT = ('Toolkit', 'Startup and Profile System') diff --git a/toolkit/components/commandlines/nsCommandLine.cpp b/toolkit/components/commandlines/nsCommandLine.cpp new file mode 100644 index 000000000..280b1d24a --- /dev/null +++ b/toolkit/components/commandlines/nsCommandLine.cpp @@ -0,0 +1,660 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsICommandLineRunner.h" + +#include "nsICategoryManager.h" +#include "nsICommandLineHandler.h" +#include "nsICommandLineValidator.h" +#include "nsIConsoleService.h" +#include "nsIClassInfoImpl.h" +#include "nsIDOMWindow.h" +#include "nsIFile.h" +#include "nsISimpleEnumerator.h" +#include "nsIStringEnumerator.h" + +#include "nsCOMPtr.h" +#include "mozilla/ModuleUtils.h" +#include "nsISupportsImpl.h" +#include "nsNativeCharsetUtils.h" +#include "nsNetUtil.h" +#include "nsIFileProtocolHandler.h" +#include "nsIURI.h" +#include "nsUnicharUtils.h" +#include "nsTArray.h" +#include "nsTextFormatter.h" +#include "nsXPCOMCID.h" +#include "plstr.h" +#include "mozilla/Attributes.h" + +#ifdef MOZ_WIDGET_COCOA +#include <CoreFoundation/CoreFoundation.h> +#include "nsILocalFileMac.h" +#elif defined(XP_WIN) +#include <windows.h> +#include <shlobj.h> +#elif defined(XP_UNIX) +#include <unistd.h> +#endif + +#ifdef DEBUG_bsmedberg +#define DEBUG_COMMANDLINE +#endif + +#define NS_COMMANDLINE_CID \ + { 0x23bcc750, 0xdc20, 0x460b, { 0xb2, 0xd4, 0x74, 0xd8, 0xf5, 0x8d, 0x36, 0x15 } } + +class nsCommandLine final : public nsICommandLineRunner +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOMMANDLINE + NS_DECL_NSICOMMANDLINERUNNER + + nsCommandLine(); + +protected: + ~nsCommandLine() { } + + typedef nsresult (*EnumerateHandlersCallback)(nsICommandLineHandler* aHandler, + nsICommandLine* aThis, + void *aClosure); + typedef nsresult (*EnumerateValidatorsCallback)(nsICommandLineValidator* aValidator, + nsICommandLine* aThis, + void *aClosure); + + void appendArg(const char* arg); + MOZ_MUST_USE nsresult resolveShortcutURL(nsIFile* aFile, nsACString& outURL); + nsresult EnumerateHandlers(EnumerateHandlersCallback aCallback, void *aClosure); + nsresult EnumerateValidators(EnumerateValidatorsCallback aCallback, void *aClosure); + + nsTArray<nsString> mArgs; + uint32_t mState; + nsCOMPtr<nsIFile> mWorkingDir; + nsCOMPtr<nsIDOMWindow> mWindowContext; + bool mPreventDefault; +}; + +nsCommandLine::nsCommandLine() : + mState(STATE_INITIAL_LAUNCH), + mPreventDefault(false) +{ + +} + + +NS_IMPL_CLASSINFO(nsCommandLine, nullptr, 0, NS_COMMANDLINE_CID) +NS_IMPL_ISUPPORTS_CI(nsCommandLine, + nsICommandLine, + nsICommandLineRunner) + +NS_IMETHODIMP +nsCommandLine::GetLength(int32_t *aResult) +{ + *aResult = int32_t(mArgs.Length()); + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::GetArgument(int32_t aIndex, nsAString& aResult) +{ + NS_ENSURE_ARG_MIN(aIndex, 0); + NS_ENSURE_ARG_MAX(aIndex, int32_t(mArgs.Length() - 1)); + + aResult = mArgs[aIndex]; + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::FindFlag(const nsAString& aFlag, bool aCaseSensitive, int32_t *aResult) +{ + NS_ENSURE_ARG(!aFlag.IsEmpty()); + + nsDefaultStringComparator caseCmp; + nsCaseInsensitiveStringComparator caseICmp; + nsStringComparator& c = aCaseSensitive ? + static_cast<nsStringComparator&>(caseCmp) : + static_cast<nsStringComparator&>(caseICmp); + + for (uint32_t f = 0; f < mArgs.Length(); f++) { + const nsString &arg = mArgs[f]; + + if (arg.Length() >= 2 && arg.First() == char16_t('-')) { + if (aFlag.Equals(Substring(arg, 1), c)) { + *aResult = f; + return NS_OK; + } + } + } + + *aResult = -1; + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::RemoveArguments(int32_t aStart, int32_t aEnd) +{ + NS_ENSURE_ARG_MIN(aStart, 0); + NS_ENSURE_ARG_MAX(uint32_t(aEnd) + 1, mArgs.Length()); + + for (int32_t i = aEnd; i >= aStart; --i) { + mArgs.RemoveElementAt(i); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::HandleFlag(const nsAString& aFlag, bool aCaseSensitive, + bool *aResult) +{ + nsresult rv; + + int32_t found; + rv = FindFlag(aFlag, aCaseSensitive, &found); + NS_ENSURE_SUCCESS(rv, rv); + + if (found == -1) { + *aResult = false; + return NS_OK; + } + + *aResult = true; + RemoveArguments(found, found); + + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::HandleFlagWithParam(const nsAString& aFlag, bool aCaseSensitive, + nsAString& aResult) +{ + nsresult rv; + + int32_t found; + rv = FindFlag(aFlag, aCaseSensitive, &found); + NS_ENSURE_SUCCESS(rv, rv); + + if (found == -1) { + aResult.SetIsVoid(true); + return NS_OK; + } + + if (found == int32_t(mArgs.Length()) - 1) { + return NS_ERROR_INVALID_ARG; + } + + ++found; + + if (mArgs[found].First() == '-') { + return NS_ERROR_INVALID_ARG; + } + + aResult = mArgs[found]; + RemoveArguments(found - 1, found); + + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::GetState(uint32_t *aResult) +{ + *aResult = mState; + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::GetPreventDefault(bool *aResult) +{ + *aResult = mPreventDefault; + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::SetPreventDefault(bool aValue) +{ + mPreventDefault = aValue; + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::GetWorkingDirectory(nsIFile* *aResult) +{ + NS_ENSURE_TRUE(mWorkingDir, NS_ERROR_NOT_INITIALIZED); + + NS_ADDREF(*aResult = mWorkingDir); + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::GetWindowContext(nsIDOMWindow* *aResult) +{ + NS_IF_ADDREF(*aResult = mWindowContext); + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::SetWindowContext(nsIDOMWindow* aValue) +{ + mWindowContext = aValue; + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::ResolveFile(const nsAString& aArgument, nsIFile* *aResult) +{ + NS_ENSURE_TRUE(mWorkingDir, NS_ERROR_NOT_INITIALIZED); + + // This is some seriously screwed-up code. nsIFile.appendRelativeNativePath + // explicitly does not accept .. or . path parts, but that is exactly what we + // need here. So we hack around it. + + nsresult rv; + +#if defined(MOZ_WIDGET_COCOA) + nsCOMPtr<nsILocalFileMac> lfm (do_QueryInterface(mWorkingDir)); + NS_ENSURE_TRUE(lfm, NS_ERROR_NO_INTERFACE); + + nsCOMPtr<nsILocalFileMac> newfile (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + NS_ENSURE_TRUE(newfile, NS_ERROR_OUT_OF_MEMORY); + + CFURLRef baseurl; + rv = lfm->GetCFURL(&baseurl); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString path; + NS_CopyUnicodeToNative(aArgument, path); + + CFURLRef newurl = + CFURLCreateFromFileSystemRepresentationRelativeToBase(nullptr, (const UInt8*) path.get(), + path.Length(), + true, baseurl); + + CFRelease(baseurl); + + rv = newfile->InitWithCFURL(newurl); + CFRelease(newurl); + if (NS_FAILED(rv)) return rv; + + newfile.forget(aResult); + return NS_OK; + +#elif defined(XP_UNIX) + nsCOMPtr<nsIFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY); + + if (aArgument.First() == '/') { + // absolute path + rv = lf->InitWithPath(aArgument); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*aResult = lf); + return NS_OK; + } + + nsAutoCString nativeArg; + NS_CopyUnicodeToNative(aArgument, nativeArg); + + nsAutoCString newpath; + mWorkingDir->GetNativePath(newpath); + + newpath.Append('/'); + newpath.Append(nativeArg); + + rv = lf->InitWithNativePath(newpath); + if (NS_FAILED(rv)) return rv; + + rv = lf->Normalize(); + if (NS_FAILED(rv)) return rv; + + lf.forget(aResult); + return NS_OK; + +#elif defined(XP_WIN32) + nsCOMPtr<nsIFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY); + + rv = lf->InitWithPath(aArgument); + if (NS_FAILED(rv)) { + // If it's a relative path, the Init is *going* to fail. We use string magic and + // win32 _fullpath. Note that paths of the form "\Relative\To\CurDrive" are + // going to fail, and I haven't figured out a way to work around this without + // the PathCombine() function, which is not available in plain win95/nt4 + + nsAutoString fullPath; + mWorkingDir->GetPath(fullPath); + + fullPath.Append('\\'); + fullPath.Append(aArgument); + + WCHAR pathBuf[MAX_PATH]; + if (!_wfullpath(pathBuf, fullPath.get(), MAX_PATH)) + return NS_ERROR_FAILURE; + + rv = lf->InitWithPath(nsDependentString(pathBuf)); + if (NS_FAILED(rv)) return rv; + } + lf.forget(aResult); + return NS_OK; + +#else +#error Need platform-specific logic here. +#endif +} + +NS_IMETHODIMP +nsCommandLine::ResolveURI(const nsAString& aArgument, nsIURI* *aResult) +{ + nsresult rv; + + // First, we try to init the argument as an absolute file path. If this doesn't + // work, it is an absolute or relative URI. + + nsCOMPtr<nsIIOService> io = do_GetIOService(); + NS_ENSURE_TRUE(io, NS_ERROR_OUT_OF_MEMORY); + + nsCOMPtr<nsIURI> workingDirURI; + if (mWorkingDir) { + io->NewFileURI(mWorkingDir, getter_AddRefs(workingDirURI)); + } + + nsCOMPtr<nsIFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + rv = lf->InitWithPath(aArgument); + if (NS_SUCCEEDED(rv)) { + lf->Normalize(); + nsAutoCString url; + // Try to resolve the url for .url files. + rv = resolveShortcutURL(lf, url); + if (NS_SUCCEEDED(rv) && !url.IsEmpty()) { + return io->NewURI(url, + nullptr, + workingDirURI, + aResult); + } + + return io->NewFileURI(lf, aResult); + } + + return io->NewURI(NS_ConvertUTF16toUTF8(aArgument), + nullptr, + workingDirURI, + aResult); +} + +void +nsCommandLine::appendArg(const char* arg) +{ +#ifdef DEBUG_COMMANDLINE + printf("Adding XP arg: %s\n", arg); +#endif + + nsAutoString warg; +#ifdef XP_WIN + CopyUTF8toUTF16(nsDependentCString(arg), warg); +#else + NS_CopyNativeToUnicode(nsDependentCString(arg), warg); +#endif + + mArgs.AppendElement(warg); +} + +nsresult +nsCommandLine::resolveShortcutURL(nsIFile* aFile, nsACString& outURL) +{ + nsCOMPtr<nsIFileProtocolHandler> fph; + nsresult rv = NS_GetFileProtocolHandler(getter_AddRefs(fph)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr<nsIURI> uri; + rv = fph->ReadURLFile(aFile, getter_AddRefs(uri)); + if (NS_FAILED(rv)) + return rv; + + return uri->GetSpec(outURL); +} + +NS_IMETHODIMP +nsCommandLine::Init(int32_t argc, const char* const* argv, nsIFile* aWorkingDir, + uint32_t aState) +{ + NS_ENSURE_ARG_MAX(aState, 2); + + int32_t i; + + mWorkingDir = aWorkingDir; + + // skip argv[0], we don't want it + for (i = 1; i < argc; ++i) { + const char* curarg = argv[i]; + +#ifdef DEBUG_COMMANDLINE + printf("Testing native arg %i: '%s'\n", i, curarg); +#endif +#if defined(XP_WIN) + if (*curarg == '/') { + char* dup = PL_strdup(curarg); + if (!dup) return NS_ERROR_OUT_OF_MEMORY; + + *dup = '-'; + char* colon = PL_strchr(dup, ':'); + if (colon) { + *colon = '\0'; + appendArg(dup); + appendArg(colon+1); + } else { + appendArg(dup); + } + PL_strfree(dup); + continue; + } +#endif +#ifdef XP_UNIX + if (*curarg == '-' && + *(curarg+1) == '-') { + ++curarg; + + char* dup = PL_strdup(curarg); + if (!dup) return NS_ERROR_OUT_OF_MEMORY; + + char* eq = PL_strchr(dup, '='); + if (eq) { + *eq = '\0'; + appendArg(dup); + appendArg(eq + 1); + } else { + appendArg(dup); + } + PL_strfree(dup); + continue; + } +#endif + + appendArg(curarg); + } + + mState = aState; + + return NS_OK; +} + +static void +LogConsoleMessage(const char16_t* fmt, ...) +{ + va_list args; + va_start(args, fmt); + char16_t* msg = nsTextFormatter::vsmprintf(fmt, args); + va_end(args); + + nsCOMPtr<nsIConsoleService> cs = do_GetService("@mozilla.org/consoleservice;1"); + if (cs) + cs->LogStringMessage(msg); + + free(msg); +} + +nsresult +nsCommandLine::EnumerateHandlers(EnumerateHandlersCallback 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-handler", + getter_AddRefs(entenum)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIUTF8StringEnumerator> strenum (do_QueryInterface(entenum)); + NS_ENSURE_TRUE(strenum, NS_ERROR_UNEXPECTED); + + nsAutoCString entry; + bool hasMore; + while (NS_SUCCEEDED(strenum->HasMore(&hasMore)) && hasMore) { + strenum->GetNext(entry); + + nsCString contractID; + rv = catman->GetCategoryEntry("command-line-handler", + entry.get(), + getter_Copies(contractID)); + if (NS_FAILED(rv)) + continue; + + nsCOMPtr<nsICommandLineHandler> clh(do_GetService(contractID.get())); + if (!clh) { + LogConsoleMessage(u"Contract ID '%s' was registered as a command line handler for entry '%s', but could not be created.", + contractID.get(), entry.get()); + continue; + } + + rv = (aCallback)(clh, this, aClosure); + if (rv == NS_ERROR_ABORT) + break; + + rv = NS_OK; + } + + 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); + + nsAutoCString entry; + bool 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*) +{ + return aHandler->Handle(aThis); +} + +NS_IMETHODIMP +nsCommandLine::Run() +{ + nsresult rv; + + rv = EnumerateValidators(EnumValidate, nullptr); + if (rv == NS_ERROR_ABORT) + return rv; + + rv = EnumerateHandlers(EnumRun, nullptr); + if (rv == NS_ERROR_ABORT) + return rv; + + return NS_OK; +} + +static nsresult +EnumHelp(nsICommandLineHandler* aHandler, nsICommandLine* aThis, void* aClosure) +{ + nsresult rv; + + nsCString text; + rv = aHandler->GetHelpInfo(text); + if (NS_SUCCEEDED(rv)) { + NS_ASSERTION(text.Length() == 0 || text.Last() == '\n', + "Help text from command line handlers should end in a newline."); + + nsACString* totalText = reinterpret_cast<nsACString*>(aClosure); + totalText->Append(text); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCommandLine::GetHelpText(nsACString& aResult) +{ + EnumerateHandlers(EnumHelp, &aResult); + + return NS_OK; +} + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsCommandLine) + +NS_DEFINE_NAMED_CID(NS_COMMANDLINE_CID); + +static const mozilla::Module::CIDEntry kCommandLineCIDs[] = { + { &kNS_COMMANDLINE_CID, false, nullptr, nsCommandLineConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kCommandLineContracts[] = { + { "@mozilla.org/toolkit/command-line;1", &kNS_COMMANDLINE_CID }, + { nullptr } +}; + +static const mozilla::Module kCommandLineModule = { + mozilla::Module::kVersion, + kCommandLineCIDs, + kCommandLineContracts +}; + +NSMODULE_DEFN(CommandLineModule) = &kCommandLineModule; diff --git a/toolkit/components/commandlines/nsICommandLine.idl b/toolkit/components/commandlines/nsICommandLine.idl new file mode 100644 index 000000000..e44b3de9a --- /dev/null +++ b/toolkit/components/commandlines/nsICommandLine.idl @@ -0,0 +1,141 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIFile; +interface nsIURI; +interface nsIDOMWindow; + +/** + * Represents the command line used to invoke a XUL application. This may be the + * original command-line of this instance, or a command line remoted from another + * instance of the application. + * + * DEFINITIONS: + * "arguments" are any values found on the command line. + * "flags" are switches. In normalized form they are preceded by a single dash. + * Some flags may take "parameters", e.g. "--url <param>". + */ + +[scriptable, uuid(bc3173bd-aa46-46a0-9d25-d9867a9659b6)] +interface nsICommandLine : nsISupports +{ + /** + * Number of arguments in the command line. The application name is not + * part of the command line. + */ + readonly attribute long length; + + /** + * Get an argument from the array of command-line arguments. + * + * On windows, flags of the form /flag are normalized to -flag. /flag:param + * are normalized to -flag param. + * + * On *nix and mac flags of the form --flag are normalized to -flag. --flag=param + * are normalized to the form -flag param. + * + * @param aIndex The argument to retrieve. This index is 0-based, and does + * not include the application name. + * @return The indexth argument. + * @throws NS_ERROR_INVALID_ARG if aIndex is out of bounds. + */ + AString getArgument(in long aIndex); + + /** + * Find a command-line flag. + * + * @param aFlag The flag name to locate. Do not include the initial + * hyphen. + * @param aCaseSensitive Whether to do case-sensitive comparisons. + * @return The position of the flag in the command line. + */ + long findFlag(in AString aFlag, in boolean aCaseSensitive); + + /** + * Remove arguments from the command line. This normally occurs after + * a handler has processed the arguments. + * + * @param aStart Index to begin removing. + * @param aEnd Index to end removing, inclusive. + */ + void removeArguments(in long aStart, in long aEnd); + + /** + * A helper method which will find a flag and remove it in one step. + * + * @param aFlag The flag name to find and remove. + * @param aCaseSensitive Whether to do case-sensitive comparisons. + * @return Whether the flag was found. + */ + boolean handleFlag(in AString aFlag, in boolean aCaseSensitive); + + /** + * Find a flag with a parameter and remove both. This is a helper + * method that combines "findFlag" and "removeArguments" in one step. + * + * @return null (a void astring) if the flag is not found. The parameter value + * if found. Note that null and the empty string are not the same. + * @throws NS_ERROR_INVALID_ARG if the flag exists without a parameter + * + * @param aFlag The flag name to find and remove. + * @param aCaseSensitive Whether to do case-sensitive flag search. + */ + AString handleFlagWithParam(in AString aFlag, in boolean aCaseSensitive); + + /** + * The type of command line being processed. + * + * STATE_INITIAL_LAUNCH is the first launch of the application instance. + * STATE_REMOTE_AUTO is a remote command line automatically redirected to + * this instance. + * STATE_REMOTE_EXPLICIT is a remote command line explicitly redirected to + * this instance using xremote/windde/appleevents. + */ + readonly attribute unsigned long state; + + const unsigned long STATE_INITIAL_LAUNCH = 0; + const unsigned long STATE_REMOTE_AUTO = 1; + const unsigned long STATE_REMOTE_EXPLICIT = 2; + + /** + * There may be a command-line handler which performs a default action if + * there was no explicit action on the command line (open a default browser + * window, for example). This flag allows the default action to be prevented. + */ + attribute boolean preventDefault; + + /** + * The working directory for this command line. Use this property instead + * of the working directory for the current process, since a redirected + * command line may have had a different working directory. + */ + readonly attribute nsIFile workingDirectory; + + /** + * A window to be targeted by this command line. In most cases, this will + * be null (xremote will sometimes set this attribute). + */ + readonly attribute nsIDOMWindow windowContext; + + /** + * Resolve a file-path argument into an nsIFile. This method gracefully + * handles relative or absolute file paths, according to the working + * directory of this command line. + * + * @param aArgument The command-line argument to resolve. + */ + nsIFile resolveFile(in AString aArgument); + + /** + * Resolves a URI argument into a URI. This method has platform-specific + * logic for converting an absolute URI or a relative file-path into the + * appropriate URI object; it gracefully handles win32 C:\ paths which would + * confuse the ioservice if passed directly. + * + * @param aArgument The command-line argument to resolve. + */ + nsIURI resolveURI(in AString aArgument); +}; diff --git a/toolkit/components/commandlines/nsICommandLineHandler.idl b/toolkit/components/commandlines/nsICommandLineHandler.idl new file mode 100644 index 000000000..cd042d6a5 --- /dev/null +++ b/toolkit/components/commandlines/nsICommandLineHandler.idl @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsICommandLine; + +/** + * Handles arguments on the command line of an XUL application. + * + * Each handler is registered in the category "command-line-handler". + * 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, handler with ordinary priority should begin with "m". + * + * Example: + * Category Entry Value + * command-line-handler c-extensions @mozilla.org/extension-manager/clh;1 + * command-line-handler m-edit @mozilla.org/composer/clh;1 + * command-line-handler m-irc @mozilla.org/chatzilla/clh;1 + * command-line-handler y-final @mozilla.org/browser/clh-final;1 + * + * @note What do we do about localizing helpInfo? Do we make each handler do it, + * or provide a generic solution of some sort? Don't freeze this interface + * without thinking about this! + */ + +[scriptable, uuid(d4b123df-51ee-48b1-a663-002180e60d3b)] +interface nsICommandLineHandler : nsISupports +{ + /** + * Process a command line. If this handler finds arguments that it + * understands, it should perform the appropriate actions (such as opening + * a window), and remove the arguments from the command-line array. + * + * @throw NS_ERROR_ABORT to immediately cease command-line handling + * (if this is STATE_INITIAL_LAUNCH, quits the app). + * All other exceptions are silently ignored. + */ + void handle(in nsICommandLine aCommandLine); + + /** + * When the app is launched with the --help argument, this attribute + * is retrieved and displayed to the user (on stdout). The text should + * have embedded newlines which wrap at 76 columns, and should include + * a newline at the end. By convention, the right column which contains flag + * descriptions begins at the 24th character. + */ + readonly attribute AUTF8String helpInfo; +}; diff --git a/toolkit/components/commandlines/nsICommandLineRunner.idl b/toolkit/components/commandlines/nsICommandLineRunner.idl new file mode 100644 index 000000000..0cd3f0c90 --- /dev/null +++ b/toolkit/components/commandlines/nsICommandLineRunner.idl @@ -0,0 +1,55 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" +#include "nsICommandLine.idl" + +[ptr] native nsArgvArray(const char* const); + +/** + * Extension of nsICommandLine that allows for initialization of new command lines + * and running the command line actions by processing the command line handlers. + * + * @status INTERNAL - This interface is not meant for use by embedders, and is + * not intended to be frozen. If you are an embedder and need + * functionality provided by this interface, talk to Benjamin + * Smedberg <benjamin@smedbergs.us>. + */ + +[uuid(c9f2996c-b25a-4d3d-821f-4cd0c4bc8afb)] +interface nsICommandLineRunner : nsICommandLine +{ + /** + * This method assumes a native character set, and is meant to be called + * with the argc/argv passed to main(). Talk to bsmedberg if you need to + * create a command line using other data. argv will not be altered in any + * way. + * + * On Windows, the "native" character set is UTF-8, not the native codepage. + * + * @param workingDir The working directory for resolving file and URI paths. + * @param state The nsICommandLine.state flag. + */ + void init(in long argc, in nsArgvArray argv, + in nsIFile workingDir, in unsigned long state); + + /** + * Set the windowContext parameter. + */ + void setWindowContext(in nsIDOMWindow aWindow); + + /** + * Process the command-line handlers in the proper order, calling "handle()" on + * each. + * + * @throws NS_ERROR_ABORT if any handler throws NS_ERROR_ABORT. All other errors + * thrown by handlers will be silently ignored. + */ + void run(); + + /** + * Process and combine the help text provided by each command-line handler. + */ + readonly attribute AUTF8String helpText; +}; diff --git a/toolkit/components/commandlines/nsICommandLineValidator.idl b/toolkit/components/commandlines/nsICommandLineValidator.idl new file mode 100644 index 000000000..eba949bf3 --- /dev/null +++ b/toolkit/components/commandlines/nsICommandLineValidator.idl @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#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); +}; diff --git a/toolkit/components/commandlines/test/unit/.eslintrc.js b/toolkit/components/commandlines/test/unit/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/toolkit/components/commandlines/test/unit/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/toolkit/components/commandlines/test/unit/data/test_bug410156.desktop b/toolkit/components/commandlines/test/unit/data/test_bug410156.desktop new file mode 100644 index 000000000..1847cdd98 --- /dev/null +++ b/toolkit/components/commandlines/test/unit/data/test_bug410156.desktop @@ -0,0 +1,7 @@ +[Desktop Entry]
+Version=1.0
+Encoding=UTF-8
+Name=test_bug410156
+Type=Link
+URL=http://www.bug410156.com/
+Icon=gnome-fs-bookmark
diff --git a/toolkit/components/commandlines/test/unit/data/test_bug410156.url b/toolkit/components/commandlines/test/unit/data/test_bug410156.url new file mode 100644 index 000000000..6920e1f77 --- /dev/null +++ b/toolkit/components/commandlines/test/unit/data/test_bug410156.url @@ -0,0 +1,9 @@ +[InternetShortcut]
+URL=http://www.bug410156.com/
+IDList=
+HotKey=0
+[{000214A0-0000-0000-C000-000000000046}]
+Prop3=19,2
+[InternetShortcut.A]
+[InternetShortcut.W]
+URL=http://www.bug410156.com/
diff --git a/toolkit/components/commandlines/test/unit/test_bug666224.js b/toolkit/components/commandlines/test/unit/test_bug666224.js new file mode 100644 index 000000000..8d372097a --- /dev/null +++ b/toolkit/components/commandlines/test/unit/test_bug666224.js @@ -0,0 +1,6 @@ +function run_test() { + var cmdLine=Components.classes["@mozilla.org/toolkit/command-line;1"].createInstance(Components.interfaces.nsICommandLine); + try { + cmdLine.getArgument(cmdLine.length); + } catch (e) {} +} diff --git a/toolkit/components/commandlines/test/unit/test_classinfo.js b/toolkit/components/commandlines/test/unit/test_classinfo.js new file mode 100644 index 000000000..a0fb1ff0a --- /dev/null +++ b/toolkit/components/commandlines/test/unit/test_classinfo.js @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() { + var clClass = Components.classes["@mozilla.org/toolkit/command-line;1"]; + var commandLine = clClass.createInstance(); + do_check_true("length" in commandLine); +} diff --git a/toolkit/components/commandlines/test/unit/xpcshell.ini b/toolkit/components/commandlines/test/unit/xpcshell.ini new file mode 100644 index 000000000..4939a3d64 --- /dev/null +++ b/toolkit/components/commandlines/test/unit/xpcshell.ini @@ -0,0 +1,10 @@ +[DEFAULT] +head = +tail = +skip-if = toolkit == 'android' +support-files = + data/test_bug410156.desktop + data/test_bug410156.url + +[test_classinfo.js] +[test_bug666224.js] diff --git a/toolkit/components/commandlines/test/unit_unix/.eslintrc.js b/toolkit/components/commandlines/test/unit_unix/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/toolkit/components/commandlines/test/unit_unix/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/toolkit/components/commandlines/test/unit_unix/test_bug410156.js b/toolkit/components/commandlines/test/unit_unix/test_bug410156.js new file mode 100644 index 000000000..06c95ac35 --- /dev/null +++ b/toolkit/components/commandlines/test/unit_unix/test_bug410156.js @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() { + var clClass = Components.classes["@mozilla.org/toolkit/command-line;1"]; + var commandLine = clClass.createInstance(); + var urlFile = do_get_file("../unit/data/test_bug410156.desktop"); + var uri = commandLine.resolveURI(urlFile.path); + do_check_eq(uri.spec, "http://www.bug410156.com/"); +} diff --git a/toolkit/components/commandlines/test/unit_unix/xpcshell.ini b/toolkit/components/commandlines/test/unit_unix/xpcshell.ini new file mode 100644 index 000000000..41f71f48d --- /dev/null +++ b/toolkit/components/commandlines/test/unit_unix/xpcshell.ini @@ -0,0 +1,9 @@ +[DEFAULT] +head = +tail = +skip-if = toolkit == 'android' +support-files = + !/toolkit/components/commandlines/test/unit/data/test_bug410156.desktop + !/toolkit/components/commandlines/test/unit/data/test_bug410156.url + +[test_bug410156.js] diff --git a/toolkit/components/commandlines/test/unit_win/.eslintrc.js b/toolkit/components/commandlines/test/unit_win/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/toolkit/components/commandlines/test/unit_win/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/toolkit/components/commandlines/test/unit_win/test_bug410156.js b/toolkit/components/commandlines/test/unit_win/test_bug410156.js new file mode 100644 index 000000000..cc04426d6 --- /dev/null +++ b/toolkit/components/commandlines/test/unit_win/test_bug410156.js @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() { + var clClass = Components.classes["@mozilla.org/toolkit/command-line;1"]; + var commandLine = clClass.createInstance(); + var urlFile = do_get_file("../unit/data/test_bug410156.url"); + var uri = commandLine.resolveURI(urlFile.path); + do_check_eq(uri.spec, "http://www.bug410156.com/"); +} diff --git a/toolkit/components/commandlines/test/unit_win/xpcshell.ini b/toolkit/components/commandlines/test/unit_win/xpcshell.ini new file mode 100644 index 000000000..efc2cfccf --- /dev/null +++ b/toolkit/components/commandlines/test/unit_win/xpcshell.ini @@ -0,0 +1,8 @@ +[DEFAULT] +head = +tail = +support-files = + !/toolkit/components/commandlines/test/unit/data/test_bug410156.desktop + !/toolkit/components/commandlines/test/unit/data/test_bug410156.url + +[test_bug410156.js] |