1
# -*- test-case-name: twisted.words.test.test_jabberxmppstringprep -*-
3
# Copyright (c) 2001-2005 Twisted Matrix Laboratories.
4
# See LICENSE for details.
8
if sys.version_info < (2,3,2):
12
dots = re.compile(u"[\u002E\u3002\uFF0E\uFF61]")
13
def nameprep(self, label):
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.")
29
from encodings import idna
36
""" Interface for character lookup classes. """
39
""" Return whether character is in this table. """
42
""" Interface for character mapping classes. """
45
""" Return mapping for character. """
47
class LookupTableFromFunction:
49
__implements__ = ILookupTable
51
def __init__(self, in_table_function):
52
self.lookup = in_table_function
56
__implements__ = ILookupTable
58
def __init__(self, table):
62
return c in self._table
64
class MappingTableFromFunction:
66
__implements__ = IMappingTable
68
def __init__(self, map_table_function):
69
self.map = map_table_function
71
class EmptyMappingTable:
73
__implements__ = IMappingTable
75
def __init__(self, in_table_function):
76
self._in_table_function = in_table_function
79
if self._in_table_function(c):
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
93
def prepare(self, string):
94
result = self.map(string)
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)
104
def map(self, string):
110
for mapping in self.mappings:
111
result_c = mapping.map(c)
115
if result_c is not None:
116
result.append(result_c)
118
return u"".join(result)
120
def check_prohibiteds(self, string):
122
for table in self.prohibiteds:
124
raise UnicodeError, "Invalid character %s" % repr(c)
126
def check_unassigneds(self, string):
128
if stringprep.in_table_a1(c):
129
raise UnicodeError, "Unassigned code point %s" % repr(c)
131
def check_bidirectionals(self, string):
133
found_RandALCat = False
136
if stringprep.in_table_d1(c):
137
found_RandALCat = True
138
if stringprep.in_table_d2(c):
141
if found_LCat and found_RandALCat:
142
raise UnicodeError, "Violation of BIDI Requirement 2"
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"
150
""" Implements nameprep on international domain names.
152
STD3ASCIIRules is assumed true in this implementation.
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) ]
162
def prepare(self, string):
165
labels = idna.dots.split(string)
167
if labels and len(labels[-1]) == 0:
174
result.append(self.nameprep(label))
176
return ".".join(result)+trailing_dot
178
def check_prohibiteds(self, string):
180
if c in self.prohibiteds:
181
raise UnicodeError, "Invalid character %s" % repr(c)
183
def nameprep(self, label):
184
label = idna.nameprep(label)
185
self.check_prohibiteds(label)
187
raise UnicodeError, "Invalid leading hyphen-minus"
189
raise UnicodeError, "Invalid trailing hyphen-minus"
193
case_map = MappingTableFromFunction(lambda c: c.lower())
194
nodeprep = Profile(mappings=[case_map],
196
prohibiteds=[LookupTable([u' ', u'"', u'&', u"'", u'/',
197
u':', u'<', u'>', u'@'])],
198
check_unassigneds=False,
201
resourceprep = Profile(normalize=False,
202
check_unassigneds=False,
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)
218
B_1 = EmptyMappingTable(stringprep.in_table_b1)
219
B_2 = MappingTableFromFunction(stringprep.map_table_b2)
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'@'])])
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])
231
nameprep = NamePrep()