Exemple #1
0
    def complete_xml_element(self, xmlnode, doc):
        """Complete the XML node with `self` content.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `doc`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `doc`: `libxml2.xmlDoc`"""
        if self.type is not None and self.type not in self.allowed_types:
            raise ValueError, "Invalid form field type: %r" % (self.type,)
        if self.type is not None:
            xmlnode.setProp("type", self.type)
        if not self.label is None:
            xmlnode.setProp("label", to_utf8(self.label))
        if not self.name is None:
            xmlnode.setProp("var", to_utf8(self.name))
        if self.values:
            if self.type and len(self.values) > 1 and not self.type.endswith(u"-multi"):
                raise ValueError, "Multiple values not allowed for %r field" % (self.type,)
            for value in self.values:
                xmlnode.newTextChild(xmlnode.ns(), "value", to_utf8(value))
        for option in self.options:
            option.as_xml(xmlnode, doc)
        if self.required:
            xmlnode.newChild(xmlnode.ns(), "required", None)
        if self.desc:
            xmlnode.newTextChild(xmlnode.ns(), "desc", to_utf8(self.desc))
        return xmlnode
Exemple #2
0
    def complete_xml_element(self, xmlnode, _unused):
        """Complete the XML node with `self` content.

        Should be overriden in classes derived from `StanzaPayloadObject`.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `_unused`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `_unused`: `libxml2.xmlDoc`"""
        if self.node:
            xmlnode.setProp("node", to_utf8(self.node))
        if self.sid:
            xmlnode.setProp("sid", to_utf8(self.sid))
        if self.mode and self.mode != 'tcp':
            xmlnode.setProp("mode", to_utf8(self.mode))
        for host in self.hosts:
            try:
                host.as_xml(xmlnode, _unused)
            except:
                pprint(host)
                raise
        if self.activate:
            xmlnode.newChild(None, "activate", JID(self.activate).as_utf8())
        if self.host_used:
            h = xmlnode.newChild(None, "streamhost-used", None)
            h.setProp("jid", JID(self.host_used).as_utf8())
Exemple #3
0
    def complete_xml_element(self, xmlnode, doc):
        """Complete the XML node with `self` content.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `doc`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `doc`: `libxml2.xmlDoc`"""
        if self.type not in self.allowed_types:
            raise ValueError, "Form type %r not allowed." % (self.type, )
        xmlnode.setProp("type", self.type)
        if self.type == "cancel":
            return
        ns = xmlnode.ns()
        if self.title is not None:
            xmlnode.newTextChild(ns, "title", to_utf8(self.title))
        if self.instructions is not None:
            xmlnode.newTextChild(ns, "instructions",
                                 to_utf8(self.instructions))
        for field in self.fields:
            field.as_xml(xmlnode, doc)
        if self.type != "result":
            return
        if self.reported_fields:
            reported = xmlnode.newChild(ns, "reported", None)
            for field in self.reported_fields:
                field.as_xml(reported, doc)
        for item in self.items:
            item.as_xml(xmlnode, doc)
Exemple #4
0
    def complete_xml_element(self, xmlnode, doc):
        """Complete the XML node with `self` content.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `doc`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `doc`: `libxml2.xmlDoc`"""
        if self.type not in self.allowed_types:
            raise ValueError, "Form type %r not allowed." % (self.type,)
        xmlnode.setProp("type", self.type)
        if self.type == "cancel":
            return
        ns = xmlnode.ns()
        if self.title is not None:
            xmlnode.newTextChild(ns, "title", to_utf8(self.title))
        if self.instructions is not None:
            xmlnode.newTextChild(ns, "instructions", to_utf8(self.instructions))
        for field in self.fields:
            field.as_xml(xmlnode, doc)
        if self.type != "result":
            return
        if self.reported_fields:
            reported = xmlnode.newChild(ns, "reported", None)
            for field in self.reported_fields:
                field.as_xml(reported, doc)
        for item in self.items:
            item.as_xml(xmlnode, doc)
Exemple #5
0
    def complete_xml_element(self, xmlnode, doc):
        """Complete the XML node with `self` content.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `doc`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `doc`: `libxml2.xmlDoc`"""
        ns = xmlnode.ns()
        if self.instructions is not None:
            xmlnode.newTextChild(ns, "instructions",
                                 to_utf8(self.instructions))
        if self.form:
            self.form.as_xml(xmlnode, doc)
        if self.remove:
            xmlnode.newChild(ns, "remove", None)
        else:
            if self.registered:
                xmlnode.newChild(ns, "registered", None)
            for field in legacy_fields:
                value = getattr(self, field)
                if value is not None:
                    xmlnode.newTextChild(ns, field, to_utf8(value))
Exemple #6
0
    def complete_xml_element(self, xmlnode, doc):
        """Complete the XML node with `self` content.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `doc`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `doc`: `libxml2.xmlDoc`"""
        if self.type is not None and self.type not in self.allowed_types:
            raise ValueError, "Invalid form field type: %r" % (self.type, )
        if self.type is not None:
            xmlnode.setProp("type", self.type)
        if not self.label is None:
            xmlnode.setProp("label", to_utf8(self.label))
        if not self.name is None:
            xmlnode.setProp("var", to_utf8(self.name))
        if self.values:
            if self.type and len(
                    self.values) > 1 and not self.type.endswith(u"-multi"):
                raise ValueError, "Multiple values not allowed for %r field" % (
                    self.type, )
            for value in self.values:
                xmlnode.newTextChild(xmlnode.ns(), "value", to_utf8(value))
        for option in self.options:
            option.as_xml(xmlnode, doc)
        if self.required:
            xmlnode.newChild(xmlnode.ns(), "required", None)
        if self.desc:
            xmlnode.newTextChild(xmlnode.ns(), "desc", to_utf8(self.desc))
        return xmlnode
Exemple #7
0
    def complete_xml_element(self, xmlnode, _unused):
        """Complete the XML node with `self` content.

        Should be overriden in classes derived from `StanzaPayloadObject`.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `_unused`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `_unused`: `libxml2.xmlDoc`"""
        if self.node:
            xmlnode.setProp("node", to_utf8(self.node))
        if self.sid:
            xmlnode.setProp("sid", to_utf8(self.sid))
        if self.mode and self.mode != 'tcp':
            xmlnode.setProp("mode", to_utf8(self.mode))
        for host in self.hosts:
            try:
                host.as_xml(xmlnode, _unused)
            except:
                pprint(host)
                raise
        if self.activate:
            xmlnode.newChild(None, "activate", JID(self.activate).as_utf8())
        if self.host_used:
            h = xmlnode.newChild(None, "streamhost-used", None)
            h.setProp("jid",JID(self.host_used).as_utf8())
Exemple #8
0
    def __init__(self, xmlnode = None, from_jid = None, to_jid = None, stanza_type = None, 
            stanza_id = None, show = None, status = None, priority = 0,
            error = None, error_cond = None, stream = None):
        """Initialize a `Presence` object.

        :Parameters:
            - `xmlnode`: XML node to_jid be wrapped into the `Presence` object
              or other Presence object to be copied. If not given then new
              presence stanza is created using following parameters.
            - `from_jid`: sender JID.
            - `to_jid`: recipient JID.
            - `stanza_type`: staza type: one of: None, "available", "unavailable",
              "subscribe", "subscribed", "unsubscribe", "unsubscribed" or
              "error". "available" is automaticaly changed to_jid None.
            - `stanza_id`: stanza id -- value of stanza's "id" attribute
            - `show`: "show" field of presence stanza. One of: None, "away",
              "xa", "dnd", "chat".
            - `status`: descriptive text for the presence stanza.
            - `priority`: presence priority.
            - `error_cond`: error condition name. Ignored if `stanza_type` is not "error"
        :Types:
            - `xmlnode`: `unicode` or `libxml2.xmlNode` or `Stanza`
            - `from_jid`: `JID`
            - `to_jid`: `JID`
            - `stanza_type`: `unicode`
            - `stanza_id`: `unicode`
            - `show`: `unicode`
            - `status`: `unicode`
            - `priority`: `unicode`
            - `error_cond`: `unicode`"""
        self.xmlnode=None
        if isinstance(xmlnode,Presence):
            pass
        elif isinstance(xmlnode,Stanza):
            raise TypeError,"Couldn't make Presence from other Stanza"
        elif isinstance(xmlnode,libxml2.xmlNode):
            pass
        elif xmlnode is not None:
            raise TypeError,"Couldn't make Presence from %r" % (type(xmlnode),)

        if stanza_type and stanza_type not in presence_types:
            raise ValueError, "Invalid presence type: %r" % (type,)

        if stanza_type=="available":
            stanza_type=None

        if xmlnode is None:
            xmlnode="presence"

        Stanza.__init__(self, xmlnode, from_jid = from_jid, to_jid = to_jid, stanza_type = stanza_type,
                stanza_id = stanza_id, error = error, error_cond = error_cond, stream = stream)

        if show:
            self.xmlnode.newTextChild(common_ns,"show",to_utf8(show))
        if status:
            self.xmlnode.newTextChild(common_ns,"status",to_utf8(status))
        if priority and priority!=0:
            self.xmlnode.newTextChild(common_ns,"priority",to_utf8(unicode(priority)))
Exemple #9
0
 def __from_xml(self, node):
     if node.type != "element":
         raise ValueError, "XML node is not an si (not en element)"
     ns = get_node_ns_uri(node)
     if ns and ns != SI_NS or node.name != self.xml_element_name:
         raise ValueError, "XML node is not an si"
     sid = node.prop("id")
     self.sid = to_utf8(sid) if sid else None
     mime_type = node.prop("mime-type")
     self.mime_type = to_utf8(mime_type) if mime_type else None
     profile_ns = node.prop("profile")
     self.profile_ns = to_utf8(profile_ns) if profile_ns else None
Exemple #10
0
    def complete_xml_element(self, xmlnode, _unused):
        'to xml'

        if isinstance(self.id, int) and self.id >=0:
            xmlnode.setProp("id",  to_utf8(str(self.id)))
        else:
            raise ValueError, "self.id must be int"
        xmlnode.setProp("protocol", to_utf8(self.protocol)) if self.protocol else None
        xmlnode.setProp("username", to_utf8(self.username)) if self.username else None
        xmlnode.setProp("password", base64.b64encode(self.password)) if self.password else None
        xmlnode.setProp("action",   to_utf8(self.action)) if self.action else None
        xmlnode.newTextChild(None, "data", binascii.b2a_base64(self.data)) if self.data is not None else None
Exemple #11
0
 def __from_xml(self, node):
     if node.type!="element":
         raise ValueError,"XML node is not an si (not en element)"
     ns=get_node_ns_uri(node)
     if ns and ns!=SI_NS or node.name!=self.xml_element_name:
         raise ValueError,"XML node is not an si"
     sid       = node.prop("id")
     self.sid  = to_utf8(sid) if sid else None
     mime_type = node.prop("mime-type")
     self.mime_type  = to_utf8(mime_type) if mime_type else None
     profile_ns   = node.prop("profile")
     self.profile_ns  = to_utf8(profile_ns) if profile_ns else None
Exemple #12
0
    def _plain_auth_stage2(self, _unused):
        """Do the second stage (<iq type='set'/>) of legacy "plain"
        authentication.

        [client only]"""
        iq = Iq(stanza_type="set")
        q = iq.new_query("jabber:iq:auth")
        q.newTextChild(None, "username", to_utf8(self.my_jid.node))
        q.newTextChild(None, "resource", to_utf8(self.my_jid.resource))
        q.newTextChild(None, "password", to_utf8(self.password))
        self.send(iq)
        self.set_response_handlers(iq, self.auth_finish, self.auth_error)
        iq.free()
Exemple #13
0
    def _plain_auth_stage2(self, _unused):
        """Do the second stage (<iq type='set'/>) of legacy "plain"
        authentication.

        [client only]"""
        iq=Iq(stanza_type="set")
        q=iq.new_query("jabber:iq:auth")
        q.newTextChild(None,"username",to_utf8(self.my_jid.node))
        q.newTextChild(None,"resource",to_utf8(self.my_jid.resource))
        q.newTextChild(None,"password",to_utf8(self.password))
        self.send(iq)
        self.set_response_handlers(iq,self.auth_finish,self.auth_error)
        iq.free()
Exemple #14
0
    def _auth_stage1(self):
        """Do the first stage (<iq type='get'/>) of legacy ("plain" or
        "digest") authentication.

        [client only]"""
        iq=Iq(stanza_type="get")
        q=iq.new_query("jabber:iq:auth")
        q.newTextChild(None,"username",to_utf8(self.my_jid.node))
        q.newTextChild(None,"resource",to_utf8(self.my_jid.resource))
        self.send(iq)
        self.set_response_handlers(iq,self.auth_stage2,self.auth_error,
                            self.auth_timeout,timeout=60)
        iq.free()
Exemple #15
0
    def __init__(self, xmlnode = None, from_jid = None, to_jid = None, stanza_type = None, stanza_id = None,
            subject = None, body = None, thread = None, error = None, error_cond = None, stream = None):
        """Initialize a `Message` object.

        :Parameters:
            - `xmlnode`: XML node to_jid be wrapped into the `Message` object
              or other Message object to be copied. If not given then new
              presence stanza is created using following parameters.
            - `from_jid`: sender JID.
            - `to_jid`: recipient JID.
            - `stanza_type`: staza type: one of: "get", "set", "result" or "error".
            - `stanza_id`: stanza id -- value of stanza's "id" attribute. If not
              given, then unique for the session value is generated.
            - `subject`: message subject,
            - `body`: message body.
            - `thread`: message thread id.
            - `error_cond`: error condition name. Ignored if `stanza_type` is not "error".
        :Types:
            - `xmlnode`: `unicode` or `libxml2.xmlNode` or `Stanza`
            - `from_jid`: `JID`
            - `to_jid`: `JID`
            - `stanza_type`: `unicode`
            - `stanza_id`: `unicode`
            - `subject`: `unicode`
            - `body`: `unicode`
            - `thread`: `unicode`
            - `error_cond`: `unicode`"""

        self.xmlnode=None
        if isinstance(xmlnode,Message):
            pass
        elif isinstance(xmlnode,Stanza):
            raise TypeError, "Couldn't make Message from other Stanza"
        elif isinstance(xmlnode,libxml2.xmlNode):
            pass
        elif xmlnode is not None:
            raise TypeError, "Couldn't make Message from %r" % (type(xmlnode),)

        if xmlnode is None:
            xmlnode="message"

        Stanza.__init__(self, xmlnode, from_jid = from_jid, to_jid = to_jid, stanza_type = stanza_type,
                stanza_id = stanza_id, error = error, error_cond = error_cond, stream = stream)

        if subject is not None:
            self.xmlnode.newTextChild(common_ns,"subject",to_utf8(subject))
        if body is not None:
            self.xmlnode.newTextChild(common_ns,"body",to_utf8(body))
        if thread is not None:
            self.xmlnode.newTextChild(common_ns,"thread",to_utf8(thread))
Exemple #16
0
    def _auth_stage1(self):
        """Do the first stage (<iq type='get'/>) of legacy ("plain" or
        "digest") authentication.

        [client only]"""
        iq = Iq(stanza_type="get")
        q = iq.new_query("jabber:iq:auth")
        q.newTextChild(None, "username", to_utf8(self.my_jid.node))
        q.newTextChild(None, "resource", to_utf8(self.my_jid.resource))
        self.send(iq)
        self.set_response_handlers(iq,
                                   self.auth_stage2,
                                   self.auth_error,
                                   self.auth_timeout,
                                   timeout=60)
        iq.free()
Exemple #17
0
    def xpath_eval(self,expr,namespaces=None):
        """Evaluate XPath expression on the error element.

        The expression will be evaluated in context where the common namespace
        (the one used for stanza elements, mapped to 'jabber:client',
        'jabber:server', etc.) is bound to prefix "ns" and other namespaces are
        bound accordingly to the `namespaces` list.

        :Parameters:
            - `expr`: the XPath expression.
            - `namespaces`: prefix to namespace mapping.
        :Types:
            - `expr`: `unicode`
            - `namespaces`: `dict`

        :return: the result of the expression evaluation.
        """
        ctxt = common_doc.xpathNewContext()
        ctxt.setContextNode(self.xmlnode)
        ctxt.xpathRegisterNs("ns",to_utf8(self.ns))
        if namespaces:
            for prefix,uri in namespaces.items():
                ctxt.xpathRegisterNs(prefix,uri)
        ret=ctxt.xpathEval(expr)
        ctxt.xpathFreeContext()
        return ret
Exemple #18
0
    def __init__(self,xmlnode_or_cond,error_type=None,copy=1,parent=None):
        """Initialize a StreamErrorNode object.

        :Parameters:
            - `xmlnode_or_cond`: XML node to be wrapped into this object
              or the primary (defined by XMPP specification) error condition name.
            - `error_type`: type of the error, one of: 'cancel', 'continue',
              'modify', 'auth', 'wait'.
            - `copy`: When `True` then the XML node will be copied,
              otherwise it is only borrowed.
            - `parent`: Parent node for the XML node to be copied or created.
        :Types:
            - `xmlnode_or_cond`: `libxml2.xmlNode` or `unicode`
            - `error_type`: `unicode`
            - `copy`: `bool`
            - `parent`: `libxml2.xmlNode`"""
        if type(xmlnode_or_cond) is str:
            xmlnode_or_cond=unicode(xmlnode_or_cond,"utf-8")
        if type(xmlnode_or_cond) is unicode:
            if not stanza_errors.has_key(xmlnode_or_cond):
                raise ValueError, "Bad error condition"

        ErrorNode.__init__(self,xmlnode_or_cond,STANZA_ERROR_NS,copy=copy,parent=parent)

        if type(xmlnode_or_cond) is unicode:
            if error_type is None:
                error_type=stanza_errors[xmlnode_or_cond][1]
            self.xmlnode.setProp("type",to_utf8(error_type))
Exemple #19
0
    def do_bind(self,stanza):
        """Do the resource binding requested by a client connected.

        [server only]

        :Parameters:
            - `stanza`: resource binding request stanza.
        :Types:
            - `stanza`: `pyxmpp.Iq`"""
        fr=stanza.get_from()
        if fr and fr!=self.peer:
            r=stanza.make_error_response("forbidden")
            self.send(r)
            r.free()
            return
        resource_n=stanza.xpath_eval("bind:bind/bind:resource",{"bind":BIND_NS})
        if resource_n:
            resource=resource_n[0].getContent()
        else:
            resource="auto"
        if not resource:
            r=stanza.make_error_response("bad-request")
        else:
            self.unset_iq_set_handler("bind",BIND_NS)
            r=stanza.make_result_response()
            self.peer.set_resource(resource)
            q=r.new_query(BIND_NS,"bind")
            q.newTextChild(None,"jid",to_utf8(self.peer.as_unicode()))
            self.state_change("authorized",self.peer)
        r.set_to(None)
        self.send(r)
        r.free()
Exemple #20
0
    def xpath_eval(self, expr, namespaces=None):
        """Evaluate XPath expression on the error element.

        The expression will be evaluated in context where the common namespace
        (the one used for stanza elements, mapped to 'jabber:client',
        'jabber:server', etc.) is bound to prefix "ns" and other namespaces are
        bound accordingly to the `namespaces` list.

        :Parameters:
            - `expr`: the XPath expression.
            - `namespaces`: prefix to namespace mapping.
        :Types:
            - `expr`: `unicode`
            - `namespaces`: `dict`

        :return: the result of the expression evaluation.
        """
        ctxt = common_doc.xpathNewContext()
        ctxt.setContextNode(self.xmlnode)
        ctxt.xpathRegisterNs("ns", to_utf8(self.ns))
        if namespaces:
            for prefix, uri in namespaces.items():
                ctxt.xpathRegisterNs(prefix, uri)
        ret = ctxt.xpathEval(expr)
        ctxt.xpathFreeContext()
        return ret
Exemple #21
0
    def __init__(self, xmlnode_or_cond, error_type=None, copy=1, parent=None):
        """Initialize a StreamErrorNode object.

        :Parameters:
            - `xmlnode_or_cond`: XML node to be wrapped into this object
              or the primary (defined by XMPP specification) error condition name.
            - `error_type`: type of the error, one of: 'cancel', 'continue',
              'modify', 'auth', 'wait'.
            - `copy`: When `True` then the XML node will be copied,
              otherwise it is only borrowed.
            - `parent`: Parent node for the XML node to be copied or created.
        :Types:
            - `xmlnode_or_cond`: `libxml2.xmlNode` or `unicode`
            - `error_type`: `unicode`
            - `copy`: `bool`
            - `parent`: `libxml2.xmlNode`"""
        if type(xmlnode_or_cond) is str:
            xmlnode_or_cond = unicode(xmlnode_or_cond, "utf-8")
        if type(xmlnode_or_cond) is unicode:
            if not stanza_errors.has_key(xmlnode_or_cond):
                raise ValueError, "Bad error condition"

        ErrorNode.__init__(self,
                           xmlnode_or_cond,
                           STANZA_ERROR_NS,
                           copy=copy,
                           parent=parent)

        if type(xmlnode_or_cond) is unicode:
            if error_type is None:
                error_type = stanza_errors[xmlnode_or_cond][1]
            self.xmlnode.setProp("type", to_utf8(error_type))
Exemple #22
0
    def do_bind(self, stanza):
        """Do the resource binding requested by a client connected.

        [server only]

        :Parameters:
            - `stanza`: resource binding request stanza.
        :Types:
            - `stanza`: `pyxmpp.Iq`"""
        fr = stanza.get_from()
        if fr and fr != self.peer:
            r = stanza.make_error_response("forbidden")
            self.send(r)
            r.free()
            return
        resource_n = stanza.xpath_eval("bind:bind/bind:resource",
                                       {"bind": BIND_NS})
        if resource_n:
            resource = resource_n[0].getContent()
        else:
            resource = "auto"
        if not resource:
            r = stanza.make_error_response("bad-request")
        else:
            self.unset_iq_set_handler("bind", BIND_NS)
            r = stanza.make_result_response()
            self.peer.set_resource(resource)
            q = r.new_query(BIND_NS, "bind")
            q.newTextChild(None, "jid", to_utf8(self.peer.as_unicode()))
            self.state_change("authorized", self.peer)
        r.set_to(None)
        self.send(r)
        r.free()
Exemple #23
0
    def _digest_auth_stage2(self, _unused):
        """Do the second stage (<iq type='set'/>) of legacy "digest"
        authentication.

        [client only]"""
        iq=Iq(stanza_type="set")
        q=iq.new_query("jabber:iq:auth")
        q.newTextChild(None,"username",to_utf8(self.my_jid.node))
        q.newTextChild(None,"resource",to_utf8(self.my_jid.resource))

        digest = hashlib.sha1(to_utf8(self.stream_id)+to_utf8(self.password)).hexdigest()

        q.newTextChild(None,"digest",digest)
        self.send(iq)
        self.set_response_handlers(iq,self.auth_finish,self.auth_error)
        iq.free()
Exemple #24
0
    def _parse_response(self, response):
        """Parse a client reponse and pass to further processing.

        :Parameters:
            - `response`: the response from the client.
        :Types:
            - `response`: `str`

        :return: a challenge, a success indicator or a failure indicator.
        :returntype: `sasl.Challenge`, `sasl.Success` or `sasl.Failure`"""
        response = response.split('\x00')[
            0]  # workaround for some SASL implementations
        if self.realm:
            realm = to_utf8(self.realm)
            realm = _quote(realm)
        else:
            realm = None
        username = None
        cnonce = None
        digest_uri = None
        response_val = None
        authzid = None
        nonce_count = None
        while response:
            m = _param_re.match(response)
            if not m:
                self.__logger.debug("Response syntax error: %r" % (response, ))
                return Failure("not-authorized")
            response = m.group("rest")
            var = m.group("var")
            val = m.group("val")
            self.__logger.debug("%r: %r" % (var, val))
            if var == "realm":
                realm = val[1:-1]
            elif var == "cnonce":
                if cnonce:
                    self.__logger.debug("Duplicate cnonce")
                    return Failure("not-authorized")
                cnonce = val[1:-1]
            elif var == "qop":
                if val != 'auth':
                    self.__logger.debug("qop other then 'auth'")
                    return Failure("not-authorized")
            elif var == "digest-uri":
                digest_uri = val[1:-1]
            elif var == "authzid":
                authzid = val[1:-1]
            elif var == "username":
                username = val[1:-1]
            elif var == "response":
                response_val = val
            elif var == "nc":
                nonce_count = val
                self.last_nonce_count += 1
                if int(nonce_count) != self.last_nonce_count:
                    self.__logger.debug("bad nonce: %r != %r" %
                                        (nonce_count, self.last_nonce_count))
                    return Failure("not-authorized")
        return self._check_params(username, realm, cnonce, digest_uri,
                                  response_val, authzid, nonce_count)
Exemple #25
0
    def _parse_response(self,response):
        """Parse a client reponse and pass to further processing.

        :Parameters:
            - `response`: the response from the client.
        :Types:
            - `response`: `str`

        :return: a challenge, a success indicator or a failure indicator.
        :returntype: `sasl.Challenge`, `sasl.Success` or `sasl.Failure`"""
        response=response.split('\x00')[0] # workaround for some SASL implementations
        if self.realm:
            realm=to_utf8(self.realm)
            realm=_quote(realm)
        else:
            realm=None
        username=None
        cnonce=None
        digest_uri=None
        response_val=None
        authzid=None
        nonce_count=None
        while response:
            m=_param_re.match(response)
            if not m:
                self.__logger.debug("Response syntax error: %r" % (response,))
                return Failure("not-authorized")
            response=m.group("rest")
            var=m.group("var")
            val=m.group("val")
            self.__logger.debug("%r: %r" % (var,val))
            if var=="realm":
                realm=val[1:-1]
            elif var=="cnonce":
                if cnonce:
                    self.__logger.debug("Duplicate cnonce")
                    return Failure("not-authorized")
                cnonce=val[1:-1]
            elif var=="qop":
                if val!='auth':
                    self.__logger.debug("qop other then 'auth'")
                    return Failure("not-authorized")
            elif var=="digest-uri":
                digest_uri=val[1:-1]
            elif var=="authzid":
                authzid=val[1:-1]
            elif var=="username":
                username=val[1:-1]
            elif var=="response":
                response_val=val
            elif var=="nc":
                nonce_count=val
                self.last_nonce_count+=1
                if int(nonce_count)!=self.last_nonce_count:
                    self.__logger.debug("bad nonce: %r != %r"
                            % (nonce_count,self.last_nonce_count))
                    return Failure("not-authorized")
        return self._check_params(username,realm,cnonce,digest_uri,
                response_val,authzid,nonce_count)
Exemple #26
0
    def _digest_auth_stage2(self, _unused):
        """Do the second stage (<iq type='set'/>) of legacy "digest"
        authentication.

        [client only]"""
        iq = Iq(stanza_type="set")
        q = iq.new_query("jabber:iq:auth")
        q.newTextChild(None, "username", to_utf8(self.my_jid.node))
        q.newTextChild(None, "resource", to_utf8(self.my_jid.resource))

        digest = hashlib.sha1(
            to_utf8(self.stream_id) + to_utf8(self.password)).hexdigest()

        q.newTextChild(None, "digest", digest)
        self.send(iq)
        self.set_response_handlers(iq, self.auth_finish, self.auth_error)
        iq.free()
Exemple #27
0
	def send_si_request(self, session) :
		'''
		<iq type='set' id='offer1' to='[email protected]/resource'>
			<si xmlns='http://jabber.org/protocol/si' id='a0' mime-type='text/plain' profile='http://jabber.org/protocol/si/profile/file-transfer'>
			<file xmlns='http://jabber.org/protocol/si/profile/file-transfer' name='test.txt' size='1022' hash='552da749930852c69ae5d2141d3766b1' date='1969-07-21T02:56:15Z'>
			<desc>This is a test. If this were a real file...</desc>
			</file>
			<feature xmlns='http://jabber.org/protocol/feature-neg'>
			<x xmlns='jabber:x:data' type='form'>
			<field var='stream-method' type='list-single'>
			<option><value>>>http://jabber.org/protocol/bytestreams</value></option>
			<option><value>>>http://jabber.org/protocol/ibb</value></option>
			</field>
			</x>
			</feature>
			</si>
		</iq>
		'''
		
		stream = self.client.get_stream()
		
		#new_id = stream.generate_id()
		iq = Iq(None, session.jid, session.to_jid, "set", session.sid)
		si_node = iq.add_new_content(SI_NS, 'si')
		si_node.setProp("id", session.sid)
		si_node.setProp("mime-type", 'application/octet-stream')
		si_node.setProp("profile", FILE_TRANSFER_NS)
	
		file_node = si_node.newChild(None,"file",None)
		file_node.setProp("xmlns", FILE_TRANSFER_NS)
		file_node.setProp("name", to_utf8(session.file_name))
		file_node.setProp("size", to_utf8(session.file_size))
	
		feature_node = si_node.newChild(None, "feature", None)
		feature_node.setProp("xmlns", FEATURE_NS)
        
		form = Form()
		form.add_field( name = 'stream-method', field_type = 'list-single', 
                        #options = [Option('http://jabber.org/protocol/bytestreams', None), Option('http://jabber.org/protocol/ibb', None)])
			options = [Option('http://jabber.org/protocol/ibb', None)])
		form.as_xml(feature_node)
		stream.set_response_handlers(iq, self.received_si_success, self.received_si_error)
		stream.send(iq)
		
		self.sessions[session.sid] = session
Exemple #28
0
    def set_status(self,status):
        """Change presence status description.

        :Parameters:
            - `status`: descriptive text for the presence stanza.
        :Types:
            - `status`: `unicode`"""
        n=self.xpath_eval("ns:status")
        if not status:
            if n:
                n[0].unlinkNode()
                n[0].freeNode()
            else:
                return
        if n:
            n[0].setContent(to_utf8(status))
        else:
            self.xmlnode.newTextChild(common_ns,"status",to_utf8(status))
Exemple #29
0
    def complete_xml_element(self, xmlnode, doc):
        xmlnode.setProp("type", self.type) if self.type else None
        xmlnode.setProp("value", self.value) if self.value else None
        xmlnode.setProp("action", self.action)
        xmlnode.setProp("order", to_utf8(self.order))

        [xmlnode.newChild(None, child, None)
         for child in PRIVACY_TYPES
         if getattr(self, util.pythonize(child))]
Exemple #30
0
    def set_status(self, status):
        """Change presence status description.

        :Parameters:
            - `status`: descriptive text for the presence stanza.
        :Types:
            - `status`: `unicode`"""
        n = self.xpath_eval("ns:status")
        if not status:
            if n:
                n[0].unlinkNode()
                n[0].freeNode()
            else:
                return
        if n:
            n[0].setContent(to_utf8(status))
        else:
            self.xmlnode.newTextChild(common_ns, "status", to_utf8(status))
Exemple #31
0
    def complete_xml_element(self, xmlnode, doc):
        xmlnode.setProp("type", self.type) if self.type else None
        xmlnode.setProp("value", self.value) if self.value else None
        xmlnode.setProp("action", self.action)
        xmlnode.setProp("order", to_utf8(self.order))

        [
            xmlnode.newChild(None, child, None) for child in PRIVACY_TYPES
            if getattr(self, util.pythonize(child))
        ]
Exemple #32
0
    def add_custom_condition(self, ns, cond, content=None):
        """Add custom condition element to the error.

        :Parameters:
            - `ns`: namespace URI.
            - `cond`: condition name.
            - `content`: content of the element.

        :Types:
            - `ns`: `unicode`
            - `cond`: `unicode`
            - `content`: `unicode`

        :return: the new condition element.
        :returntype: `libxml2.xmlNode`"""
        c = self.xmlnode.newTextChild(None, to_utf8(cond), content)
        ns = c.newNs(to_utf8(ns), None)
        c.setNs(ns)
        return c
Exemple #33
0
    def set_show(self, show):
        """Change presence "show" field.

        :Parameters:
            - `show`: new value for the "show" field of presence stanza. One
              of: None, "away", "xa", "dnd", "chat".
        :Types:
            - `show`: `unicode`"""
        n = self.xpath_eval("ns:show")
        if not show:
            if n:
                n[0].unlinkNode()
                n[0].freeNode()
            else:
                return
        if n:
            n[0].setContent(to_utf8(show))
        else:
            self.xmlnode.newTextChild(common_ns, "show", to_utf8(show))
Exemple #34
0
    def set_show(self,show):
        """Change presence "show" field.

        :Parameters:
            - `show`: new value for the "show" field of presence stanza. One
              of: None, "away", "xa", "dnd", "chat".
        :Types:
            - `show`: `unicode`"""
        n=self.xpath_eval("ns:show")
        if not show:
            if n:
                n[0].unlinkNode()
                n[0].freeNode()
            else:
                return
        if n:
            n[0].setContent(to_utf8(show))
        else:
            self.xmlnode.newTextChild(common_ns,"show",to_utf8(show))
Exemple #35
0
    def add_custom_condition(self,ns,cond,content=None):
        """Add custom condition element to the error.

        :Parameters:
            - `ns`: namespace URI.
            - `cond`: condition name.
            - `content`: content of the element.

        :Types:
            - `ns`: `unicode`
            - `cond`: `unicode`
            - `content`: `unicode`

        :return: the new condition element.
        :returntype: `libxml2.xmlNode`"""
        c=self.xmlnode.newTextChild(None,to_utf8(cond),content)
        ns=c.newNs(to_utf8(ns),None)
        c.setNs(ns)
        return c
Exemple #36
0
    def add_feature(self,var):
        """Add a feature to `self`.

        :Parameters:
            - `var`: the feature name.
        :Types:
            - `var`: `unicode`"""
        if self.has_feature(var):
            return
        n=self.xmlnode.newChild(None, "feature", None)
        n.setProp("var", to_utf8(var))
Exemple #37
0
    def complete_xml_element(self, xmlnode, _unused):
        """Complete the XML node with `self` content.

        Should be overriden in classes derived from `StanzaPayloadObject`.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `_unused`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `_unused`: `libxml2.xmlDoc`"""
        xmlnode.setProp("jid",self.jid.as_utf8())
        if self.name:
            xmlnode.setProp("name",to_utf8(self.name))
        xmlnode.setProp("subscription",self.subscription)
        if self.ask:
            xmlnode.setProp("ask",to_utf8(self.ask))
        for g in self.groups:
            xmlnode.newTextChild(None, "group", to_utf8(g))
Exemple #38
0
    def set_type(self,stanza_type):
        """Set "type" attribute of the stanza.

        :Parameters:
            - `stanza_type`: new value of the "type" attribute (stanza type).
        :Types:
            - `stanza_type`: `unicode`"""
        if stanza_type:
            return self.xmlnode.setProp("type",to_utf8(stanza_type))
        else:
            return self.xmlnode.unsetProp("type")
Exemple #39
0
    def set_id(self,stanza_id):
        """Set "id" attribute of the stanza.

        :Parameters:
            - `stanza_id`: new value of the "id" attribute (stanza identifier).
        :Types:
            - `stanza_id`: `unicode`"""
        if stanza_id:
            return self.xmlnode.setProp("id",to_utf8(stanza_id))
        else:
            return self.xmlnode.unsetProp("id")
Exemple #40
0
    def complete_xml_element(self, xmlnode, _unused):
        """Complete the XML node with `self` content.

        Should be overriden in classes derived from `StanzaPayloadObject`.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `_unused`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `_unused`: `libxml2.xmlDoc`"""
        xmlnode.setProp("jid", self.jid.as_utf8())
        if self.name:
            xmlnode.setProp("name", to_utf8(self.name))
        xmlnode.setProp("subscription", self.subscription)
        if self.ask:
            xmlnode.setProp("ask", to_utf8(self.ask))
        for g in self.groups:
            xmlnode.newTextChild(None, "group", to_utf8(g))
Exemple #41
0
    def add_feature(self, var):
        """Add a feature to `self`.

        :Parameters:
            - `var`: the feature name.
        :Types:
            - `var`: `unicode`"""
        if self.has_feature(var):
            return
        n = self.xmlnode.newChild(None, "feature", None)
        n.setProp("var", to_utf8(var))
Exemple #42
0
    def downgrade(self):
        """Downgrade an XMPP error element to the legacy format.

        Add a numeric code attribute according to the condition name."""
        if self.xmlnode.hasProp("code"):
            return
        cond = self.get_condition()
        if not cond:
            return
        cond = cond.name
        if stanza_errors.has_key(cond) and stanza_errors[cond][2]:
            self.xmlnode.setProp("code", to_utf8(stanza_errors[cond][2]))
Exemple #43
0
    def downgrade(self):
        """Downgrade an XMPP error element to the legacy format.

        Add a numeric code attribute according to the condition name."""
        if self.xmlnode.hasProp("code"):
            return
        cond=self.get_condition()
        if not cond:
            return
        cond=cond.name
        if stanza_errors.has_key(cond) and stanza_errors[cond][2]:
            self.xmlnode.setProp("code",to_utf8(stanza_errors[cond][2]))
Exemple #44
0
    def upgrade(self):
        """Upgrade a legacy error element to the XMPP compliant one.

        Use the error code provided to select the condition and the
        <error/> CDATA for the error text."""

        if not self.xmlnode.hasProp("code"):
            code = None
        else:
            try:
                code = int(self.xmlnode.prop("code"))
            except (ValueError, KeyError):
                code = None

        if code and legacy_codes.has_key(code):
            cond = legacy_codes[code]
        else:
            cond = None

        condition = self.xpath_eval("ns:*")
        if condition:
            return
        elif cond is None:
            condition = self.xmlnode.newChild(None, "undefined-condition",
                                              None)
            ns = condition.newNs(to_utf8(self.ns), None)
            condition.setNs(ns)
            condition = self.xmlnode.newChild(None, "unknown-legacy-error",
                                              None)
            ns = condition.newNs(PYXMPP_ERROR_NS, None)
            condition.setNs(ns)
        else:
            condition = self.xmlnode.newChild(None, cond, None)
            ns = condition.newNs(to_utf8(self.ns), None)
            condition.setNs(ns)
        txt = self.xmlnode.getContent()
        if txt:
            text = self.xmlnode.newTextChild(None, "text", txt)
            ns = text.newNs(to_utf8(self.ns), None)
            text.setNs(ns)
Exemple #45
0
    def as_xml(self, parent):
        """
        Create XML representation of `self`.

        :Parameters:
            - `parent`: the element to which the created node should be linked to.
        :Types:
            - `parent`: `libxml2.xmlNode`

        :return: an XML node.
        :returntype: `libxml2.xmlNode`
        """
        n = parent.newChild(None, "item", None)
        if self.actor:
            n.newTextChild(None, "actor", to_utf8(self.actor))
        if self.reason:
            n.newTextChild(None, "reason", to_utf8(self.reason))
        n.setProp("affiliation", to_utf8(self.affiliation))
        if self.role:
            n.setProp("role", to_utf8(self.role))
        if self.jid:
            n.setProp("jid", to_utf8(self.jid.as_unicode()))
        if self.nick:
            n.setProp("nick", to_utf8(self.nick))
        return n
Exemple #46
0
    def as_xml(self,parent):
        """
        Create XML representation of `self`.

        :Parameters:
            - `parent`: the element to which the created node should be linked to.
        :Types:
            - `parent`: `libxml2.xmlNode`

        :return: an XML node.
        :returntype: `libxml2.xmlNode`
        """
        n=parent.newChild(None,"item",None)
        if self.actor:
            n.newTextChild(None,"actor",to_utf8(self.actor))
        if self.reason:
            n.newTextChild(None,"reason",to_utf8(self.reason))
        n.setProp("affiliation",to_utf8(self.affiliation))
        if self.role:
            n.setProp("role",to_utf8(self.role))
        if self.jid:
            n.setProp("jid",to_utf8(self.jid.as_unicode()))
        if self.nick:
            n.setProp("nick",to_utf8(self.nick))
        return n
Exemple #47
0
    def _digest_auth_in_stage2(self, username, _unused, stanza):
        """Handle the second stage (<iq type='set'/>) of legacy "digest"
        authentication.

        [server only]"""
        digest = stanza.xpath_eval("a:query/a:digest", {"a": "jabber:iq:auth"})
        if digest:
            digest = digest[0].getContent()
        if not digest:
            self.__logger.debug("No digest found in digest auth request")
            iq = stanza.make_error_response("bad-request")
            self.send(iq)
            return

        password, pwformat = self.get_password(username)
        if not password or pwformat != "plain":
            iq = stanza.make_error_response("bad-request")
            e = iq.get_error()
            e.add_custom_condition('jabber:iq:auth:error', "user-unauthorized")
            self.send(iq)
            return

        mydigest = hashlib.sha1(to_utf8(self.stream_id) +
                                to_utf8(password)).hexdigest()

        if mydigest == digest:
            iq = stanza.make_result_response()
            self.send(iq)
            self.peer_authenticated = True
            self.auth_method_used = "digest"
            self.state_change("authorized", self.peer)
            self._post_auth()
        else:
            self.__logger.debug("Digest auth failed: %r != %r" %
                                (digest, mydigest))
            iq = stanza.make_error_response("bad-request")
            e = iq.get_error()
            e.add_custom_condition('jabber:iq:auth:error', "user-unauthorized")
            self.send(iq)
Exemple #48
0
 def query_set(self, ns, element, data, handler=None):
     stream = self.client.get_stream()
     new_id = stream.generate_id()
     iq = Iq(None, None, None, "set", new_id)
     node = iq.new_query('jabber:iq:private')
     enode = node.newChild(None, to_utf8(element), None)
     ns = enode.newNs(ns, None)
     enode.setNs(ns)
     enode.addContent(data)
     stream.set_response_handlers(iq, self.on_set_result, self.on_set_error)
     stream.send(iq)
     if handler:
         self.handlers[new_id] = handler
Exemple #49
0
    def upgrade(self):
        """Upgrade a legacy error element to the XMPP compliant one.

        Use the error code provided to select the condition and the
        <error/> CDATA for the error text."""

        if not self.xmlnode.hasProp("code"):
            code=None
        else:
            try:
                code=int(self.xmlnode.prop("code"))
            except (ValueError,KeyError):
                code=None

        if code and legacy_codes.has_key(code):
            cond=legacy_codes[code]
        else:
            cond=None

        condition=self.xpath_eval("ns:*")
        if condition:
            return
        elif cond is None:
            condition=self.xmlnode.newChild(None,"undefined-condition",None)
            ns=condition.newNs(to_utf8(self.ns),None)
            condition.setNs(ns)
            condition=self.xmlnode.newChild(None,"unknown-legacy-error",None)
            ns=condition.newNs(PYXMPP_ERROR_NS,None)
            condition.setNs(ns)
        else:
            condition=self.xmlnode.newChild(None,cond,None)
            ns=condition.newNs(to_utf8(self.ns),None)
            condition.setNs(ns)
        txt=self.xmlnode.getContent()
        if txt:
            text=self.xmlnode.newTextChild(None,"text",txt)
            ns=text.newNs(to_utf8(self.ns),None)
            text.setNs(ns)
Exemple #50
0
    def challenge(self, challenge):
        """Process the challenge and return the response.

        :Parameters:
            - `challenge`: the challenge.
        :Types:
            - `challenge`: `str`

        :return: the response or a failure indicator.
        :returntype: `sasl.Response` or `sasl.Failure`"""
        _unused = challenge
        if self.finished:
            self.__logger.debug("Already authenticated")
            return Failure("extra-challenge")
        self.finished=1
        if self.password is None:
            self.password,pformat=self.password_manager.get_password(self.username)
        if not self.password or pformat!="plain":
            self.__logger.debug("Couldn't retrieve plain password")
            return Failure("password-unavailable")
        return Response("%s\000%s\000%s" % (    to_utf8(self.authzid),
                            to_utf8(self.username),
                            to_utf8(self.password)))
Exemple #51
0
    def _digest_auth_in_stage2(self, username, _unused, stanza):
        """Handle the second stage (<iq type='set'/>) of legacy "digest"
        authentication.

        [server only]"""
        digest=stanza.xpath_eval("a:query/a:digest",{"a":"jabber:iq:auth"})
        if digest:
            digest=digest[0].getContent()
        if not digest:
            self.__logger.debug("No digest found in digest auth request")
            iq=stanza.make_error_response("bad-request")
            self.send(iq)
            return

        password,pwformat=self.get_password(username)
        if not password or pwformat!="plain":
            iq=stanza.make_error_response("bad-request")
            e=iq.get_error()
            e.add_custom_condition('jabber:iq:auth:error',"user-unauthorized")
            self.send(iq)
            return

        mydigest = hashlib.sha1(to_utf8(self.stream_id)+to_utf8(password)).hexdigest()

        if mydigest==digest:
            iq=stanza.make_result_response()
            self.send(iq)
            self.peer_authenticated=True
            self.auth_method_used="digest"
            self.state_change("authorized",self.peer)
            self._post_auth()
        else:
            self.__logger.debug("Digest auth failed: %r != %r" % (digest,mydigest))
            iq=stanza.make_error_response("bad-request")
            e=iq.get_error()
            e.add_custom_condition('jabber:iq:auth:error',"user-unauthorized")
            self.send(iq)
Exemple #52
0
    def from_xml(self, xmlnode):
        if xmlnode.type != "element":
            raise ValueError, "XML node is not a photo (not en element)"
        ns = get_node_ns_uri(xmlnode)
        if ns and ns != self.xml_element_namespace or xmlnode.name != self.xml_element_name:
            raise ValueError, "XML node is not a %s descriptor" % self.xml_element_name

        from_ = xmlnode.prop("from")
        self.from_ = to_utf8(from_) if from_ else None

        timestamp = xmlnode.prop("stamp")
        try:
            self.timestamp = datetime.strptime(timestamp, DELAY_TIME_FORMAT)
        except Exception:
            self.timestamp = None
Exemple #53
0
    def from_xml(self, xmlnode):
        if xmlnode.type!="element":
            raise ValueError,"XML node is not a photo (not en element)"
        ns=get_node_ns_uri(xmlnode)
        if ns and ns!=self.xml_element_namespace or xmlnode.name!=self.xml_element_name:
            raise ValueError,"XML node is not a %s descriptor" % self.xml_element_name

        from_       = xmlnode.prop("from")
        self.from_  = to_utf8(from_) if from_ else None

        timestamp   = xmlnode.prop("stamp")
        try:
            self.timestamp = datetime.strptime(timestamp, DELAY_TIME_FORMAT)
        except Exception:
            self.timestamp = None
Exemple #54
0
    def add_new_content(self,ns_uri,name):
        """Add a new XML element to the stanza payload.

        :Parameters:
            - `ns_uri`: XML namespace URI of the element.
            - `name`: element name.
        :Types:
            - `ns_uri`: `str`
            - `name`: `str` or `unicode`
        """
        c=self.xmlnode.newChild(None,to_utf8(name),None)
        if ns_uri:
            ns=c.newNs(ns_uri,None)
            c.setNs(ns)
        return c
Exemple #55
0
    def set_password(self, password):
        """Set password for the MUC request.

        :Parameters:
            - `password`: password
        :Types:
            - `password`: `unicode`"""
        for child in xml_element_iter(self.xmlnode.children):
            if get_node_ns_uri(child) == MUC_NS and child.name == "password":
                child.unlinkNode()
                child.freeNode()
                break

        if password is not None:
            self.xmlnode.newTextChild(self.xmlnode.ns(), "password", to_utf8(password))
Exemple #56
0
    def set_password(self, password):
        """Set password for the MUC request.

        :Parameters:
            - `password`: password
        :Types:
            - `password`: `unicode`"""
        for child in xml_element_iter(self.xmlnode.children):
            if get_node_ns_uri(child) == MUC_NS and child.name == "password":
                child.unlinkNode()
                child.freeNode()
                break

        if password is not None:
            self.xmlnode.newTextChild(self.xmlnode.ns(), "password",
                                      to_utf8(password))