]> git.0d.be Git - panikweb.git/blob - panikweb/static/js/strophe.muc.js
move static & templates to panikweb project directory
[panikweb.git] / panikweb / static / js / strophe.muc.js
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  */
9 var Occupant, RoomConfig, XmppRoom,
10     hasProp = {}.hasOwnProperty,
11     bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
12
13 Strophe.addConnectionPlugin('muc', {
14   _connection: null,
15   rooms: {},
16   roomNames: [],
17
18   /*Function
19    Initialize the MUC plugin. Sets the correct connection object and
20    extends the namesace.
21    */
22   init: function(conn) {
23     this._connection = conn;
24     this._muc_handler = null;
25     Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC + "#owner");
26     Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + "#admin");
27     Strophe.addNamespace('MUC_USER', Strophe.NS.MUC + "#user");
28     Strophe.addNamespace('MUC_ROOMCONF', Strophe.NS.MUC + "#roomconfig");
29     return Strophe.addNamespace('MUC_REGISTER', "jabber:iq:register");
30   },
31
32   /*Function
33    Join a multi-user chat room
34    Parameters:
35    (String) room - The multi-user chat room to join.
36    (String) nick - The nickname to use in the chat room. Optional
37    (Function) msg_handler_cb - The function call to handle messages from the
38    specified chat room.
39    (Function) pres_handler_cb - The function call back to handle presence
40    in the chat room.
41    (Function) roster_cb - The function call to handle roster info in the chat room
42    (String) password - The optional password to use. (password protected
43    rooms only)
44    (Object) history_attrs - Optional attributes for retrieving history
45    (XML DOM Element) extended_presence - Optional XML for extending presence
46    */
47   join: function(room, nick, msg_handler_cb, pres_handler_cb, roster_cb, password, history_attrs, extended_presence) {
48     var msg, room_nick;
49     room_nick = this.test_append_nick(room, nick);
50     msg = $pres({
51       from: this._connection.jid,
52       to: room_nick
53     }).c("x", {
54       xmlns: Strophe.NS.MUC
55     });
56     if (history_attrs != null) {
57       msg = msg.c("history", history_attrs).up();
58     }
59     if (password != null) {
60       msg.cnode(Strophe.xmlElement("password", [], password));
61     }
62     if (extended_presence != null) {
63       msg.up().cnode(extended_presence);
64     }
65     if (this._muc_handler == null) {
66       this._muc_handler = this._connection.addHandler((function(_this) {
67         return function(stanza) {
68           var from, handler, handlers, i, id, len, roomname, x, xmlns, xquery;
69           from = stanza.getAttribute('from');
70           if (!from) {
71             return true;
72           }
73           roomname = from.split("/")[0];
74           if (!_this.rooms[roomname]) {
75             return true;
76           }
77           room = _this.rooms[roomname];
78           handlers = {};
79           if (stanza.nodeName === "message") {
80             handlers = room._message_handlers;
81           } else if (stanza.nodeName === "presence") {
82             xquery = stanza.getElementsByTagName("x");
83             if (xquery.length > 0) {
84               for (i = 0, len = xquery.length; i < len; i++) {
85                 x = xquery[i];
86                 xmlns = x.getAttribute("xmlns");
87                 if (xmlns && xmlns.match(Strophe.NS.MUC)) {
88                   handlers = room._presence_handlers;
89                   break;
90                 }
91               }
92             }
93           }
94           for (id in handlers) {
95             handler = handlers[id];
96             if (!handler(stanza, room)) {
97               delete handlers[id];
98             }
99           }
100           return true;
101         };
102       })(this));
103     }
104     if (!this.rooms.hasOwnProperty(room)) {
105       this.rooms[room] = new XmppRoom(this, room, nick, password);
106       if (pres_handler_cb) {
107         this.rooms[room].addHandler('presence', pres_handler_cb);
108       }
109       if (msg_handler_cb) {
110         this.rooms[room].addHandler('message', msg_handler_cb);
111       }
112       if (roster_cb) {
113         this.rooms[room].addHandler('roster', roster_cb);
114       }
115       this.roomNames.push(room);
116     }
117     return this._connection.send(msg);
118   },
119
120   /*Function
121    Leave a multi-user chat room
122    Parameters:
123    (String) room - The multi-user chat room to leave.
124    (String) nick - The nick name used in the room.
125    (Function) handler_cb - Optional function to handle the successful leave.
126    (String) exit_msg - optional exit message.
127    Returns:
128    iqid - The unique id for the room leave.
129    */
130   leave: function(room, nick, handler_cb, exit_msg) {
131     var id, presence, presenceid, room_nick;
132     id = this.roomNames.indexOf(room);
133     delete this.rooms[room];
134     if (id >= 0) {
135       this.roomNames.splice(id, 1);
136       if (this.roomNames.length === 0) {
137         this._connection.deleteHandler(this._muc_handler);
138         this._muc_handler = null;
139       }
140     }
141     room_nick = this.test_append_nick(room, nick);
142     presenceid = this._connection.getUniqueId();
143     presence = $pres({
144       type: "unavailable",
145       id: presenceid,
146       from: this._connection.jid,
147       to: room_nick
148     });
149     if (exit_msg != null) {
150       presence.c("status", exit_msg);
151     }
152     if (handler_cb != null) {
153       this._connection.addHandler(handler_cb, null, "presence", null, presenceid);
154     }
155     this._connection.send(presence);
156     return presenceid;
157   },
158
159   /*Function
160    Parameters:
161    (String) room - The multi-user chat room name.
162    (String) nick - The nick name used in the chat room.
163    (String) message - The plaintext message to send to the room.
164    (String) html_message - The message to send to the room with html markup.
165    (String) type - "groupchat" for group chat messages o
166    "chat" for private chat messages
167    Returns:
168    msgiq - the unique id used to send the message
169    */
170   message: function(room, nick, message, html_message, type, msgid) {
171     var msg, parent, room_nick;
172     room_nick = this.test_append_nick(room, nick);
173     type = type || (nick != null ? "chat" : "groupchat");
174     msgid = msgid || this._connection.getUniqueId();
175     msg = $msg({
176       to: room_nick,
177       from: this._connection.jid,
178       type: type,
179       id: msgid
180     }).c("body").t(message);
181     msg.up();
182     if (html_message != null) {
183       msg.c("html", {
184         xmlns: Strophe.NS.XHTML_IM
185       }).c("body", {
186         xmlns: Strophe.NS.XHTML
187       }).h(html_message);
188       if (msg.node.childNodes.length === 0) {
189         parent = msg.node.parentNode;
190         msg.up().up();
191         msg.node.removeChild(parent);
192       } else {
193         msg.up().up();
194       }
195     }
196     msg.c("x", {
197       xmlns: "jabber:x:event"
198     }).c("composing");
199     this._connection.send(msg);
200     return msgid;
201   },
202
203   /*Function
204    Convenience Function to send a Message to all Occupants
205    Parameters:
206    (String) room - The multi-user chat room name.
207    (String) message - The plaintext message to send to the room.
208    (String) html_message - The message to send to the room with html markup.
209    (String) msgid - Optional unique ID which will be set as the 'id' attribute of the stanza
210    Returns:
211    msgiq - the unique id used to send the message
212    */
213   groupchat: function(room, message, html_message, msgid) {
214     return this.message(room, null, message, html_message, void 0, msgid);
215   },
216
217   /*Function
218    Send a mediated invitation.
219    Parameters:
220    (String) room - The multi-user chat room name.
221    (String) receiver - The invitation's receiver.
222    (String) reason - Optional reason for joining the room.
223    Returns:
224    msgiq - the unique id used to send the invitation
225    */
226   invite: function(room, receiver, reason) {
227     var invitation, msgid;
228     msgid = this._connection.getUniqueId();
229     invitation = $msg({
230       from: this._connection.jid,
231       to: room,
232       id: msgid
233     }).c('x', {
234       xmlns: Strophe.NS.MUC_USER
235     }).c('invite', {
236       to: receiver
237     });
238     if (reason != null) {
239       invitation.c('reason', reason);
240     }
241     this._connection.send(invitation);
242     return msgid;
243   },
244
245   /*Function
246    Send a mediated multiple invitation.
247    Parameters:
248    (String) room - The multi-user chat room name.
249    (Array) receivers - The invitation's receivers.
250    (String) reason - Optional reason for joining the room.
251    Returns:
252    msgiq - the unique id used to send the invitation
253    */
254   multipleInvites: function(room, receivers, reason) {
255     var i, invitation, len, msgid, receiver;
256     msgid = this._connection.getUniqueId();
257     invitation = $msg({
258       from: this._connection.jid,
259       to: room,
260       id: msgid
261     }).c('x', {
262       xmlns: Strophe.NS.MUC_USER
263     });
264     for (i = 0, len = receivers.length; i < len; i++) {
265       receiver = receivers[i];
266       invitation.c('invite', {
267         to: receiver
268       });
269       if (reason != null) {
270         invitation.c('reason', reason);
271         invitation.up();
272       }
273       invitation.up();
274     }
275     this._connection.send(invitation);
276     return msgid;
277   },
278
279   /*Function
280    Send a direct invitation.
281    Parameters:
282    (String) room - The multi-user chat room name.
283    (String) receiver - The invitation's receiver.
284    (String) reason - Optional reason for joining the room.
285    (String) password - Optional password for the room.
286    Returns:
287    msgiq - the unique id used to send the invitation
288    */
289   directInvite: function(room, receiver, reason, password) {
290     var attrs, invitation, msgid;
291     msgid = this._connection.getUniqueId();
292     attrs = {
293       xmlns: 'jabber:x:conference',
294       jid: room
295     };
296     if (reason != null) {
297       attrs.reason = reason;
298     }
299     if (password != null) {
300       attrs.password = password;
301     }
302     invitation = $msg({
303       from: this._connection.jid,
304       to: receiver,
305       id: msgid
306     }).c('x', attrs);
307     this._connection.send(invitation);
308     return msgid;
309   },
310
311   /*Function
312    Queries a room for a list of occupants
313    (String) room - The multi-user chat room name.
314    (Function) success_cb - Optional function to handle the info.
315    (Function) error_cb - Optional function to handle an error.
316    Returns:
317    id - the unique id used to send the info request
318    */
319   queryOccupants: function(room, success_cb, error_cb) {
320     var attrs, info;
321     attrs = {
322       xmlns: Strophe.NS.DISCO_ITEMS
323     };
324     info = $iq({
325       from: this._connection.jid,
326       to: room,
327       type: 'get'
328     }).c('query', attrs);
329     return this._connection.sendIQ(info, success_cb, error_cb);
330   },
331
332   /*Function
333    Start a room configuration.
334    Parameters:
335    (String) room - The multi-user chat room name.
336    (Function) handler_cb - Optional function to handle the config form.
337    Returns:
338    id - the unique id used to send the configuration request
339    */
340   configure: function(room, handler_cb, error_cb) {
341     var config, stanza;
342     config = $iq({
343       to: room,
344       type: "get"
345     }).c("query", {
346       xmlns: Strophe.NS.MUC_OWNER
347     });
348     stanza = config.tree();
349     return this._connection.sendIQ(stanza, handler_cb, error_cb);
350   },
351
352   /*Function
353    Cancel the room configuration
354    Parameters:
355    (String) room - The multi-user chat room name.
356    Returns:
357    id - the unique id used to cancel the configuration.
358    */
359   cancelConfigure: function(room) {
360     var config, stanza;
361     config = $iq({
362       to: room,
363       type: "set"
364     }).c("query", {
365       xmlns: Strophe.NS.MUC_OWNER
366     }).c("x", {
367       xmlns: "jabber:x:data",
368       type: "cancel"
369     });
370     stanza = config.tree();
371     return this._connection.sendIQ(stanza);
372   },
373
374   /*Function
375    Save a room configuration.
376    Parameters:
377    (String) room - The multi-user chat room name.
378    (Array) config- Form Object or an array of form elements used to configure the room.
379    Returns:
380    id - the unique id used to save the configuration.
381    */
382   saveConfiguration: function(room, config, success_cb, error_cb) {
383     var conf, i, iq, len, stanza;
384     iq = $iq({
385       to: room,
386       type: "set"
387     }).c("query", {
388       xmlns: Strophe.NS.MUC_OWNER
389     });
390     if (typeof Strophe.x !== "undefined" && typeof Strophe.x.Form !== "undefined" && config instanceof Strophe.x.Form) {
391       config.type = "submit";
392       iq.cnode(config.toXML());
393     } else {
394       iq.c("x", {
395         xmlns: "jabber:x:data",
396         type: "submit"
397       });
398       for (i = 0, len = config.length; i < len; i++) {
399         conf = config[i];
400         iq.cnode(conf).up();
401       }
402     }
403     stanza = iq.tree();
404     return this._connection.sendIQ(stanza, success_cb, error_cb);
405   },
406
407   /*Function
408    Parameters:
409    (String) room - The multi-user chat room name.
410    Returns:
411    id - the unique id used to create the chat room.
412    */
413   createInstantRoom: function(room, success_cb, error_cb) {
414     var roomiq;
415     roomiq = $iq({
416       to: room,
417       type: "set"
418     }).c("query", {
419       xmlns: Strophe.NS.MUC_OWNER
420     }).c("x", {
421       xmlns: "jabber:x:data",
422       type: "submit"
423     });
424     return this._connection.sendIQ(roomiq.tree(), success_cb, error_cb);
425   },
426
427   /*Function
428    Parameters:
429    (String) room - The multi-user chat room name.
430    (Object) config - the configuration. ex: {"muc#roomconfig_publicroom": "0", "muc#roomconfig_persistentroom": "1"}
431    Returns:
432    id - the unique id used to create the chat room.
433    */
434   createConfiguredRoom: function(room, config, success_cb, error_cb) {
435     var k, roomiq, v;
436     roomiq = $iq({
437       to: room,
438       type: "set"
439     }).c("query", {
440       xmlns: Strophe.NS.MUC_OWNER
441     }).c("x", {
442       xmlns: "jabber:x:data",
443       type: "submit"
444     });
445     roomiq.c('field', {
446       'var': 'FORM_TYPE'
447     }).c('value').t('http://jabber.org/protocol/muc#roomconfig').up().up();
448     for (k in config) {
449       if (!hasProp.call(config, k)) continue;
450       v = config[k];
451       roomiq.c('field', {
452         'var': k
453       }).c('value').t(v).up().up();
454     }
455     return this._connection.sendIQ(roomiq.tree(), success_cb, error_cb);
456   },
457
458   /*Function
459    Set the topic of the chat room.
460    Parameters:
461    (String) room - The multi-user chat room name.
462    (String) topic - Topic message.
463    */
464   setTopic: function(room, topic) {
465     var msg;
466     msg = $msg({
467       to: room,
468       from: this._connection.jid,
469       type: "groupchat"
470     }).c("subject", {
471       xmlns: "jabber:client"
472     }).t(topic);
473     return this._connection.send(msg.tree());
474   },
475
476   /*Function
477    Internal Function that Changes the role or affiliation of a member
478    of a MUC room. This function is used by modifyRole and modifyAffiliation.
479    The modification can only be done by a room moderator. An error will be
480    returned if the user doesn't have permission.
481    Parameters:
482    (String) room - The multi-user chat room name.
483    (Object) item - Object with nick and role or jid and affiliation attribute
484    (String) reason - Optional reason for the change.
485    (Function) handler_cb - Optional callback for success
486    (Function) error_cb - Optional callback for error
487    Returns:
488    iq - the id of the mode change request.
489    */
490   _modifyPrivilege: function(room, item, reason, handler_cb, error_cb) {
491     var iq;
492     iq = $iq({
493       to: room,
494       type: "set"
495     }).c("query", {
496       xmlns: Strophe.NS.MUC_ADMIN
497     }).cnode(item.node);
498     if (reason != null) {
499       iq.c("reason", reason);
500     }
501     return this._connection.sendIQ(iq.tree(), handler_cb, error_cb);
502   },
503
504   /*Function
505    Changes the role of a member of a MUC room.
506    The modification can only be done by a room moderator. An error will be
507    returned if the user doesn't have permission.
508    Parameters:
509    (String) room - The multi-user chat room name.
510    (String) nick - The nick name of the user to modify.
511    (String) role - The new role of the user.
512    (String) affiliation - The new affiliation of the user.
513    (String) reason - Optional reason for the change.
514    (Function) handler_cb - Optional callback for success
515    (Function) error_cb - Optional callback for error
516    Returns:
517    iq - the id of the mode change request.
518    */
519   modifyRole: function(room, nick, role, reason, handler_cb, error_cb) {
520     var item;
521     item = $build("item", {
522       nick: nick,
523       role: role
524     });
525     return this._modifyPrivilege(room, item, reason, handler_cb, error_cb);
526   },
527   kick: function(room, nick, reason, handler_cb, error_cb) {
528     return this.modifyRole(room, nick, 'none', reason, handler_cb, error_cb);
529   },
530   voice: function(room, nick, reason, handler_cb, error_cb) {
531     return this.modifyRole(room, nick, 'participant', reason, handler_cb, error_cb);
532   },
533   mute: function(room, nick, reason, handler_cb, error_cb) {
534     return this.modifyRole(room, nick, 'visitor', reason, handler_cb, error_cb);
535   },
536   op: function(room, nick, reason, handler_cb, error_cb) {
537     return this.modifyRole(room, nick, 'moderator', reason, handler_cb, error_cb);
538   },
539   deop: function(room, nick, reason, handler_cb, error_cb) {
540     return this.modifyRole(room, nick, 'participant', reason, handler_cb, error_cb);
541   },
542
543   /*Function
544    Changes the affiliation of a member of a MUC room.
545    The modification can only be done by a room moderator. An error will be
546    returned if the user doesn't have permission.
547    Parameters:
548    (String) room - The multi-user chat room name.
549    (String) jid  - The jid of the user to modify.
550    (String) affiliation - The new affiliation of the user.
551    (String) reason - Optional reason for the change.
552    (Function) handler_cb - Optional callback for success
553    (Function) error_cb - Optional callback for error
554    Returns:
555    iq - the id of the mode change request.
556    */
557   modifyAffiliation: function(room, jid, affiliation, reason, handler_cb, error_cb) {
558     var item;
559     item = $build("item", {
560       jid: jid,
561       affiliation: affiliation
562     });
563     return this._modifyPrivilege(room, item, reason, handler_cb, error_cb);
564   },
565   ban: function(room, jid, reason, handler_cb, error_cb) {
566     return this.modifyAffiliation(room, jid, 'outcast', reason, handler_cb, error_cb);
567   },
568   member: function(room, jid, reason, handler_cb, error_cb) {
569     return this.modifyAffiliation(room, jid, 'member', reason, handler_cb, error_cb);
570   },
571   revoke: function(room, jid, reason, handler_cb, error_cb) {
572     return this.modifyAffiliation(room, jid, 'none', reason, handler_cb, error_cb);
573   },
574   owner: function(room, jid, reason, handler_cb, error_cb) {
575     return this.modifyAffiliation(room, jid, 'owner', reason, handler_cb, error_cb);
576   },
577   admin: function(room, jid, reason, handler_cb, error_cb) {
578     return this.modifyAffiliation(room, jid, 'admin', reason, handler_cb, error_cb);
579   },
580
581   /*Function
582    Change the current users nick name.
583    Parameters:
584    (String) room - The multi-user chat room name.
585    (String) user - The new nick name.
586    */
587   changeNick: function(room, user) {
588     var presence, room_nick;
589     room_nick = this.test_append_nick(room, user);
590     presence = $pres({
591       from: this._connection.jid,
592       to: room_nick,
593       id: this._connection.getUniqueId()
594     });
595     return this._connection.send(presence.tree());
596   },
597
598   /*Function
599    Change the current users status.
600    Parameters:
601    (String) room - The multi-user chat room name.
602    (String) user - The current nick.
603    (String) show - The new show-text.
604    (String) status - The new status-text.
605    */
606   setStatus: function(room, user, show, status) {
607     var presence, room_nick;
608     room_nick = this.test_append_nick(room, user);
609     presence = $pres({
610       from: this._connection.jid,
611       to: room_nick
612     });
613     if (show != null) {
614       presence.c('show', show).up();
615     }
616     if (status != null) {
617       presence.c('status', status);
618     }
619     return this._connection.send(presence.tree());
620   },
621
622   /*Function
623    Registering with a room.
624    @see http://xmpp.org/extensions/xep-0045.html#register
625    Parameters:
626    (String) room - The multi-user chat room name.
627    (Function) handle_cb - Function to call for room list return.
628    (Function) error_cb - Function to call on error.
629    */
630   registrationRequest: function(room, handle_cb, error_cb) {
631     var iq;
632     iq = $iq({
633       to: room,
634       from: this._connection.jid,
635       type: "get"
636     }).c("query", {
637       xmlns: Strophe.NS.MUC_REGISTER
638     });
639     return this._connection.sendIQ(iq, function(stanza) {
640       var $field, $fields, field, fields, i, len, length;
641       $fields = stanza.getElementsByTagName('field');
642       length = $fields.length;
643       fields = {
644         required: [],
645         optional: []
646       };
647       for (i = 0, len = $fields.length; i < len; i++) {
648         $field = $fields[i];
649         field = {
650           "var": $field.getAttribute('var'),
651           label: $field.getAttribute('label'),
652           type: $field.getAttribute('type')
653         };
654         if ($field.getElementsByTagName('required').length > 0) {
655           fields.required.push(field);
656         } else {
657           fields.optional.push(field);
658         }
659       }
660       return handle_cb(fields);
661     }, error_cb);
662   },
663
664   /*Function
665    Submits registration form.
666    Parameters:
667    (String) room - The multi-user chat room name.
668    (Function) handle_cb - Function to call for room list return.
669    (Function) error_cb - Function to call on error.
670    */
671   submitRegistrationForm: function(room, fields, handle_cb, error_cb) {
672     var iq, key, val;
673     iq = $iq({
674       to: room,
675       type: "set"
676     }).c("query", {
677       xmlns: Strophe.NS.MUC_REGISTER
678     });
679     iq.c("x", {
680       xmlns: "jabber:x:data",
681       type: "submit"
682     });
683     iq.c('field', {
684       'var': 'FORM_TYPE'
685     }).c('value').t('http://jabber.org/protocol/muc#register').up().up();
686     for (key in fields) {
687       val = fields[key];
688       iq.c('field', {
689         'var': key
690       }).c('value').t(val).up().up();
691     }
692     return this._connection.sendIQ(iq, handle_cb, error_cb);
693   },
694
695   /*Function
696    List all chat room available on a server.
697    Parameters:
698    (String) server - name of chat server.
699    (String) handle_cb - Function to call for room list return.
700    (String) error_cb - Function to call on error.
701    */
702   listRooms: function(server, handle_cb, error_cb) {
703     var iq;
704     iq = $iq({
705       to: server,
706       from: this._connection.jid,
707       type: "get"
708     }).c("query", {
709       xmlns: Strophe.NS.DISCO_ITEMS
710     });
711     return this._connection.sendIQ(iq, handle_cb, error_cb);
712   },
713   test_append_nick: function(room, nick) {
714     var domain, node;
715     node = Strophe.escapeNode(Strophe.getNodeFromJid(room));
716     domain = Strophe.getDomainFromJid(room);
717     return node + "@" + domain + (nick != null ? "/" + nick : "");
718   }
719 });
720
721 XmppRoom = (function() {
722   function XmppRoom(client, name1, nick1, password1) {
723     this.client = client;
724     this.name = name1;
725     this.nick = nick1;
726     this.password = password1;
727     this._roomRosterHandler = bind(this._roomRosterHandler, this);
728     this._addOccupant = bind(this._addOccupant, this);
729     this.roster = {};
730     this._message_handlers = {};
731     this._presence_handlers = {};
732     this._roster_handlers = {};
733     this._handler_ids = 0;
734     if (this.client.muc) {
735       this.client = this.client.muc;
736     }
737     this.name = Strophe.getBareJidFromJid(this.name);
738     this.addHandler('presence', this._roomRosterHandler);
739   }
740
741   XmppRoom.prototype.join = function(msg_handler_cb, pres_handler_cb, roster_cb) {
742     return this.client.join(this.name, this.nick, msg_handler_cb, pres_handler_cb, roster_cb, this.password);
743   };
744
745   XmppRoom.prototype.leave = function(handler_cb, message) {
746     this.client.leave(this.name, this.nick, handler_cb, message);
747     return delete this.client.rooms[this.name];
748   };
749
750   XmppRoom.prototype.message = function(nick, message, html_message, type) {
751     return this.client.message(this.name, nick, message, html_message, type);
752   };
753
754   XmppRoom.prototype.groupchat = function(message, html_message) {
755     return this.client.groupchat(this.name, message, html_message);
756   };
757
758   XmppRoom.prototype.invite = function(receiver, reason) {
759     return this.client.invite(this.name, receiver, reason);
760   };
761
762   XmppRoom.prototype.multipleInvites = function(receivers, reason) {
763     return this.client.invite(this.name, receivers, reason);
764   };
765
766   XmppRoom.prototype.directInvite = function(receiver, reason) {
767     return this.client.directInvite(this.name, receiver, reason, this.password);
768   };
769
770   XmppRoom.prototype.configure = function(handler_cb) {
771     return this.client.configure(this.name, handler_cb);
772   };
773
774   XmppRoom.prototype.cancelConfigure = function() {
775     return this.client.cancelConfigure(this.name);
776   };
777
778   XmppRoom.prototype.saveConfiguration = function(config) {
779     return this.client.saveConfiguration(this.name, config);
780   };
781
782   XmppRoom.prototype.queryOccupants = function(success_cb, error_cb) {
783     return this.client.queryOccupants(this.name, success_cb, error_cb);
784   };
785
786   XmppRoom.prototype.setTopic = function(topic) {
787     return this.client.setTopic(this.name, topic);
788   };
789
790   XmppRoom.prototype.modifyRole = function(nick, role, reason, success_cb, error_cb) {
791     return this.client.modifyRole(this.name, nick, role, reason, success_cb, error_cb);
792   };
793
794   XmppRoom.prototype.kick = function(nick, reason, handler_cb, error_cb) {
795     return this.client.kick(this.name, nick, reason, handler_cb, error_cb);
796   };
797
798   XmppRoom.prototype.voice = function(nick, reason, handler_cb, error_cb) {
799     return this.client.voice(this.name, nick, reason, handler_cb, error_cb);
800   };
801
802   XmppRoom.prototype.mute = function(nick, reason, handler_cb, error_cb) {
803     return this.client.mute(this.name, nick, reason, handler_cb, error_cb);
804   };
805
806   XmppRoom.prototype.op = function(nick, reason, handler_cb, error_cb) {
807     return this.client.op(this.name, nick, reason, handler_cb, error_cb);
808   };
809
810   XmppRoom.prototype.deop = function(nick, reason, handler_cb, error_cb) {
811     return this.client.deop(this.name, nick, reason, handler_cb, error_cb);
812   };
813
814   XmppRoom.prototype.modifyAffiliation = function(jid, affiliation, reason, success_cb, error_cb) {
815     return this.client.modifyAffiliation(this.name, jid, affiliation, reason, success_cb, error_cb);
816   };
817
818   XmppRoom.prototype.ban = function(jid, reason, handler_cb, error_cb) {
819     return this.client.ban(this.name, jid, reason, handler_cb, error_cb);
820   };
821
822   XmppRoom.prototype.member = function(jid, reason, handler_cb, error_cb) {
823     return this.client.member(this.name, jid, reason, handler_cb, error_cb);
824   };
825
826   XmppRoom.prototype.revoke = function(jid, reason, handler_cb, error_cb) {
827     return this.client.revoke(this.name, jid, reason, handler_cb, error_cb);
828   };
829
830   XmppRoom.prototype.owner = function(jid, reason, handler_cb, error_cb) {
831     return this.client.owner(this.name, jid, reason, handler_cb, error_cb);
832   };
833
834   XmppRoom.prototype.admin = function(jid, reason, handler_cb, error_cb) {
835     return this.client.admin(this.name, jid, reason, handler_cb, error_cb);
836   };
837
838   XmppRoom.prototype.changeNick = function(nick1) {
839     this.nick = nick1;
840     return this.client.changeNick(this.name, nick);
841   };
842
843   XmppRoom.prototype.setStatus = function(show, status) {
844     return this.client.setStatus(this.name, this.nick, show, status);
845   };
846
847
848   /*Function
849    Adds a handler to the MUC room.
850    Parameters:
851    (String) handler_type - 'message', 'presence' or 'roster'.
852    (Function) handler - The handler function.
853    Returns:
854    id - the id of handler.
855    */
856
857   XmppRoom.prototype.addHandler = function(handler_type, handler) {
858     var id;
859     id = this._handler_ids++;
860     switch (handler_type) {
861       case 'presence':
862         this._presence_handlers[id] = handler;
863         break;
864       case 'message':
865         this._message_handlers[id] = handler;
866         break;
867       case 'roster':
868         this._roster_handlers[id] = handler;
869         break;
870       default:
871         this._handler_ids--;
872         return null;
873     }
874     return id;
875   };
876
877
878   /*Function
879    Removes a handler from the MUC room.
880    This function takes ONLY ids returned by the addHandler function
881    of this room. passing handler ids returned by connection.addHandler
882    may brake things!
883    Parameters:
884    (number) id - the id of the handler
885    */
886
887   XmppRoom.prototype.removeHandler = function(id) {
888     delete this._presence_handlers[id];
889     delete this._message_handlers[id];
890     return delete this._roster_handlers[id];
891   };
892
893
894   /*Function
895    Creates and adds an Occupant to the Room Roster.
896    Parameters:
897    (Object) data - the data the Occupant is filled with
898    Returns:
899    occ - the created Occupant.
900    */
901
902   XmppRoom.prototype._addOccupant = function(data) {
903     var occ;
904     occ = new Occupant(data, this);
905     this.roster[occ.nick] = occ;
906     return occ;
907   };
908
909
910   /*Function
911    The standard handler that managed the Room Roster.
912    Parameters:
913    (Object) pres - the presence stanza containing user information
914    */
915
916   XmppRoom.prototype._roomRosterHandler = function(pres) {
917     var data, handler, id, newnick, nick, ref;
918     data = XmppRoom._parsePresence(pres);
919     nick = data.nick;
920     newnick = data.newnick || null;
921     switch (data.type) {
922       case 'error':
923         return true;
924       case 'unavailable':
925         if (newnick) {
926           data.nick = newnick;
927           if (this.roster[nick] && this.roster[newnick]) {
928             this.roster[nick].update(this.roster[newnick]);
929             this.roster[newnick] = this.roster[nick];
930           }
931           if (this.roster[nick] && !this.roster[newnick]) {
932             this.roster[newnick] = this.roster[nick].update(data);
933           }
934         }
935         delete this.roster[nick];
936         break;
937       default:
938         if (this.roster[nick]) {
939           this.roster[nick].update(data);
940         } else {
941           this._addOccupant(data);
942         }
943     }
944     ref = this._roster_handlers;
945     for (id in ref) {
946       handler = ref[id];
947       if (!handler(this.roster, this)) {
948         delete this._roster_handlers[id];
949       }
950     }
951     return true;
952   };
953
954
955   /*Function
956    Parses a presence stanza
957    Parameters:
958    (Object) data - the data extracted from the presence stanza
959    */
960
961   XmppRoom._parsePresence = function(pres) {
962     var c, c2, data, i, j, len, len1, ref, ref1;
963     data = {};
964     data.nick = Strophe.getResourceFromJid(pres.getAttribute("from"));
965     data.type = pres.getAttribute("type");
966     data.states = [];
967     ref = pres.childNodes;
968     for (i = 0, len = ref.length; i < len; i++) {
969       c = ref[i];
970       switch (c.nodeName) {
971         case "status":
972           data.status = c.textContent || null;
973           break;
974         case "show":
975           data.show = c.textContent || null;
976           break;
977         case "x":
978           if (c.getAttribute("xmlns") === Strophe.NS.MUC_USER) {
979             ref1 = c.childNodes;
980             for (j = 0, len1 = ref1.length; j < len1; j++) {
981               c2 = ref1[j];
982               switch (c2.nodeName) {
983                 case "item":
984                   data.affiliation = c2.getAttribute("affiliation");
985                   data.role = c2.getAttribute("role");
986                   data.jid = c2.getAttribute("jid");
987                   data.newnick = c2.getAttribute("nick");
988                   break;
989                 case "status":
990                   if (c2.getAttribute("code")) {
991                     data.states.push(c2.getAttribute("code"));
992                   }
993               }
994             }
995           }
996       }
997     }
998     return data;
999   };
1000
1001   return XmppRoom;
1002
1003 })();
1004
1005 RoomConfig = (function() {
1006   function RoomConfig(info) {
1007     this.parse = bind(this.parse, this);
1008     if (info != null) {
1009       this.parse(info);
1010     }
1011   }
1012
1013   RoomConfig.prototype.parse = function(result) {
1014     var attr, attrs, child, field, i, identity, j, l, len, len1, len2, query, ref;
1015     query = result.getElementsByTagName("query")[0].childNodes;
1016     this.identities = [];
1017     this.features = [];
1018     this.x = [];
1019     for (i = 0, len = query.length; i < len; i++) {
1020       child = query[i];
1021       attrs = child.attributes;
1022       switch (child.nodeName) {
1023         case "identity":
1024           identity = {};
1025           for (j = 0, len1 = attrs.length; j < len1; j++) {
1026             attr = attrs[j];
1027             identity[attr.name] = attr.textContent;
1028           }
1029           this.identities.push(identity);
1030           break;
1031         case "feature":
1032           this.features.push(child.getAttribute("var"));
1033           break;
1034         case "x":
1035           if ((!child.childNodes[0].getAttribute("var") === 'FORM_TYPE') || (!child.childNodes[0].getAttribute("type") === 'hidden')) {
1036             break;
1037           }
1038           ref = child.childNodes;
1039           for (l = 0, len2 = ref.length; l < len2; l++) {
1040             field = ref[l];
1041             if (!field.attributes.type) {
1042               this.x.push({
1043                 "var": field.getAttribute("var"),
1044                 label: field.getAttribute("label") || "",
1045                 value: field.firstChild.textContent || ""
1046               });
1047             }
1048           }
1049       }
1050     }
1051     return {
1052       "identities": this.identities,
1053       "features": this.features,
1054       "x": this.x
1055     };
1056   };
1057
1058   return RoomConfig;
1059
1060 })();
1061
1062 Occupant = (function() {
1063   function Occupant(data, room1) {
1064     this.room = room1;
1065     this.update = bind(this.update, this);
1066     this.admin = bind(this.admin, this);
1067     this.owner = bind(this.owner, this);
1068     this.revoke = bind(this.revoke, this);
1069     this.member = bind(this.member, this);
1070     this.ban = bind(this.ban, this);
1071     this.modifyAffiliation = bind(this.modifyAffiliation, this);
1072     this.deop = bind(this.deop, this);
1073     this.op = bind(this.op, this);
1074     this.mute = bind(this.mute, this);
1075     this.voice = bind(this.voice, this);
1076     this.kick = bind(this.kick, this);
1077     this.modifyRole = bind(this.modifyRole, this);
1078     this.update(data);
1079   }
1080
1081   Occupant.prototype.modifyRole = function(role, reason, success_cb, error_cb) {
1082     return this.room.modifyRole(this.nick, role, reason, success_cb, error_cb);
1083   };
1084
1085   Occupant.prototype.kick = function(reason, handler_cb, error_cb) {
1086     return this.room.kick(this.nick, reason, handler_cb, error_cb);
1087   };
1088
1089   Occupant.prototype.voice = function(reason, handler_cb, error_cb) {
1090     return this.room.voice(this.nick, reason, handler_cb, error_cb);
1091   };
1092
1093   Occupant.prototype.mute = function(reason, handler_cb, error_cb) {
1094     return this.room.mute(this.nick, reason, handler_cb, error_cb);
1095   };
1096
1097   Occupant.prototype.op = function(reason, handler_cb, error_cb) {
1098     return this.room.op(this.nick, reason, handler_cb, error_cb);
1099   };
1100
1101   Occupant.prototype.deop = function(reason, handler_cb, error_cb) {
1102     return this.room.deop(this.nick, reason, handler_cb, error_cb);
1103   };
1104
1105   Occupant.prototype.modifyAffiliation = function(affiliation, reason, success_cb, error_cb) {
1106     return this.room.modifyAffiliation(this.jid, affiliation, reason, success_cb, error_cb);
1107   };
1108
1109   Occupant.prototype.ban = function(reason, handler_cb, error_cb) {
1110     return this.room.ban(this.jid, reason, handler_cb, error_cb);
1111   };
1112
1113   Occupant.prototype.member = function(reason, handler_cb, error_cb) {
1114     return this.room.member(this.jid, reason, handler_cb, error_cb);
1115   };
1116
1117   Occupant.prototype.revoke = function(reason, handler_cb, error_cb) {
1118     return this.room.revoke(this.jid, reason, handler_cb, error_cb);
1119   };
1120
1121   Occupant.prototype.owner = function(reason, handler_cb, error_cb) {
1122     return this.room.owner(this.jid, reason, handler_cb, error_cb);
1123   };
1124
1125   Occupant.prototype.admin = function(reason, handler_cb, error_cb) {
1126     return this.room.admin(this.jid, reason, handler_cb, error_cb);
1127   };
1128
1129   Occupant.prototype.update = function(data) {
1130     this.nick = data.nick || null;
1131     this.affiliation = data.affiliation || null;
1132     this.role = data.role || null;
1133     this.jid = data.jid || null;
1134     this.status = data.status || null;
1135     this.show = data.show || null;
1136     return this;
1137   };
1138
1139   return Occupant;
1140
1141 })();
1142
1143 // ---
1144 // generated by coffee-script 1.9.2