From a59f8a133cf29427bc414212018fc14c0f4dde79 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@localhost" Date: Fri, 6 Jun 2008 19:22:23 -0700 Subject: [PATCH 01/16] Made BookmarkEngine.sync() responsible for calling BookmarkEngine.syncMounts (to get the incoming shared bookmark folder contents), eliminating the FIXME that previously had this being called from special-case code in WeaveSvc.sync(). --- services/sync/modules/engines/bookmarks.js | 7 +++++++ services/sync/modules/service.js | 12 ++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 3d58c4199f22..f08457ed6faa 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -45,6 +45,13 @@ BookmarksEngine.prototype = { return this.__tracker; }, + sync: function BmkEngine_sync(onComplete) { + /* After syncing, also call syncMounts to get the + incoming shared bookmark folder contents. */ + Engine.sync.call(this, onComplete); + this.syncMounts(onComplete); + } + syncMounts: function BmkEngine_syncMounts(onComplete) { this._syncMounts.async(this, onComplete); }, diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index d8d68bb26fb0..fad2175597ee 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -508,10 +508,6 @@ WeaveSvc.prototype = { this._notify(engines[i].name + "-engine:sync", this._syncEngine, engines[i]).async(this, self.cb); yield; - if (engines[i].name == "bookmarks") { // FIXME - Engines.get("bookmarks").syncMounts(self.cb); - yield; - } } } }, @@ -574,11 +570,11 @@ WeaveSvc.prototype = { Implementation, as well as the interpretation of what 'guid' means, is left up to the engine for the specific dataType. */ - // TODO who is listening for the share-bookmarks message? let messageName = "share-" + dataType; - // so for instance, if dataType is "bookmarks" then a message - // "share-bookmarks" will be sent out to any observers who are listening - // for it. + /* so for instance, if dataType is "bookmarks" then a message + "share-bookmarks" will be sent out to any observers who are listening + for it. As far as I know, there aren't currently any listeners for + "share-bookmarks" but we'll send it out just in case. */ this._lock(this._notify(messageName, this._shareData, dataType, From 5bb48d8dfa92396c74543b3f2aaf9783e41902f2 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@localhost" Date: Fri, 6 Jun 2008 19:28:01 -0700 Subject: [PATCH 02/16] Added license block and explanatory comments to bookmarks.js --- services/sync/modules/engines/bookmarks.js | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index f08457ed6faa..6e7a3f5bd653 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -1,3 +1,40 @@ +/* ***** 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) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Mills + * Jono DiCarlo + * + * 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 = ['BookmarksEngine']; const Cc = Components.classes; @@ -56,6 +93,13 @@ BookmarksEngine.prototype = { this._syncMounts.async(this, onComplete); }, _syncMounts: function BmkEngine__syncMounts() { + /* 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 + are owned by someone else but shared to me; any changes I make + to the folder contents are simply wiped out by the latest + server contents.) */ let self = yield; let mounts = this._store.findMounts(); From ea75f4df3a84781f5f8204ade7c6a66086afb6cb Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Mon, 9 Jun 2008 11:48:52 -0700 Subject: [PATCH 03/16] Fixed my code so that BookmarkEngine._sync() now works correctly to call Engine._sync() and BookmarkEngine.syncMounts(), asynchronously. Added in some TODO comments about what's going to happen in the next round of refactoring. --- services/sync/modules/engines/bookmarks.js | 61 ++++++++++++++-------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 6e7a3f5bd653..12bee06177a6 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -41,6 +41,10 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; +// Annotation to use for shared bookmark folders, incoming and outgoing: +const INCOMING_SHARED_ANNO = "weave/shared-incoming"; +const OUTGOING_SHARED_ANNO = "weave/shared-outgoing"; + Cu.import("resource://weave/log4moz.js"); Cu.import("resource://weave/dav.js"); Cu.import("resource://weave/util.js"); @@ -82,12 +86,16 @@ BookmarksEngine.prototype = { return this.__tracker; }, - sync: function BmkEngine_sync(onComplete) { + _sync: function BmkEngine_sync() { /* After syncing, also call syncMounts to get the incoming shared bookmark folder contents. */ - Engine.sync.call(this, onComplete); - this.syncMounts(onComplete); - } + let self = yield; + this.__proto__.__proto__._sync.async(this, self.cb ); + yield; + this.syncMounts(self.cb); + yield; + self.done(); + }, syncMounts: function BmkEngine_syncMounts(onComplete) { this._syncMounts.async(this, onComplete); @@ -153,30 +161,27 @@ BookmarksEngine.prototype = { if (!enckey) throw "Could not encrypt symmetric encryption key"; + /* TODO this function needs to be broken up into createOutgoingShare + and updateOutgoingShare. */ keys.ring[username] = enckey; DAV.PUT(this.keysFile, this._json.encode(keys), self.cb); ret = yield; Utils.ensureStatus(ret.status, "Could not upload keyring file."); - this._createShare(guid, username, username); + /* TODO send an XMPP message to the recipient of the share to tell + them to call _createIncomingShare. */ this._log.debug("All done sharing!"); self.done(true); }, - _createShare: function BookmarkEngine__createShare(guid, id, title) { - /* the bookmark item identified by guid, and the whole subtree under it, - must be copied out from the main file into a separate file which is - put into the new directory and encrypted with the key in the keychain. - id is the userid of the user we're sharing with. - */ + _createIncomingShare: function BookmarkEngine__createShare(guid, id, title) { - /* TODO it appears that this just creates the folder and puts the - annotation on it; the mechanics of sharing must be done when syncing? - - Or has that not been done yet at all? - Do we have to create a new Mount? + /* TODO This used to be called just _createShare, but its semantics + have changed slightly -- its purpose now is to create a new empty + incoming shared bookmark folder. To do this is mostly the same code, + but it will need a few tweaks. */ let bms = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. getService(Ci.nsINavBookmarksService); @@ -211,19 +216,25 @@ BookmarksEngine.prototype = { } }, - _stopShare: function BookmarkeEngine__stopShare( guid, username) { - // TODO implement this; also give a way to call it from outside - // the service. - }, _syncOneMount: function BmkEngine__syncOneMount(mountData) { + /* Pull down bookmarks from the server for a single incoming + shared folder. */ + + /* TODO modify this: the old implementation assumes we want to copy + everything that the other user has, by pulling down snapshot and + diffs and applying the diffs to the snapshot. Instead, now we just + want to get a single subfolder and its children, which will be in + a separate file. */ + + // TODO for clarity maybe rename this to updateIncomingShare. + let self = yield; let user = mountData.userid; let prefix = DAV.defaultPrefix; let serverURL = Utils.prefs.getCharPref("serverURL"); let snap = new SnapshotStore(); - // TODO this is obviously what we want. this._log.debug("Syncing shared folder from user " + user); try { @@ -790,10 +801,14 @@ BookmarksStore.prototype = { }, findMounts: function BStore_findMounts() { + /* Returns list of mount data structures, each of which + represents one incoming shared-bookmark folder. */ let ret = []; - let a = this._ans.getItemsWithAnnotation("weave/mounted-share-id", {}); + let a = this._ans.getItemsWithAnnotation(INCOMING_SHARED_ANNO, {}); for (let i = 0; i < a.length; i++) { - let id = this._ans.getItemAnnotation(a[i], "weave/mounted-share-id"); + /* The value of the incoming-shared annotation is the id of the + person who has shared it with us. Get that value: */ + let id = this._ans.getItemAnnotation(a[i], INCOMING_SHARED_ANNO); ret.push(this._wrapMount(this._getNode(a[i]), id)); } return ret; From 512d95591bd32ec4e84d17fbea21b995695be9f0 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Mon, 9 Jun 2008 12:12:51 -0700 Subject: [PATCH 04/16] The folder annotation for outgoing shared folders is now a string containing the username of the person the folder is being shared with. Also moved to using const strings in bookmark-menu-overlay.js. --- services/sync/modules/engines.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/sync/modules/engines.js b/services/sync/modules/engines.js index 6d5381cec167..b025a535ebf4 100644 --- a/services/sync/modules/engines.js +++ b/services/sync/modules/engines.js @@ -656,7 +656,9 @@ Engine.prototype = { return; }, - // TODO need a "stop sharing" function. + /* TODO need a "stop sharing" function. + Actually, stopping an outgoing share and stopping an incoming share + are two different things. */ sync: function Engine_sync(onComplete) { return this._sync.async(this, onComplete); @@ -666,7 +668,7 @@ Engine.prototype = { return this._share.async(this, onComplete, guid, username); }, - resetServer: function Engine_resetServer(onComplete) { + resetServer: function Engimne_resetServer(onComplete) { this._notify("reset-server", this._resetServer).async(this, onComplete); }, From def99000e20ed358df940e96febffbb58ddc0cd0 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Mon, 9 Jun 2008 15:27:09 -0700 Subject: [PATCH 05/16] Renamed bookmarkeEngine methods so they make more sense with the new sharing model, e.g. updateAllIncomingShares instead of syncMounts. --- services/sync/modules/engines/bookmarks.js | 100 ++++++++++++++++++--- 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 12bee06177a6..ac2e9ca83092 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -54,6 +54,11 @@ Cu.import("resource://weave/engines.js"); Cu.import("resource://weave/syncCores.js"); Cu.import("resource://weave/stores.js"); Cu.import("resource://weave/trackers.js"); +/* LONGTERM TODO: when we start working on the ability to share other types +of data besides bookmarks, the xmppClient instance should be moved to hang +off of Weave.Service instead of hanging off the BookmarksEngine. But for +now this is the easiest place to deal with it. */ +Cu.import("resource://weave/xmpp/xmppClient.js"); Function.prototype.async = Async.sugar; @@ -86,21 +91,98 @@ BookmarksEngine.prototype = { return this.__tracker; }, + _startXmppClient: function BmkEngine__startXmppClient() { + /* this should probably be called asynchronously as it can take a while. */ + + // TODO add preferences for serverUrl and realm. + // Also add a boolean preference to turn XMPP messaging on or off. + let serverUrl = "http://sm-labs01.mozilla.org:5280/http_poll"; + let realm = "sm-labs01.mozilla.org"; + + // TODO once we have ejabberd talking to LDAP, the username/password + // for xmpp will be the same as the ones for Weave itself, so we can + // read username/password from ID.get('WeaveID' + let clientName = ID.get('WeaveID').username; + let clientPassword = ID.get('WeaveID').password; + + let transport = new HTTPPollingTransport( serverUrl, false, 15000 ); + let auth = new PlainAuthenticator(); + // TODO use MD5Authenticator instead once we get it working -- plain is + // a security hole. + this._xmppClient = new XmppClient( clientName, + realm, + clientPassword, + transport, + auth ); + let self = this; + let messageHandler = { + handle: function ( messageText, from ) { + /* The callback function for incoming xmpp messages. + We expect message text to be either: + "share " + (sender offers to share directory dir with us) + or "stop " + (sender has stopped sharing directory dir with us.) + or "accept " + (sharee has accepted our offer to share our dir.) + or "decline " + (sharee has declined our offer to share our dir.) + */ + let words = messageText.split(" "); + let commandWord = words[0]; + let directoryName = words[1]; + if ( commandWord == "share" ) { + self._incomingShareOffer( directoryName, from ); + } else if ( commandWord == "stop" ) { + self._incomingShareWithdrawn( directoryName, from ); + } + } + } + this._xmppClient.registerMessageHandler( messageHandler ); + this._xmppClient.connect( realm ); + }, + + _incomingShareOffer: function BmkEngine__incomingShareOffer( dir, user ) { + /* Called when we receive an offer from another user to share a + directory. + + TODO what should happen is that we add a notification to the queue + telling that the incoming share has been offered; when the offer + is accepted we will call createIncomingShare and then + updateIncomingShare. + + But since we don't have notification in place yet, I'm going to skip + right ahead to creating the incoming share. + */ + + }, + + _incomingShareWithdrawn: function BmkEngine__incomingShareStop( dir, user ) { + /* Called when we receive a message telling us that a user who has + already shared a directory with us has chosen to stop sharing + the directory. + + TODO Find the incomingShare in our bookmark tree that corresponds + to the shared directory, and delete it; add a notification to + the queue telling us what has happened. + */ + }, + _sync: function BmkEngine_sync() { /* After syncing, also call syncMounts to get the incoming shared bookmark folder contents. */ let self = yield; this.__proto__.__proto__._sync.async(this, self.cb ); yield; - this.syncMounts(self.cb); + this.updateAllIncomingShares(self.cb); yield; self.done(); }, - syncMounts: function BmkEngine_syncMounts(onComplete) { + updateAllIncomingShares: function BmkEngine_updateAllIncoming(onComplete) { this._syncMounts.async(this, onComplete); }, - _syncMounts: function BmkEngine__syncMounts() { + _updateAllIncomingShares: function BmkEngine__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 @@ -109,11 +191,11 @@ BookmarksEngine.prototype = { to the folder contents are simply wiped out by the latest server contents.) */ let self = yield; - let mounts = this._store.findMounts(); + let mounts = this._store.findIncomingShares(); for (i = 0; i < mounts.length; i++) { try { - this._syncOneMount.async(this, self.cb, mounts[i]); + this._updateIncomingShare.async(this, self.cb, mounts[i]); yield; } catch (e) { this._log.warn("Could not sync shared folder from " + mounts[i].userid); @@ -124,7 +206,7 @@ BookmarksEngine.prototype = { // TODO modify this as neccessary since I just moved it from the engine // superclass into BookmarkEngine. - _share: function BookmarkEngine__share(guid, username) { + _createOutgoingShare: function BmkEngine__createOutgoing(guid, username) { let self = yield; let prefix = DAV.defaultPrefix; @@ -217,7 +299,7 @@ BookmarksEngine.prototype = { }, - _syncOneMount: function BmkEngine__syncOneMount(mountData) { + _updateIncomingShare: function BmkEngine__updateIncomingShare(mountData) { /* Pull down bookmarks from the server for a single incoming shared folder. */ @@ -227,8 +309,6 @@ BookmarksEngine.prototype = { want to get a single subfolder and its children, which will be in a separate file. */ - // TODO for clarity maybe rename this to updateIncomingShare. - let self = yield; let user = mountData.userid; let prefix = DAV.defaultPrefix; @@ -800,7 +880,7 @@ BookmarksStore.prototype = { } }, - findMounts: function BStore_findMounts() { + findIncomingShares: function BStore_findIncomingShares() { /* Returns list of mount data structures, each of which represents one incoming shared-bookmark folder. */ let ret = []; From 09185ac26b991a85709954ff3bb2f2f27a32b670 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Mon, 9 Jun 2008 16:19:58 -0700 Subject: [PATCH 06/16] Fixed a couple minor bugs that were preventing bookmark engine from starting up properly --- services/sync/modules/engines/bookmarks.js | 28 ++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index ac2e9ca83092..0501663bb0e4 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -168,7 +168,7 @@ BookmarksEngine.prototype = { */ }, - _sync: function BmkEngine_sync() { + _sync: function BmkEngine__sync() { /* After syncing, also call syncMounts to get the incoming shared bookmark folder contents. */ let self = yield; @@ -179,8 +179,21 @@ BookmarksEngine.prototype = { self.done(); }, + _share: function BmkEngine__share( guid, username ) { + /* TODO check to see we're not already sharing this thing. */ + // this._createOutgoingShare( guid, username ); + /* TODO Setting the annotations should happen here instead of in + share.js? */ + // this._updateOutgoingShare( guid, username ); + + // or something like this: + //this._xmppClient.sendMessage( "Hey I share with you ", username ); + dump( "In bookmarkEngine._share. Sharing " + guid + " with " + username ); + return true; + }, + updateAllIncomingShares: function BmkEngine_updateAllIncoming(onComplete) { - this._syncMounts.async(this, onComplete); + this._updateAllIncomingShares.async(this, onComplete); }, _updateAllIncomingShares: function BmkEngine__updateAllIncoming() { /* For every bookmark folder in my tree that has the annotation @@ -204,13 +217,11 @@ BookmarksEngine.prototype = { } }, - // TODO modify this as neccessary since I just moved it from the engine - // superclass into BookmarkEngine. _createOutgoingShare: function BmkEngine__createOutgoing(guid, username) { let self = yield; let prefix = DAV.defaultPrefix; - this._log.debug("Sharing bookmarks with " + username); + this._log.debug("Sharing bookmarks from " + guid + " with " + username); this._getSymKey.async(this, self.cb); yield; @@ -243,8 +254,6 @@ BookmarksEngine.prototype = { if (!enckey) throw "Could not encrypt symmetric encryption key"; - /* TODO this function needs to be broken up into createOutgoingShare - and updateOutgoingShare. */ keys.ring[username] = enckey; DAV.PUT(this.keysFile, this._json.encode(keys), self.cb); ret = yield; @@ -258,6 +267,11 @@ BookmarksEngine.prototype = { self.done(true); }, + _updateOutgoingShare: function BmkEngine__updateOutgoing(guid, username) { + /* TODO this needs to have the logic to break the shared bookmark + subtree out of the store and put it in a separate file...*/ + }, + _createIncomingShare: function BookmarkEngine__createShare(guid, id, title) { /* TODO This used to be called just _createShare, but its semantics From f0b2f120ea686df812f0e235fe46409db3fdb11f Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Mon, 9 Jun 2008 16:49:04 -0700 Subject: [PATCH 07/16] Moved the writing of the outgoing-share annotation on the bookmark folder to BookmarkEngine._share, where it makes a lot more sense than it does in the share.js dialog-box code where it used to be. --- services/sync/modules/engines/bookmarks.js | 25 +++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 0501663bb0e4..7b1f4ba83976 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -179,16 +179,31 @@ BookmarksEngine.prototype = { self.done(); }, - _share: function BmkEngine__share( guid, username ) { + _share: function BmkEngine__share( selectedFolder, username ) { + // Return true if success, false if failure. + /* TODO check to see we're not already sharing this thing. */ // this._createOutgoingShare( guid, username ); - /* TODO Setting the annotations should happen here instead of in - share.js? */ // this._updateOutgoingShare( guid, username ); - // or something like this: + /* Set the annotation on the folder so we know + it's an outgoing share: */ + let folderItemId = selectedFolder.node.itemId; + let folderName = selectedFolder.getAttribute( "label" ); + let annotation = { name: "weave/share/shared_outgoing", + value: username, + flags: 0, + mimeType: null, + type: PlacesUtils.TYPE_STRING, + expires: PlacesUtils.EXPIRE_NEVER }; + // TODO: does this clobber existing annotations? + PlacesUtils.setAnnotationsForItem( folderItemId, [ annotation ] ); + /* LONGTERM TODO: in the future when we allow sharing one folder + with many people, the value of the annotation can be a whole list + of usernames instead of just one. */ + //this._xmppClient.sendMessage( "Hey I share with you ", username ); - dump( "In bookmarkEngine._share. Sharing " + guid + " with " + username ); + dump( "In bookmarkEngine._share. Sharing " +folderName + " with " + username ); return true; }, From be8d8ca4df4e7e1852e7860f6074c61a56712aa5 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Mon, 9 Jun 2008 18:44:13 -0700 Subject: [PATCH 08/16] Fixed a couple of minor bugs that were preventing bookmark share from starting (like, i was skipping enabled engines instead of disabled engines... duhh) --- services/sync/modules/engines.js | 3 ++- services/sync/modules/engines/bookmarks.js | 27 +++++++++++----------- services/sync/modules/service.js | 10 ++++---- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/services/sync/modules/engines.js b/services/sync/modules/engines.js index b025a535ebf4..ff52d2870328 100644 --- a/services/sync/modules/engines.js +++ b/services/sync/modules/engines.js @@ -650,10 +650,11 @@ Engine.prototype = { }, _share: function Engine__share(guid, username) { + let self = yield; /* This should be overridden by the engine subclass for each datatype. Implementation should share the data node identified by guid, and all its children, if any, with the user identified by username. */ - return; + self.done(); }, /* TODO need a "stop sharing" function. diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 7b1f4ba83976..40adefc9f1a0 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -54,6 +54,7 @@ Cu.import("resource://weave/engines.js"); Cu.import("resource://weave/syncCores.js"); Cu.import("resource://weave/stores.js"); Cu.import("resource://weave/trackers.js"); + /* LONGTERM TODO: when we start working on the ability to share other types of data besides bookmarks, the xmppClient instance should be moved to hang off of Weave.Service instead of hanging off the BookmarksEngine. But for @@ -181,30 +182,30 @@ BookmarksEngine.prototype = { _share: function BmkEngine__share( selectedFolder, username ) { // Return true if success, false if failure. + let ret = false; + let ans = Cc["@mozilla.org/browser/annotation-service;1"]. + getService(Ci.nsIAnnotationService); + let self = yield; /* TODO check to see we're not already sharing this thing. */ - // this._createOutgoingShare( guid, username ); - // this._updateOutgoingShare( guid, username ); - + // TODO call this._createOutgoingShare( guid, username ); + // TODO call this._updateOutgoingShare( guid, username ); + // TODO call + // this._xmppClient.sendMessage( "Hey I share with you ", username ); /* Set the annotation on the folder so we know it's an outgoing share: */ let folderItemId = selectedFolder.node.itemId; let folderName = selectedFolder.getAttribute( "label" ); - let annotation = { name: "weave/share/shared_outgoing", - value: username, - flags: 0, - mimeType: null, - type: PlacesUtils.TYPE_STRING, - expires: PlacesUtils.EXPIRE_NEVER }; + ans.setItemAnnotation(folderItemId, OUTGOING_SHARED_ANNO, username, 0, + ans.EXPIRE_NEVER); // TODO: does this clobber existing annotations? - PlacesUtils.setAnnotationsForItem( folderItemId, [ annotation ] ); /* LONGTERM TODO: in the future when we allow sharing one folder with many people, the value of the annotation can be a whole list of usernames instead of just one. */ - //this._xmppClient.sendMessage( "Hey I share with you ", username ); - dump( "In bookmarkEngine._share. Sharing " +folderName + " with " + username ); - return true; + dump( "Bookmark engine shared " +folderName + " with " + username ); + ret = true; + self.done( ret ); }, updateAllIncomingShares: function BmkEngine_updateAllIncoming(onComplete) { diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index fad2175597ee..ce9d1cf1c1fd 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -581,12 +581,14 @@ WeaveSvc.prototype = { guid, username)).async(this, onComplete); }, - _shareBookmarks: function WeaveSync__shareBookmarks(dataType, - guid, - username) { + _shareData: function WeaveSync__shareData(dataType, + guid, + username) { let self = yield; - if (Engines.get(dataType).enabled) + if (!Engines.get(dataType).enabled) { + this._log.warn( "Can't share disabled data type: " + dataType ); return; + } Engines.get(dataType).share(self.cb, guid, username); let ret = yield; self.done(ret); From 52089ca90114c7d5eba848eff16e3c4742e36e10 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@localhost" Date: Wed, 11 Jun 2008 11:01:45 -0700 Subject: [PATCH 09/16] Expanded bookmarkEngine.share and added some more todos for the next round of functions to implement --- services/sync/modules/engines/bookmarks.js | 34 ++++++++++++++++------ 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 40adefc9f1a0..489cf3b360ed 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -187,11 +187,15 @@ BookmarksEngine.prototype = { getService(Ci.nsIAnnotationService); let self = yield; - /* TODO check to see we're not already sharing this thing. */ - // TODO call this._createOutgoingShare( guid, username ); - // TODO call this._updateOutgoingShare( guid, username ); - // TODO call - // this._xmppClient.sendMessage( "Hey I share with you ", username ); + /* TODO What should the behavior be if i'm already sharing it with user + A and I ask to share it with user B? (This should be prevented by + the UI. */ + + // Create the outgoing share folder on the server + // TODO do I need to call these asynchronously? + this._createOutgoingShare.async( this, selectedFolder, username ); + this._updateOutgoingShare.async( this, selectedFolder, username ); + /* Set the annotation on the folder so we know it's an outgoing share: */ let folderItemId = selectedFolder.node.itemId; @@ -199,6 +203,13 @@ BookmarksEngine.prototype = { ans.setItemAnnotation(folderItemId, OUTGOING_SHARED_ANNO, username, 0, ans.EXPIRE_NEVER); // TODO: does this clobber existing annotations? + + // Send an xmpp message to the share-ee + if ( this._xmppClient ) { + let msgText = "share " + folderName; + this._xmppClient.sendMessage( username, msgText ); + } + /* LONGTERM TODO: in the future when we allow sharing one folder with many people, the value of the annotation can be a whole list of usernames instead of just one. */ @@ -233,7 +244,7 @@ BookmarksEngine.prototype = { } }, - _createOutgoingShare: function BmkEngine__createOutgoing(guid, username) { + _createOutgoingShare: function BmkEngine__createOutgoing(folder, username) { let self = yield; let prefix = DAV.defaultPrefix; @@ -246,6 +257,7 @@ BookmarksEngine.prototype = { DAV.GET(this.keysFile, self.cb); let ret = yield; Utils.ensureStatus(ret.status, "Could not get keys file."); + // note: this._json is just an encoder/decoder, no state. let keys = this._json.decode(ret.responseText); // get the other user's pubkey @@ -275,11 +287,11 @@ BookmarksEngine.prototype = { ret = yield; Utils.ensureStatus(ret.status, "Could not upload keyring file."); - /* TODO send an XMPP message to the recipient of the share to tell - them to call _createIncomingShare. */ - this._log.debug("All done sharing!"); + // TODO this function also needs to call Atul's js api for setting + // htaccess. + self.done(true); }, @@ -288,6 +300,10 @@ BookmarksEngine.prototype = { subtree out of the store and put it in a separate file...*/ }, + _stopOutgoingShare: function BmkEngine__stopOutgoingShare( guid, username ) { + /* TODO implement this... */ + }, + _createIncomingShare: function BookmarkEngine__createShare(guid, id, title) { /* TODO This used to be called just _createShare, but its semantics From b308c467e5795c17a38046bf53b059906ea1e8b9 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@localhost" Date: Wed, 11 Jun 2008 11:13:35 -0700 Subject: [PATCH 10/16] Created preferences for xmpp connection info (server url, realm, username, password), and a preference to turn xmpp messaging on or off, and made BookmarkEngine._init() call startXmppClient when this preference is true. --- services/sync/modules/engines/bookmarks.js | 26 ++++++++++++++++------ services/sync/services-sync.js | 7 ++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 489cf3b360ed..051a3c6e2b1a 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -92,19 +92,31 @@ BookmarksEngine.prototype = { return this.__tracker; }, + _init: function BmkEngine__init( pbeId ) { + this.__proto__.__proto__._init.call( this, pbeId ); + if ( Utils.prefs.getBoolPref( "xmpp.enabled" ) ) { + dump( "Starting XMPP client for bookmark engine..." ); + this._startXmppClient(); + // TODO catch errors if connection fails. + } + } + _startXmppClient: function BmkEngine__startXmppClient() { /* this should probably be called asynchronously as it can take a while. */ - // TODO add preferences for serverUrl and realm. - // Also add a boolean preference to turn XMPP messaging on or off. - let serverUrl = "http://sm-labs01.mozilla.org:5280/http_poll"; - let realm = "sm-labs01.mozilla.org"; + // Get serverUrl and realm of the jabber server from preferences: + let serverUrl = Utils.prefs.getStringPref( "xmpp.server.url" ); + let realm = Utils.prefs.getStringPref( "xmpp.server.realm" ); + //"http://sm-labs01.mozilla.org:5280/http_poll"; // TODO once we have ejabberd talking to LDAP, the username/password // for xmpp will be the same as the ones for Weave itself, so we can - // read username/password from ID.get('WeaveID' - let clientName = ID.get('WeaveID').username; - let clientPassword = ID.get('WeaveID').password; + // read username/password like this: + // let clientName = ID.get('WeaveID').username; + // let clientPassword = ID.get('WeaveID').password; + // until then get these from preferences as well: + let clientName = Utils.prefs.getStringPref( "xmpp.client.name" ); + let clientPassword = Utils.prefs.getStringPref( "xmpp.client.password" ); let transport = new HTTPPollingTransport( serverUrl, false, 15000 ); let auth = new PlainAuthenticator(); diff --git a/services/sync/services-sync.js b/services/sync/services-sync.js index 5769981402aa..1c0958640ca8 100644 --- a/services/sync/services-sync.js +++ b/services/sync/services-sync.js @@ -31,3 +31,10 @@ pref("extensions.weave.log.logger.service.crypto", "Debug"); pref("extensions.weave.log.logger.service.dav", "Debug"); pref("extensions.weave.log.logger.service.engine", "Debug"); pref("extensions.weave.log.logger.service.main", "Trace"); + +pref("extensions.weave.xmpp.enabled", true); +pref("extensions.weave.xmpp.server.url", + "http://sm-labs01.mozilla.org:5280/http_poll"); +pref("extensions.weave.xmpp.server.realm", "sm-labs01.mozilla.org"); +pref("extensions.weave.xmpp.client.name", ""); +pref("extensions.weave.xmpp.client.password", ""); From b047be1d6caca2ba2b7b1d124dd9fc005bfa73b8 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Wed, 11 Jun 2008 15:43:12 -0700 Subject: [PATCH 11/16] Fixed Utils.prefs.getStringPref (should be getCharPref) --- services/sync/modules/engines/bookmarks.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 051a3c6e2b1a..7042611d1bcf 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -96,18 +96,18 @@ BookmarksEngine.prototype = { this.__proto__.__proto__._init.call( this, pbeId ); if ( Utils.prefs.getBoolPref( "xmpp.enabled" ) ) { dump( "Starting XMPP client for bookmark engine..." ); + // TODO call startXmppClient asynchronously? this._startXmppClient(); // TODO catch errors if connection fails. } - } + }, _startXmppClient: function BmkEngine__startXmppClient() { - /* this should probably be called asynchronously as it can take a while. */ + // TODO this should probably be called asynchronously as it can take a while. // Get serverUrl and realm of the jabber server from preferences: - let serverUrl = Utils.prefs.getStringPref( "xmpp.server.url" ); - let realm = Utils.prefs.getStringPref( "xmpp.server.realm" ); - //"http://sm-labs01.mozilla.org:5280/http_poll"; + let serverUrl = Utils.prefs.getCharPref( "xmpp.server.url" ); + let realm = Utils.prefs.getCharPref( "xmpp.server.realm" ); // TODO once we have ejabberd talking to LDAP, the username/password // for xmpp will be the same as the ones for Weave itself, so we can @@ -115,8 +115,8 @@ BookmarksEngine.prototype = { // let clientName = ID.get('WeaveID').username; // let clientPassword = ID.get('WeaveID').password; // until then get these from preferences as well: - let clientName = Utils.prefs.getStringPref( "xmpp.client.name" ); - let clientPassword = Utils.prefs.getStringPref( "xmpp.client.password" ); + let clientName = Utils.prefs.getCharPref( "xmpp.client.name" ); + let clientPassword = Utils.prefs.getCharPref( "xmpp.client.password" ); let transport = new HTTPPollingTransport( serverUrl, false, 15000 ); let auth = new PlainAuthenticator(); @@ -301,8 +301,10 @@ BookmarksEngine.prototype = { this._log.debug("All done sharing!"); - // TODO this function also needs to call Atul's js api for setting - // htaccess. + // Call Atul's js api for setting htaccess: + let api = new Sharing.Api( DAV ); + api.shareWithUsers( directory, [username], self.cb ); + let result = yield; self.done(true); }, From a16e4f22e2439833afae2cf9308b3375e000bad1 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Thu, 12 Jun 2008 14:30:39 -0700 Subject: [PATCH 12/16] Fixed the server URL for xmpp connections. --- services/sync/services-sync.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/sync/services-sync.js b/services/sync/services-sync.js index 1c0958640ca8..9941d41c9d6a 100644 --- a/services/sync/services-sync.js +++ b/services/sync/services-sync.js @@ -34,7 +34,7 @@ pref("extensions.weave.log.logger.service.main", "Trace"); pref("extensions.weave.xmpp.enabled", true); pref("extensions.weave.xmpp.server.url", - "http://sm-labs01.mozilla.org:5280/http_poll"); + "http://sm-labs01.mozilla.org:5280/http-poll"); pref("extensions.weave.xmpp.server.realm", "sm-labs01.mozilla.org"); pref("extensions.weave.xmpp.client.name", ""); pref("extensions.weave.xmpp.client.password", ""); From 3f2b6465d86cb23395a433595950814c7f34c96e Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Thu, 12 Jun 2008 17:35:44 -0700 Subject: [PATCH 13/16] Made the initialization of the xmppClient an asynchronous call. This included modifying xmppClient.js so that connect() can be passed a callback function that will get called once the connection has succeeded or failed. For most of our purposes this is probably a better API than what we had before where you call waitForConnection() and it busy-waits until the connection has succeeded or failed. --- services/sync/modules/engines/bookmarks.js | 40 +++++++++++++++------- services/sync/modules/xmpp/xmppClient.js | 20 ++++++++--- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index 7042611d1bcf..d5607c0c308e 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -96,14 +96,14 @@ BookmarksEngine.prototype = { this.__proto__.__proto__._init.call( this, pbeId ); if ( Utils.prefs.getBoolPref( "xmpp.enabled" ) ) { dump( "Starting XMPP client for bookmark engine..." ); - // TODO call startXmppClient asynchronously? - this._startXmppClient(); - // TODO catch errors if connection fails. + this._startXmppClient.async(this); + //this._startXmppClient(); } }, _startXmppClient: function BmkEngine__startXmppClient() { - // TODO this should probably be called asynchronously as it can take a while. + // To be called asynchronously. + let self = yield; // Get serverUrl and realm of the jabber server from preferences: let serverUrl = Utils.prefs.getCharPref( "xmpp.server.url" ); @@ -127,7 +127,7 @@ BookmarksEngine.prototype = { clientPassword, transport, auth ); - let self = this; + let bmkEngine = this; let messageHandler = { handle: function ( messageText, from ) { /* The callback function for incoming xmpp messages. @@ -145,16 +145,25 @@ BookmarksEngine.prototype = { let commandWord = words[0]; let directoryName = words[1]; if ( commandWord == "share" ) { - self._incomingShareOffer( directoryName, from ); + bmkEngine._incomingShareOffer( directoryName, from ); } else if ( commandWord == "stop" ) { - self._incomingShareWithdrawn( directoryName, from ); + bmkEngine._incomingShareWithdrawn( directoryName, from ); } } } this._xmppClient.registerMessageHandler( messageHandler ); - this._xmppClient.connect( realm ); + this._xmppClient.connect( realm, self.cb ); + yield; + if ( this._xmppClient._connectionStatus == this._xmppClient.FAILED ) { + this._log.warn( "Weave can't log in to xmpp server: xmpp disabled." ); + } else if ( this._xmppClient._connectionStatus == this._xmppClient.CONNECTED ) { + this._log.info( "Weave logged into xmpp OK." ); + } + yield; + self.done(); }, + _incomingShareOffer: function BmkEngine__incomingShareOffer( dir, user ) { /* Called when we receive an offer from another user to share a directory. @@ -167,6 +176,7 @@ BookmarksEngine.prototype = { But since we don't have notification in place yet, I'm going to skip right ahead to creating the incoming share. */ + dump( "I was offered the directory " + dir + " from user " + dir ); }, @@ -205,8 +215,8 @@ BookmarksEngine.prototype = { // Create the outgoing share folder on the server // TODO do I need to call these asynchronously? - this._createOutgoingShare.async( this, selectedFolder, username ); - this._updateOutgoingShare.async( this, selectedFolder, username ); + //this._createOutgoingShare.async( this, selectedFolder, username ); + //this._updateOutgoingShare.async( this, selectedFolder, username ); /* Set the annotation on the folder so we know it's an outgoing share: */ @@ -218,9 +228,13 @@ BookmarksEngine.prototype = { // Send an xmpp message to the share-ee if ( this._xmppClient ) { - let msgText = "share " + folderName; - this._xmppClient.sendMessage( username, msgText ); - } + if ( this._xmppClient._connectionStatus == this._xmppClient.CONNECTED ) { + let msgText = "share " + folderName; + this._xmppClient.sendMessage( username, msgText ); + } else { + this._log.info( "XMPP connection not available for share notification." ); + } + } /* LONGTERM TODO: in the future when we allow sharing one folder with many people, the value of the annotation can be a whole list diff --git a/services/sync/modules/xmpp/xmppClient.js b/services/sync/modules/xmpp/xmppClient.js index 2ddc7fdcd28c..054bf28eea81 100644 --- a/services/sync/modules/xmpp/xmppClient.js +++ b/services/sync/modules/xmpp/xmppClient.js @@ -53,6 +53,7 @@ XmppClient.prototype = { this._iqResponders = []; this._nextIqId = 0; this._pendingIqs = {}; + this._callbackOnConnect = null; }, __parser: null, @@ -81,10 +82,17 @@ XmppClient.prototype = { namespace */ }, + _finishConnectionAttempt: function() { + if ( this._callbackOnConnect ) { + this._callbackOnConnect.call(); + } + }, + setError: function( errorText ) { LOG( "Error: " + errorText ); this._error = errorText; this._connectionStatus = this.FAILED; + this._finishConnectionAttempt(); }, onIncomingData: function( messageText ) { @@ -148,7 +156,7 @@ XmppClient.prototype = { this.setError( this._authenticationLayer.getError() ); } else if ( response == this._authenticationLayer.COMPLETION_CODE ){ this._connectionStatus = this.CONNECTED; - LOG( "We be connected!!" ); + this._finishConnectionAttempt(); } else { this._transportLayer.send( response ); } @@ -296,12 +304,16 @@ XmppClient.prototype = { this.setError( errorText ); }, - connect: function( host ) { - // Do the handshake to connect with the server and authenticate. + connect: function( host, callback ) { + /* Do the handshake to connect with the server and authenticate. + callback is optional: if provided, it will be called (with no arguments) + when the connection has either succeeded or failed. */ + if ( callback ) { + this._callbackOnConnect = callback; + } this._transportLayer.connect(); this._transportLayer.setCallbackObject( this ); this._transportLayer.send( this._makeHeaderXml( host ) ); - this._connectionStatus = this.CALLED_SERVER; // Now we wait... the rest of the protocol will be driven by // onIncomingData. From f0482b56e35af88e8f7aba0b516e68e63f2bc069 Mon Sep 17 00:00:00 2001 From: Myk Melez Date: Fri, 13 Jun 2008 13:08:36 -0700 Subject: [PATCH 14/16] use nsIXMLHttpRequest::mozBackgroundRequest instead of DummyAuthProvider to suppress authentication dialogs and ensure XMLHttpRequests succeed even when the window that originated the request goes away --- services/sync/modules/dav.js | 171 +------------------------------ services/sync/modules/service.js | 9 -- 2 files changed, 5 insertions(+), 175 deletions(-) diff --git a/services/sync/modules/dav.js b/services/sync/modules/dav.js index 66463de72bc7..deb5c8627112 100644 --- a/services/sync/modules/dav.js +++ b/services/sync/modules/dav.js @@ -63,7 +63,6 @@ function DAVCollection(baseURL, defaultPrefix) { this.baseURL = baseURL; this.defaultPrefix = defaultPrefix; this._identity = 'DAV:default'; - this._authProvider = new DummyAuthProvider(); this._log = Log4Moz.Service.getLogger("Service.DAV"); this._log.level = Log4Moz.Level[Utils.prefs.getCharPref("log.logger.service.dav")]; @@ -130,9 +129,9 @@ DAVCollection.prototype = { request.addEventListener("load", new Utils.EventListener(self.cb, "load"), false); request.addEventListener("error", new Utils.EventListener(self.cb, "error"), false); request = request.QueryInterface(Ci.nsIXMLHttpRequest); + request.mozBackgroundRequest = true; request.open(op, this._baseURL + path, true); - // Force cache validation let channel = request.channel; channel = channel.QueryInterface(Ci.nsIRequest); @@ -149,15 +148,10 @@ DAVCollection.prototype = { request.setRequestHeader(key, headers[key]); } - this._authProvider._authFailed = false; - request.channel.notificationCallbacks = this._authProvider; - request.send(data); let event = yield; ret = event.target; - if (this._authProvider._authFailed) - this._log.warn("_makeRequest: authentication failed"); if (ret.status < 200 || ret.status >= 300) this._log.warn("_makeRequest: got status " + ret.status); @@ -315,8 +309,7 @@ DAVCollection.prototype = { this.GET("", self.cb); let resp = yield; - if (this._authProvider._authFailed || - resp.status < 200 || resp.status >= 300) { + if (resp.status < 200 || resp.status >= 300) { self.done(false); yield; } @@ -338,8 +331,7 @@ DAVCollection.prototype = { "", self.cb); let resp = yield; - if (this._authProvider._authFailed || - resp.status < 200 || resp.status >= 300) { + if (resp.status < 200 || resp.status >= 300) { self.done(false); yield; } @@ -375,8 +367,7 @@ DAVCollection.prototype = { "", self.cb); let resp = yield; - if (this._authProvider._authFailed || - resp.status < 200 || resp.status >= 300) { + if (resp.status < 200 || resp.status >= 300) { self.done(); yield; } @@ -414,8 +405,7 @@ DAVCollection.prototype = { this.UNLOCK("lock", self.cb); let resp = yield; - if (this._authProvider._authFailed || - resp.status < 200 || resp.status >= 300) { + if (resp.status < 200 || resp.status >= 300) { self.done(false); yield; } @@ -451,154 +441,3 @@ DAVCollection.prototype = { self.done(unlocked); } }; - - -/* - * Auth provider object - * Taken from nsMicrosummaryService.js and massaged slightly - */ - -function DummyAuthProvider() {} -DummyAuthProvider.prototype = { - // Implement notification callback interfaces so we can suppress UI - // and abort loads for bad SSL certs and HTTP authorization requests. - - // Interfaces this component implements. - interfaces: [Ci.nsIBadCertListener, - Ci.nsIAuthPromptProvider, - Ci.nsIAuthPrompt, - Ci.nsIPrompt, - Ci.nsIProgressEventSink, - Ci.nsIInterfaceRequestor, - Ci.nsISupports], - - // Auth requests appear to succeed when we cancel them (since the server - // redirects us to a "you're not authorized" page), so we have to set a flag - // to let the load handler know to treat the load as a failure. - get _authFailed() { return this.__authFailed; }, - set _authFailed(newValue) { return this.__authFailed = newValue; }, - - // nsISupports - - QueryInterface: function DAP_QueryInterface(iid) { - if (!this.interfaces.some( function(v) { return iid.equals(v); } )) - throw Cr.NS_ERROR_NO_INTERFACE; - - // nsIAuthPrompt and nsIPrompt need separate implementations because - // their method signatures conflict. The other interfaces we implement - // within DummyAuthProvider itself. - switch(iid) { - case Ci.nsIAuthPrompt: - return this.authPrompt; - case Ci.nsIPrompt: - return this.prompt; - default: - return this; - } - }, - - // nsIInterfaceRequestor - - getInterface: function DAP_getInterface(iid) { - return this.QueryInterface(iid); - }, - - // nsIBadCertListener - - // Suppress UI and abort secure loads from servers with bad SSL certificates. - - confirmUnknownIssuer: function DAP_confirmUnknownIssuer(socketInfo, cert, certAddType) { - return false; - }, - - confirmMismatchDomain: function DAP_confirmMismatchDomain(socketInfo, targetURL, cert) { - return false; - }, - - confirmCertExpired: function DAP_confirmCertExpired(socketInfo, cert) { - return false; - }, - - notifyCrlNextupdate: function DAP_notifyCrlNextupdate(socketInfo, targetURL, cert) { - }, - - // nsIAuthPromptProvider - - getAuthPrompt: function(aPromptReason, aIID) { - this._authFailed = true; - throw Cr.NS_ERROR_NOT_AVAILABLE; - }, - - // HTTP always requests nsIAuthPromptProvider first, so it never needs - // nsIAuthPrompt, but not all channels use nsIAuthPromptProvider, so we - // implement nsIAuthPrompt too. - - // nsIAuthPrompt - - get authPrompt() { - var resource = this; - return { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]), - prompt: function(dialogTitle, text, passwordRealm, savePassword, defaultText, result) { - resource._authFailed = true; - return false; - }, - promptUsernameAndPassword: function(dialogTitle, text, passwordRealm, savePassword, user, pwd) { - resource._authFailed = true; - return false; - }, - promptPassword: function(dialogTitle, text, passwordRealm, savePassword, pwd) { - resource._authFailed = true; - return false; - } - }; - }, - - // nsIPrompt - - get prompt() { - var resource = this; - return { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]), - alert: function(dialogTitle, text) { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - alertCheck: function(dialogTitle, text, checkMessage, checkValue) { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - confirm: function(dialogTitle, text) { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - confirmCheck: function(dialogTitle, text, checkMessage, checkValue) { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - confirmEx: function(dialogTitle, text, buttonFlags, button0Title, button1Title, button2Title, checkMsg, checkValue) { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - prompt: function(dialogTitle, text, value, checkMsg, checkValue) { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - promptPassword: function(dialogTitle, text, password, checkMsg, checkValue) { - resource._authFailed = true; - return false; - }, - promptUsernameAndPassword: function(dialogTitle, text, username, password, checkMsg, checkValue) { - resource._authFailed = true; - return false; - }, - select: function(dialogTitle, text, count, selectList, outSelection) { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - } - }; - }, - - // nsIProgressEventSink - - onProgress: function DAP_onProgress(aRequest, aContext, - aProgress, aProgressMax) { - }, - - onStatus: function DAP_onStatus(aRequest, aContext, - aStatus, aStatusArg) { - } -}; diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index ed2bbe9b08b8..063a06d02698 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -427,15 +427,6 @@ WeaveSvc.prototype = { _login: function WeaveSync__login(password, passphrase) { let self = yield; - // XmlHttpRequests fail when the window that triggers them goes away - // because of bug 317600, and the first XmlHttpRequest we do happens - // just before the login dialog closes itself (for logins prompted by - // that dialog), so it triggers the bug. To work around it, we pause - // here and then continue after a 0ms timeout. - let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - timer.initWithCallback({ notify: self.cb }, 0, Ci.nsITimer.TYPE_ONE_SHOT); - yield; - // cache password & passphrase // if null, we'll try to get them from the pw manager below ID.get('WeaveID').setTempPassword(password); From 0fb90163fb8928a3c127c01294ff9a57d137008b Mon Sep 17 00:00:00 2001 From: Atul Varma Date: Fri, 13 Jun 2008 15:39:06 -0700 Subject: [PATCH 15/16] Fixed an 'outstanding callbacks' warning and simplified the code a tiny bit. --- services/sync/modules/dav.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/sync/modules/dav.js b/services/sync/modules/dav.js index deb5c8627112..5f17c1dcba2a 100644 --- a/services/sync/modules/dav.js +++ b/services/sync/modules/dav.js @@ -123,12 +123,12 @@ DAVCollection.prototype = { path = this._defaultPrefix + path; - let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(); - request = request.QueryInterface(Ci.nsIDOMEventTarget); + let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); - request.addEventListener("load", new Utils.EventListener(self.cb, "load"), false); - request.addEventListener("error", new Utils.EventListener(self.cb, "error"), false); - request = request.QueryInterface(Ci.nsIXMLHttpRequest); + let xhrCb = self.cb; + + request.onload = new Utils.EventListener(xhrCb, "load"); + request.onerror = new Utils.EventListener(xhrCb, "error"); request.mozBackgroundRequest = true; request.open(op, this._baseURL + path, true); From 351b7b4c82470ddbc095eface3ea57beb129b729 Mon Sep 17 00:00:00 2001 From: "jonathandicarlo@jonathan-dicarlos-macbook-pro.local" Date: Fri, 13 Jun 2008 16:20:43 -0700 Subject: [PATCH 16/16] Fixed some minor bugs -- the name of the incoming shared folder is parsed correctly, and xmppClient now catches bounce errors that were previously parsed as messages. --- services/sync/modules/engines/bookmarks.js | 7 ++++--- services/sync/modules/service.js | 1 + services/sync/modules/xmpp/xmppClient.js | 8 +++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index d5607c0c308e..7bcd19d42fa4 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -143,7 +143,7 @@ BookmarksEngine.prototype = { */ let words = messageText.split(" "); let commandWord = words[0]; - let directoryName = words[1]; + let directoryName = words.slice(1).join(" "); if ( commandWord == "share" ) { bmkEngine._incomingShareOffer( directoryName, from ); } else if ( commandWord == "stop" ) { @@ -163,7 +163,6 @@ BookmarksEngine.prototype = { self.done(); }, - _incomingShareOffer: function BmkEngine__incomingShareOffer( dir, user ) { /* Called when we receive an offer from another user to share a directory. @@ -220,15 +219,17 @@ BookmarksEngine.prototype = { /* Set the annotation on the folder so we know it's an outgoing share: */ + dump( "I'm in _share.\n" ); let folderItemId = selectedFolder.node.itemId; let folderName = selectedFolder.getAttribute( "label" ); ans.setItemAnnotation(folderItemId, OUTGOING_SHARED_ANNO, username, 0, ans.EXPIRE_NEVER); // TODO: does this clobber existing annotations? - + dump( "I set the annotation...\n" ); // Send an xmpp message to the share-ee if ( this._xmppClient ) { if ( this._xmppClient._connectionStatus == this._xmppClient.CONNECTED ) { + dump( "Gonna send notification...\n" ); let msgText = "share " + folderName; this._xmppClient.sendMessage( username, msgText ); } else { diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index 3da7770de3b3..70f426c81b9a 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -673,6 +673,7 @@ WeaveSvc.prototype = { "share-bookmarks" will be sent out to any observers who are listening for it. As far as I know, there aren't currently any listeners for "share-bookmarks" but we'll send it out just in case. */ + dump( "This fails with an Exception: cannot aquire internal lock.\n" ); this._lock(this._notify(messageName, this._shareData, dataType, diff --git a/services/sync/modules/xmpp/xmppClient.js b/services/sync/modules/xmpp/xmppClient.js index 054bf28eea81..782abedc8238 100644 --- a/services/sync/modules/xmpp/xmppClient.js +++ b/services/sync/modules/xmpp/xmppClient.js @@ -134,17 +134,19 @@ XmppClient.prototype = { } // Message is parseable, now look for message-level errors. - var rootElem = responseDOM.documentElement; - var errors = rootElem.getElementsByTagName( "stream:error" ); if ( errors.length > 0 ) { this.setError( errors[0].firstChild.nodeName ); return; } + errors = rootElem.getElementsByTagName( "error" ); + if ( errors.length > 0 ) { + this.setError( errors[0].firstChild.nodeName ); + return; + } // Stream is valid. - // Detect and handle mid-authentication steps. if ( this._connectionStatus == this.CALLED_SERVER ) { // skip TLS, go straight to SALS. (encryption should be negotiated