strophe.muc.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. /*
  2. *Plugin to implement the MUC extension.
  3. http://xmpp.org/extensions/xep-0045.html
  4. *Previous Author:
  5. Nathan Zorn <nathan.zorn@gmail.com>
  6. *Complete CoffeeScript rewrite:
  7. Andreas Guth <guth@dbis.rwth-aachen.de>
  8. *Cleanup, AMD/global registrations and bugfixes:
  9. JC Brand <jc@opkode.com>
  10. */
  11. // AMD/global registrations
  12. (function (root, factory) {
  13. if (typeof console === undefined || typeof console.log === undefined) {
  14. console = { log: function () {}, error: function () {} };
  15. }
  16. if (typeof define === 'function' && define.amd) {
  17. define([
  18. "strophe"
  19. ], function () {
  20. if (console===undefined || console.log===undefined) {
  21. console = { log: function () {}, error: function () {} };
  22. }
  23. return factory(jQuery, console);
  24. }
  25. );
  26. } else {
  27. return factory(jQuery, console);
  28. }
  29. }(this, function ($, console) {
  30. (function() {
  31. var Occupant, RoomConfig, XmppRoom,
  32. __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
  33. Strophe.addConnectionPlugin('muc', {
  34. _connection: null,
  35. rooms: [],
  36. init: function(conn) {
  37. /* Initialize the MUC plugin. Sets the correct connection object and
  38. * extends the namesace.
  39. */
  40. this._connection = conn;
  41. this._muc_handler = null;
  42. Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC + "#owner");
  43. Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + "#admin");
  44. Strophe.addNamespace('MUC_USER', Strophe.NS.MUC + "#user");
  45. return Strophe.addNamespace('MUC_ROOMCONF', Strophe.NS.MUC + "#roomconfig");
  46. },
  47. join: function(room, nick, msg_handler_cb, pres_handler_cb, roster_cb, password) {
  48. /* Join a multi-user chat room
  49. *
  50. * Parameters:
  51. * (String) room - The multi-user chat room to join.
  52. * (String) nick - Optional nickname to use in the chat room.
  53. * (Function) msg_handler_cb - The function call to handle messages from the specified chat room.
  54. * (Function) pres_handler_cb - The function call back to handle presence in the chat room.
  55. * (Function) roster_cb - The function call back to handle roster changes in the chat room.
  56. * (String) password - The optional password to use. (password protected rooms only)
  57. */
  58. var msg, room_nick, _this = this;
  59. room_nick = this.test_append_nick(room, nick);
  60. msg = $pres({
  61. from: this._connection.jid,
  62. to: room_nick
  63. }).c("x", {
  64. xmlns: Strophe.NS.MUC
  65. });
  66. if (password !== null) {
  67. msg.cnode(Strophe.xmlElement("password", [], password));
  68. }
  69. if (this._muc_handler === null) {
  70. this._muc_handler = this._connection.addHandler(function(stanza) {
  71. var from, handler, handlers, id, roomname, x, xmlns, xquery, _i, _len;
  72. from = stanza.getAttribute('from');
  73. if (!from) { return true; }
  74. roomname = from.split("/")[0];
  75. if (!_this.rooms[roomname]) { return true; }
  76. room = _this.rooms[roomname];
  77. handlers = {};
  78. if (stanza.nodeName === "message") {
  79. handlers = room._message_handlers;
  80. } else if (stanza.nodeName === "presence") {
  81. xquery = stanza.getElementsByTagName("x");
  82. if (xquery.length > 0) {
  83. for (_i = 0, _len = xquery.length; _i < _len; _i++) {
  84. x = xquery[_i];
  85. xmlns = x.getAttribute("xmlns");
  86. if (xmlns && xmlns.match(Strophe.NS.MUC)) {
  87. handlers = room._presence_handlers;
  88. break;
  89. }
  90. }
  91. }
  92. }
  93. _.each(handlers, function (handler, id, handlers) {
  94. if (!handler(stanza, room)) { delete handlers[id]; }
  95. });
  96. return true;
  97. });
  98. }
  99. if (!_.has(this.rooms, room)) {
  100. this.rooms[room] = new XmppRoom(this, room, nick, password);
  101. }
  102. if (pres_handler_cb) {
  103. this.rooms[room].addHandler('presence', pres_handler_cb);
  104. }
  105. if (msg_handler_cb) {
  106. this.rooms[room].addHandler('message', msg_handler_cb);
  107. }
  108. if (roster_cb) {
  109. this.rooms[room].addHandler('roster', roster_cb);
  110. }
  111. return this._connection.send(msg);
  112. },
  113. removeRoom: function (room) {
  114. delete this.rooms[room];
  115. if (this.rooms.length === 0) {
  116. this._connection.deleteHandler(this._muc_handler);
  117. this._muc_handler = null;
  118. }
  119. },
  120. leave: function(room, nick, handler_cb, exit_msg) {
  121. /* Leave a multi-user chat room
  122. *
  123. * Parameters:
  124. * (String) room - The multi-user chat room to leave.
  125. * (String) nick - The nick name used in the room.
  126. * (Function) handler_cb - Optional function to handle the successful leave.
  127. * (String) exit_msg - optional exit message.
  128. * Returns:
  129. * iqid - The unique id for the room leave.
  130. */
  131. var presence, presenceid, room_nick;
  132. this.removeRoom(room);
  133. room_nick = this.test_append_nick(room, nick);
  134. presenceid = this._connection.getUniqueId();
  135. presence = $pres({
  136. type: "unavailable",
  137. id: presenceid,
  138. from: this._connection.jid,
  139. to: room_nick
  140. });
  141. if (exit_msg !== null) {
  142. presence.c("status", exit_msg);
  143. }
  144. if (handler_cb !== null) {
  145. this._connection.addHandler(handler_cb, null, "presence", null, presenceid);
  146. }
  147. this._connection.send(presence);
  148. return presenceid;
  149. },
  150. message: function(room, nick, message, html_message, type) {
  151. /* Parameters:
  152. * (String) room - The multi-user chat room name.
  153. * (String) nick - The nick name used in the chat room.
  154. * (String) message - The plaintext message to send to the room.
  155. * (String) html_message - The message to send to the room with html markup.
  156. * (String) type - "groupchat" for group chat messages o
  157. * "chat" for private chat messages
  158. * Returns:
  159. * msgiq - the unique id used to send the message
  160. */
  161. var msg, msgid, parent, room_nick;
  162. room_nick = this.test_append_nick(room, nick);
  163. type = type || (nick !== null ? "chat" : "groupchat");
  164. msgid = this._connection.getUniqueId();
  165. msg = $msg({
  166. to: room_nick,
  167. from: this._connection.jid,
  168. type: type,
  169. id: msgid
  170. }).c("body", {
  171. xmlns: Strophe.NS.CLIENT
  172. }).t(message);
  173. msg.up();
  174. if (html_message != null) {
  175. msg.c("html", {xmlns: Strophe.NS.XHTML_IM}).c("body", {xmlns: Strophe.NS.XHTML}).h(html_message);
  176. if (msg.node.childNodes.length === 0) {
  177. parent = msg.node.parentNode;
  178. msg.up().up();
  179. msg.node.removeChild(parent);
  180. } else {
  181. msg.up().up();
  182. }
  183. }
  184. msg.c("x", {
  185. xmlns: "jabber:x:event"
  186. }).c("composing");
  187. this._connection.send(msg);
  188. return msgid;
  189. },
  190. groupchat: function(room, message, html_message) {
  191. /* Convenience Function to send a Message to all Occupants
  192. * Parameters:
  193. * (String) room - The multi-user chat room name.
  194. * (String) message - The plaintext message to send to the room.
  195. * (String) html_message - The message to send to the room with html markup.
  196. * Returns:
  197. * msgiq - the unique id used to send the message
  198. */
  199. return this.message(room, null, message, html_message);
  200. },
  201. invite: function(room, receiver, reason) {
  202. /* Send a mediated invitation.
  203. * Parameters:
  204. * (String) room - The multi-user chat room name.
  205. * (String) receiver - The invitation's receiver.
  206. * (String) reason - Optional reason for joining the room.
  207. * Returns:
  208. * msgiq - the unique id used to send the invitation
  209. */
  210. var invitation, msgid;
  211. msgid = this._connection.getUniqueId();
  212. invitation = $msg({
  213. from: this._connection.jid,
  214. to: room,
  215. id: msgid
  216. }).c('x', {
  217. xmlns: Strophe.NS.MUC_USER
  218. }).c('invite', {
  219. to: receiver
  220. });
  221. if (reason !== null) {
  222. invitation.c('reason', reason);
  223. }
  224. this._connection.send(invitation);
  225. return msgid;
  226. },
  227. directInvite: function(room, receiver, reason, password) {
  228. /* Send a direct invitation.
  229. * Parameters:
  230. * (String) room - The multi-user chat room name.
  231. * (String) receiver - The invitation's receiver.
  232. * (String) reason - Optional reason for joining the room.
  233. * (String) password - Optional password for the room.
  234. * Returns:
  235. * msgiq - the unique id used to send the invitation
  236. */
  237. var attrs, invitation, msgid;
  238. msgid = this._connection.getUniqueId();
  239. attrs = {
  240. xmlns: 'jabber:x:conference',
  241. jid: room
  242. };
  243. if (reason !== null) { attrs.reason = reason; }
  244. if (password !== null) { attrs.password = password; }
  245. invitation = $msg({
  246. from: this._connection.jid,
  247. to: receiver,
  248. id: msgid
  249. }).c('x', attrs);
  250. this._connection.send(invitation);
  251. return msgid;
  252. },
  253. queryOccupants: function(room, success_cb, error_cb) {
  254. /* Queries a room for a list of occupants
  255. * (String) room - The multi-user chat room name.
  256. * (Function) success_cb - Optional function to handle the info.
  257. * (Function) error_cb - Optional function to handle an error.
  258. * Returns:
  259. * id - the unique id used to send the info request
  260. */
  261. var attrs, info;
  262. attrs = {
  263. xmlns: Strophe.NS.DISCO_ITEMS
  264. };
  265. info = $iq({
  266. from: this._connection.jid,
  267. to: room,
  268. type: 'get'
  269. }).c('query', attrs);
  270. return this._connection.sendIQ(info, success_cb, error_cb);
  271. },
  272. configure: function(room, handler_cb) {
  273. /* Start a room configuration.
  274. * Parameters:
  275. * (String) room - The multi-user chat room name.
  276. * (Function) handler_cb - Optional function to handle the config form.
  277. * Returns:
  278. * id - the unique id used to send the configuration request
  279. */
  280. var config, id, stanza;
  281. config = $iq({
  282. to: room,
  283. type: "get"
  284. }).c("query", {
  285. xmlns: Strophe.NS.MUC_OWNER
  286. });
  287. stanza = config.tree();
  288. id = this._connection.sendIQ(stanza);
  289. if (handler_cb !== null) {
  290. this._connection.addHandler(function(stanza) { handler_cb(stanza);
  291. return false;
  292. }, Strophe.NS.MUC_OWNER, "iq", null, id);
  293. }
  294. return id;
  295. },
  296. cancelConfigure: function(room) {
  297. /* Cancel the room configuration
  298. * Parameters:
  299. * (String) room - The multi-user chat room name.
  300. * Returns:
  301. * id - the unique id used to cancel the configuration.
  302. */
  303. var config, stanza;
  304. config = $iq({
  305. to: room,
  306. type: "set"
  307. }).c("query", {
  308. xmlns: Strophe.NS.MUC_OWNER
  309. }).c("x", {
  310. xmlns: "jabber:x:data",
  311. type: "cancel"
  312. });
  313. stanza = config.tree();
  314. return this._connection.sendIQ(stanza);
  315. },
  316. saveConfiguration: function(room, configarray, callback, errback) {
  317. /* Save a room configuration.
  318. * Parameters:
  319. * (String) room - The multi-user chat room name.
  320. * (Array) configarray - an array of form elements used to configure the room.
  321. * Returns:
  322. * id - the unique id used to save the configuration.
  323. */
  324. var conf, config, stanza, _i, _len;
  325. config = $iq({
  326. to: room,
  327. type: "set"
  328. }).c("query", {
  329. xmlns: Strophe.NS.MUC_OWNER
  330. }).c("x", {
  331. xmlns: "jabber:x:data",
  332. type: "submit"
  333. });
  334. for (_i = 0, _len = configarray.length; _i < _len; _i++) {
  335. conf = configarray[_i];
  336. config.cnode(conf).up();
  337. }
  338. stanza = config.tree();
  339. return this._connection.sendIQ(stanza, callback, errback);
  340. },
  341. createInstantRoom: function(room) {
  342. /* Parameters:
  343. * (String) room - The multi-user chat room name.
  344. * Returns:
  345. * id - the unique id used to create the chat room.
  346. */
  347. var roomiq;
  348. roomiq = $iq({
  349. to: room,
  350. type: "set"
  351. }).c("query", {
  352. xmlns: Strophe.NS.MUC_OWNER
  353. }).c("x", {
  354. xmlns: "jabber:x:data",
  355. type: "submit"
  356. });
  357. return this._connection.sendIQ(roomiq.tree());
  358. },
  359. setTopic: function(room, topic) {
  360. /* Set the topic of the chat room.
  361. * Parameters:
  362. * (String) room - The multi-user chat room name.
  363. * (String) topic - Topic message.
  364. */
  365. var msg;
  366. msg = $msg({
  367. to: room,
  368. from: this._connection.jid,
  369. type: "groupchat"
  370. }).c("subject", {
  371. xmlns: "jabber:client"
  372. }).t(topic);
  373. return this._connection.send(msg.tree());
  374. },
  375. _modifyPrivilege: function(room, item, reason, handler_cb, error_cb) {
  376. /* Internal Function that Changes the role or affiliation of a member
  377. * of a MUC room. This function is used by modifyRole and modifyAffiliation.
  378. * The modification can only be done by a room moderator. An error will be
  379. * returned if the user doesn't have permission.
  380. * Parameters:
  381. * (String) room - The multi-user chat room name.
  382. * (Object) item - Object with nick and role or jid and affiliation attribute
  383. * (String) reason - Optional reason for the change.
  384. * (Function) handler_cb - Optional callback for success
  385. * (Function) errer_cb - Optional callback for error
  386. * Returns:
  387. * iq - the id of the mode change request.
  388. */
  389. var iq;
  390. iq = $iq({
  391. to: room,
  392. type: "set"
  393. }).c("query", {
  394. xmlns: Strophe.NS.MUC_ADMIN
  395. }).cnode(item.node);
  396. if (reason !== null) { iq.c("reason", reason); }
  397. return this._connection.sendIQ(iq.tree(), handler_cb, error_cb);
  398. },
  399. modifyRole: function(room, nick, role, reason, handler_cb, error_cb) {
  400. /* Changes the role of a member of a MUC room.
  401. * The modification can only be done by a room moderator. An error will be
  402. * returned if the user doesn't have permission.
  403. * Parameters:
  404. * (String) room - The multi-user chat room name.
  405. * (String) nick - The nick name of the user to modify.
  406. * (String) role - The new role of the user.
  407. * (String) affiliation - The new affiliation of the user.
  408. * (String) reason - Optional reason for the change.
  409. * (Function) handler_cb - Optional callback for success
  410. * (Function) errer_cb - Optional callback for error
  411. * Returns:
  412. * iq - the id of the mode change request.
  413. */
  414. var item;
  415. item = $build("item", {
  416. nick: nick,
  417. role: role
  418. });
  419. return this._modifyPrivilege(room, item, reason, handler_cb, error_cb);
  420. },
  421. kick: function(room, nick, reason, handler_cb, error_cb) {
  422. return this.modifyRole(room, nick, 'none', reason, handler_cb, error_cb);
  423. },
  424. voice: function(room, nick, reason, handler_cb, error_cb) {
  425. return this.modifyRole(room, nick, 'participant', reason, handler_cb, error_cb);
  426. },
  427. mute: function(room, nick, reason, handler_cb, error_cb) {
  428. return this.modifyRole(room, nick, 'visitor', reason, handler_cb, error_cb);
  429. },
  430. op: function(room, nick, reason, handler_cb, error_cb) {
  431. return this.modifyRole(room, nick, 'moderator', reason, handler_cb, error_cb);
  432. },
  433. deop: function(room, nick, reason, handler_cb, error_cb) {
  434. return this.modifyRole(room, nick, 'participant', reason, handler_cb, error_cb);
  435. },
  436. modifyAffiliation: function(room, jid, affiliation, reason, handler_cb, error_cb) {
  437. /* Changes the affiliation of a member of a MUC room.
  438. * The modification can only be done by a room moderator. An error will be
  439. * returned if the user doesn't have permission.
  440. * Parameters:
  441. * (String) room - The multi-user chat room name.
  442. * (String) jid - The jid of the user to modify.
  443. * (String) affiliation - The new affiliation of the user.
  444. * (String) reason - Optional reason for the change.
  445. * (Function) handler_cb - Optional callback for success
  446. * (Function) errer_cb - Optional callback for error
  447. * Returns:
  448. * iq - the id of the mode change request.
  449. */
  450. var item;
  451. item = $build("item", {
  452. jid: jid,
  453. affiliation: affiliation
  454. });
  455. return this._modifyPrivilege(room, item, reason, handler_cb, error_cb);
  456. },
  457. ban: function(room, jid, reason, handler_cb, error_cb) {
  458. return this.modifyAffiliation(room, jid, 'outcast', reason, handler_cb, error_cb);
  459. },
  460. member: function(room, jid, reason, handler_cb, error_cb) {
  461. return this.modifyAffiliation(room, jid, 'member', reason, handler_cb, error_cb);
  462. },
  463. revoke: function(room, jid, reason, handler_cb, error_cb) {
  464. return this.modifyAffiliation(room, jid, 'none', reason, handler_cb, error_cb);
  465. },
  466. owner: function(room, jid, reason, handler_cb, error_cb) {
  467. return this.modifyAffiliation(room, jid, 'owner', reason, handler_cb, error_cb);
  468. },
  469. admin: function(room, jid, reason, handler_cb, error_cb) {
  470. return this.modifyAffiliation(room, jid, 'admin', reason, handler_cb, error_cb);
  471. },
  472. changeNick: function(room, user) {
  473. /* Change the current users nick name.
  474. * Parameters:
  475. * (String) room - The multi-user chat room name.
  476. * (String) user - The new nick name.
  477. */
  478. var presence, room_nick;
  479. room_nick = this.test_append_nick(room, user);
  480. presence = $pres({
  481. from: this._connection.jid,
  482. to: room_nick,
  483. id: this._connection.getUniqueId()
  484. });
  485. return this._connection.send(presence.tree());
  486. },
  487. setStatus: function(room, user, show, status) {
  488. /* Change the current users status.
  489. * Parameters:
  490. * (String) room - The multi-user chat room name.
  491. * (String) user - The current nick.
  492. * (String) show - The new show-text.
  493. * (String) status - The new status-text.
  494. */
  495. var presence, room_nick;
  496. room_nick = this.test_append_nick(room, user);
  497. presence = $pres({
  498. from: this._connection.jid,
  499. to: room_nick
  500. });
  501. if (show !== null) { presence.c('show', show).up(); }
  502. if (status !== null) { presence.c('status', status); }
  503. return this._connection.send(presence.tree());
  504. },
  505. listRooms: function(server, callback, errback) {
  506. /* List all chat room available on a server.
  507. * Parameters:
  508. * (String) server - name of chat server.
  509. * (String) callback - Function to call for room list return.
  510. */
  511. var iq;
  512. iq = $iq({
  513. to: server,
  514. from: this._connection.jid,
  515. type: "get"
  516. }).c("query", {
  517. xmlns: Strophe.NS.DISCO_ITEMS
  518. });
  519. return this._connection.sendIQ(iq, callback, errback);
  520. },
  521. test_append_nick: function(room, nick) {
  522. return room + (nick !== null ? "/" + (Strophe.escapeNode(nick)) : "");
  523. }
  524. });
  525. XmppRoom = (function() {
  526. function XmppRoom(client, name, nick, password) {
  527. this.roster = {};
  528. this._message_handlers = {};
  529. this._presence_handlers = {};
  530. this._roster_handlers = {};
  531. this._handler_ids = 0;
  532. this.client = client;
  533. this.name = name;
  534. this.nick = nick;
  535. this.password = password;
  536. this._roomRosterHandler = __bind(this._roomRosterHandler, this);
  537. this._addOccupant = __bind(this._addOccupant, this);
  538. if (client.muc) { this.client = client.muc; }
  539. this.name = Strophe.getBareJidFromJid(name);
  540. this.client.rooms[this.name] = this;
  541. this.addHandler('presence', this._roomRosterHandler);
  542. }
  543. XmppRoom.prototype.join = function(msg_handler_cb, pres_handler_cb) {
  544. if (!this.client.rooms[this.name]) {
  545. return this.client.join(this.name, this.nick, msg_handler_cb, pres_handler_cb, this.password);
  546. }
  547. };
  548. XmppRoom.prototype.leave = function(handler_cb, message) {
  549. this.client.leave(this.name, this.nick, handler_cb, message);
  550. return delete this.client.rooms[this.name];
  551. };
  552. XmppRoom.prototype.message = function(nick, message, html_message, type) {
  553. return this.client.message(this.name, nick, message, html_message, type);
  554. };
  555. XmppRoom.prototype.groupchat = function(message, html_message) {
  556. return this.client.groupchat(this.name, message, html_message);
  557. };
  558. XmppRoom.prototype.invite = function(receiver, reason) {
  559. return this.client.invite(this.name, receiver, reason);
  560. };
  561. XmppRoom.prototype.directInvite = function(receiver, reason) {
  562. return this.client.directInvite(this.name, receiver, reason, this.password);
  563. };
  564. XmppRoom.prototype.configure = function(handler_cb) {
  565. return this.client.configure(this.name, handler_cb);
  566. };
  567. XmppRoom.prototype.cancelConfigure = function() {
  568. return this.client.cancelConfigure(this.name);
  569. };
  570. XmppRoom.prototype.saveConfiguration = function(configarray) {
  571. return this.client.saveConfiguration(this.name, configarray);
  572. };
  573. XmppRoom.prototype.queryOccupants = function(success_cb, error_cb) {
  574. return this.client.queryOccupants(this.name, success_cb, error_cb);
  575. };
  576. XmppRoom.prototype.setTopic = function(topic) {
  577. return this.client.setTopic(this.name, topic);
  578. };
  579. XmppRoom.prototype.modifyRole = function(nick, role, reason, success_cb, error_cb) {
  580. return this.client.modifyRole(this.name, nick, role, reason, success_cb, error_cb);
  581. };
  582. XmppRoom.prototype.kick = function(nick, reason, handler_cb, error_cb) {
  583. return this.client.kick(this.name, nick, reason, handler_cb, error_cb);
  584. };
  585. XmppRoom.prototype.voice = function(nick, reason, handler_cb, error_cb) {
  586. return this.client.voice(this.name, nick, reason, handler_cb, error_cb);
  587. };
  588. XmppRoom.prototype.mute = function(nick, reason, handler_cb, error_cb) {
  589. return this.client.mute(this.name, nick, reason, handler_cb, error_cb);
  590. };
  591. XmppRoom.prototype.op = function(nick, reason, handler_cb, error_cb) {
  592. return this.client.op(this.name, nick, reason, handler_cb, error_cb);
  593. };
  594. XmppRoom.prototype.deop = function(nick, reason, handler_cb, error_cb) {
  595. return this.client.deop(this.name, nick, reason, handler_cb, error_cb);
  596. };
  597. XmppRoom.prototype.modifyAffiliation = function(jid, affiliation, reason, success_cb, error_cb) {
  598. return this.client.modifyAffiliation(this.name, jid, affiliation, reason, success_cb, error_cb);
  599. };
  600. XmppRoom.prototype.ban = function(jid, reason, handler_cb, error_cb) {
  601. return this.client.ban(this.name, jid, reason, handler_cb, error_cb);
  602. };
  603. XmppRoom.prototype.member = function(jid, reason, handler_cb, error_cb) {
  604. return this.client.member(this.name, jid, reason, handler_cb, error_cb);
  605. };
  606. XmppRoom.prototype.revoke = function(jid, reason, handler_cb, error_cb) {
  607. return this.client.revoke(this.name, jid, reason, handler_cb, error_cb);
  608. };
  609. XmppRoom.prototype.owner = function(jid, reason, handler_cb, error_cb) {
  610. return this.client.owner(this.name, jid, reason, handler_cb, error_cb);
  611. };
  612. XmppRoom.prototype.admin = function(jid, reason, handler_cb, error_cb) {
  613. return this.client.admin(this.name, jid, reason, handler_cb, error_cb);
  614. };
  615. XmppRoom.prototype.changeNick = function(nick) {
  616. this.nick = nick;
  617. return this.client.changeNick(this.name, nick);
  618. };
  619. XmppRoom.prototype.setStatus = function(show, status) {
  620. return this.client.setStatus(this.name, this.nick, show, status);
  621. };
  622. XmppRoom.prototype.addHandler = function(handler_type, handler) {
  623. /* Adds a handler to the MUC room.
  624. * Parameters:
  625. * (String) handler_type - 'message', 'presence' or 'roster'.
  626. * (Function) handler - The handler function.
  627. * Returns:
  628. * id - the id of handler.
  629. */
  630. var id;
  631. id = this._handler_ids++;
  632. switch (handler_type) {
  633. case 'presence':
  634. this._presence_handlers[id] = handler;
  635. break;
  636. case 'message':
  637. this._message_handlers[id] = handler;
  638. break;
  639. case 'roster':
  640. this._roster_handlers[id] = handler;
  641. break;
  642. default:
  643. this._handler_ids--;
  644. return null;
  645. }
  646. return id;
  647. };
  648. XmppRoom.prototype.removeHandler = function(id) {
  649. /* Removes a handler from the MUC room.
  650. * This function takes ONLY ids returned by the addHandler function
  651. * of this room. passing handler ids returned by connection.addHandler
  652. * may brake things!
  653. * Parameters:
  654. * (number) id - the id of the handler
  655. */
  656. delete this._presence_handlers[id];
  657. delete this._message_handlers[id];
  658. return delete this._roster_handlers[id];
  659. };
  660. XmppRoom.prototype._addOccupant = function(data) {
  661. /* Creates and adds an Occupant to the Room Roster.
  662. * Parameters:
  663. * (Object) data - the data the Occupant is filled with
  664. * Returns:
  665. * occ - the created Occupant.
  666. */
  667. var occ;
  668. occ = new Occupant(data, this);
  669. this.roster[occ.nick] = occ;
  670. return occ;
  671. };
  672. XmppRoom.prototype._roomRosterHandler = function(pres) {
  673. /* The standard handler that managed the Room Roster.
  674. * Parameters:
  675. * (Object) pres - the presence stanza containing user information
  676. */
  677. var data, handler, id, newnick, nick, _ref;
  678. data = XmppRoom._parsePresence(pres);
  679. nick = data.nick;
  680. newnick = data.newnick || null;
  681. switch (data.type) {
  682. case 'error':
  683. return;
  684. case 'unavailable':
  685. if (newnick) {
  686. data.nick = newnick;
  687. if (this.roster[nick] && this.roster[newnick]) {
  688. this.roster[nick].update(this.roster[newnick]);
  689. this.roster[newnick] = this.roster[nick];
  690. }
  691. if (this.roster[nick] && !this.roster[newnick]) {
  692. this.roster[newnick] = this.roster[nick].update(data);
  693. }
  694. }
  695. delete this.roster[nick];
  696. break;
  697. default:
  698. if (this.roster[nick]) {
  699. this.roster[nick].update(data);
  700. } else {
  701. this._addOccupant(data);
  702. }
  703. }
  704. _ref = this._roster_handlers;
  705. for (id in _ref) {
  706. handler = _ref[id];
  707. if (!handler(this.roster, this)) { delete this._roster_handlers[id]; }
  708. }
  709. return true;
  710. };
  711. XmppRoom._parsePresence = function(pres) {
  712. /* Parses a presence stanza into a map
  713. * Parameters:
  714. * (Object) pres - the presence stanza
  715. * Returns:
  716. * (Object) data - the data extracted from the presence stanza
  717. */
  718. var $pres, data, i, j, children, item;
  719. $pres = $(pres);
  720. data = {};
  721. data.nick = Strophe.getResourceFromJid($pres.attr('from'));
  722. data.type = $pres.attr('type');
  723. data.states = [];
  724. for (i=0; i < $pres.children().length; i++) {
  725. child = $pres.children()[0];
  726. switch (child.nodeName) {
  727. case 'status':
  728. data.status = child.textContent || null;
  729. break;
  730. case 'show':
  731. data.show = child.textContent || null;
  732. break;
  733. case 'x':
  734. if ($(child).attr('xmlns') === Strophe.NS.MUC_USER) {
  735. children = $(child).children();
  736. for (j=0; j < children.length; j++) {
  737. item = children[0];
  738. switch (item.nodeName) {
  739. case "item":
  740. a = item.attributes;
  741. data.affiliation = $(item).attr('affiliation') || null;
  742. data.role = $(item).attr('role') || null;
  743. data.jid = $(item).attr('jid') || null;
  744. data.newnick = $(item).attr('nick') || null;
  745. break;
  746. case "status":
  747. if ($(item).attr('code')) {
  748. data.states.push($(item).attr('code'));
  749. }
  750. break;
  751. }
  752. }
  753. }
  754. break;
  755. }
  756. }
  757. return data;
  758. };
  759. return XmppRoom;
  760. })();
  761. RoomConfig = (function() {
  762. function RoomConfig(info) {
  763. this.parse = __bind(this.parse, this);
  764. if (info !== null) { this.parse(info); }
  765. }
  766. RoomConfig.prototype.parse = function(result) {
  767. var attr, attrs, child, field, identity, query, _i, _j, _k, _len, _len2, _len3, _ref;
  768. query = result.getElementsByTagName("query")[0].childNodes;
  769. this.identities = [];
  770. this.features = [];
  771. this.x = [];
  772. for (_i = 0, _len = query.length; _i < _len; _i++) {
  773. child = query[_i];
  774. attrs = child.attributes;
  775. switch (child.nodeName) {
  776. case "identity":
  777. identity = {};
  778. for (_j = 0, _len2 = attrs.length; _j < _len2; _j++) {
  779. attr = attrs[_j];
  780. identity[attr.name] = attr.textContent;
  781. }
  782. this.identities.push(identity);
  783. break;
  784. case "feature":
  785. this.features.push(attrs["var"].textContent);
  786. break;
  787. case "x":
  788. attrs = child.childNodes[0].attributes;
  789. if ((!attrs["var"].textContent === 'FORM_TYPE') || (!attrs.type.textContent === 'hidden')) {
  790. break;
  791. }
  792. _ref = child.childNodes;
  793. for (_k = 0, _len3 = _ref.length; _k < _len3; _k++) {
  794. field = _ref[_k];
  795. if (!(!field.attributes.type)) continue;
  796. attrs = field.attributes;
  797. this.x.push({
  798. "var": attrs["var"].textContent,
  799. label: attrs.label.textContent || "",
  800. value: field.firstChild.textContent || ""
  801. });
  802. }
  803. }
  804. }
  805. return {
  806. "identities": this.identities,
  807. "features": this.features,
  808. "x": this.x
  809. };
  810. };
  811. return RoomConfig;
  812. })();
  813. Occupant = (function() {
  814. function Occupant(data, room) {
  815. this.room = room;
  816. this.update = __bind(this.update, this);
  817. this.admin = __bind(this.admin, this);
  818. this.owner = __bind(this.owner, this);
  819. this.revoke = __bind(this.revoke, this);
  820. this.member = __bind(this.member, this);
  821. this.ban = __bind(this.ban, this);
  822. this.modifyAffiliation = __bind(this.modifyAffiliation, this);
  823. this.deop = __bind(this.deop, this);
  824. this.op = __bind(this.op, this);
  825. this.mute = __bind(this.mute, this);
  826. this.voice = __bind(this.voice, this);
  827. this.kick = __bind(this.kick, this);
  828. this.modifyRole = __bind(this.modifyRole, this);
  829. this.update(data);
  830. }
  831. Occupant.prototype.modifyRole = function(role, reason, success_cb, error_cb) {
  832. return this.room.modifyRole(this.nick, role, reason, success_cb, error_cb);
  833. };
  834. Occupant.prototype.kick = function(reason, handler_cb, error_cb) {
  835. return this.room.kick(this.nick, reason, handler_cb, error_cb);
  836. };
  837. Occupant.prototype.voice = function(reason, handler_cb, error_cb) {
  838. return this.room.voice(this.nick, reason, handler_cb, error_cb);
  839. };
  840. Occupant.prototype.mute = function(reason, handler_cb, error_cb) {
  841. return this.room.mute(this.nick, reason, handler_cb, error_cb);
  842. };
  843. Occupant.prototype.op = function(reason, handler_cb, error_cb) {
  844. return this.room.op(this.nick, reason, handler_cb, error_cb);
  845. };
  846. Occupant.prototype.deop = function(reason, handler_cb, error_cb) {
  847. return this.room.deop(this.nick, reason, handler_cb, error_cb);
  848. };
  849. Occupant.prototype.modifyAffiliation = function(affiliation, reason, success_cb, error_cb) {
  850. return this.room.modifyAffiliation(this.jid, affiliation, reason, success_cb, error_cb);
  851. };
  852. Occupant.prototype.ban = function(reason, handler_cb, error_cb) {
  853. return this.room.ban(this.jid, reason, handler_cb, error_cb);
  854. };
  855. Occupant.prototype.member = function(reason, handler_cb, error_cb) {
  856. return this.room.member(this.jid, reason, handler_cb, error_cb);
  857. };
  858. Occupant.prototype.revoke = function(reason, handler_cb, error_cb) {
  859. return this.room.revoke(this.jid, reason, handler_cb, error_cb);
  860. };
  861. Occupant.prototype.owner = function(reason, handler_cb, error_cb) {
  862. return this.room.owner(this.jid, reason, handler_cb, error_cb);
  863. };
  864. Occupant.prototype.admin = function(reason, handler_cb, error_cb) {
  865. return this.room.admin(this.jid, reason, handler_cb, error_cb);
  866. };
  867. Occupant.prototype.update = function(data) {
  868. this.nick = data.nick || null;
  869. this.affiliation = data.affiliation || null;
  870. this.role = data.role || null;
  871. this.jid = data.jid || null;
  872. this.status = data.status || null;
  873. this.show = data.show || null;
  874. return this;
  875. };
  876. return Occupant;
  877. })();
  878. }).call(this);
  879. }));