136 lines
4.4 KiB
JavaScript
136 lines
4.4 KiB
JavaScript
/* 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/. */
|
|
|
|
/**
|
|
* The IOpenWithLauncher api call protocol shared by the producer
|
|
* (ShellService.setAsDefault{PDF,Protocol}Handler) and the consumer
|
|
* (WindowsSetDefaultAppCmdHandler).
|
|
*
|
|
* ShellService arms a one-shot redirect before launching the OS "Open with"
|
|
* picker via IOpenWithLauncher; once the user picks Firefox, the OS relaunches
|
|
* Firefox with the same value and the command-line handler consumes it. This
|
|
* module owns that shared state (the pref shape and the matching rules).
|
|
*/
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
|
|
});
|
|
|
|
// This pref is an object { openWithArg, overrideUri, type } consumed by
|
|
// WindowsSetDefaultAppCmdHandler when the user picks a default (file type or
|
|
// protocol) using the IOpenWithLauncher API. It is reset anytime the dialog is
|
|
// used again, or when we intercept the OS reopening one of our openWithArgs.
|
|
export const SET_DEFAULT_REDIRECT_PREF =
|
|
"browser.shell.setDefaultApp.pendingRedirect";
|
|
|
|
export class WindowsSetDefaultRedirect {
|
|
// Supported default types to set using IOpenWithLauncher.
|
|
static TYPE = {
|
|
FILE: 1 << 0,
|
|
PROTOCOL: 1 << 1,
|
|
};
|
|
|
|
/**
|
|
* Stash a one-shot redirect for the IOpenWithLauncher call.
|
|
*
|
|
* @param {string} openWithArg
|
|
* The value handed to launchSetDefaultAppPicker, which the OS hands back as
|
|
* "-osint -url <openWithArg>" once the user picks a new default. Depending on
|
|
* type, this is either a file path on the system (file-type defaults) or a
|
|
* URL (protocol defaults).
|
|
* @param {?string} overrideUri
|
|
* URI spec to open when openWithArg comes back, or null to consume the relaunch
|
|
* and open nothing.
|
|
* @param {number} type
|
|
* One of WindowsSetDefaultRedirect.TYPE, identifying whether openWithArg is a
|
|
* file path or a URL.
|
|
*/
|
|
static arm(openWithArg, overrideUri, type) {
|
|
// Clear any stale object left by an older call.
|
|
Services.prefs.clearUserPref(SET_DEFAULT_REDIRECT_PREF);
|
|
|
|
Services.prefs.setStringPref(
|
|
SET_DEFAULT_REDIRECT_PREF,
|
|
JSON.stringify({ openWithArg, overrideUri: overrideUri ?? null, type })
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Clear a pending redirect.
|
|
*/
|
|
static clear() {
|
|
Services.prefs.clearUserPref(SET_DEFAULT_REDIRECT_PREF);
|
|
}
|
|
|
|
/**
|
|
* If `arg` is the openWithArg stashed by the most recent
|
|
* launchSetDefaultAppPicker call, consume the one-shot redirect and return
|
|
* its `{ overrideUri }`, where overrideUri is a URI spec to open or null to
|
|
* just suppress the relaunch. Returns null when `arg` is unrelated to a
|
|
* pending attempt to set a default.
|
|
*
|
|
* @param {string} arg - The -url value the OS handed back.
|
|
* @returns {?{overrideUri: ?string}}
|
|
*/
|
|
static consume(arg) {
|
|
const state = this.#read();
|
|
if (!state || !this.#matches(state, arg)) {
|
|
return null;
|
|
}
|
|
Services.prefs.clearUserPref(SET_DEFAULT_REDIRECT_PREF);
|
|
return { overrideUri: state.overrideUri ?? null };
|
|
}
|
|
|
|
/**
|
|
* Read and validate the pending redirect stashed by arm().
|
|
*
|
|
* @returns {?{openWithArg: string, overrideUri: ?string, type: number}} The
|
|
* stored state, or null when the pref is unset, holds the wrong type, or is
|
|
* malformed JSON.
|
|
*/
|
|
static #read() {
|
|
let raw;
|
|
try {
|
|
raw = Services.prefs.getStringPref(SET_DEFAULT_REDIRECT_PREF, "");
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
if (!raw) {
|
|
return null;
|
|
}
|
|
try {
|
|
const state = JSON.parse(raw);
|
|
return state && typeof state.openWithArg === "string" ? state : null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if the -url value the OS handed back matches the stashed redirect.
|
|
*
|
|
* @param {{openWithArg: string, type: number}} state - The stashed redirect.
|
|
* @param {string} arg - The -url value from the OS relaunch.
|
|
* @returns {boolean}
|
|
*/
|
|
static #matches(state, arg) {
|
|
switch (state.type) {
|
|
case this.TYPE.PROTOCOL:
|
|
return state.openWithArg === arg;
|
|
case this.TYPE.FILE:
|
|
try {
|
|
return new lazy.FileUtils.File(state.openWithArg).equals(
|
|
new lazy.FileUtils.File(arg)
|
|
);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|