merge upstream changes

This commit is contained in:
Dan Mills 2008-06-15 13:42:10 +09:00
commit a8ad7d2804
6 changed files with 307 additions and 238 deletions

View File

@ -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")];
@ -124,16 +123,15 @@ 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);
let cb = self.cb;
request.addEventListener("load", new Utils.EventListener(cb, "load"), false);
request.addEventListener("error", new Utils.EventListener(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);
// Force cache validation
let channel = request.channel;
channel = channel.QueryInterface(Ci.nsIRequest);
@ -150,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);
@ -316,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);
return;
}
@ -339,8 +331,7 @@ DAVCollection.prototype = {
"</D:propfind>", 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;
}
@ -376,8 +367,7 @@ DAVCollection.prototype = {
"</D:lockinfo>", self.cb);
let resp = yield;
if (this._authProvider._authFailed ||
resp.status < 200 || resp.status >= 300)
if (resp.status < 200 || resp.status >= 300)
return;
let tokens = Utils.xpath(resp.responseXML, '//D:locktoken/D:href');
@ -413,8 +403,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;
}
@ -450,154 +439,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) {
}
};

View File

@ -570,13 +570,16 @@ 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.
/* 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);
@ -586,7 +589,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);
},

View File

@ -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 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");
@ -14,6 +55,12 @@ 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;
function BookmarksEngine(pbeId) {
@ -45,16 +92,177 @@ BookmarksEngine.prototype = {
return this.__tracker;
},
syncMounts: function BmkEngine_syncMounts(onComplete) {
this._syncMounts.async(this, onComplete);
_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.async(this);
//this._startXmppClient();
}
},
_syncMounts: function BmkEngine__syncMounts() {
_startXmppClient: function BmkEngine__startXmppClient() {
// To be called asynchronously.
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++) {
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);
@ -63,13 +271,11 @@ 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(folder, 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;
@ -78,6 +284,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
@ -107,25 +314,31 @@ BookmarksEngine.prototype = {
ret = yield;
Utils.ensureStatus(ret.status, "Could not upload keyring file.");
this._createShare(guid, username, username);
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);
},
_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.
*/
_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...*/
},
/* TODO it appears that this just creates the folder and puts the
annotation on it; the mechanics of sharing must be done when syncing?
_stopOutgoingShare: function BmkEngine__stopOutgoingShare( guid, username ) {
/* TODO implement this... */
},
Or has that not been done yet at all?
Do we have to create a new Mount?
_createIncomingShare: function BookmarkEngine__createShare(guid, id, title) {
/* 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);
@ -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 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 {
@ -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 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;

View File

@ -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);
@ -546,10 +537,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;
}
}
},
@ -595,11 +582,6 @@ WeaveSvc.prototype = {
// overloaded, we'll contribute to the problem by trying to sync
// repeatedly at the maximum rate.
this._syncThresholds[engine.name] = INITIAL_THRESHOLD;
if (engine.name == "bookmarks") { // FIXME
Engines.get("bookmarks").syncMounts(self.cb);
yield;
}
}
else {
this._log.debug(engine.name + " score " + score +
@ -677,23 +659,27 @@ 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. */
dump( "This fails with an Exception: cannot aquire internal lock.\n" );
this._lock(this._notify(messageName,
this._shareData,
dataType,
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);

View File

@ -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 ) {
@ -126,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
@ -148,7 +158,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 +306,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.

View File

@ -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", "");