1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16  """Basic Jabber client functionality implementation. 
 17   
 18  Extends `pyxmpp.client` interface with legacy authentication 
 19  and basic Service Discovery handling. 
 20   
 21  Normative reference: 
 22    - `JEP 78 <http://www.jabber.org/jeps/jep-0078.html>`__ 
 23    - `JEP 30 <http://www.jabber.org/jeps/jep-0030.html>`__ 
 24  """ 
 25   
 26  __revision__="$Id: client.py 656 2006-08-31 20:13:46Z jajcus $" 
 27  __docformat__="restructuredtext en" 
 28   
 29  import logging 
 30   
 31  from pyxmpp.jabber.clientstream import LegacyClientStream 
 32  from pyxmpp.jabber.disco import DISCO_ITEMS_NS,DISCO_INFO_NS 
 33  from pyxmpp.jabber.disco import DiscoInfo,DiscoItems,DiscoIdentity 
 34  from pyxmpp.jabber import disco 
 35  from pyxmpp.client import Client 
 36  from pyxmpp.stanza import Stanza 
 37  from pyxmpp.cache import CacheSuite 
 38  from pyxmpp.utils import from_utf8 
 39  from pyxmpp.interfaces import IFeaturesProvider 
 40   
 42      """Base class for a Jabber client. 
 43   
 44      :Ivariables: 
 45          - `disco_items`: default Disco#items reply for a query to an empty node. 
 46          - `disco_info`: default Disco#info reply for a query to an empty node -- 
 47            provides information about the client and its supported fetures. 
 48          - `disco_identity`: default identity of the default `disco_info`. 
 49          - `register`: when `True` than registration will be started instead of authentication. 
 50      :Types: 
 51          - `disco_items`: `DiscoItems` 
 52          - `disco_info`: `DiscoInfo` 
 53          - `register`: `bool` 
 54      """ 
 55 -    def __init__(self,jid=None, password=None, server=None, port=5222, 
 56              auth_methods=("sasl:DIGEST-MD5","digest"), 
 57              tls_settings=None, keepalive=0, 
 58              disco_name=u"pyxmpp based Jabber client", disco_category=u"client", 
 59              disco_type=u"pc"): 
  60          """Initialize a JabberClient object. 
 61   
 62          :Parameters: 
 63              - `jid`: user full JID for the connection. 
 64              - `password`: user password. 
 65              - `server`: server to use. If not given then address will be derived form the JID. 
 66              - `port`: port number to use. If not given then address will be derived form the JID. 
 67              - `auth_methods`: sallowed authentication methods. SASL authentication mechanisms 
 68                in the list should be prefixed with "sasl:" string. 
 69              - `tls_settings`: settings for StartTLS -- `TLSSettings` instance. 
 70              - `keepalive`: keepalive output interval. 0 to disable. 
 71              - `disco_name`: name of the client identity in the disco#info 
 72                replies. 
 73              - `disco_category`: category of the client identity in the disco#info 
 74                replies. The default of u'client' should be the right choice in 
 75                most cases. 
 76              - `disco_type`: type of the client identity in the disco#info 
 77                replies. Use `the types registered by Jabber Registrar <http://www.jabber.org/registrar/disco-categories.html>`__ 
 78          :Types: 
 79              - `jid`: `pyxmpp.JID` 
 80              - `password`: `unicode` 
 81              - `server`: `unicode` 
 82              - `port`: `int` 
 83              - `auth_methods`: sequence of `str` 
 84              - `tls_settings`: `pyxmpp.TLSSettings` 
 85              - `keepalive`: `int` 
 86              - `disco_name`: `unicode` 
 87              - `disco_category`: `unicode` 
 88              - `disco_type`: `unicode` 
 89          """ 
 90   
 91          Client.__init__(self,jid,password,server,port,auth_methods,tls_settings,keepalive) 
 92          self.stream_class = LegacyClientStream 
 93          self.disco_items=DiscoItems() 
 94          self.disco_info=DiscoInfo() 
 95          self.disco_identity=DiscoIdentity(self.disco_info, 
 96                              disco_name, disco_category, disco_type) 
 97          self.register_feature(u"dnssrv") 
 98          self.register_feature(u"stringprep") 
 99          self.register_feature(u"urn:ietf:params:xml:ns:xmpp-sasl#c2s") 
100          self.cache = CacheSuite(max_items = 1000) 
101          self.__logger = logging.getLogger("pyxmpp.jabber.JabberClient") 
 102   
103   
104   
105 -    def connect(self, register = False): 
 106          """Connect to the server and set up the stream. 
107   
108          Set `self.stream` and notify `self.state_changed` when connection 
109          succeeds. Additionally, initialize Disco items and info of the client. 
110          """ 
111          Client.connect(self, register) 
112          if register: 
113              self.stream.registration_callback = self.process_registration_form 
 114   
116          """Register a feature to be announced by Service Discovery. 
117   
118          :Parameters: 
119              - `feature_name`: feature namespace or name. 
120          :Types: 
121              - `feature_name`: `unicode`""" 
122          self.disco_info.add_feature(feature_name) 
 123   
125          """Unregister a feature to be announced by Service Discovery. 
126   
127          :Parameters: 
128              - `feature_name`: feature namespace or name. 
129          :Types: 
130              - `feature_name`: `unicode`""" 
131          self.disco_info.remove_feature(feature_name) 
 132   
141   
142   
144          """Handle a disco#info request. 
145   
146          `self.disco_get_info` method will be used to prepare the query response. 
147   
148          :Parameters: 
149              - `iq`: the IQ stanza received. 
150          :Types: 
151              - `iq`: `pyxmpp.iq.Iq`""" 
152          q=iq.get_query() 
153          if q.hasProp("node"): 
154              node=from_utf8(q.prop("node")) 
155          else: 
156              node=None 
157          info=self.disco_get_info(node,iq) 
158          if isinstance(info,DiscoInfo): 
159              resp=iq.make_result_response() 
160              self.__logger.debug("Disco-info query: %s preparing response: %s with reply: %s" 
161                  % (iq.serialize(),resp.serialize(),info.xmlnode.serialize())) 
162              resp.set_content(info.xmlnode.copyNode(1)) 
163          elif isinstance(info,Stanza): 
164              resp=info 
165          else: 
166              resp=iq.make_error_response("item-not-found") 
167          self.__logger.debug("Disco-info response: %s" % (resp.serialize(),)) 
168          self.stream.send(resp) 
 169   
196   
207   
208   
209   
217   
219          """Return Disco#info data for a node. 
220   
221          :Parameters: 
222              - `node`: the node queried. 
223              - `iq`: the request stanza received. 
224          :Types: 
225              - `node`: `unicode` 
226              - `iq`: `pyxmpp.iq.Iq` 
227   
228          :return: self.disco_info if `node` is empty or `None` otherwise. 
229          :returntype: `DiscoInfo`""" 
230          to=iq.get_to() 
231          if to and to!=self.jid: 
232              return iq.make_error_response("recipient-unavailable") 
233          if not node and self.disco_info: 
234              return self.disco_info 
235          return None 
 236   
238          """Return Disco#items data for a node. 
239   
240          :Parameters: 
241              - `node`: the node queried. 
242              - `iq`: the request stanza received. 
243          :Types: 
244              - `node`: `unicode` 
245              - `iq`: `pyxmpp.iq.Iq` 
246   
247          :return: self.disco_info if `node` is empty or `None` otherwise. 
248          :returntype: `DiscoInfo`""" 
249          to=iq.get_to() 
250          if to and to!=self.jid: 
251              return iq.make_error_response("recipient-unavailable") 
252          if not node and self.disco_items: 
253              return self.disco_items 
254          return None 
 255   
 286   
287   
288