michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: Components.utils.import("resource://services-sync/main.js"); michael@0: Components.utils.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () { michael@0: return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {}); michael@0: }); michael@0: michael@0: const PAGE_NO_ACCOUNT = 0; michael@0: const PAGE_HAS_ACCOUNT = 1; michael@0: const PAGE_NEEDS_UPDATE = 2; michael@0: const PAGE_PLEASE_WAIT = 3; michael@0: const FXA_PAGE_LOGGED_OUT = 4; michael@0: const FXA_PAGE_LOGGED_IN = 5; michael@0: michael@0: // Indexes into the "login status" deck. michael@0: // We are in a successful verified state - everything should work! michael@0: const FXA_LOGIN_VERIFIED = 0; michael@0: // We have logged in to an unverified account. michael@0: const FXA_LOGIN_UNVERIFIED = 1; michael@0: // We are logged in locally, but the server rejected our credentials. michael@0: const FXA_LOGIN_FAILED = 2; michael@0: michael@0: let gSyncPane = { michael@0: _stringBundle: null, michael@0: prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs", michael@0: "engine.tabs", "engine.history"], michael@0: michael@0: get page() { michael@0: return document.getElementById("weavePrefsDeck").selectedIndex; michael@0: }, michael@0: michael@0: set page(val) { michael@0: document.getElementById("weavePrefsDeck").selectedIndex = val; michael@0: }, michael@0: michael@0: get _usingCustomServer() { michael@0: return Weave.Svc.Prefs.isSet("serverURL"); michael@0: }, michael@0: michael@0: needsUpdate: function () { michael@0: this.page = PAGE_NEEDS_UPDATE; michael@0: let label = document.getElementById("loginError"); michael@0: label.value = Weave.Utils.getErrorString(Weave.Status.login); michael@0: label.className = "error"; michael@0: }, michael@0: michael@0: init: function () { michael@0: // If the Service hasn't finished initializing, wait for it. michael@0: let xps = Components.classes["@mozilla.org/weave/service;1"] michael@0: .getService(Components.interfaces.nsISupports) michael@0: .wrappedJSObject; michael@0: michael@0: if (xps.ready) { michael@0: this._init(); michael@0: return; michael@0: } michael@0: michael@0: // it may take some time before we can determine what provider to use michael@0: // and the state of that provider, so show the "please wait" page. michael@0: this.page = PAGE_PLEASE_WAIT; michael@0: michael@0: let onUnload = function () { michael@0: window.removeEventListener("unload", onUnload, false); michael@0: try { michael@0: Services.obs.removeObserver(onReady, "weave:service:ready"); michael@0: } catch (e) {} michael@0: }; michael@0: michael@0: let onReady = function () { michael@0: Services.obs.removeObserver(onReady, "weave:service:ready"); michael@0: window.removeEventListener("unload", onUnload, false); michael@0: this._init(); michael@0: }.bind(this); michael@0: michael@0: Services.obs.addObserver(onReady, "weave:service:ready", false); michael@0: window.addEventListener("unload", onUnload, false); michael@0: michael@0: xps.ensureLoaded(); michael@0: }, michael@0: michael@0: _init: function () { michael@0: let topics = ["weave:service:login:error", michael@0: "weave:service:login:finish", michael@0: "weave:service:start-over:finish", michael@0: "weave:service:setup-complete", michael@0: "weave:service:logout:finish", michael@0: FxAccountsCommon.ONVERIFIED_NOTIFICATION]; michael@0: michael@0: // Add the observers now and remove them on unload michael@0: //XXXzpao This should use Services.obs.* but Weave's Obs does nice handling michael@0: // of `this`. Fix in a followup. (bug 583347) michael@0: topics.forEach(function (topic) { michael@0: Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this); michael@0: }, this); michael@0: window.addEventListener("unload", function() { michael@0: topics.forEach(function (topic) { michael@0: Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this); michael@0: }, gSyncPane); michael@0: }, false); michael@0: michael@0: this._stringBundle = michael@0: Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties"); michael@0: this.updateWeavePrefs(); michael@0: }, michael@0: michael@0: updateWeavePrefs: function () { michael@0: let service = Components.classes["@mozilla.org/weave/service;1"] michael@0: .getService(Components.interfaces.nsISupports) michael@0: .wrappedJSObject; michael@0: // service.fxAccountsEnabled is false iff sync is already configured for michael@0: // the legacy provider. michael@0: if (service.fxAccountsEnabled) { michael@0: // determine the fxa status... michael@0: this.page = PAGE_PLEASE_WAIT; michael@0: Components.utils.import("resource://gre/modules/FxAccounts.jsm"); michael@0: fxAccounts.getSignedInUser().then(data => { michael@0: if (!data) { michael@0: this.page = FXA_PAGE_LOGGED_OUT; michael@0: return; michael@0: } michael@0: this.page = FXA_PAGE_LOGGED_IN; michael@0: // We are logged in locally, but maybe we are in a state where the michael@0: // server rejected our credentials (eg, password changed on the server) michael@0: let fxaLoginStatus = document.getElementById("fxaLoginStatus"); michael@0: let enginesListDisabled; michael@0: // Not Verfied implies login error state, so check that first. michael@0: if (!data.verified) { michael@0: fxaLoginStatus.selectedIndex = FXA_LOGIN_UNVERIFIED; michael@0: enginesListDisabled = true; michael@0: // So we think we are logged in, so login problems are next. michael@0: // (Although if the Sync identity manager is still initializing, we michael@0: // ignore login errors and assume all will eventually be good.) michael@0: // LOGIN_FAILED_LOGIN_REJECTED explicitly means "you must log back in". michael@0: // All other login failures are assumed to be transient and should go michael@0: // away by themselves, so aren't reflected here. michael@0: } else if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) { michael@0: fxaLoginStatus.selectedIndex = FXA_LOGIN_FAILED; michael@0: enginesListDisabled = true; michael@0: // Else we must be golden (or in an error state we expect to magically michael@0: // resolve itself) michael@0: } else { michael@0: fxaLoginStatus.selectedIndex = FXA_LOGIN_VERIFIED; michael@0: enginesListDisabled = false; michael@0: } michael@0: document.getElementById("fxaEmailAddress1").textContent = data.email; michael@0: document.getElementById("fxaEmailAddress2").textContent = data.email; michael@0: document.getElementById("fxaEmailAddress3").textContent = data.email; michael@0: document.getElementById("fxaSyncComputerName").value = Weave.Service.clientsEngine.localName; michael@0: let engines = document.getElementById("fxaSyncEngines") michael@0: for (let checkbox of engines.querySelectorAll("checkbox")) { michael@0: checkbox.disabled = enginesListDisabled; michael@0: } michael@0: michael@0: let checkbox = document.getElementById("fxa-pweng-chk"); michael@0: let help = document.getElementById("fxa-pweng-help"); michael@0: let allowPasswordsEngine = service.allowPasswordsEngine; michael@0: michael@0: if (!allowPasswordsEngine) { michael@0: checkbox.checked = false; michael@0: } michael@0: michael@0: checkbox.disabled = !allowPasswordsEngine || enginesListDisabled; michael@0: help.hidden = allowPasswordsEngine || enginesListDisabled; michael@0: }); michael@0: // If fxAccountEnabled is false and we are in a "not configured" state, michael@0: // then fxAccounts is probably fully disabled rather than just unconfigured, michael@0: // so handle this case. This block can be removed once we remove support michael@0: // for fxAccounts being disabled. michael@0: } else if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED || michael@0: Weave.Svc.Prefs.get("firstSync", "") == "notReady") { michael@0: this.page = PAGE_NO_ACCOUNT; michael@0: // else: sync was previously configured for the legacy provider, so we michael@0: // make the "old" panels available. michael@0: } else if (Weave.Status.login == Weave.LOGIN_FAILED_INVALID_PASSPHRASE || michael@0: Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) { michael@0: this.needsUpdate(); michael@0: } else { michael@0: this.page = PAGE_HAS_ACCOUNT; michael@0: document.getElementById("accountName").value = Weave.Service.identity.account; michael@0: document.getElementById("syncComputerName").value = Weave.Service.clientsEngine.localName; michael@0: document.getElementById("tosPP").hidden = this._usingCustomServer; michael@0: } michael@0: }, michael@0: michael@0: startOver: function (showDialog) { michael@0: if (showDialog) { michael@0: let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING + michael@0: Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL + michael@0: Services.prompt.BUTTON_POS_1_DEFAULT; michael@0: let buttonChoice = michael@0: Services.prompt.confirmEx(window, michael@0: this._stringBundle.GetStringFromName("syncUnlink.title"), michael@0: this._stringBundle.GetStringFromName("syncUnlink.label"), michael@0: flags, michael@0: this._stringBundle.GetStringFromName("syncUnlinkConfirm.label"), michael@0: null, null, null, {}); michael@0: michael@0: // If the user selects cancel, just bail michael@0: if (buttonChoice == 1) michael@0: return; michael@0: } michael@0: michael@0: Weave.Service.startOver(); michael@0: this.updateWeavePrefs(); michael@0: }, michael@0: michael@0: updatePass: function () { michael@0: if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) michael@0: gSyncUtils.changePassword(); michael@0: else michael@0: gSyncUtils.updatePassphrase(); michael@0: }, michael@0: michael@0: resetPass: function () { michael@0: if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) michael@0: gSyncUtils.resetPassword(); michael@0: else michael@0: gSyncUtils.resetPassphrase(); michael@0: }, michael@0: michael@0: /** michael@0: * Invoke the Sync setup wizard. michael@0: * michael@0: * @param wizardType michael@0: * Indicates type of wizard to launch: michael@0: * null -- regular set up wizard michael@0: * "pair" -- pair a device first michael@0: * "reset" -- reset sync michael@0: */ michael@0: openSetup: function (wizardType) { michael@0: let service = Components.classes["@mozilla.org/weave/service;1"] michael@0: .getService(Components.interfaces.nsISupports) michael@0: .wrappedJSObject; michael@0: michael@0: if (service.fxAccountsEnabled) { michael@0: this.openContentInBrowser("about:accounts"); michael@0: } else { michael@0: let win = Services.wm.getMostRecentWindow("Weave:AccountSetup"); michael@0: if (win) michael@0: win.focus(); michael@0: else { michael@0: window.openDialog("chrome://browser/content/sync/setup.xul", michael@0: "weaveSetup", "centerscreen,chrome,resizable=no", michael@0: wizardType); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: openContentInBrowser: function(url) { michael@0: let win = Services.wm.getMostRecentWindow("navigator:browser"); michael@0: if (!win) { michael@0: // no window to use, so use _openLink to create a new one. We don't michael@0: // always use that as it prefers to open a new window rather than use michael@0: // an existing one. michael@0: gSyncUtils._openLink(url); michael@0: return; michael@0: } michael@0: win.switchToTabHavingURI(url, true); michael@0: // seeing as we are doing this in a tab we close the prefs dialog. michael@0: window.close(); michael@0: }, michael@0: michael@0: signUp: function() { michael@0: this.openContentInBrowser("about:accounts?action=signup"); michael@0: }, michael@0: michael@0: signIn: function() { michael@0: this.openContentInBrowser("about:accounts?action=signin"); michael@0: }, michael@0: michael@0: reSignIn: function() { michael@0: this.openContentInBrowser("about:accounts?action=reauth"); michael@0: }, michael@0: michael@0: manageFirefoxAccount: function() { michael@0: let url = Services.prefs.getCharPref("identity.fxaccounts.settings.uri"); michael@0: this.openContentInBrowser(url); michael@0: }, michael@0: michael@0: verifyFirefoxAccount: function() { michael@0: Components.utils.import("resource://gre/modules/FxAccounts.jsm"); michael@0: fxAccounts.resendVerificationEmail().then(() => { michael@0: fxAccounts.getSignedInUser().then(data => { michael@0: let sb = this._stringBundle; michael@0: let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle"); michael@0: let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading", michael@0: [data.email], 1); michael@0: let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription"); michael@0: michael@0: Services.prompt.alert(window, title, heading + "\n\n" + description); michael@0: }); michael@0: }); michael@0: }, michael@0: michael@0: openOldSyncSupportPage: function() { michael@0: let url = Services.urlFormatter.formatURLPref('app.support.baseURL') + "old-sync" michael@0: this.openContentInBrowser(url); michael@0: }, michael@0: michael@0: unlinkFirefoxAccount: function(confirm) { michael@0: if (confirm) { michael@0: // We use a string bundle shared with aboutAccounts. michael@0: let sb = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); michael@0: let continueLabel = sb.GetStringFromName("continue.label"); michael@0: let title = sb.GetStringFromName("disconnect.verify.title"); michael@0: let brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties"); michael@0: let brandShortName = brandBundle.GetStringFromName("brandShortName"); michael@0: let body = sb.GetStringFromName("disconnect.verify.heading") + michael@0: "\n\n" + michael@0: sb.formatStringFromName("disconnect.verify.description", michael@0: [brandShortName], 1); michael@0: let ps = Services.prompt; michael@0: let buttonFlags = (ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING) + michael@0: (ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL) + michael@0: ps.BUTTON_POS_1_DEFAULT; michael@0: let pressed = Services.prompt.confirmEx(window, title, body, buttonFlags, michael@0: continueLabel, null, null, null, {}); michael@0: if (pressed != 0) { // 0 is the "continue" button michael@0: return; michael@0: } michael@0: } michael@0: Components.utils.import('resource://gre/modules/FxAccounts.jsm'); michael@0: fxAccounts.signOut().then(() => { michael@0: this.updateWeavePrefs(); michael@0: }); michael@0: }, michael@0: michael@0: openQuotaDialog: function () { michael@0: let win = Services.wm.getMostRecentWindow("Sync:ViewQuota"); michael@0: if (win) michael@0: win.focus(); michael@0: else michael@0: window.openDialog("chrome://browser/content/sync/quota.xul", "", michael@0: "centerscreen,chrome,dialog,modal"); michael@0: }, michael@0: michael@0: openAddDevice: function () { michael@0: if (!Weave.Utils.ensureMPUnlocked()) michael@0: return; michael@0: michael@0: let win = Services.wm.getMostRecentWindow("Sync:AddDevice"); michael@0: if (win) michael@0: win.focus(); michael@0: else michael@0: window.openDialog("chrome://browser/content/sync/addDevice.xul", michael@0: "syncAddDevice", "centerscreen,chrome,resizable=no"); michael@0: }, michael@0: michael@0: resetSync: function () { michael@0: this.openSetup("reset"); michael@0: }, michael@0: }; michael@0: