Mercurial > libervia-backend
annotate src/plugins/plugin_exp_command_export.py @ 2227:79d279d1ee88
plugin XEP-0277: comments node access model changes:
comments node access model is now copied from parent item by default. If whitelist access is used, parent item affiliations are copied too.
publish model is now open by default instead of subscribers
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 17 Apr 2017 20:33:32 +0200 |
parents | 33c8c4973743 |
children | 074c2f157dc9 |
rev | line source |
---|---|
1934
2daf7b4c6756
use of /usr/bin/env instead of /usr/bin/python in shebang
Goffi <goffi@goffi.org>
parents:
1766
diff
changeset
|
1 #!/usr/bin/env python2 |
604 | 2 # -*- coding: utf-8 -*- |
3 | |
609
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
4 # SAT plugin to export commands (experimental) |
1766 | 5 # Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org) |
604 | 6 |
609
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
7 # This program is free software: you can redistribute it and/or modify |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
8 # it under the terms of the GNU Affero General Public License as published by |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
9 # the Free Software Foundation, either version 3 of the License, or |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
10 # (at your option) any later version. |
604 | 11 |
609
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
12 # This program is distributed in the hope that it will be useful, |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
15 # GNU Affero General Public License for more details. |
604 | 16 |
609
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
17 # You should have received a copy of the GNU Affero General Public License |
84a6e83157c2
fixed licences in docstrings (they are now in comments)
Goffi <goffi@goffi.org>
parents:
604
diff
changeset
|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
604 | 19 |
771 | 20 from sat.core.i18n import _ |
1955
633b5c21aefd
backend, frontend: messages refactoring (huge commit, not finished):
Goffi <goffi@goffi.org>
parents:
1934
diff
changeset
|
21 from sat.core.constants import Const as C |
993
301b342c697a
core: use of the new core.log module:
Goffi <goffi@goffi.org>
parents:
811
diff
changeset
|
22 from sat.core.log import getLogger |
301b342c697a
core: use of the new core.log module:
Goffi <goffi@goffi.org>
parents:
811
diff
changeset
|
23 log = getLogger(__name__) |
604 | 24 from twisted.words.protocols.jabber import jid |
25 from twisted.internet import reactor, protocol | |
26 | |
1374
0befb14ecf62
renamed tools.misc to tools.trigger
Goffi <goffi@goffi.org>
parents:
993
diff
changeset
|
27 from sat.tools import trigger |
604 | 28 from sat.tools.utils import clean_ustr |
29 | |
30 PLUGIN_INFO = { | |
2145
33c8c4973743
core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents:
2144
diff
changeset
|
31 C.PI_NAME: "Command export plugin", |
33c8c4973743
core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents:
2144
diff
changeset
|
32 C.PI_IMPORT_NAME: "EXP-COMMANS-EXPORT", |
33c8c4973743
core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents:
2144
diff
changeset
|
33 C.PI_TYPE: "EXP", |
33c8c4973743
core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents:
2144
diff
changeset
|
34 C.PI_PROTOCOLS: [], |
33c8c4973743
core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents:
2144
diff
changeset
|
35 C.PI_DEPENDENCIES: [], |
33c8c4973743
core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents:
2144
diff
changeset
|
36 C.PI_MAIN: "CommandExport", |
33c8c4973743
core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents:
2144
diff
changeset
|
37 C.PI_HANDLER: "no", |
33c8c4973743
core (plugins): added missing contants + use of new constants in PLUGIN_INFO
Goffi <goffi@goffi.org>
parents:
2144
diff
changeset
|
38 C.PI_DESCRIPTION: _("""Implementation of command export""") |
604 | 39 } |
40 | |
41 class ExportCommandProtocol(protocol.ProcessProtocol): | |
42 """ Try to register an account with prosody """ | |
43 | |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
44 def __init__(self, parent, client, target, options): |
604 | 45 self.parent = parent |
46 self.target = target | |
47 self.options = options | |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
48 self.client = client |
604 | 49 |
50 def _clean(self, data): | |
51 if not data: | |
993
301b342c697a
core: use of the new core.log module:
Goffi <goffi@goffi.org>
parents:
811
diff
changeset
|
52 log.error ("data should not be empty !") |
604 | 53 return u"" |
54 decoded = data.decode('utf-8', 'ignore')[:-1 if data[-1] == '\n' else None] | |
55 return clean_ustr(decoded) | |
56 | |
57 def connectionMade(self): | |
993
301b342c697a
core: use of the new core.log module:
Goffi <goffi@goffi.org>
parents:
811
diff
changeset
|
58 log.info("connectionMade :)") |
604 | 59 |
60 def outReceived(self, data): | |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
61 self.client.sendMessage(self.target, {'': self._clean(data)}, no_trigger=True) |
604 | 62 |
63 def errReceived(self, data): | |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
64 self.client.sendMessage(self.target, {'': self._clean(data)}, no_trigger=True) |
604 | 65 |
66 def processEnded(self, reason): | |
993
301b342c697a
core: use of the new core.log module:
Goffi <goffi@goffi.org>
parents:
811
diff
changeset
|
67 log.info (u"process finished: %d" % (reason.value.exitCode,)) |
604 | 68 self.parent.removeProcess(self.target, self) |
69 | |
70 def write(self, message): | |
71 self.transport.write(message.encode('utf-8')) | |
72 | |
73 def boolOption(self, key): | |
74 """ Get boolean value from options | |
75 @param key: name of the option | |
76 @return: True if key exists and set to "true" (case insensitive), | |
77 False in all other cases """ | |
78 value = self.options.get(key, "") | |
79 return value.lower() == "true" | |
80 | |
81 | |
82 class CommandExport(object): | |
83 """Command export plugin: export a command to an entity""" | |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
84 # XXX: This plugin can be potentially dangerous if we don't trust entities linked |
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
85 # this is specially true if we have other triggers. |
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
86 # FIXME: spawned should be a client attribute, not a class one |
604 | 87 |
88 def __init__(self, host): | |
993
301b342c697a
core: use of the new core.log module:
Goffi <goffi@goffi.org>
parents:
811
diff
changeset
|
89 log.info(_("Plugin command export initialization")) |
604 | 90 self.host = host |
91 self.spawned = {} # key = entity | |
92 host.trigger.add("MessageReceived", self.MessageReceivedTrigger, priority=10000) | |
93 host.bridge.addMethod("exportCommand", ".plugin", in_sign='sasasa{ss}s', out_sign='', method=self._exportCommand) | |
94 | |
95 def removeProcess(self, entity, process): | |
96 """ Called when the process is finished | |
97 @param entity: jid.JID attached to the process | |
98 @param process: process to remove""" | |
99 try: | |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
100 processes_set = self.spawned[(entity, process.client.profile)] |
604 | 101 processes_set.discard(process) |
102 if not processes_set: | |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
103 del(self.spawned[(entity, process.client.profile)]) |
604 | 104 except ValueError: |
105 pass | |
106 | |
1963
a2bc5089c2eb
backend, frontends: message refactoring (huge commit):
Goffi <goffi@goffi.org>
parents:
1955
diff
changeset
|
107 def MessageReceivedTrigger(self, client, message_elt, post_treat): |
604 | 108 """ Check if source is linked and repeat message, else do nothing """ |
1963
a2bc5089c2eb
backend, frontends: message refactoring (huge commit):
Goffi <goffi@goffi.org>
parents:
1955
diff
changeset
|
109 from_jid = jid.JID(message_elt["from"]) |
1955
633b5c21aefd
backend, frontend: messages refactoring (huge commit, not finished):
Goffi <goffi@goffi.org>
parents:
1934
diff
changeset
|
110 spawned_key = (from_jid.userhostJID(), client.profile) |
604 | 111 |
112 if spawned_key in self.spawned: | |
1955
633b5c21aefd
backend, frontend: messages refactoring (huge commit, not finished):
Goffi <goffi@goffi.org>
parents:
1934
diff
changeset
|
113 try: |
1963
a2bc5089c2eb
backend, frontends: message refactoring (huge commit):
Goffi <goffi@goffi.org>
parents:
1955
diff
changeset
|
114 body = message_elt.elements(C.NS_CLIENT, 'body').next() |
1955
633b5c21aefd
backend, frontend: messages refactoring (huge commit, not finished):
Goffi <goffi@goffi.org>
parents:
1934
diff
changeset
|
115 except StopIteration: |
633b5c21aefd
backend, frontend: messages refactoring (huge commit, not finished):
Goffi <goffi@goffi.org>
parents:
1934
diff
changeset
|
116 # do not block message without body (chat state notification...) |
633b5c21aefd
backend, frontend: messages refactoring (huge commit, not finished):
Goffi <goffi@goffi.org>
parents:
1934
diff
changeset
|
117 return True |
633b5c21aefd
backend, frontend: messages refactoring (huge commit, not finished):
Goffi <goffi@goffi.org>
parents:
1934
diff
changeset
|
118 |
633b5c21aefd
backend, frontend: messages refactoring (huge commit, not finished):
Goffi <goffi@goffi.org>
parents:
1934
diff
changeset
|
119 mess_data = unicode(body) + '\n' |
604 | 120 processes_set = self.spawned[spawned_key] |
121 _continue = False | |
122 exclusive = False | |
123 for process in processes_set: | |
124 process.write(mess_data) | |
125 _continue &= process.boolOption("continue") | |
126 exclusive |= process.boolOption("exclusive") | |
127 if exclusive: | |
1374
0befb14ecf62
renamed tools.misc to tools.trigger
Goffi <goffi@goffi.org>
parents:
993
diff
changeset
|
128 raise trigger.SkipOtherTriggers |
604 | 129 return _continue |
130 | |
131 return True | |
132 | |
133 def _exportCommand(self, command, args, targets, options, profile_key): | |
134 """ Export a commands to authorised targets | |
135 @param command: full path of the command to execute | |
136 @param args: list of arguments, with command name as first one | |
137 @param targets: list of allowed entities | |
138 @param options: export options, a dict which can have the following keys ("true" to set booleans): | |
139 - exclusive: if set, skip all other triggers | |
140 - loop: if set, restart the command once terminated #TODO | |
141 - pty: if set, launch in a pseudo terminal | |
142 - continue: continue normal MessageReceived handling | |
143 """ | |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
144 client = self.host.getClient(profile_key) |
604 | 145 for target in targets: |
146 try: | |
147 _jid = jid.JID(target) | |
148 if not _jid.user or not _jid.host: | |
149 raise jid.InvalidFormat | |
150 _jid = _jid.userhostJID() | |
1742
244a605623d6
complete the Exception's list when catching JID error:
souliane <souliane@mailoo.org>
parents:
1654
diff
changeset
|
151 except (RuntimeError, jid.InvalidFormat, AttributeError): |
993
301b342c697a
core: use of the new core.log module:
Goffi <goffi@goffi.org>
parents:
811
diff
changeset
|
152 log.info(u"invalid target ignored: %s" % (target,)) |
604 | 153 continue |
2144
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
154 process_prot = ExportCommandProtocol(self, client, _jid, options) |
1d3f73e065e1
core, jp: component handling + client handling refactoring:
Goffi <goffi@goffi.org>
parents:
1963
diff
changeset
|
155 self.spawned.setdefault((_jid, client.profile),set()).add(process_prot) |
604 | 156 reactor.spawnProcess(process_prot, command, args, usePTY = process_prot.boolOption('pty')) |
157 |