forked from mirrors/gecko-dev
		
	MozReview-Commit-ID: EMjJ3yWt9Wt --HG-- extra : rebase_source : 2b8327e5a7cf0bfd190d696ad5fe475f13faa3cc
		
			
				
	
	
		
			1061 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1061 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 | 
						|
/* 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/. */
 | 
						|
 | 
						|
var Ci = Components.interfaces;
 | 
						|
var Cc = Components.classes;
 | 
						|
var Cr = Components.results;
 | 
						|
var Cu = Components.utils;
 | 
						|
 | 
						|
// page consts
 | 
						|
 | 
						|
const PAIR_PAGE                     = 0;
 | 
						|
const INTRO_PAGE                    = 1;
 | 
						|
const NEW_ACCOUNT_START_PAGE        = 2;
 | 
						|
const EXISTING_ACCOUNT_CONNECT_PAGE = 3;
 | 
						|
const EXISTING_ACCOUNT_LOGIN_PAGE   = 4;
 | 
						|
const OPTIONS_PAGE                  = 5;
 | 
						|
const OPTIONS_CONFIRM_PAGE          = 6;
 | 
						|
 | 
						|
// Broader than we'd like, but after this changed from api-secure.recaptcha.net
 | 
						|
// we had no choice. At least we only do this for the duration of setup.
 | 
						|
// See discussion in Bugs 508112 and 653307.
 | 
						|
const RECAPTCHA_DOMAIN = "https://www.google.com";
 | 
						|
 | 
						|
const PIN_PART_LENGTH = 4;
 | 
						|
 | 
						|
Cu.import("resource://services-sync/main.js");
 | 
						|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 | 
						|
Cu.import("resource://gre/modules/Services.jsm");
 | 
						|
Cu.import("resource://gre/modules/PlacesUtils.jsm");
 | 
						|
Cu.import("resource://gre/modules/PluralForm.jsm");
 | 
						|
 | 
						|
 | 
						|
function setVisibility(element, visible) {
 | 
						|
  element.style.visibility = visible ? "visible" : "hidden";
 | 
						|
}
 | 
						|
 | 
						|
var gSyncSetup = {
 | 
						|
  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
 | 
						|
                                         Ci.nsIWebProgressListener,
 | 
						|
                                         Ci.nsISupportsWeakReference]),
 | 
						|
 | 
						|
  captchaBrowser: null,
 | 
						|
  wizard: null,
 | 
						|
  _disabledSites: [],
 | 
						|
 | 
						|
  status: {
 | 
						|
    password: false,
 | 
						|
    email: false,
 | 
						|
    server: false
 | 
						|
  },
 | 
						|
 | 
						|
  get _remoteSites() {
 | 
						|
    return [Weave.Service.serverURL, RECAPTCHA_DOMAIN];
 | 
						|
  },
 | 
						|
 | 
						|
  get _usingMainServers() {
 | 
						|
    if (this._settingUpNew)
 | 
						|
      return document.getElementById("server").selectedIndex == 0;
 | 
						|
    return document.getElementById("existingServer").selectedIndex == 0;
 | 
						|
  },
 | 
						|
 | 
						|
  init: function () {
 | 
						|
    let obs = [
 | 
						|
      ["weave:service:change-passphrase", "onResetPassphrase"],
 | 
						|
      ["weave:service:login:start",       "onLoginStart"],
 | 
						|
      ["weave:service:login:error",       "onLoginEnd"],
 | 
						|
      ["weave:service:login:finish",      "onLoginEnd"]];
 | 
						|
 | 
						|
    // Add the observers now and remove them on unload
 | 
						|
    let self = this;
 | 
						|
    let addRem = function(add) {
 | 
						|
      obs.forEach(function([topic, func]) {
 | 
						|
        //XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
 | 
						|
        //        of `this`. Fix in a followup. (bug 583347)
 | 
						|
        if (add)
 | 
						|
          Weave.Svc.Obs.add(topic, self[func], self);
 | 
						|
        else
 | 
						|
          Weave.Svc.Obs.remove(topic, self[func], self);
 | 
						|
      });
 | 
						|
    };
 | 
						|
    addRem(true);
 | 
						|
    window.addEventListener("unload", () => addRem(false), false);
 | 
						|
 | 
						|
    window.setTimeout(function () {
 | 
						|
      // Force Service to be loaded so that engines are registered.
 | 
						|
      // See Bug 670082.
 | 
						|
      Weave.Service;
 | 
						|
    }, 0);
 | 
						|
 | 
						|
    this.captchaBrowser = document.getElementById("captcha");
 | 
						|
 | 
						|
    this.wizardType = null;
 | 
						|
    if (window.arguments && window.arguments[0]) {
 | 
						|
      this.wizardType = window.arguments[0];
 | 
						|
    }
 | 
						|
    switch (this.wizardType) {
 | 
						|
      case null:
 | 
						|
        this.wizard.pageIndex = INTRO_PAGE;
 | 
						|
        // Fall through!
 | 
						|
      case "pair":
 | 
						|
        this.captchaBrowser.addProgressListener(this);
 | 
						|
        Weave.Svc.Prefs.set("firstSync", "notReady");
 | 
						|
        break;
 | 
						|
      case "reset":
 | 
						|
        this._resettingSync = true;
 | 
						|
        this.wizard.pageIndex = OPTIONS_PAGE;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    this.wizard.getButton("extra1").label =
 | 
						|
      this._stringBundle.GetStringFromName("button.syncOptions.label");
 | 
						|
 | 
						|
    // Remember these values because the options pages change them temporarily.
 | 
						|
    this._nextButtonLabel = this.wizard.getButton("next").label;
 | 
						|
    this._nextButtonAccesskey = this.wizard.getButton("next")
 | 
						|
                                           .getAttribute("accesskey");
 | 
						|
    this._backButtonLabel = this.wizard.getButton("back").label;
 | 
						|
    this._backButtonAccesskey = this.wizard.getButton("back")
 | 
						|
                                           .getAttribute("accesskey");
 | 
						|
  },
 | 
						|
 | 
						|
  startNewAccountSetup: function () {
 | 
						|
    if (!Weave.Utils.ensureMPUnlocked())
 | 
						|
      return;
 | 
						|
    this._settingUpNew = true;
 | 
						|
    this.wizard.pageIndex = NEW_ACCOUNT_START_PAGE;
 | 
						|
  },
 | 
						|
 | 
						|
  useExistingAccount: function () {
 | 
						|
    if (!Weave.Utils.ensureMPUnlocked())
 | 
						|
      return;
 | 
						|
    this._settingUpNew = false;
 | 
						|
    if (this.wizardType == "pair") {
 | 
						|
      // We're already pairing, so there's no point in pairing again.
 | 
						|
      // Go straight to the manual login page.
 | 
						|
      this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
 | 
						|
    } else {
 | 
						|
      this.wizard.pageIndex = EXISTING_ACCOUNT_CONNECT_PAGE;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  resetPassphrase: function resetPassphrase() {
 | 
						|
    // Apply the existing form fields so that
 | 
						|
    // Weave.Service.changePassphrase() has the necessary credentials.
 | 
						|
    Weave.Service.identity.account = document.getElementById("existingAccountName").value;
 | 
						|
    Weave.Service.identity.basicPassword = document.getElementById("existingPassword").value;
 | 
						|
 | 
						|
    // Generate a new passphrase so that Weave.Service.login() will
 | 
						|
    // actually do something.
 | 
						|
    let passphrase = Weave.Utils.generatePassphrase();
 | 
						|
    Weave.Service.identity.syncKey = passphrase;
 | 
						|
 | 
						|
    // Only open the dialog if username + password are actually correct.
 | 
						|
    Weave.Service.login();
 | 
						|
    if ([Weave.LOGIN_FAILED_INVALID_PASSPHRASE,
 | 
						|
         Weave.LOGIN_FAILED_NO_PASSPHRASE,
 | 
						|
         Weave.LOGIN_SUCCEEDED].indexOf(Weave.Status.login) == -1) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Hide any errors about the passphrase, we know it's not right.
 | 
						|
    let feedback = document.getElementById("existingPassphraseFeedbackRow");
 | 
						|
    feedback.hidden = true;
 | 
						|
    let el = document.getElementById("existingPassphrase");
 | 
						|
    el.value = Weave.Utils.hyphenatePassphrase(passphrase);
 | 
						|
 | 
						|
    // changePassphrase() will sync, make sure we set the "firstSync" pref
 | 
						|
    // according to the user's pref.
 | 
						|
    Weave.Svc.Prefs.reset("firstSync");
 | 
						|
    this.setupInitialSync();
 | 
						|
    gSyncUtils.resetPassphrase(true);
 | 
						|
  },
 | 
						|
 | 
						|
  onResetPassphrase: function () {
 | 
						|
    document.getElementById("existingPassphrase").value =
 | 
						|
      Weave.Utils.hyphenatePassphrase(Weave.Service.identity.syncKey);
 | 
						|
    this.checkFields();
 | 
						|
    this.wizard.advance();
 | 
						|
  },
 | 
						|
 | 
						|
  onLoginStart: function () {
 | 
						|
    this.toggleLoginFeedback(false);
 | 
						|
  },
 | 
						|
 | 
						|
  onLoginEnd: function () {
 | 
						|
    this.toggleLoginFeedback(true);
 | 
						|
  },
 | 
						|
 | 
						|
  sendCredentialsAfterSync: function () {
 | 
						|
    let send = function() {
 | 
						|
      Services.obs.removeObserver("weave:service:sync:finish", send);
 | 
						|
      Services.obs.removeObserver("weave:service:sync:error", send);
 | 
						|
      let credentials = {account:   Weave.Service.identity.account,
 | 
						|
                         password:  Weave.Service.identity.basicPassword,
 | 
						|
                         synckey:   Weave.Service.identity.syncKey,
 | 
						|
                         serverURL: Weave.Service.serverURL};
 | 
						|
      this._jpakeclient.sendAndComplete(credentials);
 | 
						|
    }.bind(this);
 | 
						|
    Services.obs.addObserver("weave:service:sync:finish", send, false);
 | 
						|
    Services.obs.addObserver("weave:service:sync:error", send, false);
 | 
						|
  },
 | 
						|
 | 
						|
  toggleLoginFeedback: function (stop) {
 | 
						|
    document.getElementById("login-throbber").hidden = stop;
 | 
						|
    let password = document.getElementById("existingPasswordFeedbackRow");
 | 
						|
    let server = document.getElementById("existingServerFeedbackRow");
 | 
						|
    let passphrase = document.getElementById("existingPassphraseFeedbackRow");
 | 
						|
 | 
						|
    if (!stop || (Weave.Status.login == Weave.LOGIN_SUCCEEDED)) {
 | 
						|
      password.hidden = server.hidden = passphrase.hidden = true;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    let feedback;
 | 
						|
    switch (Weave.Status.login) {
 | 
						|
      case Weave.LOGIN_FAILED_NETWORK_ERROR:
 | 
						|
      case Weave.LOGIN_FAILED_SERVER_ERROR:
 | 
						|
        feedback = server;
 | 
						|
        break;
 | 
						|
      case Weave.LOGIN_FAILED_LOGIN_REJECTED:
 | 
						|
      case Weave.LOGIN_FAILED_NO_USERNAME:
 | 
						|
      case Weave.LOGIN_FAILED_NO_PASSWORD:
 | 
						|
        feedback = password;
 | 
						|
        break;
 | 
						|
      case Weave.LOGIN_FAILED_INVALID_PASSPHRASE:
 | 
						|
        feedback = passphrase;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    this._setFeedbackMessage(feedback, false, Weave.Status.login);
 | 
						|
  },
 | 
						|
 | 
						|
  setupInitialSync: function () {
 | 
						|
    let action = document.getElementById("mergeChoiceRadio").selectedItem.id;
 | 
						|
    switch (action) {
 | 
						|
      case "resetClient":
 | 
						|
        // if we're not resetting sync, we don't need to explicitly
 | 
						|
        // call resetClient
 | 
						|
        if (!this._resettingSync)
 | 
						|
          return;
 | 
						|
        // otherwise, fall through
 | 
						|
      case "wipeClient":
 | 
						|
      case "wipeRemote":
 | 
						|
        Weave.Svc.Prefs.set("firstSync", action);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  // fun with validation!
 | 
						|
  checkFields: function () {
 | 
						|
    this.wizard.canAdvance = this.readyToAdvance();
 | 
						|
  },
 | 
						|
 | 
						|
  readyToAdvance: function () {
 | 
						|
    switch (this.wizard.pageIndex) {
 | 
						|
      case INTRO_PAGE:
 | 
						|
        return false;
 | 
						|
      case NEW_ACCOUNT_START_PAGE:
 | 
						|
        for (let i in this.status) {
 | 
						|
          if (!this.status[i])
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        if (this._usingMainServers)
 | 
						|
          return document.getElementById("tos").checked;
 | 
						|
 | 
						|
        return true;
 | 
						|
      case EXISTING_ACCOUNT_LOGIN_PAGE:
 | 
						|
        let hasUser = document.getElementById("existingAccountName").value != "";
 | 
						|
        let hasPass = document.getElementById("existingPassword").value != "";
 | 
						|
        let hasKey = document.getElementById("existingPassphrase").value != "";
 | 
						|
 | 
						|
        if (hasUser && hasPass && hasKey) {
 | 
						|
          if (this._usingMainServers)
 | 
						|
            return true;
 | 
						|
 | 
						|
          if (this._validateServer(document.getElementById("existingServer"))) {
 | 
						|
            return true;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    // Default, e.g. wizard's special page -1 etc.
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
 | 
						|
  onPINInput: function onPINInput(textbox) {
 | 
						|
    if (textbox && textbox.value.length == PIN_PART_LENGTH) {
 | 
						|
      this.nextFocusEl[textbox.id].focus();
 | 
						|
    }
 | 
						|
    this.wizard.canAdvance = (this.pin1.value.length == PIN_PART_LENGTH &&
 | 
						|
                              this.pin2.value.length == PIN_PART_LENGTH &&
 | 
						|
                              this.pin3.value.length == PIN_PART_LENGTH);
 | 
						|
  },
 | 
						|
 | 
						|
  onEmailInput: function () {
 | 
						|
    // Check account validity when the user stops typing for 1 second.
 | 
						|
    if (this._checkAccountTimer)
 | 
						|
      window.clearTimeout(this._checkAccountTimer);
 | 
						|
    this._checkAccountTimer = window.setTimeout(function () {
 | 
						|
      gSyncSetup.checkAccount();
 | 
						|
    }, 1000);
 | 
						|
  },
 | 
						|
 | 
						|
  checkAccount: function() {
 | 
						|
    delete this._checkAccountTimer;
 | 
						|
    let value = Weave.Utils.normalizeAccount(
 | 
						|
      document.getElementById("weaveEmail").value);
 | 
						|
    if (!value) {
 | 
						|
      this.status.email = false;
 | 
						|
      this.checkFields();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    let re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
 | 
						|
    let feedback = document.getElementById("emailFeedbackRow");
 | 
						|
    let valid = re.test(value);
 | 
						|
 | 
						|
    let str = "";
 | 
						|
    if (!valid) {
 | 
						|
      str = "invalidEmail.label";
 | 
						|
    } else {
 | 
						|
      let availCheck = Weave.Service.checkAccount(value);
 | 
						|
      valid = availCheck == "available";
 | 
						|
      if (!valid) {
 | 
						|
        if (availCheck == "notAvailable")
 | 
						|
          str = "usernameNotAvailable.label";
 | 
						|
        else
 | 
						|
          str = availCheck;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    this._setFeedbackMessage(feedback, valid, str);
 | 
						|
    this.status.email = valid;
 | 
						|
    if (valid)
 | 
						|
      Weave.Service.identity.account = value;
 | 
						|
    this.checkFields();
 | 
						|
  },
 | 
						|
 | 
						|
  onPasswordChange: function () {
 | 
						|
    let password = document.getElementById("weavePassword");
 | 
						|
    let pwconfirm = document.getElementById("weavePasswordConfirm");
 | 
						|
    let [valid, errorString] = gSyncUtils.validatePassword(password, pwconfirm);
 | 
						|
 | 
						|
    let feedback = document.getElementById("passwordFeedbackRow");
 | 
						|
    this._setFeedback(feedback, valid, errorString);
 | 
						|
 | 
						|
    this.status.password = valid;
 | 
						|
    this.checkFields();
 | 
						|
  },
 | 
						|
 | 
						|
  onPageShow: function() {
 | 
						|
    switch (this.wizard.pageIndex) {
 | 
						|
      case PAIR_PAGE:
 | 
						|
        this.wizard.getButton("back").hidden = true;
 | 
						|
        this.wizard.getButton("extra1").hidden = true;
 | 
						|
        this.onPINInput();
 | 
						|
        this.pin1.focus();
 | 
						|
        break;
 | 
						|
      case INTRO_PAGE:
 | 
						|
        // We may not need the captcha in the Existing Account branch of the
 | 
						|
        // wizard. However, we want to preload it to avoid any flickering while
 | 
						|
        // the Create Account page is shown.
 | 
						|
        this.loadCaptcha();
 | 
						|
        this.wizard.getButton("next").hidden = true;
 | 
						|
        this.wizard.getButton("back").hidden = true;
 | 
						|
        this.wizard.getButton("extra1").hidden = true;
 | 
						|
        this.checkFields();
 | 
						|
        break;
 | 
						|
      case NEW_ACCOUNT_START_PAGE:
 | 
						|
        this.wizard.getButton("extra1").hidden = false;
 | 
						|
        this.wizard.getButton("next").hidden = false;
 | 
						|
        this.wizard.getButton("back").hidden = false;
 | 
						|
        this.onServerCommand();
 | 
						|
        this.wizard.canRewind = true;
 | 
						|
        this.checkFields();
 | 
						|
        break;
 | 
						|
      case EXISTING_ACCOUNT_CONNECT_PAGE:
 | 
						|
        Weave.Svc.Prefs.set("firstSync", "existingAccount");
 | 
						|
        this.wizard.getButton("next").hidden = false;
 | 
						|
        this.wizard.getButton("back").hidden = false;
 | 
						|
        this.wizard.getButton("extra1").hidden = false;
 | 
						|
        this.wizard.canAdvance = false;
 | 
						|
        this.wizard.canRewind = true;
 | 
						|
        this.startEasySetup();
 | 
						|
        break;
 | 
						|
      case EXISTING_ACCOUNT_LOGIN_PAGE:
 | 
						|
        this.wizard.getButton("next").hidden = false;
 | 
						|
        this.wizard.getButton("back").hidden = false;
 | 
						|
        this.wizard.getButton("extra1").hidden = false;
 | 
						|
        this.wizard.canRewind = true;
 | 
						|
        this.checkFields();
 | 
						|
        break;
 | 
						|
      case OPTIONS_PAGE:
 | 
						|
        this.wizard.canRewind = false;
 | 
						|
        this.wizard.canAdvance = true;
 | 
						|
        if (!this._resettingSync) {
 | 
						|
          this.wizard.getButton("next").label =
 | 
						|
            this._stringBundle.GetStringFromName("button.syncOptionsDone.label");
 | 
						|
          this.wizard.getButton("next").removeAttribute("accesskey");
 | 
						|
        }
 | 
						|
        this.wizard.getButton("next").hidden = false;
 | 
						|
        this.wizard.getButton("back").hidden = true;
 | 
						|
        this.wizard.getButton("cancel").hidden = !this._resettingSync;
 | 
						|
        this.wizard.getButton("extra1").hidden = true;
 | 
						|
        document.getElementById("syncComputerName").value = Weave.Service.clientsEngine.localName;
 | 
						|
        document.getElementById("syncOptions").collapsed = this._resettingSync;
 | 
						|
        document.getElementById("mergeOptions").collapsed = this._settingUpNew;
 | 
						|
        break;
 | 
						|
      case OPTIONS_CONFIRM_PAGE:
 | 
						|
        this.wizard.canRewind = true;
 | 
						|
        this.wizard.canAdvance = true;
 | 
						|
        this.wizard.getButton("back").label =
 | 
						|
          this._stringBundle.GetStringFromName("button.syncOptionsCancel.label");
 | 
						|
        this.wizard.getButton("back").removeAttribute("accesskey");
 | 
						|
        this.wizard.getButton("back").hidden = this._resettingSync;
 | 
						|
        this.wizard.getButton("next").hidden = false;
 | 
						|
        this.wizard.getButton("finish").hidden = true;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  onWizardAdvance: function () {
 | 
						|
    // Check pageIndex so we don't prompt before the Sync setup wizard appears.
 | 
						|
    // This is a fallback in case the Master Password gets locked mid-wizard.
 | 
						|
    if ((this.wizard.pageIndex >= 0) &&
 | 
						|
        !Weave.Utils.ensureMPUnlocked()) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (this.wizard.pageIndex) {
 | 
						|
      case PAIR_PAGE:
 | 
						|
        this.startPairing();
 | 
						|
        return false;
 | 
						|
      case NEW_ACCOUNT_START_PAGE:
 | 
						|
        // If the user selects Next (e.g. by hitting enter) when we haven't
 | 
						|
        // executed the delayed checks yet, execute them immediately.
 | 
						|
        if (this._checkAccountTimer) {
 | 
						|
          this.checkAccount();
 | 
						|
        }
 | 
						|
        if (this._checkServerTimer) {
 | 
						|
          this.checkServer();
 | 
						|
        }
 | 
						|
        if (!this.wizard.canAdvance) {
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
 | 
						|
        let doc = this.captchaBrowser.contentDocument;
 | 
						|
        let getField = function getField(field) {
 | 
						|
          let node = doc.getElementById("recaptcha_" + field + "_field");
 | 
						|
          return node && node.value;
 | 
						|
        };
 | 
						|
 | 
						|
        // Display throbber
 | 
						|
        let feedback = document.getElementById("captchaFeedback");
 | 
						|
        let image = feedback.firstChild;
 | 
						|
        let label = image.nextSibling;
 | 
						|
        image.setAttribute("status", "active");
 | 
						|
        label.value = this._stringBundle.GetStringFromName("verifying.label");
 | 
						|
        setVisibility(feedback, true);
 | 
						|
 | 
						|
        let password = document.getElementById("weavePassword").value;
 | 
						|
        let email = Weave.Utils.normalizeAccount(
 | 
						|
          document.getElementById("weaveEmail").value);
 | 
						|
        let challenge = getField("challenge");
 | 
						|
        let response = getField("response");
 | 
						|
 | 
						|
        let error = Weave.Service.createAccount(email, password,
 | 
						|
                                                challenge, response);
 | 
						|
 | 
						|
        if (error == null) {
 | 
						|
          Weave.Service.identity.account = email;
 | 
						|
          Weave.Service.identity.basicPassword = password;
 | 
						|
          Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase();
 | 
						|
          this._handleNoScript(false);
 | 
						|
          Weave.Svc.Prefs.set("firstSync", "newAccount");
 | 
						|
          this.wizardFinish();
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
 | 
						|
        image.setAttribute("status", "error");
 | 
						|
        label.value = Weave.Utils.getErrorString(error);
 | 
						|
        return false;
 | 
						|
      case EXISTING_ACCOUNT_LOGIN_PAGE:
 | 
						|
        Weave.Service.identity.account = Weave.Utils.normalizeAccount(
 | 
						|
          document.getElementById("existingAccountName").value);
 | 
						|
        Weave.Service.identity.basicPassword =
 | 
						|
          document.getElementById("existingPassword").value;
 | 
						|
        let pp = document.getElementById("existingPassphrase").value;
 | 
						|
        Weave.Service.identity.syncKey = Weave.Utils.normalizePassphrase(pp);
 | 
						|
        if (Weave.Service.login()) {
 | 
						|
          this.wizardFinish();
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
      case OPTIONS_PAGE:
 | 
						|
        let desc = document.getElementById("mergeChoiceRadio").selectedIndex;
 | 
						|
        // No confirmation needed on new account setup or merge option
 | 
						|
        // with existing account.
 | 
						|
        if (this._settingUpNew || (!this._resettingSync && desc == 0))
 | 
						|
          return this.returnFromOptions();
 | 
						|
        return this._handleChoice();
 | 
						|
      case OPTIONS_CONFIRM_PAGE:
 | 
						|
        if (this._resettingSync) {
 | 
						|
          this.wizardFinish();
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
        return this.returnFromOptions();
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
 | 
						|
  onWizardBack: function () {
 | 
						|
    switch (this.wizard.pageIndex) {
 | 
						|
      case NEW_ACCOUNT_START_PAGE:
 | 
						|
        this.wizard.pageIndex = INTRO_PAGE;
 | 
						|
        return false;
 | 
						|
      case EXISTING_ACCOUNT_CONNECT_PAGE:
 | 
						|
        this.abortEasySetup();
 | 
						|
        this.wizard.pageIndex = INTRO_PAGE;
 | 
						|
        return false;
 | 
						|
      case EXISTING_ACCOUNT_LOGIN_PAGE:
 | 
						|
        // If we were already pairing on entry, we went straight to the manual
 | 
						|
        // login page. If subsequently we go back, return to the page that lets
 | 
						|
        // us choose whether we already have an account.
 | 
						|
        if (this.wizardType == "pair") {
 | 
						|
          this.wizard.pageIndex = INTRO_PAGE;
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
      case OPTIONS_CONFIRM_PAGE:
 | 
						|
        // Backing up from the confirmation page = resetting first sync to merge.
 | 
						|
        document.getElementById("mergeChoiceRadio").selectedIndex = 0;
 | 
						|
        return this.returnFromOptions();
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
 | 
						|
  wizardFinish: function () {
 | 
						|
    this.setupInitialSync();
 | 
						|
 | 
						|
    if (this.wizardType == "pair") {
 | 
						|
      this.completePairing();
 | 
						|
    }
 | 
						|
 | 
						|
    if (!this._resettingSync) {
 | 
						|
      function isChecked(element) {
 | 
						|
        return document.getElementById(element).hasAttribute("checked");
 | 
						|
      }
 | 
						|
 | 
						|
      let prefs = ["engine.bookmarks", "engine.passwords", "engine.history",
 | 
						|
                   "engine.tabs", "engine.prefs", "engine.addons"];
 | 
						|
      for (let i = 0;i < prefs.length;i++) {
 | 
						|
        Weave.Svc.Prefs.set(prefs[i], isChecked(prefs[i]));
 | 
						|
      }
 | 
						|
      this._handleNoScript(false);
 | 
						|
      if (Weave.Svc.Prefs.get("firstSync", "") == "notReady")
 | 
						|
        Weave.Svc.Prefs.reset("firstSync");
 | 
						|
 | 
						|
      Weave.Service.persistLogin();
 | 
						|
      Weave.Svc.Obs.notify("weave:service:setup-complete");
 | 
						|
    }
 | 
						|
    Weave.Utils.nextTick(Weave.Service.sync, Weave.Service);
 | 
						|
    window.close();
 | 
						|
  },
 | 
						|
 | 
						|
  onWizardCancel: function () {
 | 
						|
    if (this._resettingSync)
 | 
						|
      return;
 | 
						|
 | 
						|
    this.abortEasySetup();
 | 
						|
    this._handleNoScript(false);
 | 
						|
    Weave.Service.startOver();
 | 
						|
  },
 | 
						|
 | 
						|
  onSyncOptions: function () {
 | 
						|
    this._beforeOptionsPage = this.wizard.pageIndex;
 | 
						|
    this.wizard.pageIndex = OPTIONS_PAGE;
 | 
						|
  },
 | 
						|
 | 
						|
  returnFromOptions: function() {
 | 
						|
    this.wizard.getButton("next").label = this._nextButtonLabel;
 | 
						|
    this.wizard.getButton("next").setAttribute("accesskey",
 | 
						|
                                               this._nextButtonAccesskey);
 | 
						|
    this.wizard.getButton("back").label = this._backButtonLabel;
 | 
						|
    this.wizard.getButton("back").setAttribute("accesskey",
 | 
						|
                                               this._backButtonAccesskey);
 | 
						|
    this.wizard.getButton("cancel").hidden = false;
 | 
						|
    this.wizard.getButton("extra1").hidden = false;
 | 
						|
    this.wizard.pageIndex = this._beforeOptionsPage;
 | 
						|
    return false;
 | 
						|
  },
 | 
						|
 | 
						|
  startPairing: function startPairing() {
 | 
						|
    this.pairDeviceErrorRow.hidden = true;
 | 
						|
    // When onAbort is called, Weave may already be gone.
 | 
						|
    const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT;
 | 
						|
 | 
						|
    let self = this;
 | 
						|
    let jpakeclient = this._jpakeclient = new Weave.JPAKEClient({
 | 
						|
      onPaired: function onPaired() {
 | 
						|
        self.wizard.pageIndex = INTRO_PAGE;
 | 
						|
      },
 | 
						|
      onComplete: function onComplete() {
 | 
						|
        // This method will never be called since SendCredentialsController
 | 
						|
        // will take over after the wizard completes.
 | 
						|
      },
 | 
						|
      onAbort: function onAbort(error) {
 | 
						|
        delete self._jpakeclient;
 | 
						|
 | 
						|
        // Aborted by user, ignore. The window is almost certainly going to close
 | 
						|
        // or is already closed.
 | 
						|
        if (error == JPAKE_ERROR_USERABORT) {
 | 
						|
          return;
 | 
						|
        }
 | 
						|
 | 
						|
        self.pairDeviceErrorRow.hidden = false;
 | 
						|
        self.pairDeviceThrobber.hidden = true;
 | 
						|
        self.pin1.value = self.pin2.value = self.pin3.value = "";
 | 
						|
        self.pin1.disabled = self.pin2.disabled = self.pin3.disabled = false;
 | 
						|
        if (self.wizard.pageIndex == PAIR_PAGE) {
 | 
						|
          self.pin1.focus();
 | 
						|
        }
 | 
						|
      }
 | 
						|
    });
 | 
						|
    this.pairDeviceThrobber.hidden = false;
 | 
						|
    this.pin1.disabled = this.pin2.disabled = this.pin3.disabled = true;
 | 
						|
    this.wizard.canAdvance = false;
 | 
						|
 | 
						|
    let pin = this.pin1.value + this.pin2.value + this.pin3.value;
 | 
						|
    let expectDelay = true;
 | 
						|
    jpakeclient.pairWithPIN(pin, expectDelay);
 | 
						|
  },
 | 
						|
 | 
						|
  completePairing: function completePairing() {
 | 
						|
    if (!this._jpakeclient) {
 | 
						|
      // The channel was aborted while we were setting up the account
 | 
						|
      // locally. XXX TODO should we do anything here, e.g. tell
 | 
						|
      // the user on the last wizard page that it's ok, they just
 | 
						|
      // have to pair again?
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    let controller = new Weave.SendCredentialsController(this._jpakeclient,
 | 
						|
                                                         Weave.Service);
 | 
						|
    this._jpakeclient.controller = controller;
 | 
						|
  },
 | 
						|
 | 
						|
  startEasySetup: function () {
 | 
						|
    // Don't do anything if we have a client already (e.g. we went to
 | 
						|
    // Sync Options and just came back).
 | 
						|
    if (this._jpakeclient)
 | 
						|
      return;
 | 
						|
 | 
						|
    // When onAbort is called, Weave may already be gone
 | 
						|
    const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT;
 | 
						|
 | 
						|
    let self = this;
 | 
						|
    this._jpakeclient = new Weave.JPAKEClient({
 | 
						|
      displayPIN: function displayPIN(pin) {
 | 
						|
        document.getElementById("easySetupPIN1").value = pin.slice(0, 4);
 | 
						|
        document.getElementById("easySetupPIN2").value = pin.slice(4, 8);
 | 
						|
        document.getElementById("easySetupPIN3").value = pin.slice(8);
 | 
						|
      },
 | 
						|
 | 
						|
      onPairingStart: function onPairingStart() {},
 | 
						|
 | 
						|
      onComplete: function onComplete(credentials) {
 | 
						|
        Weave.Service.identity.account = credentials.account;
 | 
						|
        Weave.Service.identity.basicPassword = credentials.password;
 | 
						|
        Weave.Service.identity.syncKey = credentials.synckey;
 | 
						|
        Weave.Service.serverURL = credentials.serverURL;
 | 
						|
        gSyncSetup.wizardFinish();
 | 
						|
      },
 | 
						|
 | 
						|
      onAbort: function onAbort(error) {
 | 
						|
        delete self._jpakeclient;
 | 
						|
 | 
						|
        // Ignore if wizard is aborted.
 | 
						|
        if (error == JPAKE_ERROR_USERABORT)
 | 
						|
          return;
 | 
						|
 | 
						|
        // Automatically go to manual setup if we couldn't acquire a channel.
 | 
						|
        if (error == Weave.JPAKE_ERROR_CHANNEL) {
 | 
						|
          self.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
 | 
						|
          return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Restart on all other errors.
 | 
						|
        self.startEasySetup();
 | 
						|
      }
 | 
						|
    });
 | 
						|
    this._jpakeclient.receiveNoPIN();
 | 
						|
  },
 | 
						|
 | 
						|
  abortEasySetup: function () {
 | 
						|
    document.getElementById("easySetupPIN1").value = "";
 | 
						|
    document.getElementById("easySetupPIN2").value = "";
 | 
						|
    document.getElementById("easySetupPIN3").value = "";
 | 
						|
    if (!this._jpakeclient)
 | 
						|
      return;
 | 
						|
 | 
						|
    this._jpakeclient.abort();
 | 
						|
    delete this._jpakeclient;
 | 
						|
  },
 | 
						|
 | 
						|
  manualSetup: function () {
 | 
						|
    this.abortEasySetup();
 | 
						|
    this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
 | 
						|
  },
 | 
						|
 | 
						|
  // _handleNoScript is needed because it blocks the captcha. So we temporarily
 | 
						|
  // allow the necessary sites so that we can verify the user is in fact a human.
 | 
						|
  // This was done with the help of Giorgio (NoScript author). See bug 508112.
 | 
						|
  _handleNoScript: function (addExceptions) {
 | 
						|
    // if NoScript isn't installed, or is disabled, bail out.
 | 
						|
    let ns = Cc["@maone.net/noscript-service;1"];
 | 
						|
    if (ns == null)
 | 
						|
      return;
 | 
						|
 | 
						|
    ns = ns.getService().wrappedJSObject;
 | 
						|
    if (addExceptions) {
 | 
						|
      this._remoteSites.forEach(function(site) {
 | 
						|
        site = ns.getSite(site);
 | 
						|
        if (!ns.isJSEnabled(site)) {
 | 
						|
          this._disabledSites.push(site); // save status
 | 
						|
          ns.setJSEnabled(site, true); // allow site
 | 
						|
        }
 | 
						|
      }, this);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      this._disabledSites.forEach(function(site) {
 | 
						|
        ns.setJSEnabled(site, false);
 | 
						|
      });
 | 
						|
      this._disabledSites = [];
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  onExistingServerCommand: function () {
 | 
						|
    let control = document.getElementById("existingServer");
 | 
						|
    if (control.selectedIndex == 0) {
 | 
						|
      control.removeAttribute("editable");
 | 
						|
      Weave.Svc.Prefs.reset("serverURL");
 | 
						|
    } else {
 | 
						|
      control.setAttribute("editable", "true");
 | 
						|
      // Force a style flush to ensure that the binding is attached.
 | 
						|
      control.clientTop;
 | 
						|
      control.value = "";
 | 
						|
      control.inputField.focus();
 | 
						|
    }
 | 
						|
    document.getElementById("existingServerFeedbackRow").hidden = true;
 | 
						|
    this.checkFields();
 | 
						|
  },
 | 
						|
 | 
						|
  onExistingServerInput: function () {
 | 
						|
    // Check custom server validity when the user stops typing for 1 second.
 | 
						|
    if (this._existingServerTimer)
 | 
						|
      window.clearTimeout(this._existingServerTimer);
 | 
						|
    this._existingServerTimer = window.setTimeout(function () {
 | 
						|
      gSyncSetup.checkFields();
 | 
						|
    }, 1000);
 | 
						|
  },
 | 
						|
 | 
						|
  onServerCommand: function () {
 | 
						|
    setVisibility(document.getElementById("TOSRow"), this._usingMainServers);
 | 
						|
    let control = document.getElementById("server");
 | 
						|
    if (!this._usingMainServers) {
 | 
						|
      control.setAttribute("editable", "true");
 | 
						|
      // Force a style flush to ensure that the binding is attached.
 | 
						|
      control.clientTop;
 | 
						|
      control.value = "";
 | 
						|
      control.inputField.focus();
 | 
						|
      // checkServer() will call checkAccount() and checkFields().
 | 
						|
      this.checkServer();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    control.removeAttribute("editable");
 | 
						|
    Weave.Svc.Prefs.reset("serverURL");
 | 
						|
    if (this._settingUpNew) {
 | 
						|
      this.loadCaptcha();
 | 
						|
    }
 | 
						|
    this.checkAccount();
 | 
						|
    this.status.server = true;
 | 
						|
    document.getElementById("serverFeedbackRow").hidden = true;
 | 
						|
    this.checkFields();
 | 
						|
  },
 | 
						|
 | 
						|
  onServerInput: function () {
 | 
						|
    // Check custom server validity when the user stops typing for 1 second.
 | 
						|
    if (this._checkServerTimer)
 | 
						|
      window.clearTimeout(this._checkServerTimer);
 | 
						|
    this._checkServerTimer = window.setTimeout(function () {
 | 
						|
      gSyncSetup.checkServer();
 | 
						|
    }, 1000);
 | 
						|
  },
 | 
						|
 | 
						|
  checkServer: function () {
 | 
						|
    delete this._checkServerTimer;
 | 
						|
    let el = document.getElementById("server");
 | 
						|
    let valid = false;
 | 
						|
    let feedback = document.getElementById("serverFeedbackRow");
 | 
						|
    let str = "";
 | 
						|
    if (el.value) {
 | 
						|
      valid = this._validateServer(el);
 | 
						|
      let str = valid ? "" : "serverInvalid.label";
 | 
						|
      this._setFeedbackMessage(feedback, valid, str);
 | 
						|
    }
 | 
						|
    else
 | 
						|
      this._setFeedbackMessage(feedback, true);
 | 
						|
 | 
						|
    // Recheck account against the new server.
 | 
						|
    if (valid)
 | 
						|
      this.checkAccount();
 | 
						|
 | 
						|
    this.status.server = valid;
 | 
						|
    this.checkFields();
 | 
						|
  },
 | 
						|
 | 
						|
  _validateServer: function (element) {
 | 
						|
    let valid = false;
 | 
						|
    let val = element.value;
 | 
						|
    if (!val)
 | 
						|
      return false;
 | 
						|
 | 
						|
    let uri = Weave.Utils.makeURI(val);
 | 
						|
 | 
						|
    if (!uri)
 | 
						|
      uri = Weave.Utils.makeURI("https://" + val);
 | 
						|
 | 
						|
    if (uri && this._settingUpNew) {
 | 
						|
      function isValid(uri) {
 | 
						|
        Weave.Service.serverURL = uri.spec;
 | 
						|
        let check = Weave.Service.checkAccount("a");
 | 
						|
        return (check == "available" || check == "notAvailable");
 | 
						|
      }
 | 
						|
 | 
						|
      if (uri.schemeIs("http")) {
 | 
						|
        uri.scheme = "https";
 | 
						|
        if (isValid(uri))
 | 
						|
          valid = true;
 | 
						|
        else
 | 
						|
          // setting the scheme back to http
 | 
						|
          uri.scheme = "http";
 | 
						|
      }
 | 
						|
      if (!valid)
 | 
						|
        valid = isValid(uri);
 | 
						|
 | 
						|
      if (valid) {
 | 
						|
        this.loadCaptcha();
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else if (uri) {
 | 
						|
      valid = true;
 | 
						|
      Weave.Service.serverURL = uri.spec;
 | 
						|
    }
 | 
						|
 | 
						|
    if (valid)
 | 
						|
      element.value = Weave.Service.serverURL;
 | 
						|
    else
 | 
						|
      Weave.Svc.Prefs.reset("serverURL");
 | 
						|
 | 
						|
    return valid;
 | 
						|
  },
 | 
						|
 | 
						|
  _handleChoice: function () {
 | 
						|
    let desc = document.getElementById("mergeChoiceRadio").selectedIndex;
 | 
						|
    document.getElementById("chosenActionDeck").selectedIndex = desc;
 | 
						|
    switch (desc) {
 | 
						|
      case 1:
 | 
						|
        if (this._case1Setup)
 | 
						|
          break;
 | 
						|
 | 
						|
        let places_db = PlacesUtils.history
 | 
						|
                                   .QueryInterface(Ci.nsPIPlacesDatabase)
 | 
						|
                                   .DBConnection;
 | 
						|
        if (Weave.Service.engineManager.get("history").enabled) {
 | 
						|
          let daysOfHistory = 0;
 | 
						|
          let stm = places_db.createStatement(
 | 
						|
            "SELECT ROUND(( " +
 | 
						|
              "strftime('%s','now','localtime','utc') - " +
 | 
						|
              "( " +
 | 
						|
                "SELECT visit_date FROM moz_historyvisits " +
 | 
						|
                "ORDER BY visit_date ASC LIMIT 1 " +
 | 
						|
                ")/1000000 " +
 | 
						|
              ")/86400) AS daysOfHistory ");
 | 
						|
 | 
						|
          if (stm.step())
 | 
						|
            daysOfHistory = stm.getInt32(0);
 | 
						|
          // Support %S for historical reasons (see bug 600141)
 | 
						|
          document.getElementById("historyCount").value =
 | 
						|
            PluralForm.get(daysOfHistory,
 | 
						|
                           this._stringBundle.GetStringFromName("historyDaysCount.label"))
 | 
						|
                      .replace("%S", daysOfHistory)
 | 
						|
                      .replace("#1", daysOfHistory);
 | 
						|
        } else {
 | 
						|
          document.getElementById("historyCount").hidden = true;
 | 
						|
        }
 | 
						|
 | 
						|
        if (Weave.Service.engineManager.get("bookmarks").enabled) {
 | 
						|
          let bookmarks = 0;
 | 
						|
          let stm = places_db.createStatement(
 | 
						|
            "SELECT count(*) AS bookmarks " +
 | 
						|
            "FROM moz_bookmarks b " +
 | 
						|
            "LEFT JOIN moz_bookmarks t ON " +
 | 
						|
            "b.parent = t.id WHERE b.type = 1 AND t.parent <> :tag");
 | 
						|
          stm.params.tag = PlacesUtils.tagsFolderId;
 | 
						|
          if (stm.executeStep())
 | 
						|
            bookmarks = stm.row.bookmarks;
 | 
						|
          // Support %S for historical reasons (see bug 600141)
 | 
						|
          document.getElementById("bookmarkCount").value =
 | 
						|
            PluralForm.get(bookmarks,
 | 
						|
                           this._stringBundle.GetStringFromName("bookmarksCount.label"))
 | 
						|
                      .replace("%S", bookmarks)
 | 
						|
                      .replace("#1", bookmarks);
 | 
						|
        } else {
 | 
						|
          document.getElementById("bookmarkCount").hidden = true;
 | 
						|
        }
 | 
						|
 | 
						|
        if (Weave.Service.engineManager.get("passwords").enabled) {
 | 
						|
          let logins = Services.logins.getAllLogins({});
 | 
						|
          // Support %S for historical reasons (see bug 600141)
 | 
						|
          document.getElementById("passwordCount").value =
 | 
						|
            PluralForm.get(logins.length,
 | 
						|
                           this._stringBundle.GetStringFromName("passwordsCount.label"))
 | 
						|
                      .replace("%S", logins.length)
 | 
						|
                      .replace("#1", logins.length);
 | 
						|
        } else {
 | 
						|
          document.getElementById("passwordCount").hidden = true;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!Weave.Service.engineManager.get("prefs").enabled) {
 | 
						|
          document.getElementById("prefsWipe").hidden = true;
 | 
						|
        }
 | 
						|
 | 
						|
        let addonsEngine = Weave.Service.engineManager.get("addons");
 | 
						|
        if (addonsEngine.enabled) {
 | 
						|
          let ids = addonsEngine._store.getAllIDs();
 | 
						|
          let blessedcount = Object.keys(ids).filter(id => ids[id]).length;
 | 
						|
          // bug 600141 does not apply, as this does not have to support existing strings
 | 
						|
          document.getElementById("addonCount").value =
 | 
						|
            PluralForm.get(blessedcount,
 | 
						|
                           this._stringBundle.GetStringFromName("addonsCount.label"))
 | 
						|
                      .replace("#1", blessedcount);
 | 
						|
        } else {
 | 
						|
          document.getElementById("addonCount").hidden = true;
 | 
						|
        }
 | 
						|
 | 
						|
        this._case1Setup = true;
 | 
						|
        break;
 | 
						|
      case 2:
 | 
						|
        if (this._case2Setup)
 | 
						|
          break;
 | 
						|
        let count = 0;
 | 
						|
        function appendNode(label) {
 | 
						|
          let box = document.getElementById("clientList");
 | 
						|
          let node = document.createElement("label");
 | 
						|
          node.setAttribute("value", label);
 | 
						|
          node.setAttribute("class", "data indent");
 | 
						|
          box.appendChild(node);
 | 
						|
        }
 | 
						|
 | 
						|
        for (let name of Weave.Service.clientsEngine.stats.names) {
 | 
						|
          // Don't list the current client
 | 
						|
          if (name == Weave.Service.clientsEngine.localName)
 | 
						|
            continue;
 | 
						|
 | 
						|
          // Only show the first several client names
 | 
						|
          if (++count <= 5)
 | 
						|
            appendNode(name);
 | 
						|
        }
 | 
						|
        if (count > 5) {
 | 
						|
          // Support %S for historical reasons (see bug 600141)
 | 
						|
          let label =
 | 
						|
            PluralForm.get(count - 5,
 | 
						|
                           this._stringBundle.GetStringFromName("additionalClientCount.label"))
 | 
						|
                      .replace("%S", count - 5)
 | 
						|
                      .replace("#1", count - 5);
 | 
						|
          appendNode(label);
 | 
						|
        }
 | 
						|
        this._case2Setup = true;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
 | 
						|
  // sets class and string on a feedback element
 | 
						|
  // if no property string is passed in, we clear label/style
 | 
						|
  _setFeedback: function (element, success, string) {
 | 
						|
    element.hidden = success || !string;
 | 
						|
    let classname = success ? "success" : "error";
 | 
						|
    let image = element.getElementsByAttribute("class", "statusIcon")[0];
 | 
						|
    image.setAttribute("status", classname);
 | 
						|
    let label = element.getElementsByAttribute("class", "status")[0];
 | 
						|
    label.value = string;
 | 
						|
  },
 | 
						|
 | 
						|
  // shim
 | 
						|
  _setFeedbackMessage: function (element, success, string) {
 | 
						|
    let str = "";
 | 
						|
    if (string) {
 | 
						|
      try {
 | 
						|
        str = this._stringBundle.GetStringFromName(string);
 | 
						|
      } catch (e) {}
 | 
						|
 | 
						|
      if (!str)
 | 
						|
        str = Weave.Utils.getErrorString(string);
 | 
						|
    }
 | 
						|
    this._setFeedback(element, success, str);
 | 
						|
  },
 | 
						|
 | 
						|
  loadCaptcha: function loadCaptcha() {
 | 
						|
    let captchaURI = Weave.Service.miscAPI + "captcha_html";
 | 
						|
    // First check for NoScript and whitelist the right sites.
 | 
						|
    this._handleNoScript(true);
 | 
						|
    if (this.captchaBrowser.currentURI.spec != captchaURI) {
 | 
						|
      this.captchaBrowser.loadURI(captchaURI);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  onStateChange: function(webProgress, request, stateFlags, status) {
 | 
						|
    // We're only looking for the end of the frame load
 | 
						|
    if ((stateFlags & Ci.nsIWebProgressListener.STATE_STOP) == 0)
 | 
						|
      return;
 | 
						|
    if ((stateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) == 0)
 | 
						|
      return;
 | 
						|
    if ((stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) == 0)
 | 
						|
      return;
 | 
						|
 | 
						|
    // If we didn't find a captcha, assume it's not needed and don't show it.
 | 
						|
    let responseStatus = request.QueryInterface(Ci.nsIHttpChannel).responseStatus;
 | 
						|
    setVisibility(this.captchaBrowser, responseStatus != 404);
 | 
						|
    //XXX TODO we should really log any responseStatus other than 200
 | 
						|
  },
 | 
						|
  onProgressChange: function() {},
 | 
						|
  onStatusChange: function() {},
 | 
						|
  onSecurityChange: function() {},
 | 
						|
  onLocationChange: function () {}
 | 
						|
};
 | 
						|
 | 
						|
// Define lazy getters for various XUL elements.
 | 
						|
//
 | 
						|
// onWizardAdvance() and onPageShow() are run before init(), so we'll even
 | 
						|
// define things that will almost certainly be used (like 'wizard') as a lazy
 | 
						|
// getter here.
 | 
						|
["wizard",
 | 
						|
 "pin1",
 | 
						|
 "pin2",
 | 
						|
 "pin3",
 | 
						|
 "pairDeviceErrorRow",
 | 
						|
 "pairDeviceThrobber"].forEach(function (id) {
 | 
						|
  XPCOMUtils.defineLazyGetter(gSyncSetup, id, function() {
 | 
						|
    return document.getElementById(id);
 | 
						|
  });
 | 
						|
});
 | 
						|
XPCOMUtils.defineLazyGetter(gSyncSetup, "nextFocusEl", function () {
 | 
						|
  return {pin1: this.pin2,
 | 
						|
          pin2: this.pin3,
 | 
						|
          pin3: this.wizard.getButton("next")};
 | 
						|
});
 | 
						|
XPCOMUtils.defineLazyGetter(gSyncSetup, "_stringBundle", function() {
 | 
						|
  return Services.strings.createBundle("chrome://browser/locale/syncSetup.properties");
 | 
						|
});
 |