comparison libervia/backend/plugins/plugin_exp_parrot.py @ 4071:4b842c1fb686

refactoring: renamed `sat` package to `libervia.backend`
author Goffi <goffi@goffi.org>
date Fri, 02 Jun 2023 11:49:51 +0200
parents sat/plugins/plugin_exp_parrot.py@c23cad65ae99
children 0d7bb4df2343
comparison
equal deleted inserted replaced
4070:d10748475025 4071:4b842c1fb686
1 #!/usr/bin/env python3
2
3
4 # SAT plugin for parrot mode (experimental)
5 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org)
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
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/>.
19
20 from libervia.backend.core.i18n import _
21 from libervia.backend.core.constants import Const as C
22 from libervia.backend.core.log import getLogger
23
24 log = getLogger(__name__)
25 from twisted.words.protocols.jabber import jid
26
27 from libervia.backend.core.exceptions import UnknownEntityError
28
29 # from sat.tools import trigger
30
31 PLUGIN_INFO = {
32 C.PI_NAME: "Parrot Plugin",
33 C.PI_IMPORT_NAME: "EXP-PARROT",
34 C.PI_TYPE: "EXP",
35 C.PI_PROTOCOLS: [],
36 C.PI_DEPENDENCIES: ["XEP-0045"],
37 C.PI_RECOMMENDATIONS: [C.TEXT_CMDS],
38 C.PI_MAIN: "Exp_Parrot",
39 C.PI_HANDLER: "no",
40 C.PI_DESCRIPTION: _(
41 """Implementation of parrot mode (repeat messages between 2 entities)"""
42 ),
43 }
44
45
46 class Exp_Parrot(object):
47 """Parrot mode plugin: repeat messages from one entity or MUC room to another one"""
48
49 # XXX: This plugin can be potentially dangerous if we don't trust entities linked
50 # this is specially true if we have other triggers.
51 # send_message_trigger avoid other triggers execution, it's deactivated to allow
52 # /unparrot command in text commands plugin.
53 # FIXME: potentially unsecure, specially with e2e encryption
54
55 def __init__(self, host):
56 log.info(_("Plugin Parrot initialization"))
57 self.host = host
58 host.trigger.add("message_received", self.message_received_trigger, priority=100)
59 # host.trigger.add("sendMessage", self.send_message_trigger, priority=100)
60 try:
61 self.host.plugins[C.TEXT_CMDS].register_text_commands(self)
62 except KeyError:
63 log.info(_("Text commands not available"))
64
65 # def send_message_trigger(self, client, mess_data, treatments):
66 # """ Deactivate other triggers if recipient is in parrot links """
67 # try:
68 # _links = client.parrot_links
69 # except AttributeError:
70 # return True
71 #
72 # if mess_data['to'].userhostJID() in _links.values():
73 # log.debug("Parrot link detected, skipping other triggers")
74 # raise trigger.SkipOtherTriggers
75
76 def message_received_trigger(self, client, message_elt, post_treat):
77 """ Check if source is linked and repeat message, else do nothing """
78 # TODO: many things are not repeated (subject, thread, etc)
79 from_jid = message_elt["from"]
80
81 try:
82 _links = client.parrot_links
83 except AttributeError:
84 return True
85
86 if not from_jid.userhostJID() in _links:
87 return True
88
89 message = {}
90 for e in message_elt.elements(C.NS_CLIENT, "body"):
91 body = str(e)
92 lang = e.getAttribute("lang") or ""
93
94 try:
95 entity_type = self.host.memory.entity_data_get(
96 client, from_jid, [C.ENTITY_TYPE])[C.ENTITY_TYPE]
97 except (UnknownEntityError, KeyError):
98 entity_type = "contact"
99 if entity_type == C.ENTITY_TYPE_MUC:
100 src_txt = from_jid.resource
101 if src_txt == self.host.plugins["XEP-0045"].get_room_nick(
102 client, from_jid.userhostJID()
103 ):
104 # we won't repeat our own messages
105 return True
106 else:
107 src_txt = from_jid.user
108 message[lang] = "[{}] {}".format(src_txt, body)
109
110 linked = _links[from_jid.userhostJID()]
111
112 client.sendMessage(
113 jid.JID(str(linked)), message, None, "auto", no_trigger=True
114 )
115
116 return True
117
118 def add_parrot(self, client, source_jid, dest_jid):
119 """Add a parrot link from one entity to another one
120
121 @param source_jid: entity from who messages will be repeated
122 @param dest_jid: entity where the messages will be repeated
123 """
124 try:
125 _links = client.parrot_links
126 except AttributeError:
127 _links = client.parrot_links = {}
128
129 _links[source_jid.userhostJID()] = dest_jid
130 log.info(
131 "Parrot mode: %s will be repeated to %s"
132 % (source_jid.userhost(), str(dest_jid))
133 )
134
135 def remove_parrot(self, client, source_jid):
136 """Remove parrot link
137
138 @param source_jid: this entity will no more be repeated
139 """
140 try:
141 del client.parrot_links[source_jid.userhostJID()]
142 except (AttributeError, KeyError):
143 pass
144
145 def cmd_parrot(self, client, mess_data):
146 """activate Parrot mode between 2 entities, in both directions."""
147 log.debug("Catched parrot command")
148 txt_cmd = self.host.plugins[C.TEXT_CMDS]
149
150 try:
151 link_left_jid = jid.JID(mess_data["unparsed"].strip())
152 if not link_left_jid.user or not link_left_jid.host:
153 raise jid.InvalidFormat
154 except (RuntimeError, jid.InvalidFormat, AttributeError):
155 txt_cmd.feed_back(
156 client, "Can't activate Parrot mode for invalid jid", mess_data
157 )
158 return False
159
160 link_right_jid = mess_data["to"]
161
162 self.add_parrot(client, link_left_jid, link_right_jid)
163 self.add_parrot(client, link_right_jid, link_left_jid)
164
165 txt_cmd.feed_back(
166 client,
167 "Parrot mode activated for {}".format(str(link_left_jid)),
168 mess_data,
169 )
170
171 return False
172
173 def cmd_unparrot(self, client, mess_data):
174 """remove Parrot mode between 2 entities, in both directions."""
175 log.debug("Catched unparrot command")
176 txt_cmd = self.host.plugins[C.TEXT_CMDS]
177
178 try:
179 link_left_jid = jid.JID(mess_data["unparsed"].strip())
180 if not link_left_jid.user or not link_left_jid.host:
181 raise jid.InvalidFormat
182 except jid.InvalidFormat:
183 txt_cmd.feed_back(
184 client, "Can't deactivate Parrot mode for invalid jid", mess_data
185 )
186 return False
187
188 link_right_jid = mess_data["to"]
189
190 self.remove_parrot(client, link_left_jid)
191 self.remove_parrot(client, link_right_jid)
192
193 txt_cmd.feed_back(
194 client,
195 "Parrot mode deactivated for {} and {}".format(
196 str(link_left_jid), str(link_right_jid)
197 ),
198 mess_data,
199 )
200
201 return False