Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

equalized branch to upstream

  • Loading branch information...
commit 6c8f126d1c87a0a15ae3fc1fc3e19142bddc6844 1 parent 7afd300
@flosse flosse authored
View
4 archive/README.markdown
@@ -9,7 +9,3 @@ strophe.archive.js is a plugin to provide Message Archiving
- describe usage
- write specs
-
-## Authors
-
-- [radsaq](https://github.com/radsaq)
View
238 caps/strophe.caps.js
@@ -0,0 +1,238 @@
+/**
+ * Entity Capabilities (XEP-0115)
+ *
+ * Depends on disco plugin.
+ *
+ * See: http://xmpp.org/extensions/xep-0115.html
+ *
+ * Authors:
+ * - Michael Weibel <michael.weibel@gmail.com>
+ *
+ * Copyright:
+ * - Michael Weibel <michael.weibel@gmail.com>
+ */
+
+ Strophe.addConnectionPlugin('caps', {
+ /** Constant: HASH
+ * Hash used
+ *
+ * Currently only sha-1 is supported.
+ */
+ HASH: 'sha-1',
+ /** Variable: node
+ * Client which is being used.
+ *
+ * Can be overwritten as soon as Strophe has been initialized.
+ */
+ node: 'http://strophe.im/strophejs/',
+ /** PrivateVariable: _ver
+ * Own generated version string
+ */
+ _ver: '',
+ /** PrivateVariable: _connection
+ * Strophe connection
+ */
+ _connection: null,
+ /** PrivateVariable: _knownCapabilities
+ * A hashtable containing version-strings and their capabilities, serialized
+ * as string.
+ *
+ * TODO: Maybe those caps shouldn't be serialized.
+ */
+ _knownCapabilities: {},
+ /** PrivateVariable: _jidVerIndex
+ * A hashtable containing jids and their versions for better lookup of capabilities.
+ */
+ _jidVerIndex: {},
+
+ /** Function: init
+ * Initialize plugin:
+ * - Add caps namespace
+ * - Add caps feature to disco plugin
+ * - Add handler for caps stanzas
+ *
+ * Parameters:
+ * (Strophe.Connection) conn - Strophe connection
+ */
+ init: function(conn) {
+ this._connection = conn;
+
+ Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps');
+
+ if (!this._connection.disco) {
+ throw "Caps plugin requires the disco plugin to be installed.";
+ }
+
+ this._connection.disco.addFeature(Strophe.NS.CAPS);
+ this._connection.addHandler(this._delegateCapabilities.bind(this), Strophe.NS.CAPS);
+ },
+
+ /** Function: generateCapsAttrs
+ * Returns the attributes for generating the "c"-stanza containing the own version
+ *
+ * Returns:
+ * (Object) - attributes
+ */
+ generateCapsAttrs: function() {
+ return {
+ 'xmlns': Strophe.NS.CAPS,
+ 'hash': this.HASH,
+ 'node': this.node,
+ 'ver': this.generateVer()
+ };
+ },
+
+ /** Function: generateVer
+ * Returns the base64 encoded version string (encoded itself with sha1)
+ *
+ * Returns:
+ * (String) - version
+ */
+ generateVer: function() {
+ if (this._ver !== "") {
+ return this._ver;
+ }
+
+ var ver = "",
+ identities = this._connection.disco._identities.sort(this._sortIdentities),
+ identitiesLen = identities.length,
+ features = this._connection.disco._features.sort(),
+ featuresLen = features.length;
+ for(var i = 0; i < identitiesLen; i++) {
+ var curIdent = identities[i];
+ ver += curIdent.category + "/" + curIdent.type + "/" + curIdent.lang + "/" + curIdent.name + "<";
+ }
+ for(var i = 0; i < featuresLen; i++) {
+ ver += features[i] + '<';
+ }
+
+ this._ver = b64_sha1(ver);
+ return this._ver;
+ },
+
+ /** Function: getCapabilitiesByJid
+ * Returns serialized capabilities of a jid (if available).
+ * Otherwise null.
+ *
+ * Parameters:
+ * (String) jid - Jabber id
+ *
+ * Returns:
+ * (String|null) - capabilities, serialized; or null when not available.
+ */
+ getCapabilitiesByJid: function(jid) {
+ if (this._jidVerIndex[jid]) {
+ return this._knownCapabilities[this._jidVerIndex[jid]];
+ }
+ return null;
+ },
+
+ /** PrivateFunction: _delegateCapabilities
+ * Checks if the version has already been saved.
+ * If yes: do nothing.
+ * If no: Request capabilities
+ *
+ * Parameters:
+ * (Strophe.Builder) stanza - Stanza
+ *
+ * Returns:
+ * (Boolean)
+ */
+ _delegateCapabilities: function(stanza) {
+ var from = stanza.getAttribute('from'),
+ c = stanza.querySelector('c'),
+ ver = c.getAttribute('ver'),
+ node = c.getAttribute('node');
+ if (!this._knownCapabilities[ver]) {
+ return this._requestCapabilities(from, node, ver);
+ }
+ if (!this._jidVerIndex[from] || !this._jidVerIndex[from] !== ver) {
+ this._jidVerIndex[from] = ver;
+ }
+ return true;
+ },
+
+ /** PrivateFunction: _requestCapabilities
+ * Requests capabilities from the one which sent the caps-info stanza.
+ * This is done using disco info.
+ *
+ * Additionally, it registers a handler for handling the reply.
+ *
+ * Parameters:
+ * (String) to - Destination jid
+ * (String) node - Node attribute of the caps-stanza
+ * (String) ver - Version of the caps-stanza
+ *
+ * Returns:
+ * (Boolean) - true
+ */
+ _requestCapabilities: function(to, node, ver) {
+ if (to !== this._connection.jid) {
+ var id = this._connection.disco.info(to, node + '#' + ver);
+ this._connection.addHandler(this._handleDiscoInfoReply.bind(this), Strophe.NS.DISCO_INFO, 'iq', 'result', id, to);
+ }
+ return true;
+ },
+
+ /** PrivateFunction: _handleDiscoInfoReply
+ * Parses the disco info reply and adds the version & it's capabilities to the _knownCapabilities variable.
+ * Additionally, it adds the jid & the version to the _jidVerIndex variable for a better lookup.
+ *
+ * Parameters:
+ * (Strophe.Builder) stanza - Disco info stanza
+ *
+ * Returns:
+ * (Boolean) - false, to automatically remove the handler.
+ */
+ _handleDiscoInfoReply: function(stanza) {
+ var query = stanza.querySelector('query'),
+ node = query.getAttribute('node').split('#'),
+ ver = node[1],
+ from = stanza.getAttribute('from');
+ if (!this._knownCapabilities[ver]) {
+ var childNodes = query.childNodes,
+ childNodesLen = childNodes.length;
+ this._knownCapabilities[ver] = [];
+ for(var i = 0; i < childNodesLen; i++) {
+ var node = childNodes[i];
+ this._knownCapabilities[ver].push({name: node.nodeName, attributes: node.attributes});
+ }
+ this._jidVerIndex[from] = ver;
+ } else if (!this._jidVerIndex[from] || !this._jidVerIndex[from] !== ver) {
+ this._jidVerIndex[from] = ver;
+ }
+ return false;
+ },
+
+ /** PrivateFunction: _sortIdentities
+ * Sorts two identities according the sorting requirements in XEP-0115.
+ *
+ * Parameters:
+ * (Object) a - Identity a
+ * (Object) b - Identity b
+ *
+ * Returns:
+ * (Integer) - 1, 0 or -1; according to which one's greater.
+ */
+ _sortIdentities: function(a, b) {
+ if (a.category > b.category) {
+ return 1;
+ }
+ if (a.category < b.category) {
+ return -1;
+ }
+ if (a.type > b.type) {
+ return 1;
+ }
+ if (a.type < b.type) {
+ return -1;
+ }
+ if (a.lang > b.lang) {
+ return 1;
+ }
+ if (a.lang < b.lang) {
+ return -1;
+ }
+ return 0;
+ }
+ });
View
17 dataforms/jsTestDriver.conf
@@ -1,17 +0,0 @@
-server: http://localhost:9876
-
-load:
-
-# load jasmine scripts
-- "lib/jasmine/jasmine.js"
-- "lib/jasmineAdapter/src/*.js"
-
-# load libs
-- "lib/strophe.min.js"
-- "lib/jquery-1.6.4.min.js"
-
-# load src
-- "src/strophe.x.js"
-
-# load tests
-- "spec/strophe.x.js"
View
217 dataforms/strophe.dataforms.js
@@ -1,217 +0,0 @@
-/*
- Copyright 2010, François de Metz <francois@2metz.fr>
-*/
-/**
- *
- */
-Strophe.Field = function(field) {
- /**
- * @type String
- */
- this.type = field.getAttribute("type");
- /**
- * @type String
- */
- this.variable = field.getAttribute("var");
- /**
- * @type String
- */
- this.label = field.getAttribute("label");
- /**
- * @type Boolean
- */
- this.required = this._isRequired(field);
- /**
- * @type String
- */
- this.desc = this._getDesc(field);
- /**
- * @type String
- */
- this.value = null;
- /**
- * @type Array
- */
- this.values = [];
-
- this.media = null;
-
- this._fillValues(field);
- this._parseMedia(field);
- /**
- * @type Array
- */
- this.options = this._parseOptions(field);
- if (this.type != "fixed" && this.variable == null) {
- throw "must have a var attribute";
- }
-};
-Strophe.Field.prototype = {
- _isRequired: function(field) {
- var required = field.getElementsByTagName("required");
- if (required.length == 1) {
- return true;
- }
- return false;
- },
-
- _getDesc: function(field) {
- var desc = field.getElementsByTagName("desc");
- if (desc.length == 1) {
- return desc.item(0).textContent;
- }
- return null;
- },
-
- _fillValues: function(field)
- {
- var values = field.getElementsByTagName("value");
- if (values.length > 1)
- {
- var authorized = ["list-multi", "jid-multi",
- "text-multi", "hidden"];
- if (authorized.indexOf(this.type) == -1)
- {
- throw "cannot have multiple value";
- }
- for (var i = 0; i < values.length; i++)
- {
- this.values.push(values.item(i).textContent);
- }
- }
- else if (values.length == 1)
- {
- this.value = values.item(0).textContent;
- }
- },
-
- _parseMedia: function(field)
- {
- var media = field.getElementsByTagNameNS(Strophe.NS.DATA_MEDIA, 'media');
- if (media.length == 1)
- {
- this.media = {
- height : media.item(0).getAttribute('height'),
- width : media.item(0).getAttribute('width'),
- uri : []
- };
- var uris = media.item(0).getElementsByTagName('uri');
- for (var i = 0; i < uris.length; i++)
- {
- if (!uris.item(i).hasAttribute('type'))
- {
- throw "uri element must have an type attribute";
- }
- if (uris.item(i).textContent == "")
- {
- throw "uri element must have a value";
- }
- this.media.uri.push({
- type : uris.item(i).getAttribute('type'),
- value : uris.item(i).textContent
- });
- }
- }
- },
-
- _parseOptions: function(field)
- {
- var options = field.getElementsByTagName("option");
- if (options.length == 0) {
- return [];
- }
- var authorized = ["list-single", "list-multi"];
- if (authorized.indexOf(this.type) == -1) {
- throw "cannot have option";
- }
- var o = [];
- for (var i = 0; i < options.length; i++) {
- var value = this._getValue(options.item(i));
- var label = options.item(i).getAttribute("label") || value;
- o.push({value: value, label: label});
- }
- return o;
- },
-
- _getValue : function(node) {
- var value = node.getElementsByTagName("value");
- if (value.length > 1 || value.length == 0) {
- throw "must have only one value";
- }
- return value.item(0).textContent;
- }
-};
-
-/**
- * Data Forms strophe plugin
- * http://xmpp.org/extensions/xep-0004.html Data Forms
- * http://xmpp.org/extensions/xep-0221.html Data Forms Media Element
- * TODO: implement http://xmpp.org/extensions/xep-0122.html Data Forms Validation
- * TODO: implement http://xmpp.org/extensions/xep-0141.html Data Forms Layout
- */
-Strophe.addConnectionPlugin('dataforms',
-{
- /** Function: init
- * Plugin init
- *
- * Parameters:
- * (Strophe.Connection) conn - Strophe connection
- */
- init : function(conn)
- {
- Strophe.addNamespace('DATA', 'jabber:x:data');
- Strophe.addNamespace('DATA_MEDIA', 'urn:xmpp:media-element');
- if (conn.disco)
- {
- conn.disco.addFeature(Strophe.NS.DATA);
- }
- },
- /** Function: parse
- * Parse form
- * TODO: multiple title
- * TODO: multiple instructions
- * TODO: reported and item element
- * Parameters:
- * (DOMElement) form
- *
- */
- parse: function(form)
- {
- return {
- type : form.getAttribute("type"),
- title : this._getTitle(form),
- instructions : this._getInstructions(form),
- fields : this._parseFields(form)
- };
- },
-
- _getTitle: function(form)
- {
- var title = form.getElementsByTagName("title");
- if (title.length > 0)
- {
- return title.item(0).textContent;
- }
- return null;
- },
-
- _getInstructions: function(form)
- {
- var instructions = form.getElementsByTagName("instructions");
- if (instructions.length > 0)
- {
- return instructions.item(0).textContent;
- }
- return null;
- },
-
- _parseFields: function(form)
- {
- var fields = form.getElementsByTagName("field");
- var f = [];
- for (var i = 0; i < fields.length; i++) {
- f.push(new Strophe.Field(fields.item(i)));
- }
- return f;
- }
-});
View
0  disco/.monitor
No changes.
View
10 pep/strophe.pep.js
@@ -1,15 +1,12 @@
(function() {
+
Strophe.addConnectionPlugin('pep', (function() {
var conn, init, publish, subscribe, unsubscribe;
conn = null;
init = function(c) {
conn = c;
- if (conn.caps === void 0) {
- throw new Error("caps plugin required!");
- }
- if (conn.pubsub === void 0) {
- throw new Error("pubsub plugin required!");
- }
+ if (conn.caps === void 0) throw new Error("caps plugin required!");
+ if (conn.pubsub === void 0) throw new Error("pubsub plugin required!");
};
subscribe = function(node, handler) {
conn.caps.addFeature(node);
@@ -32,4 +29,5 @@
unsubscribe: unsubscribe
};
})());
+
}).call(this);
View
7 register/README.markdown
@@ -5,7 +5,8 @@ A Strophe Plugin for In-Band Registration.
## Usage
-Just link the register plugin below the strophe library in your HTML head section:
+Just link the register plugin below the strophe library in your HTML head
+section:
``` html
<head>
@@ -41,7 +42,3 @@ After that you're logged in with a fresh smelling jid.
## ToDo
- write specs
-
-## Authors
-
-- [dodo](https://github.com/dodo)
View
196 register/strophe.register.js
@@ -85,12 +85,43 @@ Strophe.addConnectionPlugin('register', {
* should almost always be set to 1 (the default).
*/
connect: function (domain, callback, wait, hold) {
+ var that = this._connection;
this.instructions = "";
this.fields = {};
- this._connection.domain = domain;
- this._connection.connect(null, null, callback, wait, hold,
- /* authentication */ false,
- this._register_cb.bind(this));
+ this.authentication = {};
+ this.registered = false;
+ this.enabled = false;
+
+ that.connect_callback = callback;
+ that.connected = false;
+ that.authenticated = false;
+ that.disconnecting = false;
+ that.errors = 0;
+
+ that.domain = domain || that.domain;
+ that.wait = wait || that.wait;
+ that.hold = hold || that.hold;
+
+ // build the body tag
+ var body = that._buildBody().attrs({
+ to: that.domain,
+ "xml:lang": "en",
+ wait: that.wait,
+ hold: that.hold,
+ content: "text/xml; charset=utf-8",
+ ver: "1.6",
+ "xmpp:version": "1.0",
+ "xmlns:xmpp": Strophe.NS.BOSH
+ });
+
+ that._changeConnectStatus(Strophe.Status.CONNECTING, null);
+
+ that._requests.push(
+ new Strophe.Request(body.tree(),
+ that._onRequestStateChange.bind(
+ that, this._register_cb.bind(this)),
+ body.tree().getAttribute("rid")));
+ that._throttledRequestHandler();
},
/** PrivateFunction: _register_cb
@@ -107,15 +138,79 @@ Strophe.addConnectionPlugin('register', {
var that = this._connection;
Strophe.info("_register_cb was called");
- that._connect_cb(req, this._register_cb.bind(this));
+ that.connected = true;
+
+ var bodyWrap = req.getResponse();
+ if (!bodyWrap) { return; }
+
+ if (that.xmlInput !== Strophe.Connection.prototype.xmlInput) {
+ that.xmlInput(bodyWrap);
+ }
+ if (that.rawInput !== Strophe.Connection.prototype.rawInput) {
+ that.rawInput(Strophe.serialize(bodyWrap));
+ }
+
+ var typ = bodyWrap.getAttribute("type");
+ var cond, conflict;
+ if (typ !== null && typ == "terminate") {
+ // an error occurred
+ cond = bodyWrap.getAttribute("condition");
+ conflict = bodyWrap.getElementsByTagName("conflict");
+ if (cond !== null) {
+ if (cond == "remote-stream-error" && conflict.length > 0) {
+ cond = "conflict";
+ }
+ that._changeConnectStatus(Strophe.Status.CONNFAIL, cond);
+ } else {
+ that._changeConnectStatus(Strophe.Status.CONNFAIL, "unknown");
+ }
+ return;
+ }
+
+ // check to make sure we don't overwrite these if _connect_cb is
+ // called multiple times in the case of missing stream:features
+ if (!that.sid) {
+ that.sid = bodyWrap.getAttribute("sid");
+ }
+ if (!that.stream_id) {
+ that.stream_id = bodyWrap.getAttribute("authid");
+ }
- var bodyWrap, register;
- bodyWrap = req.getResponse();
+ var wind = bodyWrap.getAttribute('requests');
+ if (wind) { that.window = parseInt(wind, 10); }
+ var hold = bodyWrap.getAttribute('hold');
+ if (hold) { that.hold = parseInt(hold, 10); }
+ var wait = bodyWrap.getAttribute('wait');
+ if (wait) { that.wait = parseInt(wait, 10); }
+
+
+ var register, mechanisms;
register = bodyWrap.getElementsByTagName("register");
mechanisms = bodyWrap.getElementsByTagName("mechanism");
-
- if (register.length === 0 && mechanisms.length === 0)
+ if (register.length === 0 && mechanisms.length === 0) {
+ // we didn't get stream:features yet, so we need wait for it
+ // by sending a blank poll request
+ var body = that._buildBody();
+ that._requests.push(
+ new Strophe.Request(body.tree(),
+ that._onRequestStateChange.bind(
+ that, this._register_cb.bind(this)),
+ body.tree().getAttribute("rid")));
+ that._throttledRequestHandler();
return;
+ }
+
+ var i, mech;
+ for (i = 0; i < mechanisms.length; i++) {
+ mech = Strophe.getText(mechanisms[i]);
+ if (mech == 'DIGEST-MD5') {
+ this.authentication.sasl_digest_md5 = true;
+ } else if (mech == 'PLAIN') {
+ this.authentication.sasl_plain = true;
+ } else if (mech == 'ANONYMOUS') {
+ this.authentication.sasl_anonymous = true;
+ }
+ }
if (register.length === 0) {
that._changeConnectStatus(Strophe.Status.REGIFAIL, null);
@@ -245,4 +340,87 @@ Strophe.addConnectionPlugin('register', {
}
return false;
},
+
+ /** Function: authenticate
+ * Login with newly registered account.
+ *
+ * This is just a helper function to authenticate with the new account of
+ * the successful registration. This is recommended to do in the
+ * user supplied callback when receiving Strophe.Status.REGISTERED.
+ * It is also possible to do it on Strophe.Status.SBMTFAIL when
+ * connection.register.registered is true under the circumstances that an
+ * already existing account with the appendant password was supplied.
+ */
+ authenticate: function () {
+ var auth_str, hashed_auth_str, that = this._connection;
+
+ if (Strophe.getNodeFromJid(that.jid) === null &&
+ this.authentication.sasl_anonymous) {
+ that._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
+ that._sasl_success_handler = that._addSysHandler(
+ that._sasl_success_cb.bind(that), null,
+ "success", null, null);
+ that._sasl_failure_handler = that._addSysHandler(
+ that._sasl_failure_cb.bind(that), null,
+ "failure", null, null);
+
+ that.send($build("auth", {
+ xmlns: Strophe.NS.SASL,
+ mechanism: "ANONYMOUS"
+ }).tree());
+ } else if (Strophe.getNodeFromJid(that.jid) === null) {
+ // we don't have a node, which is required for non-anonymous
+ // client connections
+ that._changeConnectStatus(Strophe.Status.CONNFAIL,
+ 'x-strophe-bad-non-anon-jid');
+ that.disconnect();
+ } else if (this.authentication.sasl_digest_md5) {
+ that._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
+ that._sasl_challenge_handler = that._addSysHandler(
+ that._sasl_challenge1_cb.bind(that), null,
+ "challenge", null, null);
+ that._sasl_failure_handler = that._addSysHandler(
+ that._sasl_failure_cb.bind(that), null,
+ "failure", null, null);
+
+ that.send($build("auth", {
+ xmlns: Strophe.NS.SASL,
+ mechanism: "DIGEST-MD5"
+ }).tree());
+ } else if (this.authentication.sasl_plain) {
+ // Build the plain auth string (barejid null
+ // username null password) and base 64 encoded.
+ auth_str = Strophe.getBareJidFromJid(that.jid);
+ auth_str = auth_str + "\u0000";
+ auth_str = auth_str + Strophe.getNodeFromJid(that.jid);
+ auth_str = auth_str + "\u0000";
+ auth_str = auth_str + that.pass;
+
+ that._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
+ that._sasl_success_handler = that._addSysHandler(
+ that._sasl_success_cb.bind(that), null,
+ "success", null, null);
+ that._sasl_failure_handler = that._addSysHandler(
+ that._sasl_failure_cb.bind(that), null,
+ "failure", null, null);
+
+ hashed_auth_str = Base64.encode(auth_str);
+ that.send($build("auth", {
+ xmlns: Strophe.NS.SASL,
+ mechanism: "PLAIN"
+ }).t(hashed_auth_str).tree());
+ } else {
+ that._changeConnectStatus(Strophe.Status.AUTHENTICATING, null);
+ that._addSysHandler(that._auth1_cb.bind(that), null, null,
+ null, "_auth_1");
+
+ that.send($iq({
+ type: "get",
+ to: that.domain,
+ id: "_auth_1"
+ }).c("query", {
+ xmlns: Strophe.NS.AUTH
+ }).c("username", {}).t(Strophe.getNodeFromJid(that.jid)).tree());
+ }
+ },
});
Please sign in to comment.
Something went wrong with that request. Please try again.