summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sleekxmpp/basexmpp.py27
-rw-r--r--sleekxmpp/exceptions.py22
-rw-r--r--sleekxmpp/stanza/rootstanza.py28
3 files changed, 64 insertions, 13 deletions
diff --git a/sleekxmpp/basexmpp.py b/sleekxmpp/basexmpp.py
index 61aaeff8..02f775ac 100644
--- a/sleekxmpp/basexmpp.py
+++ b/sleekxmpp/basexmpp.py
@@ -13,9 +13,9 @@ import copy
import logging
import sleekxmpp
-from sleekxmpp import plugins
+from sleekxmpp import plugins, roster
+from sleekxmpp.exceptions import IqError, IqTimeout
-import sleekxmpp.roster as roster
from sleekxmpp.stanza import Message, Presence, Iq, Error, StreamError
from sleekxmpp.stanza.roster import Roster
from sleekxmpp.stanza.nick import Nick
@@ -743,6 +743,29 @@ class BaseXMPP(XMLStream):
self.event("changed_status", presence)
+ def exception(self, exception):
+ """
+ Process any uncaught exceptions, notably IqError and
+ IqTimeout exceptions.
+
+ Overrides XMLStream.exception.
+
+ Arguments:
+ exception -- An unhandled exception object.
+ """
+ if isinstance(exception, IqError):
+ iq = exception.iq
+ log.error('%s: %s' % (iq['error']['condition'],
+ iq['error']['text']))
+ log.warning('You should catch IqError exceptions')
+ elif isinstance(exception, IqTimeout):
+ iq = exception.iq
+ log.error('Request timed out: %s' % iq)
+ log.warning('You should catch IqTimeout exceptions')
+ else:
+ log.exception(exception)
+
+
# Restore the old, lowercased name for backwards compatibility.
basexmpp = BaseXMPP
diff --git a/sleekxmpp/exceptions.py b/sleekxmpp/exceptions.py
index 49d0f940..61d24f6b 100644
--- a/sleekxmpp/exceptions.py
+++ b/sleekxmpp/exceptions.py
@@ -20,9 +20,9 @@ class XMPPError(Exception):
Meant for use in SleekXMPP plugins and applications using SleekXMPP.
"""
- def __init__(self, condition='undefined-condition', text=None, etype=None,
- extension=None, extension_ns=None, extension_args=None,
- clear=True):
+ def __init__(self, condition='undefined-condition', text=None,
+ etype='cancel', extension=None, extension_ns=None,
+ extension_args=None, clear=True):
"""
Create a new XMPPError exception.
@@ -31,8 +31,10 @@ class XMPPError(Exception):
Arguments:
condition -- The XMPP defined error condition.
+ Defaults to 'undefined-condition'.
text -- Human readable text describing the error.
etype -- The XMPP error type, such as cancel or modify.
+ Defaults to 'cancel'.
extension -- Tag name of the extension's XML content.
extension_ns -- XML namespace of the extensions' XML content.
extension_args -- Content and attributes for the extension
@@ -54,7 +56,7 @@ class XMPPError(Exception):
self.extension_args = extension_args
-class IqTimeout(Exception):
+class IqTimeout(XMPPError):
"""
An exception which indicates that an IQ request response has not been
@@ -62,10 +64,13 @@ class IqTimeout(Exception):
"""
def __init__(self, iq):
- self.iq = iq
+ super(IqTimeout, self).__init__(
+ condition='remote-server-timeout',
+ etype='cancel')
+ self.iq = iq
-class IqError(Exception):
+class IqError(XMPPError):
"""
An exception raised when an Iq stanza of type 'error' is received
@@ -73,4 +78,9 @@ class IqError(Exception):
"""
def __init__(self, iq):
+ super(IqError, self).__init__(
+ condition=iq['error']['condition'],
+ text=iq['error']['text'],
+ etype=iq['error']['type'])
+
self.iq = iq
diff --git a/sleekxmpp/stanza/rootstanza.py b/sleekxmpp/stanza/rootstanza.py
index 9e1d1cfa..470a1225 100644
--- a/sleekxmpp/stanza/rootstanza.py
+++ b/sleekxmpp/stanza/rootstanza.py
@@ -10,7 +10,7 @@ import logging
import traceback
import sys
-from sleekxmpp.exceptions import XMPPError
+from sleekxmpp.exceptions import XMPPError, IqError, IqTimeout
from sleekxmpp.stanza import Error
from sleekxmpp.xmlstream import ET, StanzaBase, register_stanza_plugin
@@ -43,23 +43,41 @@ class RootStanza(StanzaBase):
Arguments:
e -- Exception object
"""
- if isinstance(e, XMPPError):
- self.reply(clear=e.clear)
+ if isinstance(e, IqError):
+ # We received an Iq error reply, but it wasn't caught
+ # locally. Using the condition/text from that error
+ # response could leak too much information, so we'll
+ # only use a generic error here.
+ self.reply()
+ self['error']['condition'] = 'undefined-condition'
+ self['error']['text'] = 'External error'
+ self['error']['type'] = 'cancel'
+ log.warning('You should catch IqError exceptions')
+ self.send()
+ elif isinstance(e, IqTimeout):
+ self.reply()
+ self['error']['condition'] = 'remote-server-timeout'
+ self['error']['type'] = 'wait'
+ log.warning('You should catch IqTimeout exceptions')
+ self.send()
+ elif isinstance(e, XMPPError):
# We raised this deliberately
+ self.reply(clear=e.clear)
self['error']['condition'] = e.condition
self['error']['text'] = e.text
+ self['error']['type'] = e.etype
if e.extension is not None:
# Extended error tag
extxml = ET.Element("{%s}%s" % (e.extension_ns, e.extension),
e.extension_args)
self['error'].append(extxml)
- self['error']['type'] = e.etype
self.send()
else:
- self.reply()
# We probably didn't raise this on purpose, so send an error stanza
+ self.reply()
self['error']['condition'] = 'undefined-condition'
self['error']['text'] = "SleekXMPP got into trouble."
+ self['error']['type'] = 'cancel'
self.send()
# log the error
log.exception('Error handling {%s}%s stanza' %