Package pyxmpp :: Module jid
[hide private]

Source Code for Module pyxmpp.jid

  1  # 
  2  # (C) Copyright 2003-2006 Jacek Konieczny <jajcus@jajcus.net> 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU Lesser General Public License Version 
  6  # 2.1 as published by the Free Software Foundation. 
  7  # 
  8  # This program is distributed in the hope that it will be useful, 
  9  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 11  # GNU Lesser General Public License for more details. 
 12  # 
 13  # You should have received a copy of the GNU Lesser General Public 
 14  # License along with this program; if not, write to the Free Software 
 15  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 16  # 
 17  # pylint: disable-msg=W0232, E0201 
 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   
40 -def are_domains_equal(a,b):
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
52 -class JID(object):
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
110 - def __setattr__(self,name,value):
111 raise RuntimeError,"JID objects are immutable!"
112
113 - def __from_unicode(self,s,check=True):
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
145 - def __set_node(self,s):
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
182 - def __set_resource(self,s):
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
200 - def __str__(self):
201 warnings.warn("JIDs should not be used as strings", DeprecationWarning, stacklevel=2) 202 return self.as_utf8()
203
204 - def __unicode__(self):
205 return self.as_unicode()
206
207 - def __repr__(self):
208 return "<JID: %r>" % (self.as_unicode())
209
210 - def as_utf8(self):
211 """UTF-8 encoded JID representation. 212 213 :return: UTF-8 encoded JID.""" 214 return self.as_unicode().encode("utf-8")
215
216 - def as_string(self):
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
226 - def as_unicode(self):
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
239 - def bare(self):
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
245 - def __eq__(self,other):
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
260 - def __ne__(self,other):
261 return not self.__eq__(other)
262
263 - def __cmp__(self,other):
264 a=self.as_unicode() 265 return cmp(a,other)
266
267 - def __hash__(self):
268 return hash(self.node)^hash(self.domain)^hash(self.resource)
269 270 # vi: sts=4 et sw=4 271