| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: twisted.words.test.test_jabberjid -*- | |
| 2 # | |
| 3 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. | |
| 4 # See LICENSE for details. | |
| 5 | |
| 6 """ | |
| 7 Jabber Identifier support. | |
| 8 | |
| 9 This module provides an object to represent Jabber Identifiers (JIDs) and | |
| 10 parse string representations into them with proper checking for illegal | |
| 11 characters, case folding and canonicalisation through L{stringprep<twisted.words
.protocols.jabber.xmpp_stringprep>}. | |
| 12 """ | |
| 13 | |
| 14 from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep, resourcepre
p, nameprep | |
| 15 | |
| 16 class InvalidFormat(Exception): | |
| 17 """ | |
| 18 The given string could not be parsed into a valid Jabber Identifier (JID). | |
| 19 """ | |
| 20 | |
| 21 def parse(jidstring): | |
| 22 """ | |
| 23 Parse given JID string into its respective parts and apply stringprep. | |
| 24 | |
| 25 @param jidstring: string representation of a JID. | |
| 26 @type jidstring: C{unicode} | |
| 27 @return: tuple of (user, host, resource), each of type C{unicode} as | |
| 28 the parsed and stringprep'd parts of the given JID. If the | |
| 29 given string did not have a user or resource part, the respective | |
| 30 field in the tuple will hold C{None}. | |
| 31 @rtype: C{tuple} | |
| 32 """ | |
| 33 user = None | |
| 34 host = None | |
| 35 resource = None | |
| 36 | |
| 37 # Search for delimiters | |
| 38 user_sep = jidstring.find("@") | |
| 39 res_sep = jidstring.find("/") | |
| 40 | |
| 41 if user_sep == -1: | |
| 42 if res_sep == -1: | |
| 43 # host | |
| 44 host = jidstring | |
| 45 else: | |
| 46 # host/resource | |
| 47 host = jidstring[0:res_sep] | |
| 48 resource = jidstring[res_sep + 1:] or None | |
| 49 else: | |
| 50 if res_sep == -1: | |
| 51 # user@host | |
| 52 user = jidstring[0:user_sep] or None | |
| 53 host = jidstring[user_sep + 1:] | |
| 54 else: | |
| 55 if user_sep < res_sep: | |
| 56 # user@host/resource | |
| 57 user = jidstring[0:user_sep] or None | |
| 58 host = jidstring[user_sep + 1:user_sep + (res_sep - user_sep)] | |
| 59 resource = jidstring[res_sep + 1:] or None | |
| 60 else: | |
| 61 # host/resource (with an @ in resource) | |
| 62 host = jidstring[0:res_sep] | |
| 63 resource = jidstring[res_sep + 1:] or None | |
| 64 | |
| 65 return prep(user, host, resource) | |
| 66 | |
| 67 def prep(user, host, resource): | |
| 68 """ | |
| 69 Perform stringprep on all JID fragments. | |
| 70 | |
| 71 @param user: The user part of the JID. | |
| 72 @type user: C{unicode} | |
| 73 @param host: The host part of the JID. | |
| 74 @type host: C{unicode} | |
| 75 @param resource: The resource part of the JID. | |
| 76 @type resource: C{unicode} | |
| 77 @return: The given parts with stringprep applied. | |
| 78 @rtype: C{tuple} | |
| 79 """ | |
| 80 | |
| 81 if user: | |
| 82 try: | |
| 83 user = nodeprep.prepare(unicode(user)) | |
| 84 except UnicodeError: | |
| 85 raise InvalidFormat, "Invalid character in username" | |
| 86 else: | |
| 87 user = None | |
| 88 | |
| 89 if not host: | |
| 90 raise InvalidFormat, "Server address required." | |
| 91 else: | |
| 92 try: | |
| 93 host = nameprep.prepare(unicode(host)) | |
| 94 except UnicodeError: | |
| 95 raise InvalidFormat, "Invalid character in hostname" | |
| 96 | |
| 97 if resource: | |
| 98 try: | |
| 99 resource = resourceprep.prepare(unicode(resource)) | |
| 100 except UnicodeError: | |
| 101 raise InvalidFormat, "Invalid character in resource" | |
| 102 else: | |
| 103 resource = None | |
| 104 | |
| 105 return (user, host, resource) | |
| 106 | |
| 107 __internJIDs = {} | |
| 108 | |
| 109 def internJID(jidstring): | |
| 110 """ | |
| 111 Return interned JID. | |
| 112 | |
| 113 @rtype: L{JID} | |
| 114 """ | |
| 115 | |
| 116 if jidstring in __internJIDs: | |
| 117 return __internJIDs[jidstring] | |
| 118 else: | |
| 119 j = JID(jidstring) | |
| 120 __internJIDs[jidstring] = j | |
| 121 return j | |
| 122 | |
| 123 class JID(object): | |
| 124 """ | |
| 125 Represents a stringprep'd Jabber ID. | |
| 126 | |
| 127 JID objects are hashable so they can be used in sets and as keys in | |
| 128 dictionaries. | |
| 129 """ | |
| 130 | |
| 131 def __init__(self, str=None, tuple=None): | |
| 132 if not (str or tuple): | |
| 133 raise RuntimeError("You must provide a value for either 'str' or " | |
| 134 "'tuple' arguments.") | |
| 135 | |
| 136 if str: | |
| 137 user, host, res = parse(str) | |
| 138 else: | |
| 139 user, host, res = prep(*tuple) | |
| 140 | |
| 141 self.user = user | |
| 142 self.host = host | |
| 143 self.resource = res | |
| 144 | |
| 145 def userhost(self): | |
| 146 """ | |
| 147 Extract the bare JID as a unicode string. | |
| 148 | |
| 149 A bare JID does not have a resource part, so this returns either | |
| 150 C{user@host} or just C{host}. | |
| 151 | |
| 152 @rtype: C{unicode} | |
| 153 """ | |
| 154 if self.user: | |
| 155 return u"%s@%s" % (self.user, self.host) | |
| 156 else: | |
| 157 return self.host | |
| 158 | |
| 159 def userhostJID(self): | |
| 160 """ | |
| 161 Extract the bare JID. | |
| 162 | |
| 163 A bare JID does not have a resource part, so this returns a | |
| 164 L{JID} object representing either C{user@host} or just C{host}. | |
| 165 | |
| 166 If the object this method is called upon doesn't have a resource | |
| 167 set, it will return itself. Otherwise, the bare JID object will | |
| 168 be created, interned using L{internJID}. | |
| 169 | |
| 170 @rtype: L{JID} | |
| 171 """ | |
| 172 if self.resource: | |
| 173 return internJID(self.userhost()) | |
| 174 else: | |
| 175 return self | |
| 176 | |
| 177 def full(self): | |
| 178 """ | |
| 179 Return the string representation of this JID. | |
| 180 | |
| 181 @rtype: C{unicode} | |
| 182 """ | |
| 183 if self.user: | |
| 184 if self.resource: | |
| 185 return u"%s@%s/%s" % (self.user, self.host, self.resource) | |
| 186 else: | |
| 187 return u"%s@%s" % (self.user, self.host) | |
| 188 else: | |
| 189 if self.resource: | |
| 190 return u"%s/%s" % (self.host, self.resource) | |
| 191 else: | |
| 192 return self.host | |
| 193 | |
| 194 def __eq__(self, other): | |
| 195 """ | |
| 196 Equality comparison. | |
| 197 | |
| 198 L{JID}s compare equal if their user, host and resource parts all | |
| 199 compare equal. When comparing against instances of other types, it | |
| 200 uses the default comparison. | |
| 201 """ | |
| 202 if isinstance(other, JID): | |
| 203 return (self.user == other.user and | |
| 204 self.host == other.host and | |
| 205 self.resource == other.resource) | |
| 206 else: | |
| 207 return NotImplemented | |
| 208 | |
| 209 def __ne__(self, other): | |
| 210 """ | |
| 211 Inequality comparison. | |
| 212 | |
| 213 This negates L{__eq__} for comparison with JIDs and uses the default | |
| 214 comparison for other types. | |
| 215 """ | |
| 216 result = self.__eq__(other) | |
| 217 if result is NotImplemented: | |
| 218 return result | |
| 219 else: | |
| 220 return not result | |
| 221 | |
| 222 def __hash__(self): | |
| 223 """ | |
| 224 Calculate hash. | |
| 225 | |
| 226 L{JID}s with identical constituent user, host and resource parts have | |
| 227 equal hash values. In combination with the comparison defined on JIDs, | |
| 228 this allows for using L{JID}s in sets and as dictionary keys. | |
| 229 """ | |
| 230 return hash((self.user, self.host, self.resource)) | |
| 231 | |
| 232 def __unicode__(self): | |
| 233 """ | |
| 234 Get unicode representation. | |
| 235 | |
| 236 Return the string representation of this JID as a unicode string. | |
| 237 @see: L{full} | |
| 238 """ | |
| 239 | |
| 240 return self.full() | |
| 241 | |
| 242 def __repr__(self): | |
| 243 """ | |
| 244 Get object representation. | |
| 245 | |
| 246 Returns a string that would create a new JID object that compares equal | |
| 247 to this one. | |
| 248 """ | |
| 249 return 'JID(%r)' % self.full() | |
| OLD | NEW |