Package pyxmpp :: Package jabber :: Module muccore

[hide private]

# Source Code for Module pyxmpp.jabber.muccore

      1  #
      2  # (C) Copyright 2003-2004 Jacek Konieczny <jajcus@jajcus.net>
      3  #
      4  # This program is free software; you can redistribute it and/or modify
      5  # it under the terms of the GNU Lesser General Public License Version
      6  # 2.1 as published by the Free Software Foundation.
      7  #
      8  # This program is distributed in the hope that it will be useful,
      9  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  # GNU Lesser General Public License for more details.
     12  #
     13  # You should have received a copy of the GNU Lesser General Public
     14  # License along with this program; if not, write to the Free Software
     15  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     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: muccore.py 648 2006-08-26 20:09:37Z jajcus $"
     24  __docformat__="restructuredtext en"
     25
     26  import libxml2
     27
     28  from pyxmpp.utils import to_utf8,from_utf8
     29  from pyxmpp.xmlextra import common_doc, common_root, common_ns, get_node_ns_uri
     30  from pyxmpp.presence import Presence
     31  from pyxmpp.iq import Iq
     32  from pyxmpp.jid import JID
     33  from pyxmpp import xmlextra
     34  from pyxmpp.objects import StanzaPayloadWrapperObject
     35  from pyxmpp.xmlextra import xml_element_iter
     36
     37  MUC_NS="http://jabber.org/protocol/muc"
     38  MUC_USER_NS=MUC_NS+"#user"
     39  MUC_ADMIN_NS=MUC_NS+"#admin"
     40  MUC_OWNER_NS=MUC_NS+"#owner"
     41
     42  affiliations=("admin","member","none","outcast","owner")
     43  roles=("moderator","none","participant","visitor")
     44
     45 -class MucXBase(StanzaPayloadWrapperObject):
     46      """
     47      Base class for MUC-specific stanza payload - wrapper around
     48      an XML element.
     49
     50      :Ivariables:
     51          - `xmlnode`: the wrapped XML node
     52      """
     53      element="x"
     54      ns=None
     55 -    def __init__(self, xmlnode=None, copy=True, parent=None):
     56          """
     57          Copy MucXBase object or create a new one, possibly
     58          based on or wrapping an XML node.
     59
     60          :Parameters:
     61              - `xmlnode`: is the object to copy or an XML node to wrap.
     62              - `copy`: when `True` a copy of the XML node provided will be included
     63                in `self`, the node will be copied otherwise.
     64              - `parent`: parent node for the created/copied XML element.
     65          :Types:
     66              - `xmlnode`: `MucXBase` or `libxml2.xmlNode`
     67              - `copy`: `bool`
     68              - `parent`: `libxml2.xmlNode`
     69          """
     70          if self.ns==None:
     71              raise RuntimeError,"Pure virtual class called"
     72          self.xmlnode=None
     73          self.borrowed=False
     74          if isinstance(xmlnode,libxml2.xmlNode):
     75              if copy:
     76                  self.xmlnode=xmlnode.docCopyNode(common_doc,1)
     77                  common_root.addChild(self.xmlnode)
     78              else:
     79                  self.xmlnode=xmlnode
     80                  self.borrowed=True
     81              if copy:
     82                  ns=xmlnode.ns()
     83                  xmlextra.replace_ns(self.xmlnode, ns, common_ns)
     84          elif isinstance(xmlnode,MucXBase):
     85              if not copy:
     86                  raise TypeError, "MucXBase may only be copied"
     87              self.xmlnode=xmlnode.xmlnode.docCopyNode(common_doc,1)
     88              common_root.addChild(self.xmlnode)
     89          elif xmlnode is not None:
     90              raise TypeError, "Bad MucX constructor argument"
     91          else:
     92              if parent:
     93                  self.xmlnode=parent.newChild(None,self.element,None)
     94                  self.borrowed=True
     95              else:
     96                  self.xmlnode=common_root.newChild(None,self.element,None)
     97              ns=self.xmlnode.newNs(self.ns,None)
     98              self.xmlnode.setNs(ns)
     99
    100 -    def __del__(self):
    101          if self.xmlnode:
    102              self.free()
    103
    104 -    def free(self):
    105          """
    106          Unlink and free the XML node owned by `self`.
    107          """
    108          if not self.borrowed:
    109              self.xmlnode.unlinkNode()
    110              self.xmlnode.freeNode()
    111          self.xmlnode=None
    112
    113 -    def free_borrowed(self):
    114          """
    115          Detach the XML node borrowed by `self`.
    116          """
    117          self.xmlnode=None
    118
    119 -    def xpath_eval(self,expr):
    120          """
    121          Evaluate XPath expression in context of `self.xmlnode`.
    122
    123          :Parameters:
    124              - `expr`: the XPath expression
    125          :Types:
    126              - `expr`: `unicode`
    127
    128          :return: the result of the expression evaluation.
    129          :returntype: list of `libxml2.xmlNode`
    130          """
    131          ctxt = common_doc.xpathNewContext()
    132          ctxt.setContextNode(self.xmlnode)
    133          ctxt.xpathRegisterNs("muc",self.ns.getContent())
    134          ret=ctxt.xpathEval(to_utf8(expr))
    135          ctxt.xpathFreeContext()
    136          return ret
    137
    138 -    def serialize(self):
    139          """
    140          Serialize `self` as XML.
    141
    142          :return: serialized `self.xmlnode`.
    143          :returntype: `str`
    144          """
    145          return self.xmlnode.serialize()
    146
    147 -class MucX(MucXBase):
    148      """
    149      Wrapper for http://www.jabber.org/protocol/muc namespaced
    150      stanza payload "x" elements.
    151      """
    152      ns=MUC_NS
    153 -    def __init__(self, xmlnode=None, copy=True, parent=None):
    154          MucXBase.__init__(self,xmlnode=xmlnode, copy=copy, parent=parent)
    155
    156 -    def set_history(self, parameters):
    157          """
    158          Set history parameters.
    159
    160          Types:
    161              - `parameters`: `HistoryParameters`
    162          """
    163          for child in xml_element_iter(self.xmlnode.children):
    164              if get_node_ns_uri(child) == MUC_NS and child.name == "history":
    165                  child.unlinkNode()
    166                  child.freeNode()
    167                  break
    168
    169          if parameters.maxchars and parameters.maxchars < 0:
    170              raise ValueError, "History parameter maxchars must be positive"
    171          if parameters.maxstanzas and parameters.maxstanzas < 0:
    172              raise ValueError, "History parameter maxstanzas must be positive"
    173          if parameters.maxseconds and parameters.maxseconds < 0:
    174              raise ValueError, "History parameter maxseconds must be positive"
    175
    176          hnode=self.xmlnode.newChild(self.xmlnode.ns(), "history", None)
    177
    178          if parameters.maxchars is not None:
    179              hnode.setProp("maxchars", str(parameters.maxchars))
    180          if parameters.maxstanzas is not None:
    181              hnode.setProp("maxstanzas", str(parameters.maxstanzas))
    182          if parameters.maxseconds is not None:
    183              hnode.setProp("maxseconds", str(parameters.maxseconds))
    184          if parameters.since is not None:
    185              hnode.setProp("since", parameters.since.strftime("%Y-%m-%dT%H:%M:%SZ"))
    186
    187 -    def get_history(self):
    188          """Return history parameters carried by the stanza.
    189
    190          :returntype: `HistoryParameters`"""
    191          for child in xml_element_iter(self.xmlnode.children):
    192              if get_node_ns_uri(child) == MUC_NS and child.name == "history":
    193                  maxchars = from_utf8(child.prop("maxchars"))
    194                  if maxchars is not None:
    195                      maxchars = int(maxchars)
    196                  maxstanzas = from_utf8(child.prop("maxstanzas"))
    197                  if maxstanzas is not None:
    198                      maxstanzas = int(maxstanzas)
    199                  maxseconds = from_utf8(child.prop("maxseconds"))
    200                  if maxseconds is not None:
    201                      maxseconds = int(maxseconds)
    202                  # TODO: since -- requires parsing of Jabber dateTime profile
    203                  since = None
    204                  return HistoryParameters(maxchars, maxstanzas, maxseconds, since)
    205
    206 -    def set_password(self, password):
    207          """Set password for the MUC request.
    208
    209          :Parameters:
    210              - `password`: password
    211          :Types:
    212              - `password`: `unicode`"""
    213          for child in xml_element_iter(self.xmlnode.children):
    214              if get_node_ns_uri(child) == MUC_NS and child.name == "password":
    215                  child.unlinkNode()
    216                  child.freeNode()
    217                  break
    218
    219          if password is not None:
    220              self.xmlnode.newTextChild(self.xmlnode.ns(), "password", to_utf8(password))
    221
    222 -    def get_password(self):
    223          """Get password from the MUC request.
    224
    225          :returntype: `unicode`
    226          """
    227          for child in xml_element_iter(self.xmlnode.children):
    228              if get_node_ns_uri(child) == MUC_NS and child.name == "password":
    229                  return from_utf8(child.getContent())
    230          return None
    231
    232 -class HistoryParameters(object):
    233      """Provides parameters for MUC history management
    234
    235      :Ivariables:
    236          - `maxchars`: limit of the total number of characters in history.
    237          - `maxstanzas`: limit of the total number of messages in history.
    238          - `seconds`: send only messages received in the last `seconds` seconds.
    239          - `since`: Send only the messages received since the dateTime (UTC)
    240            specified.
    241      :Types:
    242          - `maxchars`: `int`
    243          - `maxstanzas`: `int`
    244          - `seconds`: `int`
    245          - `since`: `datetime.datetime`
    246      """
    247 -    def __init__(self, maxchars = None, maxstanzas = None, maxseconds = None, since = None):
    248          """Initializes a `HistoryParameters` object.
    249
    250          :Parameters:
    251              - `maxchars`: limit of the total number of characters in history.
    252              - `maxstanzas`: limit of the total number of messages in history.
    253              - `maxseconds`: send only messages received in the last `seconds` seconds.
    254              - `since`: Send only the messages received since the dateTime specified.
    255          :Types:
    256              - `maxchars`: `int`
    257              - `maxstanzas`: `int`
    258              - `maxseconds`: `int`
    259              - `since`: `datetime.datetime`
    260          """
    261          self.maxchars = maxchars
    262          self.maxstanzas = maxstanzas
    263          self.maxseconds = maxseconds
    264          self.since = since
    265
    266
    267 -class MucItemBase(object):
    268      """
    269      Base class for <status/> and <item/> element wrappers.
    270      """
    271 -    def __init__(self):
    272          if self.__class__ is MucItemBase:
    273              raise RuntimeError,"Abstract class called"
    274
    275 -class MucItem(MucItemBase):
    276      """
    277      MUC <item/> element -- describes a room occupant.
    278
    279      :Ivariables:
    280          - `affiliation`: affiliation of the user.
    281          - `role`: role of the user.
    282          - `jid`: JID of the user.
    283          - `nick`: nickname of the user.
    284          - `actor`: actor modyfying the user data.
    285          - `reason`: reason of change of the user data.
    286      :Types:
    287          - `affiliation`: `str`
    288          - `role`: `str`
    289          - `jid`: `JID`
    290          - `nick`: `unicode`
    291          - `actor`: `JID`
    292          - `reason`: `unicode`
    293      """
    294 -    def __init__(self,xmlnode_or_affiliation,role=None,jid=None,nick=None,actor=None,reason=None):
    295          """
    296          Initialize a `MucItem` object.
    297
    298          :Parameters:
    299              - `xmlnode_or_affiliation`: XML node to be pased or the affiliation of
    300                the user being described.
    301              - `role`: role of the user.
    302              - `jid`: JID of the user.
    303              - `nick`: nickname of the user.
    304              - `actor`: actor modyfying the user data.
    305              - `reason`: reason of change of the user data.
    306          :Types:
    307              - `xmlnode_or_affiliation`: `libxml2.xmlNode` or `str`
    308              - `role`: `str`
    309              - `jid`: `JID`
    310              - `nick`: `unicode`
    311              - `actor`: `JID`
    312              - `reason`: `unicode`
    313          """
    314          self.jid,self.nick,self.actor,self.affiliation,self.reason,self.role=(None,)*6
    315          MucItemBase.__init__(self)
    316          if isinstance(xmlnode_or_affiliation,libxml2.xmlNode):
    317              self.__from_xmlnode(xmlnode_or_affiliation)
    318          else:
    319              self.__init(xmlnode_or_affiliation,role,jid,nick,actor,reason)
    320
    321 -    def __init(self,affiliation,role,jid=None,nick=None,actor=None,reason=None):
    322          """Initialize a `MucItem` object from a set of attributes.
    323
    324          :Parameters:
    325              - `affiliation`: affiliation of the user.
    326              - `role`: role of the user.
    327              - `jid`: JID of the user.
    328              - `nick`: nickname of the user.
    329              - `actor`: actor modyfying the user data.
    330              - `reason`: reason of change of the user data.
    331          :Types:
    332              - `affiliation`: `str`
    333              - `role`: `str`
    334              - `jid`: `JID`
    335              - `nick`: `unicode`
    336              - `actor`: `JID`
    337              - `reason`: `unicode`
    338          """
    339          if not affiliation:
    340              affiliation=None
    341          elif affiliation not in affiliations:
    342              raise ValueError,"Bad affiliation"
    343          self.affiliation=affiliation
    344          if not role:
    345              role=None
    346          elif role not in roles:
    347              raise ValueError,"Bad role"
    348          self.role=role
    349          if jid:
    350              self.jid=JID(jid)
    351          else:
    352              self.jid=None
    353          if actor:
    354              self.actor=JID(actor)
    355          else:
    356              self.actor=None
    357          self.nick=nick
    358          self.reason=reason
    359
    360 -    def __from_xmlnode(self, xmlnode):
    361          """Initialize a `MucItem` object from an XML node.
    362
    363          :Parameters:
    364              - `xmlnode`: the XML node.
    365          :Types:
    366              - `xmlnode`: `libxml2.xmlNode`
    367          """
    368          actor=None
    369          reason=None
    370          n=xmlnode.children
    371          while n:
    372              ns=n.ns()
    373              if ns and ns.getContent()!=MUC_USER_NS:
    374                  continue
    375              if n.name=="actor":
    376                  actor=n.getContent()
    377              if n.name=="reason":
    378                  reason=n.getContent()
    379              n=n.next
    380          self.__init(
    381              from_utf8(xmlnode.prop("affiliation")),
    382              from_utf8(xmlnode.prop("role")),
    383              from_utf8(xmlnode.prop("jid")),
    384              from_utf8(xmlnode.prop("nick")),
    385              from_utf8(actor),
    386              from_utf8(reason),
    387              );
    388
    389 -    def as_xml(self,parent):
    390          """
    391          Create XML representation of `self`.
    392
    393          :Parameters:
    394              - `parent`: the element to which the created node should be linked to.
    395          :Types:
    396              - `parent`: `libxml2.xmlNode`
    397
    398          :return: an XML node.
    399          :returntype: `libxml2.xmlNode`
    400          """
    401          n=parent.newChild(None,"item",None)
    402          if self.actor:
    403              n.newTextChild(None,"actor",to_utf8(self.actor))
    404          if self.reason:
    405              n.newTextChild(None,"reason",to_utf8(self.reason))
    406          n.setProp("affiliation",to_utf8(self.affiliation))
    407          n.setProp("role",to_utf8(self.role))
    408          if self.jid:
    409              n.setProp("jid",to_utf8(self.jid.as_unicode()))
    410          if self.nick:
    411              n.setProp("nick",to_utf8(self.nick))
    412          return n
    413
    414 -class MucStatus(MucItemBase):
    415      """
    416      MUC <item/> element - describes special meaning of a stanza
    417
    418      :Ivariables:
    419          - `code`: staus code, as defined in JEP 45
    420      :Types:
    421          - `code`: `int`
    422      """
    423 -    def __init__(self,xmlnode_or_code):
    424          """Initialize a `MucStatus` element.
    425
    426          :Parameters:
    427              - `xmlnode_or_code`: XML node to parse or a status code.
    428          :Types:
    429              - `xmlnode_or_code`: `libxml2.xmlNode` or `int`
    430          """
    431          self.code=None
    432          MucItemBase.__init__(self)
    433          if isinstance(xmlnode_or_code,libxml2.xmlNode):
    434              self.__from_xmlnode(xmlnode_or_code)
    435          else:
    436              self.__init(xmlnode_or_code)
    437
    438 -    def __init(self,code):
    439          """Initialize a `MucStatus` element from a status code.
    440
    441          :Parameters:
    442              - `code`: the status code.
    443          :Types:
    444              - `code`: `int`
    445          """
    446          code=int(code)
    447          if code<0 or code>999:
    448              raise ValueError,"Bad status code"
    449          self.code=code
    450
    451 -    def __from_xmlnode(self, xmlnode):
    452          """Initialize a `MucStatus` element from an XML node.
    453
    454          :Parameters:
    455              - `xmlnode`: XML node to parse.
    456          :Types:
    457              - `xmlnode`: `libxml2.xmlNode`
    458          """
    459          self.code=int(xmlnode.prop("code"))
    460
    461 -    def as_xml(self,parent):
    462          """
    463          Create XML representation of `self`.
    464
    465          :Parameters:
    466              - `parent`: the element to which the created node should be linked to.
    467          :Types:
    468              - `parent`: `libxml2.xmlNode`
    469
    470          :return: an XML node.
    471          :returntype: `libxml2.xmlNode`
    472          """
    473          n=parent.newChild(None,"status",None)
    474          n.setProp("code","%03i" % (self.code,))
    475          return n
    476
    477 -class MucUserX(MucXBase):
    478      """
    479      Wrapper for http://www.jabber.org/protocol/muc#user namespaced
    480      stanza payload "x" elements and usually containing information
    481      about a room user.
    482
    483      :Ivariables:
    484          - `xmlnode`: wrapped XML node
    485      :Types:
    486          - `xmlnode`: `libxml2.xmlNode`
    487      """
    488      ns=MUC_USER_NS
    489 -    def get_items(self):
    490          """Get a list of objects describing the content of `self`.
    491
    492          :return: the list of objects.
    493          :returntype: `list` of `MucItemBase` (`MucItem` and/or `MucStatus`)
    494          """
    495          if not self.xmlnode.children:
    496              return []
    497          ret=[]
    498          n=self.xmlnode.children
    499          while n:
    500              ns=n.ns()
    501              if ns and ns.getContent()!=self.ns:
    502                  pass
    503              elif n.name=="item":
    504                  ret.append(MucItem(n))
    505              elif n.name=="status":
    506                  ret.append(MucStatus(n))
    507              # FIXME: alt,decline,invite,password
    508              n=n.next
    509          return ret
    510 -    def clear(self):
    511          """
    512          Clear the content of `self.xmlnode` removing all <item/>, <status/>, etc.
    513          """
    514          if not self.xmlnode.children:
    515              return
    516          n=self.xmlnode.children
    517          while n:
    518              ns=n.ns()
    519              if ns and ns.getContent()!=MUC_USER_NS:
    520                  pass
    521              else:
    522                  n.unlinkNode()
    523                  n.freeNode()
    524              n=n.next
    525 -    def add_item(self,item):
    526          """Add an item to `self`.
    527
    528          :Parameters:
    529              - `item`: the item to add.
    530          :Types:
    531              - `item`: `MucItemBase`
    532          """
    533          if not isinstance(item,MucItemBase):
    534              raise TypeError,"Bad item type for muc#user"
    535          item.as_xml(self.xmlnode)
    536
    537 -class MucOwnerX(MucXBase):
    538      """
    539      Wrapper for http://www.jabber.org/protocol/muc#owner namespaced
    540      stanza payload "x" elements and usually containing information
    541      about a room user.
    542
    543      :Ivariables:
    544          - `xmlnode`: wrapped XML node.
    545      :Types:
    546          - `xmlnode`: `libxml2.xmlNode`
    547      """
    548      # FIXME: implement
    549      pass
    550
    551 -class MucAdminQuery(MucUserX):
    552      """
    553      Wrapper for http://www.jabber.org/protocol/muc#admin namespaced
    554      IQ stanza payload "query" elements and usually describing
    555      administrative actions or their results.
    556
    557      Not implemented yet.
    558      """
    559      ns=MUC_ADMIN_NS
    560      element="query"
    561
    562 -class MucStanzaExt:
    563      """
    564      Base class for MUC specific stanza extensions. Used together
    565      with one of stanza classes (Iq, Message or Presence).
    566      """
    567 -    def __init__(self):
    568          """Initialize a `MucStanzaExt` derived object."""
    569          if self.__class__ is MucStanzaExt:
    570              raise RuntimeError,"Abstract class called"
    571          self.xmlnode=None
    572          self.muc_child=None
    573
    574 -    def get_muc_child(self):
    575          """
    576          Get the MUC specific payload element.
    577
    578          :return: the object describing the stanza payload in MUC namespace.
    579          :returntype: `MucX` or `MucUserX` or `MucAdminQuery` or `MucOwnerX`
    580          """
    581          if self.muc_child:
    582              return self.muc_child
    583          if not self.xmlnode.children:
    584              return None
    585          n=self.xmlnode.children
    586          while n:
    587              if n.name not in ("x","query"):
    588                  n=n.next
    589                  continue
    590              ns=n.ns()
    591              if not ns:
    592                  n=n.next
    593                  continue
    594              ns_uri=ns.getContent()
    595              if (n.name,ns_uri)==("x",MUC_NS):
    596                  self.muc_child=MucX(n)
    597                  return self.muc_child
    598              if (n.name,ns_uri)==("x",MUC_USER_NS):
    599                  self.muc_child=MucUserX(n)
    600                  return self.muc_child
    601              if (n.name,ns_uri)==("query",MUC_ADMIN_NS):
    602                  self.muc_child=MucAdminQuery(n)
    603                  return self.muc_child
    604              if (n.name,ns_uri)==("query",MUC_OWNER_NS):
    605                  self.muc_child=MucOwnerX(n)
    606                  return self.muc_child
    607              n=n.next
    608
    609 -    def clear_muc_child(self):
    610          """
    611          Remove the MUC specific stanza payload element.
    612          """
    613          if self.muc_child:
    614              self.muc_child.free_borrowed()
    615              self.muc_child=None
    616          if not self.xmlnode.children:
    617              return
    618          n=self.xmlnode.children
    619          while n:
    620              if n.name not in ("x","query"):
    621                  n=n.next
    622                  continue
    623              ns=n.ns()
    624              if not ns:
    625                  n=n.next
    626                  continue
    627              ns_uri=ns.getContent()
    628              if ns_uri in (MUC_NS,MUC_USER_NS,MUC_ADMIN_NS,MUC_OWNER_NS):
    629                  n.unlinkNode()
    630                  n.freeNode()
    631              n=n.next
    632
    633 -    def make_muc_userinfo(self):
    634          """
    635          Create <x xmlns="...muc#user"/> element in the stanza.
    636
    637          :return: the element created.
    638          :returntype: `MucUserX`
    639          """
    640          self.clear_muc_child()
    641          self.muc_child=MucUserX(parent=self.xmlnode)
    642          return self.muc_child
    643
    644 -    def make_muc_admin_quey(self):
    645          """
    646          Create <query xmlns="...muc#admin"/> element in the stanza.
    647
    648          :return: the element created.
    649          :returntype: `MucAdminQuery`
    650          """
    651          self.clear_muc_child()
    652          self.muc_child=MucAdminQuery(parent=self.xmlnode)
    653          return self.muc_child
    654
    655 -    def muc_free(self):
    656          """
    657          Free MUC specific data.
    658          """
    659          if self.muc_child:
    660              self.muc_child.free_borrowed()
    661
    662 -class MucPresence(Presence,MucStanzaExt):
    663      """
    664      Extend `Presence` with MUC related interface.
    665      """
    666 -    def __init__(self, xmlnode=None,from_jid=None,to_jid=None,stanza_type=None,stanza_id=None,
    667              show=None,status=None,priority=0,error=None,error_cond=None):
    668          """Initialize a `MucPresence` object.
    669
    670          :Parameters:
    671              - `xmlnode`: XML node to_jid be wrapped into the `MucPresence` object
    672                or other Presence object to be copied. If not given then new
    673                presence stanza is created using following parameters.
    674              - `from_jid`: sender JID.
    675              - `to_jid`: recipient JID.
    676              - `stanza_type`: staza type: one of: None, "available", "unavailable",
    677                "subscribe", "subscribed", "unsubscribe", "unsubscribed" or
    678                "error". "available" is automaticaly changed to_jid None.
    679              - `stanza_id`: stanza id -- value of stanza's "id" attribute
    680              - `show`: "show" field of presence stanza. One of: None, "away",
    681                "xa", "dnd", "chat".
    682              - `status`: descriptive text for the presence stanza.
    683              - `priority`: presence priority.
    684              - `error_cond`: error condition name. Ignored if `stanza_type` is not "error"
    685          :Types:
    686              - `xmlnode`: `unicode` or `libxml2.xmlNode` or `pyxmpp.stanza.Stanza`
    687              - `from_jid`: `JID`
    688              - `to_jid`: `JID`
    689              - `stanza_type`: `unicode`
    690              - `stanza_id`: `unicode`
    691              - `show`: `unicode`
    692              - `status`: `unicode`
    693              - `priority`: `unicode`
    694              - `error_cond`: `unicode`"""
    695          MucStanzaExt.__init__(self)
    696          Presence.__init__(self,xmlnode,from_jid=from_jid,to_jid=to_jid,
    697                  stanza_type=stanza_type,stanza_id=stanza_id,
    698                  show=show,status=status,priority=priority,
    699                  error=error,error_cond=error_cond)
    700
    701 -    def copy(self):
    702          """
    703          Return a copy of `self`.
    704          """
    705          return MucPresence(self)
    706
    707 -    def make_join_request(self, password = None, history_maxchars = None,
    708              history_maxstanzas = None, history_seconds = None,
    709              history_since = None):
    710          """
    711          Make the presence stanza a MUC room join request.
    712
    713          :Parameters:
    714              - `password`: password to the room.
    715              - `history_maxchars`: limit of the total number of characters in
    716                history.
    717              - `history_maxstanzas`: limit of the total number of messages in
    718                history.
    719              - `history_seconds`: send only messages received in the last
    720                `seconds` seconds.
    721              - `history_since`: Send only the messages received since the
    722                dateTime specified (UTC).
    723          :Types:
    724              - `password`: `unicode`
    725              - `history_maxchars`: `int`
    726              - `history_maxstanzas`: `int`
    727              - `history_seconds`: `int`
    728              - `history_since`: `datetime.datetime`
    729          """
    730          self.clear_muc_child()
    731          self.muc_child=MucX(parent=self.xmlnode)
    732          if (history_maxchars is not None or history_maxstanzas is not None
    733                  or history_seconds is not None or history_since is not None):
    734              history = HistoryParameters(history_maxchars, history_maxstanzas,
    735                      history_seconds, history_since)
    736              self.muc_child.set_history(history)
    737          if password is not None:
    738              self.muc_child.set_password(password)
    739
    740 -    def get_join_info(self):
    741          """If `self` is a MUC room join request return the information contained.
    742
    743          :return: the join request details or `None`.
    744          :returntype: `MucX`
    745          """
    746          x=self.get_muc_child()
    747          if not x:
    748              return None
    749          if not isinstance(x,MucX):
    750              return None
    751          return x
    752
    753 -    def free(self):
    754          """Free the data associated with this `MucPresence` object."""
    755          self.muc_free()
    756          Presence.free(self)
    757
    758 -class MucIq(Iq,MucStanzaExt):
    759      """
    760      Extend `Iq` with MUC related interface.
    761      """
    762 -    def __init__(self,xmlnode=None,from_jid=None,to_jid=None,stanza_type=None,stanza_id=None,
    763              error=None,error_cond=None):
    764          """Initialize an `Iq` object.
    765
    766          :Parameters:
    767              - `xmlnode`: XML node to_jid be wrapped into the `Iq` object
    768                or other Iq object to be copied. If not given then new
    769                presence stanza is created using following parameters.
    770              - `from_jid`: sender JID.
    771              - `to_jid`: recipient JID.
    772              - `stanza_type`: staza type: one of: "get", "set", "result" or "error".
    773              - `stanza_id`: stanza id -- value of stanza's "id" attribute. If not
    774                given, then unique for the session value is generated.
    775              - `error_cond`: error condition name. Ignored if `stanza_type` is not "error".
    776          :Types:
    777              - `xmlnode`: `unicode` or `libxml2.xmlNode` or `Iq`
    778              - `from_jid`: `JID`
    779              - `to_jid`: `JID`
    780              - `stanza_type`: `unicode`
    781              - `stanza_id`: `unicode`
    782              - `error_cond`: `unicode`"""
    783          MucStanzaExt.__init__(self)
    784          Iq.__init__(self,xmlnode,from_jid=from_jid,to_jid=to_jid,
    785                  stanza_type=stanza_type,stanza_id=stanza_id,
    786                  error=error,error_cond=error_cond)
    787
    788 -    def copy(self):
    789          """ Return a copy of `self`.  """
    790          return MucIq(self)
    791
    792 -    def make_kick_request(self,nick,reason):
    793          """
    794          Make the iq stanza a MUC room participant kick request.
    795
    796          :Parameters:
    797              - `nick`: nickname of user to kick.
    798              - `reason`: reason of the kick.
    799          :Types:
    800              - `nick`: `unicode`
    801              - `reason`: `unicode`
    802
    803          :return: object describing the kick request details.
    804          :returntype: `MucItem`
    805          """
    806          self.clear_muc_child()
    807          self.muc_child=MucAdminQuery(parent=self.xmlnode)
    808          item=MucItem("none","none",nick=nick,reason=reason)
    809          self.muc_child.add_item(item)
    810          return self.muc_child
    811
    812 -    def free(self):
    813          """Free the data associated with this `MucIq` object."""
    814          self.muc_free()
    815          Iq.free(self)
    816
    817  # vi: sts=4 et sw=4
    818