Package xmpp :: Module features

[hide private]
[frames] | no frames]

# Source Code for Module xmpp.features

      1  ##   features.py
      2  ##
      3  ##   Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
      4  ##
      5  ##   This program is free software; you can redistribute it and/or modify
      6  ##   it under the terms of the GNU General Public License as published by
      7  ##   the Free Software Foundation; either version 2, or (at your option)
      8  ##   any later version.
      9  ##
     10  ##   This program is distributed in the hope that it will be useful,
     11  ##   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  ##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  ##   GNU General Public License for more details.
     14
     15  # $Id: features.py,v 1.24 2006/03/25 05:47:22 snakeru Exp $
     16
     17  """
     18  This module contains variable stuff that is not worth splitting into separate modules.
     19  Here is:
     20      DISCO client and agents-to-DISCO and browse-to-DISCO emulators.
     21      IBR and password manager.
     22      jabber:iq:privacy methods
     23  All these methods takes 'disp' first argument that should be already connected
     24  (and in most cases already authorised) dispatcher instance.
     25  """
     26
     27  from protocol import *
     28
     29  REGISTER_DATA_RECEIVED='REGISTER DATA RECEIVED'
     30
     31  ### DISCO ### http://jabber.org/protocol/disco ### JEP-0030 ####################
     32  ### Browse ### jabber:iq:browse ### JEP-0030 ###################################
     33  ### Agents ### jabber:iq:agents ### JEP-0030 ###################################
     34 -def _discover(disp,ns,jid,node=None,fb2b=0,fb2a=1):
     35      """ Try to obtain info from the remote object.
     36          If remote object doesn't support disco fall back to browse (if fb2b is true)
     37          and if it doesnt support browse (or fb2b is not true) fall back to agents protocol
     38          (if gb2a is true). Returns obtained info. Used internally. """
     39      iq=Iq(to=jid,typ='get',queryNS=ns)
     40      if node: iq.setQuerynode(node)
     41      rep=disp.SendAndWaitForResponse(iq)
     42      if fb2b and not isResultNode(rep): rep=disp.SendAndWaitForResponse(Iq(to=jid,typ='get',queryNS=NS_BROWSE))   # Fallback to browse
     43      if fb2a and not isResultNode(rep): rep=disp.SendAndWaitForResponse(Iq(to=jid,typ='get',queryNS=NS_AGENTS))   # Fallback to agents
     44      if isResultNode(rep): return rep.getQueryPayload()
     45      return []
     46
     47 -def discoverItems(disp,jid,node=None):
     48      """ Query remote object about any items that it contains. Return items list. """
     49      """ According to JEP-0030:
     50          query MAY have node attribute
     51          item: MUST HAVE jid attribute and MAY HAVE name, node, action attributes.
     52          action attribute of item can be either of remove or update value."""
     53      ret=[]
     54      for i in _discover(disp,NS_DISCO_ITEMS,jid,node):
     55          if i.getName()=='agent' and i.getTag('name'): i.setAttr('name',i.getTagData('name'))
     56          ret.append(i.attrs)
     57      return ret
     58
     59 -def discoverInfo(disp,jid,node=None):
     60      """ Query remote object about info that it publishes. Returns identities and features lists."""
     61      """ According to JEP-0030:
     62          query MAY have node attribute
     63          identity: MUST HAVE category and name attributes and MAY HAVE type attribute.
     64          feature: MUST HAVE var attribute"""
     65      identities , features = [] , []
     66      for i in _discover(disp,NS_DISCO_INFO,jid,node):
     67          if i.getName()=='identity': identities.append(i.attrs)
     68          elif i.getName()=='feature': features.append(i.getAttr('var'))
     69          elif i.getName()=='agent':
     70              if i.getTag('name'): i.setAttr('name',i.getTagData('name'))
     71              if i.getTag('description'): i.setAttr('name',i.getTagData('description'))
     72              identities.append(i.attrs)
     73              if i.getTag('groupchat'): features.append(NS_GROUPCHAT)
     74              if i.getTag('register'): features.append(NS_REGISTER)
     75              if i.getTag('search'): features.append(NS_SEARCH)
     76      return identities , features
     77
     78  ### Registration ### jabber:iq:register ### JEP-0077 ###########################
     79 -def getRegInfo(disp,host,info={},sync=True):
     80      """ Gets registration form from remote host.
     81          You can pre-fill the info dictionary.
     82          F.e. if you are requesting info on registering user joey than specify
     83          info as {'username':'joey'}. See JEP-0077 for details.
     84          'disp' must be connected dispatcher instance."""
     85      iq=Iq('get',NS_REGISTER,to=host)
     86      for i in info.keys(): iq.setTagData(i,info[i])
     87      if sync:
     88          resp=disp.SendAndWaitForResponse(iq)
     89          _ReceivedRegInfo(disp.Dispatcher,resp, host)
     90          return resp
     91      else: disp.SendAndCallForResponse(iq,_ReceivedRegInfo, {'agent': host})
     92
     93 -def _ReceivedRegInfo(con, resp, agent):
     94      iq=Iq('get',NS_REGISTER,to=agent)
     95      if not isResultNode(resp): return
     96      df=resp.getTag('query',namespace=NS_REGISTER).getTag('x',namespace=NS_DATA)
     97      if df:
     98          con.Event(NS_REGISTER,REGISTER_DATA_RECEIVED,(agent, DataForm(node=df)))
     99          return
    100      df=DataForm(typ='form')
    101      for i in resp.getQueryPayload():
    102          if type(i)<>type(iq): pass
    103          elif i.getName()=='instructions': df.addInstructions(i.getData())
    104          else: df.setField(i.getName()).setValue(i.getData())
    105      con.Event(NS_REGISTER,REGISTER_DATA_RECEIVED,(agent, df))
    106
    107 -def register(disp,host,info):
    108      """ Perform registration on remote server with provided info.
    109          disp must be connected dispatcher instance.
    110          Returns true or false depending on registration result.
    111          If registration fails you can get additional info from the dispatcher's owner
    112          attributes lastErrNode, lastErr and lastErrCode.
    113      """
    114      iq=Iq('set',NS_REGISTER,to=host)
    115      if type(info)<>type({}): info=info.asDict()
    116      for i in info.keys(): iq.setTag('query').setTagData(i,info[i])
    117      resp=disp.SendAndWaitForResponse(iq)
    118      if isResultNode(resp): return 1
    119
    120 -def unregister(disp,host):
    121      """ Unregisters with host (permanently removes account).
    122          disp must be connected and authorized dispatcher instance.
    123          Returns true on success."""
    124      resp=disp.SendAndWaitForResponse(Iq('set',NS_REGISTER,to=host,payload=[Node('remove')]))
    125      if isResultNode(resp): return 1
    126
    127 -def changePasswordTo(disp,newpassword,host=None):
    128      """ Changes password on specified or current (if not specified) server.
    129          disp must be connected and authorized dispatcher instance.
    130          Returns true on success."""
    131      if not host: host=disp._owner.Server
    132      resp=disp.SendAndWaitForResponse(Iq('set',NS_REGISTER,to=host,payload=[Node('username',payload=[disp._owner.Server]),Node('password',payload=[newpassword])]))
    133      if isResultNode(resp): return 1
    134
    135  ### Privacy ### jabber:iq:privacy ### draft-ietf-xmpp-im-19 ####################
    136  #type=[jid|group|subscription]
    137  #action=[allow|deny]
    138
    139 -def getPrivacyLists(disp):
    140      """ Requests privacy lists from connected server.
    141          Returns dictionary of existing lists on success."""
    142      try:
    143          dict={'lists':[]}
    144          resp=disp.SendAndWaitForResponse(Iq('get',NS_PRIVACY))
    145          if not isResultNode(resp): return
    146          for list in resp.getQueryPayload():
    147              if list.getName()=='list': dict['lists'].append(list.getAttr('name'))
    148              else: dict[list.getName()]=list.getAttr('name')
    149          return dict
    150      except: pass
    151
    152 -def getPrivacyList(disp,listname):
    153      """ Requests specific privacy list listname. Returns list of XML nodes (rules)
    154          taken from the server responce."""
    155      try:
    156          resp=disp.SendAndWaitForResponse(Iq('get',NS_PRIVACY,payload=[Node('list',{'name':listname})]))
    157          if isResultNode(resp): return resp.getQueryPayload()[0]
    158      except: pass
    159
    160 -def setActivePrivacyList(disp,listname=None,typ='active'):
    161      """ Switches privacy list 'listname' to specified type.
    162          By default the type is 'active'. Returns true on success."""
    163      if listname: attrs={'name':listname}
    164      else: attrs={}
    165      resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[Node(typ,attrs)]))
    166      if isResultNode(resp): return 1
    167
    168 -def setDefaultPrivacyList(disp,listname=None):
    169      """ Sets the default privacy list as 'listname'. Returns true on success."""
    170      return setActivePrivacyList(disp,listname,'default')
    171
    172 -def setPrivacyList(disp,list):
    173      """ Set the ruleset. 'list' should be the simpleXML node formatted
    174          according to RFC 3921 (XMPP-IM) (I.e. Node('list',{'name':listname},payload=[...]) )
    175          Returns true on success."""
    176      resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[list]))
    177      if isResultNode(resp): return 1
    178
    179 -def delPrivacyList(disp,listname):
    180      """ Deletes privacy list 'listname'. Returns true on success."""
    181      resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[Node('list',{'name':listname})]))
    182      if isResultNode(resp): return 1
    183