From 3221534b0f77a00043032c1e350814f607a56380 Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 14 Apr 2014 22:32:34 +0200 Subject: Implement XEP-0249 (Direct MUC Invitations) - fallback to mediated invitations if only the bare jid is given to the command or if the jid does not advertise support TODO: provide a way to send passwords --- doc/source/dev/xep.rst | 2 ++ src/connection.py | 1 + src/core/commands.py | 6 +++--- src/core/completions.py | 7 ++++++- src/core/core.py | 28 ++++++++++++++++++++++++++-- src/core/handlers.py | 34 +++++++++++++++++++++++++++++++++- 6 files changed, 71 insertions(+), 7 deletions(-) diff --git a/doc/source/dev/xep.rst b/doc/source/dev/xep.rst index 7cfffa20..7d303a03 100644 --- a/doc/source/dev/xep.rst +++ b/doc/source/dev/xep.rst @@ -50,6 +50,8 @@ Table of all XEPs implemented in poezio. +----------+-------------------------+---------------------+ |0245 |The /me Command |80% | +----------+-------------------------+---------------------+ +|0249 |Direct MUC Invitations |90% | ++----------+-------------------------+---------------------+ |0280 |Messsage Carbons |100% | +----------+-------------------------+---------------------+ |0296 |Best Practices for |100% | diff --git a/src/connection.py b/src/connection.py index bf84bd6d..5dc7c8e4 100644 --- a/src/connection.py +++ b/src/connection.py @@ -115,6 +115,7 @@ class Connection(sleekxmpp.ClientXMPP): if config.get('send_time', True): self.register_plugin('xep_0202') self.register_plugin('xep_0224') + self.register_plugin('xep_0249') self.register_plugin('xep_0280') self.register_plugin('xep_0297') self.register_plugin('xep_0308') diff --git a/src/core/commands.py b/src/core/commands.py index 39bf505d..dcbd762f 100644 --- a/src/core/commands.py +++ b/src/core/commands.py @@ -698,10 +698,10 @@ def command_invite(self, arg): args = common.shell_split(arg) if len(args) < 2: return - reason = args[2] if len(args) > 2 else '' + reason = args[2] if len(args) > 2 else None to = safeJID(args[0]) - room = safeJID(args[1]) - self.xmpp.plugin['xep_0045'].invite(room, str(to), reason) + room = safeJID(args[1]).bare + self.invite(to.full, room, reason=reason) def command_decline(self, arg): """/decline [reason]""" diff --git a/src/core/completions.py b/src/core/completions.py index 1df8d23d..75122885 100644 --- a/src/core/completions.py +++ b/src/core/completions.py @@ -249,7 +249,12 @@ def completion_invite(self, the_input): """Completion for /invite""" n = the_input.get_argument_position(quoted=True) if n == 1: - return the_input.new_completion(sorted(jid for jid in roster.jids()), n, quotify=True) + comp = reduce(lambda x, y: x + [i.jid for i in y], (roster[jid].resources for jid in roster.jids() if len(roster[jid])), []) + comp = sorted(comp) + bares = sorted(roster[contact].bare_jid for contact in roster.jids() if len(roster[contact])) + off = sorted(jid for jid in roster.jids() if jid not in bares) + comp = comp + bares + off + return the_input.new_completion(comp, n, quotify=True) elif n == 2: rooms = [] for tab in self.get_tabs(tabs.MucTab): diff --git a/src/core/core.py b/src/core/core.py index 41cb9586..b41bb1a4 100644 --- a/src/core/core.py +++ b/src/core/core.py @@ -188,7 +188,8 @@ class Core(object): self.xmpp.add_event_handler("session_start", self.on_session_start_features) self.xmpp.add_event_handler("groupchat_presence", self.on_groupchat_presence) self.xmpp.add_event_handler("groupchat_message", self.on_groupchat_message) - self.xmpp.add_event_handler("groupchat_invite", self.on_groupchat_invite) + self.xmpp.add_event_handler("groupchat_invite", self.on_groupchat_invitation) + self.xmpp.add_event_handler("groupchat_direct_invite", self.on_groupchat_direct_invitation) self.xmpp.add_event_handler("groupchat_decline", self.on_groupchat_decline) self.xmpp.add_event_handler("groupchat_config_status", self.on_status_codes) self.xmpp.add_event_handler("groupchat_subject", self.on_groupchat_subject) @@ -705,6 +706,27 @@ class Core(object): self.current_tab().command_say(msg) return True + def invite(self, jid, room, reason=None): + """ + Checks if the sender supports XEP-0249, then send an invitation, + or a mediated one if it does not. + TODO: allow passwords + """ + def callback(iq): + if not iq: + return + if 'jabber:x:conference' in iq['disco_info'].get_features(): + self.xmpp.plugin['xep_0249'].send_invitation( + jid, + room, + reason=reason) + else: # fallback + self.xmpp.plugin['xep_0045'].invite(room, jid, + reason=reason or '') + + self.xmpp.plugin['xep_0030'].get_info(jid=jid, block=False, + timeout=5, callback=callback) + def get_error_message(self, stanza, deprecated=False): """ Takes a stanza of the form @@ -1422,6 +1444,7 @@ class Core(object): if not desc and shortdesc: desc = shortdesc self.commands[name] = Command(func, desc, completion, shortdesc, usage) + def register_initial_commands(self): """ Register the commands when poezio starts @@ -1623,7 +1646,8 @@ class Core(object): on_session_start_features = handlers.on_session_start_features on_carbon_received = handlers.on_carbon_received on_carbon_sent = handlers.on_carbon_sent - on_groupchat_invite = handlers.on_groupchat_invite + on_groupchat_invitation = handlers.on_groupchat_invitation + on_groupchat_direct_invitation = handlers.on_groupchat_direct_invitation on_groupchat_decline = handlers.on_groupchat_decline on_message = handlers.on_message on_normal_message = handlers.on_normal_message diff --git a/src/core/handlers.py b/src/core/handlers.py index 076bd986..b0256246 100644 --- a/src/core/handlers.py +++ b/src/core/handlers.py @@ -76,7 +76,10 @@ def on_carbon_sent(self, message): ### Invites ### -def on_groupchat_invite(self, message): +def on_groupchat_invitation(self, message): + """ + Mediated invitation received + """ jid = message['from'] if jid.bare in self.pending_invites: return @@ -97,8 +100,37 @@ def on_groupchat_invite(self, message): self.pending_invites[jid.bare] = inviter.full def on_groupchat_decline(self, decline): + "Mediated invitation declined; skip for now" pass +def on_groupchat_direct_invitation(self, message): + """ + Direct invitation received + """ + room = safeJID(message['groupchat_invite']['jid']) + if room.bare in self.pending_invites: + return + + inviter = message['from'] + reason = message['groupchat_invite']['reason'] + password = message['groupchat_invite']['password'] + continue_ = message['groupchat_invite']['continue'] + msg = "You are invited to the room %s by %s" % (room, inviter.full) + + if password: + msg += ' (password: "%s")' % password + if continue_: + msg += '\nto continue the discussion' + if reason: + msg += "\nreason: %s" % reason + + self.information(msg, 'Info') + if 'invite' in config.get('beep_on', 'invite').split(): + curses.beep() + + self.pending_invites[room.bare] = inviter.full + logger.log_roster_change(inviter.full, 'invited you to %s' % room.bare) + ### "classic" messages ### def on_message(self, message): -- cgit v1.2.3