blob: 06c08578346e8a28ca91012ea869daf7ea8acdbe [file] [log] [blame]
// Spoof the prompt service. Interesting thread on mozillazine:
// http://www.mail-archive.com/dev-tech-xpcom@lists.mozilla.org/msg00193.html
goog.require('fxdriver.logging');
goog.require('fxdriver.modals');
goog.require('fxdriver.moz');
goog.require('goog.array');
var EXCLUDED_NAMES = [
'QueryInterface',
'alert',
'alertCheck',
'confirm',
'confirmCheck',
'confirmEx',
'getPrompt',
'prompt',
'promptPassword',
'promptUsernameAndPassword',
'select'
];
function addInterfaces(to, delegate, interfaces) {
goog.array.forEach(interfaces, function(iid) {
try {
var queried = delegate.QueryInterface(iid);
for (var i in queried) {
if (!goog.array.contains(EXCLUDED_NAMES, i.toString())) {
to[i] = queried[i];
}
}
} catch (ignored) {}
});
}
// Implementation of nsIPrompt
function ObservingAlert(parentWindow, delegate) {
this.parentWindow_ = parentWindow;
var interfaces = [CI.nsIPrompt, CI.nsIAuthPrompt, CI.nsIAuthPrompt2, CI.nsIWritablePropertyBag2];
addInterfaces(this, delegate, interfaces);
this.delegate_ = delegate;
this.QueryInterface = fxdriver.moz.queryInterface(this, interfaces);
}
ObservingAlert.prototype.alert = function(dialogTitle, text) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
this.delegate_.alert(dialogTitle, text);
};
ObservingAlert.prototype.alertCheck = function(dialogTitle, text, checkMsg, checkValue) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
this.delegate_.alertCheck(dialogTitle, text, checkMsg, checkValue);
};
ObservingAlert.prototype.confirm = function(dialogTitle, text) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
return this.delegate_.confirm(dialogTitle, text);
};
ObservingAlert.prototype.confirmCheck = function(dialogTitle, text, checkMsg, checkValue) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
return this.delegate_.confirmCheck(dialogTitle, text, checkMsg, checkValue);
};
ObservingAlert.prototype.confirmEx = function(dialogTitle, text,
buttonFlags, button0Title, button1Title, button2Title,
checkMsg, checkValue) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
return this.delegate_.confirmEx(dialogTitle, text,
buttonFlags, button0Title, button1Title, button2Title,
checkMsg, checkValue);
};
ObservingAlert.prototype.prompt = function(dialogTitle, text, value, checkMsg, checkValue) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
return this.delegate_.prompt(dialogTitle, text, value, checkMsg, checkValue);
};
ObservingAlert.prototype.promptPassword = function(dialogTitle, text, password, checkMsg, checkValue) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
return this.delegate_.promptPassword(dialogTitle, text, password, checkMsg, checkValue);
};
ObservingAlert.prototype.promptUsernameAndPassword = function(dialogTitle, text, username, password, checkMsg, checkValue) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
return this.delegate_.promptUsernameAndPassword(dialogTitle, text, username, password, checkMsg, checkValue);
};
ObservingAlert.prototype.select = function(dialogTitle, text, count, selectList, outSelection) {
fxdriver.modals.signalOpenModal(this.parentWindow_, text);
return this.delegate_.select(dialogTitle, text, count, selectList, outSelection);
};
// Spoof implementation
function DrivenPromptService() {
fxdriver.logging.info('Spoofing prompt service');
// @mozilla.org/prompter;1
var prompters = [
'{1c978d25-b37f-43a8-a2d6-0c7a239ead87}' // nsPrompter.js: Firefox 4 late betas onwards
];
// @mozilla.org/embedcomp/prompt-service;
var promptServices = [
'{7ad1b327-6dfa-46ec-9234-f2a620ea7e00}', // nsPrompter.js: Firefox 4 betas
'{A2112D6A-0E28-421f-B46A-25C0B308CBD0}' // nsPromptService.h: Firefox 3.x
];
var findImplementation = function(interfaceName, cids) {
for (var i = 0; i < cids.length; i++) {
var impl = Components.classesByID[cids[i]];
if (!impl) { continue; }
var service = impl.getService();
if (!service) { continue; }
try {
var toReturn = service.QueryInterface(interfaceName);
fxdriver.logging.info('Found implementation at: ' + cids[i]);
return toReturn;
} catch (ignored) {}
}
return null;
};
// Keep a reference to the original service. Check for the most recent version of Firefox first
var originalPromptService_ = findImplementation(CI.nsIPromptService2, promptServices);
var originalPrompter_ = findImplementation(CI.nsIPromptFactory, prompters);
if (!originalPromptService_) {
fxdriver.logging.info('Unable to locate original prompt service');
}
if (!originalPrompter_) {
fxdriver.logging.info('Unable to locate original prompter');
}
this.delegate_ = originalPrompter_ ? originalPrompter_ : originalPromptService_;
var interfaces = [CI.nsIPromptFactory, CI.nsIPromptService, CI.nsIPromptService2];
addInterfaces(this, this.delegate_, interfaces);
this.QueryInterface = fxdriver.moz.queryInterface(this,
[CI.nsIPromptFactory, CI.nsIPromptService, CI.nsIPromptService2]);
fxdriver.logging.info('Finished initializing spoofed prompt service');
}
// Constants from nsIPromtService.idl
DrivenPromptService.prototype = {
BUTTON_POS_0: 1,
BUTTON_POS_1: 256,
BUTTON_POS_2: 65536,
// Button Title Flags (used to set the labels of buttons in the prompt)
BUTTON_TITLE_OK: 1,
BUTTON_TITLE_CANCEL: 2,
BUTTON_TITLE_YES: 3,
BUTTON_TITLE_NO: 4,
BUTTON_TITLE_SAVE: 5,
BUTTON_TITLE_DONT_SAVE: 6,
BUTTON_TITLE_REVERT: 7,
BUTTON_TITLE_IS_STRING: 127,
// Button Default Flags (used to select which button is the default one)
BUTTON_POS_0_DEFAULT: 0,
BUTTON_POS_1_DEFAULT: 16777216,
BUTTON_POS_2_DEFAULT: 33554432,
// Causes the buttons to be initially disabled. They are enabled after a
// timeout expires. The implementation may interpret this loosely as the
// intent is to ensure that the user does not click through a security dialog
// too quickly. Strictly speaking, the implementation could choose to ignore
// this flag.
BUTTON_DELAY_ENABLE: 67108864,
// Selects the standard set of OK/Cancel buttons.
STD_OK_CANCEL_BUTTONS: (this.BUTTON_TITLE_OK * this.BUTTON_POS_0) + (this.BUTTON_TITLE_CANCEL
* this.BUTTON_POS_1),
// Selects the standard set of Yes/No buttons.
STD_YES_NO_BUTTONS: (this.BUTTON_TITLE_YES * this.BUTTON_POS_0) + (this.BUTTON_TITLE_NO
* this.BUTTON_POS_1)
};
DrivenPromptService.prototype.alert = function(aParent, aDialogTitle, aText) {
fxdriver.modals.signalOpenModal(aParent, aText);
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.alert(aParent, aDialogTitle, aText);
};
DrivenPromptService.prototype.alertCheck =
function(aParent, aDialogTitle, aText, aCheckMsg, aCheckState) {
fxdriver.modals.signalOpenModal(aParent, aText);
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.alertCheck(aParent, aDialogTitle, aText, aCheckMsg, aCheckState);
};
DrivenPromptService.prototype.confirm = function(aParent, aDialogTitle, aText) {
fxdriver.modals.signalOpenModal(aParent, aText);
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.confirm(aParent, aDialogTitle, aText);
};
DrivenPromptService.prototype.confirmCheck =
function(aParent, aDialogTitle, aText, aCheckMsg, aCheckState) {
fxdriver.modals.signalOpenModal(aParent, aText);
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.confirmCheck(aParent, aDialogTitle, aText, aCheckMsg, aCheckState);
};
DrivenPromptService.prototype.confirmEx =
function(aParent, aDialogTitle, aText, aButtonFlags, aButton0Title, aButton1Title, aButton2Title, aCheckMsg, aCheckState) {
fxdriver.modals.signalOpenModal(aParent, aText);
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.confirmEx(aParent, aDialogTitle, aText, aButtonFlags, aButton0Title, aButton1Title, aButton2Title, aCheckMsg, aCheckState);
};
DrivenPromptService.prototype.prompt =
function(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState) {
fxdriver.modals.signalOpenModal(aParent, aText);
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.prompt(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState);
};
DrivenPromptService.prototype.promptUsernameAndPassword =
function(aParent, aDialogTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState) {
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.promptUsernameAndPassword(aParent, aDialogTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState);
};
DrivenPromptService.prototype.promptPassword =
function(aParent, aDialogTitle, aText, aPassword, aCheckMsg, aCheckState) {
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.promptPassword(aParent, aDialogTitle, aText, aPassword, aCheckMsg, aCheckState);
};
DrivenPromptService.prototype.select =
function(aParent, aDialogTitle, aText, aCount, aSelectList, aOutSelection) {
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.select(aParent, aDialogTitle, aText, aCount, aSelectList, aOutSelection);
};
// nsIPromptService2 functions
DrivenPromptService.prototype.promptAuth = function(aParent, aChannel, level, authInfo, checkboxLabel, checkValue) {
fxdriver.modals.signalOpenModal(aParent, '');
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.promptAuth(aParent, aChannel, level, authInfo, checkboxLabel, checkValue);
};
DrivenPromptService.prototype.asyncPromptAuth = function(aParent, aChannel, aCallback, aContext, level, authInfo, checkboxLabel,checkValue) {
fxdriver.modals.signalOpenModal(aParent, '');
var service = this.delegate_.QueryInterface(CI.nsIPromptService2);
return service.asyncPromptAuth(aParent, aChannel, aCallback, aContext, level, authInfo, checkboxLabel, checkValue);
};
// nsIPromptFactory
DrivenPromptService.prototype.getPrompt = function(domWin, iid) {
var factory = this.delegate_.QueryInterface(CI.nsIPromptFactory);
var rawPrompt = factory.getPrompt(domWin, iid);
return new ObservingAlert(domWin, rawPrompt);
};
// nsIObserver
DrivenPromptService.prototype.observe = function(aSubject, aTopic, aData) {
return this.delegate_.observe(aSubject, aTopic, aData);
};
/** @const */ var PROMPT_SERVICE_CONTRACT_ID = '@mozilla.org/embedcomp/prompt-service;1';
/** @const */ var PROMPTER_CONTRACT_ID = '@mozilla.org/prompter;1';
// This is defined by us
/** @const */ var DRIVEN_PROMPT_SERVICE_CLASS_ID = Components.ID('{e26dbdcd-d3ba-4ded-88c3-6cb07ee3e9e0}');
var service = undefined;
var PromptServiceSpoofFactory = {
createInstance: function(aOuter, aIID) {
if (aOuter != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
if (service == undefined) {
service = new DrivenPromptService();
}
return service;
}
};
function PromptServiceSpoofModule() {
this.firstTime_ = true;
}
PromptServiceSpoofModule.prototype.registerSelf = function(aCompMgr, aFileSpec, aLocation, aType) {
if (this.firstTime_) {
this.firstTime_ = false;
throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
}
aCompMgr = aCompMgr.QueryInterface(CI.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation(
DRIVEN_PROMPT_SERVICE_CLASS_ID, 'Driven prompt service', PROMPT_SERVICE_CONTRACT_ID, aFileSpec, aLocation, aType);
aCompMgr.registerFactoryLocation(
DRIVEN_PROMPT_SERVICE_CLASS_ID, 'Driven prompter service', PROMPTER_CONTRACT_ID, aFileSpec, aLocation, aType);
};
PromptServiceSpoofModule.prototype.unregisterSelf = function(aCompMgr, aLocation, aType) {
fxdriver.logging.info('Unregistering\n');
aCompMgr.QueryInterface(CI.nsIComponentRegistrar);
aCompMgr.unregisterFactoryLocation(DRIVEN_PROMPT_SERVICE_CLASS_ID, aLocation);
};
PromptServiceSpoofModule.prototype.getClassObject = function(aCompMgr, aCID, aIID) {
if (!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
if (aCID.equals(DRIVEN_PROMPT_SERVICE_CLASS_ID))
return PromptServiceSpoofFactory;
throw Components.results.NS_ERROR_NO_INTERFACE;
};
PromptServiceSpoofModule.prototype.canUnload = function(aCompMgr) {
return true;
};
NSGetModule = function(comMgr, fileSpec) {
return new PromptServiceSpoofModule();
};
DrivenPromptService.prototype.classID = DRIVEN_PROMPT_SERVICE_CLASS_ID;
fxdriver.moz.load('resource://gre/modules/XPCOMUtils.jsm');
if (XPCOMUtils.generateNSGetFactory) {
/** @const */ NSGetFactory = XPCOMUtils.generateNSGetFactory([DrivenPromptService]);
}