import logging import os import slixmpp from dotenv import load_dotenv load_dotenv() logger = logging.getLogger(__name__) class XmppBot(slixmpp.ClientXMPP): def __init__(self, jid, password, rooms="", on_message=None): super().__init__(jid, password) self.nickname = jid.split("@")[0] self.rooms = rooms self.on_message = on_message self.register_plugin("xep_0045") self.register_plugin("xep_0066") self.add_event_handler("session_start", self.start) self.add_event_handler("message", self.handle_message) async def start(self, event): self.send_presence() await self.get_roster() if self.rooms: for room in self.rooms.split(","): room = room.strip() if room: self["xep_0045"].join_muc(room, self.nickname) async def handle_message(self, msg): sender = msg["from"] body_preview = msg["body"][:100] logger.info("<< [%s] %s: %s", msg["type"], sender, body_preview) if msg["type"] == "groupchat": if msg["mucnick"] == self.nickname: return body = msg["body"].strip() if not body: return mention = f"@{self.nickname}" mention2 = f"{self.nickname}:" if not (body.startswith(mention) or body.startswith(mention2)): return for prefix in (mention, mention2): if body.startswith(prefix): body = body[len(prefix):].strip() break else: if msg["type"] not in ("chat", "normal"): return body = msg["body"].strip() if not body: return if msg["oob"]["url"]: msg.reply("message received").send() return if self.on_message: await self.on_message(body, msg["type"], str(sender), msg) else: msg.reply(f"echo-{body}").send() if __name__ == "__main__": logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", ) jid = os.getenv("XMPP_USERNAME") password = os.getenv("XMPP_PASSWORD") if not jid or not password: logger.error("XMPP_USERNAME and XMPP_PASSWORD must be set in .env") exit(1) bot = XmppBot(jid, password, rooms=os.getenv("XMPP_ROOMS", "")) bot.connect() bot.loop.run_forever()