Commit 749933fc authored by louiz’'s avatar louiz’

/accept and /deny commands

User can now decide to accept or deny a subscription, in
the roster
parent 6bb94cdf
...@@ -50,6 +50,7 @@ class Connection(sleekxmpp.ClientXMPP): ...@@ -50,6 +50,7 @@ class Connection(sleekxmpp.ClientXMPP):
password = None password = None
sleekxmpp.ClientXMPP.__init__(self, jid, password, ssl=True) sleekxmpp.ClientXMPP.__init__(self, jid, password, ssl=True)
self.auto_reconnect = False self.auto_reconnect = False
self.auto_authorize = None
self.register_plugin('xep_0030') self.register_plugin('xep_0030')
self.register_plugin('xep_0045') self.register_plugin('xep_0045')
if config.get('send_poezio_info', 'true') == 'true': if config.get('send_poezio_info', 'true') == 'true':
......
...@@ -159,7 +159,7 @@ class Core(object): ...@@ -159,7 +159,7 @@ class Core(object):
self.xmpp.add_event_handler("got_offline" , self.on_got_offline) self.xmpp.add_event_handler("got_offline" , self.on_got_offline)
self.xmpp.add_event_handler("roster_update", self.on_roster_update) self.xmpp.add_event_handler("roster_update", self.on_roster_update)
self.xmpp.add_event_handler("changed_status", self.on_presence) self.xmpp.add_event_handler("changed_status", self.on_presence)
self.xmpp.add_event_handler("changed_subscription", self.on_changed_subscription)
self.information(_('Welcome to poezio!')) self.information(_('Welcome to poezio!'))
self.refresh_window() self.refresh_window()
...@@ -594,6 +594,22 @@ class Core(object): ...@@ -594,6 +594,22 @@ class Core(object):
if isinstance(self.current_tab(), tabs.RosterInfoTab): if isinstance(self.current_tab(), tabs.RosterInfoTab):
self.refresh_window() self.refresh_window()
def on_changed_subscription(self, presence):
"""
Triggered whenever a presence stanza with a type of subscribe, subscribed, unsubscribe, or unsubscribed is received.
"""
if presence['type'] == 'subscribe':
jid = presence['from'].bare
contact = roster.get_contact_by_jid(jid)
if not contact:
contact = Contact(jid)
roster.add_contact(contact, jid)
roster.edit_groups_of_contact(contact, [])
contact.set_ask('asked')
if isinstance(self.current_tab(), tabs.RosterInfoTab):
self.refresh_window()
def full_screen_redraw(self): def full_screen_redraw(self):
""" """
Completely erase and redraw the screen Completely erase and redraw the screen
......
...@@ -37,9 +37,17 @@ class Roster(object): ...@@ -37,9 +37,17 @@ class Roster(object):
""" """
Add a contact to the contact list Add a contact to the contact list
""" """
assert jid not in self._contacts
self._contacts[jid] = contact self._contacts[jid] = contact
def remove_contact(self, jid):
"""
Remove a contact from the contact list
"""
contact = self.get_contact_by_jid(jid)
for group in contact._groups:
group.remove_contact_from_group(contact)
del self._contacts[jid]
def get_contact_len(self): def get_contact_len(self):
""" """
Return the number of contacts in this group Return the number of contacts in this group
...@@ -110,6 +118,12 @@ class Roster(object): ...@@ -110,6 +118,12 @@ class Roster(object):
""" """
return self._roster_groups return self._roster_groups
def get_contacts(self):
"""
Return a list of all the contact
"""
return [contact for contact in self._contacts.values()]
def save_to_config_file(self): def save_to_config_file(self):
""" """
Save various information to the config file Save various information to the config file
...@@ -127,7 +141,7 @@ class Roster(object): ...@@ -127,7 +141,7 @@ class Roster(object):
""" """
length = 0 length = 0
for group in self._roster_groups: for group in self._roster_groups:
if group.get_nb_connected_contacts() == 0: if config.get('roster_show_offline', 'false') == 'false' and group.get_nb_connected_contacts() == 0:
continue continue
length += 1 # One for the group's line itself length += 1 # One for the group's line itself
if not group.folded: if not group.folded:
......
...@@ -94,6 +94,26 @@ class Tab(object): ...@@ -94,6 +94,26 @@ class Tab(object):
return True return True
return False return False
def on_enter(self, provided_text=None):
"""
Execute the command in the input and return False if
the input didn't contain a command
"""
txt = provided_text or self.input.key_enter()
if txt.startswith('/') and not txt.startswith('//') and\
not txt.startswith('/me '):
command = txt.strip().split()[0][1:]
arg = txt[2+len(command):] # jump the '/' and the ' '
if command in self.core.commands: # check global commands
self.core.commands[command][0](arg)
elif command in self.commands: # check tab-specific commands
self.commands[command][0](arg)
else:
self.core.information(_("Unknown command (%s)") % (command), _('Error'))
return True
else:
return False
def resize(self): def resize(self):
self.size = (self.height, self.width) = self.core.stdscr.getmaxyx() self.size = (self.height, self.width) = self.core.stdscr.getmaxyx()
if self.height < MIN_HEIGHT or self.width < MIN_WIDTH: if self.height < MIN_HEIGHT or self.width < MIN_WIDTH:
...@@ -225,18 +245,7 @@ class ChatTab(Tab): ...@@ -225,18 +245,7 @@ class ChatTab(Tab):
self.input.auto_completion(words, ' ') self.input.auto_completion(words, ' ')
def on_enter(self): def on_enter(self):
txt = self.input.key_enter() if not Tab.on_enter(self):
if txt.startswith('/') and not txt.startswith('//') and\
not txt.startswith('/me '):
command = txt.strip().split()[0][1:]
arg = txt[2+len(command):] # jump the '/' and the ' '
if command in self.core.commands: # check global commands
self.core.commands[command][0](arg)
elif command in self.commands: # check tab-specific commands
self.commands[command][0](arg)
else:
self.core.information(_("Unknown command (%s)") % (command), _('Error'))
else:
if txt.startswith('//'): if txt.startswith('//'):
txt = txt[1:] txt = txt[1:]
self.command_say(txt) self.command_say(txt)
...@@ -277,20 +286,6 @@ class InfoTab(ChatTab): ...@@ -277,20 +286,6 @@ class InfoTab(ChatTab):
self.tab_win.refresh(tabs, tabs[0]) self.tab_win.refresh(tabs, tabs[0])
self.input.refresh() self.input.refresh()
def on_enter(self):
# TODO duplicate
txt = self.input.get_text()
if txt.startswith('/') and not txt.startswith('//') and\
not txt.startswith('/me '):
command = txt.strip().split()[0][1:]
arg = txt[2+len(command):] # jump the '/' and the ' '
if command in self.core.commands: # check global commands
self.core.commands[command][0](arg)
elif command in self.commands: # check tab-specific commands
self.commands[command][0](arg)
else:
self.core.information(_("Unknown command (%s)") % (command), _('Error'))
def completion(self): def completion(self):
self.complete_commands(self.input) self.complete_commands(self.input)
...@@ -758,6 +753,7 @@ class RosterInfoTab(Tab): ...@@ -758,6 +753,7 @@ class RosterInfoTab(Tab):
self.key_func["s"] = self.start_search self.key_func["s"] = self.start_search
self.key_func["S"] = self.start_search_slow self.key_func["S"] = self.start_search_slow
self.commands['deny'] = (self.command_deny, _("Usage: /deny [jid]\nDeny: Use this command to remove and deny your presence to the provided JID (or the selected contact in your roster), who is asking you to be in his/here roster"), self.completion_deny) self.commands['deny'] = (self.command_deny, _("Usage: /deny [jid]\nDeny: Use this command to remove and deny your presence to the provided JID (or the selected contact in your roster), who is asking you to be in his/here roster"), self.completion_deny)
self.commands['accept'] = (self.command_accept, _("Usage: /accpet [jid]\nAccept: Use this command to authorize the provided JID (or the selected contact in your roster), to see your presence, and to ask to subscribe to it (mutual presence subscription)."), self.completion_deny)
self.resize() self.resize()
def resize(self): def resize(self):
...@@ -781,7 +777,46 @@ class RosterInfoTab(Tab): ...@@ -781,7 +777,46 @@ class RosterInfoTab(Tab):
""" """
Denies a JID from our roster Denies a JID from our roster
""" """
args = args.split()
if not args:
item = self.roster_win.selected_row
if isinstance(item, Contact) and item.get_ask() == 'asked':
jid = item.get_bare_jid()
else:
self.core.information('No subscription to deny')
return
else:
jid = args[0]
self.core.xmpp.sendPresence(pto=jid, ptype='unsubscribed')
if self.core.xmpp.update_roster(jid, subscription='remove'):
roster.remove_contact(jid)
def completion_deny(self, the_input):
"""
Complete the first argument from the list of the
contact with ask=='subscribe'
"""
jids = [contact.get_bare_jid() for contact in roster.get_contacts()\
if contact.get_ask() == 'asked']
the_input.auto_completion(jids, '')
def command_accept(self, args):
"""
Accept a JID from in roster. Authorize it AND subscribe to it
"""
args = args.split()
if not args:
item = self.roster_win.selected_row
if isinstance(item, Contact) and item.get_ask() == 'asked':
jid = item.get_bare_jid()
else:
self.core.information('No subscription to deny')
return
else:
jid = args[0]
self.core.xmpp.sendPresence(pto=jid, ptype='subscribed')
self.core.xmpp.sendPresence(pto=jid, ptype='subscribe')
def refresh(self, tabs, informations, roster): def refresh(self, tabs, informations, roster):
if not self.visible: if not self.visible:
return return
...@@ -836,7 +871,7 @@ class RosterInfoTab(Tab): ...@@ -836,7 +871,7 @@ class RosterInfoTab(Tab):
def execute_slash_command(self, txt): def execute_slash_command(self, txt):
if txt.startswith('/'): if txt.startswith('/'):
self.core.execute(txt) Tab.on_enter(self, txt)
return self.reset_help_message() return self.reset_help_message()
def on_lose_focus(self): def on_lose_focus(self):
......
...@@ -1187,7 +1187,7 @@ class RosterWin(Win): ...@@ -1187,7 +1187,7 @@ class RosterWin(Win):
self.draw_roster_information(roster) self.draw_roster_information(roster)
y = 1 y = 1
for group in roster.get_groups(): for group in roster.get_groups():
if group.get_nb_connected_contacts() == 0: if config.get('roster_show_offline', 'false') == 'false' and group.get_nb_connected_contacts() == 0:
continue # Ignore empty groups continue # Ignore empty groups
# This loop is really REALLY ugly :^) # This loop is really REALLY ugly :^)
if y-1 == self.pos: if y-1 == self.pos:
...@@ -1283,7 +1283,7 @@ class RosterWin(Win): ...@@ -1283,7 +1283,7 @@ class RosterWin(Win):
self.addstr(display_name, curses.color_pair(14)) self.addstr(display_name, curses.color_pair(14))
else: else:
self.addstr(display_name) self.addstr(display_name)
if contact.get_ask(): if contact.get_ask() == 'asked':
self.addstr('?', curses.color_pair(1)) self.addstr('?', curses.color_pair(1))
def draw_resource_line(self, y, resource, colored): def draw_resource_line(self, y, resource, colored):
...@@ -1324,7 +1324,10 @@ class ContactInfoWin(Win): ...@@ -1324,7 +1324,10 @@ class ContactInfoWin(Win):
self.finish_line(theme.COLOR_INFORMATION_BAR) self.finish_line(theme.COLOR_INFORMATION_BAR)
self.addstr(1, 0, 'Subscription: %s' % (contact.get_subscription(),)) self.addstr(1, 0, 'Subscription: %s' % (contact.get_subscription(),))
if contact.get_ask(): if contact.get_ask():
self.addstr(' Ask: %s' % (contact.get_ask(),), curses.color_pair(1)) if contact.get_ask() == 'asked':
self.addstr(' Ask: %s' % (contact.get_ask(),), curses.color_pair(1))
else:
self.addstr(' Ask: %s' % (contact.get_ask(),))
def draw_group_info(self, group): def draw_group_info(self, group):
""" """
......
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