You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

strophe.caps.jsonly.js 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /**
  2. * Entity Capabilities (XEP-0115)
  3. *
  4. * Depends on disco plugin.
  5. *
  6. * See: http://xmpp.org/extensions/xep-0115.html
  7. *
  8. * Authors:
  9. * - Michael Weibel <michael.weibel@gmail.com>
  10. *
  11. * Copyright:
  12. * - Michael Weibel <michael.weibel@gmail.com>
  13. */
  14. Strophe.addConnectionPlugin('caps', {
  15. /** Constant: HASH
  16. * Hash used
  17. *
  18. * Currently only sha-1 is supported.
  19. */
  20. HASH: 'sha-1',
  21. /** Variable: node
  22. * Client which is being used.
  23. *
  24. * Can be overwritten as soon as Strophe has been initialized.
  25. */
  26. node: 'http://strophe.im/strophejs/',
  27. /** PrivateVariable: _ver
  28. * Own generated version string
  29. */
  30. _ver: '',
  31. /** PrivateVariable: _connection
  32. * Strophe connection
  33. */
  34. _connection: null,
  35. /** PrivateVariable: _knownCapabilities
  36. * A hashtable containing version-strings and their capabilities, serialized
  37. * as string.
  38. *
  39. * TODO: Maybe those caps shouldn't be serialized.
  40. */
  41. _knownCapabilities: {},
  42. /** PrivateVariable: _jidVerIndex
  43. * A hashtable containing jids and their versions for better lookup of capabilities.
  44. */
  45. _jidVerIndex: {},
  46. /** Function: init
  47. * Initialize plugin:
  48. * - Add caps namespace
  49. * - Add caps feature to disco plugin
  50. * - Add handler for caps stanzas
  51. *
  52. * Parameters:
  53. * (Strophe.Connection) conn - Strophe connection
  54. */
  55. init: function(conn) {
  56. this._connection = conn;
  57. Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps');
  58. if (!this._connection.disco) {
  59. throw "Caps plugin requires the disco plugin to be installed.";
  60. }
  61. this._connection.disco.addFeature(Strophe.NS.CAPS);
  62. this._connection.addHandler(this._delegateCapabilities.bind(this), Strophe.NS.CAPS);
  63. },
  64. /** Function: generateCapsAttrs
  65. * Returns the attributes for generating the "c"-stanza containing the own version
  66. *
  67. * Returns:
  68. * (Object) - attributes
  69. */
  70. generateCapsAttrs: function() {
  71. return {
  72. 'xmlns': Strophe.NS.CAPS,
  73. 'hash': this.HASH,
  74. 'node': this.node,
  75. 'ver': this.generateVer()
  76. };
  77. },
  78. /** Function: generateVer
  79. * Returns the base64 encoded version string (encoded itself with sha1)
  80. *
  81. * Returns:
  82. * (String) - version
  83. */
  84. generateVer: function() {
  85. if (this._ver !== "") {
  86. return this._ver;
  87. }
  88. var ver = "",
  89. identities = this._connection.disco._identities.sort(this._sortIdentities),
  90. identitiesLen = identities.length,
  91. features = this._connection.disco._features.sort(),
  92. featuresLen = features.length;
  93. for(var i = 0; i < identitiesLen; i++) {
  94. var curIdent = identities[i];
  95. ver += curIdent.category + "/" + curIdent.type + "/" + curIdent.lang + "/" + curIdent.name + "<";
  96. }
  97. for(var i = 0; i < featuresLen; i++) {
  98. ver += features[i] + '<';
  99. }
  100. this._ver = b64_sha1(ver);
  101. return this._ver;
  102. },
  103. /** Function: getCapabilitiesByJid
  104. * Returns serialized capabilities of a jid (if available).
  105. * Otherwise null.
  106. *
  107. * Parameters:
  108. * (String) jid - Jabber id
  109. *
  110. * Returns:
  111. * (String|null) - capabilities, serialized; or null when not available.
  112. */
  113. getCapabilitiesByJid: function(jid) {
  114. if (this._jidVerIndex[jid]) {
  115. return this._knownCapabilities[this._jidVerIndex[jid]];
  116. }
  117. return null;
  118. },
  119. /** PrivateFunction: _delegateCapabilities
  120. * Checks if the version has already been saved.
  121. * If yes: do nothing.
  122. * If no: Request capabilities
  123. *
  124. * Parameters:
  125. * (Strophe.Builder) stanza - Stanza
  126. *
  127. * Returns:
  128. * (Boolean)
  129. */
  130. _delegateCapabilities: function(stanza) {
  131. var from = stanza.getAttribute('from'),
  132. c = stanza.querySelector('c'),
  133. ver = c.getAttribute('ver'),
  134. node = c.getAttribute('node');
  135. if (!this._knownCapabilities[ver]) {
  136. return this._requestCapabilities(from, node, ver);
  137. } else {
  138. this._jidVerIndex[from] = ver;
  139. }
  140. if (!this._jidVerIndex[from] || !this._jidVerIndex[from] !== ver) {
  141. this._jidVerIndex[from] = ver;
  142. }
  143. return true;
  144. },
  145. /** PrivateFunction: _requestCapabilities
  146. * Requests capabilities from the one which sent the caps-info stanza.
  147. * This is done using disco info.
  148. *
  149. * Additionally, it registers a handler for handling the reply.
  150. *
  151. * Parameters:
  152. * (String) to - Destination jid
  153. * (String) node - Node attribute of the caps-stanza
  154. * (String) ver - Version of the caps-stanza
  155. *
  156. * Returns:
  157. * (Boolean) - true
  158. */
  159. _requestCapabilities: function(to, node, ver) {
  160. if (to !== this._connection.jid) {
  161. var id = this._connection.disco.info(to, node + '#' + ver);
  162. this._connection.addHandler(this._handleDiscoInfoReply.bind(this), Strophe.NS.DISCO_INFO, 'iq', 'result', id, to);
  163. }
  164. return true;
  165. },
  166. /** PrivateFunction: _handleDiscoInfoReply
  167. * Parses the disco info reply and adds the version & it's capabilities to the _knownCapabilities variable.
  168. * Additionally, it adds the jid & the version to the _jidVerIndex variable for a better lookup.
  169. *
  170. * Parameters:
  171. * (Strophe.Builder) stanza - Disco info stanza
  172. *
  173. * Returns:
  174. * (Boolean) - false, to automatically remove the handler.
  175. */
  176. _handleDiscoInfoReply: function(stanza) {
  177. var query = stanza.querySelector('query'),
  178. node = query.getAttribute('node').split('#'),
  179. ver = node[1],
  180. from = stanza.getAttribute('from');
  181. if (!this._knownCapabilities[ver]) {
  182. var childNodes = query.childNodes,
  183. childNodesLen = childNodes.length;
  184. this._knownCapabilities[ver] = [];
  185. for(var i = 0; i < childNodesLen; i++) {
  186. var node = childNodes[i];
  187. this._knownCapabilities[ver].push({name: node.nodeName, attributes: node.attributes});
  188. }
  189. this._jidVerIndex[from] = ver;
  190. } else if (!this._jidVerIndex[from] || !this._jidVerIndex[from] !== ver) {
  191. this._jidVerIndex[from] = ver;
  192. }
  193. return false;
  194. },
  195. /** PrivateFunction: _sortIdentities
  196. * Sorts two identities according the sorting requirements in XEP-0115.
  197. *
  198. * Parameters:
  199. * (Object) a - Identity a
  200. * (Object) b - Identity b
  201. *
  202. * Returns:
  203. * (Integer) - 1, 0 or -1; according to which one's greater.
  204. */
  205. _sortIdentities: function(a, b) {
  206. if (a.category > b.category) {
  207. return 1;
  208. }
  209. if (a.category < b.category) {
  210. return -1;
  211. }
  212. if (a.type > b.type) {
  213. return 1;
  214. }
  215. if (a.type < b.type) {
  216. return -1;
  217. }
  218. if (a.lang > b.lang) {
  219. return 1;
  220. }
  221. if (a.lang < b.lang) {
  222. return -1;
  223. }
  224. return 0;
  225. }
  226. });