1 from xmpp import *
2 import types
3 import copy
4
5 import pickle
6
7
9 '''
10 The user provided a wrong password
11 '''
14 '''
15 The user is not a member of the room
16 '''
19 '''
20 The user is in the black list of the room
21 '''
24 '''
25 The maximum number of users for this room has been reached
26 '''
29 '''
30 The user has no voice in this room
31 '''
34 '''
35 The nickname that the user is trying to set is already locked down
36 '''
38
40 """
41 A client that participates in a MUC room
42 """
43 - def __init__(self, fulljid, barejid=None, nick=None, role=None, affiliation=None):
44
45 self.fulljid = fulljid
46
47 if not barejid:
48 self.barejid = str(fulljid).split('/')[0]
49 else:
50 self.barejid = barejid
51
52 if not nick:
53 self.nick = self.barejid
54 else:
55 self.nick = nick
56
57 if not role:
58 self.role = 'none'
59 else:
60 self.role = role
61
62 if not affiliation:
63 self.affiliation = 'none'
64 else:
65 self.affiliation = affiliation
66
68 return '<' + str(self.fulljid) + ' barejid="' + str(self.barejid) + '" nick="' + str(self.nick) + '" role="' + str(self.role) + '" affiliation="' + str(self.affiliation) + '">'
69
71 """
72 Get the participant's full JID
73 """
74 return self.fulljid
75
77 """
78 Get the participant's bare JID
79 """
80 return self.barejid
81
83 """
84 Get the participant's nickname
85 """
86 return self.nick
87
89 """
90 Get the participant's role
91 """
92 if self.role:
93 return self.role.lower()
94 else:
95 return 'none'
96
98 """
99 Get the participant's affiliation
100 """
101 if self.affiliation:
102 return self.affiliation.lower()
103 else:
104 return 'none'
105
107 """
108 Set the participant's full JID
109 """
110 self.fulljid = fulljid
111
113 """
114 Set the participant's bare JID
115 """
116 self.barejid = barejid
117
119 """
120 Set the participant's nickname
121 """
122 self.nick = nick
123
125 """
126 Set the participant's role
127 """
128 self.role = role
129
131 """
132 Set the participant's affiliation
133 """
134 self.affiliation = affiliation
135
136
138 """
139 A serializable (reduced) version of a Room
140 """
142
143 self.config = orig.config
144 self.name = orig.name
145 self.locked = orig.locked
146 self.role_privileges = orig.role_privileges
147 self.subject = orig.getSubject()
148 self.whitelist = orig.whitelist
149 self.blacklist = orig.blacklist
150 self.creator = orig.creator
151
153 """
154 A MUC room
155 """
156 - def __init__(self, name, muc, subject=None, template=None, creator=None, whitelist=[], blacklist=[], password=None):
157
158 self.config = {}
159
160
161 self.muc = muc
162
163 self.name = name
164 self.config['muc#roomconfig_roomname'] = ""
165 self.config['muc#roomconfig_roomdesc'] = ""
166 self.config['muc#roomconfig_enablelogging'] = 0
167 self.config['muc#roomconfig_lang'] = "en"
168 self.config['muc#roomconfig_changesubject'] = 1
169 self.config['muc#roomconfig_allowinvites'] = 0
170 self.config['muc#roomconfig_maxusers'] = 100
171 self.config['muc#roomconfig_minusers'] = 1
172 self.config['muc#roomconfig_presencebroadcast'] = ["moderator","participant","visitor"]
173 self.config['muc#roomconfig_publicroom'] = 1
174 self.config['muc#roomconfig_persistentroom'] = 0
175 self.config['muc#roomconfig_moderatedroom'] = 0
176 self.config['muc#roomconfig_allowregister'] = 0
177 self.config['muc#roomconfig_nicklockdown'] = 0
178 self.config['muc#roomconfig_membersonly'] = 0
179 self.config['muc#roomconfig_passwordprotectedroom'] = 0
180 self.config['muc#roomconfig_roomsecret'] = ""
181 self.config['muc#roomconfig_whois'] = ""
182 self.config['muc#roomconfig_roomadmins'] = []
183 self.config['muc#roomconfig_roomowners'] = []
184
185
186 self.DEBUG = self.muc.DEBUG
187
188
189
190
191
192
193
194
195
196
197 self.locked = False
198
199
200
201
202
203 self.role_privileges = {}
204 self.role_privileges['change_nick'] = 'visitor'
205 self.role_privileges['send_private'] = 'visitor'
206 self.role_privileges['invite'] = 'visitor'
207 self.role_privileges['send'] = 'participant'
208 self.role_privileges['subject'] = 'participant'
209
210
211 if not subject:
212
213 self.setSubject("")
214 else:
215
216 self.setSubject(subject)
217
218 if template:
219 self.DEBUG("TODO: Implement room templates",'warn')
220
221
222 self.whitelist = copy.copy(whitelist)
223 self.blacklist = copy.copy(blacklist)
224
225
226
227 self.moderators = []
228 self.visitors = []
229
230 self.participants = {}
231
232
233
234
235
236
237 self.reserved_nicks = {}
238
239
240 if creator:
241 self.creator = creator
242
243 self.addRoomOwner(creator.getBareJID())
244
245 if self.isModeratedRoom():
246 creator.setRole('moderator')
247 else:
248 creator.setRole('participant')
249 creator.setAffiliation('owner')
250 self.participants[creator.getFullJID()] = creator
251 self.reserved_nicks[creator.getBareJID()] = creator.getNick()
252 else:
253 self.creator = None
254
255
257 """
258 Get the room's true Name
259 """
260 return self.name
262 """
263 Set the room's true Name
264 """
265 self.name = str(n)
267 """
268 Get the room's RoomName (display name)
269 """
270 return self.config["muc#roomconfig_roomname"]
272 """
273 Set the room's RoomName (display name)
274 """
275 self.config["muc#roomconfig_roomname"] = name
277 """
278 Get the room's Subject (topic)
279 """
280 return self.subject
282 """
283 Set the room's Subject (topic)
284 """
285 self.subject = name
287 """
288 Get the room's Description
289 """
290 return self.config["muc#roomconfig_roomdesc"]
292 """
293 Set the room's Description
294 """
295 self.config["muc#roomconfig_roomdesc"] = name
297 """
298 Check if message logging is enabled in the room
299 """
300 return self.config["muc#roomconfig_enablelogging"]
302 """
303 Enable or disable message logging in the room
304 """
305 if val in [0,'0',False]: val = 0
306 else: val = 1
307 self.config["muc#roomconfig_enablelogging"] = val
309 """
310 Get the language used in the room
311 """
312 return self.config["muc#roomconfig_lang"]
314 """
315 Set the language used in the room
316 """
317 self.config["muc#roomconfig_lang"] = name
319 """
320 Check wether the subject can be changed in the room
321 """
322 return self.config["muc#roomconfig_changesubject"]
324 """
325 Allow or disallow users to change the subject of the room
326 """
327 if val in [0,'0',False]: val = 0
328 else: val = 1
329 self.config["muc#roomconfig_changesubject"] = val
331 """
332 Check wether invitations are allowed in the room
333 """
334 return self.config["muc#roomconfig_allowinvites"]
336 """
337 Enable or disable invitations to the room
338 """
339 if val in [0,'0',False]: val = 0
340 else: val = 1
341 self.config["muc#roomconfig_allowinvites"] = val
343 """
344 Gets maximum number of concurrent users in the room
345 """
346 return self.config["muc#roomconfig_maxusers"]
348 """
349 Gets maximum number of concurrent users in the room
350 """
351 try:
352 im = int(m)
353 self.config["muc#roomconfig_maxusers"] = im
354 except:
355 self.config["muc#roomconfig_maxusers"] = 0
356 return
358 """
359 Gets minimum number of concurrent users in the room
360 """
361 return self.config["muc#roomconfig_minusers"]
363 """
364 Gets maximum number of concurrent users in the room
365 """
366 try:
367 im = int(m)
368 self.config["muc#roomconfig_minusers"] = im
369 except:
370 self.config["muc#roomconfig_minusers"] = 0
371 return
373 """
374 Get the list of roles which receive presence stanzas broadcasted in the room
375 """
376 return self.config["muc#roomconfig_presencebroadcast"]
378 """
379 Add a role to the list of roles which receive presence stanzas broadcasted in the room
380 """
381 if name not in self.config["muc#roomconfig_presencebroadcast"]:
382 self.config["muc#roomconfig_presencebroadcast"].append(name)
384 """
385 Remove a role from the list of roles which receive presence stanzas broadcasted in the room
386 """
387 if name in self.config["muc#roomconfig_presencebroadcast"]:
388 self.config["muc#roomconfig_presencebroadcast"].remove(name)
390 """
391 Check wether the room is public
392 """
393 return self.config["muc#roomconfig_publicroom"]
395 """
396 Stablish wether the room public or not. If a room is not public, then it is hidden
397 """
398 if val in [0,'0',False]: val = 0
399 else: val = 1
400 self.config["muc#roomconfig_publicroom"] = val
402 """
403 Check wether the room is persistent
404 """
405 return self.config["muc#roomconfig_persistentroom"]
407 """
408 Set the persistency of the room. If the room is not persistent, then it is temporary
409 """
410 if val in [0,'0',False]: val = 0
411 else: val = 1
412 self.config["muc#roomconfig_persistentroom"] = val
414 """
415 Check wether the room is moderated
416 """
417 return self.config["muc#roomconfig_moderatedroom"]
419 """
420 Make the room (un)moderated. All the required notifications and role changes will take effect
421 """
422 if val in [0,'0',False]:
423 self.config["muc#roomconfig_moderatedroom"] = 0
424 for j in self.visitors+self.moderators:
425 for k in self.participants.keys():
426 if j in k:
427 self.participants[k].setRole('participant')
428 try:
429 self.visitors.remove(j)
430 except:
431 self.moderators.remove(j)
432 for k,to in self.participants.items():
433
434 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
435 relative_frm = self.fullJID() + '/' + to.getNick()
436 newitem = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole(), 'nick':to.getNick() } )
437 for other in self.participants.values():
438 if self.getWhois()== "anyone" \
439 or self.getWhois() == "moderators" and to.getRole() == "moderator":
440 newitem.setAttr('jid', other.getFullJID())
441 x.addChild(node=newitem)
442
443 reply = Presence( other.getFullJID(), frm=relative_frm )
444 reply.addChild(node=x)
445 s = self.muc.server.getsession(other.getFullJID())
446 if s:
447 s.enqueue(reply)
448
449 else:
450 self.DEBUG("Room %s set to be Moderated"%(self.getName()),"info")
451 self.config["muc#roomconfig_moderatedroom"] = 1
452 for k,to in self.participants.items():
453 self.DEBUG("Checking %s with affiliation %s"%(to.getNick(),to.getAffiliation()))
454 if to.getAffiliation() in ['admin','owner']:
455 to.setRole("moderator")
456 try:
457 if to.getBareJID() in self.visitors:
458 self.visitors.remove(to.getBareJID())
459 if to.getBareJID() not in self.moderators:
460 self.moderators.append(to.getBareJID())
461 self.DEBUG("Changed role of %s to moderator"%(to.getBareJID()),"ok")
462 except:
463 self.DEBUG("Could not change role for %s"%(to.getBareJID()),"error")
464 return
465
466
467 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
468 relative_frm = self.fullJID() + '/' + to.getNick()
469 newitem = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole(), 'nick':to.getNick() } )
470 for other in self.participants.values():
471 if self.getWhois()== "anyone" \
472 or self.getWhois() == "moderators" and to.getRole() == "moderator":
473 newitem.setAttr('jid', other.getFullJID())
474 x.addChild(node=newitem)
475
476 reply = Presence( other.getFullJID(), frm=relative_frm )
477 reply.addChild(node=x)
478 s = self.muc.server.getsession(other.getFullJID())
479 if s:
480 s.enqueue(reply)
481 return
482
484 """
485 Check wether the room is locked down. A room is locked down while the owner is configuring it for the first time
486 """
487 return self.config["muc#roomconfig_nicklockdown"]
489 """
490 Lock or unlock down the room
491 """
492 if val in [0,'0',False]: val = 0
493 else: val = 1
494 self.config["muc#roomconfig_nicklockdown"] = val
496 """
497 Check wether the room allows the registration process
498 """
499 return self.config["muc#roomconfig_allowregister"]
501 """
502 Enable or disable the registration process to the room
503 """
504 if val in [0,'0',False]: val = 0
505 else: val = 1
506 self.config["muc#roomconfig_allowregister"] = val
508 """
509 Check wether the room is members-only
510 """
511 return self.config["muc#roomconfig_membersonly"]
513 """
514 Set or unset the room to members-only. If the rooms becomes members-only,
515 all the non-members, non-admins and non-owners participants will be
516 miserably kicked out
517 """
518 if val in [0,'0',False]:
519 val = 0
520 self.DEBUG("Room set to be NOT Members Only","info")
521 else:
522 val = 1
523
524 """
525 for memb in self.getRoomAdmins():
526 if memb not in self.whitelist:
527 self.whitelist.append(memb)
528 for memb in self.getRoomOwners():
529 if memb not in self.whitelist:
530 self.whitelist.append(memb)
531 """
532 self.DEBUG("Room set to be Members Only","info")
533
534 for k,to in self.participants.items():
535 if to.getBareJID() not in self.whitelist \
536 and to.getAffiliation() in ['outcast','none']:
537
538 to.setRole('none')
539
540
541 self.DEBUG("User %s got his ass kicked"%(str(to)),"warn")
542 relative_frm = self.fullJID() + "/" + to.getNick()
543 p = Presence(to=to.getFullJID(), frm=relative_frm ,typ='unavailable')
544 x = Node('x',{'xmlns':"http://jabber.org/protocol/muc#user"})
545 newitem = Node('item',{'affiliation':to.getAffiliation(),'role':to.getRole()})
546 reason = Node('reason')
547 reason.addData("Room is now Members-Only")
548 newitem.addChild(node=reason)
549 actor = Node('actor',{'jid':self.fullJID()})
550 newitem.addChild(node=actor)
551 x.addChild(node=newitem)
552 status = Node('status',{'code':'307'})
553 x.addChild(node=status)
554 p.addChild(node=x)
555 s = self.muc.server.getsession(to.getFullJID())
556 if s: s.enqueue(p)
557 self.deleteParticipant(to.getFullJID())
558
559
560 relative_frm = self.fullJID() + '/' + to.getNick()
561
562 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
563 status = Node('status', {'code':'307'})
564 x.addChild(node=status)
565 for other in self.participants.values():
566 item = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole() } )
567 if self.getWhois() != "" and other.getRole() == "moderator":
568 item.setAttr('jid', to.getFullJID())
569 x.addChild(node=item)
570 reply = Presence( other.getFullJID(), 'unavailable', frm=relative_frm )
571 reply.addChild(node=x)
572 s = self.muc.server.getsession(other.getFullJID())
573 if s:
574 s.enqueue(reply)
575
576
577 self.config["muc#roomconfig_membersonly"] = val
578
580 """
581 Check wether entrance to the room is protected by a password
582 """
583 return self.config["muc#roomconfig_passwordprotectedroom"]
585 """
586 Enable or disable password-protection. Note that this method does NOT set the password itself. To set the actual password use I{setPassword}
587 """
588 if val in [0,'0',False]: val = 0
589 else: val = 1
590 self.config["muc#roomconfig_passwordprotectedroom"] = val
592 """
593 Get the password of the room
594 """
595 return self.config["muc#roomconfig_roomsecret"]
597 """
598 Set the actual password of the room
599 """
600 self.config["muc#roomconfig_roomsecret"] = name
602 """
603 Get the whois permission
604 """
605 return self.config["muc#roomconfig_whois"]
607 """
608 Set the whois permission. Possible values are:
609 - 'anyone' : the room is non-anonymous
610 - 'moderators' : the room is semi-anonymous
611 - '' (empty) : the room is fully-anonymous
612 """
613 if name in ['anyone','moderators','']:
614 self.config["muc#roomconfig_whois"] = name
616 """
617 Get the list of room admins
618 """
619 return self.config["muc#roomconfig_roomadmins"]
621 """
622 Add an admin to the room
623 """
624 if name not in self.config["muc#roomconfig_roomadmins"]:
625 self.config["muc#roomconfig_roomadmins"].append(name)
626 else:
627 return
628 barejid = JID(name).getStripped()
629 self.reserveNick(barejid, None)
630
631 for k,v in self.participants.items():
632 if barejid in k:
633
634 self.DEBUG("Granting admin privileges to "+k,"info")
635 v.setAffiliation('admin')
636 self.reserveNick(v.getBareJID(), v.getNick())
637
638 if barejid not in self.moderators:
639 if barejid in self.visitors:
640 self.visitors.remove(barejid)
641 if self.isModeratedRoom():
642 v.setRole('moderator')
643 self.moderators.append(barejid)
644 else:
645 v.setRole('participant')
646 if self.isMembersOnly():
647 if barejid not in self.whitelist:
648 self.whitelist.append(barejid)
649 break
650
651
652
653
654 for p in self.participants.values():
655 if p.getBareJID() == barejid:
656 nick = p.getNick()
657 relative_frm = self.fullJID() + '/' + nick
658 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
659 newitem = Node('item', {'affiliation': 'admin'})
660 newitem.setAttr('role',p.getRole())
661 if nick: newitem.setAttr('nick',nick)
662 if self.getWhois()== "anyone" \
663 or self.getWhois() == "moderators" and other.getRole() == "moderator":
664 newitem.setAttr('jid', barejid)
665 x.addChild(node=newitem)
666
667 for other in self.participants.values():
668 reply = Presence( other.getFullJID(), frm=relative_frm )
669 reply.addChild(node=x)
670 s = self.muc.server.getsession(other.getFullJID())
671 if s:
672 s.enqueue(reply)
673 return
674
730
732 """
733 Get the list of room owners
734 """
735 return self.config["muc#roomconfig_roomowners"]
737 """
738 Add a room owner
739 """
740 if name not in self.config["muc#roomconfig_roomowners"]:
741 self.config["muc#roomconfig_roomowners"].append(name)
742 else:
743 return
744 barejid = JID(name).getStripped()
745 self.reserveNick(barejid, None)
746
747 for k,v in self.participants.items():
748 if barejid in k:
749
750 self.DEBUG("Granting owner privileges to "+k,"info")
751 v.setAffiliation('owner')
752 self.reserveNick(v.getBareJID(), v.getNick())
753
754 if barejid not in self.moderators:
755 if barejid in self.visitors:
756 self.visitors.remove(barejid)
757 if self.isModeratedRoom():
758 v.setRole('moderator')
759 self.moderators.append(barejid)
760 else:
761 v.setRole('participant')
762 if self.isMembersOnly():
763 if barejid not in self.whitelist:
764 self.whitelist.append(barejid)
765
766 break
767
768
769
770 for p in self.participants.values():
771 if p.getBareJID() == barejid:
772 nick = p.getNick()
773 relative_frm = self.fullJID() + '/' + nick
774 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
775 newitem = Node('item', {'affiliation': 'owner'})
776 newitem.setAttr('role',p.getRole())
777 if nick: newitem.setAttr('nick',nick)
778 if self.getWhois()== "anyone" \
779 or self.getWhois() == "moderators" and other.getRole() == "moderator":
780 newitem.setAttr('jid', barejid)
781 x.addChild(node=newitem)
782
783 for other in self.participants.values():
784 reply = Presence( other.getFullJID(), frm=relative_frm )
785 reply.addChild(node=x)
786 s = self.muc.server.getsession(other.getFullJID())
787 if s:
788 s.enqueue(reply)
789 return
790
792 """
793 Remove an owner from the room. Will not work if there is only one owner and tries to step down
794 """
795 if name in self.config["muc#roomconfig_roomowners"]:
796 self.config["muc#roomconfig_roomowners"].remove(name)
797 else:
798 return
799 barejid = JID(name).getStripped()
800
801 for k,v in self.participants.items():
802 if barejid in k:
803
804 self.DEBUG("Removing owner privileges to "+k,"info")
805 if self.isMembersOnly():
806 v.setAffiliation('member')
807 else:
808 v.setAffiliation('none')
809 try:
810 del self.reserved_nicks[barejid]
811 except:
812 pass
813
814 if self.isModeratedRoom():
815 if barejid in self.moderators:
816 self.moderators.remove(barejid)
817 v.setRole('participant')
818 else:
819 v.setRole('visitor')
820 if barejid not in self.visitors:
821 self.visitors.append(barejid)
822 break
823
824
825 for p in self.participants.values():
826 if p.getBareJID() == barejid:
827 nick = p.getNick()
828 relative_frm = self.fullJID() + '/' + nick
829 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
830 newitem = Node('item', {'affiliation': p.getAffiliation()})
831 newitem.setAttr('role',p.getRole())
832 if nick: newitem.setAttr('nick',nick)
833 if self.getWhois()== "anyone" \
834 or self.getWhois() == "moderators" and other.getRole() == "moderator":
835 newitem.setAttr('jid', barejid)
836 x.addChild(node=newitem)
837
838 for other in self.participants.values():
839 reply = Presence( other.getFullJID(), frm=relative_frm )
840 reply.addChild(node=x)
841 s = self.muc.server.getsession(other.getFullJID())
842 if s:
843 s.enqueue(reply)
844 return
845
846
847
849 """
850 Return a string representation of the room
851 """
852 """
853 s = str(self.name) + ": " + self.subject
854 s = s + "\nLocked = " + str(self.locked)
855 s = s + "\nHidden = " + str(self.hidden) + "\nOpen = " + str(self.open) + "\nModerated = " + str(self.moderated) + "\nAnonymous = " + str(self.anonymous) + "\nUnsecured = " + str(self.unsecured) + "\nPersistent = " + str(self.persistent)
856 s = s + "\nRole Privileges = " + str(self.role_privileges)
857 s = s + "\nParticipants = " + str(self.participants.keys())
858 if self.creator:
859 s = s + "\nCreator = " + str(self.creator.getFullJID())
860 s = s + "\nWhitelist = " + str(self.whitelist)
861 s = s + "\nBlacklist = " + str(self.blacklist)
862 s = s + "\nOwners = " + str(self.owners)
863 s = s + "\nAdmins = " + str(self.admins)
864 s = s + "\nModerators = " + str(self.moderators)
865 s = s + "\nVisitors = " + str(self.visitors)
866 """
867 s = ""
868 s = str(self.name) + ": " + self.subject
869 s = s + "\nLocked = " + str(self.locked)
870 s = s + "\nParticipants = " + str(self.participants.keys())
871 if self.creator:
872 s = s + "\nCreator = " + str(self.creator.getFullJID())
873 s = s + "\nWhitelist = " + str(self.whitelist)
874 s = s + "\nBlacklist = " + str(self.blacklist)
875 s = s + "\nModerators = " + str(self.moderators)
876 s = s + "\nVisitors = " + str(self.visitors)
877 s = s + "\nReserved Nicks = " + str(self.reserved_nicks) + "\n"
878 for k in self.config.keys():
879 s = s + str(k) + ": " + str(self.config[k]) + "\n"
880 return s
881
883 """
884 Returns the room's full JID in the form of I{room@muc.platform}
885 """
886 return str(self.name) + '@' + str(self.muc.jid)
887
899
900
902 """
903 Manages messages directed to a room
904 """
905 self.DEBUG("Message callback of room %s called"%(self.getName()),"info")
906 frm = str(session.peer)
907 to = stanza['to']
908 typ = stanza.getAttr('type')
909 if typ == 'groupchat':
910
911 if str(to) == self.fullJID():
912 self.DEBUG("Message directed to the room itself: " + str(self.getName()),'info')
913 subject = stanza.getTag('subject')
914
915 if subject:
916 if self.isChangeSubject():
917 if not self.isModeratedRoom():
918
919 try:
920
921 p = self.participants[frm]
922 self.setSubject(subject.getData())
923 self.DEBUG("Subject changed to "+str(subject.getData()),"info")
924 self.muc.saveRoomDB()
925 except:
926
927 return
928 else:
929
930 try:
931 p = self.participants[frm]
932 if p.getRole() == 'moderator':
933
934 self.setSubject(subject.getData())
935 self.DEBUG("Subject changed to "+str(subject.getData()),"info")
936 self.muc.saveRoomDB()
937 else:
938
939 self.DEBUG("Not enough permissions to change subject","warn")
940 stanza.setTo(frm)
941 stanza.setFrom(self.fullJID())
942 stanza.setType('error')
943 err = Node('error', {'code': '403', 'type': 'auth'} )
944 badr = Node('forbidden', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
945 err.addChild(node=badr)
946 stanza.addChild(node=err)
947 session.enqueue(stanza)
948 return
949 except:
950
951 return
952
953 try:
954 relative_frm = self.fullJID() + '/' + p.getNick()
955 stanza.setFrom(relative_frm)
956 for participant in self.participants.values():
957 stanza.setTo(participant.getFullJID())
958 s = self.muc.server.getsession(participant.getFullJID())
959 s.enqueue(stanza)
960 except:
961
962 return
963 else:
964
965 self.DEBUG("Not enough permissions to change subject","warn")
966 stanza.setTo(frm)
967 stanza.setFrom(self.fullJID())
968 stanza.setType('error')
969 err = Node('error', {'code': '403', 'type': 'auth'} )
970 badr = Node('forbidden', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
971 err.addChild(node=badr)
972 stanza.addChild(node=err)
973 session.enqueue(stanza)
974 return
975
976
977
978 elif self.participants.has_key(frm):
979 try:
980 if self.isModeratedRoom() and JID(frm).getStripped() in self.visitors:
981 raise NoVoice
982
983 self.DEBUG("General message from %s to everyone in room %s"%(str(frm),str(self.getName())),'info')
984
985 messenger = self.participants[frm]
986 stanza.setFrom(self.fullJID()+'/'+messenger.getNick())
987 for participant in self.participants.values():
988 stanza.setTo(participant.getFullJID())
989 s = self.muc.server.getsession(participant.getFullJID())
990 if s:
991 s.enqueue(stanza)
992
993
994 if stanza.getBody() == ".str" or stanza.getBody() == u".str": print self
995 if stanza.getBody() == ".savedb" or stanza.getBody() == u".savedb": self.muc.saveRoomDB()
996 if stanza.getBody() == ".rooms" or stanza.getBody() == u".rooms":
997 for k,v in self.muc.rooms.items():
998 print k,str(v)
999 return
1000
1001 except NoVoice:
1002 self.DEBUG("This user has No voice",'warn')
1003 stanza.setTo(frm)
1004 stanza.setFrom(self.fullJID())
1005 stanza.setType('error')
1006 err = Node('error', {'code': '403', 'type': 'auth'} )
1007 badr = Node('forbidden', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1008 err.addChild(node=badr)
1009 stanza.addChild(node=err)
1010 session.enqueue(stanza)
1011 return
1012 else:
1013 self.DEBUG("Message from an outsider","warn")
1014 stanza.setTo(frm)
1015 stanza.setFrom(self.fullJID())
1016 stanza.setType('error')
1017 err = Node('error', {'code': '406', 'type': 'cancel'} )
1018 badr = Node('not-acceptable', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1019 err.addChild(node=badr)
1020 stanza.addChild(node=err)
1021 session.enqueue(stanza)
1022 return
1023
1024 else:
1025 self.DEBUG("Message of 'groupchat' type directed to a particular participant. That is wrong!","warn")
1026 stanza.setTo(frm)
1027 stanza.setFrom(self.fullJID())
1028 stanza.setType('error')
1029 err = Node('error', {'code': '400', 'type': 'modify'} )
1030 badr = Node('bad-request', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1031 err.addChild(node=badr)
1032 stanza.addChild(node=err)
1033 session.enqueue(stanza)
1034 return
1035
1036
1037 elif typ == 'chat':
1038 self.DEBUG("Private message within room "+self.getName(),"info")
1039 try:
1040 nick = to.getResource()
1041 except: return
1042
1043 try:
1044 for k,v in self.participants.items():
1045 if v.getNick() == nick:
1046 self.DEBUG("Private message for nick "+nick)
1047 stanza.setTo(k)
1048 if not self.participants.has_key(frm): return
1049 stanza.setFrom(self.fullJID()+'/'+self.participants[frm].getNick())
1050 s = self.muc.server.getsession(k)
1051 if s: s.enqueue(stanza)
1052 return
1053 except:
1054 self.DEBUG("Error forwarding private message","error")
1055
1056 elif not typ:
1057 self.DEBUG("Not type!","warn")
1058
1059 for child in stanza.getTags('x'):
1060 if child.getNamespace() == "http://jabber.org/protocol/muc#user":
1061 if child.getTag('invite'):
1062 if self.isAllowInvites():
1063 self.DEBUG("An invitation","info")
1064
1065 mess = Message()
1066 mess.setFrom(self.fullJID())
1067 invite_node = child.getTag('invite')
1068 invite_to = invite_node.getAttr('to')
1069 if invite_to:
1070
1071
1072 if self.isMembersOnly():
1073 self.whitelist.append(invite_to)
1074
1075 mess.setTo(invite_to)
1076 mess.setBody("You have been invited to room %s by %s"%(str(self.getName()),str(frm)))
1077 x = Node('x', attrs={'xmlns':'http://jabber.org/protocol/muc#user'})
1078 inv = Node('invite', attrs={'from':frm})
1079 for c in invite_node.getChildren():
1080 inv.addChild(node=c)
1081 x.addChild(node=inv)
1082
1083 if self.getPassword():
1084 pwd = Node('password')
1085 pwd.setData(self.getPassword())
1086 x.addChild(node=pwd)
1087 mess.addChild(node=x)
1088 x = Node('x', attrs={'xmlns':'jabber:x:conference', 'jid':self.fullJID()})
1089 reason = invite_node.getTagData('reason')
1090 if reason:
1091 x.setData(reason)
1092 mess.addChild(node=x)
1093 s = self.muc.server.getsession(invite_to)
1094 if s:
1095 s.enqueue(mess)
1096 return
1097 else:
1098
1099 reply = Message(frm, frm=self.fullJID(), typ='error')
1100 err = Node('error', {'code': '404', 'type': 'cancel'} )
1101 reply.addChild(node=err)
1102 session.enqueue(reply)
1103 return
1104
1105 else:
1106
1107 reply = Message(frm, frm=self.fullJID(), typ='error')
1108 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
1109 err = Node('error', {'code':'405','type':'cancel'})
1110 err.addChild(node=na)
1111 reply.addChild(node=err)
1112 session.enqueue(reply)
1113 return
1114
1115
1116 elif child.getTag('decline'):
1117 self.DEBUG("Decline invitation","info")
1118 mess = Message()
1119 mess.setFrom(self.fullJID())
1120 decline_node = child.getTag('decline')
1121 decline_to = decline_node.getAttr('to')
1122 if decline_to:
1123
1124
1125 if self.isMembersOnly() and decline_to in self.whitelist:
1126 self.whitelist.remove(decline_to)
1127
1128 mess.setTo(decline_to)
1129 x = Node('x', attrs={'xmlns':'http://jabber.org/protocol/muc#user'})
1130 dec = Node('decline', attrs={'from':frm})
1131 for c in decline_node.getChildren():
1132 dec.addChild(node=c)
1133 x.addChild(node=dec)
1134 mess.addChild(node=x)
1135
1136 s = self.muc.server.getsession(decline_to)
1137 if s:
1138 s.enqueue(mess)
1139 return
1140 else:
1141
1142 reply = Message(frm, frm=self.fullJID(), typ='error')
1143 err = Node('error', {'code': '404', 'type': 'cancel'} )
1144 reply.addChild(node=err)
1145 session.enqueue(reply)
1146 return
1147
1148 self.DEBUG("Private message without 'chat' type. Re-dispatching","info")
1149 stanza.setType('chat')
1150 self.dispatch(session,stanza)
1151 return
1152
1153
1155 """
1156 Manages presence stanzas directed to a room
1157 """
1158 self.muc.DEBUG("Room '"+self.getName()+"' presence handler called")
1159
1160 to = stanza['to']
1161 room = to.getNode()
1162 domain = to.getDomain()
1163 nick = to.getResource()
1164 frm = str(session.peer)
1165 typ = stanza.getType()
1166 try:
1167 password = None
1168 for x in stanza.getTags('x'):
1169 if x.getNamespace() == "http://jabber.org/protocol/muc":
1170 if x.getTag("password"):
1171 password = x.T.password.getData()
1172 except:
1173 password = None
1174
1175 if typ == None or typ == 'available':
1176
1177
1178 if self.locked and JID(frm).getStripped() not in self.getRoomOwners():
1179
1180 self.DEBUG("Non-owner trying to enter locked room. Nope.", "warn")
1181 rr = Node('item-not-found', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
1182 err = Node('error', {'code': '404', 'type': 'cancel'})
1183 err.addChild(node=rr)
1184 p = Presence(frm, 'error', frm=self.fullJID())
1185 p.addChild(node=err)
1186 session.enqueue(p)
1187 return
1188
1189
1190 if nick == '':
1191 self.DEBUG("There is no nick, we must send back an error 400",'warn')
1192 reply = Presence(frm, 'error', frm=self.fullJID())
1193 error = Node('error', { 'code': '400', 'type': 'modify' } )
1194 error.setTag('jid-malformed', { 'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas' } )
1195 reply.addChild(node=error)
1196 session.enqueue(reply)
1197 return
1198 else:
1199
1200 for k,p in self.participants.items():
1201 if p.getNick() == nick and frm != k:
1202
1203 self.DEBUG("Nickname conflict !!!","warn")
1204 reply = Presence(frm, frm=self.fullJID(), typ='error')
1205 err = Node('error', {'code': '409', 'type': 'cancel'} )
1206 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1207 err.addChild(node=conflict)
1208 reply.addChild(node=err)
1209 session.enqueue(reply)
1210 return
1211
1212
1213 for j,n in self.reserved_nicks.items():
1214 if n and n == nick and j != JID(frm).getStripped():
1215
1216 self.DEBUG("Nickname conflict",'warn')
1217 reply = Presence(frm, frm=self.fullJID(), typ='error')
1218 err = Node('error', {'code': '409', 'type': 'cancel'} )
1219 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1220 err.addChild(node=conflict)
1221 reply.addChild(node=err)
1222 session.enqueue(reply)
1223 return
1224
1225
1226 if self.participants.has_key(frm):
1227 oldnick = self.participants[frm].getNick()
1228 if nick != oldnick:
1229
1230
1231 self.DEBUG("Nick change",'info')
1232 if self.isLockedDown():
1233
1234 self.DEBUG("Nickname conflict",'warn')
1235 reply = Presence(frm, frm=self.fullJID(), typ='error')
1236 err = Node('error', {'code': '409', 'type': 'cancel'} )
1237 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1238 err.addChild(node=conflict)
1239 reply.addChild(node=err)
1240 session.enqueue(reply)
1241 return
1242 for p in self.participants.values():
1243 if nick == p.getNick():
1244
1245 self.DEBUG("Nickname conflict",'warn')
1246 reply = Presence(frm, frm=self.fullJID(), typ='error')
1247 err = Node('error', {'code': '409', 'type': 'cancel'} )
1248 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1249 err.addChild(node=conflict)
1250 reply.addChild(node=err)
1251 session.enqueue(reply)
1252 return
1253
1254
1255 p = self.participants[frm]
1256 relative_frm = self.fullJID() + '/' + p.getNick()
1257 pres = Presence(frm=relative_frm, typ='unavailable')
1258 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1259 item = Node('item', {'affiliation': p.getAffiliation(), 'role': p.getRole(), 'nick': nick } )
1260 status = Node('status', {'code': '303'})
1261 x.addChild(node=item)
1262 x.addChild(node=status)
1263 pres.addChild(node=x)
1264 for participant in self.participants.values():
1265 pres.setTo(participant.getFullJID())
1266 s = self.muc.server.getsession(participant.getFullJID())
1267 if s:
1268 s.enqueue(pres)
1269
1270 p.setNick(nick)
1271
1272
1273 try:
1274
1275
1276
1277 if self.addParticipant(fulljid=frm, nick=nick, password=password):
1278 self.DEBUG("New Participant has correct credentials", "info")
1279
1280
1281
1282
1283
1284
1285
1286 for k,participant in self.participants.items():
1287 relative_frm = self.fullJID() + '/' + participant.getNick()
1288 reply = Presence( frm, frm=relative_frm )
1289 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1290 item = Node('item', {'affiliation': participant.getAffiliation(), 'role': participant.getRole() } )
1291
1292 if self.getWhois() == "moderators":
1293 if self.participants[frm].getRole() == "moderator":
1294 item.setAttr('jid', k)
1295
1296 elif self.getWhois() == "anyone":
1297 item.setAttr('jid', k)
1298 x.addChild(node=item)
1299 reply.addChild(node=x)
1300
1301 try:
1302 p = self.muc.server.Router._data[participant.getBareJID()][JID(k).getResource()]
1303 for child in p.getChildren():
1304 reply.addChild(node=child)
1305 except:
1306 print self.muc.server.data
1307 session.enqueue(reply)
1308
1309
1310 relative_frm = self.fullJID() + '/' + nick
1311 newcomer = self.participants[frm]
1312 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1313 item = Node('item', {'affiliation': str(newcomer.getAffiliation()), 'role': str(newcomer.getRole()) } )
1314
1315 if self.getWhois() == "moderators":
1316 if newcomer.getRole() == "moderator":
1317 item.setAttr('jid', frm)
1318
1319 elif self.getWhois() == "anyone":
1320 item.setAttr('jid', frm)
1321
1322 x.addChild(node=item)
1323 for participant in self.participants.values():
1324 reply = Presence( participant.getFullJID(), frm=relative_frm )
1325 reply.addChild(node=x)
1326 for child in stanza.getChildren():
1327 reply.addChild(node=child)
1328 s = self.muc.server.getsession(participant.getFullJID())
1329 self.DEBUG("Session " + str(s) + " found for client " + participant.getFullJID(),'info')
1330 if s:
1331 s.enqueue(reply)
1332
1333
1334 if self.getWhois() == "anyone":
1335 warning = Message(frm, "This room is not anonymous.", frm=self.fullJID(), typ="groupchat")
1336 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1337 status = Node('status', {'code': 100} )
1338 x.addChild(node=status)
1339 warning.addChild(node=x)
1340 session.enqueue(warning)
1341
1342 if self.getSubject():
1343 subj = Message(frm, frm=self.fullJID(), typ="groupchat")
1344 s = Node('subject')
1345 s.addData(self.getSubject())
1346 subj.addChild(node=s)
1347 session.enqueue(subj)
1348
1349 except BadPassword:
1350
1351 self.DEBUG("The client sent a bad password","warn")
1352 rr = Node('not-authorized', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
1353 err = Node('error', {'code': '401', 'type': 'auth'})
1354 err.addChild(node=rr)
1355 p = Presence(frm, 'error', frm=self.fullJID())
1356 p.addChild(node=err)
1357 session.enqueue(p)
1358
1359
1360 except NotAMember:
1361
1362 self.DEBUG("the client is not a member of this room","warn")
1363 rr = Node('registration-required', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
1364 err = Node('error', {'code': '407', 'type': 'auth'})
1365 err.addChild(node=rr)
1366 p = Presence(frm, 'error', frm=self.fullJID())
1367 p.addChild(node=err)
1368 session.enqueue(p)
1369
1370 except Blacklisted:
1371 self.DEBUG("The client is blacklisted","warn")
1372 rr = Node('forbidden', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
1373 err = Node('error', {'code': '403', 'type': 'auth'})
1374 err.addChild(node=rr)
1375 p = Presence(frm, 'error', frm=self.fullJID())
1376 p.addChild(node=err)
1377 session.enqueue(p)
1378
1379 except MaxUsers:
1380 self.DEBUG("MaxUsers reached","warn")
1381 rr = Node('service-unavailable', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
1382 err = Node('error', {'code': '503', 'type': 'wait'})
1383 err.addChild(node=rr)
1384 p = Presence(frm, 'error', frm=self.fullJID())
1385 p.addChild(node=err)
1386 session.enqueue(p)
1387
1388 except NickLockedDown:
1389 self.DEBUG("The Nick is Locked Down","warn")
1390 reply = Presence(frm, frm=self.fullJID(), typ='error')
1391 err = Node('error', {'code': '409', 'type': 'cancel'} )
1392 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1393 err.addChild(node=conflict)
1394 reply.addChild(node=err)
1395 session.enqueue(reply)
1396 return
1397
1398 except Exception, e:
1399 self.DEBUG("Access Check failed with unknowk exception: " + str(e),'error')
1400
1401 return
1402
1403 elif typ == 'unavailable':
1404 try:
1405 participant = self.participants[frm]
1406 except:
1407 return
1408 relative_frm = self.fullJID() + '/' + participant.getNick()
1409
1410 if str(to) == relative_frm:
1411
1412 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1413 item = Node('item', {'affiliation': str(participant.getAffiliation()), 'role': str(participant.getRole()) } )
1414 x.addChild(node=item)
1415 for other in self.participants.values():
1416 reply = Presence( other.getFullJID(), 'unavailable', frm=relative_frm )
1417 reply.addChild(node=x)
1418 if stanza.getTag('status'):
1419 reply.addChild(node=stanza.getTag('status'))
1420 s = self.muc.server.getsession(other.getFullJID())
1421 self.DEBUG("Session " + str(s) + " found for client " + other.getFullJID(),'info')
1422 if s:
1423 s.enqueue(reply)
1424 self.deleteParticipant(frm)
1425
1426 if len(self.participants.keys()) == 0:
1427
1428 if not self.isPersistentRoom():
1429 del self.muc.rooms[self.getName()]
1430
1431
1432
1433
1434
1435 return
1436
1437
1438 - def IQ_cb(self, session, iq):
1439 """
1440 Manages IQ stanzas directed to a room
1441 """
1442 self.DEBUG("IQ callback of room %s called"%(self.getName()),"info")
1443
1444 query = iq.getTag('query')
1445 frm = str(session.peer)
1446 stanza = iq
1447 if query:
1448 try:
1449 ns = str(iq.getQueryNS())
1450 typ = str(iq.getType())
1451 nod = iq.getQuerynode()
1452 id = iq.getAttr('id')
1453
1454 if ns == NS_DISCO_INFO and typ == 'get' and nod == None:
1455
1456 reply = Iq('result', NS_DISCO_INFO, to=frm, frm=str(self.fullJID()))
1457 rquery=reply.getTag('query')
1458 if id:
1459 reply.setAttr('id', id)
1460
1461 identity = { 'category': 'conference', 'type': 'text', 'name':self.getRoomName() }
1462 rquery.setTag('identity', identity)
1463
1464 feature = { 'var': 'http://jabber.org/protocol/muc' }
1465 rquery.setTag('feature', feature)
1466
1467
1468 if not self.isPublicRoom():
1469 feature = { 'var': 'muc_hidden' }
1470 rquery.setTag('feature', feature)
1471
1472 if not self.isMembersOnly():
1473 feature = { 'var': 'muc_open' }
1474 rquery.setTag('feature', feature)
1475 if not self.isModeratedRoom():
1476 feature = { 'var': 'muc_unmoderated' }
1477 rquery.setTag('feature', feature)
1478
1479 if self.getWhois() == "anyone":
1480 feature = { 'var': 'muc_nonanonymous' }
1481 rquery.setTag('feature', feature)
1482 if not self.isPersistentRoom():
1483 feature = { 'var': 'muc_temporary' }
1484 rquery.setTag('feature', feature)
1485 if self.isPasswordProtectedRoom():
1486 feature = { 'var': 'muc_passwordprotected' }
1487 rquery.setTag('feature', feature)
1488
1489 if self.isPublicRoom():
1490 df = DataForm(typ="result")
1491 field = DataField()
1492 df.addChild(node=DataField(name="FORM_TYPE",value="http://jabber.org/protocol/muc#roominfo",typ="hidden"))
1493 field=DataField(name="muc#roominfo_description",value=self.getRoomDesc())
1494 field.setAttr('label','Description')
1495 df.addChild(node=field)
1496 field=DataField(name="muc#roominfo_subject",value=self.getSubject())
1497 field.setAttr('label','Subject')
1498 df.addChild(node=field)
1499 field=DataField(name="muc#roominfo_occupants",value=str(len(self.participants.keys())))
1500 field.setAttr('label','Number of occupants')
1501 df.addChild(node=field)
1502 field=DataField(name="muc#roominfo_maxusers",value=str(self.getMaxUsers()))
1503 field.setAttr('label','Maximum number of occupants')
1504 df.addChild(node=field)
1505 field=DataField(name="muc#roominfo_minusers",value=str(self.getMinUsers()))
1506 field.setAttr('label','Minimum number of occupants')
1507 df.addChild(node=field)
1508 field=DataField(name="muc#roominfo_lang",value=self.getLang())
1509 field.setAttr('label','Language of discussion')
1510 df.addChild(node=field)
1511 rquery.addChild(node=df)
1512 session.enqueue(reply)
1513
1514
1515 elif ns == NS_DISCO_INFO and typ == 'get' and nod == 'http://jabber.org/protocol/muc#traffic':
1516 self.DEBUG("TRAFFIC IQ REQUEST",'info')
1517
1518 reply = Iq('error', NS_DISCO_INFO, to=frm, frm=self.fullJID() )
1519 rquery=reply.getTag('query')
1520 id = iq.getAttr('id')
1521 if id:
1522 reply.setAttr('id', id)
1523 error = Node('error', { 'code': 501, 'type': 'cancel' })
1524 error.setTag('feature-not-implemented', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
1525 text = Node('text', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
1526 text.addData('The feature requested is not implemented by the recipient or server and therefore cannot be processed.')
1527 error.addChild(node=text)
1528 reply.addChild(node=error)
1529 session.enqueue(reply)
1530 return
1531
1532 elif ns == NS_DISCO_INFO and typ == 'get' and nod == 'x-roomuser-item':
1533
1534 self.DEBUG("User %s requests its own nick"%(frm),"info")
1535 reply = stanza.buildReply(typ="result")
1536 id = iq.getAttr('id')
1537 if id:
1538 reply.setAttr('id', id)
1539 if self.reserved_nicks.has_key(JID(frm).getStripped()):
1540 nick = self.reserved_nicks[JID(frm).getStripped()]
1541 if nick:
1542 i = reply.T.query.NT.identity
1543 i.setAttr("name",nick)
1544 i.setAttr("category","conference")
1545 i.setAttr("type","text")
1546 session.enqueue(reply)
1547 return
1548
1549
1550 elif ns == NS_DISCO_ITEMS and typ == 'get':
1551
1552
1553 self.DEBUG("NS_DISCO_ITEMS requested", "warn")
1554
1555 reply = Iq('result', NS_DISCO_ITEMS, to=iq.getFrom(), frm=str(self.fullJID()))
1556 rquery=reply.getTag('query')
1557 id = iq.getAttr('id')
1558 if id:
1559 reply.setAttr('id', id)
1560 if self.isPublicRoom():
1561 for k,p in self.participants.items():
1562 item = Node('item', {'jid':self.fullJID()+"/"+p.getNick()})
1563 rquery.addChild(node=item)
1564 session.enqueue(reply)
1565
1566
1567 elif ns == "http://jabber.org/protocol/muc#admin" and typ == 'set':
1568 self.DEBUG("Admin command","info")
1569 for item in query.getTags('item'):
1570 nick = item.getAttr('nick')
1571 affiliation = item.getAttr('affiliation')
1572 role = item.getAttr('role')
1573 jid = item.getAttr('jid')
1574 to = None
1575 for k,v in self.participants.items():
1576 if nick:
1577 if v.getNick() == nick:
1578 to = v
1579 jid = v.getBareJID()
1580 elif jid:
1581 if v.getBareJID() == jid:
1582 to = v
1583 nick = to.getNick()
1584 if not to:
1585
1586 to = Participant(jid)
1587 if nick: to.setNick(nick)
1588 if jid in self.moderators: to.setRole('moderator')
1589 elif jid in self.visitors: to.setRole('visitor')
1590 else: to.setRole('none')
1591 if jid in self.blacklist: to.setAffiliation('outcast')
1592 elif jid in self.whitelist: to.setAffiliation('member')
1593 elif jid in self.getRoomAdmins(): to.setAffiliation('admin')
1594 elif jid in self.getRoomOwners(): to.setAffiliation('owner')
1595 else: to.setAffiliation('none')
1596
1597
1598 if self.participants[frm].getRole() == 'moderator':
1599 if role == "none" and (nick or jid) and not affiliation:
1600
1601 my_aff = self.participants[frm].getAffiliation()
1602 if my_aff=="outcast" \
1603 or my_aff=="none" and to.getAffiliation() in ['none','member','admin','owner'] \
1604 or my_aff=="member" and to.getAffiliation() in ['admin','owner','member'] \
1605 or my_aff=="admin" and to.getAffiliation() in ['owner','admin'] \
1606 or to.getAffiliation() in ['owner']:
1607 self.DEBUG("Service returns error on atempt to kick user with higher affiliation","warn")
1608 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
1609 id = iq.getAttr('id')
1610 if id:
1611 reply.setAttr('id', id)
1612 reply.NT.query.addChild(node=item)
1613 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
1614 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
1615 err = Node('error', {'code':'405','type':'cancel'})
1616 err.addChild(node=na)
1617 reply.addChild(node=err)
1618 session.enqueue(reply)
1619 return
1620
1621 to.setRole('none')
1622
1623
1624 self.DEBUG("User %s got his ass kicked"%(str(to.getNick())),"info")
1625 p = Presence(to=to.getFullJID(), frm=self.fullJID()+"/"+to.getNick(),typ='unavailable')
1626 x = Node('x',{'xmlns':"http://jabber.org/protocol/muc#user"})
1627 newitem = Node('item',{'affiliation':to.getAffiliation(),'role':to.getRole()})
1628 actor = Node('actor',{'jid':JID(frm).getStripped()})
1629 status = Node('status',{'code':'307'})
1630 for child in item.getChildren():
1631 newitem.addChild(node=child)
1632 newitem.addChild(node=actor)
1633 x.addChild(node=newitem)
1634 x.addChild(node=status)
1635 p.addChild(node=x)
1636 s = self.muc.server.getsession(to.getFullJID())
1637 if s: s.enqueue(p)
1638 to_aff = to.getAffiliation()
1639 self.deleteParticipant(to.getFullJID())
1640
1641
1642 result = Iq(to=frm, frm=self.fullJID(),typ='result')
1643 session.enqueue(result)
1644
1645
1646 relative_frm = self.fullJID() + '/' + nick
1647
1648 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1649 status = Node('status', {'code':'307'})
1650 x.addChild(node=status)
1651 item = Node('item', {'affiliation': to_aff, 'role': to.getRole() } )
1652 if self.getWhois() != "" and self.participants[frm].getRole() == "moderator":
1653 item.setAttr('jid', to.getFullJID())
1654 x.addChild(node=item)
1655
1656 for other in self.participants.values():
1657 reply = Presence( other.getFullJID(), 'unavailable', frm=relative_frm )
1658 reply.addChild(node=x)
1659 s = self.muc.server.getsession(other.getFullJID())
1660 if s:
1661 s.enqueue(reply)
1662 return
1663
1664 elif role == "participant" and (nick or jid) and not affiliation:
1665
1666 my_aff = self.participants[frm].getAffiliation()
1667 if my_aff=="outcast" \
1668 or my_aff=="none" and to.getAffiliation() in ['none','member','admin','owner'] \
1669 or my_aff=="member" and to.getAffiliation() in ['admin','owner','member'] \
1670 or my_aff=="admin" and to.getAffiliation() in ['owner','admin'] \
1671 or to.getAffiliation() in ['owner']:
1672 self.DEBUG("Service returns error on atempt to kick user with higher affiliation","warn")
1673 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
1674 id = iq.getAttr('id')
1675 if id:
1676 reply.setAttr('id', id)
1677 reply.NT.query.addChild(node=item)
1678 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
1679 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
1680 err = Node('error', {'code':'405','type':'cancel'})
1681 err.addChild(node=na)
1682 reply.addChild(node=err)
1683 session.enqueue(reply)
1684 return
1685
1686
1687
1688
1689
1690 to.setRole("participant")
1691 try:
1692 self.visitors.remove(to.getBareJID())
1693 except:
1694 self.DEBUG("Could not remove %s from visitors"%(to.getBareJID()),"warn")
1695
1696
1697 result = Iq(to=frm, frm=self.fullJID(),typ='result')
1698 session.enqueue(result)
1699
1700
1701 relative_frm = self.fullJID() + '/' + to.getNick()
1702
1703 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1704 newitem = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole(), 'nick':to.getNick() } )
1705 if self.getWhois() != "" and self.participants[frm].getRole() == "moderator":
1706 newitem.setAttr('jid', to.getFullJID())
1707 for child in item.getChildren():
1708 newitem.addChild(node=child)
1709 x.addChild(node=newitem)
1710
1711 for other in self.participants.values():
1712 reply = Presence( other.getFullJID(), frm=relative_frm )
1713 reply.addChild(node=x)
1714 s = self.muc.server.getsession(other.getFullJID())
1715 if s:
1716 s.enqueue(reply)
1717 return
1718
1719 elif role == "visitor" and (nick or jid) and not affiliation:
1720 if to.getRole() == 'moderator':
1721
1722 my_aff = self.participants[frm].getAffiliation()
1723 if to.getAffiliation() in ['owner'] \
1724 or my_aff == 'admin' and to.getAffiliation() in ['owner','admin']:
1725 self.DEBUG("Affiliation is not high enough to deny voice","warn")
1726 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
1727 id = iq.getAttr('id')
1728 if id:
1729 reply.setAttr('id', id)
1730 reply.NT.query.addChild(node=item)
1731 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
1732 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
1733 err = Node('error', {'code':'405','type':'cancel'})
1734 err.addChild(node=na)
1735 reply.addChild(node=err)
1736 session.enqueue(reply)
1737 return
1738
1739 to.setRole("visitor")
1740 try:
1741 if to.getBareJID() not in self.visitors:
1742 self.visitors.append(to.getBareJID())
1743 if to.getBareJID() in self.moderators:
1744 self.moderators.remove(to.getBareJID())
1745 except:
1746 self.DEBUG("Could not change role for %s"%(to.getBareJID()),"error")
1747 return
1748
1749
1750 result = Iq(to=frm, frm=self.fullJID(),typ='result')
1751 session.enqueue(result)
1752
1753
1754 relative_frm = self.fullJID() + '/' + to.getNick()
1755 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1756 newitem = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole(), 'nick':to.getNick() } )
1757 if self.getWhois()== "anyone" \
1758 or self.getWhois() == "moderators" and self.participants[frm].getRole() == "moderator":
1759 newitem.setAttr('jid', to.getFullJID())
1760 for child in item.getChildren():
1761 newitem.addChild(node=child)
1762 x.addChild(node=newitem)
1763
1764 for other in self.participants.values():
1765 reply = Presence( other.getFullJID(), frm=relative_frm)
1766 reply.addChild(node=x)
1767 s = self.muc.server.getsession(other.getFullJID())
1768 if s:
1769 s.enqueue(reply)
1770 return
1771
1772 if self.participants[frm].getAffiliation() in ['owner','admin']:
1773 if role == "moderator" and (nick or jid) and not affiliation:
1774 if self.participants[frm].getAffiliation() not in ['owner','admin']:
1775 self.DEBUG("Affiliation is not enough to give moderation","warn")
1776 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
1777 id = iq.getAttr('id')
1778 if id:
1779 reply.setAttr('id', id)
1780 reply.NT.query.addChild(node=item)
1781 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
1782 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
1783 err = Node('error', {'code':'405','type':'cancel'})
1784 err.addChild(node=na)
1785 reply.addChild(node=err)
1786 session.enqueue(reply)
1787 return
1788
1789 to.setRole("moderator")
1790 try:
1791 if to.getBareJID() in self.visitors:
1792 self.visitors.remove(to.getBareJID())
1793 if to.getBareJID() not in self.moderators:
1794 self.moderators.append(to.getBareJID())
1795 except:
1796 self.DEBUG("Could not change role for %s"%(to.getBareJID()),"error")
1797 return
1798
1799
1800 result = Iq(to=frm, frm=self.fullJID(),typ='result')
1801 session.enqueue(result)
1802
1803
1804 relative_frm = self.fullJID() + '/' + to.getNick()
1805 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1806 newitem = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole(), 'nick':to.getNick() } )
1807 if self.getWhois()== "anyone" \
1808 or self.getWhois() == "moderators" and self.participants[frm].getRole() == "moderator":
1809 newitem.setAttr('jid', to.getFullJID())
1810 for child in item.getChildren():
1811 newitem.addChild(node=child)
1812 x.addChild(node=newitem)
1813 for other in self.participants.values():
1814 reply = Presence( other.getFullJID(), frm=relative_frm )
1815 reply.addChild(node=x)
1816 s = self.muc.server.getsession(other.getFullJID())
1817 if s:
1818 s.enqueue(reply)
1819 return
1820
1821
1822 if self.participants[frm].getAffiliation() in ['owner','admin']:
1823 if affiliation == "outcast" and jid and not role:
1824 my_aff = self.participants[frm].getAffiliation()
1825
1826 if JID(frm).getStripped() == to.getBareJID() and \
1827 my_aff in ['admin','owner']:
1828
1829
1830
1831 reply = stanza.buildReply(typ="error")
1832 err = Node('error', {'code': '409', 'type': 'cancel'} )
1833 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1834 err.addChild(node=conflict)
1835 reply.addChild(node=err)
1836 session.enqueue(reply)
1837 return
1838
1839 if my_aff == "admin" and to.getAffiliation() not in ['member','none'] \
1840 or my_aff == "owner" and to.getAffiliation() not in ['admin','member','none']\
1841 or my_aff not in ['admin','owner']:
1842 self.DEBUG("Affiliation is not enough to Ban user","warn")
1843 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
1844 id = iq.getAttr('id')
1845 if id:
1846 reply.setAttr('id', id)
1847 reply.NT.query.addChild(node=item)
1848 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
1849 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
1850 err = Node('error', {'code':'405','type':'cancel'})
1851 err.addChild(node=na)
1852 reply.addChild(node=err)
1853 session.enqueue(reply)
1854 return
1855
1856 to.setAffiliation("outcast")
1857 to.setRole('none')
1858 try:
1859 if to.getBareJID() in self.whitelist:
1860 self.whitelist.remove(to.getBareJID())
1861 if to.getBareJID() not in self.blacklist:
1862 self.blacklist.append(to.getBareJID())
1863 except:
1864 self.DEBUG("Could not change affiliation for %s"%(to.getBareJID()),"error")
1865 return
1866
1867
1868 result = Iq(to=frm, frm=self.fullJID(),typ='result')
1869 session.enqueue(result)
1870
1871
1872 if to.getFullJID() in self.participants.keys():
1873 other = self.participants[frm]
1874 relative_frm = self.fullJID() + '/' + to.getNick()
1875 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1876 newitem = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole(), 'nick':to.getNick() } )
1877 if self.getWhois()== "anyone" \
1878 or self.getWhois() == "moderators" and self.participants[frm].getRole() == "moderator":
1879 newitem.setAttr('jid', to.getFullJID())
1880 actor = Node('actor',{'jid':other.getBareJID()})
1881 x.addChild(node=actor)
1882 for child in item.getChildren():
1883 newitem.addChild(node=child)
1884 status = Node('status',{'code':'301'})
1885 x.addChild(node=newitem)
1886 x.addChild(node=status)
1887 reply = Presence( to=to.getFullJID(), frm=relative_frm,typ='unavailable' )
1888 reply.addChild(node=x)
1889 s = self.muc.server.getsession(to.getFullJID())
1890 if s:
1891 s.enqueue(reply)
1892 self.deleteParticipant(to.getFullJID())
1893
1894
1895 relative_frm = self.fullJID() + '/' + to.getNick()
1896 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1897 newitem = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole(), 'nick':to.getNick() } )
1898 if self.getWhois()== "anyone" \
1899 or self.getWhois() == "moderators" and self.participants[frm].getRole() == "moderator":
1900 newitem.setAttr('jid', to.getFullJID())
1901
1902
1903 status = Node('status',{'code':'301'})
1904 x.addChild(node=newitem)
1905 for other in self.participants.values():
1906 reply = Presence( other.getFullJID(), frm=relative_frm, typ='unavailable' )
1907 reply.addChild(node=x)
1908 s = self.muc.server.getsession(other.getFullJID())
1909 if s:
1910 s.enqueue(reply)
1911 return
1912
1913 elif affiliation == "none" and (jid or nick) and not role:
1914 my_aff = self.participants[frm].getAffiliation()
1915
1916 if JID(frm).getStripped() == to.getBareJID() and \
1917 my_aff == "owner" and len(self.getRoomOwners()) == 1:
1918
1919
1920 reply = stanza.buildReply(typ="error")
1921 err = Node('error', {'code': '409', 'type': 'cancel'} )
1922 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
1923 err.addChild(node=conflict)
1924 reply.addChild(node=err)
1925 session.enqueue(reply)
1926 return
1927
1928 if my_aff == "admin" and to.getAffiliation() not in ['member','none','outcast'] \
1929 or my_aff == "owner" and to.getAffiliation() not in ['admin','member','none','outcast']\
1930 or my_aff not in ['admin','owner']:
1931
1932 self.DEBUG("Affiliation is not enough to Grant membership","warn")
1933 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
1934 id = iq.getAttr('id')
1935 if id:
1936 reply.setAttr('id', id)
1937 reply.NT.query.addChild(node=item)
1938 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
1939 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
1940 err = Node('error', {'code':'405','type':'cancel'})
1941 err.addChild(node=na)
1942 reply.addChild(node=err)
1943 session.enqueue(reply)
1944 return
1945
1946
1947 to.setAffiliation("none")
1948 try:
1949 del self.reserved_nicks[barejid]
1950 except:
1951 pass
1952
1953
1954
1955 if jid in self.whitelist:
1956 self.whitelist.remove(jid)
1957 if jid in self.blacklist:
1958 self.blacklist.remove(jid)
1959
1960
1961 result = Iq(to=frm, frm=self.fullJID(),typ='result')
1962 session.enqueue(result)
1963
1964
1965
1966 if self.isMembersOnly():
1967 other = self.participants[frm]
1968 relative_frm = self.fullJID() + '/' + to.getNick()
1969 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1970 newitem = Node('item', {'affiliation': to.getAffiliation(), 'role': to.getRole(), 'nick':to.getNick() } )
1971 if self.getWhois()== "anyone" \
1972 or self.getWhois() == "moderators" and self.participants[frm].getRole() == "moderator":
1973 newitem.setAttr('jid', to.getFullJID())
1974 for child in item.getChildren():
1975 newitem.addChild(node=child)
1976 status = Node('status',{'code':'321'})
1977 actor = Node('actor',{'jid':frm})
1978 x.addChild(node=actor)
1979 x.addChild(node=newitem)
1980 reply = Presence( to=to.getFullJID(), frm=relative_frm, typ='unavailable' )
1981 reply.addChild(node=x)
1982 s = self.muc.server.getsession(to.getFullJID())
1983 if s:
1984 s.enqueue(reply)
1985 self.deleteParticipant(to.getFullJID())
1986
1987
1988
1989
1990 relative_frm = self.fullJID() + '/' + to.getNick()
1991 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
1992 newitem = Node('item', {'affiliation': to.getAffiliation()})
1993 newitem.setAttr('role',to.getRole())
1994 newitem.setAttr('nick',to.getNick())
1995 if self.getWhois()== "anyone" \
1996 or self.getWhois() == "moderators" and self.participants[frm].getRole() == "moderator":
1997 newitem.setAttr('jid', to.getFullJID())
1998 x.addChild(node=newitem)
1999 for other in self.participants.values():
2000 reply = Presence( other.getFullJID(), frm=relative_frm, typ='unavailable' )
2001 reply.addChild(node=x)
2002 s = self.muc.server.getsession(other.getFullJID())
2003 if s:
2004 s.enqueue(reply)
2005 return
2006
2007 elif affiliation == "member" and (jid or nick) and not role:
2008 my_aff = self.participants[frm].getAffiliation()
2009
2010 if JID(frm).getStripped() == to.getBareJID() and \
2011 my_aff == "owner" and len(self.getRoomOwners()) == 1:
2012
2013
2014 self.DEBUG("The last owner MUST NOT step down","warn")
2015 reply = stanza.buildReply(typ="error")
2016 err = Node('error', {'code': '409', 'type': 'cancel'} )
2017 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
2018 err.addChild(node=conflict)
2019 reply.addChild(node=err)
2020 session.enqueue(reply)
2021 return
2022
2023 if my_aff not in ['admin','owner']:
2024 self.DEBUG("Affiliation is not enough to Grant membership","warn")
2025 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
2026 id = iq.getAttr('id')
2027 if id:
2028 reply.setAttr('id', id)
2029 reply.NT.query.addChild(node=item)
2030 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
2031 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
2032 err = Node('error', {'code':'405','type':'cancel'})
2033 err.addChild(node=na)
2034 reply.addChild(node=err)
2035 session.enqueue(reply)
2036 return
2037
2038 self.DEBUG("Granting membership to "+to.getBareJID(),"info")
2039
2040 to.setAffiliation("member")
2041
2042 if nick :
2043 self.reserveNick(to.getBareJID(), nick)
2044 else:
2045 self.reserveNick(to.getBareJID(), None)
2046
2047 if jid not in self.whitelist:
2048 self.whitelist.append(jid)
2049 if jid in self.blacklist:
2050 self.blacklist.remove(jid)
2051 if jid in self.visitors:
2052 self.visitors.remove(jid)
2053
2054
2055 result = Iq(to=frm, frm=self.fullJID(),typ='result')
2056 session.enqueue(result)
2057
2058
2059
2060 for p in self.participants.values():
2061 if p.getBareJID() == jid:
2062 relative_frm = self.fullJID() + '/' + nick
2063 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
2064 newitem = Node('item', {'affiliation':to.getAffiliation()} )
2065 newitem.setAttr('role',to.getRole())
2066 newitem.setAttr('nick',to.getNick())
2067 if self.getWhois()== "anyone" \
2068 or self.getWhois() == "moderators" and self.participants[frm].getRole() == "moderator":
2069 newitem.setAttr('jid', jid)
2070 x.addChild(node=newitem)
2071
2072 for other in self.participants.values():
2073 reply = Presence( other.getFullJID(), frm=relative_frm )
2074 reply.addChild(node=x)
2075 s = self.muc.server.getsession(other.getFullJID())
2076 if s:
2077 s.enqueue(reply)
2078 return
2079
2080 elif affiliation == "admin" and (jid or nick) and not role:
2081 my_aff = self.participants[frm].getAffiliation()
2082
2083 if JID(frm).getStripped() == to.getBareJID() and \
2084 my_aff == "owner" and len(self.getRoomOwners()) == 1:
2085
2086
2087 reply = stanza.buildReply(typ="error")
2088 err = Node('error', {'code': '409', 'type': 'cancel'} )
2089 conflict = Node('conflict', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
2090 err.addChild(node=conflict)
2091 reply.addChild(node=err)
2092 session.enqueue(reply)
2093 return
2094
2095 if my_aff not in ['owner']:
2096 self.DEBUG("Affiliation is not enough to Grant administrative privileges","warn")
2097 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
2098 id = iq.getAttr('id')
2099 if id:
2100 reply.setAttr('id', id)
2101 reply.NT.query.addChild(node=item)
2102 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
2103 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
2104 err = Node('error', {'code':'405','type':'cancel'})
2105 err.addChild(node=na)
2106 reply.addChild(node=err)
2107 session.enqueue(reply)
2108 return
2109
2110 """
2111 self.DEBUG("Granting admin privileges to "+str(to),"info")
2112 if to:
2113 to.setAffiliation("admin")
2114
2115 for p in self.participants.values():
2116 if p.getBareJID() == jid:
2117 if jid not in self.moderators:
2118 if jid in self.visitors:
2119 self.visitors.remove(jid)
2120 if self.isModeratedRoom():
2121 to.setRole('moderator')
2122 self.moderators.append(jid)
2123 else:
2124 to.setRole('participant')
2125 """
2126
2127 if jid not in self.getRoomAdmins():
2128 self.addRoomAdmin(jid)
2129 if jid in self.getRoomOwners():
2130 self.delRoomOwner(jid)
2131
2132
2133 result = Iq(to=frm, frm=self.fullJID(),typ='result')
2134 session.enqueue(result)
2135
2136 """
2137 #service informs remaining occupants
2138 #if jid in self.participants.keys():
2139 for p in self.participants.values():
2140 if p.getBareJID() == jid:
2141 relative_frm = self.fullJID() + '/' + nick
2142 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
2143 for other in self.participants.values():
2144 newitem = Node('item', {'affiliation': affiliation})
2145 newitem.setAttr('role',to.getRole())
2146 if nick: newitem.setAttr('nick',nick)
2147
2148 #if self.anonymous == "non" \
2149 #or self.anonymous == "semi" and other.getRole() == "moderator":
2150 if self.getWhois()== "anyone" \
2151 or self.getWhois() == "moderators" and other.getRole() == "moderator":
2152 newitem.setAttr('jid', jid)
2153 x.addChild(node=newitem)
2154 reply = Presence( other.getFullJID(), frm=relative_frm )
2155 reply.addChild(node=x)
2156 s = self.muc.server.getsession(other.getFullJID())
2157 if s:
2158 s.enqueue(reply)
2159 return
2160 """
2161
2162 return
2163
2164 elif affiliation == "owner" and (jid or nick) and not role:
2165 if self.participants[frm].getAffiliation() not in ['owner']:
2166 self.DEBUG("Affiliation is not enough to Grant owner privileges","warn")
2167 reply = Iq(frm=self.fullJID(), to=frm, typ="error")
2168 id = iq.getAttr('id')
2169 if id:
2170 reply.setAttr('id', id)
2171 reply.NT.query.addChild(node=item)
2172 reply.setQueryNS("http://jabber.org/protocol/muc#admin")
2173 na = Node('not-allowed', {'xmlns':"urn:ietf:params:xml:ns:xmpp-stanzas"})
2174 err = Node('error', {'code':'405','type':'cancel'})
2175 err.addChild(node=na)
2176 reply.addChild(node=err)
2177 session.enqueue(reply)
2178 return
2179
2180 """
2181 if to:
2182 to.setAffiliation("owner")
2183 """
2184
2185 if jid not in self.getRoomOwners():
2186 self.addRoomOwner(jid)
2187 if jid in self.getRoomAdmins():
2188 self.delRoomAdmin(jid)
2189
2190 """
2191 for p in self.participants.values():
2192 if p.getBareJID() == jid:
2193 if jid not in self.moderators:
2194 if jid in self.visitors:
2195 self.visitors.remove(jid)
2196 if self.isModeratedRoom():
2197 to.setRole('moderator')
2198 self.moderators.append(jid)
2199 else:
2200 to.setRole('participant')
2201 """
2202
2203
2204 result = Iq(to=frm, frm=self.fullJID(),typ='result')
2205 session.enqueue(result)
2206
2207 """
2208 #service informs remaining occupants
2209 #if jid in self.participants.keys():
2210 for p in self.participants.values():
2211 if p.getBareJID() == jid:
2212 relative_frm = self.fullJID() + '/' + nick
2213 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
2214 for other in self.participants.values():
2215 newitem = Node('item', {'affiliation': affiliation})
2216 newitem.setAttr('role',to.getRole())
2217 if nick: newitem.setAttr('nick',nick)
2218
2219 #if self.anonymous == "non" \
2220 #or self.anonymous == "semi" and other.getRole() == "moderator":
2221 if self.getWhois()== "anyone" \
2222 or self.getWhois() == "moderators" and other.getRole() == "moderator":
2223 newitem.setAttr('jid', jid)
2224 x.addChild(node=newitem)
2225 reply = Presence( other.getFullJID(), frm=relative_frm )
2226 reply.addChild(node=x)
2227 s = self.muc.server.getsession(other.getFullJID())
2228 if s:
2229 s.enqueue(reply)
2230 return
2231 """
2232 return
2233
2234
2235
2236 elif ns == "http://jabber.org/protocol/muc#admin" and typ == 'get':
2237 self.DEBUG("Admin query","info")
2238 if self.participants[frm].getRole() == "moderator" or \
2239 self.participants[frm].getAffiliation() in ['admin','owner']:
2240 for item in query.getTags('item'):
2241 nick = item.getAttr('nick')
2242 affiliation = item.getAttr('affiliation')
2243 role = item.getAttr('role')
2244 jid = item.getAttr('jid')
2245 to = None
2246 for k,v in self.participants.items():
2247 if v.getNick() == nick: to = v
2248 sender = self.participants[frm]
2249 if role and not nick and not affiliation:
2250 self.DEBUG("Retrieving list of "+role+"s","info")
2251 reply = Iq(typ='result',frm=self.fullJID(),to=frm,queryNS="http://jabber.org/protocol/muc#admin")
2252 id = iq.getAttr('id')
2253 if id:
2254 reply.setAttr('id', id)
2255 for k,v in self.participants.items():
2256 if v.getRole() == role:
2257 newitem = Node('item',{'nick':v.getNick(),'role':v.getRole(),'affiliation':v.getAffiliation()})
2258
2259 if self.getWhois():
2260 newitem.setAttr('jid',k)
2261 reply.T.query.addChild(node=newitem)
2262 reply.setID(stanza.getID())
2263 session.enqueue(reply)
2264 return
2265
2266
2267 elif affiliation and not nick and not role:
2268 self.DEBUG("Retrieving list of "+affiliation+"s","info")
2269 reply = Iq(typ='result',frm=self.fullJID(),to=frm,queryNS="http://jabber.org/protocol/muc#admin")
2270 id = iq.getAttr('id')
2271 if id:
2272 reply.setAttr('id', id)
2273 if affiliation == 'outcast':
2274 for v in self.blacklist:
2275 newitem = Node('item',{'affiliation':'outcast'})
2276 newitem.setAttr('jid',v)
2277 reply.T.query.addChild(node=newitem)
2278 elif affiliation == 'member':
2279 for v in self.whitelist:
2280 newitem = Node('item',{'affiliation':'member'})
2281 newitem.setAttr('jid',v)
2282 if v in self.participants.keys():
2283 p = self.participants[v]
2284 newitem.setAttr('nick',p.getNick())
2285 newitem.setAttr('role',p.getRole())
2286 reply.T.query.addChild(node=newitem)
2287
2288 elif affiliation == 'owner':
2289 for v in self.getRoomOwners():
2290 newitem = Node('item',{'affiliation':'owner'})
2291 newitem.setAttr('jid',v)
2292 if v in self.participants.keys():
2293 p = self.participants[v]
2294 newitem.setAttr('nick',p.getNick())
2295 newitem.setAttr('role',p.getRole())
2296 reply.T.query.addChild(node=newitem)
2297
2298 elif affiliation == 'admin':
2299 for v in self.getRoomAdmins():
2300 newitem = Node('item',{'affiliation':'admin'})
2301 newitem.setAttr('jid',v)
2302 if v in self.participants.keys():
2303 p = self.participants[v]
2304 newitem.setAttr('nick',p.getNick())
2305 newitem.setAttr('role',p.getRole())
2306 reply.T.query.addChild(node=newitem)
2307 reply.setID(stanza.getID())
2308 session.enqueue(reply)
2309 return
2310
2311 elif ns == "http://jabber.org/protocol/muc#owner" and typ == 'set':
2312 if self.participants[frm].getAffiliation() == "owner":
2313
2314 try:
2315 if stanza.T.query.getTag('destroy'): destroy = True
2316 else: destroy = False
2317 except:
2318 destroy = False
2319
2320 if destroy:
2321 self.DEBUG("Owner DESTROYING room "+ self.getName())
2322 self.muc.destroyRoom(self.getName(), session, stanza)
2323 else:
2324
2325 self.DEBUG("Owner sends room configuration")
2326 for child in stanza.T.query.getTags('x'):
2327 if child.getNamespace() == "jabber:x:data" and child.getAttr('type') == "submit":
2328
2329 if child.getTags('field'):
2330 self.DEBUG("Configuring room "+self.getName())
2331 self.configRoom(child)
2332 self.locked = False
2333 iq = Iq(frm=self.fullJID(), to=frm, typ='result')
2334 iq.setID(stanza.getID())
2335 session.enqueue(iq)
2336 elif child.getNamespace() == "jabber:x:data" and child.getType() == "cancel":
2337
2338 if self.locked: del self.muc.rooms[self.getName()]
2339 self.muc.saveRoomDB()
2340 else:
2341
2342 reply = stanza.buildReply(typ="error")
2343 err = Node('error', {'code': '403', 'type': 'auth'} )
2344 badr = Node('forbidden', {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
2345 err.addChild(node=badr)
2346 reply.addChild(node=err)
2347 session.enqueue(reply)
2348 return
2349
2350 elif ns == "http://jabber.org/protocol/muc#owner" and typ == 'get':
2351 if self.participants[frm].getAffiliation() == "owner":
2352
2353
2354 iq = stanza.buildReply('result')
2355 iq.setQueryNS(ns)
2356 form = DataForm()
2357 form.setTitle("Configuration for %s room"%(self.getName()))
2358 form.setInstructions("Your room has been created\nThe default configuration is good enough for you.\nIf you want to screw up this implementation, please fill in the form.")
2359 df = DataField("FORM_TYPE", "http://jabber.org/protocol/muc#roomconfig","hidden")
2360 form.addChild(node=df)
2361 df = DataField(name="muc#roomconfig_roomname",typ="text-single")
2362 df.addValue(self.getRoomName())
2363 df.setAttr("label","Natural-Language Room Name")
2364 form.addChild(node=df)
2365 df = DataField(name="muc#roomconfig_roomdesc",typ="text-single")
2366 df.setAttr("label","Short Description of Room")
2367 df.addValue(self.getRoomDesc())
2368 form.addChild(node=df)
2369 df = DataField(name="muc#roomconfig_lang",typ="text-single")
2370 df.setAttr("label","Natural Language for Room Discussions")
2371 df.addValue(self.getLang())
2372 form.addChild(node=df)
2373 df = DataField(name="muc#roomconfig_enablelogging",typ="boolean")
2374 df.setAttr("label","Enable Logging?")
2375 df.addValue(str(self.isLogging()))
2376 form.addChild(node=df)
2377 df = DataField(name="muc#roomconfig_changesubject",typ="boolean")
2378 df.setAttr("label","Allow Occupants to Change Subject?")
2379 df.addValue(str(self.isChangeSubject()))
2380 form.addChild(node=df)
2381 df = DataField(name="muc#roomconfig_allowinvites",typ="boolean")
2382 df.setAttr("label","Allow Occupants to Invite Others?")
2383 df.addValue(str(self.isAllowInvites()))
2384 form.addChild(node=df)
2385
2386 df = DataField(name="muc#roomconfig_maxusers",typ="text-single")
2387 df.setAttr("label","Maximum Number of Occupants")
2388 df.addValue(str(self.getMaxUsers()))
2389 form.addChild(node=df)
2390 df = DataField(name="muc#roomconfig_minusers",typ="text-single")
2391 df.setAttr("label","Minimum Number of Occupants")
2392 df.addValue(str(self.getMinUsers()))
2393
2394
2395
2396
2397
2398
2399 form.addChild(node=df)
2400 df = DataField(name="muc#roomconfig_presencebroadcast",typ="list-multi")
2401 df.setAttr("label","Roles for which Presence is Broadcast")
2402 for v in self.getPresenceBroadcast():
2403 df.addValue(str(v))
2404 df.addOption(('Moderator',"moderator"))
2405 df.addOption(('Participant',"participant"))
2406 df.addOption(('Visitor',"visitor"))
2407 form.addChild(node=df)
2408 df = DataField(name="muc#roomconfig_publicroom",typ="boolean")
2409 df.setAttr("label","Make Room Publicy Searchable?")
2410 df.addValue(str(self.isPublicRoom()))
2411 form.addChild(node=df)
2412 df = DataField(name="muc#roomconfig_persistentroom",typ="boolean")
2413 df.setAttr("label","Make Room Persistent?")
2414 df.addValue(str(self.isPersistentRoom()))
2415 form.addChild(node=df)
2416 df = DataField(name="muc#roomconfig_moderatedroom",typ="boolean")
2417 df.setAttr("label","Make Room Moderated?")
2418 df.addValue(str(self.isModeratedRoom()))
2419 form.addChild(node=df)
2420 df = DataField(name="muc#roomconfig_membersonly",typ="boolean")
2421 df.setAttr("label","Make Room Members-Only?")
2422 df.addValue(str(self.isMembersOnly()))
2423 form.addChild(node=df)
2424
2425 df = DataField(name="muc#roomconfig_allowregister",typ="boolean")
2426 df.setAttr("label","Allow users to register as members?")
2427 df.addValue(str(self.isAllowRegister()))
2428 form.addChild(node=df)
2429 df = DataField(name="muc#roomconfig_nicklockdown",typ="boolean")
2430 df.setAttr("label","Force members to use the registered nickname?")
2431 df.addValue(str(self.isLockedDown()))
2432 form.addChild(node=df)
2433
2434 df = DataField(name="muc#roomconfig_passwordprotectedroom",typ="boolean")
2435 df.setAttr("label","Password Required to Enter?")
2436 df.addValue(str(self.isPasswordProtectedRoom()))
2437 form.addChild(node=df)
2438 df = DataField(typ="fixed")
2439 df.addValue("If a password is required to enter this room, you must specify the password below.")
2440 form.addChild(node=df)
2441 df = DataField(name="muc#roomconfig_roomsecret",typ="text-private")
2442 df.setAttr("label","Password")
2443 df.addValue(str(self.getPassword()))
2444 form.addChild(node=df)
2445 df = DataField(name="muc#roomconfig_whois",typ="list-single")
2446 df.setAttr("label","Who May Discover Real JIDs?")
2447 df.addOption(('Moderators Only',"moderators"))
2448 df.addOption(('Anyone',"anyone"))
2449 df.addOption(('Nobody (Fully-Anonymous)',""))
2450 df.addValue(self.getWhois())
2451 form.addChild(node=df)
2452 df = DataField(typ="fixed")
2453 df.addValue("You may specify additional people who have administrative privileges in the room. Please provide one Jabber ID per line.")
2454 form.addChild(node=df)
2455 df = DataField(name="muc#roomconfig_roomadmins",typ="jid-multi")
2456 df.setAttr("label","Room Admins")
2457 for a in self.getRoomAdmins():
2458 df.addValue(a)
2459 form.addChild(node=df)
2460 df = DataField(typ="fixed")
2461 df.addValue("You may specify additional owners for this room. Please provide one Jabber ID per line.")
2462 form.addChild(node=df)
2463 df = DataField(name="muc#roomconfig_roomowners",typ="jid-multi")
2464 df.setAttr("label","Room Owners")
2465 for a in self.getRoomOwners():
2466 df.addValue(a)
2467 form.addChild(node=df)
2468
2469 iq.T.query.addChild(node=form)
2470
2471 session.enqueue(iq)
2472 return
2473
2474 elif ns == NS_REGISTER and typ == 'get':
2475
2476
2477 if JID(frm).getStripped() in self.whitelist or \
2478 JID(frm).getStripped() in self.getRoomOwners() or \
2479 JID(frm).getStripped() in self.getRoomAdmins():
2480
2481 reply = stanza.buildReply(typ="result")
2482 reply.setTag("register")
2483 session.enqueue(reply)
2484 return
2485 else:
2486
2487 reply = stanza.buildReply(typ="result")
2488 df = DataForm(typ="form",title=self.getRoomName()+" Registration Form")
2489 df.addInstructions("Please fill in this form in order to register with this room.")
2490 field = DataField(name="FORM_TYPE",value="http://jabber.org/protocol/muc#register",typ="hidden")
2491 df.addChild(node=field)
2492 field = DataField(name="muc#register_first",typ="text-single")
2493 field.setAttr("label","First Name")
2494 df.addChild(node=field)
2495 field = DataField(name="muc#register_last",typ="text-single")
2496 field.setAttr("label","Last Name")
2497 df.addChild(node=field)
2498 field = DataField(name="muc#register_roomnick",typ="text-single",required=1)
2499 field.setAttr("label","Desired Nickname")
2500 df.addChild(node=field)
2501 field = DataField(name="muc#register_url",typ="text-single")
2502 field.setAttr("label","Your URL")
2503 df.addChild(node=field)
2504 field = DataField(name="muc#register_email",typ="text-single")
2505 field.setAttr("label","Email Address")
2506 df.addChild(node=field)
2507 field = DataField(name="muc#register_faqentry",typ="text-multi")
2508 field.setAttr("label","FAQ Entry")
2509 df.addChild(node=field)
2510 reply.T.query.addChild(node=df)
2511 session.enqueue(reply)
2512 return
2513
2514 elif ns == NS_REGISTER and typ == 'set':
2515
2516 self.DEBUG("User attempts to register in room "+self.getName(),"info")
2517
2518 if not self.isAllowRegister():
2519 self.DEBUG("Registration is NOT allowed on room "+self.getName(),"warn")
2520 reply = stanza.buildReply(typ="error")
2521 err = Node('error', {'code':'503','type':'cancel'})
2522 err.setTag('service-unavailable', {'xmlns':'urn:ietf:params:xml:ns:xmpp-stanzas'})
2523 reply.addChild(node=err)
2524 session.enqueue(reply)
2525 return
2526
2527
2528 if JID(frm).getStripped() in self.whitelist or \
2529 JID(frm).getStripped() in self.getRoomOwners() or \
2530 JID(frm).getStripped() in self.getRoomAdmins():
2531
2532 reply = stanza.buildReply(typ="result")
2533 reply.setTag("register")
2534 session.enqueue(reply)
2535 return
2536
2537 for child in stanza.T.query.getTags('x'):
2538 if child.getNamespace() == "jabber:x:data" and child.getAttr('type') == "submit":
2539
2540 if child.getTags('field'):
2541 self.DEBUG("Registering user in room "+self.getName())
2542 if self.processRegistration(child,frm,stanza,session):
2543 iq = Iq(frm=self.fullJID(), to=frm, typ='result')
2544 session.enqueue(iq)
2545 self.muc.saveRoomDB()
2546
2547
2548
2549 except:
2550 self.DEBUG("No xmlns, don't know what to do","error")
2551
2553 """
2554 Reserve a nick in a the room.
2555 A jid can make a pre-reservation (nick == None).
2556 If a jid already has a correct nick reserved, it cannot be changed.
2557 """
2558
2559
2560
2561
2562
2563
2564
2565 if nick:
2566 for j,n in self.reserved_nicks.items():
2567 if nick == n:
2568 self.DEBUG("Could not reserve nick "+str(nick),"warn")
2569 return False
2570 if jid == j and n:
2571 self.DEBUG("The jid %s already has a nick registered"%(str(j)),"warn")
2572 return False
2573
2574 self.reserved_nicks[jid] = nick
2575 self.DEBUG("Reserved nick %s for %s"%(str(nick),jid),"ok")
2576 return True
2577
2578
2580 """
2581 Process the registration form (to a room) of a user
2582 """
2583 try:
2584 self.DEBUG("Process Registration","info")
2585 form = DataForm(node=x)
2586 self.DEBUG("DataForm parsed","info")
2587 except:
2588 self.DEBUG("ERROR PARSING","error")
2589
2590 reply = stanza.buildReply(typ="error")
2591 err = Node('error', {'code':'400','type':'modify'})
2592 err.setTag("bad-request",{'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
2593 reply.addChild(node=err)
2594 session.enqueue(reply)
2595 return
2596
2597 nick = None
2598 for field in form.getTags("field"):
2599 try:
2600 var = field.getVar()
2601 values = field.getValues()
2602
2603 if var == "muc#register_first":
2604 self.DEBUG("First Name is %s"%(values[0]),"info")
2605 elif var == "muc#register_last":
2606 self.DEBUG("Last Name is %s"%(values[0]),"info")
2607 elif var == "muc#register_roomnick":
2608 nick = values[0]
2609 self.DEBUG("Desired Nickname is %s"%(nick),"info")
2610 if nick in self.reserved_nicks.values() and nick:
2611
2612 reply = stanza.buildReply(typ="error")
2613 err = Node('error', {'code':'409','type':'cancel'})
2614 err.setTag("conflict",{'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
2615 reply.addChild(node=err)
2616 session.enqueue(reply)
2617 return
2618 else:
2619 self.reserved_nicks[JID(frm).getStripped()] = nick
2620 elif var == "muc#register_url":
2621 if values:
2622 self.DEBUG("URL is %s"%(values[0]),"info")
2623 elif var == "muc#register_email":
2624 if values:
2625 self.DEBUG("Email is %s"%(values[0]),"info")
2626 elif var == "muc#register_faqentry":
2627 if values:
2628 self.DEBUG("Faq is %s"%(str(values)),"info")
2629
2630 except:
2631 self.DEBUG("Registration of user %s in room %s failed"%(frm,self.getName()),"error")
2632
2633 reply = stanza.buildReply(typ="error")
2634 err = Node('error', {'code':'400','type':'modify'})
2635 err.setTag("bad-request",{'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'} )
2636 reply.addChild(node=err)
2637 session.enqueue(reply)
2638 return
2639
2640 self.DEBUG("Client %s successfully registered in room %s"%(frm,self.getName()),"ok")
2641
2642 to = None
2643 for k,p in self.participants.items():
2644 if k == frm:
2645 to = p
2646 break
2647
2648 if to:
2649 to.setAffiliation("member")
2650
2651 else:
2652 to = Participant(fulljid=frm, nick=nick, role="none", affiliation="member")
2653
2654 jid = to.getBareJID()
2655 if jid not in self.whitelist:
2656 self.whitelist.append(jid)
2657 if jid in self.blacklist:
2658 self.blacklist.remove(jid)
2659 if jid in self.visitors:
2660 self.visitors.remove(jid)
2661
2662
2663 reply = stanza.buildReply(typ="result")
2664 session.enqueue(reply)
2665
2666
2667
2668 for p in self.participants.values():
2669 if p.getBareJID() == jid:
2670 relative_frm = self.fullJID() + '/' + to.getNick()
2671 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
2672 newitem = Node('item', {'affiliation':to.getAffiliation()} )
2673 newitem.setAttr('role',to.getRole())
2674 newitem.setAttr('nick',to.getNick())
2675 if self.getWhois()== "anyone" \
2676 or self.getWhois() == "moderators" and other.getRole() == "moderator":
2677 newitem.setAttr('jid', jid)
2678 x.addChild(node=newitem)
2679
2680 for other in self.participants.values():
2681 reply = Presence( other.getFullJID(), frm=relative_frm )
2682 reply.addChild(node=x)
2683 s = self.muc.server.getsession(other.getFullJID())
2684 if s:
2685 s.enqueue(reply)
2686 return
2687
2688 self.muc.saveRoomDB()
2689
2690
2692 """
2693 Configurate a room given a dataform with the desired configuration
2694 """
2695 form = DataForm(node=x)
2696 self.DEBUG("DataForm parsed","info")
2697 for field in form.getTags("field"):
2698 try:
2699 var = field.getVar()
2700 values = field.getValues()
2701
2702 if var == "muc#roomconfig_maxusers":
2703 try:
2704 self.setMaxUsers(values[0])
2705 except:
2706 pass
2707 if var == "muc#roomconfig_minusers":
2708 try:
2709 self.setMinUsers(values[0])
2710 except:
2711 pass
2712 elif var == "muc#roomconfig_presencebroadcast":
2713 self.config[var] = []
2714 for val in values:
2715 if val in ["moderator","participant","visitor"]:
2716 self.config[var].append(val)
2717 elif var == "muc#roomconfig_whois":
2718 if values[0] in ["moderators","anyone",""]:
2719 self.config[var] = str(values[0])
2720 elif var == "muc#roomconfig_roomadmins":
2721 old_admin_list = copy.copy(self.config[var])
2722
2723 for val in values:
2724
2725 self.addRoomAdmin(val)
2726
2727
2728 for adm in old_admin_list:
2729 if adm not in values:
2730
2731 self.delRoomAdmin(adm)
2732 elif var == "muc#roomconfig_roomowners":
2733 self.config[var] = []
2734 for val in values:
2735 self.config[var].append(val)
2736 elif var =="muc#roomconfig_membersonly":
2737 self.setMembersOnly(values[0])
2738 elif var =="muc#roomconfig_moderatedroom":
2739 self.setModeratedRoom(values[0])
2740 elif var in ["muc#roomconfig_passwordprotectedroom", "muc#roomconfig_nicklockdown", "muc#roomconfig_allowregister", \
2741 "muc#roomconfig_persistentroom","muc#roomconfig_publicroom","muc#roomconfig_allowinvites", \
2742 "muc#roomconfig_changesubject","muc#roomconfig_enablelogging"]:
2743 if values[0] in [0, '0', False]:
2744 self.config[var] = 0
2745 elif values[0] in [1, '1', True]:
2746 self.config[var] = 1
2747 elif var in ["muc#roomconfig_roomname","muc#roomconfig_roomdesc","muc#roomconfig_lang","muc#roomconfig_roomsecret"]:
2748 self.config[var] = str(values[0])
2749
2750 except:
2751 self.DEBUG("Configuration of room %s failed"%(self.getName()),"error")
2752
2753 self.DEBUG("Room %s successfully configured"%(self.getName()),"ok")
2754 self.muc.saveRoomDB()
2755
2756
2878
2880 """
2881 Delete a participant from a room
2882 """
2883 try:
2884 barejid = JID(fulljid).getStripped()
2885 if barejid in self.visitors:
2886 self.visitors.remove(barejid)
2887 if barejid in self.moderators:
2888 self.moderators.remove(barejid)
2889 del self.participants[fulljid]
2890 self.DEBUG("Participant %s deleted from room %s"%(fulljid,self.getName()),"info")
2891 except:
2892
2893 pass
2894
2896 """
2897 Set the affiliation of a participant
2898 """
2899
2900 if type(participant) == types.StringType:
2901 jid = participant
2902
2903 elif type(participant) == types.InstanceType:
2904 if isinstance(participant, JID):
2905 jid = str(participant)
2906 elif isinstance(participant, Participant):
2907 jid = participant.getFullJID()
2908
2909
2910 try:
2911 self.participants[jid].setAffiliation(affiliation)
2912 if affiliation == "owner":
2913
2914 self.addRoomOwner(jid)
2915 if affiliation == "admin":
2916 self.addRoomAdmin(jid)
2917
2918 except:
2919 self.DEBUG("No such participant " + str(jid),'error')
2920
2921
2923 """
2924 The conference component. Composed of multiple rooms
2925 """
2926 NS = ''
2927
2929 self.server = server
2930 try:
2931 self.jid = server.plugins['MUC']['jid']
2932 self.name = server.plugins['MUC']['name']
2933 except:
2934 self.DEBUG("Could not find MUC jid or name","error")
2935 return
2936
2937 self.rooms = dict()
2938 self.loadRoomDB()
2939
2940 general = Room('general', self, 'General Discussion')
2941 self.addRoom(general)
2942 coffee = Room('coffee', self, 'Coffee Room')
2943 self.addRoom(coffee)
2944 spade_room = Room('spade', self, 'SPADE Agents')
2945 self.addRoom(spade_room)
2946 member_room = Room('restricted', self, 'Restricted Area', whitelist=['q1@thx1138.dsic.upv.es'])
2947
2948 member_room.setMembersOnly(True)
2949 self.addRoom(member_room)
2950
2951 black_room = Room('black', self, 'Black Note')
2952
2953 black_room.setModeratedRoom(True)
2954 black_room.moderators.append('q1@thx1138.dsic.upv.es')
2955
2956 black_room.visitors.append('q3@thx1138.dsic.upv.es')
2957
2958 black_room.addRoomOwner('q1@thx1138.dsic.upv.es')
2959
2960
2961
2962 black_room.whitelist.append('q1@thx1138.dsic.upv.es')
2963
2964 black_room.moderators.append('q1@tatooine.dsic.upv.es')
2965
2966 black_room.visitors.append('q3@tatooine.dsic.upv.es')
2967 black_room.addRoomOwner('q1@tatooine.dsic.upv.es')
2968
2969
2970
2971
2972
2973 black_room.setMembersOnly(True)
2974
2975
2976
2977
2978 self.addRoom(black_room)
2979 non = Room('non',self,'Non-Anonima')
2980
2981 non.setWhois("anyone")
2982 self.addRoom(non)
2983 fully = Room('fully',self,'Fully-Anonima')
2984
2985 fully.setWhois("")
2986 self.addRoom(fully)
2987
2988 self.DEBUG("Created MUC: '%s' '%s'"%(self.name,str(self.jid)), "warn")
2989
2991 """
2992 Show a textual representation of the conference
2993 """
2994 return str(self.jid) + ": " + str(self.rooms)
2995
2996 - def addRoom(self, room = None, name = None):
2997 """
2998 Add a room to the conference
2999 """
3000 if room:
3001
3002 room.muc = self
3003
3004 self.rooms[str(room.getName())] = room
3005 self.saveRoomDB()
3006 return True
3007 elif name:
3008
3009 self.rooms[str(name)] = Room(name, self)
3010 self.saveRoomDB()
3011 return True
3012 else:
3013
3014 return False
3015
3017 """
3018 Destroy a room (for a reason). A venue (alternative new room) may be declared
3019 to take place of the destroyed room
3020 """
3021 if self.rooms.has_key(name):
3022 room = self.rooms[name]
3023 else:
3024 return
3025
3026
3027 try:
3028 venue = stanza.T.query.getAttr('jid')
3029 except:
3030 venue = None
3031 try:
3032 reason = stanza.T.query.T.destroy.T.reason
3033 except:
3034 reason = None
3035
3036 if reason:
3037 self.DEBUG("Destroying the room %s because: %s"%(name,reason.getData()), "info")
3038 else:
3039 self.DEBUG("Destroying the room %s"%(name), "info")
3040 x = Node('x', {'xmlns':'http://jabber.org/protocol/muc#user'})
3041 item = Node('item', {'role':'none', 'affiliation':'none'})
3042 destroy = Node('destroy')
3043 if venue:
3044 destroy.setAttr('jid',venue)
3045 if reason:
3046 rea = Node('reason')
3047 rea.setData(reason.getData())
3048 destroy.addChild(node=rea)
3049 x.addChild(node=item)
3050 x.addChild(node=destroy)
3051 for k,p in room.participants.items():
3052
3053 relative_frm = room.fullJID() + "/" + p.getNick()
3054 pres = Presence(to=k, frm=relative_frm, typ="unavailable")
3055 pres.addChild(node=x)
3056 s = None
3057 s = self.server.getsession(k)
3058 if s:
3059 s.enqueue(pres)
3060
3061
3062 iq = stanza.buildReply(typ="result")
3063 owner_session.enqueue(iq)
3064
3065
3066 del self.rooms[name]
3067 del room
3068
3069
3070 self.saveRoomDB()
3071
3072 return
3073
3075 """
3076 Mini-dispatcher for the jabber stanzas that arrive to the Conference
3077 """
3078 self.DEBUG("MUC dispatcher called", "warn")
3079 try:
3080 to = stanza['to']
3081 room = to.getNode()
3082 domain = to.getDomain()
3083 except:
3084 self.DEBUG("There was no 'to'",'warn')
3085
3086
3087 if room == '' and domain == str(self.jid):
3088 if stanza.getName() == 'iq':
3089 self.IQ_cb(session, stanza)
3090 elif stanza.getName() == 'presence':
3091 self.Presence_cb(session, stanza)
3092
3093
3094 if room in self.rooms.keys() and domain == str(self.jid):
3095 self.rooms[room].dispatch(session, stanza)
3096 else:
3097
3098 self.notExist_cb(session,stanza)
3099
3101 '''
3102 Callback for presence stanzas directed to the conference itself
3103 '''
3104 self.DEBUG("Presence callback of the MUC called")
3105 pass
3106
3107
3108
3110 '''
3111 Callback called when a stanza is directed to a room that does not (yet) exist
3112 '''
3113 self.DEBUG("NotExist handler called","info")
3114
3115 to = stanza['to']
3116 room = to.getNode()
3117 domain = to.getDomain()
3118 nick = to.getResource()
3119 frm = str(session.peer)
3120 typ = stanza.getType()
3121 name = stanza.getName()
3122
3123 if name == "presence":
3124 if typ == "available" or not typ:
3125
3126 p = Participant(frm, nick=nick, affiliation='owner')
3127 room_node = Room(room, self, creator = p)
3128 self.addRoom(room_node)
3129
3130 relative_frm = room_node.fullJID() + '/' + nick
3131 pres = Presence(frm=relative_frm)
3132 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} )
3133 item = Node('item', { 'affiliation': p.getAffiliation(), 'role': p.getRole() } )
3134 status = Node('status', {'code': '201'})
3135 x.addChild(node=item)
3136 x.addChild(node=status)
3137 pres.addChild(node=x)
3138 session.enqueue(pres)
3139
3140 for tag in stanza.getChildren():
3141 if tag.getName() =='x':
3142 if tag.getNamespace() == "http://jabber.org/protocol/muc":
3143
3144 room_node.locked = True
3145 else:
3146
3147 room_node.locked = False
3148
3149 room_node.dispatch(session,stanza)
3150 return
3151
3152 if name == "iq":
3153 if stanza.getQueryNS() == NS_REGISTER:
3154
3155
3156 self.DEBUG("Room does not exist","warn")
3157 reply = stanza.buildReply(typ="error")
3158 err = Node('error', {'code':'503','type':'cancel'})
3159 err.setTag('service-unavailable', {'xmlns':'urn:ietf:params:xml:ns:xmpp-stanzas'})
3160 reply.addChild(node=err)
3161 session.enqueue(reply)
3162 return
3163
3164
3165 - def IQ_cb(self, session, iq):
3166 """
3167 Manages IQ stanzas directed to the Conference itself
3168 """
3169 self.DEBUG("MUC Iq callback called", "warn")
3170
3171 query = iq.getTag('query')
3172 if query:
3173 try:
3174 ns = str(iq.getQueryNS())
3175 typ = str(iq.getType())
3176
3177 if ns == NS_DISCO_INFO and typ == 'get':
3178
3179 reply = Iq('result', NS_DISCO_INFO, to=iq.getFrom(), frm=str(self.jid))
3180 rquery=reply.getTag('query')
3181 id = iq.getAttr('id')
3182 if id:
3183 reply.setAttr('id', id)
3184 identity = { 'category': 'conference', 'type': 'text', 'name':self.name }
3185 feature = { 'var': 'http://jabber.org/protocol/muc' }
3186 rquery.setTag('identity', identity)
3187 rquery.setTag('feature', feature)
3188 session.enqueue(reply)
3189
3190 elif ns == NS_DISCO_ITEMS:
3191 self.DEBUG("NS_DISCO_ITEMS requested", "warn")
3192
3193 reply = Iq('result', NS_DISCO_ITEMS, to=iq.getFrom(), frm=str(self.jid))
3194 rquery=reply.getTag('query')
3195 id = iq.getAttr('id')
3196 if id:
3197 reply.setAttr('id', id)
3198
3199 for room,v in self.rooms.items():
3200
3201 if v.isPublicRoom() and not v.locked:
3202
3203 attrs = { 'jid': str(room+'@'+self.jid), 'name': str(v.getName()) }
3204 rquery.setTag('item', attrs)
3205 session.enqueue(reply)
3206 self.DEBUG("NS_DISCO_ITEMS sent", "warn")
3207
3208 except:
3209 self.DEBUG("No xmlns, don't know what to do",'warn')
3210
3212 """
3213 Load persistent rooms and their configurations to the database
3214 """
3215 try:
3216 fh = open("roomdb.xml", 'r')
3217 roomdb = pickle.load(fh)
3218 fh.close()
3219 for r in roomdb.values():
3220 v = Room(name=r.name, subject=r.subject, muc=self, creator=r.creator, whitelist=copy.copy(r.whitelist), blacklist=copy.copy(r.blacklist))
3221 v.config = r.config
3222 v.locked = r.locked
3223 v.role_privileges = r.role_privileges
3224 self.rooms[v.getName()] = v
3225 self.DEBUG("Room Database Loaded","info")
3226 except:
3227 self.DEBUG("Could not load Room Database","error")
3228
3229 return
3230
3232 """
3233 Save persistent rooms and their configurations to a static database
3234 """
3235 try:
3236 roomdb = dict()
3237 for k,v in self.rooms.items():
3238 if v.isPersistentRoom():
3239
3240 r = SerializableRoom(v)
3241 roomdb[k] = r
3242
3243 fh = open("roomdb.xml", 'w')
3244
3245 pickle.dump(roomdb, fh)
3246 fh.close()
3247 self.DEBUG('Room database saved', 'info')
3248 except:
3249 self.DEBUG("Could not save room database", "error")
3250
3251 return
3252
3253
3254
3255 if __name__ == "__main__":
3256 conf = Conference("muc.localhost")
3257 p1 = Participant('p1@localhost/res', nick="PlayerOne")
3258 p2 = Participant('p2@localhost/Gaim', nick="PlayerTwo")
3259 r1 = Room('house@muc.localhost', conf, "My House", creator=p1)
3260 r2 = Room('auction@muc.localhost', conf, "Auction House", creator=p2)
3261
3262
3263 conf.addRoom(r1)
3264 conf.addRoom(r2)
3265
3266 print p1
3267 print p2
3268 print r1
3269 print conf
3270