/www/js/strophe.js

https://github.com/southwolf/sample-chat-xmpp-phonegap · JavaScript · 3623 lines · 1939 code · 328 blank · 1356 comment · 329 complexity · 3be70f8cbc74c5f032e57fbfadbabc0c MD5 · raw file

Large files are truncated click here to view the full file

  1. // This code was written by Tyler Akins and has been placed in the
  2. // public domain. It would be nice if you left this header intact.
  3. // Base64 code from Tyler Akins -- http://rumkin.com
  4. var Base64 = (function () {
  5. var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  6. var obj = {
  7. /**
  8. * Encodes a string in base64
  9. * @param {String} input The string to encode in base64.
  10. */
  11. encode: function (input) {
  12. var output = "";
  13. var chr1, chr2, chr3;
  14. var enc1, enc2, enc3, enc4;
  15. var i = 0;
  16. do {
  17. chr1 = input.charCodeAt(i++);
  18. chr2 = input.charCodeAt(i++);
  19. chr3 = input.charCodeAt(i++);
  20. enc1 = chr1 >> 2;
  21. enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  22. enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  23. enc4 = chr3 & 63;
  24. if (isNaN(chr2)) {
  25. enc3 = enc4 = 64;
  26. } else if (isNaN(chr3)) {
  27. enc4 = 64;
  28. }
  29. output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
  30. keyStr.charAt(enc3) + keyStr.charAt(enc4);
  31. } while (i < input.length);
  32. return output;
  33. },
  34. /**
  35. * Decodes a base64 string.
  36. * @param {String} input The string to decode.
  37. */
  38. decode: function (input) {
  39. var output = "";
  40. var chr1, chr2, chr3;
  41. var enc1, enc2, enc3, enc4;
  42. var i = 0;
  43. // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
  44. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  45. do {
  46. enc1 = keyStr.indexOf(input.charAt(i++));
  47. enc2 = keyStr.indexOf(input.charAt(i++));
  48. enc3 = keyStr.indexOf(input.charAt(i++));
  49. enc4 = keyStr.indexOf(input.charAt(i++));
  50. chr1 = (enc1 << 2) | (enc2 >> 4);
  51. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  52. chr3 = ((enc3 & 3) << 6) | enc4;
  53. output = output + String.fromCharCode(chr1);
  54. if (enc3 != 64) {
  55. output = output + String.fromCharCode(chr2);
  56. }
  57. if (enc4 != 64) {
  58. output = output + String.fromCharCode(chr3);
  59. }
  60. } while (i < input.length);
  61. return output;
  62. }
  63. };
  64. return obj;
  65. })();
  66. /*
  67. * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
  68. * Digest Algorithm, as defined in RFC 1321.
  69. * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
  70. * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
  71. * Distributed under the BSD License
  72. * See http://pajhome.org.uk/crypt/md5 for more info.
  73. */
  74. var MD5 = (function () {
  75. /*
  76. * Configurable variables. You may need to tweak these to be compatible with
  77. * the server-side, but the defaults work in most cases.
  78. */
  79. var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
  80. var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
  81. var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
  82. /*
  83. * Add integers, wrapping at 2^32. This uses 16-bit operations internally
  84. * to work around bugs in some JS interpreters.
  85. */
  86. var safe_add = function (x, y) {
  87. var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  88. var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  89. return (msw << 16) | (lsw & 0xFFFF);
  90. };
  91. /*
  92. * Bitwise rotate a 32-bit number to the left.
  93. */
  94. var bit_rol = function (num, cnt) {
  95. return (num << cnt) | (num >>> (32 - cnt));
  96. };
  97. /*
  98. * Convert a string to an array of little-endian words
  99. * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
  100. */
  101. var str2binl = function (str) {
  102. var bin = [];
  103. var mask = (1 << chrsz) - 1;
  104. for(var i = 0; i < str.length * chrsz; i += chrsz)
  105. {
  106. bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  107. }
  108. return bin;
  109. };
  110. /*
  111. * Convert an array of little-endian words to a string
  112. */
  113. var binl2str = function (bin) {
  114. var str = "";
  115. var mask = (1 << chrsz) - 1;
  116. for(var i = 0; i < bin.length * 32; i += chrsz)
  117. {
  118. str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  119. }
  120. return str;
  121. };
  122. /*
  123. * Convert an array of little-endian words to a hex string.
  124. */
  125. var binl2hex = function (binarray) {
  126. var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  127. var str = "";
  128. for(var i = 0; i < binarray.length * 4; i++)
  129. {
  130. str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
  131. hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
  132. }
  133. return str;
  134. };
  135. /*
  136. * Convert an array of little-endian words to a base-64 string
  137. */
  138. var binl2b64 = function (binarray) {
  139. var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  140. var str = "";
  141. var triplet, j;
  142. for(var i = 0; i < binarray.length * 4; i += 3)
  143. {
  144. triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) |
  145. (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) |
  146. ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
  147. for(j = 0; j < 4; j++)
  148. {
  149. if(i * 8 + j * 6 > binarray.length * 32) { str += b64pad; }
  150. else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); }
  151. }
  152. }
  153. return str;
  154. };
  155. /*
  156. * These functions implement the four basic operations the algorithm uses.
  157. */
  158. var md5_cmn = function (q, a, b, x, s, t) {
  159. return safe_add(bit_rol(safe_add(safe_add(a, q),safe_add(x, t)), s),b);
  160. };
  161. var md5_ff = function (a, b, c, d, x, s, t) {
  162. return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
  163. };
  164. var md5_gg = function (a, b, c, d, x, s, t) {
  165. return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
  166. };
  167. var md5_hh = function (a, b, c, d, x, s, t) {
  168. return md5_cmn(b ^ c ^ d, a, b, x, s, t);
  169. };
  170. var md5_ii = function (a, b, c, d, x, s, t) {
  171. return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
  172. };
  173. /*
  174. * Calculate the MD5 of an array of little-endian words, and a bit length
  175. */
  176. var core_md5 = function (x, len) {
  177. /* append padding */
  178. x[len >> 5] |= 0x80 << ((len) % 32);
  179. x[(((len + 64) >>> 9) << 4) + 14] = len;
  180. var a = 1732584193;
  181. var b = -271733879;
  182. var c = -1732584194;
  183. var d = 271733878;
  184. var olda, oldb, oldc, oldd;
  185. for (var i = 0; i < x.length; i += 16)
  186. {
  187. olda = a;
  188. oldb = b;
  189. oldc = c;
  190. oldd = d;
  191. a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
  192. d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
  193. c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
  194. b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
  195. a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
  196. d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
  197. c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
  198. b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
  199. a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
  200. d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
  201. c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
  202. b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
  203. a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
  204. d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
  205. c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
  206. b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
  207. a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
  208. d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
  209. c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
  210. b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
  211. a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
  212. d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
  213. c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
  214. b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
  215. a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
  216. d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
  217. c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
  218. b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
  219. a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
  220. d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
  221. c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
  222. b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
  223. a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
  224. d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
  225. c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
  226. b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
  227. a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
  228. d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
  229. c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
  230. b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
  231. a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
  232. d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
  233. c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
  234. b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
  235. a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
  236. d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
  237. c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
  238. b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
  239. a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
  240. d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
  241. c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
  242. b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
  243. a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
  244. d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
  245. c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
  246. b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
  247. a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
  248. d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
  249. c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
  250. b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
  251. a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
  252. d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
  253. c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
  254. b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
  255. a = safe_add(a, olda);
  256. b = safe_add(b, oldb);
  257. c = safe_add(c, oldc);
  258. d = safe_add(d, oldd);
  259. }
  260. return [a, b, c, d];
  261. };
  262. /*
  263. * Calculate the HMAC-MD5, of a key and some data
  264. */
  265. var core_hmac_md5 = function (key, data) {
  266. var bkey = str2binl(key);
  267. if(bkey.length > 16) { bkey = core_md5(bkey, key.length * chrsz); }
  268. var ipad = new Array(16), opad = new Array(16);
  269. for(var i = 0; i < 16; i++)
  270. {
  271. ipad[i] = bkey[i] ^ 0x36363636;
  272. opad[i] = bkey[i] ^ 0x5C5C5C5C;
  273. }
  274. var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  275. return core_md5(opad.concat(hash), 512 + 128);
  276. };
  277. var obj = {
  278. /*
  279. * These are the functions you'll usually want to call.
  280. * They take string arguments and return either hex or base-64 encoded
  281. * strings.
  282. */
  283. hexdigest: function (s) {
  284. return binl2hex(core_md5(str2binl(s), s.length * chrsz));
  285. },
  286. b64digest: function (s) {
  287. return binl2b64(core_md5(str2binl(s), s.length * chrsz));
  288. },
  289. hash: function (s) {
  290. return binl2str(core_md5(str2binl(s), s.length * chrsz));
  291. },
  292. hmac_hexdigest: function (key, data) {
  293. return binl2hex(core_hmac_md5(key, data));
  294. },
  295. hmac_b64digest: function (key, data) {
  296. return binl2b64(core_hmac_md5(key, data));
  297. },
  298. hmac_hash: function (key, data) {
  299. return binl2str(core_hmac_md5(key, data));
  300. },
  301. /*
  302. * Perform a simple self-test to see if the VM is working
  303. */
  304. test: function () {
  305. return MD5.hexdigest("abc") === "900150983cd24fb0d6963f7d28e17f72";
  306. }
  307. };
  308. return obj;
  309. })();
  310. /*
  311. This program is distributed under the terms of the MIT license.
  312. Please see the LICENSE file for details.
  313. Copyright 2006-2008, OGG, LLC
  314. */
  315. /* jslint configuration: */
  316. /*global document, window, setTimeout, clearTimeout, console,
  317. XMLHttpRequest, ActiveXObject,
  318. Base64, MD5,
  319. Strophe, $build, $msg, $iq, $pres */
  320. /** File: strophe.js
  321. * A JavaScript library for XMPP BOSH.
  322. *
  323. * This is the JavaScript version of the Strophe library. Since JavaScript
  324. * has no facilities for persistent TCP connections, this library uses
  325. * Bidirectional-streams Over Synchronous HTTP (BOSH) to emulate
  326. * a persistent, stateful, two-way connection to an XMPP server. More
  327. * information on BOSH can be found in XEP 124.
  328. */
  329. /** PrivateFunction: Function.prototype.bind
  330. * Bind a function to an instance.
  331. *
  332. * This Function object extension method creates a bound method similar
  333. * to those in Python. This means that the 'this' object will point
  334. * to the instance you want. See
  335. * <a href='https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind'>MDC's bind() documentation</a> and
  336. * <a href='http://benjamin.smedbergs.us/blog/2007-01-03/bound-functions-and-function-imports-in-javascript/'>Bound Functions and Function Imports in JavaScript</a>
  337. * for a complete explanation.
  338. *
  339. * This extension already exists in some browsers (namely, Firefox 3), but
  340. * we provide it to support those that don't.
  341. *
  342. * Parameters:
  343. * (Object) obj - The object that will become 'this' in the bound function.
  344. * (Object) argN - An option argument that will be prepended to the
  345. * arguments given for the function call
  346. *
  347. * Returns:
  348. * The bound function.
  349. */
  350. if (!Function.prototype.bind) {
  351. Function.prototype.bind = function (obj /*, arg1, arg2, ... */)
  352. {
  353. var func = this;
  354. var _slice = Array.prototype.slice;
  355. var _concat = Array.prototype.concat;
  356. var _args = _slice.call(arguments, 1);
  357. return function () {
  358. return func.apply(obj ? obj : this,
  359. _concat.call(_args,
  360. _slice.call(arguments, 0)));
  361. };
  362. };
  363. }
  364. /** PrivateFunction: Array.prototype.indexOf
  365. * Return the index of an object in an array.
  366. *
  367. * This function is not supplied by some JavaScript implementations, so
  368. * we provide it if it is missing. This code is from:
  369. * http://developer.mozilla.org/En/Core_JavaScript_1.5_Reference:Objects:Array:indexOf
  370. *
  371. * Parameters:
  372. * (Object) elt - The object to look for.
  373. * (Integer) from - The index from which to start looking. (optional).
  374. *
  375. * Returns:
  376. * The index of elt in the array or -1 if not found.
  377. */
  378. if (!Array.prototype.indexOf)
  379. {
  380. Array.prototype.indexOf = function(elt /*, from*/)
  381. {
  382. var len = this.length;
  383. var from = Number(arguments[1]) || 0;
  384. from = (from < 0) ? Math.ceil(from) : Math.floor(from);
  385. if (from < 0) {
  386. from += len;
  387. }
  388. for (; from < len; from++) {
  389. if (from in this && this[from] === elt) {
  390. return from;
  391. }
  392. }
  393. return -1;
  394. };
  395. }
  396. /* All of the Strophe globals are defined in this special function below so
  397. * that references to the globals become closures. This will ensure that
  398. * on page reload, these references will still be available to callbacks
  399. * that are still executing.
  400. */
  401. (function (callback) {
  402. var Strophe;
  403. /** Function: $build
  404. * Create a Strophe.Builder.
  405. * This is an alias for 'new Strophe.Builder(name, attrs)'.
  406. *
  407. * Parameters:
  408. * (String) name - The root element name.
  409. * (Object) attrs - The attributes for the root element in object notation.
  410. *
  411. * Returns:
  412. * A new Strophe.Builder object.
  413. */
  414. function $build(name, attrs) { return new Strophe.Builder(name, attrs); }
  415. /** Function: $msg
  416. * Create a Strophe.Builder with a <message/> element as the root.
  417. *
  418. * Parmaeters:
  419. * (Object) attrs - The <message/> element attributes in object notation.
  420. *
  421. * Returns:
  422. * A new Strophe.Builder object.
  423. */
  424. function $msg(attrs) { return new Strophe.Builder("message", attrs); }
  425. /** Function: $iq
  426. * Create a Strophe.Builder with an <iq/> element as the root.
  427. *
  428. * Parameters:
  429. * (Object) attrs - The <iq/> element attributes in object notation.
  430. *
  431. * Returns:
  432. * A new Strophe.Builder object.
  433. */
  434. function $iq(attrs) { return new Strophe.Builder("iq", attrs); }
  435. /** Function: $pres
  436. * Create a Strophe.Builder with a <presence/> element as the root.
  437. *
  438. * Parameters:
  439. * (Object) attrs - The <presence/> element attributes in object notation.
  440. *
  441. * Returns:
  442. * A new Strophe.Builder object.
  443. */
  444. function $pres(attrs) { return new Strophe.Builder("presence", attrs); }
  445. /** Class: Strophe
  446. * An object container for all Strophe library functions.
  447. *
  448. * This class is just a container for all the objects and constants
  449. * used in the library. It is not meant to be instantiated, but to
  450. * provide a namespace for library objects, constants, and functions.
  451. */
  452. Strophe = {
  453. /** Constant: VERSION
  454. * The version of the Strophe library. Unreleased builds will have
  455. * a version of head-HASH where HASH is a partial revision.
  456. */
  457. VERSION: "1.0.2",
  458. /** Constants: XMPP Namespace Constants
  459. * Common namespace constants from the XMPP RFCs and XEPs.
  460. *
  461. * NS.HTTPBIND - HTTP BIND namespace from XEP 124.
  462. * NS.BOSH - BOSH namespace from XEP 206.
  463. * NS.CLIENT - Main XMPP client namespace.
  464. * NS.AUTH - Legacy authentication namespace.
  465. * NS.ROSTER - Roster operations namespace.
  466. * NS.PROFILE - Profile namespace.
  467. * NS.DISCO_INFO - Service discovery info namespace from XEP 30.
  468. * NS.DISCO_ITEMS - Service discovery items namespace from XEP 30.
  469. * NS.MUC - Multi-User Chat namespace from XEP 45.
  470. * NS.SASL - XMPP SASL namespace from RFC 3920.
  471. * NS.STREAM - XMPP Streams namespace from RFC 3920.
  472. * NS.BIND - XMPP Binding namespace from RFC 3920.
  473. * NS.SESSION - XMPP Session namespace from RFC 3920.
  474. */
  475. NS: {
  476. HTTPBIND: "http://jabber.org/protocol/httpbind",
  477. BOSH: "urn:xmpp:xbosh",
  478. CLIENT: "jabber:client",
  479. AUTH: "jabber:iq:auth",
  480. ROSTER: "jabber:iq:roster",
  481. PROFILE: "jabber:iq:profile",
  482. DISCO_INFO: "http://jabber.org/protocol/disco#info",
  483. DISCO_ITEMS: "http://jabber.org/protocol/disco#items",
  484. MUC: "http://jabber.org/protocol/muc",
  485. SASL: "urn:ietf:params:xml:ns:xmpp-sasl",
  486. STREAM: "http://etherx.jabber.org/streams",
  487. BIND: "urn:ietf:params:xml:ns:xmpp-bind",
  488. SESSION: "urn:ietf:params:xml:ns:xmpp-session",
  489. VERSION: "jabber:iq:version",
  490. STANZAS: "urn:ietf:params:xml:ns:xmpp-stanzas"
  491. },
  492. /** Function: addNamespace
  493. * This function is used to extend the current namespaces in
  494. * Strophe.NS. It takes a key and a value with the key being the
  495. * name of the new namespace, with its actual value.
  496. * For example:
  497. * Strophe.addNamespace('PUBSUB', "http://jabber.org/protocol/pubsub");
  498. *
  499. * Parameters:
  500. * (String) name - The name under which the namespace will be
  501. * referenced under Strophe.NS
  502. * (String) value - The actual namespace.
  503. */
  504. addNamespace: function (name, value)
  505. {
  506. Strophe.NS[name] = value;
  507. },
  508. /** Constants: Connection Status Constants
  509. * Connection status constants for use by the connection handler
  510. * callback.
  511. *
  512. * Status.ERROR - An error has occurred
  513. * Status.CONNECTING - The connection is currently being made
  514. * Status.CONNFAIL - The connection attempt failed
  515. * Status.AUTHENTICATING - The connection is authenticating
  516. * Status.AUTHFAIL - The authentication attempt failed
  517. * Status.CONNECTED - The connection has succeeded
  518. * Status.DISCONNECTED - The connection has been terminated
  519. * Status.DISCONNECTING - The connection is currently being terminated
  520. * Status.ATTACHED - The connection has been attached
  521. */
  522. Status: {
  523. ERROR: 0,
  524. CONNECTING: 1,
  525. CONNFAIL: 2,
  526. AUTHENTICATING: 3,
  527. AUTHFAIL: 4,
  528. CONNECTED: 5,
  529. DISCONNECTED: 6,
  530. DISCONNECTING: 7,
  531. ATTACHED: 8
  532. },
  533. /** Constants: Log Level Constants
  534. * Logging level indicators.
  535. *
  536. * LogLevel.DEBUG - Debug output
  537. * LogLevel.INFO - Informational output
  538. * LogLevel.WARN - Warnings
  539. * LogLevel.ERROR - Errors
  540. * LogLevel.FATAL - Fatal errors
  541. */
  542. LogLevel: {
  543. DEBUG: 0,
  544. INFO: 1,
  545. WARN: 2,
  546. ERROR: 3,
  547. FATAL: 4
  548. },
  549. /** PrivateConstants: DOM Element Type Constants
  550. * DOM element types.
  551. *
  552. * ElementType.NORMAL - Normal element.
  553. * ElementType.TEXT - Text data element.
  554. */
  555. ElementType: {
  556. NORMAL: 1,
  557. TEXT: 3,
  558. CDATA: 4
  559. },
  560. /** PrivateConstants: Timeout Values
  561. * Timeout values for error states. These values are in seconds.
  562. * These should not be changed unless you know exactly what you are
  563. * doing.
  564. *
  565. * TIMEOUT - Timeout multiplier. A waiting request will be considered
  566. * failed after Math.floor(TIMEOUT * wait) seconds have elapsed.
  567. * This defaults to 1.1, and with default wait, 66 seconds.
  568. * SECONDARY_TIMEOUT - Secondary timeout multiplier. In cases where
  569. * Strophe can detect early failure, it will consider the request
  570. * failed if it doesn't return after
  571. * Math.floor(SECONDARY_TIMEOUT * wait) seconds have elapsed.
  572. * This defaults to 0.1, and with default wait, 6 seconds.
  573. */
  574. TIMEOUT: 1.1,
  575. SECONDARY_TIMEOUT: 0.1,
  576. /** Function: forEachChild
  577. * Map a function over some or all child elements of a given element.
  578. *
  579. * This is a small convenience function for mapping a function over
  580. * some or all of the children of an element. If elemName is null, all
  581. * children will be passed to the function, otherwise only children
  582. * whose tag names match elemName will be passed.
  583. *
  584. * Parameters:
  585. * (XMLElement) elem - The element to operate on.
  586. * (String) elemName - The child element tag name filter.
  587. * (Function) func - The function to apply to each child. This
  588. * function should take a single argument, a DOM element.
  589. */
  590. forEachChild: function (elem, elemName, func)
  591. {
  592. var i, childNode;
  593. for (i = 0; i < elem.childNodes.length; i++) {
  594. childNode = elem.childNodes[i];
  595. if (childNode.nodeType == Strophe.ElementType.NORMAL &&
  596. (!elemName || this.isTagEqual(childNode, elemName))) {
  597. func(childNode);
  598. }
  599. }
  600. },
  601. /** Function: isTagEqual
  602. * Compare an element's tag name with a string.
  603. *
  604. * This function is case insensitive.
  605. *
  606. * Parameters:
  607. * (XMLElement) el - A DOM element.
  608. * (String) name - The element name.
  609. *
  610. * Returns:
  611. * true if the element's tag name matches _el_, and false
  612. * otherwise.
  613. */
  614. isTagEqual: function (el, name)
  615. {
  616. return el.tagName.toLowerCase() == name.toLowerCase();
  617. },
  618. /** PrivateVariable: _xmlGenerator
  619. * _Private_ variable that caches a DOM document to
  620. * generate elements.
  621. */
  622. _xmlGenerator: null,
  623. /** PrivateFunction: _makeGenerator
  624. * _Private_ function that creates a dummy XML DOM document to serve as
  625. * an element and text node generator.
  626. */
  627. _makeGenerator: function () {
  628. var doc;
  629. if (document.implementation.createDocument === undefined) {
  630. doc = this._getIEXmlDom();
  631. doc.appendChild(doc.createElement('strophe'));
  632. } else {
  633. doc = document.implementation
  634. .createDocument('jabber:client', 'strophe', null);
  635. }
  636. return doc;
  637. },
  638. /** Function: xmlGenerator
  639. * Get the DOM document to generate elements.
  640. *
  641. * Returns:
  642. * The currently used DOM document.
  643. */
  644. xmlGenerator: function () {
  645. if (!Strophe._xmlGenerator) {
  646. Strophe._xmlGenerator = Strophe._makeGenerator();
  647. }
  648. return Strophe._xmlGenerator;
  649. },
  650. /** PrivateFunction: _getIEXmlDom
  651. * Gets IE xml doc object
  652. *
  653. * Returns:
  654. * A Microsoft XML DOM Object
  655. * See Also:
  656. * http://msdn.microsoft.com/en-us/library/ms757837%28VS.85%29.aspx
  657. */
  658. _getIEXmlDom : function() {
  659. var doc = null;
  660. var docStrings = [
  661. "Msxml2.DOMDocument.6.0",
  662. "Msxml2.DOMDocument.5.0",
  663. "Msxml2.DOMDocument.4.0",
  664. "MSXML2.DOMDocument.3.0",
  665. "MSXML2.DOMDocument",
  666. "MSXML.DOMDocument",
  667. "Microsoft.XMLDOM"
  668. ];
  669. for (var d = 0; d < docStrings.length; d++) {
  670. if (doc === null) {
  671. try {
  672. doc = new ActiveXObject(docStrings[d]);
  673. } catch (e) {
  674. doc = null;
  675. }
  676. } else {
  677. break;
  678. }
  679. }
  680. return doc;
  681. },
  682. /** Function: xmlElement
  683. * Create an XML DOM element.
  684. *
  685. * This function creates an XML DOM element correctly across all
  686. * implementations. Note that these are not HTML DOM elements, which
  687. * aren't appropriate for XMPP stanzas.
  688. *
  689. * Parameters:
  690. * (String) name - The name for the element.
  691. * (Array|Object) attrs - An optional array or object containing
  692. * key/value pairs to use as element attributes. The object should
  693. * be in the format {'key': 'value'} or {key: 'value'}. The array
  694. * should have the format [['key1', 'value1'], ['key2', 'value2']].
  695. * (String) text - The text child data for the element.
  696. *
  697. * Returns:
  698. * A new XML DOM element.
  699. */
  700. xmlElement: function (name)
  701. {
  702. if (!name) { return null; }
  703. var node = Strophe.xmlGenerator().createElement(name);
  704. // FIXME: this should throw errors if args are the wrong type or
  705. // there are more than two optional args
  706. var a, i, k;
  707. for (a = 1; a < arguments.length; a++) {
  708. if (!arguments[a]) { continue; }
  709. if (typeof(arguments[a]) == "string" ||
  710. typeof(arguments[a]) == "number") {
  711. node.appendChild(Strophe.xmlTextNode(arguments[a]));
  712. } else if (typeof(arguments[a]) == "object" &&
  713. typeof(arguments[a].sort) == "function") {
  714. for (i = 0; i < arguments[a].length; i++) {
  715. if (typeof(arguments[a][i]) == "object" &&
  716. typeof(arguments[a][i].sort) == "function") {
  717. node.setAttribute(arguments[a][i][0],
  718. arguments[a][i][1]);
  719. }
  720. }
  721. } else if (typeof(arguments[a]) == "object") {
  722. for (k in arguments[a]) {
  723. if (arguments[a].hasOwnProperty(k)) {
  724. node.setAttribute(k, arguments[a][k]);
  725. }
  726. }
  727. }
  728. }
  729. return node;
  730. },
  731. /* Function: xmlescape
  732. * Excapes invalid xml characters.
  733. *
  734. * Parameters:
  735. * (String) text - text to escape.
  736. *
  737. * Returns:
  738. * Escaped text.
  739. */
  740. xmlescape: function(text)
  741. {
  742. text = text.replace(/\&/g, "&amp;");
  743. text = text.replace(/</g, "&lt;");
  744. text = text.replace(/>/g, "&gt;");
  745. text = text.replace(/'/g, "&apos;");
  746. text = text.replace(/"/g, "&quot;");
  747. return text;
  748. },
  749. /** Function: xmlTextNode
  750. * Creates an XML DOM text node.
  751. *
  752. * Provides a cross implementation version of document.createTextNode.
  753. *
  754. * Parameters:
  755. * (String) text - The content of the text node.
  756. *
  757. * Returns:
  758. * A new XML DOM text node.
  759. */
  760. xmlTextNode: function (text)
  761. {
  762. //ensure text is escaped
  763. text = Strophe.xmlescape(text);
  764. return Strophe.xmlGenerator().createTextNode(text);
  765. },
  766. /** Function: getText
  767. * Get the concatenation of all text children of an element.
  768. *
  769. * Parameters:
  770. * (XMLElement) elem - A DOM element.
  771. *
  772. * Returns:
  773. * A String with the concatenated text of all text element children.
  774. */
  775. getText: function (elem)
  776. {
  777. if (!elem) { return null; }
  778. var str = "";
  779. if (elem.childNodes.length === 0 && elem.nodeType ==
  780. Strophe.ElementType.TEXT) {
  781. str += elem.nodeValue;
  782. }
  783. for (var i = 0; i < elem.childNodes.length; i++) {
  784. if (elem.childNodes[i].nodeType == Strophe.ElementType.TEXT) {
  785. str += elem.childNodes[i].nodeValue;
  786. }
  787. }
  788. return str;
  789. },
  790. /** Function: copyElement
  791. * Copy an XML DOM element.
  792. *
  793. * This function copies a DOM element and all its descendants and returns
  794. * the new copy.
  795. *
  796. * Parameters:
  797. * (XMLElement) elem - A DOM element.
  798. *
  799. * Returns:
  800. * A new, copied DOM element tree.
  801. */
  802. copyElement: function (elem)
  803. {
  804. var i, el;
  805. if (elem.nodeType == Strophe.ElementType.NORMAL) {
  806. el = Strophe.xmlElement(elem.tagName);
  807. for (i = 0; i < elem.attributes.length; i++) {
  808. el.setAttribute(elem.attributes[i].nodeName.toLowerCase(),
  809. elem.attributes[i].value);
  810. }
  811. for (i = 0; i < elem.childNodes.length; i++) {
  812. el.appendChild(Strophe.copyElement(elem.childNodes[i]));
  813. }
  814. } else if (elem.nodeType == Strophe.ElementType.TEXT) {
  815. el = Strophe.xmlGenerator().createTextNode(elem.nodeValue);
  816. }
  817. return el;
  818. },
  819. /** Function: escapeNode
  820. * Escape the node part (also called local part) of a JID.
  821. *
  822. * Parameters:
  823. * (String) node - A node (or local part).
  824. *
  825. * Returns:
  826. * An escaped node (or local part).
  827. */
  828. escapeNode: function (node)
  829. {
  830. return node.replace(/^\s+|\s+$/g, '')
  831. .replace(/\\/g, "\\5c")
  832. .replace(/ /g, "\\20")
  833. .replace(/\"/g, "\\22")
  834. .replace(/\&/g, "\\26")
  835. .replace(/\'/g, "\\27")
  836. .replace(/\//g, "\\2f")
  837. .replace(/:/g, "\\3a")
  838. .replace(/</g, "\\3c")
  839. .replace(/>/g, "\\3e")
  840. .replace(/@/g, "\\40");
  841. },
  842. /** Function: unescapeNode
  843. * Unescape a node part (also called local part) of a JID.
  844. *
  845. * Parameters:
  846. * (String) node - A node (or local part).
  847. *
  848. * Returns:
  849. * An unescaped node (or local part).
  850. */
  851. unescapeNode: function (node)
  852. {
  853. return node.replace(/\\20/g, " ")
  854. .replace(/\\22/g, '"')
  855. .replace(/\\26/g, "&")
  856. .replace(/\\27/g, "'")
  857. .replace(/\\2f/g, "/")
  858. .replace(/\\3a/g, ":")
  859. .replace(/\\3c/g, "<")
  860. .replace(/\\3e/g, ">")
  861. .replace(/\\40/g, "@")
  862. .replace(/\\5c/g, "\\");
  863. },
  864. /** Function: getNodeFromJid
  865. * Get the node portion of a JID String.
  866. *
  867. * Parameters:
  868. * (String) jid - A JID.
  869. *
  870. * Returns:
  871. * A String containing the node.
  872. */
  873. getNodeFromJid: function (jid)
  874. {
  875. if (jid.indexOf("@") < 0) { return null; }
  876. return jid.split("@")[0];
  877. },
  878. /** Function: getDomainFromJid
  879. * Get the domain portion of a JID String.
  880. *
  881. * Parameters:
  882. * (String) jid - A JID.
  883. *
  884. * Returns:
  885. * A String containing the domain.
  886. */
  887. getDomainFromJid: function (jid)
  888. {
  889. var bare = Strophe.getBareJidFromJid(jid);
  890. if (bare.indexOf("@") < 0) {
  891. return bare;
  892. } else {
  893. var parts = bare.split("@");
  894. parts.splice(0, 1);
  895. return parts.join('@');
  896. }
  897. },
  898. /** Function: getResourceFromJid
  899. * Get the resource portion of a JID String.
  900. *
  901. * Parameters:
  902. * (String) jid - A JID.
  903. *
  904. * Returns:
  905. * A String containing the resource.
  906. */
  907. getResourceFromJid: function (jid)
  908. {
  909. var s = jid.split("/");
  910. if (s.length < 2) { return null; }
  911. s.splice(0, 1);
  912. return s.join('/');
  913. },
  914. /** Function: getBareJidFromJid
  915. * Get the bare JID from a JID String.
  916. *
  917. * Parameters:
  918. * (String) jid - A JID.
  919. *
  920. * Returns:
  921. * A String containing the bare JID.
  922. */
  923. getBareJidFromJid: function (jid)
  924. {
  925. return jid ? jid.split("/")[0] : null;
  926. },
  927. /** Function: log
  928. * User overrideable logging function.
  929. *
  930. * This function is called whenever the Strophe library calls any
  931. * of the logging functions. The default implementation of this
  932. * function does nothing. If client code wishes to handle the logging
  933. * messages, it should override this with
  934. * > Strophe.log = function (level, msg) {
  935. * > (user code here)
  936. * > };
  937. *
  938. * Please note that data sent and received over the wire is logged
  939. * via Strophe.Connection.rawInput() and Strophe.Connection.rawOutput().
  940. *
  941. * The different levels and their meanings are
  942. *
  943. * DEBUG - Messages useful for debugging purposes.
  944. * INFO - Informational messages. This is mostly information like
  945. * 'disconnect was called' or 'SASL auth succeeded'.
  946. * WARN - Warnings about potential problems. This is mostly used
  947. * to report transient connection errors like request timeouts.
  948. * ERROR - Some error occurred.
  949. * FATAL - A non-recoverable fatal error occurred.
  950. *
  951. * Parameters:
  952. * (Integer) level - The log level of the log message. This will
  953. * be one of the values in Strophe.LogLevel.
  954. * (String) msg - The log message.
  955. */
  956. log: function (level, msg)
  957. {
  958. return;
  959. },
  960. /** Function: debug
  961. * Log a message at the Strophe.LogLevel.DEBUG level.
  962. *
  963. * Parameters:
  964. * (String) msg - The log message.
  965. */
  966. debug: function(msg)
  967. {
  968. this.log(this.LogLevel.DEBUG, msg);
  969. },
  970. /** Function: info
  971. * Log a message at the Strophe.LogLevel.INFO level.
  972. *
  973. * Parameters:
  974. * (String) msg - The log message.
  975. */
  976. info: function (msg)
  977. {
  978. this.log(this.LogLevel.INFO, msg);
  979. },
  980. /** Function: warn
  981. * Log a message at the Strophe.LogLevel.WARN level.
  982. *
  983. * Parameters:
  984. * (String) msg - The log message.
  985. */
  986. warn: function (msg)
  987. {
  988. this.log(this.LogLevel.WARN, msg);
  989. },
  990. /** Function: error
  991. * Log a message at the Strophe.LogLevel.ERROR level.
  992. *
  993. * Parameters:
  994. * (String) msg - The log message.
  995. */
  996. error: function (msg)
  997. {
  998. this.log(this.LogLevel.ERROR, msg);
  999. },
  1000. /** Function: fatal
  1001. * Log a message at the Strophe.LogLevel.FATAL level.
  1002. *
  1003. * Parameters:
  1004. * (String) msg - The log message.
  1005. */
  1006. fatal: function (msg)
  1007. {
  1008. this.log(this.LogLevel.FATAL, msg);
  1009. },
  1010. /** Function: serialize
  1011. * Render a DOM element and all descendants to a String.
  1012. *
  1013. * Parameters:
  1014. * (XMLElement) elem - A DOM element.
  1015. *
  1016. * Returns:
  1017. * The serialized element tree as a String.
  1018. */
  1019. serialize: function (elem)
  1020. {
  1021. var result;
  1022. if (!elem) { return null; }
  1023. if (typeof(elem.tree) === "function") {
  1024. elem = elem.tree();
  1025. }
  1026. var nodeName = elem.nodeName;
  1027. var i, child;
  1028. if (elem.getAttribute("_realname")) {
  1029. nodeName = elem.getAttribute("_realname");
  1030. }
  1031. result = "<" + nodeName;
  1032. for (i = 0; i < elem.attributes.length; i++) {
  1033. if(elem.attributes[i].nodeName != "_realname") {
  1034. result += " " + elem.attributes[i].nodeName.toLowerCase() +
  1035. "='" + elem.attributes[i].value
  1036. .replace(/&/g, "&amp;")
  1037. .replace(/\'/g, "&apos;")
  1038. .replace(/</g, "&lt;") + "'";
  1039. }
  1040. }
  1041. if (elem.childNodes.length > 0) {
  1042. result += ">";
  1043. for (i = 0; i < elem.childNodes.length; i++) {
  1044. child = elem.childNodes[i];
  1045. switch( child.nodeType ){
  1046. case Strophe.ElementType.NORMAL:
  1047. // normal element, so recurse
  1048. result += Strophe.serialize(child);
  1049. break;
  1050. case Strophe.ElementType.TEXT:
  1051. // text element to escape values
  1052. result += Strophe.xmlescape(child.nodeValue);
  1053. break;
  1054. case Strophe.ElementType.CDATA:
  1055. // cdata section so don't escape values
  1056. result += "<![CDATA["+child.nodeValue+"]]>";
  1057. }
  1058. }
  1059. result += "</" + nodeName + ">";
  1060. } else {
  1061. result += "/>";
  1062. }
  1063. return result;
  1064. },
  1065. /** PrivateVariable: _requestId
  1066. * _Private_ variable that keeps track of the request ids for
  1067. * connections.
  1068. */
  1069. _requestId: 0,
  1070. /** PrivateVariable: Strophe.connectionPlugins
  1071. * _Private_ variable Used to store plugin names that need
  1072. * initialization on Strophe.Connection construction.
  1073. */
  1074. _connectionPlugins: {},
  1075. /** Function: addConnectionPlugin
  1076. * Extends the Strophe.Connection object with the given plugin.
  1077. *
  1078. * Parameters:
  1079. * (String) name - The name of the extension.
  1080. * (Object) ptype - The plugin's prototype.
  1081. */
  1082. addConnectionPlugin: function (name, ptype)
  1083. {
  1084. Strophe._connectionPlugins[name] = ptype;
  1085. }
  1086. };
  1087. /** Class: Strophe.Builder
  1088. * XML DOM builder.
  1089. *
  1090. * This object provides an interface similar to JQuery but for building
  1091. * DOM element easily and rapidly. All the functions except for toString()
  1092. * and tree() return the object, so calls can be chained. Here's an
  1093. * example using the $iq() builder helper.
  1094. * > $iq({to: 'you', from: 'me', type: 'get', id: '1'})
  1095. * > .c('query', {xmlns: 'strophe:example'})
  1096. * > .c('example')
  1097. * > .toString()
  1098. * The above generates this XML fragment
  1099. * > <iq to='you' from='me' type='get' id='1'>
  1100. * > <query xmlns='strophe:example'>
  1101. * > <example/>
  1102. * > </query>
  1103. * > </iq>
  1104. * The corresponding DOM manipulations to get a similar fragment would be
  1105. * a lot more tedious and probably involve several helper variables.
  1106. *
  1107. * Since adding children makes new operations operate on the child, up()
  1108. * is provided to traverse up the tree. To add two children, do
  1109. * > builder.c('child1', ...).up().c('child2', ...)
  1110. * The next operation on the Builder will be relative to the second child.
  1111. */
  1112. /** Constructor: Strophe.Builder
  1113. * Create a Strophe.Builder object.
  1114. *
  1115. * The attributes should be passed in object notation. For example
  1116. * > var b = new Builder('message', {to: 'you', from: 'me'});
  1117. * or
  1118. * > var b = new Builder('messsage', {'xml:lang': 'en'});
  1119. *
  1120. * Parameters:
  1121. * (String) name - The name of the root element.
  1122. * (Object) attrs - The attributes for the root element in object notation.
  1123. *
  1124. * Returns:
  1125. * A new Strophe.Builder.
  1126. */
  1127. Strophe.Builder = function (name, attrs)
  1128. {
  1129. // Set correct namespace for jabber:client elements
  1130. if (name == "presence" || name == "message" || name == "iq") {
  1131. if (attrs && !attrs.xmlns) {
  1132. attrs.xmlns = Strophe.NS.CLIENT;
  1133. } else if (!attrs) {
  1134. attrs = {xmlns: Strophe.NS.CLIENT};
  1135. }
  1136. }
  1137. // Holds the tree being built.
  1138. this.nodeTree = Strophe.xmlElement(name, attrs);
  1139. // Points to the current operation node.
  1140. this.node = this.nodeTree;
  1141. };
  1142. Strophe.Builder.prototype = {
  1143. /** Function: tree
  1144. * Return the DOM tree.
  1145. *
  1146. * This function returns the current DOM tree as an element object. This
  1147. * is suitable for passing to functions like Strophe.Connection.send().
  1148. *
  1149. * Returns:
  1150. * The DOM tree as a element object.
  1151. */
  1152. tree: function ()
  1153. {
  1154. return this.nodeTree;
  1155. },
  1156. /** Function: toString
  1157. * Serialize the DOM tree to a String.
  1158. *
  1159. * This function returns a string serialization of the current DOM
  1160. * tree. It is often used internally to pass data to a
  1161. * Strophe.Request object.
  1162. *
  1163. * Returns:
  1164. * The serialized DOM tree in a String.
  1165. */
  1166. toString: function ()
  1167. {
  1168. return Strophe.serialize(this.nodeTree);
  1169. },
  1170. /** Function: up
  1171. * Make the current parent element the new current element.
  1172. *
  1173. * This function is often used after c() to traverse back up the tree.
  1174. * For example, to add two children to the same element
  1175. * > builder.c('child1', {}).up().c('child2', {});
  1176. *
  1177. * Returns:
  1178. * The Stophe.Builder object.
  1179. */
  1180. up: function ()
  1181. {
  1182. this.node = this.node.parentNode;
  1183. return this;
  1184. },
  1185. /** Function: attrs
  1186. * Add or modify attributes of the current element.
  1187. *
  1188. * The attributes should be passed in object notation. This function
  1189. * does not move the current element pointer.
  1190. *
  1191. * Parameters:
  1192. * (Object) moreattrs - The attributes to add/modify in object notation.
  1193. *
  1194. * Returns:
  1195. * The Strophe.Builder object.
  1196. */
  1197. attrs: function (moreattrs)
  1198. {
  1199. for (var k in moreattrs) {
  1200. if (moreattrs.hasOwnProperty(k)) {
  1201. this.node.setAttribute(k, moreattrs[k]);
  1202. }
  1203. }
  1204. return this;
  1205. },
  1206. /** Function: c
  1207. * Add a child to the current element and make it the new current
  1208. * element.
  1209. *
  1210. * This function moves the current element pointer to the child,
  1211. * unless text is provided. If you need to add another child, it
  1212. * is necessary to use up() to go back to the parent in the tree.
  1213. *
  1214. * Parameters:
  1215. * (String) name - The name of the child.
  1216. * (Object) attrs - The attributes of the child in object notation.
  1217. * (String) text - The text to add to the child.
  1218. *
  1219. * Returns:
  1220. * The Strophe.Builder object.
  1221. */
  1222. c: function (name, attrs, text)
  1223. {
  1224. var child = Strophe.xmlElement(name, attrs, text);
  1225. this.node.appendChild(child);
  1226. if (!text) {
  1227. this.node = child;
  1228. }
  1229. return this;
  1230. },
  1231. /** Function: cnode
  1232. * Add a child to the current element and make it the new current
  1233. * element.
  1234. *
  1235. * This function is the same as c() except that instead of using a
  1236. * name and an attributes object to create the child it uses an
  1237. * existing DOM element object.
  1238. *
  1239. * Parameters:
  1240. * (XMLElement) elem - A DOM element.
  1241. *
  1242. * Returns:
  1243. * The Strophe.Builder object.
  1244. */
  1245. cnode: function (elem)
  1246. {
  1247. var xmlGen = Strophe.xmlGenerator();
  1248. try {
  1249. var impNode = (xmlGen.importNode !== undefined);
  1250. }
  1251. catch (e) {
  1252. var impNode = false;
  1253. }
  1254. var newElem = impNode ?
  1255. xmlGen.importNode(elem, true) :
  1256. Strophe.copyElement(elem);
  1257. this.node.appendChild(newElem);
  1258. this.node = newElem;
  1259. return this;
  1260. },
  1261. /** Function: t
  1262. * Add a child text element.
  1263. *
  1264. * This *does not* make the child the new current element since there
  1265. * are no children of text elements.
  1266. *
  1267. * Parameters:
  1268. * (String) text - The text data to append to the current element.
  1269. *
  1270. * Returns:
  1271. * The Strophe.Builder object.
  1272. */
  1273. t: function (text)
  1274. {
  1275. var child = Strophe.xmlTextNode(text);
  1276. this.node.appendChild(child);
  1277. return this;
  1278. }
  1279. };
  1280. /** PrivateClass: Strophe.Handler
  1281. * _Private_ helper class for managing stanza handlers.
  1282. *
  1283. * A Strophe.Handler encapsulates a user provided callback function to be
  1284. * executed when matching stanzas are received by the connection.
  1285. * Handlers can be either one-off or persistant depending on their
  1286. * return value. Returning true will cause a Handler to remain active, and
  1287. * returning false will remove the Handler.
  1288. *
  1289. * Users will not use Strophe.Handler objects directly, but instead they
  1290. * will use Strophe.Connection.addHandler() and
  1291. * Strophe.Connection.deleteHandler().
  1292. */
  1293. /** PrivateConstructor: Strophe.Handler
  1294. * Create and initialize a new Strophe.Handler.
  1295. *
  1296. * Parameters:
  1297. * (Function) handler - A function to be executed when the handler is run.
  1298. * (String) ns - The namespace to match.
  1299. * (String) name - The element name to match.
  1300. * (String) type - The element type to match.
  1301. * (String) id - The element id attribute to match.
  1302. * (String) from - The element from attribute to match.
  1303. * (Object) options - Handler options
  1304. *
  1305. * Returns:
  1306. * A new Strophe.Handler object.
  1307. */
  1308. Strophe.Handler = function (handler, ns, name, type, id, from, options)
  1309. {
  1310. this.handler = handler;
  1311. this.ns = ns;
  1312. this.name = name;
  1313. this.type = type;
  1314. this.id = id;
  1315. this.options = options || {matchbare: false};
  1316. // default matchBare to false if undefined
  1317. if (!this.options.matchBare) {
  1318. this.options.matchBare = false;
  1319. }
  1320. if (this.options.matchBare) {
  1321. this.from = from ? Strophe.getBareJidFromJid(from) : null;
  1322. } else {
  1323. this.from = from;
  1324. }
  1325. // whether the handler is a user handler or a system handler
  1326. this.user = true;
  1327. };
  1328. Strophe.Handler.prototype = {
  1329. /** PrivateFunction: isMatch
  1330. * Tests if a stanza matches the Strophe.Handler.
  1331. *
  1332. * Parameters:
  1333. * (XMLElement) elem - The XML element to test.
  1334. *
  1335. * Returns:
  1336. * true if the stanza matches and false otherwise.
  1337. */
  1338. isMatch: function (elem)
  1339. {
  1340. var nsMatch;
  1341. var from = null;
  1342. if (this.options.matchBare) {
  1343. from = Strophe.getBareJidFromJid(elem.getAttribute('from'));
  1344. } else {
  1345. from = elem.getAttribute('from');
  1346. }
  1347. nsMatch = false;
  1348. if (!this.ns) {
  1349. nsMatch = true;
  1350. } else {
  1351. var that = this;
  1352. Strophe.forEachChild(elem, null, function (elem) {
  1353. if (elem.getAttribute("xmlns") == that.ns) {
  1354. nsMatch = true;
  1355. }
  1356. });
  1357. nsMatch = nsMatch || elem.getAttribute("xmlns") == this.ns;
  1358. }
  1359. if (nsMatch &&
  1360. (!this.name || Strophe.isTagEqual(elem, this.name)) &&
  1361. (!this.type || elem.getAttribute("type") == this.type) &&
  1362. (!this.id || elem.getAttribute("id") == this.id) &&
  1363. (!this.from || from == this.from)) {
  1364. return true;
  1365. }
  1366. return false;
  1367. },
  1368. /** PrivateFunction: run
  1369. * Run the callback on a matching stanza.
  1370. *
  1371. * Parameters:
  1372. * (XMLElement) elem - The DOM element that triggered the
  1373. * Strophe.Handler.
  1374. *
  1375. * Returns:
  1376. * A boolean indicating if the handler should remain active.
  1377. */
  1378. run: function (elem)
  1379. {
  1380. var result = null;
  1381. try {
  1382. result = this.handler(elem);
  1383. } catch (e) {
  1384. if (e.sourceURL) {
  1385. Strophe.fatal("error: " + this.handler +
  1386. " " + e.sourceURL + ":" +
  1387. e.line + " - " + e.name + ": " + e.message);
  1388. } else if (e.fileName) {
  1389. if (typeof(console) != "undefined") {
  1390. console.trace();
  1391. console.error(this.handler, " - error - ", e, e.message);
  1392. }
  1393. Strophe.fatal("error: " + this.handler + " " +
  1394. e.fileName + ":" + e.lineNumber + " - " +
  1395. e.name + ": " + e.message);
  1396. } else {
  1397. Strophe.fatal("error: " + this.handler);
  1398. }
  1399. throw e;
  1400. }
  1401. return result;
  1402. },
  1403. /** PrivateFunction: toString
  1404. * Get a String representation of the Strophe.Handler object.
  1405. *
  1406. * Returns:
  1407. * A String.
  1408. */
  1409. toString: function ()
  1410. {
  1411. return "{Handler: " + this.handler + "(" + this.name + "," +
  1412. this.id + ",…