-
Notifications
You must be signed in to change notification settings - Fork 110
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3aa2523
commit e61fad8
Showing
6 changed files
with
1,920 additions
and
1,583 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,240 +1,103 @@ | ||
/** | ||
* Entity Capabilities (XEP-0115) | ||
* | ||
* Depends on disco plugin. | ||
* | ||
* See: http://xmpp.org/extensions/xep-0115.html | ||
* | ||
* Authors: | ||
* - Michael Weibel <[email protected]> | ||
* | ||
* Copyright: | ||
* - Michael Weibel <[email protected]> | ||
*/ | ||
/* | ||
# This plugin is distributed under the terms of the MIT licence. | ||
# Please see the LICENCE file for details. | ||
# | ||
# Copyright (c) | ||
# Markus Kohlhase, 2011 | ||
# Adán Sánchez de Pedro Crespo, 2014 | ||
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: {}, | ||
# File: strophe.caps.js | ||
# A Strophe plugin for ( http://xmpp.org/extensions/xep-0115.html ) | ||
/** 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; | ||
# NOTE: This plugin has following dependencies: | ||
# | ||
# - strophe.disco.js (by François de Metz) | ||
# - sha1.js | ||
*/ | ||
|
||
Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps'); | ||
|
||
if (!this._connection.disco) { | ||
throw "Caps plugin requires the disco plugin to be installed."; | ||
} | ||
Strophe.addConnectionPlugin('caps', | ||
{ | ||
_connection: null, | ||
|
||
init: function (conn) { | ||
this._conn = conn; | ||
Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps'); | ||
if (this._conn.disco === void 0) throw new Error('disco plugin required!'); | ||
if (b64_sha1 === void 0) throw new Error('SHA-1 library required!'); | ||
this._conn.disco.addFeature(Strophe.NS.CAPS); | ||
this._conn.disco.addFeature(Strophe.NS.DISCO_INFO); | ||
this._conn.disco.addFeature(Strophe.NS.DISCO_ITEMS); | ||
if (this._conn.disco._identities.length === 0) { | ||
return this._conn.disco.addIdentity('client', Lungo.Core.environment().isMobile ? 'phone' : 'pc', 'http://loqui.im', ''); | ||
} | ||
}, | ||
|
||
addFeature: function(feature) { | ||
return this._conn.disco.addFeature(feature); | ||
}, | ||
|
||
removeFeature: function(feature) { | ||
return this._conn.disco.removeFeature(feature); | ||
}, | ||
|
||
sendPres: function() { | ||
return this._conn.send($pres().cnode(this.createCapsNode().tree())); | ||
}, | ||
|
||
createCapsNode: function() { | ||
var node; | ||
if (this._conn.disco._identities.length > 0) { | ||
node = this._conn.disco._identities[0].name || ""; | ||
} else { | ||
node = dummyId.name; | ||
} | ||
return $build("c", { | ||
xmlns: Strophe.NS.CAPS, | ||
hash: "sha-1", | ||
node: node, | ||
ver: this.generateVerificationString() | ||
}); | ||
}, | ||
|
||
propertySort: function(array, property) { | ||
return array.sort(function(a, b) { | ||
if (a[property] > b[property]) { | ||
return -1; | ||
} else { | ||
return 1; | ||
} | ||
}); | ||
}, | ||
|
||
generateVerificationString: function() { | ||
var S, features, i, id, ids, k, key, ns, _i, _j, _k, _len, _len2, _len3, _ref, _ref2; | ||
ids = []; | ||
_ref = this._conn.disco._identities; | ||
for (_i = 0, _len = _ref.length; _i < _len; _i++) { | ||
i = _ref[_i]; | ||
ids.push(i); | ||
} | ||
features = []; | ||
_ref2 = this._conn.disco._features; | ||
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { | ||
k = _ref2[_j]; | ||
features.push(k); | ||
} | ||
S = ""; | ||
this.propertySort(ids, "category"); | ||
this.propertySort(ids, "type"); | ||
this.propertySort(ids, "lang"); | ||
for (key in ids) { | ||
id = ids[key]; | ||
S += "" + id.category + "/" + id.type + "/" + id.lang + "/" + id.name + "<"; | ||
} | ||
features.sort(); | ||
for (_k = 0, _len3 = features.length; _k < _len3; _k++) { | ||
ns = features[_k]; | ||
S += "" + ns + "<"; | ||
} | ||
return "" + (b64_sha1(S)) + "="; | ||
} | ||
|
||
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; | ||
} | ||
}); | ||
}); |
Oops, something went wrong.