summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2011-01-11 06:43:31 +0100
committerFlorent Le Coz <louiz@louiz.org>2011-01-11 06:43:31 +0100
commit749933fc16005d8e81d54830f532dd1cb9f85773 (patch)
treebd34b228e49f83c225afdd8ea9fa661b5ec36504 /src
parent6bb94cdf0b88671b2ac12eb67f70555da565f238 (diff)
downloadpoezio-749933fc16005d8e81d54830f532dd1cb9f85773.tar.gz
poezio-749933fc16005d8e81d54830f532dd1cb9f85773.tar.bz2
poezio-749933fc16005d8e81d54830f532dd1cb9f85773.tar.xz
poezio-749933fc16005d8e81d54830f532dd1cb9f85773.zip
/accept and /deny commands
User can now decide to accept or deny a subscription, in the roster
Diffstat (limited to 'src')
-rw-r--r--src/connection.py1
-rw-r--r--src/core.py18
-rw-r--r--src/roster.py18
-rw-r--r--src/tabs.py91
-rw-r--r--src/windows.py9
5 files changed, 103 insertions, 34 deletions
diff --git a/src/connection.py b/src/connection.py
index dc2eeaae..d29fec82 100644
--- a/src/connection.py
+++ b/src/connection.py
@@ -50,6 +50,7 @@ class Connection(sleekxmpp.ClientXMPP):
password = None
sleekxmpp.ClientXMPP.__init__(self, jid, password, ssl=True)
self.auto_reconnect = False
+ self.auto_authorize = None
self.register_plugin('xep_0030')
self.register_plugin('xep_0045')
if config.get('send_poezio_info', 'true') == 'true':
diff --git a/src/core.py b/src/core.py
index 6fdb883c..c3b3510d 100644
--- a/src/core.py
+++ b/src/core.py
@@ -159,7 +159,7 @@ class Core(object):
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("changed_status", self.on_presence)
-
+ self.xmpp.add_event_handler("changed_subscription", self.on_changed_subscription)
self.information(_('Welcome to poezio!'))
self.refresh_window()
@@ -594,6 +594,22 @@ class Core(object):
if isinstance(self.current_tab(), tabs.RosterInfoTab):
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):
"""
Completely erase and redraw the screen
diff --git a/src/roster.py b/src/roster.py
index 1abc1cd3..1fd1099d 100644
--- a/src/roster.py
+++ b/src/roster.py
@@ -37,9 +37,17 @@ class Roster(object):
"""
Add a contact to the contact list
"""
- assert jid not in self._contacts
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):
"""
Return the number of contacts in this group
@@ -110,6 +118,12 @@ class Roster(object):
"""
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):
"""
Save various information to the config file
@@ -127,7 +141,7 @@ class Roster(object):
"""
length = 0
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
length += 1 # One for the group's line itself
if not group.folded:
diff --git a/src/tabs.py b/src/tabs.py
index c5c7d791..6396b833 100644
--- a/src/tabs.py
+++ b/src/tabs.py
@@ -94,6 +94,26 @@ class Tab(object):
return True
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):
self.size = (self.height, self.width) = self.core.stdscr.getmaxyx()
if self.height < MIN_HEIGHT or self.width < MIN_WIDTH:
@@ -225,18 +245,7 @@ class ChatTab(Tab):
self.input.auto_completion(words, ' ')
def on_enter(self):
- txt = 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'))
- else:
+ if not Tab.on_enter(self):
if txt.startswith('//'):
txt = txt[1:]
self.command_say(txt)
@@ -277,20 +286,6 @@ class InfoTab(ChatTab):
self.tab_win.refresh(tabs, tabs[0])
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):
self.complete_commands(self.input)
@@ -758,6 +753,7 @@ class RosterInfoTab(Tab):
self.key_func["s"] = self.start_search
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['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()
def resize(self):
@@ -781,7 +777,46 @@ class RosterInfoTab(Tab):
"""
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):
if not self.visible:
return
@@ -836,7 +871,7 @@ class RosterInfoTab(Tab):
def execute_slash_command(self, txt):
if txt.startswith('/'):
- self.core.execute(txt)
+ Tab.on_enter(self, txt)
return self.reset_help_message()
def on_lose_focus(self):
diff --git a/src/windows.py b/src/windows.py
index 4020e72b..cbb58b3f 100644
--- a/src/windows.py
+++ b/src/windows.py
@@ -1187,7 +1187,7 @@ class RosterWin(Win):
self.draw_roster_information(roster)
y = 1
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
# This loop is really REALLY ugly :^)
if y-1 == self.pos:
@@ -1283,7 +1283,7 @@ class RosterWin(Win):
self.addstr(display_name, curses.color_pair(14))
else:
self.addstr(display_name)
- if contact.get_ask():
+ if contact.get_ask() == 'asked':
self.addstr('?', curses.color_pair(1))
def draw_resource_line(self, y, resource, colored):
@@ -1324,7 +1324,10 @@ class ContactInfoWin(Win):
self.finish_line(theme.COLOR_INFORMATION_BAR)
self.addstr(1, 0, 'Subscription: %s' % (contact.get_subscription(),))
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):
"""