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