strophe.muc.js 37 KB

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