Mercurial > libervia-backend
comparison src/plugins/plugin_misc_text_commands.py @ 921:8dd168c7741c
plugin text commands: refactoring:
- commands can now return a deferred
- if commands return True, message is sent, else it is cancelled
- the escape sequence is now '//' instead of '\/'
- added software version to /whois command
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 22 Mar 2014 13:47:33 +0100 |
parents | 1fe00f0c9a91 |
children | c897c8d321b3 |
comparison
equal
deleted
inserted
replaced
920:45dffd67a18a | 921:8dd168c7741c |
---|---|
16 | 16 |
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _ | 20 from sat.core.i18n import _ |
21 from sat.core.sat_main import MessageSentAndStored | |
21 from twisted.words.protocols.jabber import jid | 22 from twisted.words.protocols.jabber import jid |
23 from twisted.internet import defer | |
24 from twisted.python.failure import Failure | |
22 from logging import debug, info, warning, error | 25 from logging import debug, info, warning, error |
23 | 26 |
24 PLUGIN_INFO = { | 27 PLUGIN_INFO = { |
25 "name": "Text commands", | 28 "name": "Text commands", |
26 "import_name": "TEXT-COMMANDS", | 29 "import_name": "TEXT-COMMANDS", |
27 "type": "Misc", | 30 "type": "Misc", |
28 "protocols": [], | 31 "protocols": [], |
29 "dependencies": ["XEP-0045", "EXP-PARROT"], | 32 "dependencies": ["XEP-0045", "EXP-PARROT", "XEP-0092"], |
30 "main": "TextCommands", | 33 "main": "TextCommands", |
31 "handler": "no", | 34 "handler": "no", |
32 "description": _("""IRC like text commands""") | 35 "description": _("""IRC like text commands""") |
33 } | 36 } |
34 | 37 |
42 info(_("Text commands initialization")) | 45 info(_("Text commands initialization")) |
43 self.host = host | 46 self.host = host |
44 host.trigger.add("sendMessage", self.sendMessageTrigger) | 47 host.trigger.add("sendMessage", self.sendMessageTrigger) |
45 | 48 |
46 def sendMessageTrigger(self, mess_data, treatments, profile): | 49 def sendMessageTrigger(self, mess_data, treatments, profile): |
47 """ Check text commands in message, and react consequently """ | 50 """ Install SendMessage command hook """ |
51 treatments.addCallback(self._sendMessageCmdHook, profile) | |
52 return True | |
53 | |
54 def _sendMessageCmdHook(self, mess_data, profile): | |
55 """ Check text commands in message, and react consequently | |
56 msg starting with / are potential command. If a command is found, it is executed, else message is sent normally | |
57 msg starting with // are escaped: they are sent with a single / | |
58 commands can abord message sending (if they return anything evaluating to False), or continue it (if they return True), eventually after modifying the message | |
59 an "unparsed" key is added to message, containing part of the message not yet parsed | |
60 commands can be deferred or not | |
61 | |
62 """ | |
48 msg = mess_data["message"] | 63 msg = mess_data["message"] |
49 if msg: | 64 try: |
50 if msg[0] == '/': | 65 if msg[:2] == '//': |
51 command = msg[1:].partition(' ')[0].lower() | 66 # we have a double '/', it's the escape sequence |
52 if command.isalpha(): | 67 mess_data["message"] = msg[1:] |
53 # looks like an actual command, we try to call the corresponding method | 68 return mess_data |
54 try: | 69 if msg[0] != '/': |
55 mess_data["unparsed"] = msg[1 + len(command):] # part not yet parsed of the message | 70 return mess_data |
56 return getattr(self, "cmd_%s" % command)(mess_data, profile) | 71 except IndexError: |
57 except AttributeError: | 72 return mess_data |
58 pass | 73 |
59 elif msg[0] == '\\': # we have escape char | 74 # we have a command |
60 try: | 75 d = None |
61 if msg[1] in ('/', '\\'): # we have '\/' or '\\', we escape to '/' or '\' | 76 command = msg[1:].partition(' ')[0].lower() |
62 mess_data["message"] = msg[1:] | 77 if command.isalpha(): |
63 except IndexError: | 78 # looks like an actual command, we try to call the corresponding method |
64 pass | 79 def retHandling(ret): |
65 return True | 80 """ Handle command return value: |
81 if ret is True, normally send message (possibly modified by command) | |
82 else, abord message sending | |
83 | |
84 """ | |
85 if ret: | |
86 return mess_data | |
87 else: | |
88 return Failure(MessageSentAndStored("text commands took over", mess_data)) | |
89 | |
90 try: | |
91 mess_data["unparsed"] = msg[1 + len(command):] # part not yet parsed of the message | |
92 d = defer.maybeDeferred(getattr(self, "cmd_%s" % command), mess_data, profile) | |
93 d.addCallback(retHandling) | |
94 except AttributeError: | |
95 pass | |
96 | |
97 return d or mess_data # if a command is detected, we should have a deferred, else be send the message normally | |
66 | 98 |
67 def _getRoomJID(self, arg, service_jid): | 99 def _getRoomJID(self, arg, service_jid): |
68 """Return a room jid with a shortcut | 100 """Return a room jid with a shortcut |
69 @param arg: argument: can be a full room jid (e.g.: sat@chat.jabberfr.org) | 101 @param arg: argument: can be a full room jid (e.g.: sat@chat.jabberfr.org) |
70 or a shortcut (e.g.: sat or sat@ for sat on current service) | 102 or a shortcut (e.g.: sat or sat@ for sat on current service) |
228 raise jid.InvalidFormat | 260 raise jid.InvalidFormat |
229 except (jid.InvalidFormat, RuntimeError): | 261 except (jid.InvalidFormat, RuntimeError): |
230 self._feedBack(_("Invalid jid, can't whois"), mess_data, profile) | 262 self._feedBack(_("Invalid jid, can't whois"), mess_data, profile) |
231 return False | 263 return False |
232 | 264 |
265 if not target_jid.resource: | |
266 target_jid.resource = self.host.memory.getLastResource(target_jid, profile) | |
267 | |
233 whois_msg = [_(u"whois for %(jid)s") % {'jid': target_jid}] | 268 whois_msg = [_(u"whois for %(jid)s") % {'jid': target_jid}] |
234 #TODO: add informations here (client version, vcard, etc) | 269 |
235 | 270 # version |
236 self._feedBack(u"\n".join(whois_msg), mess_data, profile) | 271 def versionCb(version_data): |
237 | 272 name, version, os = version_data |
238 return False | 273 if name: |
274 whois_msg.append(_("Client name: %s") % name) | |
275 if version: | |
276 whois_msg.append(_("Client version: %s") % version) | |
277 if os: | |
278 whois_msg.append(_("Operating system: %s") % os) | |
279 | |
280 d = self.host.plugins['XEP-0092'].getVersion(target_jid, profile) | |
281 d.addCallback(versionCb) | |
282 | |
283 #TODO: add informations here (vcard, etc) | |
284 | |
285 def feedBack(ignore): | |
286 self._feedBack(u"\n".join(whois_msg), mess_data, profile) | |
287 return False | |
288 | |
289 d.addCallback(feedBack) | |
290 return d | |
239 | 291 |
240 def cmd_help(self, mess_data, profile): | 292 def cmd_help(self, mess_data, profile): |
241 """show help on available commands""" | 293 """show help on available commands""" |
242 commands = filter(lambda method: method.startswith('cmd_'), dir(self)) | 294 commands = filter(lambda method: method.startswith('cmd_'), dir(self)) |
243 longuest = max([len(command) for command in commands]) | 295 longuest = max([len(command) for command in commands]) |