merge upstream changes
authorDan Mills <thunder@mozilla.com>
Fri, 08 Aug 2008 14:43:36 -0700
changeset 44993 5ffe9b279c9d6146adc674ed848c976bd50ab79c
parent 44992 07d02a30011e20c9ac930a26a86ec84e6364cfc3 (current diff)
parent 44989 a152624d1c47cd3c5282178ad9d89484d1e66d4a (diff)
child 44994 90542900ba59dfe6dda990e94264418f1b8ef97e
push idunknown
push userunknown
push dateunknown
merge upstream changes
services/sync/modules/remote.js
new file mode 100644
--- /dev/null
+++ b/services/sync/locales/en-US/oauth.dtd
@@ -0,0 +1,18 @@
+<!ENTITY oauth.title      "3rd Party Authorization">
+
+<!ENTITY intro.title      "3rd Party Authorization Wizard">
+<!ENTITY intro.msg        "A third party has requested access to your Weave data. Before you can authorize the party, we must first authenticate you.">
+<!ENTITY intro.uid        "Username:">
+<!ENTITY intro.pwd        "Password:">
+<!ENTITY intro.pas        "Verify Passphrase:">
+<!ENTITY intro.loading    "Please Wait...">
+<!ENTITY intro.success    "Your account has been verified! Please click Continue to proceed.">
+<!ENTITY intro.error      "Your account could not be verified, please try again!">
+
+<!ENTITY conf.title       "Authorization">
+<!ENTITY conf.loading     "Please wait while we verify the third party's request...">
+<!ENTITY conf.proceed     "By clicking the Continue button, you automatically authorize the third party. If you do not wish to grant access, you may click the Cancel button.">
+
+<!ENTITY final.title      "Granting Access to third party">
+<!ENTITY final.processing "Please wait while your data is re-encrypted to enable access by the authorized third party...">
+<!ENTITY final.manual     "Please notify the consumer that their request token was successfully authorized!">
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/services/sync/locales/en-US/oauth.properties
@@ -0,0 +1,10 @@
+intro.uidmsg            = You are logged in as %S
+conf.conmsg             = A third party identifying itself as %S is requesting access to your Weave Data.
+conf.error              = Sorry, but the third party's request was invalid: %S
+conf.error1             = a request token was not issued.
+conf.error2             = the third party is unregistered.
+conf.error3             = the request token has expired.
+conf.error4             = your account details could not be verified.
+final.step1             = Unwrapping symmetric key...
+final.step2             = Adding third party to your keyring...
+final.step3             = Done!
\ No newline at end of file
--- a/services/sync/locales/en-US/preferences.dtd
+++ b/services/sync/locales/en-US/preferences.dtd
@@ -32,16 +32,17 @@
 <!ENTITY syncNowButton.label                "Sync Now...">
 <!ENTITY syncItemsList.label                "Synchronize these items:">
 <!ENTITY bookmarksCheckbox.label            "Bookmarks">
 <!ENTITY historyCheckbox.label              "Browsing History">
 <!ENTITY cookiesCheckbox.label              "Cookies">
 <!ENTITY passwordsCheckbox.label            "Saved Passwords">
 <!ENTITY formsCheckbox.label                "Saved Form Data">
 <!ENTITY tabsCheckbox.label                 "Tabs">
+<!ENTITY inputCheckbox.label                "Input History">
 <!ENTITY extensionsCheckbox.label           "Extensions">
 <!ENTITY themesCheckbox.label               "Themes">
 <!ENTITY pluginsCheckbox.label              "Search Plugins">
 <!ENTITY microformatsCheckbox.label         "Microformats">
 
 <!ENTITY addonsGroupbox.description         "This is where you will find, install, and manage Weave add-ons.">
 
 <!ENTITY serverSettingsCaption.label        "Server Settings">
--- a/services/sync/modules/dav.js
+++ b/services/sync/modules/dav.js
@@ -248,16 +248,24 @@ DAVCollection.prototype = {
     return this._makeRequest.async(this, onComplete, "GET", path,
                                    this._defaultHeaders);
   },
 
   POST: function DC_POST(path, data, onComplete) {
     return this._makeRequest.async(this, onComplete, "POST", path,
                                    this._defaultHeaders, data);
   },
+  
+  formPost: function DC_formPOST(path, data, onComplete) {
+    let headers = {'Content-type': 'application/x-www-form-urlencoded'};
+    headers.__proto__ = this._defaultHeaders;
+    
+    return this._makeRequest.async(this, onComplete, "POST", path,
+                                   headers, data);
+  },
 
   PUT: function DC_PUT(path, data, onComplete) {
     return this._makeRequest.async(this, onComplete, "PUT", path,
                                    this._defaultHeaders, data);
   },
 
   DELETE: function DC_DELETE(path, onComplete) {
     return this._makeRequest.async(this, onComplete, "DELETE", path,
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -15,16 +15,17 @@
  *
  * The Initial Developer of the Original Code is Mozilla.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Dan Mills <thunder@mozilla.com>
  *  Jono DiCarlo <jdicarlo@mozilla.org>
+ *  Anant Narayanan <anant@kix.in>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -285,16 +286,44 @@ BookmarksSharingManager.prototype = {
     // Send message to the share-ee, so they can stop their incoming share
     let abspath = "/user/" + this._myUsername + "/" + serverPath;
     this._sendXmppNotification( username, "stop", abspath, folderName );
 
     this._log.info("Stopped sharing " + folderName + "with " + username);
     self.done( true );
   },
 
+  /* FIXME! Gets all shares, not just the new ones. Doesn't impact
+     functionality because _incomingShareOffer does not create
+     duplicates, but annoys the user by showing notification of ALL
+     shares on EVERY sync :(
+  */
+  getNewShares: function BmkSharing_getNewShares(onComplete) {
+    this._getNewShares.async(this, onComplete);
+  },
+  _getNewShares: function BmkSharing__getNewShares() {
+    let self = yield;
+
+    let sharingApi = new Sharing.Api( DAV );
+    let result = yield sharingApi.getShares(self.cb);
+
+		this._log.info("Got Shares: " + result);
+		let shares = result.split(',');
+		if (shares.length > 1) {
+		  this._log.info('Found shares');
+		  for (var i = 0; i < shares.length - 1; i++) {
+		    let share = shares[i].split(':');
+		    let name = share[0];
+		    let user = share[1];
+		    let path = share[2];
+		    this._incomingShareOffer(user, '/user/' + user + '/' + path, name);
+		  }
+		}
+  },
+  
   updateAllIncomingShares: function BmkSharing_updateAllIncoming(onComplete) {
     this._updateAllIncomingShares.async(this, onComplete);
   },
   _updateAllIncomingShares: function BmkSharing__updateAllIncoming() {
     /* For every bookmark folder in my tree that has the annotation
        marking it as an incoming shared folder, pull down its latest
        contents from its owner's account on the server.  (This is
        a one-way data transfer because I can't modify bookmarks that
@@ -431,18 +460,19 @@ BookmarksSharingManager.prototype = {
     if (encryptionTurnedOn) {
       yield this._createKeyChain.async(this, self.cb, serverPath,
 				       this._myUsername, username);
     }
 
     // Call Atul's js api for setting htaccess:
     let sharingApi = new Sharing.Api( DAV );
     let result = yield sharingApi.shareWithUsers( serverPath,
-						  [username],
+						  [username], folderName,
 						  self.cb );
+		this._log.info(result.errorText);
     // return the server path:
     self.done( serverPath );
   },
 
   _updateOutgoingShare: function BmkSharing__updateOutgoing(folderId) {
     /* Puts all the bookmark data from the specified bookmark folder,
        encrypted, onto the shared directory on the server (replacing
        anything that was already there).
@@ -720,16 +750,17 @@ BookmarksEngine.prototype = {
       this.__sharing = new BookmarksSharingManager(this);
     return this.__sharing;
   },
 
   _sync: function BmkEngine__sync() {
     /* After syncing the regular bookmark folder contents,
      * also update both the incoming and outgoing shared folders. */
     let self = yield;
+    let ret = yield this._sharing.getNewShares(self.cb);
     this.__proto__.__proto__._sync.async(this, self.cb );
     yield;
     this._sharing.updateAllOutgoingShares(self.cb);
     yield;
     this._sharing.updateAllIncomingShares(self.cb);
     yield;
     self.done();
   },
--- a/services/sync/modules/engines/history.js
+++ b/services/sync/modules/engines/history.js
@@ -116,39 +116,58 @@ HistorySyncCore.prototype = {
 };
 HistorySyncCore.prototype.__proto__ = new SyncCore();
 
 function HistoryStore() {
   this._init();
 }
 HistoryStore.prototype = {
   _logName: "HistStore",
+  _lookup: null,
 
   __hsvc: null,
   get _hsvc() {
     if (!this.__hsvc) {
       this.__hsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
                     getService(Ci.nsINavHistoryService);
       this.__hsvc.QueryInterface(Ci.nsIGlobalHistory2);
       this.__hsvc.QueryInterface(Ci.nsIBrowserHistory);
     }
     return this.__hsvc;
   },
 
+  __histDB: null,
+  get _histDB() {
+    if (!this.__histDB) {
+      let file = Cc["@mozilla.org/file/directory_service;1"].
+                 getService(Ci.nsIProperties).
+                 get("ProfD", Ci.nsIFile);
+      file.append("places.sqlite");
+      let stor = Cc["@mozilla.org/storage/service;1"].
+                 getService(Ci.mozIStorageService);
+      this.__histDB = stor.openDatabase(file);
+    }
+    return this.__histDB;
+  },
+
   _itemExists: function HistStore__itemExists(GUID) {
     // we don't care about already-existing items; just try to re-add them
     return false;
   },
 
   _createCommand: function HistStore__createCommand(command) {
     this._log.debug("  -> creating history entry: " + command.GUID);
     try {
       let uri = Utils.makeURI(command.data.URI);
+      let redirect = false;
+      if (command.data.transition == 5 || command.data.transition == 6)
+        redirect = true;
+
       this._hsvc.addVisit(uri, command.data.time, null,
-                          this._hsvc.TRANSITION_TYPED, false, null);
+                          command.data.transition, redirect, 0);
       this._hsvc.setPageTitle(uri, command.data.title);
     } catch (e) {
       this._log.error("Exception caught: " + (e.message? e.message : e));
     }
   },
 
   _removeCommand: function HistStore__removeCommand(command) {
     this._log.trace("  -> NOT removing history entry: " + command.GUID);
@@ -173,30 +192,54 @@ HistoryStore.prototype = {
     options.sortingMode = options.SORT_BY_DATE_DESCENDING;
     options.queryType = options.QUERY_TYPE_HISTORY;
 
     let root = this._hsvc.executeQuery(query, options).root;
     root.QueryInterface(Ci.nsINavHistoryQueryResultNode);
     return root;
   },
 
+  /* UGLY, UGLY way of syncing visit type !
+     We'll just have to wait for bug #320831 */
+  _getVisitType: function HistStore__getVisitType(uri) {
+    let visitStmnt = this._histDB.createStatement("SELECT visit_type FROM moz_historyvisits WHERE place_id = ?1");
+    let pidStmnt = this._histDB.createStatement("SELECT id FROM moz_places WHERE url = ?1");
+    
+    pidStmnt.bindUTF8StringParameter(0, uri);
+    
+    let placeID = null;
+    if (pidStmnt.executeStep()) {
+      placeID = pidStmnt.getInt32(0);
+    }
+
+    if (placeID) {
+      visitStmnt.bindInt32Parameter(0, placeID);
+      if (visitStmnt.executeStep())
+        return visitStmnt.getInt32(0);
+    }
+    return null;
+  },
+  
   wrap: function HistStore_wrap() {
     let root = this._historyRoot();
     root.containerOpen = true;
     let items = {};
     for (let i = 0; i < root.childCount; i++) {
       let item = root.getChild(i);
-      let guid = item.time + ":" + item.uri
+      let guid = item.time + ":" + item.uri;
+      let vType = this._getVisitType(item.uri);
       items[guid] = {parentGUID: '',
 			 title: item.title,
 			 URI: item.uri,
-			 time: item.time
+			 time: item.time,
+			 transition: vType
 			};
-      // FIXME: sync transition type - requires FULL_VISITs
     }
+    
+    this._lookup = items;
     return items;
   },
 
   wipe: function HistStore_wipe() {
     this._hsvc.removeAllPages();
   },
 
   _resetGUIDs: function FormStore__resetGUIDs() {
new file mode 100644
--- /dev/null
+++ b/services/sync/modules/engines/input.js
@@ -0,0 +1,295 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Bookmarks Sync.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Anant Narayanan <anant@kix.in>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const EXPORTED_SYMBOLS = ['InputEngine'];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://weave/log4moz.js");
+Cu.import("resource://weave/async.js");
+Cu.import("resource://weave/util.js");
+Cu.import("resource://weave/engines.js");
+Cu.import("resource://weave/syncCores.js");
+Cu.import("resource://weave/stores.js");
+Cu.import("resource://weave/trackers.js");
+
+Function.prototype.async = Async.sugar;
+
+function InputEngine(pbeId) {
+  this._init(pbeId);
+}
+InputEngine.prototype = {
+  __proto__: new SyncEngine(),
+
+  get name() { return "input"; },
+  get displayName() { return "Input History"; },
+  get logName() { return "InputEngine"; },
+  get serverPrefix() { return "user-data/input/"; },
+
+  __store: null,
+  get _store() {
+    if (!this.__store)
+      this.__store = new InputStore();
+    return this.__store;
+  },
+
+  __core: null,
+  get _core() {
+    if (!this.__core)
+      this.__core = new InputSyncCore(this._store);
+    return this.__core;
+  },
+
+  __tracker: null,
+  get _tracker() {
+    if (!this.__tracker)
+      this.__tracker = new InputTracker();
+    return this.__tracker;
+  }
+};
+
+function InputSyncCore(store) {
+  this._store = store;
+  this._init();
+}
+InputSyncCore.prototype = {
+  _logName: "InputSync",
+  _store: null,
+
+  _commandLike: function FSC_commandLike(a, b) {
+    /* Not required as GUIDs for similar data sets will be the same */
+    return false;
+  }
+};
+InputSyncCore.prototype.__proto__ = new SyncCore();
+
+function InputStore() {
+  this._init();
+}
+InputStore.prototype = {
+  _logName: "InputStore",
+  _lookup: null,
+
+  __placeDB: null,
+  get _placeDB() {
+    if (!this.__placeDB) {
+      let file = Cc["@mozilla.org/file/directory_service;1"].
+                 getService(Ci.nsIProperties).
+                 get("ProfD", Ci.nsIFile);
+      file.append("places.sqlite");
+      let stor = Cc["@mozilla.org/storage/service;1"].
+                 getService(Ci.mozIStorageService);
+      this.__histDB = stor.openDatabase(file);
+    }
+    return this.__histDB;
+  },
+  
+  _getIDfromURI: function InputStore__getIDfromURI(uri) {
+    let pidStmnt = this._placeDB.createStatement("SELECT id FROM moz_places WHERE url = ?1");
+    pidStmnt.bindUTF8StringParameter(0, uri);
+    if (pidStmnt.executeStep())
+      return pidStmnt.getInt32(0);
+    else
+      return null;
+  },
+  
+  _getInputHistory: function InputStore__getInputHistory(id) {
+    let ipStmnt = this._placeDB.createStatement("SELECT input, use_count FROM moz_inputhistory WHERE place_id = ?1");
+    ipStmnt.bindInt32Parameter(0, id);
+    
+    let input = [];
+    while (ipStmnt.executeStep()) {
+      let ip = ipStmnt.getUTF8String(0);
+      let cnt = ipStmnt.getInt32(1);
+      input[input.length] = {'input': ip, 'count': cnt};
+    }
+    
+    return input;
+  },
+
+  _createCommand: function InputStore__createCommand(command) {
+    this._log.info("InputStore got createCommand: " + command);
+    
+    let placeID = this._getIDfromURI(command.GUID);
+    if (placeID) {
+      let createStmnt = this._placeDB.createStatement("INSERT INTO moz_inputhistory (?1, ?2, ?3)");
+      createStmnt.bindInt32Parameter(0, placeID);
+      createStmnt.bindUTF8StringParameter(1, command.data.input);
+      createStmnt.bindInt32Parameter(2, command.data.count);
+      
+      createStmnt.execute();
+    }
+  },
+
+  _removeCommand: function InputStore__removeCommand(command) {
+    this._log.info("InputStore got removeCommand: " + command);
+
+    if (!(command.GUID in this._lookup)) {
+      this._log.warn("Invalid GUID found, ignoring remove request.");
+      return;
+    }
+
+    let placeID = this._getIDfromURI(command.GUID);
+    let remStmnt = this._placeDB.createStatement("DELETE FROM moz_inputhistory WHERE place_id = ?1 AND input = ?2");
+    
+    remStmnt.bindInt32Parameter(0, placeID);
+    remStmnt.bindUTF8StringParameter(1, command.data.input);
+    remStmnt.execute();
+    
+    delete this._lookup[command.GUID];
+  },
+
+  _editCommand: function InputStore__editCommand(command) {
+    this._log.info("InputStore got editCommand: " + command);
+    
+    if (!(command.GUID in this._lookup)) {
+      this._log.warn("Invalid GUID found, ignoring remove request.");
+      return;
+    }
+
+    let placeID = this._getIDfromURI(command.GUID);
+    let editStmnt = this._placeDB.createStatement("UPDATE moz_inputhistory SET input = ?1, use_count = ?2 WHERE place_id = ?3");
+    
+    if ('input' in command.data) {
+      editStmnt.bindUTF8StringParameter(0, command.data.input);
+    } else {
+      editStmnt.bindUTF8StringParameter(0, this._lookup[command.GUID].input);
+    }
+    
+    if ('count' in command.data) {
+      editStmnt.bindInt32Parameter(1, command.data.count);
+    } else {
+      editStmnt.bindInt32Parameter(1, this._lookup[command.GUID].count);
+    }
+    
+    editStmnt.bindInt32Parameter(2, placeID);
+    editStmnt.execute();
+  },
+
+  wrap: function InputStore_wrap() {
+    this._lookup = {};
+    let stmnt = this._placeDB.createStatement("SELECT * FROM moz_inputhistory");
+    
+    while (stmnt.executeStep()) {
+      let pid = stmnt.getInt32(0);
+      let inp = stmnt.getUTF8String(1);
+      let cnt = stmnt.getInt32(2);
+
+      let idStmnt = this._placeDB.createStatement("SELECT url FROM moz_places WHERE id = ?1");
+      idStmnt.bindInt32Parameter(0, pid);
+      if (idStmnt.executeStep()) {
+        let key = idStmnt.getUTF8String(0);
+        this._lookup[key] = { 'input': inp, 'count': cnt };
+      }
+    }
+
+    return this._lookup;
+  },
+
+  wipe: function InputStore_wipe() {
+    var stmnt = this._placeDB.createStatement("DELETE FROM moz_inputhistory");
+    stmnt.execute();
+  },
+
+  _resetGUIDs: function InputStore__resetGUIDs() {
+    let self = yield;
+    // Not needed.
+  }
+};
+InputStore.prototype.__proto__ = new Store();
+
+function InputTracker() {
+  this._init();
+}
+InputTracker.prototype = {
+  _logName: "InputTracker",
+
+  __placeDB: null,
+  get _placeDB() {
+    if (!this.__placeDB) {
+      let file = Cc["@mozilla.org/file/directory_service;1"].
+                 getService(Ci.nsIProperties).
+                 get("ProfD", Ci.nsIFile);
+      file.append("places.sqlite");
+      let stor = Cc["@mozilla.org/storage/service;1"].
+                 getService(Ci.mozIStorageService);
+      this.__histDB = stor.openDatabase(file);
+    }
+    return this.__histDB;
+  },
+
+  /* 
+   * To calculate scores, we just count the changes in
+   * the database since the last time we were asked.
+   *
+   * Each change is worth 5 points.
+   */
+  _rowCount: 0,
+  get score() {
+    var stmnt = this._placeDB.createStatement("SELECT COUNT(place_id) FROM moz_inputhistory");
+    stmnt.executeStep();
+    var count = stmnt.getInt32(0);
+    stmnt.reset();
+
+    this._score = Math.abs(this._rowCount - count) * 5;
+
+    if (this._score >= 100)
+      return 100;
+    else
+      return this._score;
+  },
+
+  resetScore: function InputTracker_resetScore() {
+    var stmnt = this._placeDB.createStatement("SELECT COUNT(place_id) FROM moz_inputhistory");
+    stmnt.executeStep();
+    this._rowCount = stmnt.getInt32(0);
+    stmnt.reset();
+    this._score = 0;
+  },
+
+  _init: function InputTracker__init() {
+    this._log = Log4Moz.Service.getLogger("Service." + this._logName);
+    this._score = 0;
+
+    var stmnt = this._placeDB.createStatement("SELECT COUNT(place_id) FROM moz_inputhistory");
+    stmnt.executeStep();
+    this._rowCount = stmnt.getInt32(0);
+    stmnt.reset();
+  }
+};
+InputTracker.prototype.__proto__ = new Tracker();
new file mode 100644
--- /dev/null
+++ b/services/sync/modules/oauth.js
@@ -0,0 +1,156 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Bookmarks Sync.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2008.
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Anant Narayanan <anant@kix.in>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const EXPORTED_SYMBOLS = ['OAuth'];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://weave/log4moz.js");
+Cu.import("resource://weave/constants.js");
+Cu.import("resource://weave/util.js");
+Cu.import("resource://weave/async.js");
+Cu.import("resource://weave/identity.js");
+Cu.import("resource://weave/engines.js");
+
+Function.prototype.async = Async.sugar;
+
+Utils.lazy(this, 'OAuth', OAuthSvc);
+
+function OAuthSvc() {
+  this._init();
+}
+OAuthSvc.prototype = {
+  _logName: "OAuth",
+  _keyring: null,
+  _consKey: null,
+  _bulkID: null,
+  _rsaKey: null,
+  _token: null,
+  _cback: null,
+  _uid: null,
+  _pwd: null,
+  _pas: null,
+  _cb1: null,
+  _cb2: null,
+  
+  _init: function OAuth__init() {
+    this._log = Log4Moz.Service.getLogger("Service." + this._logName);
+    this._log.level = "Debug";
+    this._log.info("OAuth Module Initialized");
+  },
+
+  setToken: function OAuth_setToken(token, cback) {
+    this._token = token;
+    this._cback = cback;
+  },
+  
+  setUser: function OAuth_setUser(username, password, passphrase) {
+    this._uid = username;
+    this._pwd = password;
+    this._pas = passphrase;
+  },
+  
+  validate: function OAuth_getName(obj, cb) {
+    if (!this._token || !this._uid || !this._pwd)
+      cb(obj, false);
+
+    var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
+              createInstance(Ci.nsIXMLHttpRequest);
+    var key = btoa(this._uid + ":" + this._pwd);
+    
+    req.onreadystatechange = function(e) {
+      if (req.readyState == 4) {
+        if (req.status == 200) {
+          var fields = req.responseText.split(',');
+          cb(obj, fields[0], fields[1], fields[2]);
+        } else {
+          cb(obj, req.responseText);
+        }
+      }
+    };
+    req.open('GET', 'https://services.mozilla.com/api/oauth/info.php?token=' + this._token + '&key=' + key);
+    req.send(null);
+  },
+  
+  finalize: function OAuth_finalize(cb1, cb2, bundle) {
+    this._cb1 = cb1;
+    this._cb2 = cb2;
+    this._bundle = bundle;
+
+    var bmkEngine = Engines.get('bookmarks');
+    var bmkRstore = bmkEngine._remote;
+
+    this._keyring = bmkRstore.keys;
+    this._keyring.getKeyAndIV(Utils.bind2(this, this._gotBulkKey), ID.get('WeaveID'));
+  },
+  
+  _gotBulkKey: function OAuth_gotBulkKey() {
+    let consID = new Identity();
+    consID.pubkey = this._rsaKey;
+    consID.username = this._consKey;
+    this._cb1(this._bundle);
+    this._log.info("Updating keyring for 3rd party access");
+    this._keyring.setKey(Utils.bind2(this, this._done), ID.get('WeaveID'), consID);
+  },
+  
+  _done: function OAuth__done() {
+    var cb = this._cb2;
+    var bu = this._bundle;
+
+    if (!this._token || !this._uid || !this._pwd)
+      cb(this._bundle, false);
+    
+    var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
+              createInstance(Ci.nsIXMLHttpRequest);
+    var key = btoa(this._uid + ":" + this._pwd);
+    
+    req.onreadystatechange = function(e) {
+      if (req.readyState == 4) {
+        if (req.status == 200 && req.responseText == "1") {
+          cb(bu, true);
+        } else {
+          cb(bu, false);
+        }
+      }
+    };
+    req.open('GET', 'https://services.mozilla.com/api/oauth/update.php?token=' + this._token + '&key=' + key);
+    req.send(null);
+  }
+};
--- a/services/sync/modules/remote.js
+++ b/services/sync/modules/remote.js
@@ -413,20 +413,42 @@ Keychain.prototype = {
     let idRSA = ID.get('WeaveCryptoID');
     let symkey = yield Crypto.unwrapKey.async(Crypto, self.cb,
                            this.data.ring[identity.username], idRSA);
     let iv = this.data.bulkIV;
 
     identity.bulkKey = symkey;
     identity.bulkIV  = iv;
   },
+  _setKey: function KeyChain__setKey(bulkID, newID) {
+    /* FIXME!: It's possible that the keyring is changed on the server
+       after we do a GET. Then we're just uploading this new local keyring,
+       thereby losing any changes made on the server keyring since this GET.
+    
+       Also, if this.data was not instantiated properly (i.e. you're
+       using KeyChain directly instead of getting it from the engine),
+       you run the risk of wiping the server-side keychain.
+    */
+    let self = yield;
+
+    this.get(self.cb);
+    yield;
+    
+    let wrappedKey = yield Crypto.wrapKey.async(Crypto, self.cb,
+                          bulkID.bulkKey, newID);
+    this.data.ring[newID.username] = wrappedKey;
+    this.put(self.cb, this.data);
+    yield;
+  },
   getKeyAndIV: function Keychain_getKeyAndIV(onComplete, identity) {
     this._getKeyAndIV.async(this, onComplete, identity);
+  },
+  setKey: function Keychain_setKey(onComplete, bulkID, newID) {
+    this._setKey.async(this, onComplete, bulkID, newID);
   }
-  // FIXME: implement setKey()
 };
 
 function RemoteStore(engine) {
   this._engine = engine;
   this._log = Log4Moz.Service.getLogger("Service.RemoteStore");
 }
 RemoteStore.prototype = {
   get serverPrefix() this._engine.serverPrefix,
@@ -677,17 +699,17 @@ RemoteStore.prototype = {
                              "status.uploading-deltas");
     yield this._deltas.put(self.cb, id, delta);
 
     // if we have more than KEEP_DELTAS, then upload a new snapshot
     // this allows us to remove old deltas
     if ((id - this.status.data.snapVersion) > KEEP_DELTAS) {
       this._os.notifyObservers(null, "weave:service:sync:status",
                                "status.uploading-snapshot");
-      yield this.snapshot.put(self.cb, snapshot.data);
+      yield this._snapshot.put(self.cb, snapshot.data);
       this.status.data.snapVersion = id;
     }
 
     // XXX we could define another constant here
     // (e.g. KEEP_MAX_DELTAS) to define when to actually start
     // deleting deltas from the server.  However, we can do this more
     // efficiently server-side
 
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -67,26 +67,28 @@ const THRESHOLD_DECREMENT_STEP = 25;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://weave/log4moz.js");
 Cu.import("resource://weave/constants.js");
 Cu.import("resource://weave/util.js");
 Cu.import("resource://weave/wrap.js");
 Cu.import("resource://weave/faultTolerance.js");
 Cu.import("resource://weave/crypto.js");
 Cu.import("resource://weave/engines.js");
+Cu.import("resource://weave/oauth.js");
 Cu.import("resource://weave/dav.js");
 Cu.import("resource://weave/identity.js");
 Cu.import("resource://weave/async.js");
 Cu.import("resource://weave/clientData.js");
 Cu.import("resource://weave/engines/cookies.js");
 Cu.import("resource://weave/engines/bookmarks.js");
 Cu.import("resource://weave/engines/history.js");
 Cu.import("resource://weave/engines/passwords.js");
 Cu.import("resource://weave/engines/forms.js");
 Cu.import("resource://weave/engines/tabs.js");
+Cu.import("resource://weave/engines/input.js");
 
 Function.prototype.async = Async.sugar;
 
 // for export
 let Weave = {};
 Cu.import("resource://weave/constants.js", Weave);
 Cu.import("resource://weave/util.js", Weave);
 Cu.import("resource://weave/async.js", Weave);
@@ -94,23 +96,25 @@ Cu.import("resource://weave/faultToleran
 Cu.import("resource://weave/crypto.js", Weave);
 Cu.import("resource://weave/notifications.js", Weave);
 Cu.import("resource://weave/identity.js", Weave);
 Cu.import("resource://weave/clientData.js", Weave);
 Cu.import("resource://weave/dav.js", Weave);
 Cu.import("resource://weave/stores.js", Weave);
 Cu.import("resource://weave/syncCores.js", Weave);
 Cu.import("resource://weave/engines.js", Weave);
+Cu.import("resource://weave/oauth.js", Weave);
 Cu.import("resource://weave/service.js", Weave);
 Cu.import("resource://weave/engines/cookies.js", Weave);
 Cu.import("resource://weave/engines/passwords.js", Weave);
 Cu.import("resource://weave/engines/bookmarks.js", Weave);
 Cu.import("resource://weave/engines/history.js", Weave);
 Cu.import("resource://weave/engines/forms.js", Weave);
 Cu.import("resource://weave/engines/tabs.js", Weave);
+Cu.import("resource://weave/engines/input.js", Weave);
 
 Utils.lazy(Weave, 'Service', WeaveSvc);
 
 /*
  * Service singleton
  * Main entry point into Weave's sync framework
  */
 
@@ -545,16 +549,19 @@ WeaveSvc.prototype = {
   },
 
   _verifyPassphrase: function WeaveSvc__verifyPassphrase(username, password,
                                                          passphrase) {
     let self = yield;
 
     this._log.debug("Verifying passphrase");
 
+    this.username = username;
+    ID.get('WeaveID').setTempPassword(password);
+    
     let id = new Identity('Passphrase Verification', username);
     id.setTempPassword(passphrase);
 
     // FIXME: abstract common bits and share code with getKeypair()
 
     // XXX: We're not checking the version of the server here, in part because
     // we have no idea what to do if the version is different than we expect
     // it to be.
--- a/services/sync/modules/sharing.js
+++ b/services/sync/modules/sharing.js
@@ -14,16 +14,17 @@
  * The Original Code is Bookmarks Sync.
  *
  * The Initial Developer of the Original Code is Mozilla.
  * Portions created by the Initial Developer are Copyright (C) 2008
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Atul Varma <varmaa@toolness.com>
+ *  Anant Narayanan <anant@kix.in>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -45,37 +46,53 @@ Cu.import("resource://weave/identity.js"
 
 Function.prototype.async = Async.sugar;
 
 function Api(dav) {
   this._dav = dav;
 }
 
 Api.prototype = {
-  shareWithUsers: function Api_shareWithUsers(path, users, onComplete) {
-    this._shareGenerator.async(this,
+  shareWithUsers: function Api_shareWithUsers(path, users, folder, onComplete) {
+    return this._shareGenerator.async(this,
                                onComplete,
                                path,
-                               users);
+                               users, folder);
   },
 
-  _shareGenerator: function Api__shareGenerator(path, users) {
+  getShares: function Api_getShares(onComplete) {
+    return this._getShareGenerator.async(this, onComplete);
+  },
+  
+  _getShareGenerator: function Api__getShareGenerator() {
+    let self = yield;
+    let id = ID.get(this._dav.identity);
+    
+    this._dav.formPost("/api/share/get.php", ("uid=" + escape(id.username) +
+                                              "&password=" + escape(id.password)),
+                                              self.cb);
+    let xhr = yield;
+    self.done(xhr.responseText);
+  },
+
+  _shareGenerator: function Api__shareGenerator(path, users, folder) {
     let self = yield;
     let id = ID.get(this._dav.identity);
 
     let cmd = {"version" : 1,
                "directory" : path,
                "share_to_users" : users};
     let jsonSvc = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
     let json = jsonSvc.encode(cmd);
 
-    this._dav.POST("/api/share/",
+    this._dav.formPost("/api/share/",
                    ("cmd=" + escape(json) +
                     "&uid=" + escape(id.username) +
-                    "&password=" + escape(id.password)),
+                    "&password=" + escape(id.password) +
+                    "&name=" + escape(folder)),
                    self.cb);
     let xhr = yield;
 
     let retval;
 
     if (xhr.status == 200) {
       if (xhr.responseText == "OK") {
         retval = {wasSuccessful: true};
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -16,16 +16,17 @@ pref("extensions.weave.schedule", 1);
 pref("extensions.weave.syncOnQuit.enabled", true);
 
 pref("extensions.weave.engine.bookmarks", true);
 pref("extensions.weave.engine.history", true);
 pref("extensions.weave.engine.cookies", true );
 pref("extensions.weave.engine.passwords", false);
 pref("extensions.weave.engine.forms", false);
 pref("extensions.weave.engine.tabs", true);
+pref("extensions.weave.engine.input", false);
 
 pref("extensions.weave.log.appender.console", "Warn");
 pref("extensions.weave.log.appender.dump", "Error");
 pref("extensions.weave.log.appender.briefLog", "Info");
 pref("extensions.weave.log.appender.debugLog", "Trace");
 
 pref("extensions.weave.log.rootLogger", "Trace");
 pref("extensions.weave.log.logger.async", "Debug");