2 SleekXMPP: The Sleek XMPP Library
3 Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON).
4 This file is part of SleekXMPP.
6 See the file LICENSE for copying permission.
9 from sleekxmpp
.plugins
import base
10 from sleekxmpp
.plugins
.xep_0009
.stanza
.RPC
import RPCQuery
, MethodCall
, MethodResponse
11 from sleekxmpp
.stanza
.iq
import Iq
12 from sleekxmpp
.xmlstream
.handler
.callback
import Callback
13 from sleekxmpp
.xmlstream
.matcher
.xpath
import MatchXPath
14 from sleekxmpp
.xmlstream
.stanzabase
import register_stanza_plugin
15 from xml
.etree
import cElementTree
as ET
20 log
= logging
.getLogger(__name__
)
24 class xep_0009(base
.base_plugin
):
26 def plugin_init(self
):
28 self
.description
= 'Jabber-RPC'
29 #self.stanza = sleekxmpp.plugins.xep_0009.stanza
31 register_stanza_plugin(Iq
, RPCQuery
)
32 register_stanza_plugin(RPCQuery
, MethodCall
)
33 register_stanza_plugin(RPCQuery
, MethodResponse
)
35 self
.xmpp
.registerHandler(
36 Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self
.xmpp
.default_ns
, RPCQuery
.namespace
, RPCQuery
.namespace
)),
37 self
._handle
_method
_call
)
39 self
.xmpp
.registerHandler(
40 Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self
.xmpp
.default_ns
, RPCQuery
.namespace
, RPCQuery
.namespace
)),
41 self
._handle
_method
_response
)
43 self
.xmpp
.registerHandler(
44 Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self
.xmpp
.default_ns
, self
.xmpp
.default_ns
)),
47 self
.xmpp
.add_event_handler('jabber_rpc_method_call', self
._on
_jabber
_rpc
_method
_call
)
48 self
.xmpp
.add_event_handler('jabber_rpc_method_response', self
._on
_jabber
_rpc
_method
_response
)
49 self
.xmpp
.add_event_handler('jabber_rpc_method_fault', self
._on
_jabber
_rpc
_method
_fault
)
50 self
.xmpp
.add_event_handler('jabber_rpc_error', self
._on
_jabber
_rpc
_error
)
51 self
.xmpp
.add_event_handler('error', self
._handle
_error
)
52 #self.activeCalls = []
55 base
.base_plugin
.post_init(self
)
56 self
.xmpp
.plugin
['xep_0030'].add_feature('jabber:iq:rpc')
57 self
.xmpp
.plugin
['xep_0030'].add_identity('automation','rpc')
59 def make_iq_method_call(self
, pto
, pmethod
, params
):
60 iq
= self
.xmpp
.makeIqSet()
62 iq
.attrib
['from'] = self
.xmpp
.boundjid
.full
63 iq
.enable('rpc_query')
64 iq
['rpc_query']['method_call']['method_name'] = pmethod
65 iq
['rpc_query']['method_call']['params'] = params
68 def make_iq_method_response(self
, pid
, pto
, params
):
69 iq
= self
.xmpp
.makeIqResult(pid
)
71 iq
.attrib
['from'] = self
.xmpp
.boundjid
.full
72 iq
.enable('rpc_query')
73 iq
['rpc_query']['method_response']['params'] = params
76 def make_iq_method_response_fault(self
, pid
, pto
, params
):
77 iq
= self
.xmpp
.makeIqResult(pid
)
79 iq
.attrib
['from'] = self
.xmpp
.boundjid
.full
80 iq
.enable('rpc_query')
81 iq
['rpc_query']['method_response']['params'] = None
82 iq
['rpc_query']['method_response']['fault'] = params
85 # def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition):
86 # iq = self.xmpp.makeIqError(pid)
87 # iq.attrib['to'] = pto
88 # iq.attrib['from'] = self.xmpp.boundjid.full
89 # iq['error']['code'] = code
90 # iq['error']['type'] = type
91 # iq['error']['condition'] = condition
92 # iq['rpc_query']['method_call']['method_name'] = pmethod
93 # iq['rpc_query']['method_call']['params'] = params
96 def _item_not_found(self
, iq
):
97 payload
= iq
.get_payload()
98 iq
.reply().error().set_payload(payload
);
99 iq
['error']['code'] = '404'
100 iq
['error']['type'] = 'cancel'
101 iq
['error']['condition'] = 'item-not-found'
104 def _undefined_condition(self
, iq
):
105 payload
= iq
.get_payload()
106 iq
.reply().error().set_payload(payload
)
107 iq
['error']['code'] = '500'
108 iq
['error']['type'] = 'cancel'
109 iq
['error']['condition'] = 'undefined-condition'
112 def _forbidden(self
, iq
):
113 payload
= iq
.get_payload()
114 iq
.reply().error().set_payload(payload
)
115 iq
['error']['code'] = '403'
116 iq
['error']['type'] = 'auth'
117 iq
['error']['condition'] = 'forbidden'
120 def _recipient_unvailable(self
, iq
):
121 payload
= iq
.get_payload()
122 iq
.reply().error().set_payload(payload
)
123 iq
['error']['code'] = '404'
124 iq
['error']['type'] = 'wait'
125 iq
['error']['condition'] = 'recipient-unavailable'
128 def _handle_method_call(self
, iq
):
131 log
.debug("Incoming Jabber-RPC call from %s" % iq
['from'])
132 self
.xmpp
.event('jabber_rpc_method_call', iq
)
134 if type == 'error' and ['rpc_query'] is None:
135 self
.handle_error(iq
)
137 log
.debug("Incoming Jabber-RPC error from %s" % iq
['from'])
138 self
.xmpp
.event('jabber_rpc_error', iq
)
140 def _handle_method_response(self
, iq
):
141 if iq
['rpc_query']['method_response']['fault'] is not None:
142 log
.debug("Incoming Jabber-RPC fault from %s" % iq
['from'])
143 #self._on_jabber_rpc_method_fault(iq)
144 self
.xmpp
.event('jabber_rpc_method_fault', iq
)
146 log
.debug("Incoming Jabber-RPC response from %s" % iq
['from'])
147 self
.xmpp
.event('jabber_rpc_method_response', iq
)
149 def _handle_error(self
, iq
):
150 print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq
)
151 print("#######################")
152 print("### NOT IMPLEMENTED ###")
153 print("#######################")
155 def _on_jabber_rpc_method_call(self
, iq
, forwarded
=False):
157 A default handler for Jabber-RPC method call. If another
158 handler is registered, this one will defer and not run.
160 If this handler is called by your own custom handler with
161 forwarded set to True, then it will run as normal.
163 if not forwarded
and self
.xmpp
.event_handled('jabber_rpc_method_call') > 1:
165 # Reply with error by default
166 error
= self
.client
.plugin
['xep_0009']._item
_not
_found
(iq
)
169 def _on_jabber_rpc_method_response(self
, iq
, forwarded
=False):
171 A default handler for Jabber-RPC method response. If another
172 handler is registered, this one will defer and not run.
174 If this handler is called by your own custom handler with
175 forwarded set to True, then it will run as normal.
177 if not forwarded
and self
.xmpp
.event_handled('jabber_rpc_method_response') > 1:
179 error
= self
.client
.plugin
['xep_0009']._recpient
_unavailable
(iq
)
182 def _on_jabber_rpc_method_fault(self
, iq
, forwarded
=False):
184 A default handler for Jabber-RPC fault response. If another
185 handler is registered, this one will defer and not run.
187 If this handler is called by your own custom handler with
188 forwarded set to True, then it will run as normal.
190 if not forwarded
and self
.xmpp
.event_handled('jabber_rpc_method_fault') > 1:
192 error
= self
.client
.plugin
['xep_0009']._recpient
_unavailable
(iq
)
195 def _on_jabber_rpc_error(self
, iq
, forwarded
=False):
197 A default handler for Jabber-RPC error response. If another
198 handler is registered, this one will defer and not run.
200 If this handler is called by your own custom handler with
201 forwarded set to True, then it will run as normal.
203 if not forwarded
and self
.xmpp
.event_handled('jabber_rpc_error') > 1:
205 error
= self
.client
.plugin
['xep_0009']._recpient
_unavailable
(iq
, iq
.get_payload())
208 def _send_fault(self
, iq
, fault_xml
): #
209 fault
= self
.make_iq_method_response_fault(iq
['id'], iq
['from'], fault_xml
)
212 def _send_error(self
, iq
):
213 print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq
)
214 print("#######################")
215 print("### NOT IMPLEMENTED ###")
216 print("#######################")
218 def _extract_method(self
, stanza
):
219 xml
= ET
.fromstring("%s" % stanza
)
220 return xml
.find("./methodCall/methodName").text