1   
   2   
   3   
   4   
   5   
   6   
   7   
   8   
   9   
  10   
  11   
  12   
  13   
  14   
  15   
  16   
  17  """Jabber Multi-User Chat implementation. 
  18   
  19  Normative reference: 
  20    - `JEP 45 <http://www.jabber.org/jeps/jep-0045.html>`__ 
  21  """ 
  22   
  23  __revision__="$Id: muc.py 647 2006-08-26 18:27:39Z jajcus $" 
  24  __docformat__="restructuredtext en" 
  25   
  26  import logging 
  27   
  28  from pyxmpp.presence import Presence 
  29  from pyxmpp.message import Message 
  30  from pyxmpp.iq import Iq 
  31  from pyxmpp.jid import JID 
  32   
  33  from pyxmpp.xmlextra import xml_element_ns_iter 
  34   
  35  from pyxmpp.jabber.muccore import MucPresence,MucUserX,MucItem,MucStatus 
  36  from pyxmpp.jabber.muccore import MUC_OWNER_NS 
  37   
  38  from pyxmpp.jabber.dataforms import DATAFORM_NS, Form 
  39   
  40  import weakref 
  41   
  43      """ 
  44      Base class for MUC room handlers. 
  45   
  46      Methods of this class will be called for various events in the room. 
  47   
  48      :Ivariables: 
  49        - `room_state`: MucRoomState object describing room state and its 
  50          participants. 
  51   
  52      """ 
  54          """Initialize a `MucRoomHandler` object.""" 
  55          self.room_state=None 
  56          self.__logger=logging.getLogger("pyxmpp.jabber.MucRoomHandler") 
   57   
  59          """Assign a state object to this `MucRoomHandler` instance. 
  60   
  61          :Parameters: 
  62              - `state_obj`: the state object. 
  63          :Types: 
  64              - `state_obj`: `MucRoomState`""" 
  65          self.room_state=state_obj 
   66   
  68          """ 
  69          Called when the room has been created. 
  70   
  71          Default action is to request an "instant room" by accepting the default 
  72          configuration. Instead the application may want to request a 
  73          configuration form and submit it. 
  74   
  75          :Parameters: 
  76              - `stanza`: the stanza received. 
  77   
  78          :Types: 
  79              - `stanza`: `pyxmpp.stanza.Stanza` 
  80          """ 
  81          _unused = stanza 
  82          self.room_state.request_instant_room() 
   83   
  97   
 103   
 105          """ 
 106          Called when a new participant joins the room. 
 107   
 108          :Parameters: 
 109              - `user`: the user joining. 
 110              - `stanza`: the stanza received. 
 111   
 112          :Types: 
 113              - `user`: `MucRoomUser` 
 114              - `stanza`: `pyxmpp.stanza.Stanza` 
 115          """ 
 116          pass 
  117   
 119          """ 
 120          Called when a participant leaves the room. 
 121   
 122          :Parameters: 
 123              - `user`: the user leaving. 
 124              - `stanza`: the stanza received. 
 125   
 126          :Types: 
 127              - `user`: `MucRoomUser` 
 128              - `stanza`: `pyxmpp.stanza.Stanza` 
 129          """ 
 130          pass 
  131   
 133          """ 
 134          Called when a role of an user has been changed. 
 135   
 136          :Parameters: 
 137              - `user`: the user (after update). 
 138              - `old_role`: user's role before update. 
 139              - `new_role`: user's role after update. 
 140              - `stanza`: the stanza received. 
 141   
 142          :Types: 
 143              - `user`: `MucRoomUser` 
 144              - `old_role`: `unicode` 
 145              - `new_role`: `unicode` 
 146              - `stanza`: `pyxmpp.stanza.Stanza` 
 147          """ 
 148          pass 
  149   
 151          """ 
 152          Called when a affiliation of an user has been changed. 
 153   
 154          `user` MucRoomUser object describing the user (after update). 
 155          `old_aff` is user's affiliation before update. 
 156          `new_aff` is user's affiliation after update. 
 157          `stanza` the stanza received. 
 158          """ 
 159          pass 
  160   
 162          """ 
 163          Called when user nick change is started. 
 164   
 165          :Parameters: 
 166              - `user`: the user (before update). 
 167              - `new_nick`: the new nick. 
 168              - `stanza`: the stanza received. 
 169   
 170          :Types: 
 171              - `user`: `MucRoomUser` 
 172              - `new_nick`: `unicode` 
 173              - `stanza`: `pyxmpp.stanza.Stanza` 
 174          """ 
 175          pass 
  176   
 178          """ 
 179          Called after a user nick has been changed. 
 180   
 181          :Parameters: 
 182              - `user`: the user (after update). 
 183              - `old_nick`: the old nick. 
 184              - `stanza`: the stanza received. 
 185   
 186          :Types: 
 187              - `user`: `MucRoomUser` 
 188              - `old_nick`: `unicode` 
 189              - `stanza`: `pyxmpp.stanza.Stanza` 
 190          """ 
 191          pass 
  192   
 194          """ 
 195          Called whenever user's presence changes (includes nick, role or 
 196          affiliation changes). 
 197   
 198          :Parameters: 
 199              - `user`: MucRoomUser object describing the user. 
 200              - `stanza`: the stanza received. 
 201   
 202          :Types: 
 203              - `user`: `MucRoomUser` 
 204              - `stanza`: `pyxmpp.stanza.Stanza` 
 205          """ 
 206          pass 
  207   
 209          """ 
 210          Called when the room subject has been changed. 
 211   
 212          :Parameters: 
 213              - `user`: the user changing the subject. 
 214              - `stanza`: the stanza used to change the subject. 
 215   
 216          :Types: 
 217              - `user`: `MucRoomUser` 
 218              - `stanza`: `pyxmpp.stanza.Stanza` 
 219          """ 
 220          pass 
  221   
 223          """ 
 224          Called when groupchat message has been received. 
 225   
 226          :Parameters: 
 227              - `user`: the sender. 
 228              - `stanza`: is the message stanza received. 
 229   
 230          :Types: 
 231              - `user`: `MucRoomUser` 
 232              - `stanza`: `pyxmpp.stanza.Stanza` 
 233          """ 
 234          pass 
  235   
 237          """ 
 238          Called when an error stanza is received in reply to a room 
 239          configuration request. 
 240   
 241          By default `self.error` is called. 
 242   
 243          :Parameters: 
 244              - `stanza`: the stanza received. 
 245          :Types: 
 246              - `stanza`: `pyxmpp.stanza.Stanza` 
 247          """ 
 248          self.error(stanza) 
  249   
 251          """ 
 252          Called when an error stanza is received. 
 253   
 254          :Parameters: 
 255              - `stanza`: the stanza received. 
 256          :Types: 
 257              - `stanza`: `pyxmpp.stanza.Stanza` 
 258          """ 
 259          err=stanza.get_error() 
 260          self.__logger.debug("Error from: %r Condition: %r" 
 261                  % (stanza.get_from(),err.get_condition)) 
   262   
 264      """ 
 265      Describes a user of a MUC room. 
 266   
 267      The attributes of this object should not be changed directly. 
 268   
 269      :Ivariables: 
 270          - `presence`: last presence stanza received for the user. 
 271          - `role`: user's role. 
 272          - `affiliation`: user's affiliation. 
 273          - `room_jid`: user's room jid. 
 274          - `real_jid`: user's real jid or None if not available. 
 275          - `nick`: user's nick (resource part of `room_jid`) 
 276      :Types: 
 277          - `presence`: `MucPresence` 
 278          - `role`: `str` 
 279          - `affiliation`: `str` 
 280          - `room_jid`: `JID` 
 281          - `real_jid`: `JID` 
 282          - `nick`: `unicode` 
 283      """ 
 284 -    def __init__(self,presence_or_user_or_jid): 
  285          """ 
 286          Initialize a `MucRoomUser` object. 
 287   
 288          :Parameters: 
 289              - `presence_or_user_or_jid`: a MUC presence stanza with user 
 290                information, a user object to copy or a room JID of a user. 
 291          :Types: 
 292              - `presence_or_user_or_jid`: `MucPresence` or `MucRoomUser` or 
 293                `JID` 
 294   
 295          When `presence_or_user_or_jid` is a JID user's 
 296          role and affiliation are set to "none". 
 297          """ 
 298          if isinstance(presence_or_user_or_jid,MucRoomUser): 
 299              self.presence=presence_or_user_or_jid.presence 
 300              self.role=presence_or_user_or_jid.role 
 301              self.affiliation=presence_or_user_or_jid.affiliation 
 302              self.room_jid=presence_or_user_or_jid.room_jid 
 303              self.real_jid=presence_or_user_or_jid.real_jid 
 304              self.nick=presence_or_user_or_jid.nick 
 305              self.new_nick=None 
 306          else: 
 307              self.affiliation="none" 
 308              self.presence=None 
 309              self.real_jid=None 
 310              self.new_nick=None 
 311              if isinstance(presence_or_user_or_jid,JID): 
 312                  self.nick=presence_or_user_or_jid.resource 
 313                  self.room_jid=presence_or_user_or_jid 
 314                  self.role="none" 
 315              elif isinstance(presence_or_user_or_jid,Presence): 
 316                  self.nick=None 
 317                  self.room_jid=None 
 318                  self.role="participant" 
 319                  self.update_presence(presence_or_user_or_jid) 
 320              else: 
 321                  raise TypeError,"Bad argument type for MucRoomUser constructor" 
  322   
 324          """ 
 325          Update user information. 
 326   
 327          :Parameters: 
 328              - `presence`: a presence stanza with user information update. 
 329          :Types: 
 330              - `presence`: `MucPresence` 
 331          """ 
 332          self.presence=MucPresence(presence) 
 333          t=presence.get_type() 
 334          if t=="unavailable": 
 335              self.role="none" 
 336              self.affiliation="none" 
 337          self.room_jid=self.presence.get_from() 
 338          self.nick=self.room_jid.resource 
 339          mc=self.presence.get_muc_child() 
 340          if isinstance(mc,MucUserX): 
 341              items=mc.get_items() 
 342              for item in items: 
 343                  if not isinstance(item,MucItem): 
 344                      continue 
 345                  if item.role: 
 346                      self.role=item.role 
 347                  if item.affiliation: 
 348                      self.affiliation=item.affiliation 
 349                  if item.jid: 
 350                      self.real_jid=item.jid 
 351                  if item.nick: 
 352                      self.new_nick=item.nick 
 353                  break 
  354   
 356          """Check if two `MucRoomUser` objects describe the same user in the 
 357          same room. 
 358   
 359          :Parameters: 
 360              - `other`: the user object to compare `self` with. 
 361          :Types: 
 362              - `other`: `MucRoomUser` 
 363   
 364          :return: `True` if the two object describe the same user. 
 365          :returntype: `bool`""" 
 366          return self.room_jid==other.room_jid 
   367   
 369      """ 
 370      Describes the state of a MUC room, handles room events 
 371      and provides an interface for room actions. 
 372   
 373      :Ivariables: 
 374          - `own_jid`: real jid of the owner (client using this class). 
 375          - `room_jid`: room jid of the owner. 
 376          - `handler`: MucRoomHandler object containing callbacks to be called. 
 377          - `manager`: MucRoomManager object managing this room. 
 378          - `joined`: True if the channel is joined. 
 379          - `subject`: current subject of the room. 
 380          - `users`: dictionary of users in the room. Nicknames are the keys. 
 381          - `me`: MucRoomUser instance of the owner. 
 382          - `configured`: `False` if the room requires configuration. 
 383      """ 
 384 -    def __init__(self,manager,own_jid,room_jid,handler): 
  385          """ 
 386          Initialize a `MucRoomState` object. 
 387   
 388          :Parameters: 
 389              - `manager`: an object to manage this room. 
 390              - `own_jid`: real JID of the owner (client using this class). 
 391              - `room_jid`: room JID of the owner (provides the room name and 
 392                the nickname). 
 393              - `handler`: an object to handle room events. 
 394          :Types: 
 395              - `manager`: `MucRoomManager` 
 396              - `own_jid`: JID 
 397              - `room_jid`: JID 
 398              - `handler`: `MucRoomHandler` 
 399          """ 
 400          self.own_jid=own_jid 
 401          self.room_jid=room_jid 
 402          self.handler=handler 
 403          self.manager=weakref.proxy(manager) 
 404          self.joined=False 
 405          self.subject=None 
 406          self.users={} 
 407          self.me=MucRoomUser(room_jid) 
 408          self.configured = None 
 409          self.configuration_form = None 
 410          handler.assign_state(self) 
 411          self.__logger=logging.getLogger("pyxmpp.jabber.MucRoomState") 
  412   
 413 -    def get_user(self,nick_or_jid,create=False): 
  414          """ 
 415          Get a room user with given nick or JID. 
 416   
 417          :Parameters: 
 418              - `nick_or_jid`: the nickname or room JID of the user requested. 
 419              - `create`: if `True` and `nick_or_jid` is a JID, then a new 
 420                user object will be created if there is no such user in the room. 
 421          :Types: 
 422              - `nick_or_jid`: `unicode` or `JID` 
 423              - `create`: `bool` 
 424   
 425          :return: the named user or `None` 
 426          :returntype: `MucRoomUser` 
 427          """ 
 428          if isinstance(nick_or_jid,JID): 
 429              if not nick_or_jid.resource: 
 430                  return None 
 431              for u in self.users.values(): 
 432                  if nick_or_jid in (u.room_jid,u.real_jid): 
 433                      return u 
 434              if create: 
 435                  return MucRoomUser(nick_or_jid) 
 436              else: 
 437                  return None 
 438          return self.users.get(nick_or_jid) 
  439   
 441          """ 
 442          Called when current stream changes. 
 443   
 444          Mark the room not joined and inform `self.handler` that it was left. 
 445   
 446          :Parameters: 
 447              - `stream`: the new stream. 
 448          :Types: 
 449              - `stream`: `pyxmpp.stream.Stream` 
 450          """ 
 451          _unused = stream 
 452          if self.joined and self.handler: 
 453              self.handler.user_left(self.me,None) 
 454          self.joined=False 
  455   
 456 -    def join(self, password=None, history_maxchars = None, 
 457              history_maxstanzas = None, history_seconds = None, history_since = None): 
  458          """ 
 459          Send a join request for the room. 
 460   
 461          :Parameters: 
 462              - `password`: password to the room. 
 463              - `history_maxchars`: limit of the total number of characters in 
 464                history. 
 465              - `history_maxstanzas`: limit of the total number of messages in 
 466                history. 
 467              - `history_seconds`: send only messages received in the last 
 468                `history_seconds` seconds. 
 469              - `history_since`: Send only the messages received since the 
 470                dateTime specified (UTC). 
 471          :Types: 
 472              - `password`: `unicode` 
 473              - `history_maxchars`: `int` 
 474              - `history_maxstanzas`: `int` 
 475              - `history_seconds`: `int` 
 476              - `history_since`: `datetime.datetime` 
 477          """ 
 478          if self.joined: 
 479              raise RuntimeError,"Room is already joined" 
 480          p=MucPresence(to_jid=self.room_jid) 
 481          p.make_join_request(password, history_maxchars, history_maxstanzas, 
 482                  history_seconds, history_since) 
 483          self.manager.stream.send(p) 
  484   
 486          """ 
 487          Send a leave request for the room. 
 488          """ 
 489          if self.joined: 
 490              p=MucPresence(to_jid=self.room_jid,stanza_type="unavailable") 
 491              self.manager.stream.send(p) 
  492   
 494          """ 
 495          Send a message to the room. 
 496   
 497          :Parameters: 
 498              - `body`: the message body. 
 499          :Types: 
 500              - `body`: `unicode` 
 501          """ 
 502          m=Message(to_jid=self.room_jid.bare(),stanza_type="groupchat",body=body) 
 503          self.manager.stream.send(m) 
  504   
 506          """ 
 507          Send a subject change request to the room. 
 508   
 509          :Parameters: 
 510              - `subject`: the new subject. 
 511          :Types: 
 512              - `subject`: `unicode` 
 513          """ 
 514          m=Message(to_jid=self.room_jid.bare(),stanza_type="groupchat",subject=subject) 
 515          self.manager.stream.send(m) 
  516   
 518          """ 
 519          Send a nick change request to the room. 
 520   
 521          :Parameters: 
 522              - `new_nick`: the new nickname requested. 
 523          :Types: 
 524              - `new_nick`: `unicode` 
 525          """ 
 526          new_room_jid=JID(self.room_jid.node,self.room_jid.domain,new_nick) 
 527          p=Presence(to_jid=new_room_jid) 
 528          self.manager.stream.send(p) 
  529   
 531          """ 
 532          Get own room JID or a room JID for given `nick`. 
 533   
 534          :Parameters: 
 535              - `nick`: a nick for which the room JID is requested. 
 536          :Types: 
 537              - `nick`: `unicode` 
 538   
 539          :return: the room JID. 
 540          :returntype: `JID` 
 541          """ 
 542          if nick is None: 
 543              return self.room_jid 
 544          return JID(self.room_jid.node,self.room_jid.domain,nick) 
  545   
 547          """ 
 548          Get own nick. 
 549   
 550          :return: own nick. 
 551          :returntype: `unicode` 
 552          """ 
 553          return self.room_jid.resource 
  554   
 556          """ 
 557          Process <presence/> received from the room. 
 558   
 559          :Parameters: 
 560              - `stanza`: the stanza received. 
 561          :Types: 
 562              - `stanza`: `MucPresence` 
 563          """ 
 564          fr=stanza.get_from() 
 565          if not fr.resource: 
 566              return 
 567          nick=fr.resource 
 568          user=self.users.get(nick) 
 569          if user: 
 570              old_user=MucRoomUser(user) 
 571              user.update_presence(stanza) 
 572              user.nick=nick 
 573          else: 
 574              old_user=None 
 575              user=MucRoomUser(stanza) 
 576              self.users[user.nick]=user 
 577          self.handler.presence_changed(user,stanza) 
 578          if fr==self.room_jid and not self.joined: 
 579              self.joined=True 
 580              self.me=user 
 581              mc=stanza.get_muc_child() 
 582              if isinstance(mc,MucUserX): 
 583                  status = [i for i in mc.get_items() if isinstance(i,MucStatus) and i.code==201] 
 584                  if status: 
 585                      self.configured = False 
 586                      self.handler.room_created(stanza) 
 587              if self.configured is None: 
 588                  self.configured = True 
 589          if not old_user or old_user.role=="none": 
 590              self.handler.user_joined(user,stanza) 
 591          else: 
 592              if old_user.nick!=user.nick: 
 593                  self.handler.nick_changed(user,old_user.nick,stanza) 
 594                  if old_user.room_jid==self.room_jid: 
 595                      self.room_jid=fr 
 596              if old_user.role!=user.role: 
 597                  self.handler.role_changed(user,old_user.role,user.role,stanza) 
 598              if old_user.affiliation!=user.affiliation: 
 599                  self.handler.affiliation_changed(user,old_user.affiliation,user.affiliation,stanza) 
  600   
 639           
 640   
 658   
 660          """ 
 661          Process <message type="error"/> received from the room. 
 662   
 663          :Parameters: 
 664              - `stanza`: the stanza received. 
 665          :Types: 
 666              - `stanza`: `Message` 
 667          """ 
 668          self.handler.error(stanza) 
  669   
 671          """ 
 672          Process <presence type="error"/> received from the room. 
 673   
 674          :Parameters: 
 675              - `stanza`: the stanza received. 
 676          :Types: 
 677              - `stanza`: `Presence` 
 678          """ 
 679          self.handler.error(stanza) 
  680   
 701   
 712   
 729   
 731          """ 
 732          Process success response for a room configuration request. 
 733   
 734          :Parameters: 
 735              - `stanza`: the stanza received. 
 736          :Types: 
 737              - `stanza`: `Presence` 
 738          """ 
 739          _unused = stanza 
 740          self.configured = True 
 741          self.handler.room_configured() 
  742   
 744          """ 
 745          Process error response for a room configuration request. 
 746   
 747          :Parameters: 
 748              - `stanza`: the stanza received. 
 749          :Types: 
 750              - `stanza`: `Presence` 
 751          """ 
 752          self.handler.room_configuration_error(stanza) 
  753   
 781   
 783          """ 
 784          Request an "instant room" -- the default configuration for a MUC room. 
 785   
 786          :return: id of the request stanza. 
 787          :returntype: `unicode` 
 788          """ 
 789          if self.configured: 
 790              raise RuntimeError, "Instant room may be requested for unconfigured room only" 
 791          form = Form("submit") 
 792          return self.configure_room(form) 
   793   
 795      """ 
 796      Manage collection of MucRoomState objects and dispatch events. 
 797   
 798      :Ivariables: 
 799        - `rooms`: a dictionary containing known MUC rooms. Unicode room JIDs are the 
 800          keys. 
 801        - `stream`: the stream associated with the room manager. 
 802   
 803      """ 
 805          """ 
 806          Initialize a `MucRoomManager` object. 
 807   
 808          :Parameters: 
 809              - `stream`: a stream to be initially assigned to `self`. 
 810          :Types: 
 811              - `stream`: `pyxmpp.stream.Stream` 
 812          """ 
 813          self.rooms={} 
 814          self.stream,self.jid=(None,)*2 
 815          self.set_stream(stream) 
 816          self.__logger=logging.getLogger("pyxmpp.jabber.MucRoomManager") 
  817   
 819          """ 
 820          Change the stream assigned to `self`. 
 821   
 822          :Parameters: 
 823              - `stream`: the new stream to be assigned to `self`. 
 824          :Types: 
 825              - `stream`: `pyxmpp.stream.Stream` 
 826          """ 
 827          self.jid=stream.me 
 828          self.stream=stream 
 829          for r in self.rooms.values(): 
 830              r.set_stream(stream) 
  831   
 833          """ 
 834          Assign MUC stanza handlers to the `self.stream`. 
 835   
 836          :Parameters: 
 837              - `priority`: priority for the handlers. 
 838          :Types: 
 839              - `priority`: `int` 
 840          """ 
 841          self.stream.set_message_handler("groupchat",self.__groupchat_message,None,priority) 
 842          self.stream.set_message_handler("error",self.__error_message,None,priority) 
 843          self.stream.set_presence_handler("available",self.__presence_available,None,priority) 
 844          self.stream.set_presence_handler("unavailable",self.__presence_unavailable,None,priority) 
 845          self.stream.set_presence_handler("error",self.__presence_error,None,priority) 
  846   
 847 -    def join(self, room, nick, handler, password = None, history_maxchars = None, 
 848              history_maxstanzas = None, history_seconds = None, history_since = None): 
  849          """ 
 850          Create and return a new room state object and request joining 
 851          to a MUC room. 
 852   
 853          :Parameters: 
 854              - `room`: the name of a room to be joined 
 855              - `nick`: the nickname to be used in the room 
 856              - `handler`: is an object to handle room events. 
 857              - `password`: password for the room, if any 
 858              - `history_maxchars`: limit of the total number of characters in 
 859                history. 
 860              - `history_maxstanzas`: limit of the total number of messages in 
 861                history. 
 862              - `history_seconds`: send only messages received in the last 
 863                `history_seconds` seconds. 
 864              - `history_since`: Send only the messages received since the 
 865                dateTime specified (UTC). 
 866   
 867          :Types: 
 868              - `room`: `JID` 
 869              - `nick`: `unicode` 
 870              - `handler`: `MucRoomHandler` 
 871              - `password`: `unicode` 
 872              - `history_maxchars`: `int` 
 873              - `history_maxstanzas`: `int` 
 874              - `history_seconds`: `int` 
 875              - `history_since`: `datetime.datetime` 
 876   
 877          :return: the room state object created. 
 878          :returntype: `MucRoomState` 
 879          """ 
 880   
 881          if not room.node or room.resource: 
 882              raise ValueError,"Invalid room JID" 
 883   
 884          room_jid = JID(room.node, room.domain, nick) 
 885   
 886          cur_rs = self.rooms.get(room_jid.bare().as_unicode()) 
 887          if cur_rs and cur_rs.joined: 
 888              raise RuntimeError,"Room already joined" 
 889   
 890          rs=MucRoomState(self, self.stream.me, room_jid, handler) 
 891          self.rooms[room_jid.bare().as_unicode()]=rs 
 892          rs.join(password, history_maxchars, history_maxstanzas, 
 893              history_seconds, history_since) 
 894          return rs 
  895   
 897          """Get the room state object of a room. 
 898   
 899          :Parameters: 
 900              - `room`: JID or the room which state is requested. 
 901          :Types: 
 902              - `room`: `JID` 
 903   
 904          :return: the state object. 
 905          :returntype: `MucRoomState`""" 
 906          return self.rooms.get(room.bare().as_unicode()) 
  907   
 909          """ 
 910          Remove a room from the list of managed rooms. 
 911   
 912          :Parameters: 
 913              - `rs`: the state object of the room. 
 914          :Types: 
 915              - `rs`: `MucRoomState` 
 916          """ 
 917          try: 
 918              del self.rooms[rs.room_jid.bare().as_unicode()] 
 919          except KeyError: 
 920              pass 
  921   
 923          """Process a groupchat message from a MUC room. 
 924   
 925          :Parameters: 
 926              - `stanza`: the stanza received. 
 927          :Types: 
 928              - `stanza`: `Message` 
 929   
 930          :return: `True` if the message was properly recognized as directed to 
 931              one of the managed rooms, `False` otherwise. 
 932          :returntype: `bool`""" 
 933          fr=stanza.get_from() 
 934          key=fr.bare().as_unicode() 
 935          rs=self.rooms.get(key) 
 936          if not rs: 
 937              self.__logger.debug("groupchat message from unknown source") 
 938              return False 
 939          rs.process_groupchat_message(stanza) 
 940          return True 
  941   
 943          """Process an error message from a MUC room. 
 944   
 945          :Parameters: 
 946              - `stanza`: the stanza received. 
 947          :Types: 
 948              - `stanza`: `Message` 
 949   
 950          :return: `True` if the message was properly recognized as directed to 
 951              one of the managed rooms, `False` otherwise. 
 952          :returntype: `bool`""" 
 953          fr=stanza.get_from() 
 954          key=fr.bare().as_unicode() 
 955          rs=self.rooms.get(key) 
 956          if not rs: 
 957              return False 
 958          rs.process_error_message(stanza) 
 959          return True 
  960   
 962          """Process an presence error from a MUC room. 
 963   
 964          :Parameters: 
 965              - `stanza`: the stanza received. 
 966          :Types: 
 967              - `stanza`: `Presence` 
 968   
 969          :return: `True` if the stanza was properly recognized as generated by 
 970              one of the managed rooms, `False` otherwise. 
 971          :returntype: `bool`""" 
 972          fr=stanza.get_from() 
 973          key=fr.bare().as_unicode() 
 974          rs=self.rooms.get(key) 
 975          if not rs: 
 976              return False 
 977          rs.process_error_presence(stanza) 
 978          return True 
  979   
 981          """Process an available presence from a MUC room. 
 982   
 983          :Parameters: 
 984              - `stanza`: the stanza received. 
 985          :Types: 
 986              - `stanza`: `Presence` 
 987   
 988          :return: `True` if the stanza was properly recognized as generated by 
 989              one of the managed rooms, `False` otherwise. 
 990          :returntype: `bool`""" 
 991          fr=stanza.get_from() 
 992          key=fr.bare().as_unicode() 
 993          rs=self.rooms.get(key) 
 994          if not rs: 
 995              return False 
 996          rs.process_available_presence(MucPresence(stanza)) 
 997          return True 
  998   
1000          """Process an unavailable presence from a MUC room. 
1001   
1002          :Parameters: 
1003              - `stanza`: the stanza received. 
1004          :Types: 
1005              - `stanza`: `Presence` 
1006   
1007          :return: `True` if the stanza was properly recognized as generated by 
1008              one of the managed rooms, `False` otherwise. 
1009          :returntype: `bool`""" 
1010          fr=stanza.get_from() 
1011          key=fr.bare().as_unicode() 
1012          rs=self.rooms.get(key) 
1013          if not rs: 
1014              return False 
1015          rs.process_unavailable_presence(MucPresence(stanza)) 
1016          return True 
  1017   
1018   
1019