1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """jid -- Jabber ID handling
20
21 Normative reference:
22 - `RFC 3920 <http://www.ietf.org/rfc/rfc3920.txt>`__
23 """
24
25 __docformat__="restructuredtext en"
26
27 import re
28 import weakref
29 import warnings
30
31 from encodings import idna
32
33 from pyxmpp.xmppstringprep import nodeprep,resourceprep
34 from pyxmpp.exceptions import JIDError
35
36 node_invalid_re=re.compile(ur"[" u'"' ur"&'/:<>@\s\x00-\x19]",re.UNICODE)
37 resource_invalid_re=re.compile(ur"[\s\x00-\x19]",re.UNICODE)
38
40 """Compare two International Domain Names.
41
42 :Parameters:
43 - `a`,`b`: domains names to compare
44
45 :return: True `a` and `b` are equal as domain names."""
46
47 a=idna.ToASCII(a)
48 b=idna.ToASCII(b)
49 return a.lower()==b.lower()
50
52 """JID.
53
54 :Ivariables:
55 - `node`: node part of the JID
56 - `domain`: domain part of the JID
57 - `resource`: resource part of the JID
58
59 JID objects are immutable. They are also cached for better performance.
60 """
61 cache=weakref.WeakValueDictionary()
62 __slots__=["node","domain","resource","__weakref__"]
63 - def __new__(cls,node_or_jid=None,domain=None,resource=None,check=True):
64 """Create a new JID object or take one from the cache.
65
66 :Parameters:
67 - `node_or_jid`: node part of the JID, JID object to copy or
68 Unicode representation of the JID.
69 - `domain`: domain part of the JID
70 - `resource`: resource part of the JID
71 - `check`: if `False` then JID is not checked for specifiaction
72 compliance.
73 """
74
75 if isinstance(node_or_jid,JID):
76 return node_or_jid
77
78 if domain is None and resource is None:
79 obj=cls.cache.get(node_or_jid)
80 if obj:
81 return obj
82 else:
83 obj=None
84 if obj is None:
85 obj=object.__new__(cls)
86
87 if node_or_jid:
88 node_or_jid = unicode(node_or_jid)
89 if (node_or_jid and
90 ((u"@" in node_or_jid) or (u"/" in node_or_jid))):
91 obj.__from_unicode(node_or_jid)
92 cls.cache[node_or_jid]=obj
93 else:
94 if domain is None and resource is None:
95 if node_or_jid is None:
96 raise JIDError,"At least domain must be given"
97 domain=node_or_jid
98 node_or_jid=None
99 if check:
100 obj.__set_node(node_or_jid)
101 obj.__set_domain(domain)
102 obj.__set_resource(resource)
103 else:
104 object.__setattr__(obj,"node",node_or_jid)
105 object.__setattr__(obj,"domain",domain)
106 object.__setattr__(obj,"resource",resource)
107 return obj
108
110 raise RuntimeError,"JID objects are immutable!"
111
113 """Initialize JID object from Unicode string.
114
115 :Parameters:
116 - `s`: the JID string
117 - `check`: when `False` then the JID is not checked for
118 specification compliance."""
119 s1=s.split(u"/",1)
120 s2=s1[0].split(u"@",1)
121 if len(s2)==2:
122 if check:
123 self.__set_node(s2[0])
124 self.__set_domain(s2[1])
125 else:
126 object.__setattr__(self,"node",s2[0])
127 object.__setattr__(self,"domain",s2[1])
128 else:
129 if check:
130 self.__set_domain(s2[0])
131 else:
132 object.__setattr__(self,"domain",s2[0])
133 object.__setattr__(self,"node",None)
134 if len(s1)==2:
135 if check:
136 self.__set_resource(s1[1])
137 else:
138 object.__setattr__(self,"resource",s1[1])
139 else:
140 object.__setattr__(self,"resource",None)
141 if not self.domain:
142 raise JIDError,"Domain is required in JID."
143
145 """Initialize `self.node`
146
147 :Parameters:
148 - `s`: Node part of the JID
149 :Types:
150 - `s`: unicode
151
152 :raise JIDError: if the node name is too long.
153 :raise pyxmpp.xmppstringprep.StringprepError: if the
154 node name fails Nodeprep preparation."""
155 if s:
156 s = unicode(s)
157 s=nodeprep.prepare(s)
158 if len(s.encode("utf-8"))>1023:
159 raise JIDError,"Node name too long"
160 else:
161 s=None
162 object.__setattr__(self,"node",s)
163
164 - def __set_domain(self,s):
165 """Initialize `self.domain`
166
167 :Parameters:
168 - `s`: Unicode or UTF-8 domain part of the JID
169
170 :raise JIDError: if the domain name is too long."""
171
172 if s is None:
173 raise JIDError,"Domain must be given"
174 if s:
175 s = unicode(s)
176 s=idna.nameprep(s)
177 if len(s.encode("utf-8"))>1023:
178 raise JIDError,"Domain name too long"
179 object.__setattr__(self,"domain",s)
180
182 """Initialize `self.resource`
183
184 :Parameters:
185 - `s`: Unicode or UTF-8 resource part of the JID
186
187 :raise JIDError: if the resource name is too long.
188 :raise pyxmpp.xmppstringprep.StringprepError: if the
189 node name fails Resourceprep preparation."""
190 if s:
191 s = unicode(s)
192 s=resourceprep.prepare(s)
193 if len(s.encode("utf-8"))>1023:
194 raise JIDError,"Resource name too long"
195 else:
196 s=None
197 object.__setattr__(self,"resource",s)
198
200 warnings.warn("JIDs should not be used as strings", DeprecationWarning, stacklevel=2)
201 return self.as_utf8()
202
205
208
210 """UTF-8 encoded JID representation.
211
212 :return: UTF-8 encoded JID."""
213 return self.as_unicode().encode("utf-8")
214
216 """UTF-8 encoded JID representation.
217
218 *Deprecated* Always use Unicode objects, or `as_utf8` if you really want.
219
220 :return: UTF-8 encoded JID."""
221 warnings.warn("JID.as_string() is deprecated. Use unicode() or `as_utf8` instead.",
222 DeprecationWarning, stacklevel=1)
223 return self.as_utf8()
224
226 """Unicode string JID representation.
227
228 :return: JID as Unicode string."""
229 r=self.domain
230 if self.node:
231 r=self.node+u'@'+r
232 if self.resource:
233 r=r+u'/'+self.resource
234 if not JID.cache.has_key(r):
235 JID.cache[r]=self
236 return r
237
239 """Make bare JID made by removing resource from current `self`.
240
241 :return: new JID object without resource part."""
242 return JID(self.node,self.domain,check=False)
243
245 if other is None:
246 return False
247 elif type(other) in (str, unicode):
248 try:
249 other=JID(other)
250 except:
251 return False
252 elif not isinstance(other,JID):
253 return False
254
255 return (self.node==other.node
256 and are_domains_equal(self.domain,other.domain)
257 and self.resource==other.resource)
258
260 return not self.__eq__(other)
261
265
268
269
270