Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 const Cc = Components.classes;
7 const Ci = Components.interfaces;
8 const Cr = Components.results;
9 const Cu = Components.utils;
11 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
12 Cu.import("resource://gre/modules/Services.jsm");
13 Cu.import("resource://gre/modules/SharedPromptUtils.jsm");
15 function Prompter() {
16 // Note that EmbedPrompter clones this implementation.
17 }
19 Prompter.prototype = {
20 classID : Components.ID("{1c978d25-b37f-43a8-a2d6-0c7a239ead87}"),
21 QueryInterface : XPCOMUtils.generateQI([Ci.nsIPromptFactory, Ci.nsIPromptService, Ci.nsIPromptService2]),
24 /* ---------- private memebers ---------- */
26 pickPrompter : function (domWin) {
27 return new ModalPrompter(domWin);
28 },
31 /* ---------- nsIPromptFactory ---------- */
34 getPrompt : function (domWin, iid) {
35 // This is still kind of dumb; the C++ code delegated to login manager
36 // here, which in turn calls back into us via nsIPromptService2.
37 if (iid.equals(Ci.nsIAuthPrompt2) || iid.equals(Ci.nsIAuthPrompt)) {
38 try {
39 let pwmgr = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"].
40 getService(Ci.nsIPromptFactory);
41 return pwmgr.getPrompt(domWin, iid);
42 } catch (e) {
43 Cu.reportError("nsPrompter: Delegation to password manager failed: " + e);
44 }
45 }
47 let p = new ModalPrompter(domWin);
48 p.QueryInterface(iid);
49 return p;
50 },
53 /* ---------- nsIPromptService ---------- */
56 alert : function (domWin, title, text) {
57 let p = this.pickPrompter(domWin);
58 p.alert(title, text);
59 },
61 alertCheck : function (domWin, title, text, checkLabel, checkValue) {
62 let p = this.pickPrompter(domWin);
63 p.alertCheck(title, text, checkLabel, checkValue);
64 },
66 confirm : function (domWin, title, text) {
67 let p = this.pickPrompter(domWin);
68 return p.confirm(title, text);
69 },
71 confirmCheck : function (domWin, title, text, checkLabel, checkValue) {
72 let p = this.pickPrompter(domWin);
73 return p.confirmCheck(title, text, checkLabel, checkValue);
74 },
76 confirmEx : function (domWin, title, text, flags, button0, button1, button2, checkLabel, checkValue) {
77 let p = this.pickPrompter(domWin);
78 return p.confirmEx(title, text, flags, button0, button1, button2, checkLabel, checkValue);
79 },
81 prompt : function (domWin, title, text, value, checkLabel, checkValue) {
82 let p = this.pickPrompter(domWin);
83 return p.nsIPrompt_prompt(title, text, value, checkLabel, checkValue);
84 },
86 promptUsernameAndPassword : function (domWin, title, text, user, pass, checkLabel, checkValue) {
87 let p = this.pickPrompter(domWin);
88 return p.nsIPrompt_promptUsernameAndPassword(title, text, user, pass, checkLabel, checkValue);
89 },
91 promptPassword : function (domWin, title, text, pass, checkLabel, checkValue) {
92 let p = this.pickPrompter(domWin);
93 return p.nsIPrompt_promptPassword(title, text, pass, checkLabel, checkValue);
94 },
96 select : function (domWin, title, text, count, list, selected) {
97 let p = this.pickPrompter(domWin);
98 return p.select(title, text, count, list, selected);
99 },
102 /* ---------- nsIPromptService2 ---------- */
105 promptAuth : function (domWin, channel, level, authInfo, checkLabel, checkValue) {
106 let p = this.pickPrompter(domWin);
107 return p.promptAuth(channel, level, authInfo, checkLabel, checkValue);
108 },
110 asyncPromptAuth : function (domWin, channel, callback, context, level, authInfo, checkLabel, checkValue) {
111 let p = this.pickPrompter(domWin);
112 return p.asyncPromptAuth(channel, callback, context, level, authInfo, checkLabel, checkValue);
113 },
115 };
118 // Common utils not specific to a particular prompter style.
119 let PromptUtilsTemp = {
120 __proto__ : PromptUtils,
122 getLocalizedString : function (key, formatArgs) {
123 if (formatArgs)
124 return this.strBundle.formatStringFromName(key, formatArgs, formatArgs.length);
125 else
126 return this.strBundle.GetStringFromName(key);
127 },
129 confirmExHelper : function (flags, button0, button1, button2) {
130 const BUTTON_DEFAULT_MASK = 0x03000000;
131 let defaultButtonNum = (flags & BUTTON_DEFAULT_MASK) >> 24;
132 let isDelayEnabled = (flags & Ci.nsIPrompt.BUTTON_DELAY_ENABLE);
134 // Flags can be used to select a specific pre-defined button label or
135 // a caller-supplied string (button0/button1/button2). If no flags are
136 // set for a button, then the button won't be shown.
137 let argText = [button0, button1, button2];
138 let buttonLabels = [null, null, null];
139 for (let i = 0; i < 3; i++) {
140 let buttonLabel;
141 switch (flags & 0xff) {
142 case Ci.nsIPrompt.BUTTON_TITLE_OK:
143 buttonLabel = PromptUtils.getLocalizedString("OK");
144 break;
145 case Ci.nsIPrompt.BUTTON_TITLE_CANCEL:
146 buttonLabel = PromptUtils.getLocalizedString("Cancel");
147 break;
148 case Ci.nsIPrompt.BUTTON_TITLE_YES:
149 buttonLabel = PromptUtils.getLocalizedString("Yes");
150 break;
151 case Ci.nsIPrompt.BUTTON_TITLE_NO:
152 buttonLabel = PromptUtils.getLocalizedString("No");
153 break;
154 case Ci.nsIPrompt.BUTTON_TITLE_SAVE:
155 buttonLabel = PromptUtils.getLocalizedString("Save");
156 break;
157 case Ci.nsIPrompt.BUTTON_TITLE_DONT_SAVE:
158 buttonLabel = PromptUtils.getLocalizedString("DontSave");
159 break;
160 case Ci.nsIPrompt.BUTTON_TITLE_REVERT:
161 buttonLabel = PromptUtils.getLocalizedString("Revert");
162 break;
163 case Ci.nsIPrompt.BUTTON_TITLE_IS_STRING:
164 buttonLabel = argText[i];
165 break;
166 }
167 if (buttonLabel)
168 buttonLabels[i] = buttonLabel;
169 flags >>= 8;
170 }
172 return [buttonLabels[0], buttonLabels[1], buttonLabels[2], defaultButtonNum, isDelayEnabled];
173 },
175 getAuthInfo : function (authInfo) {
176 let username, password;
178 let flags = authInfo.flags;
179 if (flags & Ci.nsIAuthInformation.NEED_DOMAIN && authInfo.domain)
180 username = authInfo.domain + "\\" + authInfo.username;
181 else
182 username = authInfo.username;
184 password = authInfo.password;
186 return [username, password];
187 },
189 setAuthInfo : function (authInfo, username, password) {
190 let flags = authInfo.flags;
191 if (flags & Ci.nsIAuthInformation.NEED_DOMAIN) {
192 // Domain is separated from username by a backslash
193 let idx = username.indexOf("\\");
194 if (idx == -1) {
195 authInfo.username = username;
196 } else {
197 authInfo.domain = username.substring(0, idx);
198 authInfo.username = username.substring(idx+1);
199 }
200 } else {
201 authInfo.username = username;
202 }
203 authInfo.password = password;
204 },
206 // Copied from login manager
207 getFormattedHostname : function (uri) {
208 let scheme = uri.scheme;
209 let hostname = scheme + "://" + uri.host;
211 // If the URI explicitly specified a port, only include it when
212 // it's not the default. (We never want "http://foo.com:80")
213 port = uri.port;
214 if (port != -1) {
215 let handler = Services.io.getProtocolHandler(scheme);
216 if (port != handler.defaultPort)
217 hostname += ":" + port;
218 }
220 return hostname;
221 },
223 // Copied from login manager
224 getAuthTarget : function (aChannel, aAuthInfo) {
225 let hostname, realm;
227 // If our proxy is demanding authentication, don't use the
228 // channel's actual destination.
229 if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
230 if (!(aChannel instanceof Ci.nsIProxiedChannel))
231 throw "proxy auth needs nsIProxiedChannel";
233 let info = aChannel.proxyInfo;
234 if (!info)
235 throw "proxy auth needs nsIProxyInfo";
237 // Proxies don't have a scheme, but we'll use "moz-proxy://"
238 // so that it's more obvious what the login is for.
239 let idnService = Cc["@mozilla.org/network/idn-service;1"].
240 getService(Ci.nsIIDNService);
241 hostname = "moz-proxy://" +
242 idnService.convertUTF8toACE(info.host) +
243 ":" + info.port;
244 realm = aAuthInfo.realm;
245 if (!realm)
246 realm = hostname;
248 return [hostname, realm];
249 }
251 hostname = this.getFormattedHostname(aChannel.URI);
253 // If a HTTP WWW-Authenticate header specified a realm, that value
254 // will be available here. If it wasn't set or wasn't HTTP, we'll use
255 // the formatted hostname instead.
256 realm = aAuthInfo.realm;
257 if (!realm)
258 realm = hostname;
260 return [hostname, realm];
261 },
264 makeAuthMessage : function (channel, authInfo) {
265 let isProxy = (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY);
266 let isPassOnly = (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD);
268 let username = authInfo.username;
269 let [displayHost, realm] = this.getAuthTarget(channel, authInfo);
271 // Suppress "the site says: $realm" when we synthesized a missing realm.
272 if (!authInfo.realm && !isProxy)
273 realm = "";
275 // Trim obnoxiously long realms.
276 if (realm.length > 150) {
277 realm = realm.substring(0, 150);
278 // Append "..." (or localized equivalent).
279 realm += this.ellipsis;
280 }
282 let text;
283 if (isProxy)
284 text = PromptUtils.getLocalizedString("EnterLoginForProxy", [realm, displayHost]);
285 else if (isPassOnly)
286 text = PromptUtils.getLocalizedString("EnterPasswordFor", [username, displayHost]);
287 else if (!realm)
288 text = PromptUtils.getLocalizedString("EnterUserPasswordFor", [displayHost]);
289 else
290 text = PromptUtils.getLocalizedString("EnterLoginForRealm", [realm, displayHost]);
292 return text;
293 },
295 getTabModalPrompt : function (domWin) {
296 var promptBox = null;
298 try {
299 // Get the topmost window, in case we're in a frame.
300 var promptWin = domWin.top;
302 // Get the chrome window for the content window we're using.
303 // (Unwrap because we need a non-IDL property below.)
304 var chromeWin = promptWin.QueryInterface(Ci.nsIInterfaceRequestor)
305 .getInterface(Ci.nsIWebNavigation)
306 .QueryInterface(Ci.nsIDocShell)
307 .chromeEventHandler.ownerDocument
308 .defaultView.wrappedJSObject;
310 if (chromeWin.getTabModalPromptBox)
311 promptBox = chromeWin.getTabModalPromptBox(promptWin);
312 } catch (e) {
313 // If any errors happen, just assume no tabmodal prompter.
314 }
316 return promptBox;
317 },
318 };
320 PromptUtils = PromptUtilsTemp;
322 XPCOMUtils.defineLazyGetter(PromptUtils, "strBundle", function () {
323 let bunService = Cc["@mozilla.org/intl/stringbundle;1"].
324 getService(Ci.nsIStringBundleService);
325 let bundle = bunService.createBundle("chrome://global/locale/commonDialogs.properties");
326 if (!bundle)
327 throw "String bundle for Prompter not present!";
328 return bundle;
329 });
331 XPCOMUtils.defineLazyGetter(PromptUtils, "ellipsis", function () {
332 let ellipsis = "\u2026";
333 try {
334 ellipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
335 } catch (e) { }
336 return ellipsis;
337 });
341 function openModalWindow(domWin, uri, args) {
342 // There's an implied contract that says modal prompts should still work
343 // when no "parent" window is passed for the dialog (eg, the "Master
344 // Password" dialog does this). These prompts must be shown even if there
345 // are *no* visible windows at all.
346 // There's also a requirement for prompts to be blocked if a window is
347 // passed and that window is hidden (eg, auth prompts are supressed if the
348 // passed window is the hidden window).
349 // See bug 875157 comment 30 for more...
350 if (domWin) {
351 // a domWin was passed, so we can apply the check for it being hidden.
352 let winUtils = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
353 .getInterface(Ci.nsIDOMWindowUtils);
355 if (winUtils && !winUtils.isParentWindowMainWidgetVisible) {
356 throw Components.Exception("Cannot call openModalWindow on a hidden window",
357 Cr.NS_ERROR_NOT_AVAILABLE);
358 }
359 } else {
360 // We try and find a window to use as the parent, but don't consider
361 // if that is visible before showing the prompt.
362 domWin = Services.ww.activeWindow;
363 // domWin may still be null here if there are _no_ windows open.
364 }
365 // Note that we don't need to fire DOMWillOpenModalDialog and
366 // DOMModalDialogClosed events here, wwatcher's OpenWindowInternal
367 // will do that. Similarly for enterModalState / leaveModalState.
369 Services.ww.openWindow(domWin, uri, "_blank", "centerscreen,chrome,modal,titlebar", args);
370 }
372 function openTabPrompt(domWin, tabPrompt, args) {
373 PromptUtils.fireDialogEvent(domWin, "DOMWillOpenModalDialog");
375 let winUtils = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
376 .getInterface(Ci.nsIDOMWindowUtils);
377 winUtils.enterModalState();
379 // We provide a callback so the prompt can close itself. We don't want to
380 // wait for this event loop to return... Otherwise the presence of other
381 // prompts on the call stack would in this dialog appearing unresponsive
382 // until the other prompts had been closed.
383 let callbackInvoked = false;
384 let newPrompt;
385 function onPromptClose(forceCleanup) {
386 if (!newPrompt && !forceCleanup)
387 return;
388 callbackInvoked = true;
389 if (newPrompt)
390 tabPrompt.removePrompt(newPrompt);
392 domWin.removeEventListener("pagehide", pagehide);
394 winUtils.leaveModalState();
396 PromptUtils.fireDialogEvent(domWin, "DOMModalDialogClosed");
397 }
399 domWin.addEventListener("pagehide", pagehide);
400 function pagehide() {
401 domWin.removeEventListener("pagehide", pagehide);
403 if (newPrompt) {
404 newPrompt.abortPrompt();
405 }
406 }
408 try {
409 let topPrincipal = domWin.top.document.nodePrincipal;
410 let promptPrincipal = domWin.document.nodePrincipal;
411 args.showAlertOrigin = topPrincipal.equals(promptPrincipal);
412 args.promptActive = true;
414 newPrompt = tabPrompt.appendPrompt(args, onPromptClose);
416 // TODO since we don't actually open a window, need to check if
417 // there's other stuff in nsWindowWatcher::OpenWindowInternal
418 // that we might need to do here as well.
420 let thread = Services.tm.currentThread;
421 while (args.promptActive)
422 thread.processNextEvent(true);
423 delete args.promptActive;
425 if (args.promptAborted)
426 throw Components.Exception("prompt aborted by user", Cr.NS_ERROR_NOT_AVAILABLE);
427 } finally {
428 // If the prompt unexpectedly failed to invoke the callback, do so here.
429 if (!callbackInvoked)
430 onPromptClose(true);
431 }
432 }
434 function openRemotePrompt(domWin, args, tabPrompt) {
435 let messageManager = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
436 .getInterface(Ci.nsIWebNavigation)
437 .QueryInterface(Ci.nsIDocShell)
438 .QueryInterface(Ci.nsIInterfaceRequestor)
439 .getInterface(Ci.nsITabChild)
440 .messageManager;
442 PromptUtils.fireDialogEvent(domWin, "DOMWillOpenModalDialog");
444 let winUtils = domWin.QueryInterface(Ci.nsIInterfaceRequestor)
445 .getInterface(Ci.nsIDOMWindowUtils);
446 winUtils.enterModalState();
447 let closed = false;
449 // It should be hard or impossible to cause a window to create multiple
450 // prompts, but just in case, give our prompt an ID.
451 let id = "id" + Cc["@mozilla.org/uuid-generator;1"]
452 .getService(Ci.nsIUUIDGenerator).generateUUID().toString();
454 messageManager.addMessageListener("Prompt:Close", function listener(message) {
455 if (message.data._remoteId !== id) {
456 return;
457 }
459 messageManager.removeMessageListener("Prompt:Close", listener);
460 domWin.removeEventListener("pagehide", pagehide);
462 winUtils.leaveModalState();
463 PromptUtils.fireDialogEvent(domWin, "DOMModalDialogClosed");
465 // Copy the response from the closed prompt into our args, it will be
466 // read by our caller.
467 if (message.data) {
468 for (let key in message.data) {
469 args[key] = message.data[key];
470 }
471 }
473 // Exit our nested event loop when we unwind.
474 closed = true;
475 });
477 domWin.addEventListener("pagehide", pagehide);
478 function pagehide() {
479 domWin.removeEventListener("pagehide", pagehide);
480 messageManager.sendAsyncMessage("Prompt:ForceClose", { _remoteId: id });
481 }
483 let topPrincipal = domWin.top.document.nodePrincipal;
484 let promptPrincipal = domWin.document.nodePrincipal;
485 args.showAlertOrigin = topPrincipal.equals(promptPrincipal);
487 args._remoteId = id;
489 messageManager.sendAsyncMessage("Prompt:Open", args, {});
491 let thread = Services.tm.currentThread;
492 while (!closed) {
493 thread.processNextEvent(true);
494 }
495 }
497 function ModalPrompter(domWin) {
498 this.domWin = domWin;
499 }
500 ModalPrompter.prototype = {
501 domWin : null,
502 /*
503 * Default to not using a tab-modal prompt, unless the caller opts in by
504 * QIing to nsIWritablePropertyBag and setting the value of this property
505 * to true.
506 */
507 allowTabModal : false,
509 QueryInterface : XPCOMUtils.generateQI([Ci.nsIPrompt, Ci.nsIAuthPrompt,
510 Ci.nsIAuthPrompt2,
511 Ci.nsIWritablePropertyBag2]),
514 /* ---------- internal methods ---------- */
517 openPrompt : function (args) {
518 // Check pref, if false/missing do not ever allow tab-modal prompts.
519 const prefName = "prompts.tab_modal.enabled";
520 let prefValue = false;
521 if (Services.prefs.getPrefType(prefName) == Services.prefs.PREF_BOOL)
522 prefValue = Services.prefs.getBoolPref(prefName);
524 let allowTabModal = this.allowTabModal && prefValue;
526 if (allowTabModal && this.domWin) {
527 if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
528 openRemotePrompt(this.domWin, args, true);
529 return;
530 }
532 let tabPrompt = PromptUtils.getTabModalPrompt(this.domWin);
533 if (tabPrompt) {
534 openTabPrompt(this.domWin, tabPrompt, args);
535 return;
536 }
537 }
539 // If we can't do a tab modal prompt, fallback to using a window-modal dialog.
540 const COMMON_DIALOG = "chrome://global/content/commonDialog.xul";
541 const SELECT_DIALOG = "chrome://global/content/selectDialog.xul";
543 let uri = (args.promptType == "select") ? SELECT_DIALOG : COMMON_DIALOG;
545 if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
546 args.uri = uri;
547 openRemotePrompt(this.domWin, args);
548 return;
549 }
551 let propBag = PromptUtils.objectToPropBag(args);
552 openModalWindow(this.domWin, uri, propBag);
553 PromptUtils.propBagToObject(propBag, args);
554 },
558 /*
559 * ---------- interface disambiguation ----------
560 *
561 * nsIPrompt and nsIAuthPrompt share 3 method names with slightly
562 * different arguments. All but prompt() have the same number of
563 * arguments, so look at the arg types to figure out how we're being
564 * called. :-(
565 */
566 prompt : function() {
567 // also, the nsIPrompt flavor has 5 args instead of 6.
568 if (typeof arguments[2] == "object")
569 return this.nsIPrompt_prompt.apply(this, arguments);
570 else
571 return this.nsIAuthPrompt_prompt.apply(this, arguments);
572 },
574 promptUsernameAndPassword : function() {
575 // Both have 6 args, so use types.
576 if (typeof arguments[2] == "object")
577 return this.nsIPrompt_promptUsernameAndPassword.apply(this, arguments);
578 else
579 return this.nsIAuthPrompt_promptUsernameAndPassword.apply(this, arguments);
580 },
582 promptPassword : function() {
583 // Both have 5 args, so use types.
584 if (typeof arguments[2] == "object")
585 return this.nsIPrompt_promptPassword.apply(this, arguments);
586 else
587 return this.nsIAuthPrompt_promptPassword.apply(this, arguments);
588 },
591 /* ---------- nsIPrompt ---------- */
594 alert : function (title, text) {
595 if (!title)
596 title = PromptUtils.getLocalizedString("Alert");
598 let args = {
599 promptType: "alert",
600 title: title,
601 text: text,
602 };
604 this.openPrompt(args);
605 },
607 alertCheck : function (title, text, checkLabel, checkValue) {
608 if (!title)
609 title = PromptUtils.getLocalizedString("Alert");
611 let args = {
612 promptType: "alertCheck",
613 title: title,
614 text: text,
615 checkLabel: checkLabel,
616 checked: checkValue.value,
617 };
619 this.openPrompt(args);
621 // Checkbox state always returned, even if cancel clicked.
622 checkValue.value = args.checked;
623 },
625 confirm : function (title, text) {
626 if (!title)
627 title = PromptUtils.getLocalizedString("Confirm");
629 let args = {
630 promptType: "confirm",
631 title: title,
632 text: text,
633 ok: false,
634 };
636 this.openPrompt(args);
638 // Did user click Ok or Cancel?
639 return args.ok;
640 },
642 confirmCheck : function (title, text, checkLabel, checkValue) {
643 if (!title)
644 title = PromptUtils.getLocalizedString("ConfirmCheck");
646 let args = {
647 promptType: "confirmCheck",
648 title: title,
649 text: text,
650 checkLabel: checkLabel,
651 checked: checkValue.value,
652 ok: false,
653 };
655 this.openPrompt(args);
657 // Checkbox state always returned, even if cancel clicked.
658 checkValue.value = args.checked;
660 // Did user click Ok or Cancel?
661 return args.ok;
662 },
664 confirmEx : function (title, text, flags, button0, button1, button2,
665 checkLabel, checkValue) {
667 if (!title)
668 title = PromptUtils.getLocalizedString("Confirm");
670 let args = {
671 promptType: "confirmEx",
672 title: title,
673 text: text,
674 checkLabel: checkLabel,
675 checked: checkValue.value,
676 ok: false,
677 buttonNumClicked: 1,
678 };
680 let [label0, label1, label2, defaultButtonNum, isDelayEnabled] =
681 PromptUtils.confirmExHelper(flags, button0, button1, button2);
683 args.defaultButtonNum = defaultButtonNum;
684 args.enableDelay = isDelayEnabled;
686 if (label0) {
687 args.button0Label = label0;
688 if (label1) {
689 args.button1Label = label1;
690 if (label2) {
691 args.button2Label = label2;
692 }
693 }
694 }
696 this.openPrompt(args);
698 // Checkbox state always returned, even if cancel clicked.
699 checkValue.value = args.checked;
701 // Get the number of the button the user clicked.
702 return args.buttonNumClicked;
703 },
705 nsIPrompt_prompt : function (title, text, value, checkLabel, checkValue) {
706 if (!title)
707 title = PromptUtils.getLocalizedString("Prompt");
709 let args = {
710 promptType: "prompt",
711 title: title,
712 text: text,
713 value: value.value,
714 checkLabel: checkLabel,
715 checked: checkValue.value,
716 ok: false,
717 };
719 this.openPrompt(args);
721 // Did user click Ok or Cancel?
722 let ok = args.ok;
723 if (ok) {
724 checkValue.value = args.checked;
725 value.value = args.value;
726 }
728 return ok;
729 },
731 nsIPrompt_promptUsernameAndPassword : function (title, text, user, pass, checkLabel, checkValue) {
732 if (!title)
733 title = PromptUtils.getLocalizedString("PromptUsernameAndPassword2");
735 let args = {
736 promptType: "promptUserAndPass",
737 title: title,
738 text: text,
739 user: user.value,
740 pass: pass.value,
741 checkLabel: checkLabel,
742 checked: checkValue.value,
743 ok: false,
744 };
746 this.openPrompt(args);
748 // Did user click Ok or Cancel?
749 let ok = args.ok;
750 if (ok) {
751 checkValue.value = args.checked;
752 user.value = args.user;
753 pass.value = args.pass;
754 }
756 return ok;
757 },
759 nsIPrompt_promptPassword : function (title, text, pass, checkLabel, checkValue) {
760 if (!title)
761 title = PromptUtils.getLocalizedString("PromptPassword2");
763 let args = {
764 promptType: "promptPassword",
765 title: title,
766 text: text,
767 pass: pass.value,
768 checkLabel: checkLabel,
769 checked: checkValue.value,
770 ok: false,
771 }
773 this.openPrompt(args);
775 // Did user click Ok or Cancel?
776 let ok = args.ok;
777 if (ok) {
778 checkValue.value = args.checked;
779 pass.value = args.pass;
780 }
782 return ok;
783 },
785 select : function (title, text, count, list, selected) {
786 if (!title)
787 title = PromptUtils.getLocalizedString("Select");
789 let args = {
790 promptType: "select",
791 title: title,
792 text: text,
793 list: list,
794 selected: -1,
795 ok: false,
796 };
798 this.openPrompt(args);
800 // Did user click Ok or Cancel?
801 let ok = args.ok;
802 if (ok)
803 selected.value = args.selected;
805 return ok;
806 },
809 /* ---------- nsIAuthPrompt ---------- */
812 nsIAuthPrompt_prompt : function (title, text, passwordRealm, savePassword, defaultText, result) {
813 // The passwordRealm and savePassword args were ignored by nsPrompt.cpp
814 if (defaultText)
815 result.value = defaultText;
816 return this.nsIPrompt_prompt(title, text, result, null, {});
817 },
819 nsIAuthPrompt_promptUsernameAndPassword : function (title, text, passwordRealm, savePassword, user, pass) {
820 // The passwordRealm and savePassword args were ignored by nsPrompt.cpp
821 return this.nsIPrompt_promptUsernameAndPassword(title, text, user, pass, null, {});
822 },
824 nsIAuthPrompt_promptPassword : function (title, text, passwordRealm, savePassword, pass) {
825 // The passwordRealm and savePassword args were ignored by nsPrompt.cpp
826 return this.nsIPrompt_promptPassword(title, text, pass, null, {});
827 },
830 /* ---------- nsIAuthPrompt2 ---------- */
833 promptAuth : function (channel, level, authInfo, checkLabel, checkValue) {
834 let message = PromptUtils.makeAuthMessage(channel, authInfo);
836 let [username, password] = PromptUtils.getAuthInfo(authInfo);
838 let userParam = { value: username };
839 let passParam = { value: password };
841 let ok;
842 if (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD)
843 ok = this.nsIPrompt_promptPassword(null, message, passParam, checkLabel, checkValue);
844 else
845 ok = this.nsIPrompt_promptUsernameAndPassword(null, message, userParam, passParam, checkLabel, checkValue);
847 if (ok)
848 PromptUtils.setAuthInfo(authInfo, userParam.value, passParam.value);
849 return ok;
850 },
852 asyncPromptAuth : function (channel, callback, context, level, authInfo, checkLabel, checkValue) {
853 // Nothing calls this directly; netwerk ends up going through
854 // nsIPromptService::GetPrompt, which delegates to login manager.
855 // Login manger handles the async bits itself, and only calls out
856 // promptAuth, never asyncPromptAuth.
857 //
858 // Bug 565582 will change this.
859 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
860 },
862 /* ---------- nsIWritablePropertyBag2 ---------- */
864 // Only a partial implementation, for one specific use case...
866 setPropertyAsBool : function(name, value) {
867 if (name == "allowTabModal")
868 this.allowTabModal = value;
869 else
870 throw Cr.NS_ERROR_ILLEGAL_VALUE;
871 },
872 };
875 function AuthPromptAdapterFactory() {
876 }
877 AuthPromptAdapterFactory.prototype = {
878 classID : Components.ID("{6e134924-6c3a-4d86-81ac-69432dd971dc}"),
879 QueryInterface : XPCOMUtils.generateQI([Ci.nsIAuthPromptAdapterFactory]),
881 /* ---------- nsIAuthPromptAdapterFactory ---------- */
883 createAdapter : function (oldPrompter) {
884 return new AuthPromptAdapter(oldPrompter);
885 }
886 };
889 // Takes an nsIAuthPrompt implementation, wraps it with a nsIAuthPrompt2 shell.
890 function AuthPromptAdapter(oldPrompter) {
891 this.oldPrompter = oldPrompter;
892 }
893 AuthPromptAdapter.prototype = {
894 QueryInterface : XPCOMUtils.generateQI([Ci.nsIAuthPrompt2]),
895 oldPrompter : null,
897 /* ---------- nsIAuthPrompt2 ---------- */
899 promptAuth : function (channel, level, authInfo, checkLabel, checkValue) {
900 let message = PromptUtils.makeAuthMessage(channel, authInfo);
902 let [username, password] = PromptUtils.getAuthInfo(authInfo);
903 let userParam = { value: username };
904 let passParam = { value: password };
906 let [host, realm] = PromptUtils.getAuthTarget(channel, authInfo);
907 let authTarget = host + " (" + realm + ")";
909 let ok;
910 if (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD)
911 ok = this.oldPrompter.promptPassword(null, message, authTarget, Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, passParam);
912 else
913 ok = this.oldPrompter.promptUsernameAndPassword(null, message, authTarget, Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, userParam, passParam);
915 if (ok)
916 PromptUtils.setAuthInfo(authInfo, userParam.value, passParam.value);
917 return ok;
918 },
920 asyncPromptAuth : function (channel, callback, context, level, authInfo, checkLabel, checkValue) {
921 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
922 }
923 };
926 // Wrapper using the old embedding contractID, since it's already common in
927 // the addon ecosystem.
928 function EmbedPrompter() {
929 }
930 EmbedPrompter.prototype = new Prompter();
931 EmbedPrompter.prototype.classID = Components.ID("{7ad1b327-6dfa-46ec-9234-f2a620ea7e00}");
933 var component = [Prompter, EmbedPrompter, AuthPromptAdapterFactory];
934 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);