Philipp Hörist pushed to branch master at gajim / python-nbxmpp

Commits:

5 changed files:

Changes:

  • nbxmpp/protocol.py
    ... ... @@ -1084,11 +1084,27 @@ class Protocol(Node):
    1084 1084
             of the error (otherwise)
    
    1085 1085
             """
    
    1086 1086
             errtag = self.getTag('error')
    
    1087
    -        if errtag:
    
    1088
    -            for tag in errtag.getChildren():
    
    1089
    -                if tag.getName() != 'text':
    
    1090
    -                    return tag.getName()
    
    1091
    -            return errtag.getData()
    
    1087
    +        if errtag is None:
    
    1088
    +            return
    
    1089
    +        for tag in errtag.getChildren():
    
    1090
    +            if tag.getName() != 'text' and tag.getNamespace() == NS_STANZAS:
    
    1091
    +                return tag.getName()
    
    1092
    +
    
    1093
    +    def getAppError(self):
    
    1094
    +        errtag = self.getTag('error')
    
    1095
    +        if errtag is None:
    
    1096
    +            return
    
    1097
    +        for tag in errtag.getChildren():
    
    1098
    +            if tag.getName() != 'text' and tag.getNamespace() != NS_STANZAS:
    
    1099
    +                return tag.getName()
    
    1100
    +
    
    1101
    +    def getAppErrorNamespace(self):
    
    1102
    +        errtag = self.getTag('error')
    
    1103
    +        if errtag is None:
    
    1104
    +            return
    
    1105
    +        for tag in errtag.getChildren():
    
    1106
    +            if tag.getName() != 'text' and tag.getNamespace() != NS_STANZAS:
    
    1107
    +                return tag.getNamespace()
    
    1092 1108
     
    
    1093 1109
         def getErrorMsg(self):
    
    1094 1110
             """
    

  • nbxmpp/simplexml.py
    ... ... @@ -431,6 +431,14 @@ class Node:
    431 431
             except Exception:
    
    432 432
                 self.addChild(tag, attrs, payload = [str(val)])
    
    433 433
     
    
    434
    +    def getXmlLang(self):
    
    435
    +        lang = self.attrs.get('xml:lang')
    
    436
    +        if lang is not None:
    
    437
    +            return lang
    
    438
    +
    
    439
    +        if self.parent is not None:
    
    440
    +            return self.parent.getXmlLang()
    
    441
    +
    
    434 442
         def has_attr(self, key):
    
    435 443
             """
    
    436 444
             Check if node have attribute "key"
    

  • nbxmpp/structs.py
    ... ... @@ -309,11 +309,52 @@ class OMEMOBundle(namedtuple('OMEMOBundle', 'spk spk_signature ik otpks')):
    309 309
             return random.SystemRandom().choice(self.otpks)
    
    310 310
     
    
    311 311
     
    
    312
    -class CommonError(namedtuple('CommonError', 'type message jid')):
    
    312
    +class CommonError:
    
    313
    +    def __init__(self, stanza):
    
    314
    +        self._error_node = stanza.getTag('error')
    
    315
    +        self.condition = stanza.getError()
    
    316
    +        self.app_condition = stanza.getAppError()
    
    317
    +        self.type = stanza.getErrorType()
    
    318
    +        self.jid = stanza.getFrom()
    
    319
    +        self.id = stanza.getID()
    
    320
    +        self._text = {}
    
    321
    +
    
    322
    +        error = stanza.getTag('error')
    
    323
    +        if error is not None:
    
    324
    +            text_elements = error.getTags('text', namespace=NS_STANZAS)
    
    325
    +            for element in text_elements:
    
    326
    +                lang = element.getXmlLang()
    
    327
    +                text = element.getData()
    
    328
    +                self._text[lang] = text
    
    329
    +
    
    330
    +    def get_text(self, pref_lang=None):
    
    331
    +        if pref_lang is not None:
    
    332
    +            text = self._text.get(pref_lang)
    
    333
    +            if text is not None:
    
    334
    +                return text
    
    335
    +
    
    336
    +        if self._text:
    
    337
    +            text = self._text.get('en')
    
    338
    +            if text is not None:
    
    339
    +                return text
    
    340
    +
    
    341
    +            text = self._text.get(None)
    
    342
    +            if text is not None:
    
    343
    +                return text
    
    344
    +            return self._text.popitem()[1]
    
    345
    +        return ''
    
    346
    +
    
    347
    +    def set_text(self, lang, text):
    
    348
    +        self._text[lang] = text
    
    349
    +
    
    313 350
         def __str__(self):
    
    314
    -        if self.message is not None:
    
    315
    -            return 'Error from %s %s: %s' % (self.jid, self.type, self.message)
    
    316
    -        return 'Error from %s: %s' % (self.jid, self.type)
    
    351
    +        condition = self.condition
    
    352
    +        if self.app_condition is not None:
    
    353
    +            condition = '%s (%s)' % (self.condition, self.app_condition)
    
    354
    +        text = self.get_text('en') or ''
    
    355
    +        if text:
    
    356
    +            text = ' - %s' % text
    
    357
    +        return 'Error from %s: %s%s' % (self.jid, condition, text)
    
    317 358
     
    
    318 359
     
    
    319 360
     class TuneData(namedtuple('TuneData', 'artist length rating source title track uri')):
    

  • nbxmpp/util.py
    ... ... @@ -138,14 +138,19 @@ def to_xs_boolean(value):
    138 138
             'Cant convert %s to xs:boolean' % value)
    
    139 139
     
    
    140 140
     
    
    141
    -def raise_error(log_method, stanza, type_=None, message=None):
    
    142
    -    if message is not None:
    
    143
    -        message = str(message)
    
    144
    -    if type_ is None:
    
    145
    -        type_ = stanza.getError()
    
    146
    -        message = stanza.getErrorMsg()
    
    147
    -    jid = stanza.getFrom()
    
    148
    -    error = CommonError(type_, message, jid)
    
    141
    +error_classes = {}
    
    142
    +
    
    143
    +def error_factory(stanza):
    
    144
    +    app_namespace = stanza.getAppErrorNamespace()
    
    145
    +    return error_classes.get(app_namespace, CommonError)(stanza)
    
    146
    +
    
    147
    +
    
    148
    +def raise_error(log_method, stanza, condition=None, text=None):
    
    149
    +    error = error_factory(stanza)
    
    150
    +    if text is not None:
    
    151
    +        error.set_text('en', str(text))
    
    152
    +    if condition is not None:
    
    153
    +        error.condition = str(condition)
    
    149 154
         log_method(error)
    
    150 155
         if log_method.__name__ in ('warning', 'error'):
    
    151 156
             log_method(stanza)
    

  • test/unit/test_error_parsing.py
    1
    +import unittest
    
    2
    +
    
    3
    +from nbxmpp.protocol import Iq
    
    4
    +from nbxmpp.util import error_factory
    
    5
    +
    
    6
    +
    
    7
    +class TestErrorParsing(unittest.TestCase):
    
    8
    +
    
    9
    +    def test_error_parsing(self):
    
    10
    +        stanza = '''
    
    11
    +        <iq from='upload.montague.tld'
    
    12
    +            id='step_03'
    
    13
    +            to='romeo@montague.tld/garden'
    
    14
    +            type='error'>
    
    15
    +          <error type='modify'>
    
    16
    +            <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' />
    
    17
    +            <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File too large. The maximum file size is 20000 bytes</text>
    
    18
    +            <text xml:lang='de' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File zu groß. Erlaubt sind 20000 bytes</text>
    
    19
    +            <file-too-large xmlns='urn:xmpp:http:upload:0'>
    
    20
    +              <max-file-size>20000</max-file-size>
    
    21
    +            </file-too-large>
    
    22
    +          </error>
    
    23
    +        </iq>'''
    
    24
    +
    
    25
    +        error = error_factory(Iq(node=stanza))
    
    26
    +        self.assertEqual(error.condition, 'not-acceptable')
    
    27
    +        self.assertEqual(error.app_condition, 'file-too-large')
    
    28
    +        self.assertEqual(error.get_text(), 'File too large. The maximum file size is 20000 bytes')
    
    29
    +        self.assertEqual(error.get_text('de'), 'File zu groß. Erlaubt sind 20000 bytes')
    
    30
    +        self.assertEqual(error.type, 'modify')
    
    31
    +        self.assertEqual(error.id, 'step_03')
    
    32
    +        self.assertEqual(error.jid, 'upload.montague.tld')