root/trunk/RBJabber/RBJabber/JID.py

Revision 253, 7.0 kB (checked in by sholloway, 6 years ago)

Changed to BSD License

Line 
1 #!/usr/bin/env python
2 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 ##~ License
4 ##~
5 ##- The RuneBlade Foundation library is intended to ease some
6 ##- aspects of writing intricate Jabber, XML, and User Interface (wxPython, etc.)
7 ##- applications, while providing the flexibility to modularly change the
8 ##- architecture. Enjoy.
9 ##~
10 ##~ Copyright (C) 2002  TechGame Networks, LLC.
11 ##~
12 ##~ This library is free software; you can redistribute it and/or
13 ##~ modify it under the terms of the BSD style License as found in the
14 ##~ LICENSE file included with this distribution.
15 ##~
16 ##~ TechGame Networks, LLC can be reached at:
17 ##~ 3578 E. Hartsel Drive #211
18 ##~ Colorado Springs, Colorado, USA, 80920
19 ##~
20 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22 """JID class and convenience functions.
23
24 Dependencies:
25     re
26 """
27
28 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29 #~ Imports
30 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31
32 import re
33
34 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35 #~ Constants / Variables / Etc.
36 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37
38 __all__ = ['reJabberURL', 'reJabberJID', 'JID']
39
40 _restrID = '''[\w-]+(?:[\w\.-]+[\w-]+)?'''
41 _restrServer = '''[\w-]+(?:[\w\.-]+[\w-]+)?(?::[0-9]+)?'''
42 _restrResource = '''\S+'''
43 reJabberURL = re.compile('''(?:jabber://)?(%s)''' % (_restrServer))
44 reJabberJID = re.compile('''(?:(%s)@)?(%s)(?:/(%s))?''' % (_restrID, _restrServer, _restrResource))
45
46 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47 #~ Definitions
48 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
49
50 def splitnorm(strJID, start=1, end=4):
51     """Splits username@server/resource into [username, server, resource],
52     and normalizes username and server.  Returns a start to end-1 of the list"""
53     result = reJabberJID.split(strJID)[start:end]
54     return [x and x.lower() or x for x in result[1-start:3-start]] + result[3-start:]
55
56 def split(strJID, start=1, end=4):
57     """Splits username@server/resource into [username, server, resource]. 
58     Returns a start to end-1 of the list"""
59     return reJabberJID.split(strJID)[start:end]
60
61 def splitex(strJID, start=1, end=4, normalize=0):
62     """Uses normalize flag to choose between split and splitnorm."""
63     if normalize: return splitnorm(strJID, start, end)
64     else: return split(strJID, start, end)
65
66 def cmp_(strJIDa, strJIDb, resource=1):
67     """Compares two JIDs, including resources if flag is set. 
68     Note that case is insensitive in username and server, but IS sensitive in the resource."""
69     jida = splitnorm(strJIDa, end=3+resource)
70     jidb = splitnorm(strJIDb, end=3+resource)
71     return cmp(jida, jidb)
72
73 def compare(*args, **kw):
74     """Same as cmp_, except returns a python truth value instead of a cmp result."""
75     return 0 == cmp_(*args, **kw)
76
77 def contains(strJIDa, strJIDb):
78     """Returns true if strJIDb is strJIDb, or strJIDb is qualified by a resource.
79     Will fail if strJIDa has a resource and is not the same JID as strJIDb."""
80     jida = filter(None, splitnorm(strJIDa, end=4))
81     jidb = filter(None, splitnorm(strJIDb, end=3))[-len(jida):]
82     return jida == jidb or compare(strJIDa, strJIDb)
83
84 def join(*args):
85     """Combines a (username, server, resource) into username@server/resource, but does so
86     in several different formats"""
87     if isinstance(args[0], (tuple, list)):
88         args = tuple(args[0])
89     args = filter(None, args)
90     if len(args) == 3:
91         return JID('%s@%s/%s' % args)
92     elif len(args) == 2:
93         return JID('%s@%s' % args)
94     elif len(args) == 1:
95         return args[0]
96     else: return ''
97
98 def username(strJID, normalize=0):
99     """Extracts the username from the JID"""
100     return splitex(strJID, 1, 2, normalize)[0]
101 def server(strJID, normalize=0):
102     """Extracts the server from the JID"""
103     return splitex(strJID, 2, 3, normalize)[0]
104 def resource(strJID, normalize=0):
105     """Extracts the resource from the JID"""
106     return splitex(strJID, 3, 4, normalize)[0]
107 def noresource(strJID, normalize=0):
108     """Returns the JID without the resource qualification"""
109     return join(splitex(strJID, 1, 3, normalize))
110 def nominal(strJID):
111     """Returns the JID with username and server lowercased, and no resource"""
112     return join(splitnorm(strJID, 1, 3))
113 def normalize(strJID):
114     """Returns the JID with the username and server lowercased, but retaining the resource"""
115     return join(splitnorm(strJID))
116
117 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118 #~ Class JID
119 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
120
121 class JID(str):
122     """An object-oriented way of dealing with JIDs"""
123
124     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
125     #~ Public Methods
126     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
127
128     split = split
129     splitnorm = splitnorm
130     splitex = splitex
131    
132     normalize = normalize
133     nominal = nominal
134     compare = compare
135
136     noresource = noresource
137     username = username
138     server = server
139     resource = resource
140  
141     def join(Class, *args):
142         return Class(join(*args))
143     join = classmethod(join)
144
145     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
146     #~ Special
147     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148
149     __cmp__ = cmp_
150     def __eq__(self, other):
151         return cmp_(self, other) == 0
152     def __ne__(self, other):
153         return cmp_(self, other) != 0
154     def __lt__(self, other):
155         return cmp_(self, other) < 0
156     def __le__(self, other):
157         return cmp_(self, other) <= 0
158     def __gt__(self, other):
159         return cmp_(self, other) > 0
160     def __ge__(self, other):
161         return cmp_(self, other) >= 0
162
163     def __contains__(self, other):
164         return contains(self, other)
165        
166     def __hash__(self):
167         return hash(tuple(self.splitnorm()))
168
169 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170 #~ Testing
171 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
172
173 def _Test_JID():
174     j1 = JID('user.name@jabber.org/Resource')
175     j2 = JID('User.Name@Jabber.org/Resource')
176     j3 = JID('User.Name@Jabber.org/ReSoUrCe')
177     j4 = JID('conference.jabber.org')
178
179     assert j1 in j1
180     assert j1 in JID('user.name@Jabber.org')
181     assert j3 in JID('JaBBer.org')
182     assert j2 not in j3
183
184     assert j4.normalize() == j4
185     assert j4.username() is None
186     assert j4.server() == j4
187     assert j4.resource() is None
188     assert j4.noresource() == j4
189
190     assert j1 == j2
191     assert j1 >= j2
192     assert j1 <= j2
193     assert j1 != j3
194     assert j2 != j3
195     assert j3 < j1
196     assert j1 > j3
197     assert j3 < j2
198     assert j2 > j3
199     assert j1.splitnorm() == j2.splitnorm() != j3.splitnorm()
200     assert j1.splitnorm(1,3) == j2.splitnorm(1,3) == j3.splitnorm(1,3)
201     assert hash(j1) == hash(j2)
202     assert hash(j1) != hash(j3)
203     assert hash(j2) != hash(j3)
204
205     dictTest = {}
206     dictTest[j1] = 1
207     dictTest[j2] = 1
208     dictTest[j3] = 1
209     # Length should be 2 because j2 and j1s' hashes should be identical
210     assert len(dictTest)==2
211    
212 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
213
214 if __name__=='__main__':
215     print "Testing..."
216     _Test_JID()
217     print "Test complete."
218
219
Note: See TracBrowser for help on using the browser.