Adds advertisement of XEP-0115 capabilities to MUC presence.
This commit is contained in:
parent
f0a278cad5
commit
8c64d3192b
|
@ -11,6 +11,7 @@ var config = {
|
||||||
// useIPv6: true, // ipv6 support. use at your own risk
|
// useIPv6: true, // ipv6 support. use at your own risk
|
||||||
useNicks: false,
|
useNicks: false,
|
||||||
bosh: '//jitsi-meet.example.com/http-bind', // FIXME: use xep-0156 for that
|
bosh: '//jitsi-meet.example.com/http-bind', // FIXME: use xep-0156 for that
|
||||||
|
clientNode: 'http://jitsi.org/jitsimeet', // The name of client node advertised in XEP-0115 'c' stanza
|
||||||
desktopSharing: 'ext', // Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable.
|
desktopSharing: 'ext', // Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable.
|
||||||
chromeExtensionId: 'diibjkoicjeejcmhdnailmkgecihlobk', // Id of desktop streamer Chrome extension
|
chromeExtensionId: 'diibjkoicjeejcmhdnailmkgecihlobk', // Id of desktop streamer Chrome extension
|
||||||
desktopSharingSources: ['screen', 'window'],
|
desktopSharingSources: ['screen', 'window'],
|
||||||
|
|
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
||||||
|
* in FIPS PUB 180-1
|
||||||
|
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
||||||
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
||||||
|
* Distributed under the BSD License
|
||||||
|
* See http://pajhome.org.uk/crypt/md5 for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configurable variables. You may need to tweak these to be compatible with
|
||||||
|
* the server-side, but the defaults work in most cases.
|
||||||
|
*/
|
||||||
|
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
|
||||||
|
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
|
||||||
|
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These are the functions you'll usually want to call
|
||||||
|
* They take string arguments and return either hex or base-64 encoded strings
|
||||||
|
*/
|
||||||
|
function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
|
||||||
|
function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
|
||||||
|
function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
|
||||||
|
function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
|
||||||
|
function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
|
||||||
|
function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform a simple self-test to see if the VM is working
|
||||||
|
*/
|
||||||
|
function sha1_vm_test()
|
||||||
|
{
|
||||||
|
return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the SHA-1 of an array of big-endian words, and a bit length
|
||||||
|
*/
|
||||||
|
function core_sha1(x, len)
|
||||||
|
{
|
||||||
|
/* append padding */
|
||||||
|
x[len >> 5] |= 0x80 << (24 - len % 32);
|
||||||
|
x[((len + 64 >> 9) << 4) + 15] = len;
|
||||||
|
|
||||||
|
var w = Array(80);
|
||||||
|
var a = 1732584193;
|
||||||
|
var b = -271733879;
|
||||||
|
var c = -1732584194;
|
||||||
|
var d = 271733878;
|
||||||
|
var e = -1009589776;
|
||||||
|
|
||||||
|
for(var i = 0; i < x.length; i += 16)
|
||||||
|
{
|
||||||
|
var olda = a;
|
||||||
|
var oldb = b;
|
||||||
|
var oldc = c;
|
||||||
|
var oldd = d;
|
||||||
|
var olde = e;
|
||||||
|
|
||||||
|
for(var j = 0; j < 80; j++)
|
||||||
|
{
|
||||||
|
if(j < 16) w[j] = x[i + j];
|
||||||
|
else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
|
||||||
|
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
|
||||||
|
safe_add(safe_add(e, w[j]), sha1_kt(j)));
|
||||||
|
e = d;
|
||||||
|
d = c;
|
||||||
|
c = rol(b, 30);
|
||||||
|
b = a;
|
||||||
|
a = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = safe_add(a, olda);
|
||||||
|
b = safe_add(b, oldb);
|
||||||
|
c = safe_add(c, oldc);
|
||||||
|
d = safe_add(d, oldd);
|
||||||
|
e = safe_add(e, olde);
|
||||||
|
}
|
||||||
|
return Array(a, b, c, d, e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform the appropriate triplet combination function for the current
|
||||||
|
* iteration
|
||||||
|
*/
|
||||||
|
function sha1_ft(t, b, c, d)
|
||||||
|
{
|
||||||
|
if(t < 20) return (b & c) | ((~b) & d);
|
||||||
|
if(t < 40) return b ^ c ^ d;
|
||||||
|
if(t < 60) return (b & c) | (b & d) | (c & d);
|
||||||
|
return b ^ c ^ d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the appropriate additive constant for the current iteration
|
||||||
|
*/
|
||||||
|
function sha1_kt(t)
|
||||||
|
{
|
||||||
|
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
|
||||||
|
(t < 60) ? -1894007588 : -899497514;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the HMAC-SHA1 of a key and some data
|
||||||
|
*/
|
||||||
|
function core_hmac_sha1(key, data)
|
||||||
|
{
|
||||||
|
var bkey = str2binb(key);
|
||||||
|
if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
|
||||||
|
|
||||||
|
var ipad = Array(16), opad = Array(16);
|
||||||
|
for(var i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
ipad[i] = bkey[i] ^ 0x36363636;
|
||||||
|
opad[i] = bkey[i] ^ 0x5C5C5C5C;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
|
||||||
|
return core_sha1(opad.concat(hash), 512 + 160);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
||||||
|
* to work around bugs in some JS interpreters.
|
||||||
|
*/
|
||||||
|
function safe_add(x, y)
|
||||||
|
{
|
||||||
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
||||||
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||||||
|
return (msw << 16) | (lsw & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bitwise rotate a 32-bit number to the left.
|
||||||
|
*/
|
||||||
|
function rol(num, cnt)
|
||||||
|
{
|
||||||
|
return (num << cnt) | (num >>> (32 - cnt));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an 8-bit or 16-bit string to an array of big-endian words
|
||||||
|
* In 8-bit function, characters >255 have their hi-byte silently ignored.
|
||||||
|
*/
|
||||||
|
function str2binb(str)
|
||||||
|
{
|
||||||
|
var bin = Array();
|
||||||
|
var mask = (1 << chrsz) - 1;
|
||||||
|
for(var i = 0; i < str.length * chrsz; i += chrsz)
|
||||||
|
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
|
||||||
|
return bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of big-endian words to a string
|
||||||
|
*/
|
||||||
|
function binb2str(bin)
|
||||||
|
{
|
||||||
|
var str = "";
|
||||||
|
var mask = (1 << chrsz) - 1;
|
||||||
|
for(var i = 0; i < bin.length * 32; i += chrsz)
|
||||||
|
str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of big-endian words to a hex string.
|
||||||
|
*/
|
||||||
|
function binb2hex(binarray)
|
||||||
|
{
|
||||||
|
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||||
|
var str = "";
|
||||||
|
for(var i = 0; i < binarray.length * 4; i++)
|
||||||
|
{
|
||||||
|
str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
|
||||||
|
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert an array of big-endian words to a base-64 string
|
||||||
|
*/
|
||||||
|
function binb2b64(binarray)
|
||||||
|
{
|
||||||
|
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
var str = "";
|
||||||
|
for(var i = 0; i < binarray.length * 4; i += 3)
|
||||||
|
{
|
||||||
|
var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
|
||||||
|
| (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
|
||||||
|
| ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
|
||||||
|
for(var j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
|
||||||
|
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
|
@ -0,0 +1,240 @@
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
} else {
|
||||||
|
this._jidVerIndex[from] = 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;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
Copyright 2010, François de Metz <francois@2metz.fr>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disco Strophe Plugin
|
||||||
|
* Implement http://xmpp.org/extensions/xep-0030.html
|
||||||
|
* TODO: manage node hierarchies, and node on info request
|
||||||
|
*/
|
||||||
|
Strophe.addConnectionPlugin('disco',
|
||||||
|
{
|
||||||
|
_connection: null,
|
||||||
|
_identities : [],
|
||||||
|
_features : [],
|
||||||
|
_items : [],
|
||||||
|
/** Function: init
|
||||||
|
* Plugin init
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* (Strophe.Connection) conn - Strophe connection
|
||||||
|
*/
|
||||||
|
init: function(conn)
|
||||||
|
{
|
||||||
|
this._connection = conn;
|
||||||
|
this._identities = [];
|
||||||
|
this._features = [];
|
||||||
|
this._items = [];
|
||||||
|
// disco info
|
||||||
|
conn.addHandler(this._onDiscoInfo.bind(this), Strophe.NS.DISCO_INFO, 'iq', 'get', null, null);
|
||||||
|
// disco items
|
||||||
|
conn.addHandler(this._onDiscoItems.bind(this), Strophe.NS.DISCO_ITEMS, 'iq', 'get', null, null);
|
||||||
|
},
|
||||||
|
/** Function: addIdentity
|
||||||
|
* See http://xmpp.org/registrar/disco-categories.html
|
||||||
|
* Parameters:
|
||||||
|
* (String) category - category of identity (like client, automation, etc ...)
|
||||||
|
* (String) type - type of identity (like pc, web, bot , etc ...)
|
||||||
|
* (String) name - name of identity in natural language
|
||||||
|
* (String) lang - lang of name parameter
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Boolean
|
||||||
|
*/
|
||||||
|
addIdentity: function(category, type, name, lang)
|
||||||
|
{
|
||||||
|
for (var i=0; i<this._identities.length; i++)
|
||||||
|
{
|
||||||
|
if (this._identities[i].category == category &&
|
||||||
|
this._identities[i].type == type &&
|
||||||
|
this._identities[i].name == name &&
|
||||||
|
this._identities[i].lang == lang)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._identities.push({category: category, type: type, name: name, lang: lang});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
/** Function: addFeature
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* (String) var_name - feature name (like jabber:iq:version)
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* boolean
|
||||||
|
*/
|
||||||
|
addFeature: function(var_name)
|
||||||
|
{
|
||||||
|
for (var i=0; i<this._features.length; i++)
|
||||||
|
{
|
||||||
|
if (this._features[i] == var_name)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this._features.push(var_name);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
/** Function: removeFeature
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* (String) var_name - feature name (like jabber:iq:version)
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* boolean
|
||||||
|
*/
|
||||||
|
removeFeature: function(var_name)
|
||||||
|
{
|
||||||
|
for (var i=0; i<this._features.length; i++)
|
||||||
|
{
|
||||||
|
if (this._features[i] === var_name){
|
||||||
|
this._features.splice(i,1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
/** Function: addItem
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* (String) jid
|
||||||
|
* (String) name
|
||||||
|
* (String) node
|
||||||
|
* (Function) call_back
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* boolean
|
||||||
|
*/
|
||||||
|
addItem: function(jid, name, node, call_back)
|
||||||
|
{
|
||||||
|
if (node && !call_back)
|
||||||
|
return false;
|
||||||
|
this._items.push({jid: jid, name: name, node: node, call_back: call_back});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
/** Function: info
|
||||||
|
* Info query
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* (Function) call_back
|
||||||
|
* (String) jid
|
||||||
|
* (String) node
|
||||||
|
*/
|
||||||
|
info: function(jid, node, success, error, timeout)
|
||||||
|
{
|
||||||
|
var attrs = {xmlns: Strophe.NS.DISCO_INFO};
|
||||||
|
if (node)
|
||||||
|
attrs.node = node;
|
||||||
|
|
||||||
|
var info = $iq({from:this._connection.jid,
|
||||||
|
to:jid, type:'get'}).c('query', attrs);
|
||||||
|
this._connection.sendIQ(info, success, error, timeout);
|
||||||
|
},
|
||||||
|
/** Function: items
|
||||||
|
* Items query
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* (Function) call_back
|
||||||
|
* (String) jid
|
||||||
|
* (String) node
|
||||||
|
*/
|
||||||
|
items: function(jid, node, success, error, timeout)
|
||||||
|
{
|
||||||
|
var attrs = {xmlns: Strophe.NS.DISCO_ITEMS};
|
||||||
|
if (node)
|
||||||
|
attrs.node = node;
|
||||||
|
|
||||||
|
var items = $iq({from:this._connection.jid,
|
||||||
|
to:jid, type:'get'}).c('query', attrs);
|
||||||
|
this._connection.sendIQ(items, success, error, timeout);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** PrivateFunction: _buildIQResult
|
||||||
|
*/
|
||||||
|
_buildIQResult: function(stanza, query_attrs)
|
||||||
|
{
|
||||||
|
var id = stanza.getAttribute('id');
|
||||||
|
var from = stanza.getAttribute('from');
|
||||||
|
var iqresult = $iq({type: 'result', id: id});
|
||||||
|
|
||||||
|
if (from !== null) {
|
||||||
|
iqresult.attrs({to: from});
|
||||||
|
}
|
||||||
|
|
||||||
|
return iqresult.c('query', query_attrs);
|
||||||
|
},
|
||||||
|
|
||||||
|
/** PrivateFunction: _onDiscoInfo
|
||||||
|
* Called when receive info request
|
||||||
|
*/
|
||||||
|
_onDiscoInfo: function(stanza)
|
||||||
|
{
|
||||||
|
var node = stanza.getElementsByTagName('query')[0].getAttribute('node');
|
||||||
|
var attrs = {xmlns: Strophe.NS.DISCO_INFO};
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
attrs.node = node;
|
||||||
|
}
|
||||||
|
var iqresult = this._buildIQResult(stanza, attrs);
|
||||||
|
for (var i=0; i<this._identities.length; i++)
|
||||||
|
{
|
||||||
|
var attrs = {category: this._identities[i].category,
|
||||||
|
type : this._identities[i].type};
|
||||||
|
if (this._identities[i].name)
|
||||||
|
attrs.name = this._identities[i].name;
|
||||||
|
if (this._identities[i].lang)
|
||||||
|
attrs['xml:lang'] = this._identities[i].lang;
|
||||||
|
iqresult.c('identity', attrs).up();
|
||||||
|
}
|
||||||
|
for (var i=0; i<this._features.length; i++)
|
||||||
|
{
|
||||||
|
iqresult.c('feature', {'var':this._features[i]}).up();
|
||||||
|
}
|
||||||
|
this._connection.send(iqresult.tree());
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
/** PrivateFunction: _onDiscoItems
|
||||||
|
* Called when receive items request
|
||||||
|
*/
|
||||||
|
_onDiscoItems: function(stanza)
|
||||||
|
{
|
||||||
|
var query_attrs = {xmlns: Strophe.NS.DISCO_ITEMS};
|
||||||
|
var node = stanza.getElementsByTagName('query')[0].getAttribute('node');
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
query_attrs.node = node;
|
||||||
|
var items = [];
|
||||||
|
for (var i = 0; i < this._items.length; i++)
|
||||||
|
{
|
||||||
|
if (this._items[i].node == node)
|
||||||
|
{
|
||||||
|
items = this._items[i].call_back(stanza);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var items = this._items;
|
||||||
|
}
|
||||||
|
var iqresult = this._buildIQResult(stanza, query_attrs);
|
||||||
|
for (var i = 0; i < items.length; i++)
|
||||||
|
{
|
||||||
|
var attrs = {jid: items[i].jid};
|
||||||
|
if (items[i].name)
|
||||||
|
attrs.name = items[i].name;
|
||||||
|
if (items[i].node)
|
||||||
|
attrs.node = items[i].node;
|
||||||
|
iqresult.c('item', attrs).up();
|
||||||
|
}
|
||||||
|
this._connection.send(iqresult.tree());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
|
@ -13,6 +13,8 @@
|
||||||
<script src="simulcast.js?v=1"></script><!-- simulcast handling -->
|
<script src="simulcast.js?v=1"></script><!-- simulcast handling -->
|
||||||
<script src="libs/strophe/strophe.jingle.adapter.js?v=1"></script><!-- strophe.jingle bundles -->
|
<script src="libs/strophe/strophe.jingle.adapter.js?v=1"></script><!-- strophe.jingle bundles -->
|
||||||
<script src="libs/strophe/strophe.min.js?v=1"></script>
|
<script src="libs/strophe/strophe.min.js?v=1"></script>
|
||||||
|
<script src="libs/strophe/strophe.disco.min.js?v=1"></script>
|
||||||
|
<script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
|
||||||
<script src="libs/strophe/strophe.jingle.js?v=1"></script>
|
<script src="libs/strophe/strophe.jingle.js?v=1"></script>
|
||||||
<script src="libs/strophe/strophe.jingle.sdp.js?v=2"></script>
|
<script src="libs/strophe/strophe.jingle.sdp.js?v=2"></script>
|
||||||
<script src="libs/strophe/strophe.jingle.sdp.util.js?v=1"></script>
|
<script src="libs/strophe/strophe.jingle.sdp.util.js?v=1"></script>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Strophe.addConnectionPlugin("caps",{HASH:"sha-1",node:"http://strophe.im/strophejs/",_ver:"",_connection:null,_knownCapabilities:{},_jidVerIndex:{},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)},generateCapsAttrs:function(){return{xmlns:Strophe.NS.CAPS,hash:this.HASH,node:this.node,ver:this.generateVer()}},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},getCapabilitiesByJid:function(jid){if(this._jidVerIndex[jid]){return this._knownCapabilities[this._jidVerIndex[jid]]}return null},_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)}else{this._jidVerIndex[from]=ver}if(!this._jidVerIndex[from]||!this._jidVerIndex[from]!==ver){this._jidVerIndex[from]=ver}return 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},_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},_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}});
|
|
@ -0,0 +1 @@
|
||||||
|
Strophe.addConnectionPlugin("disco",{_connection:null,_identities:[],_features:[],_items:[],init:function(conn){this._connection=conn;this._identities=[];this._features=[];this._items=[];conn.addHandler(this._onDiscoInfo.bind(this),Strophe.NS.DISCO_INFO,"iq","get",null,null);conn.addHandler(this._onDiscoItems.bind(this),Strophe.NS.DISCO_ITEMS,"iq","get",null,null)},addIdentity:function(category,type,name,lang){for(var i=0;i<this._identities.length;i++){if(this._identities[i].category==category&&this._identities[i].type==type&&this._identities[i].name==name&&this._identities[i].lang==lang){return false}}this._identities.push({category:category,type:type,name:name,lang:lang});return true},addFeature:function(var_name){for(var i=0;i<this._features.length;i++){if(this._features[i]==var_name){return false}}this._features.push(var_name);return true},removeFeature:function(var_name){for(var i=0;i<this._features.length;i++){if(this._features[i]===var_name){this._features.splice(i,1);return true}}return false},addItem:function(jid,name,node,call_back){if(node&&!call_back){return false}this._items.push({jid:jid,name:name,node:node,call_back:call_back});return true},info:function(jid,node,success,error,timeout){var attrs={xmlns:Strophe.NS.DISCO_INFO};if(node){attrs.node=node}var info=$iq({from:this._connection.jid,to:jid,type:"get"}).c("query",attrs);this._connection.sendIQ(info,success,error,timeout)},items:function(jid,node,success,error,timeout){var attrs={xmlns:Strophe.NS.DISCO_ITEMS};if(node){attrs.node=node}var items=$iq({from:this._connection.jid,to:jid,type:"get"}).c("query",attrs);this._connection.sendIQ(items,success,error,timeout)},_buildIQResult:function(stanza,query_attrs){var id=stanza.getAttribute("id");var from=stanza.getAttribute("from");var iqresult=$iq({type:"result",id:id});if(from!==null){iqresult.attrs({to:from})}return iqresult.c("query",query_attrs)},_onDiscoInfo:function(stanza){var node=stanza.getElementsByTagName("query")[0].getAttribute("node");var attrs={xmlns:Strophe.NS.DISCO_INFO};if(node){attrs.node=node}var iqresult=this._buildIQResult(stanza,attrs);for(var i=0;i<this._identities.length;i++){var attrs={category:this._identities[i].category,type:this._identities[i].type};if(this._identities[i].name){attrs.name=this._identities[i].name}if(this._identities[i].lang){attrs["xml:lang"]=this._identities[i].lang}iqresult.c("identity",attrs).up()}for(var i=0;i<this._features.length;i++){iqresult.c("feature",{"var":this._features[i]}).up()}this._connection.send(iqresult.tree());return true},_onDiscoItems:function(stanza){var query_attrs={xmlns:Strophe.NS.DISCO_ITEMS};var node=stanza.getElementsByTagName("query")[0].getAttribute("node");if(node){query_attrs.node=node;var items=[];for(var i=0;i<this._items.length;i++){if(this._items[i].node==node){items=this._items[i].call_back(stanza);break}}}else{var items=this._items}var iqresult=this._buildIQResult(stanza,query_attrs);for(var i=0;i<items.length;i++){var attrs={jid:items[i].jid};if(items[i].name){attrs.name=items[i].name}if(items[i].node){attrs.node=items[i].node}iqresult.c("item",attrs).up()}this._connection.send(iqresult.tree());return true}});
|
6
muc.js
6
muc.js
|
@ -291,6 +291,12 @@ Strophe.addConnectionPlugin('emuc', {
|
||||||
|
|
||||||
pres.up();
|
pres.up();
|
||||||
|
|
||||||
|
// Send XEP-0115 'c' stanza that contains our capabilities info
|
||||||
|
if (connection.caps) {
|
||||||
|
connection.caps.node = config.clientNode;
|
||||||
|
pres.c('c', connection.caps.generateCapsAttrs()).up();
|
||||||
|
}
|
||||||
|
|
||||||
if(this.presMap['bridgeIsDown']) {
|
if(this.presMap['bridgeIsDown']) {
|
||||||
pres.c('bridgeIsDown').up();
|
pres.c('bridgeIsDown').up();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue