Commit 3221534b authored by mathieui's avatar mathieui

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
parent 245f5f05
......@@ -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% |
......
......@@ -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')
......
......@@ -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 <room@server.tld> [reason]"""
......
......@@ -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):
......
......@@ -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 <message type='error'><error/></message>
......@@ -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
......
......@@ -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):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment