~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/words/protocols/jabber/xmpp_stringprep.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-01-16 19:56:10 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060116195610-ykmxbia4mnnod9o2
Tags: 2.1.0-0ubuntu2
debian/copyright: Include copyright for python 2.3; some 2.3 files
are included in the upstream tarball, but not in the binary packages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- test-case-name: twisted.words.test.test_jabberxmppstringprep -*-
2
 
#
3
 
# Copyright (c) 2001-2005 Twisted Matrix Laboratories.
4
 
# See LICENSE for details.
5
 
 
6
 
import sys, warnings
7
 
 
8
 
if sys.version_info < (2,3,2):
9
 
    import re
10
 
 
11
 
    class IDNA:
12
 
        dots = re.compile(u"[\u002E\u3002\uFF0E\uFF61]")
13
 
        def nameprep(self, label):
14
 
            return label.lower()
15
 
 
16
 
    idna = IDNA()
17
 
 
18
 
    crippled = True
19
 
 
20
 
    warnings.warn("Accented and non-Western Jabber IDs will not be properly "
21
 
                  "case-folded with this version of Python, resulting in "
22
 
                  "incorrect protocol-level behavior.  It is strongly "
23
 
                  "recommended you upgrade to Python 2.3.2 or newer if you "
24
 
                  "intend to use Twisted's Jabber support.")
25
 
 
26
 
else:
27
 
    import stringprep
28
 
    import unicodedata
29
 
    from encodings import idna
30
 
 
31
 
    crippled = False
32
 
 
33
 
del sys, warnings
34
 
 
35
 
class ILookupTable:
36
 
    """ Interface for character lookup classes. """
37
 
 
38
 
    def lookup(self, c):
39
 
        """ Return whether character is in this table. """
40
 
 
41
 
class IMappingTable:
42
 
    """ Interface for character mapping classes. """
43
 
 
44
 
    def map(self, c):
45
 
        """ Return mapping for character. """
46
 
 
47
 
class LookupTableFromFunction:
48
 
 
49
 
    __implements__ = ILookupTable
50
 
 
51
 
    def __init__(self, in_table_function):
52
 
        self.lookup = in_table_function
53
 
 
54
 
class LookupTable:
55
 
 
56
 
    __implements__ = ILookupTable
57
 
 
58
 
    def __init__(self, table):
59
 
        self._table = table
60
 
 
61
 
    def lookup(self, c):
62
 
        return c in self._table
63
 
 
64
 
class MappingTableFromFunction:
65
 
 
66
 
    __implements__ = IMappingTable
67
 
 
68
 
    def __init__(self, map_table_function):
69
 
        self.map = map_table_function
70
 
 
71
 
class EmptyMappingTable:
72
 
    
73
 
    __implements__ = IMappingTable
74
 
 
75
 
    def __init__(self, in_table_function):
76
 
        self._in_table_function = in_table_function
77
 
 
78
 
    def map(self, c):
79
 
        if self._in_table_function(c):
80
 
            return None
81
 
        else:
82
 
            return c
83
 
 
84
 
class Profile:
85
 
    def __init__(self, mappings=[],  normalize=True, prohibiteds=[],
86
 
                       check_unassigneds=True, check_bidi=True):
87
 
        self.mappings = mappings
88
 
        self.normalize = normalize
89
 
        self.prohibiteds = prohibiteds
90
 
        self.do_check_unassigneds = check_unassigneds
91
 
        self.do_check_bidi = check_bidi
92
 
 
93
 
    def prepare(self, string):
94
 
        result = self.map(string)
95
 
        if self.normalize:
96
 
            result = unicodedata.normalize("NFKC", result)
97
 
        self.check_prohibiteds(result)
98
 
        if self.do_check_unassigneds:
99
 
            self.check_unassigneds(result)
100
 
        if self.do_check_bidi:
101
 
            self.check_bidirectionals(result)
102
 
        return result
103
 
 
104
 
    def map(self, string):
105
 
        result = []
106
 
 
107
 
        for c in string:
108
 
            result_c = c
109
 
 
110
 
            for mapping in self.mappings:
111
 
                result_c = mapping.map(c)
112
 
                if result_c != c:
113
 
                    break
114
 
 
115
 
            if result_c is not None:
116
 
                result.append(result_c)
117
 
 
118
 
        return u"".join(result)
119
 
 
120
 
    def check_prohibiteds(self, string):
121
 
        for c in string:
122
 
            for table in self.prohibiteds:
123
 
                if table.lookup(c):
124
 
                    raise UnicodeError, "Invalid character %s" % repr(c)
125
 
 
126
 
    def check_unassigneds(self, string):
127
 
        for c in string:
128
 
            if stringprep.in_table_a1(c):
129
 
                raise UnicodeError, "Unassigned code point %s" % repr(c)
130
 
    
131
 
    def check_bidirectionals(self, string):
132
 
        found_LCat = False
133
 
        found_RandALCat = False
134
 
 
135
 
        for c in string:
136
 
            if stringprep.in_table_d1(c):
137
 
                found_RandALCat = True
138
 
            if stringprep.in_table_d2(c):
139
 
                found_LCat = True
140
 
 
141
 
        if found_LCat and found_RandALCat:
142
 
            raise UnicodeError, "Violation of BIDI Requirement 2"
143
 
 
144
 
        if found_RandALCat and not (stringprep.in_table_d1(string[0]) and
145
 
                                    stringprep.in_table_d1(string[-1])):
146
 
            raise UnicodeError, "Violation of BIDI Requirement 3"
147
 
 
148
 
 
149
 
class NamePrep:
150
 
    """ Implements nameprep on international domain names.
151
 
    
152
 
    STD3ASCIIRules is assumed true in this implementation.
153
 
    """
154
 
 
155
 
    # Prohibited characters.
156
 
    prohibiteds = [unichr(n) for n in range(0x00, 0x2c + 1) +
157
 
                                       range(0x2e, 0x2f + 1) +
158
 
                                       range(0x3a, 0x40 + 1) +
159
 
                                       range(0x5b, 0x60 + 1) +
160
 
                                       range(0x7b, 0x7f + 1) ]
161
 
 
162
 
    def prepare(self, string):
163
 
        result = []
164
 
 
165
 
        labels = idna.dots.split(string)
166
 
 
167
 
        if labels and len(labels[-1]) == 0:
168
 
            trailing_dot = '.'
169
 
            del labels[-1]
170
 
        else:
171
 
            trailing_dot = ''
172
 
 
173
 
        for label in labels:
174
 
            result.append(self.nameprep(label))
175
 
 
176
 
        return ".".join(result)+trailing_dot
177
 
 
178
 
    def check_prohibiteds(self, string):
179
 
        for c in string:
180
 
           if c in self.prohibiteds:
181
 
               raise UnicodeError, "Invalid character %s" % repr(c)
182
 
 
183
 
    def nameprep(self, label):
184
 
        label = idna.nameprep(label)
185
 
        self.check_prohibiteds(label)
186
 
        if label[0] == '-':
187
 
            raise UnicodeError, "Invalid leading hyphen-minus"
188
 
        if label[-1] == '-':
189
 
            raise UnicodeError, "Invalid trailing hyphen-minus"
190
 
        return label
191
 
 
192
 
if crippled:
193
 
    case_map = MappingTableFromFunction(lambda c: c.lower())
194
 
    nodeprep = Profile(mappings=[case_map],
195
 
                       normalize=False,
196
 
                       prohibiteds=[LookupTable([u' ', u'"', u'&', u"'", u'/',
197
 
                                                 u':', u'<', u'>', u'@'])],
198
 
                       check_unassigneds=False,
199
 
                       check_bidi=False) 
200
 
 
201
 
    resourceprep = Profile(normalize=False,
202
 
                           check_unassigneds=False,
203
 
                           check_bidi=False)
204
 
   
205
 
else:
206
 
    C_11 = LookupTableFromFunction(stringprep.in_table_c11)
207
 
    C_12 = LookupTableFromFunction(stringprep.in_table_c12)
208
 
    C_21 = LookupTableFromFunction(stringprep.in_table_c21)
209
 
    C_22 = LookupTableFromFunction(stringprep.in_table_c22)
210
 
    C_3 = LookupTableFromFunction(stringprep.in_table_c3)
211
 
    C_4 = LookupTableFromFunction(stringprep.in_table_c4)
212
 
    C_5 = LookupTableFromFunction(stringprep.in_table_c5)
213
 
    C_6 = LookupTableFromFunction(stringprep.in_table_c6)
214
 
    C_7 = LookupTableFromFunction(stringprep.in_table_c7)
215
 
    C_8 = LookupTableFromFunction(stringprep.in_table_c8)
216
 
    C_9 = LookupTableFromFunction(stringprep.in_table_c9)
217
 
 
218
 
    B_1 = EmptyMappingTable(stringprep.in_table_b1)
219
 
    B_2 = MappingTableFromFunction(stringprep.map_table_b2)
220
 
 
221
 
    nodeprep = Profile(mappings=[B_1, B_2],
222
 
                       prohibiteds=[C_11, C_12, C_21, C_22,
223
 
                                    C_3, C_4, C_5, C_6, C_7, C_8, C_9,
224
 
                                    LookupTable([u'"', u'&', u"'", u'/',
225
 
                                                 u':', u'<', u'>', u'@'])])
226
 
 
227
 
    resourceprep = Profile(mappings=[B_1,],
228
 
                           prohibiteds=[C_12, C_21, C_22,
229
 
                                        C_3, C_4, C_5, C_6, C_7, C_8, C_9])
230
 
 
231
 
nameprep = NamePrep()