Пример #1
0
    def sendop(self, jid, methname, *methargs, **keywords):
        """sendop() -- utility function for send(). Do not call.
        """

        timeout = keywords.pop('timeout', None)
        if (keywords):
            raise ValueError, 'unknown keyword argument to send'

        msg = interface.Node('iq', attrs={'to': unicode(jid), 'type': 'set'})
        qnod = msg.setchild('query', namespace=interface.NS_RPC)
        methnod = rpcdata.makecall(methname, *methargs)
        qnod.addchild(methnod)

        id = self.agent.send(msg)

        defer = sched.Deferred(self.handlesend)

        dsp = self.agent.adddispatcher(defer.queue,
                                       self.agent,
                                       'result',
                                       name='iq',
                                       type=('result', 'error'),
                                       id=id,
                                       accept=True)
        if (timeout != None):
            ac = self.agent.addtimer(defer, 'timeout', delay=timeout)
        defer.addaction(ac)

        raise defer
Пример #2
0
def makeparams(argls):
    """makeparams(argls) -> Node

    Return a <params> node containing the list of arguments *argls*,
    in XML-RPC format.

    The arguments are converted with makevalue(), so you can pass in either
    RPCType objects or Python data.
    """

    parnod = interface.Node('params')
    for arg in argls:
        pnod = interface.Node('param')
        valnod = makevalue(arg)
        pnod.addchild(valnod)
        parnod.addchild(pnod)
    return parnod
Пример #3
0
def makefaultresponse(faultcode, faultstring=''):
    """makefaultresponse(faultcode [, faultstring='']) -> Node

    Return a <methodResponse> node containing a <fault> with the given
    *faultcode* and *faultstring*.

    *faultcode* must be an int, and *faultstring* a string (or values
    convertable to those types). Do not pass RPCInt or RPCString objects.
    """

    rpccode = RPCInt(faultcode)
    rpcstring = RPCString(faultstring)
    callnod = interface.Node('methodResponse')
    faultnod = interface.Node('fault')
    callnod.addchild(faultnod)
    valnod = makevalue(RPCStruct(faultCode=rpccode, faultString=rpcstring))
    faultnod.addchild(valnod)
    return callnod
Пример #4
0
def makediscoitems(items):
    """makediscoitems(items) -> Node

    Given a DiscoItems object, return a <query> node in the disco#items
    namespace, containing the item list.
    """

    qnod = interface.Node('query')
    qnod.setnamespace(interface.NS_DISCO_ITEMS)

    for (jid, name, node) in items.items:
        nod = interface.Node('item', attrs={'jid': jid})
        if (name):
            nod.setattr('name', name)
        if (node):
            nod.setattr('node', node)
        qnod.addchild(nod)

    return qnod
Пример #5
0
def makediscofeatures(features):
    """makediscofeatures(list) -> list

    Given a list of strings, return a list of <feature> nodes.
    """

    ls = []
    for st in features:
        nod = interface.Node('feature', attrs={'var': st})
        ls.append(nod)
    return ls
Пример #6
0
    def set(self, avail=True):
        """set(avail=True) -> None

        Initially, you are unavailable. If you call set(), you are
        available. If you call set(False), you're unavailable. I
        told you it was simplistic.

        You should not call this method until the Jabber connection has
        reached the 'authresource' state.
        """

        avail = bool(avail)
        if (self.available == avail):
            return

        if (avail):
            self.log.debug('announcing available')
            msg = interface.Node('presence')
            try:
                for hook in self.hooklist:
                    res = hook(msg)
                    if (res != None):
                        msg = res
                self.agent.send(msg, addid=False, addfrom=False)
            except interface.StanzaHandled:
                pass
        else:
            self.log.debug('announcing unavailable')
            msg = interface.Node('presence', attrs={'type':'unavailable'})
            try:
                for hook in self.hooklist:
                    res = hook(msg)
                    if (res != None):
                        msg = res
                self.agent.send(msg, addid=False)
            except interface.StanzaHandled:
                pass
        
        self.available = avail
Пример #7
0
    def makenode(self):
        """makenode() -> Node
        
        Convert the form to a Node tree. The returned node will be an
        <x> node in the 'jabber:x:data' namespace.
        """
        
        dic = { 'type':'result' }
        formnod = interface.Node('x', dic)
        formnod.setnamespace(interface.NS_DATA)

        for (var, val, label, typ) in self.fields:
            dic = { 'var':var }
            if (label):
                dic['label'] = label
            if (typ):
                dic['type'] = typ
            nod = interface.Node('field', dic)
            nod.setchilddata('value', val)
            formnod.addchild(nod)

        return formnod
Пример #8
0
def makediscoidentities(identities):
    """makediscoidentities(list) -> list

    Given a list of (category, type, name) tuples, return a list of
    <identity> nodes.
    """

    ls = []
    for (cat, typ, name) in identities:
        nod = interface.Node('identity', attrs={'category': cat, 'type': typ})
        if (name):
            nod.setattr('name', name)
        ls.append(nod)
    return ls
Пример #9
0
def makecall(method, *argls):
    """makecall(method, [ arg1, arg2, ... ]) -> Node

    Return a <methodCall> node containing the <methodName> *method*,
    and the <params> given by the succeeding arguments *argls*.

    The arguments (if any) are converted with makevalue(), so you can pass 
    in either RPCType objects or Python data.
    """

    if (not nameisvalid(method)):
        raise ValueError('\'' + method + '\' is not a valid method name')
    callnod = interface.Node('methodCall')
    callnod.setchilddata('methodName', method)
    if (argls):
        parnod = makeparams(argls)
        callnod.addchild(parnod)
    return callnod
Пример #10
0
    def deferreditemswrapper(self, tup, jidstr, id):
        """deferreditemswrapper(tup, jidstr, id) -- callback for deferred
        handlers.

        This is used by handlegetitems(), for the case where a disco handler
        wants to undertake a deferral operation. You should not call it,
        or even try to understand it.
        """

        items = sched.Deferred.extract(tup)
        if (not isinstance(items, DiscoItems)):
            raise TypeError('items must be or return a DiscoItems')

        msg = interface.Node('iq',
            attrs={ 'to':jidstr, 'type':'result', 'id':id })
        qnod = discodata.makediscoitems(items)
        msg.addchild(qnod)

        self.agent.send(msg)
Пример #11
0
def makediscoinfo(info):
    """makediscoinfo(info) -> Node

    Given a DiscoInfo object, return a <query> node in the disco#info
    namespace, containing the identities, features, and extended info.
    """

    qnod = interface.Node('query')
    qnod.setnamespace(interface.NS_DISCO_INFO)

    for nod in makediscoidentities(info.identities):
        qnod.addchild(nod)
    for nod in makediscofeatures(info.features):
        qnod.addchild(nod)
    if (info.extended):
        nod = makediscoextended(info.extended)
        qnod.addchild(nod)

    return qnod
Пример #12
0
def makeresponse(arg=True):
    """makeresponse(arg=True) -> Node

    Return a <methodResponse> node containing the <params> given
    by the argument *arg*.

    The argument is converted with makevalue(), so you can pass 
    in either an RPCType object or Python data.

    An RPC response requires a value. There is no equivalent of null/None,
    so if you pass that in here, it is taken to be (boolean) True.
    """

    callnod = interface.Node('methodResponse')
    if (arg == None):
        arg = True
    parnod = makeparams([arg])
    callnod.addchild(parnod)
    return callnod
Пример #13
0
    def queryitemsop(self, jid, node=None, timeout=None):
        """queryitemsop() -- utility function for queryitems(). Do not call.
        """
        
        msg = interface.Node('iq',
            attrs={ 'to':unicode(jid), 'type':'get' })
        qnod = msg.setchild('query', namespace=interface.NS_DISCO_ITEMS)
        if (node):
            qnod.setattr('node', unicode(node))

        id = self.agent.send(msg)
        
        defer = sched.Deferred(self.handlequeryitems)

        dsp = self.agent.adddispatcher(defer.queue, self.agent, 'result',
            name='iq', type=('result','error'), id=id, accept=True)
        if (timeout != None):
            ac = self.agent.addtimer(defer, 'timeout', delay=timeout)
        defer.addaction(ac)

        raise defer
Пример #14
0
class DiscoService(service.Service):
    """DiscoService: A high-level Jabber facility for responding to service
    discovery queries from other entities.

    (Service label: 'discoservice'.)

    The DiscoService is a generic framework for disco queries (both info
    and items). It receives the query stanza and then looks up the results
    in the information you have supplied.

    You can set up info and items replies for any query node
    (including the default "no node specified" query). You do this by
    calling the service's addinfo() and additems() methods. You can
    provide either an DiscoInfo / DiscoItems instance (see the
    discodata module for these classes), or a callable which does one
    of the following:

    * Return a DiscoInfo / DiscoItems instance (as appropriate).
    * Raise an interface.StanzaError. This will cause the query to be replied
        to with the given stanza-level error.
    * Raise some other kind of Exception. This will become a stanza-level
        'internal-server-error' error.
    * Raise a sched.Deferred(op). This is a promise that you will eventually
        invoke the Deferred object. That will result in *op* being called;
        and the *op* should then do one of the things on this list.

    DiscoService() -- constructor.

    Public methods:

    addinfo() -- add an info query response.
    getinfo() -- get an info query response.
    additems() -- add an items query response.
    getitems() -- get an items query response.

    Internal methods:

    attach() -- attach this Service to a JabberStream.
    handleget() -- disco stanza handler.
    handlegetinfo() -- disco stanza handler.
    handlegetitems() -- disco stanza handler.
    deferredinfowrapper() -- callback for deferred handlers.
    deferreditemswrapper() -- callback for deferred handlers.
    """
    
    label = 'discoservice'
    logprefix = 'zymb.jabber.disco'
    
    def __init__(self):
        service.Service.__init__(self)

        self.info = {}
        self.items = {}

    def attach(self, agent):
        """attach() -- internal method to attach this Service to a
        JabberStream. Do not call this directly. Instead, call
        jstream.addservice(service).

        This calls the inherited class method, and then sets up the
        stanza dispatcher which catches incoming disco queries.
        """
        
        service.Service.attach(self, agent)
        self.agent.adddispatcher(self.handleget, name='iq', type='get')

    def addinfo(self, node=None, info=None):
        """addinfo(node=None, info=None) -> DiscoInfo or callable

        Add a response for disco-info queries to the given *node*. If *node*
        is None, the response applies to queries that have no node attribute.

        The *info* should be either a DiscoInfo object, a function which
        returns a DiscoInfo object, or None. (If None, a new DiscoInfo
        is generated and initialized with the
        'http://jabber.org/protocol/disco#info' and
        'http://jabber.org/protocol/disco#items' features.)

        The return value is the *info* you passed in, or the newly-generated
        DiscoInfo if you passed None.
        """
        
        if (not info):
            info = DiscoInfo()
            info.addfeature(interface.NS_DISCO_INFO)
            info.addfeature(interface.NS_DISCO_ITEMS)

        self.info[node] = info
        return info

    def getinfo(self, node=None):
        """getinfo(node=None) -> DiscoInfo or callable

        Return the response set for disco-info queries to the given *node*.
        If *node* is None, the response applies to queries that have no node
        attribute.
        """
        
        return self.info.get(node)

    def additems(self, node=None, items=None):
        """additems(node=None, items=None) -> DiscoItems or callable

        Add a response for disco-items queries to the given *node*. If *node*
        is None, the response applies to queries that have no node attribute.

        The *items* should be either a DiscoItems object, a function which
        returns a DiscoItems object, or None. (If None, a new DiscoItems
        is generated.)

        The return value is the *items* you passed in, or the newly-generated
        DiscoItems if you passed None.
        """
        
        if (not items):
            items = DiscoItems()
            
        self.items[node] = items
        return items

    def getitems(self, node=None):
        """getitems(node=None) -> DiscoItems or callable

        Return the response set for disco-items queries to the given *node*.
        If *node* is None, the response applies to queries that have no node
        attribute.
        """
        
        return self.items.get(node)

    def handleget(self, msg):
        """handleget() -- disco stanza handler. Do not call.

        This checks to see if the query stanza is in a disco query namespace.
        If so, it calls handlegetinfo or handlegetitems.
        """
        
        qnod = msg.getchild('query')
        if (not qnod):
            return

        ns = qnod.getnamespace()
        
        if (ns == interface.NS_DISCO_INFO):
            fromstr = msg.getattr('from')
            id = msg.getattr('id')
            node = qnod.getattr('node')
            self.handlegetinfo(fromstr, id, node)
            return
            
        if (ns == interface.NS_DISCO_ITEMS):
            fromstr = msg.getattr('from')
            id = msg.getattr('id')
            node = qnod.getattr('node')
            self.handlegetitems(fromstr, id, node)
            return

        # Not a disco query after all
        return

    def handlegetinfo(self, jidstr, id, node=None):
        """handlegetinfo() -- disco stanza handler. Do not call.
        """
        
        self.log.debug('Disco#info from <%s>, id %s, node %s',
            jidstr, id, node)

        if (not self.info.has_key(node)):
            if (not node):
                raise interface.StanzaItemNotFound('info does not exist')
            else:
                raise interface.StanzaItemNotFound('info for node "%s" does not exist' % node)

        info = self.info[node]
        if (not isinstance(info, DiscoInfo)):
            try:
                info = info()
            except sched.Deferred, ex:
                ex.addcontext(self.deferredinfowrapper, jidstr, id)
                raise
            if (not isinstance(info, DiscoInfo)):
                raise TypeError('info must be or return a DiscoInfo')

        msg = interface.Node('iq',
            attrs={ 'to':jidstr, 'type':'result', 'id':id })
        qnod = discodata.makediscoinfo(info)
        msg.addchild(qnod)
        
        self.agent.send(msg)
        raise interface.StanzaHandled
Пример #15
0
            if (not node):
                raise interface.StanzaItemNotFound('items do not exist')
            else:
                raise interface.StanzaItemNotFound('items for node "%s" do not exist' % node)

        items = self.items[node]
        if (not isinstance(items, DiscoItems)):
            try:
                items = items()
            except sched.Deferred, ex:
                ex.addcontext(self.deferreditemswrapper, jidstr, id)
                raise
            if (not isinstance(items, DiscoItems)):
                raise TypeError('items must be or return a DiscoItems')
        
        msg = interface.Node('iq',
            attrs={ 'to':jidstr, 'type':'result', 'id':id })
        qnod = discodata.makediscoitems(items)
        msg.addchild(qnod)

        self.agent.send(msg)
        raise interface.StanzaHandled

    def deferreditemswrapper(self, tup, jidstr, id):
        """deferreditemswrapper(tup, jidstr, id) -- callback for deferred
        handlers.

        This is used by handlegetitems(), for the case where a disco handler
        wants to undertake a deferral operation. You should not call it,
        or even try to understand it.
        """
Пример #16
0
 def buildnode(self):
     valnod = interface.Node('value')
     valnod.setchilddata(self.typename, self.argstring)
     return valnod