plugin XEP-0297: Reworked forward method and add bridge method:
`Forward` method has been reworked and now includes a fallback. XEP-0297 ask to not use fallback, but following a discussion on xsf@, we agreed that this is a legacy thing and a fallback should nowadays be used, I'll propose a patch to the specification. A `message_forward` has been added to bridge. rel 461
This commit is contained in:
parent
030be64c45
commit
b1e0e336c2
1 changed files with 123 additions and 38 deletions
|
|
@ -18,41 +18,65 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from libervia.backend.core.constants import Const as C
|
||||
from libervia.backend.core.i18n import _, D_
|
||||
from libervia.backend.core.log import getLogger
|
||||
from datetime import datetime
|
||||
from typing import cast
|
||||
|
||||
from dateutil import tz
|
||||
from twisted.internet import defer
|
||||
from twisted.words.protocols.jabber import jid
|
||||
from twisted.words.protocols.jabber.xmlstream import XMPPHandler
|
||||
from twisted.words.xish import domish
|
||||
from wokkel import disco, iwokkel
|
||||
from zope.interface import implementer
|
||||
|
||||
from libervia.backend import G
|
||||
from libervia.backend.core import exceptions
|
||||
from libervia.backend.core.constants import Const as C
|
||||
from libervia.backend.core.core_types import SatXMPPEntity
|
||||
from libervia.backend.models.core import MessageData
|
||||
from libervia.backend.core.i18n import D_, _
|
||||
from libervia.backend.core.log import getLogger
|
||||
from libervia.backend.memory.sqla_mapping import History
|
||||
from libervia.backend.plugins.plugin_xep_0428 import XEP_0428
|
||||
from libervia.backend.tools.common.date_utils import date_fmt
|
||||
|
||||
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
from wokkel import disco, iwokkel
|
||||
|
||||
try:
|
||||
from twisted.words.protocols.xmlstream import XMPPHandler
|
||||
except ImportError:
|
||||
from wokkel.subprotocols import XMPPHandler
|
||||
from zope.interface import implementer
|
||||
|
||||
from twisted.words.xish import domish
|
||||
|
||||
PLUGIN_INFO = {
|
||||
C.PI_NAME: "Stanza Forwarding",
|
||||
C.PI_IMPORT_NAME: "XEP-0297",
|
||||
C.PI_TYPE: "XEP",
|
||||
C.PI_PROTOCOLS: ["XEP-0297"],
|
||||
C.PI_DEPENDENCIES: ["XEP-0428"],
|
||||
C.PI_MAIN: "XEP_0297",
|
||||
C.PI_HANDLER: "yes",
|
||||
C.PI_DESCRIPTION: D_("""Implementation of Stanza Forwarding"""),
|
||||
}
|
||||
|
||||
NS_FORWARD = "urn:xmpp:forward:0"
|
||||
|
||||
class XEP_0297(object):
|
||||
# FIXME: check this implementation which doesn't seems to be used
|
||||
|
||||
class XEP_0297:
|
||||
# TODO: Handle forwarded message reception, for now the fallback will be used.
|
||||
# TODO: Add a method to forward Pubsub Item, and notably blog content.
|
||||
|
||||
def __init__(self, host):
|
||||
log.info(_("Stanza Forwarding plugin initialization"))
|
||||
self.host = host
|
||||
self._fallback = cast(XEP_0428, host.plugins["XEP-0428"])
|
||||
host.register_namespace("forward", NS_FORWARD)
|
||||
host.bridge.add_method(
|
||||
"message_forward",
|
||||
".plugin",
|
||||
in_sign="sss",
|
||||
out_sign="",
|
||||
method=self._forward,
|
||||
async_=True,
|
||||
)
|
||||
|
||||
def get_handler(self, client):
|
||||
return XEP_0297_handler(self, client.profile)
|
||||
|
|
@ -72,41 +96,102 @@ class XEP_0297(object):
|
|||
if isinstance(child, domish.Element) and not child.uri:
|
||||
XEP_0297.update_uri(child, uri)
|
||||
|
||||
def forward(self, stanza, to_jid, stamp, body="", profile_key=C.PROF_KEY_NONE):
|
||||
def _forward(
|
||||
self,
|
||||
message_id: str,
|
||||
recipient_jid_s: str,
|
||||
profile_key: str
|
||||
) -> defer.Deferred[None]:
|
||||
client = self.host.get_client(profile_key)
|
||||
recipient_jid = jid.JID(recipient_jid_s)
|
||||
return defer.ensureDeferred(self.forward_by_id(client, message_id, recipient_jid))
|
||||
|
||||
async def forward_by_id(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
message_id: str,
|
||||
recipient_jid: jid.JID
|
||||
) -> None:
|
||||
history = cast(History, await G.storage.get(
|
||||
client,
|
||||
History,
|
||||
History.uid,
|
||||
message_id,
|
||||
joined_loads=[History.messages, History.subjects, History.thread],
|
||||
))
|
||||
if not history:
|
||||
raise exceptions.NotFound(
|
||||
f"No history found with message {message_id!r}."
|
||||
)
|
||||
# FIXME: Q&D way to get MessageData from History. History should have a proper
|
||||
# way to do that.
|
||||
serialised_history = history.serialise()
|
||||
serialised_history["from"] = jid.JID(serialised_history["from"])
|
||||
serialised_history["to"] = jid.JID(serialised_history["to"])
|
||||
mess_data = MessageData(serialised_history)
|
||||
client.generate_message_xml(mess_data)
|
||||
message_elt = cast(domish.Element, mess_data["xml"])
|
||||
timestamp_float = float(history.timestamp or history.received_timestamp)
|
||||
timestamp = datetime.fromtimestamp(timestamp_float, tz.tzutc())
|
||||
|
||||
fallback_lines = [
|
||||
f"{client.jid.userhost()} is forwarding this message to you:",
|
||||
f"[{date_fmt(timestamp_float)}]",
|
||||
f"From: {history.source_jid.full()}",
|
||||
f"To: {history.dest_jid.full()}"
|
||||
]
|
||||
|
||||
for subject in history.subjects:
|
||||
if subject.language:
|
||||
fallback_lines.append(f"Subject [{subject.language}]: {subject.subject}")
|
||||
else:
|
||||
fallback_lines.append(f"Subject: {subject.subject}")
|
||||
|
||||
for message in history.messages:
|
||||
if message.language:
|
||||
fallback_lines.append(f"Message [{message.language}]: {message.message}")
|
||||
else:
|
||||
fallback_lines.append(f"Message: {message.message}")
|
||||
|
||||
fallback_msg = "\n".join(fallback_lines)
|
||||
|
||||
await self.forward(client, message_elt, recipient_jid, timestamp, fallback_msg)
|
||||
|
||||
async def forward(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
stanza: domish.Element,
|
||||
to_jid: jid.JID,
|
||||
timestamp: datetime|None,
|
||||
fallback_msg: str | None = None
|
||||
):
|
||||
"""Forward a message to the given JID.
|
||||
|
||||
@param stanza (domish.Element): original stanza to be forwarded.
|
||||
@param to_jid (JID): recipient JID.
|
||||
@param stamp (datetime): offset-aware timestamp of the original reception.
|
||||
@param body (unicode): optional description.
|
||||
@param profile_key (unicode): %(doc_profile_key)s
|
||||
@param client: client instance.
|
||||
@param stanza: original stanza to be forwarded.
|
||||
@param to_jid: recipient JID.
|
||||
@param timestamp: offset-aware timestamp of the original reception.
|
||||
@param body: optional description.
|
||||
@return: a Deferred when the message has been sent
|
||||
"""
|
||||
# FIXME: this method is not used and doesn't use mess_data which should be used for client.send_message_data
|
||||
# should it be deprecated? A method constructing the element without sending it seems more natural
|
||||
log.warning(
|
||||
"THIS METHOD IS DEPRECATED"
|
||||
) # FIXME: we use this warning until we check the method
|
||||
msg = domish.Element((None, "message"))
|
||||
msg["to"] = to_jid.full()
|
||||
msg["type"] = stanza["type"]
|
||||
|
||||
body_elt = domish.Element((None, "body"))
|
||||
if body:
|
||||
body_elt.addContent(body)
|
||||
message_elt = domish.Element((None, "message"))
|
||||
message_elt["to"] = to_jid.full()
|
||||
message_elt["type"] = stanza["type"]
|
||||
|
||||
forwarded_elt = domish.Element((C.NS_FORWARD, "forwarded"))
|
||||
delay_elt = self.host.plugins["XEP-0203"].delay(stamp)
|
||||
forwarded_elt.addChild(delay_elt)
|
||||
if not stanza.uri: # None or ''
|
||||
if timestamp:
|
||||
delay_elt = self.host.plugins["XEP-0203"].delay(timestamp)
|
||||
forwarded_elt.addChild(delay_elt)
|
||||
if not stanza.uri:
|
||||
XEP_0297.update_uri(stanza, "jabber:client")
|
||||
forwarded_elt.addChild(stanza)
|
||||
|
||||
msg.addChild(body_elt)
|
||||
msg.addChild(forwarded_elt)
|
||||
|
||||
client = self.host.get_client(profile_key)
|
||||
return defer.ensureDeferred(client.send_message_data({"xml": msg}))
|
||||
message_elt.addChild(domish.Element((None, "body")))
|
||||
message_elt.addChild(forwarded_elt)
|
||||
self._fallback.add_fallback_elt(message_elt, NS_FORWARD, fallback_msg)
|
||||
return await client.send_message_data(
|
||||
MessageData({"xml": message_elt, "extra": {}})
|
||||
)
|
||||
|
||||
|
||||
@implementer(iwokkel.IDisco)
|
||||
|
|
|
|||
Loading…
Reference in a new issue