COMMON_NS = "http://pyxmpp.jajcus.net/xmlns/common"
class StreamHandler:
    class error(Exception):
    class _SAXCallback(libxml2.SAXCallback):
    class _PythonReader:
class StreamReader:
    def __init__(self):
    def _stream_start(self,_doc):
    def _stream_end(self,_doc):
    def _stanza(self,_doc,_node):
    def stream_start(self,doc):
    def stream_end(self,doc):
    def stanza(self, _unused, node):
    def error(self,descr):
    def warning(self,desc):
    def replace_ns(node, old_ns,new_ns):
    def _escape(data):
        def __init__(self, handler):
        def cdataBlock(self, data):
        def characters(self, data):
        def comment(self, content):
        def endDocument(self):
        def endElement(self, tag):
        def error(self, msg):
        def reference(self, name):
        def startDocument(self):
        def startElement(self, tag, attrs):
        def warning(self):
        def __init__(self,handler):
        def feed(self, data):
    def _get_ns(node):
    def replace_ns(node, old_ns, new_ns):
def get_node_ns(xmlnode):
def get_node_ns_uri(xmlnode):
def xml_node_iter(nodelist):
def xml_element_iter(nodelist):
def xml_element_ns_iter(nodelist, ns_uri):
def remove_evil_characters(s):
def safe_serialize(xmlnode):
    def __init__(self,handler):
    def doc(self):
    def feed(self,s): class ExpiringDictionary(dict):
    """An extension to standard Python dictionary objects which implements item
    expiration.

    Each item in ExpiringDictionary has its expiration time assigned, after
    which the item is removed from the mapping.

    :Ivariables:
        - `_timeouts`: a dictionary with timeout values and timeout callback for
          stored objects.
        - `_default_timeout`: the default timeout value (in seconds from now).
        - `_lock`: access synchronization lock.
    :Types:
        - `_timeouts`: `dict`
        - `_default_timeout`: `int`
        - `_lock`: `threading.RLock`"""

    __slots__=['_timeouts','_default_timeout','_lock']

    def __init__(self,default_timeout=300):
        """Initialize an `ExpiringDictionary` object.

        :Parameters:
            - `default_timeout`: default timeout value for stored objects.
        :Types:
            - `default_timeout`: `int`"""
        dict.__init__(self)
        self._timeouts={}
        self._default_timeout=default_timeout
        self._lock=threading.RLock()

    def __delitem__(self,key):
        self._lock.acquire()
        try:
            del self._timeouts[key]
            return dict.__delitem__(self,key)
        finally:
            self._lock.release()

    def __getitem__(self,key):
        self._lock.acquire()
        try:
            self._expire_item(key)
            return dict.__getitem__(self,key)
        finally:
            self._lock.release()

    def pop(self,key,default=sentinel):
        self._lock.acquire()
        try:
            self._expire_item(key)
            del self._timeouts[key]
            if default is not sentinel:
                return dict.pop(self,key,default)
            else:
                return dict.pop(self,key)
        finally:
            self._lock.release()

    def __setitem__(self,key,value):
        return self.set_item(key,value)

    def set_item(self,key,value,timeout=None,timeout_callback=None):
        """Set item of the dictionary.

        :Parameters:
            - `key`: the key.
            - `value`: the object to store.
            - `timeout`: timeout value for the object (in seconds from now).
            - `timeout_callback`: function to be called when the item expires.
              The callback should accept none, one (the key) or two (the key
              and the value) arguments.
        :Types:
            - `key`: any hashable value
            - `value`: any python object
            - `timeout`: `int`
            - `timeout_callback`: callable"""
        self._lock.acquire()
        try:
            if not timeout:
                timeout=self._default_timeout
            self._timeouts[key]=(time.time()+timeout,timeout_callback)
            return dict.__setitem__(self,key,value)
        finally:
            self._lock.release()

    def expire(self):
        """Do the expiration of dictionary items.

        Remove items that expired by now from the dictionary."""
        self._lock.acquire()
        try:
            for k in self._timeouts.keys():
                self._expire_item(k)
        finally:
            self._lock.release()

    def _expire_item(self,key):
        """Do the expiration of a dictionary item.

        Remove the item if it has expired by now.

        :Parameters:
            - `key`: key to the object.
        :Types:
            - `key`: any hashable value"""
        (timeout,callback)=self._timeouts[key]
        if timeout<=time.time():
            item = dict.pop(self, key)
            del self._timeouts[key]
            if callback:
                try:
                    callback(key,item)
                except TypeError:
                    try:
                        callback(key)
                    except TypeError:
                        callback() def to_utf8(s):
    """
    Convevert `s` to UTF-8 if it is Unicode, leave unchanged
    if it is string or None and convert to string overwise
    """
    if s is None:
        return None
    elif type(s) is unicode:
        return s.encode("utf-8")
    elif type(s) is str:
        return s
    else:
        return unicode(s).encode("utf-8") def from_utf8(s):
    """
    Convert `s` to Unicode or leave unchanged if it is None.

    Regular strings are assumed to be UTF-8 encoded
    """
    if s is None:
        return None
    elif type(s) is unicode:
        return s
    elif type(s) is str:
        return unicode(s,"utf-8")
    else:
        return unicode(s) class Stanza:
    """Base class for all XMPP stanzas.

    :Ivariables:
        - `xmlnode`: stanza XML node.
        - `_error`: `pyxmpp.error.StanzaErrorNode` describing the error associated with
          the stanza of type "error".
        - `stream`: stream on which the stanza was received or `None`. May be
          used to send replies or get some session-related parameters.
    :Types:
        - `xmlnode`: `libxml2.xmlNode`
        - `_error`: `pyxmpp.error.StanzaErrorNode`"""
    stanza_type="Unknown"

    def __init__(self, name_or_xmlnode, from_jid=None, to_jid=None,
            stanza_type=None, stanza_id=None, error=None, error_cond=None,
            stream = None):
        """Initialize a Stanza object.

        :Parameters:
            - `name_or_xmlnode`: XML node to be wrapped into the Stanza 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: "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.
            - `error`: error object. Ignored if `stanza_type` is not "error".
            - `error_cond`: error condition name. Ignored if `stanza_type` is not
              "error" or `error` is not None.
        :Types:
            - `name_or_xmlnode`: `unicode` or `libxml2.xmlNode` or `Stanza`
            - `from_jid`: `JID`
            - `to_jid`: `JID`
            - `stanza_type`: `unicode`
            - `stanza_id`: `unicode`
            - `error`: `pyxmpp.error.StanzaErrorNode`
            - `error_cond`: `unicode`"""
        self._error=None
        self.xmlnode=None
        if isinstance(name_or_xmlnode,Stanza):
            self.xmlnode=name_or_xmlnode.xmlnode.docCopyNode(common_doc, True)
            common_doc.addChild(self.xmlnode)
            self.xmlnode.reconciliateNs(common_doc)
        elif isinstance(name_or_xmlnode,libxml2.xmlNode):
            self.xmlnode=name_or_xmlnode.docCopyNode(common_doc,1)
            common_doc.addChild(self.xmlnode)
            try:
                ns = self.xmlnode.ns()
            except libxml2.treeError:
                ns = None
            if not ns or not ns.name:
                xmlextra.replace_ns(self.xmlnode, ns, common_ns)
            self.xmlnode.reconciliateNs(common_doc)
        else:
            self.xmlnode=common_doc.newChild(common_ns,name_or_xmlnode,None)

        if from_jid is not None:
            if not isinstance(from_jid,JID):
                from_jid=JID(from_jid)
            self.xmlnode.setProp("from",from_jid.as_utf8())

        if to_jid is not None:
            if not isinstance(to_jid,JID):
                to_jid=JID(to_jid)
            self.xmlnode.setProp("to",to_jid.as_utf8())

        if stanza_type:
            self.xmlnode.setProp("type",stanza_type)

        if stanza_id:
            self.xmlnode.setProp("id",stanza_id)

        if self.get_type()=="error":
            from pyxmpp.error import StanzaErrorNode
            if error:
                self._error=StanzaErrorNode(error,parent=self.xmlnode,copy=1)
            elif error_cond:
                self._error=StanzaErrorNode(error_cond,parent=self.xmlnode)
        self.stream = stream

    def __del__(self):
        if self.xmlnode:
            self.free()

    def free(self):
        """Free the node associated with this `Stanza` object."""
        if self._error:
            self._error.free_borrowed()
        self.xmlnode.unlinkNode()
        self.xmlnode.freeNode()
        self.xmlnode=None

    def copy(self):
        """Create a deep copy of the stanza.

        :returntype: `Stanza`"""
        return Stanza(self)

    def serialize(self):
        """Serialize the stanza into an UTF-8 encoded XML string.

        :return: serialized stanza.
        :returntype: `str`"""
        return self.xmlnode.serialize(encoding="utf-8")

    def get_node(self):
        """Return the XML node wrapped into `self`.

        :returntype: `libxml2.xmlNode`"""
        return self.xmlnode

    def get_from(self):
        """Get "from" attribute of the stanza.

        :return: value of the "from" attribute (sender JID) or None.
        :returntype: `JID`"""
        if self.xmlnode.hasProp("from"):
            try:
                return JID(from_utf8(self.xmlnode.prop("from")))
            except JIDError:
                raise JIDMalformedProtocolError, "Bad JID in the 'from' attribute"
        else:
            return None

    get_from_jid=get_from

    def get_to(self):
        """Get "to" attribute of the stanza.

        :return: value of the "to" attribute (recipient JID) or None.
        :returntype: `JID`"""
        if self.xmlnode.hasProp("to"):
            try:
                return JID(from_utf8(self.xmlnode.prop("to")))
            except JIDError:
                raise JIDMalformedProtocolError, "Bad JID in the 'to' attribute"
        else:
            return None

    get_to_jid=get_to

    def get_type(self):
        """Get "type" attribute of the stanza.

        :return: value of the "type" attribute (stanza type) or None.
        :returntype: `unicode`"""
        if self.xmlnode.hasProp("type"):
            return from_utf8(self.xmlnode.prop("type"))
        else:
            return None

    get_stanza_type=get_type

    def get_id(self):
        """Get "id" attribute of the stanza.

        :return: value of the "id" attribute (stanza identifier) or None.
        :returntype: `unicode`"""
        if self.xmlnode.hasProp("id"):
            return from_utf8(self.xmlnode.prop("id"))
        else:
            return None

    get_stanza_id=get_id

    def get_error(self):
        """Get stanza error information.

        :return: object describing the error.
        :returntype: `pyxmpp.error.StanzaErrorNode`"""
        if self._error:
            return self._error
        n=self.xpath_eval(u"ns:error")
        if not n:
            raise ProtocolError, (None, "This stanza contains no error: %r" % (self.serialize(),))
        from pyxmpp.error import StanzaErrorNode
        self._error=StanzaErrorNode(n[0],copy=0)
        return self._error

    def set_from(self,from_jid):
        """Set "from" attribute of the stanza.

        :Parameters:
            - `from_jid`: new value of the "from" attribute (sender JID).
        :Types:
            - `from_jid`: `JID`"""
        if from_jid:
            return self.xmlnode.setProp("from", JID(from_jid).as_utf8())
        else:
            return self.xmlnode.unsetProp("from")

    def set_to(self,to_jid):
        """Set "to" attribute of the stanza.

        :Parameters:
            - `to_jid`: new value of the "to" attribute (recipient JID).
        :Types:
            - `to_jid`: `JID`"""
        if to_jid:
            return self.xmlnode.setProp("to", JID(to_jid).as_utf8())
        else:
            return self.xmlnode.unsetProp("to")

    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")

    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")

    def set_content(self,content):
        """Set stanza content to an XML node.

        :Parameters:
            - `content`: XML node to be included in the stanza.
        :Types:
            - `content`: `libxml2.xmlNode` or unicode, or UTF-8 `str`
        """
        while self.xmlnode.children:
            self.xmlnode.children.unlinkNode()
        if hasattr(content,"as_xml"):
            content.as_xml(parent=self.xmlnode,doc=common_doc)
        elif isinstance(content,libxml2.xmlNode):
            self.xmlnode.addChild(content.docCopyNode(common_doc,1))
        elif isinstance(content,unicode):
            self.xmlnode.setContent(to_utf8(content))
        else:
            self.xmlnode.setContent(content)

    def add_content(self,content):
        """Add an XML node to the stanza's payload.

        :Parameters:
            - `content`: XML node to be added to the payload.
        :Types:
            - `content`: `libxml2.xmlNode`, UTF-8 `str` or unicode, or
               an object with "as_xml()" method.
        """
        if hasattr(content, "as_xml"):
            content.as_xml(parent = self.xmlnode, doc = common_doc)
        elif isinstance(content,libxml2.xmlNode):
            self.xmlnode.addChild(content.docCopyNode(common_doc,1))
        elif isinstance(content,unicode):
            self.xmlnode.addContent(to_utf8(content))
        else:
            self.xmlnode.addContent(content)

    def set_new_content(self,ns_uri,name):
        """Set stanza payload to a new XML element.

        :Parameters:
            - `ns_uri`: XML namespace URI of the element.
            - `name`: element name.
        :Types:
            - `ns_uri`: `str`
            - `name`: `str` or `unicode`
        """
        while self.xmlnode.children:
            self.xmlnode.children.unlinkNode()
        return self.add_new_content(ns_uri,name)

    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

    def xpath_eval(self,expr,namespaces=None):
        """Evaluate an XPath expression on the stanza XML node.

        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`: XPath expression.
            - `namespaces`: mapping from namespace prefixes to URIs.
        :Types:
            - `expr`: `unicode`
            - `namespaces`: `dict` or other mapping
        """
        ctxt = common_doc.xpathNewContext()
        ctxt.setContextNode(self.xmlnode)
        ctxt.xpathRegisterNs("ns",COMMON_NS)
        if namespaces:
            for prefix,uri in namespaces.items():
                ctxt.xpathRegisterNs(unicode(prefix),uri)
        ret=ctxt.xpathEval(unicode(expr))
        ctxt.xpathFreeContext()
        return ret

    def __eq__(self,other):
        if not isinstance(other,Stanza):
            return False
        return self.xmlnode.serialize()==other.xmlnode.serialize()

    def __ne__(self,other):
        if not isinstance(other,Stanza):
            return True
        return self.xmlnode.serialize()!=other.xmlnode.serialize() class StreamErrorNode(ErrorNode):
    """Stream error element."""
    def __init__(self,xmlnode_or_cond,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.
            - `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`
            - `copy`: `bool`
            - `parent`: `libxml2.xmlNode`"""
        if type(xmlnode_or_cond) is str:
            xmlnode_or_cond = xmlnode_or_cond.decode("utf-8")
        if type(xmlnode_or_cond) is unicode:
            if not stream_errors.has_key(xmlnode_or_cond):
                raise ValueError, "Bad error condition"
        ErrorNode.__init__(self,xmlnode_or_cond,STREAM_ERROR_NS,copy=copy,parent=parent)

    def get_message(self):
        """Get the message for the error.

        :return: the error message.
        :returntype: `unicode`"""
        cond=self.get_condition()
        if not cond:
            self.upgrade()
            cond=self.get_condition()
            if not cond:
                return None
        cond=cond.name
        if not stream_errors.has_key(cond):
            return None
        return stream_errors[cond][0] class Iq(Stanza):
    """Wraper object for <iq /> stanzas."""
    stanza_type="iq"
    def __init__(self, xmlnode = None, from_jid = None, to_jid = None, stanza_type = None,
            stanza_id = None, error = None, error_cond=None, stream = None):
        """Initialize an `Iq` object.

        :Parameters:
            - `xmlnode`: XML node to_jid be wrapped into the `Iq` object
              or other Iq 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.
            - `error_cond`: error condition name. Ignored if `stanza_type` is not "error".
        :Types:
            - `xmlnode`: `unicode` or `libxml2.xmlNode` or `Iq`
            - `from_jid`: `JID`
            - `to_jid`: `JID`
            - `stanza_type`: `unicode`
            - `stanza_id`: `unicode`
            - `error_cond`: `unicode`"""
        self.xmlnode=None
        if isinstance(xmlnode,Iq):
            pass
        elif isinstance(xmlnode,Stanza):
            raise TypeError,"Couldn't make Iq from other Stanza"
        elif isinstance(xmlnode,libxml2.xmlNode):
            pass
        elif xmlnode is not None:
            raise TypeError,"Couldn't make Iq from %r" % (type(xmlnode),)
        elif not stanza_type:
            raise ValueError, "type is required for Iq"
        else:
            if not stanza_id and stanza_type in ("get", "set"):
                stanza_id=gen_id()

        if not xmlnode and stanza_type not in ("get","set","result","error"):
            raise ValueError, "Invalid Iq type: %r" % (stanza_type,)

        if xmlnode is None:
            xmlnode="iq"

        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)

    def copy(self):
        """Create a deep copy of the iq stanza.

        :returntype: `Iq`"""
        return Iq(self)

    def make_error_response(self,cond):
        """Create error response for the a "get" or "set" iq stanza.

        :Parameters:
            - `cond`: error condition name, as defined in XMPP specification.

        :return: new `Iq` object with the same "id" as self, "from" and "to"
            attributes swapped, type="error" and containing <error /> element
            plus payload of `self`.
        :returntype: `Iq`"""

        if self.get_type() in ("result", "error"):
            raise ValueError, "Errors may not be generated for 'result' and 'error' iq"

        iq=Iq(stanza_type="error",from_jid=self.get_to(),to_jid=self.get_from(),
            stanza_id=self.get_id(),error_cond=cond)
        n=self.get_query()
        if n:
            n=n.copyNode(1)
            iq.xmlnode.children.addPrevSibling(n)
        return iq

    def make_result_response(self):
        """Create result response for the a "get" or "set" iq stanza.

        :return: new `Iq` object with the same "id" as self, "from" and "to"
            attributes replaced and type="result".
        :returntype: `Iq`"""

        if self.get_type() not in ("set","get"):
            raise ValueError, "Results may only be generated for 'set' or 'get' iq"

        iq=Iq(stanza_type="result", from_jid=self.get_to(),
                to_jid=self.get_from(), stanza_id=self.get_id())

        return iq

    def new_query(self,ns_uri,name="query"):
        """Create new payload element for the stanza.

        :Parameters:
            - `ns_uri`: namespace URI of the element.
            - `name`: element name.
        :Types:
            - `ns_uri`: `str`
            - `name`: `unicode`

        :return: the new payload node.
        :returntype: `libxml2.xmlNode`"""
        return self.set_new_content(ns_uri,name)

    def get_query(self):
        """Get the payload element of the stanza.

        :return: the payload element or None if there is no payload.
        :returntype: `libxml2.xmlNode`"""
        c = self.xmlnode.children
        while c:
            try:
                if c.ns():
                    return c
            except libxml2.treeError:
                pass
            c = c.next
        return None

    def get_query_ns(self):
        """Get a namespace of the stanza payload.

        :return: XML namespace URI of the payload or None if there is no
            payload.
        :returntype: `str`"""
        q=self.get_query()
        if q:
            return get_node_ns_uri(q)
        else:
            return None class Presence(Stanza):
    """Wraper object for <presence /> stanzas."""
    stanza_type="presence"
    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)))

    def copy(self):
        """Create a deep copy of the presence stanza.

        :returntype: `Presence`"""
        return Presence(self)

    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))

    def get_status(self):
        """Get presence status description.

        :return: value of stanza's <status/> field.
        :returntype: `unicode`"""
        n=self.xpath_eval("ns:status")
        if n:
            return from_utf8(n[0].getContent())
        else:
            return None

    def get_show(self):
        """Get presence "show" field.

        :return: value of stanza's <show/> field.
        :returntype: `unicode`"""
        n=self.xpath_eval("ns:show")
        if n:
            return from_utf8(n[0].getContent())
        else:
            return None

    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))

    def get_priority(self):
        """Get presence priority.

        :return: value of stanza's priority. 0 if the stanza doesn't contain
            <priority/> element.
        :returntype: `int`"""
        n=self.xpath_eval("ns:priority")
        if not n:
            return 0
        try:
            prio=int(n[0].getContent())
        except ValueError:
            return 0
        return prio

    def set_priority(self,priority):
        """Change presence priority.

        :Parameters:
            - `priority`: new presence priority.
        :Types:
            - `priority`: `int`"""
        n=self.xpath_eval("ns:priority")
        if not priority:
            if n:
                n[0].unlinkNode()
                n[0].freeNode()
            else:
                return
        priority=int(priority)
        if priority<-128 or priority>127:
            raise ValueError, "Bad priority value"
        priority=str(priority)
        if n:
            n[0].setContent(priority)
        else:
            self.xmlnode.newTextChild(common_ns,"priority",priority)

    def make_accept_response(self):
        """Create "accept" response for the "subscribe"/"subscribed"/"unsubscribe"/"unsubscribed"
        presence stanza.

        :return: new stanza.
        :returntype: `Presence`"""

        if self.get_type() not in ("subscribe","subscribed","unsubscribe","unsubscribed"):
            raise ValueError, ("Results may only be generated for 'subscribe',"
                "'subscribed','unsubscribe' or 'unsubscribed' presence")

        pr=Presence(stanza_type=accept_responses[self.get_type()],
            from_jid=self.get_to(),to_jid=self.get_from(),stanza_id=self.get_id())
        return pr

    def make_deny_response(self):
        """Create "deny" response for the "subscribe"/"subscribed"/"unsubscribe"/"unsubscribed"
        presence stanza.

        :return: new presence stanza.
        :returntype: `Presence`"""
        if self.get_type() not in ("subscribe","subscribed","unsubscribe","unsubscribed"):
            raise ValueError, ("Results may only be generated for 'subscribe',"
                "'subscribed','unsubscribe' or 'unsubscribed' presence")

        pr=Presence(stanza_type=deny_responses[self.get_type()],
            from_jid=self.get_to(),to_jid=self.get_from(),stanza_id=self.get_id())
        return pr

    def make_error_response(self,cond):
        """Create error response for the any non-error presence stanza.

        :Parameters:
            - `cond`: error condition name, as defined in XMPP specification.
        :Types:
            - `cond`: `unicode`

        :return: new presence stanza.
        :returntype: `Presence`"""

        if self.get_type() == "error":
            raise ValueError, "Errors may not be generated in response to errors"

        p=Presence(stanza_type="error",from_jid=self.get_to(),to_jid=self.get_from(),
            stanza_id=self.get_id(),error_cond=cond)

        if self.xmlnode.children:
            n=self.xmlnode.children
            while n:
                p.xmlnode.children.addPrevSibling(n.copyNode(1))
                n=n.next
        return p class Message(Stanza):
    """Wraper object for <message /> stanzas."""
    stanza_type="message"
    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))

    def get_subject(self):
        """Get the message subject.

        :return: the message subject or `None` if there is no subject.
        :returntype: `unicode`"""
        n=self.xpath_eval("ns:subject")
        if n:
            return from_utf8(n[0].getContent())
        else:
            return None

    def get_thread(self):
        """Get the thread-id subject.

        :return: the thread-id or `None` if there is no thread-id.
        :returntype: `unicode`"""
        n=self.xpath_eval("ns:thread")
        if n:
            return from_utf8(n[0].getContent())
        else:
            return None

    def copy(self):
        """Create a deep copy of the message stanza.

        :returntype: `Message`"""
        return Message(self)

    def get_body(self):
        """Get the body of the message.

        :return: the body of the message or `None` if there is no body.
        :returntype: `unicode`"""
        n=self.xpath_eval("ns:body")
        if n:
            return from_utf8(n[0].getContent())
        else:
            return None

    def make_error_response(self,cond):
        """Create error response for any non-error message stanza.

        :Parameters:
            - `cond`: error condition name, as defined in XMPP specification.

        :return: new message stanza with the same "id" as self, "from" and
            "to" attributes swapped, type="error" and containing <error />
            element plus payload of `self`.
        :returntype: `unicode`"""

        if self.get_type() == "error":
            raise ValueError, "Errors may not be generated in response to errors"

        m=Message(stanza_type="error",from_jid=self.get_to(),to_jid=self.get_from(),
            stanza_id=self.get_id(),error_cond=cond)

        if self.xmlnode.children:
            n=self.xmlnode.children
            while n:
                m.xmlnode.children.addPrevSibling(n.copyNode(1))
                n=n.next
        return m class JID(object):
    """JID.

    :Ivariables:
        - `node`: node part of the JID
        - `domain`: domain part of the JID
        - `resource`: resource part of the JID

    JID objects are immutable. They are also cached for better performance.
    """
    cache=weakref.WeakValueDictionary()
    __slots__=["node","domain","resource","__weakref__"]
    def __new__(cls,node_or_jid=None,domain=None,resource=None,check=True):
        """Create a new JID object or take one from the cache.

        :Parameters:
            - `node_or_jid`: node part of the JID, JID object to copy or
              Unicode representation of the JID.
            - `domain`: domain part of the JID
            - `resource`: resource part of the JID
            - `check`: if `False` then JID is not checked for specifiaction
              compliance.
        """

        if isinstance(node_or_jid,JID):
            return node_or_jid

        if domain is None and resource is None:
            obj=cls.cache.get(node_or_jid)
            if obj:
                return obj
        else:
            obj=None
        if obj is None:
            obj=object.__new__(cls)

        if node_or_jid:
            node_or_jid = unicode(node_or_jid)
        if (node_or_jid and
                ((u"@" in node_or_jid) or (u"/" in node_or_jid))):
            obj.__from_unicode(node_or_jid)
            cls.cache[node_or_jid]=obj
        else:
            if domain is None and resource is None:
                if node_or_jid is None:
                    raise JIDError,"At least domain must be given"
                domain=node_or_jid
                node_or_jid=None
            if check:
                obj.__set_node(node_or_jid)
                obj.__set_domain(domain)
                obj.__set_resource(resource)
            else:
                object.__setattr__(obj,"node",node_or_jid)
                object.__setattr__(obj,"domain",domain)
                object.__setattr__(obj,"resource",resource)
        return obj

    def __setattr__(self,name,value):
        raise RuntimeError,"JID objects are immutable!"

    def __from_unicode(self,s,check=True):
        """Initialize JID object from Unicode string.

        :Parameters:
            - `s`: the JID string
            - `check`: when `False` then the JID is not checked for
              specification compliance."""
        s1=s.split(u"/",1)
        s2=s1[0].split(u"@",1)
        if len(s2)==2:
            if check:
                self.__set_node(s2[0])
                self.__set_domain(s2[1])
            else:
                object.__setattr__(self,"node",s2[0])
                object.__setattr__(self,"domain",s2[1])
        else:
            if check:
                self.__set_domain(s2[0])
            else:
                object.__setattr__(self,"domain",s2[0])
            object.__setattr__(self,"node",None)
        if len(s1)==2:
            if check:
                self.__set_resource(s1[1])
            else:
                object.__setattr__(self,"resource",s1[1])
        else:
            object.__setattr__(self,"resource",None)
        if not self.domain:
            raise JIDError,"Domain is required in JID."

    def __set_node(self,s):
        """Initialize `self.node`

        :Parameters:
            - `s`: Node part of the JID
        :Types:
            - `s`: unicode

        :raise JIDError: if the node name is too long.
        :raise pyxmpp.xmppstringprep.StringprepError: if the
            node name fails Nodeprep preparation."""
        if s:
            s = unicode(s)
            s=nodeprep.prepare(s)
            if len(s.encode("utf-8"))>1023:
                raise JIDError,"Node name too long"
        else:
            s=None
        object.__setattr__(self,"node",s)

    def __set_domain(self,s):
        """Initialize `self.domain`

        :Parameters:
            - `s`: Unicode or UTF-8 domain part of the JID

        :raise JIDError: if the domain name is too long."""

        if s is None:
            raise JIDError,"Domain must be given"
        if s:
            s = unicode(s)
        s=idna.nameprep(s)
        if len(s.encode("utf-8"))>1023:
            raise JIDError,"Domain name too long"
        object.__setattr__(self,"domain",s)

    def __set_resource(self,s):
        """Initialize `self.resource`

        :Parameters:
            - `s`: Unicode or UTF-8 resource part of the JID

        :raise JIDError: if the resource name is too long.
        :raise pyxmpp.xmppstringprep.StringprepError: if the
            node name fails Resourceprep preparation."""
        if s:
            s = unicode(s)
            s=resourceprep.prepare(s)
            if len(s.encode("utf-8"))>1023:
                raise JIDError,"Resource name too long"
        else:
            s=None
        object.__setattr__(self,"resource",s)

    def __str__(self):
        warnings.warn("JIDs should not be used as strings", DeprecationWarning, stacklevel=2)
        return self.as_utf8()

    def __unicode__(self):
        return self.as_unicode()

    def __repr__(self):
        return "<JID: %r>" % (self.as_unicode())

    def as_utf8(self):
        """UTF-8 encoded JID representation.

        :return: UTF-8 encoded JID."""
        return self.as_unicode().encode("utf-8")

    def as_string(self):
        """UTF-8 encoded JID representation.

        *Deprecated* Always use Unicode objects, or `as_utf8` if you really want.

        :return: UTF-8 encoded JID."""
        warnings.warn("JID.as_string() is deprecated. Use unicode() or `as_utf8` instead.",
                 DeprecationWarning, stacklevel=1)
        return self.as_utf8()

    def as_unicode(self):
        """Unicode string JID representation.

        :return: JID as Unicode string."""
        r=self.domain
        if self.node:
            r=self.node+u'@'+r
        if self.resource:
            r=r+u'/'+self.resource
        if not JID.cache.has_key(r):
            JID.cache[r]=self
        return r

    def bare(self):
        """Make bare JID made by removing resource from current `self`.

        :return: new JID object without resource part."""
        return JID(self.node,self.domain,check=False)

    def __eq__(self,other):
        if other is None:
            return False
        elif type(other) in (str, unicode):
            try:
                other=JID(other)
            except:
                return False
        elif not isinstance(other,JID):
            return False

        return (self.node==other.node
            and are_domains_equal(self.domain,other.domain)
            and self.resource==other.resource)

    def __ne__(self,other):
        return not self.__eq__(other)

    def __cmp__(self,other):
        a=self.as_unicode()
        return cmp(a,other)

    def __hash__(self):
        return hash(self.node)^hash(self.domain)^hash(self.resource) def set_default_address_family(family):
def shuffle_srv(records):
def reorder_srv(records):
def resolve_srv(domain, service, proto="tcp"):
def getaddrinfo(host, port, family = None,
                socktype = socket.SOCK_STREAM, proto = 0, allow_cname = True): class StanzaProcessor:
    """Universal stanza handler/router class.

    Provides facilities to set up custom handlers for various types of stanzas.

    :Ivariables:
        - `lock`: lock object used to synchronize access to the
          `StanzaProcessor` object.
        - `me`: local JID.
        - `peer`: remote stream endpoint JID.
        - `process_all_stanzas`: when `True` then all stanzas received are
          considered local.
        - `initiator`: `True` if local stream endpoint is the initiating entity.
    """
    def __init__(self):
        """Initialize a `StanzaProcessor` object."""
        self.me=None
        self.peer=None
        self.initiator=None
        self.peer_authenticated=False
        self.process_all_stanzas=True
        self._iq_response_handlers=ExpiringDictionary()
        self._iq_get_handlers={}
        self._iq_set_handlers={}
        self._message_handlers=[]
        self._presence_handlers=[]
        self.__logger=logging.getLogger("pyxmpp.Stream")
        self.lock=threading.RLock()

    def process_response(self, response):
        """Examines out the response returned by a stanza handler and sends all
        stanzas provided.

        :Returns:
           - `True`: if `response` is `Stanza`, iterable or `True` (meaning the stanza was processed).
           - `False`: when `response` is `False` or `None`
        :returntype: `bool`
        """

        if response is None or response is False:
            return False

        if isinstance(response, Stanza):
            self.send(response)
            return True

        try:
            response = iter(response)
        except TypeError:
            return bool(response)

        for stanza in response:
            if isinstance(stanza, Stanza):
                self.send(stanza)
        return True

    def process_iq(self, stanza):
        """Process IQ stanza received.

        :Parameters:
            - `stanza`: the stanza received

        If a matching handler is available pass the stanza to it.
        Otherwise ignore it if it is "error" or "result" stanza
        or return "feature-not-implemented" error."""

        sid=stanza.get_id()
        fr=stanza.get_from()

        typ=stanza.get_type()
        if typ in ("result","error"):
            if fr:
                ufr=fr.as_unicode()
            else:
                ufr=None
            res_handler = err_handler = None
            try:
                res_handler, err_handler = self._iq_response_handlers.pop((sid,ufr))
            except KeyError:
                if ( (fr==self.peer or fr==self.me or fr==self.me.bare()) ):
                    try:
                        res_handler, err_handler = self._iq_response_handlers.pop((sid,None))
                    except KeyError:
                        pass
                if None is res_handler is err_handler:
                    return False
            if typ=="result":
                response = res_handler(stanza)
            else:
                response = err_handler(stanza)
            self.process_response(response)
            return True

        q=stanza.get_query()
        if not q:
            raise BadRequestProtocolError, "Stanza with no child element"
        el=q.name
        ns=q.ns().getContent()

        if typ=="get":
            if self._iq_get_handlers.has_key((el,ns)):
                response = self._iq_get_handlers[(el,ns)](stanza)
                self.process_response(response)
                return True
            else:
                raise FeatureNotImplementedProtocolError, "Not implemented"
        elif typ=="set":
            if self._iq_set_handlers.has_key((el,ns)):
                response = self._iq_set_handlers[(el,ns)](stanza)
                self.process_response(response)
                return True
            else:
                raise FeatureNotImplementedProtocolError, "Not implemented"
        else:
            raise BadRequestProtocolError, "Unknown IQ stanza type"

    def __try_handlers(self,handler_list,typ,stanza):
        """ Search the handler list for handlers matching
        given stanza type and payload namespace. Run the
        handlers found ordering them by priority until
        the first one which returns `True`.

        :Parameters:
            - `handler_list`: list of available handlers
            - `typ`: stanza type (value of its "type" attribute)
            - `stanza`: the stanza to handle

        :return: result of the last handler or `False` if no
            handler was found."""
        namespaces=[]
        if stanza.xmlnode.children:
            c=stanza.xmlnode.children
            while c:
                try:
                    ns=c.ns()
                except libxml2.treeError:
                    ns=None
                if ns is None:
                    c=c.next
                    continue
                ns_uri=ns.getContent()
                if ns_uri not in namespaces:
                    namespaces.append(ns_uri)
                c=c.next
        for handler_entry in handler_list:
            t=handler_entry[1]
            ns=handler_entry[2]
            handler=handler_entry[3]
            if t!=typ:
                continue
            if ns is not None and ns not in namespaces:
                continue
            response = handler(stanza)
            if self.process_response(response):
                return True
        return False

    def process_message(self,stanza):
        """Process message stanza.

        Pass it to a handler of the stanza's type and payload namespace.
        If no handler for the actual stanza type succeeds then hadlers
        for type "normal" are used.

        :Parameters:
            - `stanza`: message stanza to be handled
        """

        if not self.initiator and not self.peer_authenticated:
            self.__logger.debug("Ignoring message - peer not authenticated yet")
            return True

        typ=stanza.get_type()
        if self.__try_handlers(self._message_handlers,typ,stanza):
            return True
        if typ!="error":
            return self.__try_handlers(self._message_handlers,"normal",stanza)
        return False

    def process_presence(self,stanza):
        """Process presence stanza.

        Pass it to a handler of the stanza's type and payload namespace.

        :Parameters:
            - `stanza`: presence stanza to be handled
        """

        if not self.initiator and not self.peer_authenticated:
            self.__logger.debug("Ignoring presence - peer not authenticated yet")
            return True

        typ=stanza.get_type()
        if not typ:
            typ="available"
        return self.__try_handlers(self._presence_handlers,typ,stanza)

    def route_stanza(self,stanza):
        """Process stanza not addressed to us.

        Return "recipient-unavailable" return if it is not
        "error" nor "result" stanza.

        This method should be overriden in derived classes if they
        are supposed to handle stanzas not addressed directly to local
        stream endpoint.

        :Parameters:
            - `stanza`: presence stanza to be processed
        """
        if stanza.get_type() not in ("error","result"):
            r = stanza.make_error_response("recipient-unavailable")
            self.send(r)
        return True

    def process_stanza(self,stanza):
        """Process stanza received from the stream.

        First "fix" the stanza with `self.fix_in_stanza()`,
        then pass it to `self.route_stanza()` if it is not directed
        to `self.me` and `self.process_all_stanzas` is not True. Otherwise
        stanza is passwd to `self.process_iq()`, `self.process_message()`
        or `self.process_presence()` appropriately.

        :Parameters:
            - `stanza`: the stanza received.

        :returns: `True` when stanza was handled
        """

        self.fix_in_stanza(stanza)
        to=stanza.get_to()

        if to and to.node == None and (not self.me
                                        or to.domain == self.me.domain):
            # workaround for OpenFire bug
            # http://community.igniterealtime.org/thread/35966
            to = None

        if not self.process_all_stanzas and to and to!=self.me and to.bare()!=self.me.bare():
            return self.route_stanza(stanza)

        try:
            if stanza.stanza_type=="iq":
                if self.process_iq(stanza):
                    return True
            elif stanza.stanza_type=="message":
                if self.process_message(stanza):
                    return True
            elif stanza.stanza_type=="presence":
                if self.process_presence(stanza):
                    return True
        except ProtocolError, e:
            typ = stanza.get_type()
            if typ != 'error' and (typ != 'result' or stanza.stanza_type != 'iq'):
                r = stanza.make_error_response(e.xmpp_name)
                self.send(r)
                e.log_reported()
            else:
                e.log_ignored()

        self.__logger.debug("Unhandled %r stanza: %r" % (stanza.stanza_type,stanza.serialize()))
        return False

    def check_to(self,to):
        """Check "to" attribute of received stream header.

        :return: `to` if it is equal to `self.me`, None otherwise.

        Should be overriden in derived classes which require other logic
        for handling that attribute."""
        if to!=self.me:
            return None
        return to

    def set_response_handlers(self,iq,res_handler,err_handler,timeout_handler=None,timeout=300):
        """Set response handler for an IQ "get" or "set" stanza.

        This should be called before the stanza is sent.

        :Parameters:
            - `iq`: an IQ stanza
            - `res_handler`: result handler for the stanza. Will be called
              when matching <iq type="result"/> is received. Its only
              argument will be the stanza received. The handler may return
              a stanza or list of stanzas which should be sent in response.
            - `err_handler`: error handler for the stanza. Will be called
              when matching <iq type="error"/> is received. Its only
              argument will be the stanza received. The handler may return
              a stanza or list of stanzas which should be sent in response
              but this feature should rather not be used (it is better not to
              respond to 'error' stanzas).
            - `timeout_handler`: timeout handler for the stanza. Will be called
              when no matching <iq type="result"/> or <iq type="error"/> is
              received in next `timeout` seconds. The handler should accept
              two arguments and ignore them.
            - `timeout`: timeout value for the stanza. After that time if no
              matching <iq type="result"/> nor <iq type="error"/> stanza is
              received, then timeout_handler (if given) will be called.
        """
        self.lock.acquire()
        try:
            self._set_response_handlers(iq,res_handler,err_handler,timeout_handler,timeout)
        finally:
            self.lock.release()

    def _set_response_handlers(self,iq,res_handler,err_handler,timeout_handler=None,timeout=300):
        """Same as `Stream.set_response_handlers` but assume `self.lock` is acquired."""
        self.fix_out_stanza(iq)
        to=iq.get_to()
        if to:
            to=to.as_unicode()
        if timeout_handler:
            self._iq_response_handlers.set_item((iq.get_id(),to),
                    (res_handler,err_handler),
                    timeout,timeout_handler)
        else:
            self._iq_response_handlers.set_item((iq.get_id(),to),
                    (res_handler,err_handler),timeout)

    def set_iq_get_handler(self,element,namespace,handler):
        """Set <iq type="get"/> handler.

        :Parameters:
            - `element`: payload element name
            - `namespace`: payload element namespace URI
            - `handler`: function to be called when a stanza
              with defined element is received. Its only argument
              will be the stanza received. The handler may return a stanza or
              list of stanzas which should be sent in response.

        Only one handler may be defined per one namespaced element.
        If a handler for the element was already set it will be lost
        after calling this method.
        """
        self.lock.acquire()
        try:
            self._iq_get_handlers[(element,namespace)]=handler
        finally:
            self.lock.release()

    def unset_iq_get_handler(self,element,namespace):
        """Remove <iq type="get"/> handler.

        :Parameters:
            - `element`: payload element name
            - `namespace`: payload element namespace URI
        """
        self.lock.acquire()
        try:
            if self._iq_get_handlers.has_key((element,namespace)):
                del self._iq_get_handlers[(element,namespace)]
        finally:
            self.lock.release()

    def set_iq_set_handler(self,element,namespace,handler):
        """Set <iq type="set"/> handler.

        :Parameters:
            - `element`: payload element name
            - `namespace`: payload element namespace URI
            - `handler`: function to be called when a stanza
              with defined element is received. Its only argument
              will be the stanza received. The handler may return a stanza or
              list of stanzas which should be sent in response.


        Only one handler may be defined per one namespaced element.
        If a handler for the element was already set it will be lost
        after calling this method."""
        self.lock.acquire()
        try:
            self._iq_set_handlers[(element,namespace)]=handler
        finally:
            self.lock.release()

    def unset_iq_set_handler(self,element,namespace):
        """Remove <iq type="set"/> handler.

        :Parameters:
            - `element`: payload element name.
            - `namespace`: payload element namespace URI."""
        self.lock.acquire()
        try:
            if self._iq_set_handlers.has_key((element,namespace)):
                del self._iq_set_handlers[(element,namespace)]
        finally:
            self.lock.release()

    def __add_handler(self,handler_list,typ,namespace,priority,handler):
        """Add a handler function to a prioritized handler list.

        :Parameters:
            - `handler_list`: a handler list.
            - `typ`: stanza type.
            - `namespace`: stanza payload namespace.
            - `priority`: handler priority. Must be >=0 and <=100. Handlers
              with lower priority list will be tried first."""
        if priority<0 or priority>100:
            raise ValueError,"Bad handler priority (must be in 0:100)"
        handler_list.append((priority,typ,namespace,handler))
        handler_list.sort()

    def set_message_handler(self, typ, handler, namespace=None, priority=100):
        """Set a handler for <message/> stanzas.

        :Parameters:
            - `typ`: message type. `None` will be treated the same as "normal",
              and will be the default for unknown types (those that have no
              handler associated).
            - `namespace`: payload namespace. If `None` that message with any
              payload (or even with no payload) will match.
            - `priority`: priority value for the handler. Handlers with lower
              priority value are tried first.
            - `handler`: function to be called when a message stanza
              with defined type and payload namespace is received. Its only
              argument will be the stanza received. The handler may return a
              stanza or list of stanzas which should be sent in response.

        Multiple <message /> handlers with the same type/namespace/priority may
        be set. Order of calling handlers with the same priority is not defined.
        Handlers will be called in priority order until one of them returns True or
        any stanza(s) to send (even empty list will do).
        """
        self.lock.acquire()
        try:
            if not typ:
                typ = "normal"
            self.__add_handler(self._message_handlers,typ,namespace,priority,handler)
        finally:
            self.lock.release()

    def set_presence_handler(self,typ,handler,namespace=None,priority=100):
        """Set a handler for <presence/> stanzas.

        :Parameters:
            - `typ`: presence type. "available" will be treated the same as `None`.
            - `namespace`: payload namespace. If `None` that presence with any
              payload (or even with no payload) will match.
            - `priority`: priority value for the handler. Handlers with lower
              priority value are tried first.
            - `handler`: function to be called when a presence stanza
              with defined type and payload namespace is received. Its only
              argument will be the stanza received. The handler may return a
              stanza or list of stanzas which should be sent in response.

        Multiple <presence /> handlers with the same type/namespace/priority may
        be set. Order of calling handlers with the same priority is not defined.
        Handlers will be called in priority order until one of them returns
        True or any stanza(s) to send (even empty list will do).
        """
        self.lock.acquire()
        try:
            if not typ:
                typ="available"
            self.__add_handler(self._presence_handlers,typ,namespace,priority,handler)
        finally:
            self.lock.release()

    def fix_in_stanza(self,stanza):
        """Modify incoming stanza before processing it.

        This implementation does nothig. It should be overriden in derived
        classes if needed."""
        pass

    def fix_out_stanza(self,stanza):
        """Modify outgoing stanza before sending into the stream.

        This implementation does nothig. It should be overriden in derived
        classes if needed."""
        pass


    def send(self,stanza):
        """Send a stanza somwhere. This one does nothing. Should be overriden
        in derived classes.

        :Parameters:
            - `stanza`: the stanza to send.
        :Types:
            - `stanza`: `pyxmpp.stanza.Stanza`"""
        raise NotImplementedError,"This method must be overriden in derived classes.""" class StreamError(Error):
    """Base class for all stream errors."""
    pass class StreamEncryptionRequired(StreamError):
    """Exception raised when stream encryption is requested, but not used."""
    pass class HostMismatch(StreamError):
    """Exception raised when the connected host name is other then requested."""
    pass class ProtocolError(Error):
    """Raised when there is something wrong with a stanza processed.

    When not processed earlier by an application, the exception will be catched
    by the stanza dispatcher to return XMPP error to the stanza sender, when
    allowed.

    ProtocolErrors handled internally by PyXMPP will be logged via the logging
    interface. Errors reported to the sender will be logged using
    "pyxmpp.ProtocolError.reported" channel and the ignored errors using
    "pyxmpp.ProtocolError.ignored" channel. Both with the "debug" level.
    
    :Ivariables:
        - `xmpp_name` -- XMPP error name which should be reported.
        - `message` -- the error message."""

    logger_reported = logging.getLogger("pyxmpp.ProtocolError.reported")
    logger_ignored = logging.getLogger("pyxmpp.ProtocolError.ignored")

    def __init__(self, xmpp_name, message):
        self.args = (xmpp_name, message)
    @property
    def xmpp_name(self):
        return self.args[0]
    @property
    def message(self):
        return self.args[1]
    def log_reported(self):
        self.logger_reported.debug(u"Protocol error detected: %s", self.message)
    def log_ignored(self):
        self.logger_ignored.debug(u"Protocol error detected: %s", self.message)
    def __unicode__(self):
        return str(self.args[1])
    def __repr__(self):
        return "<ProtocolError %r %r>" % (self.xmpp_name, self.message) class DNSError(FatalStreamError):
    """Raised when no host name could be resolved for the target."""
    pass class UnexpectedCNAMEError(DNSError):
    """Raised when CNAME record was found when A or AAAA was expected."""
    pass class FatalStreamError(StreamError):
    """Base class for all fatal Stream exceptions.

    When `FatalStreamError` is raised the stream is no longer usable."""
    pass class StreamParseError(FatalStreamError):
    """Raised when invalid XML is received in an XMPP stream."""
    pass class StreamAuthenticationError(FatalStreamError):
    """Raised when stream authentication fails."""
    pass
import libxml2
import socket
import os
import time
import random
import threading
import errno
import logging
        import select
from pyxmpp import xmlextra
from pyxmpp.expdict import ExpiringDictionary
from pyxmpp.utils import to_utf8, from_utf8
from pyxmpp.stanza import Stanza
from pyxmpp.error import StreamErrorNode
from pyxmpp.iq import Iq
from pyxmpp.presence import Presence
from pyxmpp.message import Message
from pyxmpp.jid import JID
from pyxmpp import resolver
from pyxmpp.stanzaprocessor import StanzaProcessor
from pyxmpp.exceptions import StreamError, StreamEncryptionRequired
from pyxmpp.exceptions import HostMismatch, ProtocolError
from pyxmpp.exceptions import DNSError, UnexpectedCNAMEError
from pyxmpp.exceptions import FatalStreamError, StreamParseError, StreamAuthenticationError
        connections."""
        self.doc_in=None
        self.doc_out=None
        self.socket=None
        self._reader=None
        self.addr=None
        self.default_ns=None
        self.extra_ns={}
        self.stream_ns=None
        self._reader=None
        self.ioreader=None
        self.me=None
        self.peer=None
        self.skip=False
        self.stream_id=None
        self._iq_response_handlers=ExpiringDictionary()
        self._iq_get_handlers={}
        self._iq_set_handlers={}
        self._message_handlers=[]
        self._presence_handlers=[]
        self.eof=False
        self.initiator=None
        self.features=None
        self.authenticated=False
        self.peer_authenticated=False
        self.auth_method_used=None
        self.version=None
        self.last_keepalive=False

    def __del__(self):
        self.close()

    def _connect_socket(self,sock,to=None):
        """Initialize stream on outgoing connection.

        :Parameters:
          - `sock`: connected socket for the stream
          - `to`: name of the remote host
        """
        self.eof=0
        self.socket=sock
        if to:
            self.peer=JID(to)
        else:
            self.peer=None
        self.initiator=1
        self._send_stream_start()
        self._make_reader()

    def connect(self,addr,port,service=None,to=None):
        """Establish XMPP connection with given address.

        [initiating entity only]

        :Parameters:
            - `addr`: peer name or IP address
            - `port`: port number to connect to
            - `service`: service name (to be resolved using SRV DNS records)
            - `to`: peer name if different than `addr`
        """
        self.lock.acquire()
        try:
            return self._connect(addr,port,service,to)
        finally:
            self.lock.release()

    def _connect(self, addr, port, service = None, to = None):
        """Same as `Stream.connect` but assume `self.lock` is acquired."""
        if to is None:
            to = from_utf8(addr)
        allow_cname = True
        if service is not None:
            self.state_change("resolving srv", (addr, service))
            addrs = resolver.resolve_srv(addr, service)
            if not addrs:
                addrs = [(addr, port)]
            else:
                allow_cname = False
        else:
            addrs=[(addr, port)]
        exception = None
        for addr, port in addrs:
            if type(addr) in (str, unicode):
                self.state_change("resolving", addr)
            s=None
            while True:
                try:
                    addresses = resolver.getaddrinfo(addr, port, None,
                                socket.SOCK_STREAM, allow_cname = allow_cname)
                    break
                except UnexpectedCNAMEError, err:
                    self.__logger.warning(str(err))
                    allow_cname = True
                    continue
                except DNSError, err:
                    self.__logger.debug(str(err))
                    exception = err
                    addresses = []
                    break
            for res in addresses:
                family, socktype, proto, _unused, sockaddr = res
                try:
                    s=socket.socket(family,socktype,proto)
                    self.state_change("connecting",sockaddr)
                    s.connect(sockaddr)
                    self.state_change("connected",sockaddr)
                except socket.error, err:
                    exception = err
                    self.__logger.debug("Connect to %r failed" % (sockaddr,))
                    if s:
                        s.close()
                        s=None
                    continue
                break
            if s:
                break
        if not s:
            if exception:
                raise exception
            else:

                raise FatalStreamError,"Cannot connect"