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