Package nbxmpp :: Module stringprepare |
[hide private]
[frames] | no frames]

# Source Code for Module nbxmpp.stringprepare

      1  # -*- coding:utf-8 -*-
      2  ## src/common/xmpp/stringprepare.py
      3  ##
      4  ## Copyright (C) 2001-2005 Twisted Matrix Laboratories
      5  ## Copyright (C) 2005-2012 Yann Leboulanger <asterix AT lagaule.org>
      6  ## Copyright (C) 2006 Stefan Bethge <stefan AT lanpartei.de>
      7  ## Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
      8  ##
      9  ## This file is part of Gajim.
     10  ##
     11  ## Gajim is free software; you can redistribute it and/or modify
     12  ## it under the terms of the GNU General Public License as published
     13  ## by the Free Software Foundation; version 3 only.
     14  ##
     15  ## Gajim is distributed in the hope that it will be useful,
     16  ## but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     18  ## GNU General Public License for more details.
     19  ##
     20  ## You should have received a copy of the GNU General Public License
     21  ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
     22  ##
     23
     24  import stringprep
     25  import unicodedata
     26  from encodings import idna
     27
     28 -class ILookupTable:
     29      """
     30      Interface for character lookup classes
     31      """
     32
     33 -    def lookup(self, c):
     34          """
     35          Return whether character is in this table
     36          """
     37          pass
     38
     39 -class IMappingTable:
     40      """
     41      Interface for character mapping classes
     42      """
     43
     44 -    def map(self, c):
     45          """
     46          Return mapping for character
     47          """
     48          pass
     49
     50 -class LookupTableFromFunction:
     51
     52      __implements__ = ILookupTable
     53
     54 -    def __init__(self, in_table_function):
     55          self.lookup = in_table_function
     56
     57 -class LookupTable:
     58
     59      __implements__ = ILookupTable
     60
     61 -    def __init__(self, table):
     62          self._table = table
     63
     64 -    def lookup(self, c):
     65          return c in self._table
     66
     67 -class MappingTableFromFunction:
     68
     69      __implements__ = IMappingTable
     70
     71 -    def __init__(self, map_table_function):
     72          self.map = map_table_function
     73
     74 -class EmptyMappingTable:
     75
     76      __implements__ = IMappingTable
     77
     78 -    def __init__(self, in_table_function):
     79          self._in_table_function = in_table_function
     80
     81 -    def map(self, c):
     82          if self._in_table_function(c):
     83              return None
     84          else:
     85              return c
     86
     87 -class Profile:
     88 -    def __init__(self, mappings=[], normalize=True, prohibiteds=[],
     89                      check_unassigneds=True, check_bidi=True):
     90          self.mappings = mappings
     91          self.normalize = normalize
     92          self.prohibiteds = prohibiteds
     93          self.do_check_unassigneds = check_unassigneds
     94          self.do_check_bidi = check_bidi
     95
     96 -    def prepare(self, string):
     97          result = self.map(string)
     98          if self.normalize:
     99              result = unicodedata.normalize("NFKC", result)
    100          self.check_prohibiteds(result)
    101          if self.do_check_unassigneds:
    102              self.check_unassigneds(result)
    103          if self.do_check_bidi:
    104              self.check_bidirectionals(result)
    105          return result
    106
    107 -    def map(self, string):
    108          result = []
    109
    110          for c in string:
    111              result_c = c
    112
    113              for mapping in self.mappings:
    114                  result_c = mapping.map(c)
    115                  if result_c != c:
    116                      break
    117
    118              if result_c is not None:
    119                  result.append(result_c)
    120
    121          return u"".join(result)
    122
    123 -    def check_prohibiteds(self, string):
    124          for c in string:
    125              for table in self.prohibiteds:
    126                  if table.lookup(c):
    127                      raise UnicodeError, "Invalid character %s" % repr(c)
    128
    129 -    def check_unassigneds(self, string):
    130          for c in string:
    131              if stringprep.in_table_a1(c):
    132                  raise UnicodeError, "Unassigned code point %s" % repr(c)
    133
    134 -    def check_bidirectionals(self, string):
    135          found_LCat = False
    136          found_RandALCat = False
    137
    138          for c in string:
    139              if stringprep.in_table_d1(c):
    140                  found_RandALCat = True
    141              if stringprep.in_table_d2(c):
    142                  found_LCat = True
    143
    144          if found_LCat and found_RandALCat:
    145              raise UnicodeError, "Violation of BIDI Requirement 2"
    146
    147          if found_RandALCat and not (stringprep.in_table_d1(string[0]) and
    148                                                                  stringprep.in_table_d1(string[-1])):
    149              raise UnicodeError, "Violation of BIDI Requirement 3"
    150
    151
    152 -class NamePrep:
    153      """
    154      Implements preparation of internationalized domain names
    155
    156      This class implements preparing internationalized domain names using the
    157      rules defined in RFC 3491, section 4 (Conversion operations).
    158
    159      We do not perform step 4 since we deal with unicode representations of
    160      domain names and do not convert from or to ASCII representations using
    161      punycode encoding. When such a conversion is needed, the L{idna} standard
    162      library provides the C{ToUnicode()} and C{ToASCII()} functions. Note that
    163      L{idna} itself assumes UseSTD3ASCIIRules to be false.
    164
    165      The following steps are performed by C{prepare()}:
    166
    167              * Split the domain name in labels at the dots (RFC 3490, 3.1)
    168              * Apply nameprep proper on each label (RFC 3491)
    169              * Enforce the restrictions on ASCII characters in host names by
    170                      assuming STD3ASCIIRules to be true. (STD 3)
    171              * Rejoin the labels using the label separator U+002E (full stop).
    172      """
    173
    174      # Prohibited characters.
    175      prohibiteds = [unichr(n) for n in range(0x00, 0x2c + 1) +
    176                                                                              range(0x2e, 0x2f + 1) +
    177                                                                              range(0x3a, 0x40 + 1) +
    178                                                                              range(0x5b, 0x60 + 1) +
    179                                                                              range(0x7b, 0x7f + 1) ]
    180
    181 -    def prepare(self, string):
    182          result = []
    183
    184          labels = idna.dots.split(string)
    185
    186          if labels and len(labels[-1]) == 0:
    187              trailing_dot = '.'
    188              del labels[-1]
    189          else:
    190              trailing_dot = ''
    191
    192          for label in labels:
    193              result.append(self.nameprep(label))
    194
    195          return ".".join(result)+trailing_dot
    196
    197 -    def check_prohibiteds(self, string):
    198          for c in string:
    199              if c in self.prohibiteds:
    200                  raise UnicodeError, "Invalid character %s" % repr(c)
    201
    202 -    def nameprep(self, label):
    203          label = idna.nameprep(label)
    204          self.check_prohibiteds(label)
    205          if len(label) == 0:
    206              raise UnicodeError, "Invalid empty name"
    207          if label[0] == '-':
    208              raise UnicodeError, "Invalid leading hyphen-minus"
    209          if label[-1] == '-':
    210              raise UnicodeError, "Invalid trailing hyphen-minus"
    211          return label
    212
    213  C_11 = LookupTableFromFunction(stringprep.in_table_c11)
    214  C_12 = LookupTableFromFunction(stringprep.in_table_c12)
    215  C_21 = LookupTableFromFunction(stringprep.in_table_c21)
    216  C_22 = LookupTableFromFunction(stringprep.in_table_c22)
    217  C_3 = LookupTableFromFunction(stringprep.in_table_c3)
    218  C_4 = LookupTableFromFunction(stringprep.in_table_c4)
    219  C_5 = LookupTableFromFunction(stringprep.in_table_c5)
    220  C_6 = LookupTableFromFunction(stringprep.in_table_c6)
    221  C_7 = LookupTableFromFunction(stringprep.in_table_c7)
    222  C_8 = LookupTableFromFunction(stringprep.in_table_c8)
    223  C_9 = LookupTableFromFunction(stringprep.in_table_c9)
    224
    225  B_1 = EmptyMappingTable(stringprep.in_table_b1)
    226  B_2 = MappingTableFromFunction(stringprep.map_table_b2)
    227
    228  nodeprep = Profile(mappings=[B_1, B_2],
    229                                                  prohibiteds=[C_11, C_12, C_21, C_22,
    230                                                                                  C_3, C_4, C_5, C_6, C_7, C_8, C_9,
    231                                                                                  LookupTable([u'"', u'&', u"'", u'/',
    232                                                                                                                  u':', u'<', u'>', u'@'])])
    233
    234  resourceprep = Profile(mappings=[B_1,],
    235                                                          prohibiteds=[C_12, C_21, C_22,
    236                                                                                          C_3, C_4, C_5, C_6, C_7, C_8, C_9])
    237
    238  nameprep = NamePrep()
    239