This commit is contained in:
Dan Mills 2008-06-15 13:42:10 +09:00
Родитель b9e5b182df 2092466c5f
Коммит ba5e8762d2
6 изменённых файлов: 307 добавлений и 238 удалений

Просмотреть файл

@ -63,7 +63,6 @@ function DAVCollection(baseURL, defaultPrefix) {
this.baseURL = baseURL; this.baseURL = baseURL;
this.defaultPrefix = defaultPrefix; this.defaultPrefix = defaultPrefix;
this._identity = 'DAV:default'; this._identity = 'DAV:default';
this._authProvider = new DummyAuthProvider();
this._log = Log4Moz.Service.getLogger("Service.DAV"); this._log = Log4Moz.Service.getLogger("Service.DAV");
this._log.level = this._log.level =
Log4Moz.Level[Utils.prefs.getCharPref("log.logger.service.dav")]; Log4Moz.Level[Utils.prefs.getCharPref("log.logger.service.dav")];
@ -124,16 +123,15 @@ DAVCollection.prototype = {
path = this._defaultPrefix + path; path = this._defaultPrefix + path;
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(); let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
request = request.QueryInterface(Ci.nsIDOMEventTarget);
let cb = self.cb; let xhrCb = self.cb;
request.addEventListener("load", new Utils.EventListener(cb, "load"), false);
request.addEventListener("error", new Utils.EventListener(cb, "error"), false); request.onload = new Utils.EventListener(xhrCb, "load");
request = request.QueryInterface(Ci.nsIXMLHttpRequest); request.onerror = new Utils.EventListener(xhrCb, "error");
request.mozBackgroundRequest = true;
request.open(op, this._baseURL + path, true); request.open(op, this._baseURL + path, true);
// Force cache validation // Force cache validation
let channel = request.channel; let channel = request.channel;
channel = channel.QueryInterface(Ci.nsIRequest); channel = channel.QueryInterface(Ci.nsIRequest);
@ -150,15 +148,10 @@ DAVCollection.prototype = {
request.setRequestHeader(key, headers[key]); request.setRequestHeader(key, headers[key]);
} }
this._authProvider._authFailed = false;
request.channel.notificationCallbacks = this._authProvider;
request.send(data); request.send(data);
let event = yield; let event = yield;
ret = event.target; ret = event.target;
if (this._authProvider._authFailed)
this._log.warn("_makeRequest: authentication failed");
if (ret.status < 200 || ret.status >= 300) if (ret.status < 200 || ret.status >= 300)
this._log.warn("_makeRequest: got status " + ret.status); this._log.warn("_makeRequest: got status " + ret.status);
@ -316,8 +309,7 @@ DAVCollection.prototype = {
this.GET("", self.cb); this.GET("", self.cb);
let resp = yield; let resp = yield;
if (this._authProvider._authFailed || if (resp.status < 200 || resp.status >= 300) {
resp.status < 200 || resp.status >= 300) {
self.done(false); self.done(false);
return; return;
} }
@ -339,8 +331,7 @@ DAVCollection.prototype = {
"</D:propfind>", self.cb); "</D:propfind>", self.cb);
let resp = yield; let resp = yield;
if (this._authProvider._authFailed || if (resp.status < 200 || resp.status >= 300) {
resp.status < 200 || resp.status >= 300) {
self.done(false); self.done(false);
yield; yield;
} }
@ -376,8 +367,7 @@ DAVCollection.prototype = {
"</D:lockinfo>", self.cb); "</D:lockinfo>", self.cb);
let resp = yield; let resp = yield;
if (this._authProvider._authFailed || if (resp.status < 200 || resp.status >= 300)
resp.status < 200 || resp.status >= 300)
return; return;
let tokens = Utils.xpath(resp.responseXML, '//D:locktoken/D:href'); let tokens = Utils.xpath(resp.responseXML, '//D:locktoken/D:href');
@ -413,8 +403,7 @@ DAVCollection.prototype = {
this.UNLOCK("lock", self.cb); this.UNLOCK("lock", self.cb);
let resp = yield; let resp = yield;
if (this._authProvider._authFailed || if (resp.status < 200 || resp.status >= 300) {
resp.status < 200 || resp.status >= 300) {
self.done(false); self.done(false);
yield; yield;
} }
@ -450,154 +439,3 @@ DAVCollection.prototype = {
self.done(unlocked); 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) {
}
};

Просмотреть файл

@ -570,13 +570,16 @@ Engine.prototype = {
}, },
_share: function Engine__share(guid, username) { _share: function Engine__share(guid, username) {
let self = yield;
/* This should be overridden by the engine subclass for each datatype. /* This should be overridden by the engine subclass for each datatype.
Implementation should share the data node identified by guid, Implementation should share the data node identified by guid,
and all its children, if any, with the user identified by username. */ and all its children, if any, with the user identified by username. */
return; self.done();
}, },
// 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) { sync: function Engine_sync(onComplete) {
return this._sync.async(this, onComplete); return this._sync.async(this, onComplete);
@ -586,7 +589,7 @@ Engine.prototype = {
return this._share.async(this, onComplete, guid, username); 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); this._notify("reset-server", this._resetServer).async(this, onComplete);
}, },

Просмотреть файл

@ -1,9 +1,50 @@
/* ***** 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 <thunder@mozilla.com>
* Jono DiCarlo <jdicarlo@mozilla.org>
*
* 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 EXPORTED_SYMBOLS = ['BookmarksEngine'];
const Cc = Components.classes; const Cc = Components.classes;
const Ci = Components.interfaces; const Ci = Components.interfaces;
const Cu = Components.utils; 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/log4moz.js");
Cu.import("resource://weave/dav.js"); Cu.import("resource://weave/dav.js");
Cu.import("resource://weave/util.js"); Cu.import("resource://weave/util.js");
@ -14,6 +55,12 @@ Cu.import("resource://weave/syncCores.js");
Cu.import("resource://weave/stores.js"); Cu.import("resource://weave/stores.js");
Cu.import("resource://weave/trackers.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; Function.prototype.async = Async.sugar;
function BookmarksEngine(pbeId) { function BookmarksEngine(pbeId) {
@ -45,16 +92,177 @@ BookmarksEngine.prototype = {
return this.__tracker; return this.__tracker;
}, },
syncMounts: function BmkEngine_syncMounts(onComplete) { _init: function BmkEngine__init( pbeId ) {
this._syncMounts.async(this, onComplete); this.__proto__.__proto__._init.call( this, pbeId );
if ( Utils.prefs.getBoolPref( "xmpp.enabled" ) ) {
dump( "Starting XMPP client for bookmark engine..." );
this._startXmppClient.async(this);
//this._startXmppClient();
}
}, },
_syncMounts: function BmkEngine__syncMounts() {
_startXmppClient: function BmkEngine__startXmppClient() {
// To be called asynchronously.
let self = yield; let self = yield;
let mounts = this._store.findMounts();
// Get serverUrl and realm of the jabber server from preferences:
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
// 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.getCharPref( "xmpp.client.name" );
let clientPassword = Utils.prefs.getCharPref( "xmpp.client.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 bmkEngine = this;
let messageHandler = {
handle: function ( messageText, from ) {
/* The callback function for incoming xmpp messages.
We expect message text to be either:
"share <dir>"
(sender offers to share directory dir with us)
or "stop <dir>"
(sender has stopped sharing directory dir with us.)
or "accept <dir>"
(sharee has accepted our offer to share our dir.)
or "decline <dir>"
(sharee has declined our offer to share our dir.)
*/
let words = messageText.split(" ");
let commandWord = words[0];
let directoryName = words.slice(1).join(" ");
if ( commandWord == "share" ) {
bmkEngine._incomingShareOffer( directoryName, from );
} else if ( commandWord == "stop" ) {
bmkEngine._incomingShareWithdrawn( directoryName, from );
}
}
}
this._xmppClient.registerMessageHandler( messageHandler );
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.
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.
*/
dump( "I was offered the directory " + dir + " from user " + dir );
},
_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.updateAllIncomingShares(self.cb);
yield;
self.done();
},
_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 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: */
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 {
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
of usernames instead of just one. */
dump( "Bookmark engine shared " +folderName + " with " + username );
ret = true;
self.done( ret );
},
updateAllIncomingShares: function BmkEngine_updateAllIncoming(onComplete) {
this._updateAllIncomingShares.async(this, onComplete);
},
_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
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.findIncomingShares();
for (i = 0; i < mounts.length; i++) { for (i = 0; i < mounts.length; i++) {
try { try {
this._syncOneMount.async(this, self.cb, mounts[i]); this._updateIncomingShare.async(this, self.cb, mounts[i]);
yield; yield;
} catch (e) { } catch (e) {
this._log.warn("Could not sync shared folder from " + mounts[i].userid); this._log.warn("Could not sync shared folder from " + mounts[i].userid);
@ -63,13 +271,11 @@ BookmarksEngine.prototype = {
} }
}, },
// TODO modify this as neccessary since I just moved it from the engine _createOutgoingShare: function BmkEngine__createOutgoing(folder, username) {
// superclass into BookmarkEngine.
_share: function BookmarkEngine__share(guid, username) {
let self = yield; let self = yield;
let prefix = DAV.defaultPrefix; 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); this._getSymKey.async(this, self.cb);
yield; yield;
@ -78,6 +284,7 @@ BookmarksEngine.prototype = {
DAV.GET(this.keysFile, self.cb); DAV.GET(this.keysFile, self.cb);
let ret = yield; let ret = yield;
Utils.ensureStatus(ret.status, "Could not get keys file."); 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); let keys = this._json.decode(ret.responseText);
// get the other user's pubkey // get the other user's pubkey
@ -107,25 +314,31 @@ BookmarksEngine.prototype = {
ret = yield; ret = yield;
Utils.ensureStatus(ret.status, "Could not upload keyring file."); Utils.ensureStatus(ret.status, "Could not upload keyring file.");
this._createShare(guid, username, username);
this._log.debug("All done sharing!"); this._log.debug("All done sharing!");
// 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); self.done(true);
}, },
_createShare: function BookmarkEngine__createShare(guid, id, title) { _updateOutgoingShare: function BmkEngine__updateOutgoing(guid, username) {
/* the bookmark item identified by guid, and the whole subtree under it, /* TODO this needs to have the logic to break the shared bookmark
must be copied out from the main file into a separate file which is subtree out of the store and put it in a separate file...*/
put into the new directory and encrypted with the key in the keychain. },
id is the userid of the user we're sharing with.
*/
/* TODO it appears that this just creates the folder and puts the _stopOutgoingShare: function BmkEngine__stopOutgoingShare( guid, username ) {
annotation on it; the mechanics of sharing must be done when syncing? /* TODO implement this... */
},
Or has that not been done yet at all? _createIncomingShare: function BookmarkEngine__createShare(guid, id, title) {
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"]. let bms = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService); getService(Ci.nsINavBookmarksService);
@ -160,19 +373,23 @@ 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) { _updateIncomingShare: function BmkEngine__updateIncomingShare(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. */
let self = yield; let self = yield;
let user = mountData.userid; let user = mountData.userid;
let prefix = DAV.defaultPrefix; let prefix = DAV.defaultPrefix;
let serverURL = Utils.prefs.getCharPref("serverURL"); let serverURL = Utils.prefs.getCharPref("serverURL");
let snap = new SnapshotStore(); let snap = new SnapshotStore();
// TODO this is obviously what we want.
this._log.debug("Syncing shared folder from user " + user); this._log.debug("Syncing shared folder from user " + user);
try { try {
@ -738,11 +955,15 @@ 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 = []; 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++) { 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)); ret.push(this._wrapMount(this._getNode(a[i]), id));
} }
return ret; return ret;

Просмотреть файл

@ -427,15 +427,6 @@ WeaveSvc.prototype = {
_login: function WeaveSync__login(password, passphrase) { _login: function WeaveSync__login(password, passphrase) {
let self = yield; 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 // cache password & passphrase
// if null, we'll try to get them from the pw manager below // if null, we'll try to get them from the pw manager below
ID.get('WeaveID').setTempPassword(password); ID.get('WeaveID').setTempPassword(password);
@ -546,10 +537,6 @@ WeaveSvc.prototype = {
this._notify(engines[i].name + "-engine:sync", this._notify(engines[i].name + "-engine:sync",
this._syncEngine, engines[i]).async(this, self.cb); this._syncEngine, engines[i]).async(this, self.cb);
yield; yield;
if (engines[i].name == "bookmarks") { // FIXME
Engines.get("bookmarks").syncMounts(self.cb);
yield;
}
} }
}, },
@ -595,11 +582,6 @@ WeaveSvc.prototype = {
// overloaded, we'll contribute to the problem by trying to sync // overloaded, we'll contribute to the problem by trying to sync
// repeatedly at the maximum rate. // repeatedly at the maximum rate.
this._syncThresholds[engine.name] = INITIAL_THRESHOLD; this._syncThresholds[engine.name] = INITIAL_THRESHOLD;
if (engine.name == "bookmarks") { // FIXME
Engines.get("bookmarks").syncMounts(self.cb);
yield;
}
} }
else { else {
this._log.debug(engine.name + " score " + score + this._log.debug(engine.name + " score " + score +
@ -677,23 +659,27 @@ WeaveSvc.prototype = {
Implementation, as well as the interpretation of what 'guid' means, Implementation, as well as the interpretation of what 'guid' means,
is left up to the engine for the specific dataType. */ is left up to the engine for the specific dataType. */
// TODO who is listening for the share-bookmarks message?
let messageName = "share-" + dataType; let messageName = "share-" + dataType;
// so for instance, if dataType is "bookmarks" then a message /* so for instance, if dataType is "bookmarks" then a message
// "share-bookmarks" will be sent out to any observers who are listening "share-bookmarks" will be sent out to any observers who are listening
// for it. 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._lock(this._notify(messageName,
this._shareData, this._shareData,
dataType, dataType,
guid, guid,
username)).async(this, onComplete); username)).async(this, onComplete);
}, },
_shareBookmarks: function WeaveSync__shareBookmarks(dataType,
guid, _shareData: function WeaveSync__shareData(dataType,
username) { guid,
username) {
let self = yield; let self = yield;
if (Engines.get(dataType).enabled) if (!Engines.get(dataType).enabled) {
this._log.warn( "Can't share disabled data type: " + dataType );
return; return;
}
Engines.get(dataType).share(self.cb, guid, username); Engines.get(dataType).share(self.cb, guid, username);
let ret = yield; let ret = yield;
self.done(ret); self.done(ret);

Просмотреть файл

@ -53,6 +53,7 @@ XmppClient.prototype = {
this._iqResponders = []; this._iqResponders = [];
this._nextIqId = 0; this._nextIqId = 0;
this._pendingIqs = {}; this._pendingIqs = {};
this._callbackOnConnect = null;
}, },
__parser: null, __parser: null,
@ -81,10 +82,17 @@ XmppClient.prototype = {
namespace */ namespace */
}, },
_finishConnectionAttempt: function() {
if ( this._callbackOnConnect ) {
this._callbackOnConnect.call();
}
},
setError: function( errorText ) { setError: function( errorText ) {
LOG( "Error: " + errorText ); LOG( "Error: " + errorText );
this._error = errorText; this._error = errorText;
this._connectionStatus = this.FAILED; this._connectionStatus = this.FAILED;
this._finishConnectionAttempt();
}, },
onIncomingData: function( messageText ) { onIncomingData: function( messageText ) {
@ -126,17 +134,19 @@ XmppClient.prototype = {
} }
// Message is parseable, now look for message-level errors. // Message is parseable, now look for message-level errors.
var rootElem = responseDOM.documentElement; var rootElem = responseDOM.documentElement;
var errors = rootElem.getElementsByTagName( "stream:error" ); var errors = rootElem.getElementsByTagName( "stream:error" );
if ( errors.length > 0 ) { if ( errors.length > 0 ) {
this.setError( errors[0].firstChild.nodeName ); this.setError( errors[0].firstChild.nodeName );
return; return;
} }
errors = rootElem.getElementsByTagName( "error" );
if ( errors.length > 0 ) {
this.setError( errors[0].firstChild.nodeName );
return;
}
// Stream is valid. // Stream is valid.
// Detect and handle mid-authentication steps. // Detect and handle mid-authentication steps.
if ( this._connectionStatus == this.CALLED_SERVER ) { if ( this._connectionStatus == this.CALLED_SERVER ) {
// skip TLS, go straight to SALS. (encryption should be negotiated // skip TLS, go straight to SALS. (encryption should be negotiated
@ -148,7 +158,7 @@ XmppClient.prototype = {
this.setError( this._authenticationLayer.getError() ); this.setError( this._authenticationLayer.getError() );
} else if ( response == this._authenticationLayer.COMPLETION_CODE ){ } else if ( response == this._authenticationLayer.COMPLETION_CODE ){
this._connectionStatus = this.CONNECTED; this._connectionStatus = this.CONNECTED;
LOG( "We be connected!!" ); this._finishConnectionAttempt();
} else { } else {
this._transportLayer.send( response ); this._transportLayer.send( response );
} }
@ -296,12 +306,16 @@ XmppClient.prototype = {
this.setError( errorText ); this.setError( errorText );
}, },
connect: function( host ) { connect: function( host, callback ) {
// Do the handshake to connect with the server and authenticate. /* 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.connect();
this._transportLayer.setCallbackObject( this ); this._transportLayer.setCallbackObject( this );
this._transportLayer.send( this._makeHeaderXml( host ) ); this._transportLayer.send( this._makeHeaderXml( host ) );
this._connectionStatus = this.CALLED_SERVER; this._connectionStatus = this.CALLED_SERVER;
// Now we wait... the rest of the protocol will be driven by // Now we wait... the rest of the protocol will be driven by
// onIncomingData. // onIncomingData.

Просмотреть файл

@ -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.dav", "Debug");
pref("extensions.weave.log.logger.service.engine", "Debug"); pref("extensions.weave.log.logger.service.engine", "Debug");
pref("extensions.weave.log.logger.service.main", "Trace"); 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", "");