Package spade :: Package xmppd :: Package modules :: Module muc
[hide private]
[frames] | no frames]

Source Code for Module spade.xmppd.modules.muc

   1  from xmpp import * 
   2  import types 
   3  import copy 
   4   
   5  import pickle 
   6   
   7   
8 -class BadPassword(Exception):
9 ''' 10 The user provided a wrong password 11 '''
12 - def __init__(self): pass
13 -class NotAMember(Exception):
14 ''' 15 The user is not a member of the room 16 '''
17 - def __init__(self): pass
18 -class Blacklisted(Exception):
19 ''' 20 The user is in the black list of the room 21 '''
22 - def __init__(self): pass
23 -class MaxUsers(Exception):
24 ''' 25 The maximum number of users for this room has been reached 26 '''
27 - def __init__(self): pass
28 -class NoVoice(Exception):
29 ''' 30 The user has no voice in this room 31 '''
32 - def __init__(self): pass
33 -class NickLockedDown(Exception):
34 ''' 35 The nickname that the user is trying to set is already locked down 36 '''
37 - def __init__(self): pass
38
39 -class Participant:
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 # Get data from constructor 45 self.fulljid = fulljid 46 # If there was no barejid, build it 47 if not barejid: 48 self.barejid = str(fulljid).split('/')[0] 49 else: 50 self.barejid = barejid 51 # If there was no nick, take the barejid instead 52 if not nick: 53 self.nick = self.barejid 54 else: 55 self.nick = nick 56 # If there was no role, take the 'none' role 57 if not role: 58 self.role = 'none' 59 else: 60 self.role = role 61 # Same as role 62 if not affiliation: 63 self.affiliation = 'none' 64 else: 65 self.affiliation = affiliation
66
67 - def __str__(self):
68 return '<' + str(self.fulljid) + ' barejid="' + str(self.barejid) + '" nick="' + str(self.nick) + '" role="' + str(self.role) + '" affiliation="' + str(self.affiliation) + '">'
69
70 - def getFullJID(self):
71 """ 72 Get the participant's full JID 73 """ 74 return self.fulljid
75
76 - def getBareJID(self):
77 """ 78 Get the participant's bare JID 79 """ 80 return self.barejid
81
82 - def getNick(self):
83 """ 84 Get the participant's nickname 85 """ 86 return self.nick
87
88 - def getRole(self):
89 """ 90 Get the participant's role 91 """ 92 if self.role: 93 return self.role.lower() 94 else: 95 return 'none'
96
97 - def getAffiliation(self):
98 """ 99 Get the participant's affiliation 100 """ 101 if self.affiliation: 102 return self.affiliation.lower() 103 else: 104 return 'none'
105
106 - def setFullJID(self, fulljid):
107 """ 108 Set the participant's full JID 109 """ 110 self.fulljid = fulljid
111
112 - def setBareJID(self, barejid):
113 """ 114 Set the participant's bare JID 115 """ 116 self.barejid = barejid
117
118 - def setNick(self, nick):
119 """ 120 Set the participant's nickname 121 """ 122 self.nick = nick
123
124 - def setRole(self, role):
125 """ 126 Set the participant's role 127 """ 128 self.role = role
129
130 - def setAffiliation(self, affiliation):
131 """ 132 Set the participant's affiliation 133 """ 134 self.affiliation = affiliation
135 136
137 -class SerializableRoom:
138 """ 139 A serializable (reduced) version of a Room 140 """
141 - def __init__(self,orig):
142 # Get original room's important data 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
152 -class Room:
153 """ 154 A MUC room 155 """
156 - def __init__(self, name, muc, subject=None, template=None, creator=None, whitelist=[], blacklist=[], password=None):
157 # Configuration dict 158 self.config = {} 159 160 # The Conference that owns the room 161 self.muc = muc 162 # Get data from constructor 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'] = "" # FULLY_ANONYMOUS 182 self.config['muc#roomconfig_roomadmins'] = [] 183 self.config['muc#roomconfig_roomowners'] = [] 184 185 # Init DEBUG 186 self.DEBUG = self.muc.DEBUG 187 188 # Initialize default room specific values 189 #self.hidden = False 190 #self.open = True 191 #self.moderated = False 192 #self.anonymous = 'fully' 193 #self.unsecured = True 194 #self.password = password 195 #self.persistent = False 196 #self.maxusers = 0 # No max 197 self.locked = False # Locked for other clients than the owner. See MUC XEP Section 9.1.1 198 199 # Initialize default role privileges 200 # Every privilege is expressed in a hierarchical form. 201 # If a given privilege is granted to a client with the role of 'visitor', 202 # all superior roles, will have that privilege too (i.e. 'participant' and 'moderator') 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 # If there was no subject, take the first part of the jid instead 211 if not subject: 212 #self.subject = name 213 self.setSubject("") 214 else: 215 #self.subject = subject 216 self.setSubject(subject) 217 # If there was a template, change values by default 218 if template: 219 self.DEBUG("TODO: Implement room templates",'warn') 220 221 # Initialize white and blacklists 222 self.whitelist = copy.copy(whitelist) 223 self.blacklist = copy.copy(blacklist) 224 225 # Moderators, owners, voices, etc... 226 # Roles. A standard client is considered a "participant", role-wise 227 self.moderators = [] 228 self.visitors = [] 229 # Initialize participants dict. It will be indexed by the participants full JIDs 230 self.participants = {} # 'jid':'Participant_instance' 231 232 # Affiliations. A outcast is so if he/she is placed in the blacklist 233 #self.owners = [] 234 #self.admins = [] 235 236 # List of reserved nicks 237 self.reserved_nicks = {} 238 239 # If there was a creator, add it to the participants dict 240 if creator: 241 self.creator = creator 242 #self.owners.append(creator.getBareJID()) 243 self.addRoomOwner(creator.getBareJID()) 244 #if self.moderated: 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
256 - def getName(self):
257 """ 258 Get the room's true Name 259 """ 260 return self.name
261 - def setName(self, n):
262 """ 263 Set the room's true Name 264 """ 265 self.name = str(n)
266 - def getRoomName(self):
267 """ 268 Get the room's RoomName (display name) 269 """ 270 return self.config["muc#roomconfig_roomname"]
271 - def setRoomName(self,name):
272 """ 273 Set the room's RoomName (display name) 274 """ 275 self.config["muc#roomconfig_roomname"] = name
276 - def getSubject(self):
277 """ 278 Get the room's Subject (topic) 279 """ 280 return self.subject
281 - def setSubject(self,name):
282 """ 283 Set the room's Subject (topic) 284 """ 285 self.subject = name
286 - def getRoomDesc(self):
287 """ 288 Get the room's Description 289 """ 290 return self.config["muc#roomconfig_roomdesc"]
291 - def setRoomDesc(self,name):
292 """ 293 Set the room's Description 294 """ 295 self.config["muc#roomconfig_roomdesc"] = name
296 - def isLogging(self):
297 """ 298 Check if message logging is enabled in the room 299 """ 300 return self.config["muc#roomconfig_enablelogging"]
301 - def setLogging(self,val):
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
308 - def getLang(self):
309 """ 310 Get the language used in the room 311 """ 312 return self.config["muc#roomconfig_lang"]
313 - def setLang(self,name):
314 """ 315 Set the language used in the room 316 """ 317 self.config["muc#roomconfig_lang"] = name
318 - def isChangeSubject(self): # Enforce this on subject change
319 """ 320 Check wether the subject can be changed in the room 321 """ 322 return self.config["muc#roomconfig_changesubject"]
323 - def setChangeSubject(self,val):
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
330 - def isAllowInvites(self):
331 """ 332 Check wether invitations are allowed in the room 333 """ 334 return self.config["muc#roomconfig_allowinvites"]
335 - def setAllowInvites(self,val):
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
342 - def getMaxUsers(self):
343 """ 344 Gets maximum number of concurrent users in the room 345 """ 346 return self.config["muc#roomconfig_maxusers"]
347 - def setMaxUsers(self,m):
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
357 - def getMinUsers(self):
358 """ 359 Gets minimum number of concurrent users in the room 360 """ 361 return self.config["muc#roomconfig_minusers"]
362 - def setMinUsers(self,m):
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
372 - def getPresenceBroadcast(self): # Enforce this on presence broadcasting
373 """ 374 Get the list of roles which receive presence stanzas broadcasted in the room 375 """ 376 return self.config["muc#roomconfig_presencebroadcast"]
377 - def addPresenceBroadcast(self,name):
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)
383 - def delPresenceBroadcast(self,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)
389 - def isPublicRoom(self):
390 """ 391 Check wether the room is public 392 """ 393 return self.config["muc#roomconfig_publicroom"]
394 - def setPublicRoom(self,val):
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
401 - def isPersistentRoom(self):
402 """ 403 Check wether the room is persistent 404 """ 405 return self.config["muc#roomconfig_persistentroom"]
406 - def setPersistentRoom(self,val):
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
413 - def isModeratedRoom(self):
414 """ 415 Check wether the room is moderated 416 """ 417 return self.config["muc#roomconfig_moderatedroom"]
418 - def setModeratedRoom(self,val):
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 #service informs remaining occupants 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 #service informs remaining occupants 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
483 - def isLockedDown(self):
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"]
488 - def setLockedDown(self,val):
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
495 - def isAllowRegister(self):
496 """ 497 Check wether the room allows the registration process 498 """ 499 return self.config["muc#roomconfig_allowregister"]
500 - def setAllowRegister(self,val):
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
507 - def isMembersOnly(self):
508 """ 509 Check wether the room is members-only 510 """ 511 return self.config["muc#roomconfig_membersonly"]
512 - def setMembersOnly(self,val):
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 # Copy admins and owner to the whitelist 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 # Kick all non-members, non-owners and non-admins out of the room 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 #service removes kicked occupant 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 #service informs remaining occupants 560 relative_frm = self.fullJID() + '/' + to.getNick() 561 # If 'to' equals the 'relative from' of the sender, exit the room 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
579 - def isPasswordProtectedRoom(self):
580 """ 581 Check wether entrance to the room is protected by a password 582 """ 583 return self.config["muc#roomconfig_passwordprotectedroom"]
584 - def setPasswordProtectedRoom(self,val):
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
591 - def getPassword(self):
592 """ 593 Get the password of the room 594 """ 595 return self.config["muc#roomconfig_roomsecret"]
596 - def setPassword(self,name):
597 """ 598 Set the actual password of the room 599 """ 600 self.config["muc#roomconfig_roomsecret"] = name
601 - def getWhois(self):
602 """ 603 Get the whois permission 604 """ 605 return self.config["muc#roomconfig_whois"]
606 - def setWhois(self,name):
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
615 - def getRoomAdmins(self):
616 """ 617 Get the list of room admins 618 """ 619 return self.config["muc#roomconfig_roomadmins"]
620 - def addRoomAdmin(self,name):
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) # Pre-reserve nick 630 631 for k,v in self.participants.items(): 632 if barejid in k: 633 # Set this participant (k,v) to admin 634 self.DEBUG("Granting admin privileges to "+k,"info") 635 v.setAffiliation('admin') 636 self.reserveNick(v.getBareJID(), v.getNick()) 637 # Add the participant to the correct lists and change the role 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 #service informs remaining occupants 653 #if jid in self.participants.keys(): 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
675 - def delRoomAdmin(self,name):
676 """ 677 Remove an admin from the room 678 """ 679 if name in self.config["muc#roomconfig_roomadmins"]: 680 self.config["muc#roomconfig_roomadmins"].remove(name) 681 else: 682 return 683 barejid = JID(name).getStripped() 684 685 for k,v in self.participants.items(): 686 if barejid in k: 687 # Set this participant (k,v) to member 688 self.DEBUG("Removing admin privileges to "+k,"info") 689 if self.isMembersOnly(): 690 v.setAffiliation('member') 691 else: 692 v.setAffiliation('none') 693 try: 694 del self.reserved_nicks[barejid] 695 except: 696 pass 697 # Add the participant to the correct lists and change the role 698 if self.isModeratedRoom(): 699 if barejid in self.moderators: 700 self.moderators.remove(barejid) 701 v.setRole('participant') 702 else: 703 v.setRole('visitor') 704 if barejid not in self.visitors: 705 self.visitors.append(barejid) 706 707 break 708 709 #service informs remaining occupants 710 for p in self.participants.values(): 711 if p.getBareJID() == barejid: 712 nick = p.getNick() 713 relative_frm = self.fullJID() + '/' + nick 714 x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc#user'} ) 715 newitem = Node('item', {'affiliation': p.getAffiliation()}) 716 newitem.setAttr('role',p.getRole()) 717 if nick: newitem.setAttr('nick',nick) 718 if self.getWhois()== "anyone" \ 719 or self.getWhois() == "moderators" and other.getRole() == "moderator": 720 newitem.setAttr('jid', barejid) 721 x.addChild(node=newitem) 722 723 for other in self.participants.values(): 724 reply = Presence( other.getFullJID(), frm=relative_frm ) 725 reply.addChild(node=x) 726 s = self.muc.server.getsession(other.getFullJID()) 727 if s: 728 s.enqueue(reply) 729 return
730
731 - def getRoomOwners(self):
732 """ 733 Get the list of room owners 734 """ 735 return self.config["muc#roomconfig_roomowners"]
736 - def addRoomOwner(self,name):
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) # Pre-reserve nick 746 747 for k,v in self.participants.items(): 748 if barejid in k: 749 # Set this participant (k,v) to admin 750 self.DEBUG("Granting owner privileges to "+k,"info") 751 v.setAffiliation('owner') 752 self.reserveNick(v.getBareJID(), v.getNick()) 753 # Add the participant to the correct lists and change the role 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 #service informs remaining occupants 769 #if jid in self.participants.keys(): 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
791 - def delRoomOwner(self,name):
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 # Set this participant (k,v) to member 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 # Add the participant to the correct lists and change the role 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 #service informs remaining occupants 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
848 - def __str__(self):
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
882 - def fullJID(self):
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
888 - def dispatch(self, session, stanza):
889 """ 890 Mini-dispatcher for the jabber stanzas that arrive to the room 891 """ 892 self.muc.DEBUG("Room '"+self.getName()+"' dispatcher called") 893 if stanza.getName() == 'iq': 894 self.IQ_cb(session, stanza) 895 elif stanza.getName() == 'presence': 896 self.Presence_cb(session, stanza) 897 elif stanza.getName() == 'message': 898 self.Message_cb(session, stanza)
899 # TODO: Implement the rest of protocols 900
901 - def Message_cb(self, session, stanza):
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 # Message should be to the room itself 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 # A 'subject'-change message 915 if subject: 916 if self.isChangeSubject(): 917 if not self.isModeratedRoom(): 918 # Unmoderated room, change the subject 919 try: 920 # Get the participant who changes the subject 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 # Not a participant of this room 927 return 928 else: 929 # Moderated room, check permissions 930 try: 931 p = self.participants[frm] 932 if p.getRole() == 'moderator': 933 #Change the subject 934 self.setSubject(subject.getData()) 935 self.DEBUG("Subject changed to "+str(subject.getData()),"info") 936 self.muc.saveRoomDB() 937 else: 938 # Not enough permissions 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 # Error changing the subject 951 return 952 # Notify the change of subject 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 # Error sending the subject change 962 return 963 else: 964 # Not enough permissions 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 # General message to everyone 978 elif self.participants.has_key(frm): 979 try: 980 if self.isModeratedRoom() and JID(frm).getStripped() in self.visitors: # Visitor in a moderated room 981 raise NoVoice 982 983 self.DEBUG("General message from %s to everyone in room %s"%(str(frm),str(self.getName())),'info') 984 # Change the 'from' 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 # Special bot-like commands 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 # Is it an invitation? 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 # It's an invitation 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 # Add new member to the room if it is members only 1071 #if not self.open: 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 #if self.password: 1083 if self.getPassword(): 1084 pwd = Node('password') 1085 pwd.setData(self.getPassword()) # With two balls 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 #send an "item-not-found error" to the sender 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 #send a "not-allowed error" to the sender 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 # Remove member to the room if it is members only 1124 #if not self.open and decline_to in self.whitelist: 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 #send an "item-not-found error" to the sender 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
1154 - def Presence_cb(self, session, stanza):
1155 """ 1156 Manages presence stanzas directed to a room 1157 """ 1158 self.muc.DEBUG("Room '"+self.getName()+"' presence handler called") 1159 # Analyze the 'to' element from the stanza 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': # Not sure about the 'available' part 1176 # Process a client's request to join the room 1177 # Check wether the room is locked (for non-owners) 1178 if self.locked and JID(frm).getStripped() not in self.getRoomOwners(): 1179 # Send a not-allowed error 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 # If there is no nick, we must send back an error 400 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 # Check nick unicity 1200 for k,p in self.participants.items(): 1201 if p.getNick() == nick and frm != k: 1202 # OMG nick conflict! 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 # Check wether the nick is reserved 1213 for j,n in self.reserved_nicks.items(): 1214 if n and n == nick and j != JID(frm).getStripped(): 1215 # CONFLICT! 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 # Check if its a nick change 1226 if self.participants.has_key(frm): 1227 oldnick = self.participants[frm].getNick() 1228 if nick != oldnick: 1229 # It is indeed a nick change 1230 # Check wether the new nick is available 1231 self.DEBUG("Nick change",'info') 1232 if self.isLockedDown(): 1233 # Nickname conflict, report back to the changer 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 # Nickname conflict, report back to the changer 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 # Now we must send an 'unavailable' Presence to everyone (in this room) 1254 # with status code 303 (and the new nick) on behalf of the changer 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 # Change the nick in the participant instance 1270 p.setNick(nick) 1271 1272 1273 try: 1274 # Try to add a participant to the room. If it everything goes well, 1275 # addParticipant will return True. Otherwise, it will throw a 1276 # specific exception, catched later 1277 if self.addParticipant(fulljid=frm, nick=nick, password=password): 1278 self.DEBUG("New Participant has correct credentials", "info") 1279 # Conform first standard reply 1280 #reply = Presence( frm, frm=self.fullJID() ) 1281 #x = Node('x', {'xmlns': 'http://jabber.org/protocol/muc'} ) 1282 #reply.addChild(node=x) 1283 #session.enqueue(reply) 1284 1285 # Send presence information from existing participants to the new participant 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 #if self.anonymous == "semi": 1292 if self.getWhois() == "moderators": 1293 if self.participants[frm].getRole() == "moderator": 1294 item.setAttr('jid', k) 1295 #elif self.anonymous == "non": 1296 elif self.getWhois() == "anyone": 1297 item.setAttr('jid', k) 1298 x.addChild(node=item) 1299 reply.addChild(node=x) 1300 # Get extended presence attributes 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 # Send new participant's presence to all participants 1310 relative_frm = self.fullJID() + '/' + nick # Newcomer's relative JID 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 #if self.anonymous == "semi": 1315 if self.getWhois() == "moderators": #Semi-Anonymous 1316 if newcomer.getRole() == "moderator": 1317 item.setAttr('jid', frm) 1318 #elif self.anonymous == "non": 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 # If the room is non-anonymous, send a warning message to the new occupant 1333 #if self.anonymous == "non": 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 # The client sent a bad password 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 # the client is not a member of this room 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 # If 'to' equals the 'relative from' of the sender, exit the room 1410 if str(to) == relative_frm: 1411 # Send leaving participant's presence to all participants 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 # Check if an empty room must be destroyed (if its temporary) 1426 if len(self.participants.keys()) == 0: 1427 # Empty room 1428 if not self.isPersistentRoom(): 1429 del self.muc.rooms[self.getName()] 1430 1431 # TODO: 1432 # If an 'unavailable' presence is sent from the owner of a room that is locked (configuring), 1433 # the Conference must delete such room 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 # Look for the query xml namespace 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 # Discovery Info 1454 if ns == NS_DISCO_INFO and typ == 'get' and nod == None: 1455 # Build reply 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 # Fill 'identity' item 1461 identity = { 'category': 'conference', 'type': 'text', 'name':self.getRoomName() } 1462 rquery.setTag('identity', identity) 1463 # Fill 'feature' items, representing the features that the room supports 1464 feature = { 'var': 'http://jabber.org/protocol/muc' } 1465 rquery.setTag('feature', feature) 1466 # See the specific features of the room 1467 #if self.hidden: 1468 if not self.isPublicRoom(): 1469 feature = { 'var': 'muc_hidden' } 1470 rquery.setTag('feature', feature) 1471 #if self.open: 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 #if self.anonymous == "non": 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 # Fill in Extended Disco Info Results using DataForms 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 # Traffic is not supported at this time 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 # Generate an error 501 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 # Forgetful user requesting his nick 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 # Return a list of participants in the rooms 1552 # We leave it in TODO, for the moment, we return an empty list 1553 self.DEBUG("NS_DISCO_ITEMS requested", "warn") 1554 # Build reply 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 #build a 'virtual' participant 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 # Role-related commands 1598 if self.participants[frm].getRole() == 'moderator': 1599 if role == "none" and (nick or jid) and not affiliation: #kicked 1600 # Compare affiliations 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 #service removes kicked occupant 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 #service informs moderator of success 1642 result = Iq(to=frm, frm=self.fullJID(),typ='result') 1643 session.enqueue(result) 1644 1645 #service informs remaining occupants 1646 relative_frm = self.fullJID() + '/' + nick 1647 # If 'to' equals the 'relative from' of the sender, exit the room 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: # Granting voice to a visitor 1665 # Compare affiliations 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 #if to.getRole() in ['moderator','participant']: 1687 # self.DEBUG("Cannot grant voice to a moderator or participant","warn") 1688 # return 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 #service informs moderator of success 1697 result = Iq(to=frm, frm=self.fullJID(),typ='result') 1698 session.enqueue(result) 1699 1700 #service informs remaining occupants 1701 relative_frm = self.fullJID() + '/' + to.getNick() 1702 # If 'to' equals the 'relative from' of the sender, exit the room 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: # Denying voice to a participant 1720 if to.getRole() == 'moderator': 1721 # Special case: denying voice to a moderator. Compare affiliations 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 #service informs moderator of success 1750 result = Iq(to=frm, frm=self.fullJID(),typ='result') 1751 session.enqueue(result) 1752 1753 #service informs remaining occupants 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: # Grant moderator privileges 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 #service informs moderator of success 1800 result = Iq(to=frm, frm=self.fullJID(),typ='result') 1801 session.enqueue(result) 1802 1803 #service informs remaining occupants 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 # Affiliation-related commands 1822 if self.participants[frm].getAffiliation() in ['owner','admin']: 1823 if affiliation == "outcast" and jid and not role: # Ban a user 1824 my_aff = self.participants[frm].getAffiliation() 1825 # Check if an owner is affecting himself 1826 if JID(frm).getStripped() == to.getBareJID() and \ 1827 my_aff in ['admin','owner']: 1828 # An owner is trying step down but he is the last of his kind 1829 # OR and admin or owner is trying to ban himself 1830 # We must prevent this to happen 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 #service informs moderator of success 1868 result = Iq(to=frm, frm=self.fullJID(),typ='result') 1869 session.enqueue(result) 1870 1871 #service informs banned user (if he's present in the room) 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 #service informs remaining occupants 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 #for child in item.getChildren(): 1902 # newitem.addChild(node=child) 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: # Revoke membership 1914 my_aff = self.participants[frm].getAffiliation() 1915 # Check if an owner is affecting himself 1916 if JID(frm).getStripped() == to.getBareJID() and \ 1917 my_aff == "owner" and len(self.getRoomOwners()) == 1: 1918 # An owner is trying step down but he is the last of his kind 1919 # We must prevent this to happen 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 #if self.isModeratedRoom() and to.getRole() in ['participant','moderator']: 1953 # to.setRole('visitor') 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 #service informs moderator of success 1961 result = Iq(to=frm, frm=self.fullJID(),typ='result') 1962 session.enqueue(result) 1963 1964 #service removes non-member 1965 #if not self.open: 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 #service informs remaining occupants 1988 #for p in self.participants.values(): 1989 # if p.getBareJID() == jid: 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: # Grant membership 2008 my_aff = self.participants[frm].getAffiliation() 2009 # Check if an owner is affecting himself 2010 if JID(frm).getStripped() == to.getBareJID() and \ 2011 my_aff == "owner" and len(self.getRoomOwners()) == 1: 2012 # An owner is trying step down but he is the last of his kind 2013 # We must prevent this to happen 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 #to.setRole('participant') 2042 if nick : 2043 self.reserveNick(to.getBareJID(), nick) 2044 else: 2045 self.reserveNick(to.getBareJID(), None) # Pre-reserve nick 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 #service informs moderator of success 2055 result = Iq(to=frm, frm=self.fullJID(),typ='result') 2056 session.enqueue(result) 2057 2058 #service informs remaining occupants 2059 #if jid in self.participants.keys(): 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: # Grant admin privileges 2081 my_aff = self.participants[frm].getAffiliation() 2082 # Check if an owner is affecting himself 2083 if JID(frm).getStripped() == to.getBareJID() and \ 2084 my_aff == "owner" and len(self.getRoomOwners()) == 1: 2085 # An owner is trying step down but he is the last of his kind 2086 # We must prevent this to happen 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 #service informs moderator of success 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: # Grant admin privileges 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 #service informs moderator of success 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 #if not self.anonymous == "fully": 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 # Test for a destruction 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 # Owner sets room properties 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 # Confirmation of room. Let's see if there's a form 2329 if child.getTags('field'): # If it has any children it's a form :-O 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 #del self if locked 2338 if self.locked: del self.muc.rooms[self.getName()] 2339 self.muc.saveRoomDB() 2340 else: 2341 # Forbidden 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 # Owner requests room properties 2353 #iq = Iq(frm=self.fullJID(), to=frm, typ='result') 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 #df = DataField(name="muc#roomconfig_maxusers",typ="list-single") 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 #df.addOption(('10',10)) 2394 #df.addOption(('20',10)) 2395 #df.addOption(('30',10)) 2396 #df.addOption(('50',10)) 2397 #df.addOption(('100',10)) 2398 #df.addOption(('None',"")) 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 # EYE! New custom fields 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 # End of custom fields 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 # User wants registration information of a room 2476 # Check wether the user is already registered 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 # Already registered 2481 reply = stanza.buildReply(typ="result") 2482 reply.setTag("register") 2483 session.enqueue(reply) 2484 return 2485 else: 2486 # User not registered. Send a registration form 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 # A user attempts to register in the room 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 # Check wether the user is already registered 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 # Already registered 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 # Confirmation of registration. Let's see if there's a form 2540 if child.getTags('field'): # If it has any children it's a form :-O 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
2552 - def reserveNick(self,jid,nick=None):
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 # <internal_joke> 2559 # loop: goto _start 2560 # _start: add r0,r2 2561 # ld r4,(r0) 2562 # bnez r4,_start 2563 # </internal_joke> 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
2579 - def processRegistration(self, x, frm, stanza, session):
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 # We must send a "bad-request" error 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 # Switch var 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 # Nick conflict 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 # We must send a "bad-request" error 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 # Grant membership to this user and tell everyone he's now a member (if he's in the room) 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 #to.setRole('participant') 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 # inform new member of his approved membership 2663 reply = stanza.buildReply(typ="result") 2664 session.enqueue(reply) 2665 2666 #service informs remaining occupants 2667 #if jid in self.participants.keys(): 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
2691 - def configRoom(self, x):
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 # Switch var 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 #self.config[var] = [] 2723 for val in values: 2724 #self.config[var].append(val) 2725 self.addRoomAdmin(val) 2726 # We have to check if some admins have been deleted from the 2727 # old list in order to notify it to the clients 2728 for adm in old_admin_list: 2729 if adm not in values: 2730 # Deleted admin 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
2757 - def addParticipant(self, nick, fulljid, password=None):
2758 """ 2759 Add a participant to a room 2760 """ 2761 self.DEBUG("addParticipant called with: " +str(fulljid) + " " + str(nick),'info') 2762 2763 # Check max users in this room 2764 if self.getMaxUsers() > 0 and len(self.participants) == self.getMaxUsers() and \ 2765 JID(fulljid).getStripped() not in self.getRoomOwners() and \ 2766 JID(fulljid).getStripped() not in self.getRoomAdmins(): 2767 raise MaxUsers 2768 2769 # fulljid must be a string 2770 if isinstance(fulljid, JID): 2771 fulljid = str(fulljid) 2772 2773 if fulljid not in self.participants.keys(): 2774 # Instantiate a new participant 2775 p = Participant(fulljid) 2776 else: 2777 # Modify an existing participant 2778 p = self.participants[fulljid] 2779 2780 # Now, override the new participant's attributes 2781 p.setNick(nick) 2782 2783 # Set the role 2784 if p.getBareJID() in self.moderators: 2785 p.setRole("moderator") 2786 elif p.getBareJID() in self.visitors and self.isModeratedRoom(): 2787 p.setRole("visitor") 2788 else: 2789 p.setRole("participant") 2790 2791 # Set the affiliation 2792 if p.getBareJID() in self.getRoomOwners(): 2793 p.setAffiliation("owner") 2794 elif p.getBareJID() in self.getRoomAdmins(): 2795 p.setAffiliation("admin") 2796 elif p.getBareJID() in self.whitelist: 2797 p.setAffiliation("member") 2798 elif p.getBareJID() in self.blacklist: 2799 p.setAffiliation("outcast") 2800 else: 2801 p.setAffiliation("none") 2802 2803 # See wether the participant can be added to the room depending on the room's type 2804 # Case 0: The participant is blacklisted 2805 if p.getBareJID() in self.blacklist: 2806 # "I told you not to come back! Get the f**k out of here!" 2807 raise Blacklisted 2808 # Case 1: Open and without password. Free way 2809 #if self.open and self.unsecured: 2810 if not self.isMembersOnly() and not self.isPasswordProtectedRoom(): 2811 # Set the participants role based on the room's moderation and the 'role' parameter provided 2812 self.participants[p.getFullJID()] = p 2813 self.DEBUG("Participant " + str(p.getFullJID()) + " has been granted the role of " + str(p.getRole()) + " at room " + self.getName(),'info') 2814 return True 2815 # Case 2: Open but with password. "Say say say say the password" 2816 #elif self.open and not self.unsecured: 2817 elif not self.isMembersOnly() and self.isPasswordProtectedRoom(): 2818 if password == self.getPassword(): 2819 # Free way 2820 # Set the participants role based on the room's moderation and the 'role' parameter provided 2821 self.participants[p.getFullJID()] = p 2822 return True 2823 else: 2824 # Wrong password 2825 raise BadPassword 2826 # Case 3: Members-only but without password 2827 elif self.isMembersOnly() and not self.isPasswordProtectedRoom(): 2828 #print "LA WHITELIST DE "+str(self.getName())+ " ES: "+str(self.whitelist) 2829 if p.getBareJID() in self.whitelist or \ 2830 p.getBareJID() in self.getRoomAdmins() or \ 2831 p.getBareJID() in self.getRoomOwners(): 2832 # "Welcome back, sir" 2833 # Check and/or register the nick 2834 if p.getBareJID() in self.reserved_nicks.keys(): 2835 if not self.reserved_nicks[p.getBareJID()]: 2836 self.reserveNick(p.getBareJID(),p.getNick()) 2837 else: 2838 if self.isLockedDown(): 2839 if p.getNick() != self.reserved_nicks[p.getBareJID()]: 2840 raise NickLockedDown 2841 else: 2842 # Strange case 2843 raise NotAMember 2844 # Set the participants role based on the room's moderation and the 'role' parameter provided 2845 self.participants[p.getFullJID()] = p 2846 return True 2847 else: 2848 # "You're not on my list. Get lost" 2849 raise NotAMember 2850 # Case 4: Members-only and with password 2851 elif self.isMembersOnly() and self.isPasswordProtectedRoom(): 2852 self.DEBUG("Case 4: Members-only and with password","info") 2853 if p.getBareJID() in self.whitelist or \ 2854 p.getBareJID() in self.getRoomAdmins() or \ 2855 p.getBareJID() in self.getRoomOwners(): 2856 if password == self.getPassword(): 2857 # Check and/or register the nick 2858 if p.getBareJID() in self.reserved_nicks.keys(): 2859 if not self.reserved_nicks[p.getBareJID()]: 2860 self.reserved_nicks[p.getBareJID()] = p.getNick() 2861 else: 2862 if self.isLockedDown(): 2863 if p.getNick() != self.reserved_nicks[p.getBareJID()]: 2864 raise NickLockedDown 2865 else: 2866 # Strange case 2867 raise NotAMember 2868 # Free way 2869 # Set the participants role based on the room's moderation and the 'role' parameter provided 2870 self.participants[p.getFullJID()] = p 2871 return True 2872 else: 2873 # Bad password 2874 raise BadPassword 2875 else: 2876 # Not a member. Get lost 2877 raise NotAMember
2878
2879 - def deleteParticipant(self, fulljid):
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 # Participant not really in room 2893 pass
2894
2895 - def setAffiliation(self, participant, affiliation):
2896 """ 2897 Set the affiliation of a participant 2898 """ 2899 # If 'participant' is a string 2900 if type(participant) == types.StringType: 2901 jid = participant 2902 # If its an instance of JID or Participant 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 # Change affiliation in the participants dict 2910 try: 2911 self.participants[jid].setAffiliation(affiliation) 2912 if affiliation == "owner": 2913 #self.owners.append(jid) 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
2922 -class MUC(PlugIn):
2923 """ 2924 The conference component. Composed of multiple rooms 2925 """ 2926 NS = '' 2927 #def __init__(self, jid, name):
2928 - def plugin(self, server):
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 #member_room.open = False 2948 member_room.setMembersOnly(True) 2949 self.addRoom(member_room) 2950 #black_room = Room('black', self, 'Black Note', blacklist=['q3@thx1138.dsic.upv.es']) 2951 black_room = Room('black', self, 'Black Note') 2952 #black_room.moderated = True 2953 black_room.setModeratedRoom(True) 2954 black_room.moderators.append('q1@thx1138.dsic.upv.es') 2955 #black_room.moderators.append('q2@thx1138.dsic.upv.es') 2956 black_room.visitors.append('q3@thx1138.dsic.upv.es') 2957 #black_room.owners.append('q1@thx1138.dsic.upv.es') 2958 black_room.addRoomOwner('q1@thx1138.dsic.upv.es') 2959 2960 #black_room.admins.append('q2@thx1138.dsic.upv.es') 2961 #black_room.blacklist.append('q2@thx1138.dsic.upv.es') 2962 black_room.whitelist.append('q1@thx1138.dsic.upv.es') 2963 2964 black_room.moderators.append('q1@tatooine.dsic.upv.es') 2965 #black_room.moderators.append('q2@tatooine.dsic.upv.es') 2966 black_room.visitors.append('q3@tatooine.dsic.upv.es') 2967 black_room.addRoomOwner('q1@tatooine.dsic.upv.es') 2968 #black_room.admins.append('q2@tatooine.dsic.upv.es') 2969 #black_room.whitelist.append('q1@tatooine.dsic.upv.es') 2970 #black_room.whitelist.append('q2@tatooine.dsic.upv.es') 2971 #black_room.whitelist.append('q3@tatooine.dsic.upv.es') 2972 #black_room.blacklist.append('q2@tatooine.dsic.upv.es') 2973 black_room.setMembersOnly(True) 2974 2975 #black_room.maxusers = 1 2976 #black_room.password = "secret" 2977 #black_room.unsecured = False 2978 self.addRoom(black_room) 2979 non = Room('non',self,'Non-Anonima') 2980 #non.anonymous = "non" 2981 non.setWhois("anyone") 2982 self.addRoom(non) 2983 fully = Room('fully',self,'Fully-Anonima') 2984 #fully.anonymous = "fully" 2985 fully.setWhois("") 2986 self.addRoom(fully) 2987 2988 self.DEBUG("Created MUC: '%s' '%s'"%(self.name,str(self.jid)), "warn")
2989
2990 - def printMUC(self):
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 # Add the given room 3002 room.muc = self 3003 #self.rooms[str(room.name)] = room 3004 self.rooms[str(room.getName())] = room 3005 self.saveRoomDB() 3006 return True 3007 elif name: 3008 # Create a new (empty) default room with given jid 3009 self.rooms[str(name)] = Room(name, self) 3010 self.saveRoomDB() 3011 return True 3012 else: 3013 # Error: no room and no jid. Don't know what to do 3014 return False
3015
3016 - def destroyRoom(self, name, owner_session, stanza):
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 # Get venue and reason 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 # Send a final presence 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 # Notify the owner of the success in destroying the room 3062 iq = stanza.buildReply(typ="result") 3063 owner_session.enqueue(iq) 3064 3065 # Destroy room instance 3066 del self.rooms[name] 3067 del room 3068 3069 # Execute persistency 3070 self.saveRoomDB() 3071 3072 return
3073
3074 - def dispatch(self, session, stanza):
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 # No room name. Stanza directed to the Conference 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 # TODO: Implement the rest of protocols 3093 # Stanza directed to a specific room 3094 if room in self.rooms.keys() and domain == str(self.jid): 3095 self.rooms[room].dispatch(session, stanza) 3096 else: 3097 # The room does not exist 3098 self.notExist_cb(session,stanza)
3099
3100 - def Presence_cb(self,session,stanza):
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
3109 - def notExist_cb(self, session, stanza):
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: # Available 3125 # Create the room and add the client as the owner 3126 p = Participant(frm, nick=nick, affiliation='owner') 3127 room_node = Room(room, self, creator = p) 3128 self.addRoom(room_node) 3129 # Reply the client with an OK 201 code 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 # Check wether the room must be locked 3140 for tag in stanza.getChildren(): 3141 if tag.getName() =='x': 3142 if tag.getNamespace() == "http://jabber.org/protocol/muc": 3143 # MUC protocol 3144 room_node.locked = True 3145 else: 3146 # Groupchat 1.0 protocol 3147 room_node.locked = False 3148 # Redirect the stanza to the handler of the new room 3149 room_node.dispatch(session,stanza) 3150 return 3151 3152 if name == "iq": 3153 if stanza.getQueryNS() == NS_REGISTER: 3154 # User requesting registration in a non-existent room or requesting the registration form. 3155 # Either way it's WRONG 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 # Look for the query xml namespace 3171 query = iq.getTag('query') 3172 if query: 3173 try: 3174 ns = str(iq.getQueryNS()) 3175 typ = str(iq.getType()) 3176 # Discovery Info 3177 if ns == NS_DISCO_INFO and typ == 'get': 3178 # Build reply 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 # Discovery Items, i.e., the rooms 3190 elif ns == NS_DISCO_ITEMS: 3191 self.DEBUG("NS_DISCO_ITEMS requested", "warn") 3192 # Build reply 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 # For each room in the conference, generate an 'item' element with info about the room 3199 for room,v in self.rooms.items(): 3200 #if not v.hidden and not v.locked: 3201 if v.isPublicRoom() and not v.locked: 3202 #attrs = { 'jid': str(room+'@'+self.jid), 'name': str(v.subject) } 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
3211 - def loadRoomDB(self):
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
3231 - def saveRoomDB(self):
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 # Make a serializable object out of the room 3240 r = SerializableRoom(v) 3241 roomdb[k] = r 3242 3243 fh = open("roomdb.xml", 'w') 3244 #pickle.dump(roomdb, fh, -1) 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 # Debug main code 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 #r1.addParticipant(participant=p2) 3262 3263 conf.addRoom(r1) 3264 conf.addRoom(r2) 3265 3266 print p1 3267 print p2 3268 print r1 3269 print conf 3270