diff --git a/mautrix_telegram/__main__.py b/mautrix_telegram/__main__.py
index 6023a7c8..0936e514 100644
--- a/mautrix_telegram/__main__.py
+++ b/mautrix_telegram/__main__.py
@@ -35,6 +35,7 @@ from .user import init as init_user, User
from .bot import init as init_bot
from .portal import init as init_portal
from .puppet import init as init_puppet
+from .formatter import init as init_formatter
from .public import PublicBridgeWebsite
from .context import Context
@@ -99,6 +100,7 @@ with appserv.run(config["appservice.hostname"], config["appservice.port"]) as st
init_abstract_user(context)
context.bot = init_bot(context)
context.mx = MatrixHandler(context)
+ init_formatter(context)
init_portal(context)
init_puppet(context)
startup_actions = init_user(context) + [start, context.mx.init_as_bot()]
diff --git a/mautrix_telegram/formatter/__init__.py b/mautrix_telegram/formatter/__init__.py
index 0428e723..6252455a 100644
--- a/mautrix_telegram/formatter/__init__.py
+++ b/mautrix_telegram/formatter/__init__.py
@@ -1,2 +1,8 @@
-from .from_matrix import matrix_reply_to_telegram, matrix_to_telegram, matrix_text_to_telegram
-from .from_telegram import telegram_reply_to_matrix, telegram_to_matrix
+from .from_matrix import (matrix_reply_to_telegram, matrix_to_telegram, matrix_text_to_telegram,
+ init_mx)
+from .from_telegram import (telegram_reply_to_matrix, telegram_to_matrix, init_tg)
+
+
+def init(context):
+ init_mx(context)
+ init_tg(context)
diff --git a/mautrix_telegram/formatter/from_matrix.py b/mautrix_telegram/formatter/from_matrix.py
index b5b3576f..971e7a97 100644
--- a/mautrix_telegram/formatter/from_matrix.py
+++ b/mautrix_telegram/formatter/from_matrix.py
@@ -219,11 +219,46 @@ class MatrixParser(HTMLParser):
command_regex = re.compile("(\s|^)!([A-Za-z0-9@]+)")
+plain_mention_regex = None
def matrix_text_to_telegram(text):
text = command_regex.sub(r"\1/\2", text)
- return text
+ entities, pmr_replacer = plain_mention_to_text()
+ text = plain_mention_regex.sub(pmr_replacer, text)
+ return text, entities
+
+
+def plain_mention_to_text():
+ entities = []
+
+ def replacer(match):
+ puppet = pu.Puppet.find_by_displayname(match.group(2))
+ if puppet:
+ offset = match.start()
+ length = match.end() - offset
+ if puppet.username:
+ entity = MessageEntityMention(offset, length)
+ text = f"@{puppet.username}"
+ else:
+ entity = InputMessageEntityMentionName(offset, length,
+ user_id=InputUser(puppet.tgid, 0))
+ text = puppet.displayname
+ entities.append(entity)
+ return text
+ return "".join(match.groups())
+
+ return entities, replacer
+
+
+def plain_mention_to_html(match):
+ puppet = pu.Puppet.find_by_displayname(match.group(2))
+ if puppet:
+ return (f"{match.group(1)}"
+ f""
+ f"{puppet.displayname}"
+ "")
+ return "".join(match.groups())
def matrix_to_telegram(html):
@@ -231,6 +266,7 @@ def matrix_to_telegram(html):
parser = MatrixParser()
html = html.replace("\n", "")
html = command_regex.sub(r"\1\2", html)
+ html = plain_mention_regex.sub(plain_mention_to_html, html)
parser.feed(add_surrogates(html))
return remove_surrogates(parser.text.strip()), parser.entities
except Exception:
@@ -258,3 +294,11 @@ def matrix_reply_to_telegram(content, tg_space, room_id=None):
except KeyError:
pass
return None
+
+
+def init_mx(context):
+ global plain_mention_regex
+ config = context.config
+ dn_template = config.get("bridge.displayname_template", "{displayname} (Telegram)")
+ dn_template = re.escape(dn_template).replace(re.escape("{displayname}"), "[^>]+")
+ plain_mention_regex = re.compile(f"(\s|^)({dn_template})")
diff --git a/mautrix_telegram/formatter/from_telegram.py b/mautrix_telegram/formatter/from_telegram.py
index 6dfbb1fe..7d4be35e 100644
--- a/mautrix_telegram/formatter/from_telegram.py
+++ b/mautrix_telegram/formatter/from_telegram.py
@@ -254,3 +254,7 @@ def _parse_url(html, entity_text, url):
url = "http://" + url
html.append(f"{entity_text}")
return False
+
+
+def init_tg(context):
+ pass
diff --git a/mautrix_telegram/portal.py b/mautrix_telegram/portal.py
index b6bd56e0..94153ff8 100644
--- a/mautrix_telegram/portal.py
+++ b/mautrix_telegram/portal.py
@@ -594,12 +594,9 @@ class Portal:
for entity in entities:
if isinstance(entity, InputMessageEntityMentionName):
entity.user_id = await client.get_input_entity(entity.user_id.user_id)
-
- return await client.send_message(self.peer, message, entities=entities,
- reply_to=reply_to)
else:
- message = formatter.matrix_text_to_telegram(message["body"])
- return await client.send_message(self.peer, message, reply_to=reply_to)
+ message, entities = formatter.matrix_text_to_telegram(message["body"])
+ return await client.send_message(self.peer, message, reply_to=reply_to)
async def _handle_matrix_file(self, client, message, reply_to):
file = await self.main_intent.download_file(message["url"])
diff --git a/mautrix_telegram/puppet.py b/mautrix_telegram/puppet.py
index 4340498a..782ad2a5 100644
--- a/mautrix_telegram/puppet.py
+++ b/mautrix_telegram/puppet.py
@@ -191,6 +191,21 @@ class Puppet:
return None
+ @classmethod
+ def find_by_displayname(cls, displayname):
+ if not displayname:
+ return None
+
+ for _, puppet in cls.cache.items():
+ if puppet.displayname and puppet.displayname == displayname:
+ return puppet
+
+ puppet = DBPuppet.query.filter(DBPuppet.displayname == displayname).one_or_none()
+ if puppet:
+ return cls.from_db(puppet)
+
+ return None
+
def init(context):
global config