Rename to slixmpp
[slixmpp.git] / slixmpp / plugins / xep_0009 / rpc.py
blobff17c417b2eec98c9eaf1a6c2e67e588e0ca0feb
1 """
2 Slixmpp: The Slick XMPP Library
3 Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON).
4 This file is part of Slixmpp.
6 See the file LICENSE for copying permission.
7 """
9 import logging
11 from slixmpp import Iq
12 from slixmpp.xmlstream import ET, register_stanza_plugin
13 from slixmpp.xmlstream.handler import Callback
14 from slixmpp.xmlstream.matcher import MatchXPath
15 from slixmpp.plugins import BasePlugin
16 from slixmpp.plugins.xep_0009 import stanza
17 from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse
20 log = logging.getLogger(__name__)
23 class XEP_0009(BasePlugin):
25 name = 'xep_0009'
26 description = 'XEP-0009: Jabber-RPC'
27 dependencies = set(['xep_0030'])
28 stanza = stanza
30 def plugin_init(self):
31 register_stanza_plugin(Iq, RPCQuery)
32 register_stanza_plugin(RPCQuery, MethodCall)
33 register_stanza_plugin(RPCQuery, MethodResponse)
35 self.xmpp.register_handler(
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.register_handler(
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.register_handler(
44 Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)),
45 self._handle_error)
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 = []
54 self.xmpp['xep_0030'].add_feature('jabber:iq:rpc')
55 self.xmpp['xep_0030'].add_identity('automation','rpc')
57 def make_iq_method_call(self, pto, pmethod, params):
58 iq = self.xmpp.makeIqSet()
59 iq.attrib['to'] = pto
60 iq.attrib['from'] = self.xmpp.boundjid.full
61 iq.enable('rpc_query')
62 iq['rpc_query']['method_call']['method_name'] = pmethod
63 iq['rpc_query']['method_call']['params'] = params
64 return iq;
66 def make_iq_method_response(self, pid, pto, params):
67 iq = self.xmpp.makeIqResult(pid)
68 iq.attrib['to'] = pto
69 iq.attrib['from'] = self.xmpp.boundjid.full
70 iq.enable('rpc_query')
71 iq['rpc_query']['method_response']['params'] = params
72 return iq
74 def make_iq_method_response_fault(self, pid, pto, params):
75 iq = self.xmpp.makeIqResult(pid)
76 iq.attrib['to'] = pto
77 iq.attrib['from'] = self.xmpp.boundjid.full
78 iq.enable('rpc_query')
79 iq['rpc_query']['method_response']['params'] = None
80 iq['rpc_query']['method_response']['fault'] = params
81 return iq
83 # def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition):
84 # iq = self.xmpp.makeIqError(pid)
85 # iq.attrib['to'] = pto
86 # iq.attrib['from'] = self.xmpp.boundjid.full
87 # iq['error']['code'] = code
88 # iq['error']['type'] = type
89 # iq['error']['condition'] = condition
90 # iq['rpc_query']['method_call']['method_name'] = pmethod
91 # iq['rpc_query']['method_call']['params'] = params
92 # return iq
94 def _item_not_found(self, iq):
95 payload = iq.get_payload()
96 iq.reply().error().set_payload(payload);
97 iq['error']['code'] = '404'
98 iq['error']['type'] = 'cancel'
99 iq['error']['condition'] = 'item-not-found'
100 return iq
102 def _undefined_condition(self, iq):
103 payload = iq.get_payload()
104 iq.reply().error().set_payload(payload)
105 iq['error']['code'] = '500'
106 iq['error']['type'] = 'cancel'
107 iq['error']['condition'] = 'undefined-condition'
108 return iq
110 def _forbidden(self, iq):
111 payload = iq.get_payload()
112 iq.reply().error().set_payload(payload)
113 iq['error']['code'] = '403'
114 iq['error']['type'] = 'auth'
115 iq['error']['condition'] = 'forbidden'
116 return iq
118 def _recipient_unvailable(self, iq):
119 payload = iq.get_payload()
120 iq.reply().error().set_payload(payload)
121 iq['error']['code'] = '404'
122 iq['error']['type'] = 'wait'
123 iq['error']['condition'] = 'recipient-unavailable'
124 return iq
126 def _handle_method_call(self, iq):
127 type = iq['type']
128 if type == 'set':
129 log.debug("Incoming Jabber-RPC call from %s", iq['from'])
130 self.xmpp.event('jabber_rpc_method_call', iq)
131 else:
132 if type == 'error' and ['rpc_query'] is None:
133 self.handle_error(iq)
134 else:
135 log.debug("Incoming Jabber-RPC error from %s", iq['from'])
136 self.xmpp.event('jabber_rpc_error', iq)
138 def _handle_method_response(self, iq):
139 if iq['rpc_query']['method_response']['fault'] is not None:
140 log.debug("Incoming Jabber-RPC fault from %s", iq['from'])
141 #self._on_jabber_rpc_method_fault(iq)
142 self.xmpp.event('jabber_rpc_method_fault', iq)
143 else:
144 log.debug("Incoming Jabber-RPC response from %s", iq['from'])
145 self.xmpp.event('jabber_rpc_method_response', iq)
147 def _handle_error(self, iq):
148 print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq)
149 print("#######################")
150 print("### NOT IMPLEMENTED ###")
151 print("#######################")
153 def _on_jabber_rpc_method_call(self, iq, forwarded=False):
155 A default handler for Jabber-RPC method call. If another
156 handler is registered, this one will defer and not run.
158 If this handler is called by your own custom handler with
159 forwarded set to True, then it will run as normal.
161 if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1:
162 return
163 # Reply with error by default
164 error = self.client.plugin['xep_0009']._item_not_found(iq)
165 error.send()
167 def _on_jabber_rpc_method_response(self, iq, forwarded=False):
169 A default handler for Jabber-RPC method response. If another
170 handler is registered, this one will defer and not run.
172 If this handler is called by your own custom handler with
173 forwarded set to True, then it will run as normal.
175 if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1:
176 return
177 error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
178 error.send()
180 def _on_jabber_rpc_method_fault(self, iq, forwarded=False):
182 A default handler for Jabber-RPC fault response. If another
183 handler is registered, this one will defer and not run.
185 If this handler is called by your own custom handler with
186 forwarded set to True, then it will run as normal.
188 if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1:
189 return
190 error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
191 error.send()
193 def _on_jabber_rpc_error(self, iq, forwarded=False):
195 A default handler for Jabber-RPC error response. If another
196 handler is registered, this one will defer and not run.
198 If this handler is called by your own custom handler with
199 forwarded set to True, then it will run as normal.
201 if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1:
202 return
203 error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload())
204 error.send()
206 def _send_fault(self, iq, fault_xml): #
207 fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml)
208 fault.send()
210 def _send_error(self, iq):
211 print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq)
212 print("#######################")
213 print("### NOT IMPLEMENTED ###")
214 print("#######################")
216 def _extract_method(self, stanza):
217 xml = ET.fromstring("%s" % stanza)
218 return xml.find("./methodCall/methodName").text