From c9c066ae336fd315d87de39894f06ce3aca3a2fc Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Jan 2012 19:13:04 +0100 Subject: [Link Mauve] Add the ability to send and receive Attention (XEP-0224). --- src/connection.py | 1 + src/core.py | 20 ++++++++++++++++++ src/tabs.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++------ src/theming.py | 6 ++++-- 4 files changed, 81 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/connection.py b/src/connection.py index 1079b5a6..74a21cdb 100644 --- a/src/connection.py +++ b/src/connection.py @@ -59,6 +59,7 @@ class Connection(sleekxmpp.ClientXMPP): self.register_plugin('xep_0092', pconfig=info) if config.get('send_time', 'true') == 'true': self.register_plugin('xep_0202') + self.register_plugin('xep_0224') def start(self): # TODO, try multiple servers diff --git a/src/core.py b/src/core.py index 9b74c1a5..4364734e 100644 --- a/src/core.py +++ b/src/core.py @@ -194,6 +194,7 @@ class Core(object): self.xmpp.add_event_handler("chatstate_paused", self.on_chatstate_paused) self.xmpp.add_event_handler("chatstate_gone", self.on_chatstate_gone) self.xmpp.add_event_handler("chatstate_inactive", self.on_chatstate_inactive) + self.xmpp.add_event_handler("attention", self.on_attention) self.xmpp.register_handler(Callback('ALL THE STANZAS', connection.MatchAll(None), self.incoming_stanza)) self.timed_events = set() @@ -503,6 +504,21 @@ class Core(object): tab.input.refresh() self.doupdate() + def on_attention(self, message): + jid_from = message['from'] + self.information('%s requests your attention!' % jid_from, 'Info') + for tab in self.tabs: + if tab.get_name() == jid_from: + tab.state = 'attention' + self.refresh_tab_win() + return + for tab in self.tabs: + if tab.get_name() == jid_from.bare: + tab.state = 'attention' + self.refresh_tab_win() + return + self.information('%s tab not found.' % jid_from, 'Error') + def open_new_form(self, form, on_cancel, on_send, **kwargs): """ Open a new tab containing the form @@ -1075,6 +1091,10 @@ class Core(object): - A Muc with an highlight - A Muc with any new message """ + for tab in self.tabs: + if tab.state == 'attention': + self.command_win('%s' % tab.nb) + return for tab in self.tabs: if tab.state == 'private': self.command_win('%s' % tab.nb) diff --git a/src/tabs.py b/src/tabs.py index 7df200b0..9bc6e24c 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -67,7 +67,7 @@ STATE_COLORS = { 'private': lambda: get_theme().COLOR_TAB_PRIVATE, 'normal': lambda: get_theme().COLOR_TAB_NORMAL, 'current': lambda: get_theme().COLOR_TAB_CURRENT, -# 'attention': lambda: get_theme().COLOR_TAB_ATTENTION, + 'attention': lambda: get_theme().COLOR_TAB_ATTENTION, } VERTICAL_STATE_COLORS = { @@ -77,7 +77,7 @@ VERTICAL_STATE_COLORS = { 'private': lambda: get_theme().COLOR_VERTICAL_TAB_PRIVATE, 'normal': lambda: get_theme().COLOR_VERTICAL_TAB_NORMAL, 'current': lambda: get_theme().COLOR_VERTICAL_TAB_CURRENT, -# 'attention': lambda: get_theme().COLOR_VERTICAL_TAB_ATTENTION, + 'attention': lambda: get_theme().COLOR_VERTICAL_TAB_ATTENTION, } @@ -88,7 +88,7 @@ STATE_PRIORITY = { 'message': 1, 'highlight': 2, 'private': 2, -# 'attention': 3 + 'attention': 3 } class Tab(object): @@ -156,7 +156,7 @@ class Tab(object): log.debug("Invalid value for tab state: %s", value) elif STATE_PRIORITY[value] < STATE_PRIORITY[self._state] and \ value != 'current': - log.debug("Did not set status because of lower priority, asked: %s, kept: %s", (value, self.state)) + log.debug("Did not set status because of lower priority, asked: %s, kept: %s", (value, self._state)) else: self._state = value @@ -349,6 +349,7 @@ class ChatTab(Tab): # if that’s None, then no paused chatstate was sent recently # if that’s a weakref returning None, then a paused chatstate was sent # since the last input + self.remote_supports_attention = False self.key_func['M-v'] = self.move_separator self.key_func['M-/'] = self.last_words_completion self.key_func['^M'] = self.on_enter @@ -495,6 +496,7 @@ class ChatTab(Tab): def command_say(self, line): raise NotImplementedError + class MucTab(ChatTab): """ The tab containing a multi-user-chat room. @@ -1359,6 +1361,7 @@ class PrivateTab(ChatTab): self._text_buffer.add_window(self.text_win) self.info_header = windows.PrivateInfoWin() self.input = windows.MessageInput() + self.check_attention() # keys self.key_func['^I'] = self.completion # commands @@ -1379,7 +1382,7 @@ class PrivateTab(ChatTab): def completion(self): self.complete_commands(self.input) - def command_say(self, line): + def command_say(self, line, attention=False): if not self.on: return msg = self.core.xmpp.make_message(self.get_name()) @@ -1396,12 +1399,35 @@ class PrivateTab(ChatTab): if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and self.remote_wants_chatstates is not False: needed = 'inactive' if self.core.status.show in ('xa', 'away') else 'active' msg['chat_state'] = needed + if attention and self.remote_supports_attention: + msg['attention'] = True self.core.events.trigger('private_say_after', msg, self) msg.send() self.cancel_paused_delay() self.text_win.refresh() self.input.refresh() + def command_attention(self, message=''): + if message is not '': + self.command_say(message, attention=True) + else: + msg = self.core.xmpp.make_message(self.get_name()) + msg['type'] = 'chat' + msg['attention'] = True + msg.send() + + def check_attention(self): + self.core.xmpp.plugin['xep_0030'].get_info(jid=self.get_name(), block=False, timeout=5, callback=self.on_attention_checked) + + def on_attention_checked(self, iq): + if 'urn:xmpp:attention:0' in iq['disco_info'].get_features(): + self.core.information('Attention is supported!', 'Info') + self.remote_supports_attention = True + self.commands['attention'] = (self.command_attention, _('Usage: /attention [message]\nAttention: Require the attention of the contact. Can also send a message along with the attention.'), None) + else: + self.core.information('Attention is not supported. :(', 'Info') + self.remote_supports_attention = False + def command_unquery(self, arg): """ /unquery @@ -2096,6 +2122,7 @@ class ConversationTab(ChatTab): self.upper_bar = windows.ConversationStatusMessageWin() self.info_header = windows.ConversationInfoWin() self.input = windows.MessageInput() + self.check_attention() # keys self.key_func['^I'] = self.completion # commands @@ -2125,7 +2152,7 @@ class ConversationTab(ChatTab): def completion(self): self.complete_commands(self.input) - def command_say(self, line): + def command_say(self, line, attention=False): msg = self.core.xmpp.make_message(self.get_name()) msg['type'] = 'chat' msg['body'] = line @@ -2141,6 +2168,8 @@ class ConversationTab(ChatTab): if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and self.remote_wants_chatstates is not False: needed = 'inactive' if self.core.status.show in ('xa', 'away') else 'active' msg['chat_state'] = needed + if attention and self.remote_supports_attention: + msg['attention'] = True self.core.events.trigger('conversation_say_after', msg, self) msg.send() logger.log_message(JID(self.get_name()).bare, self.core.own_nick, line) @@ -2160,6 +2189,27 @@ class ConversationTab(ChatTab): self.refresh() self.core.doupdate() + def command_attention(self, message=''): + if message is not '': + self.command_say(message, attention=True) + else: + msg = self.core.xmpp.make_message(self.get_name()) + msg['type'] = 'chat' + msg['attention'] = True + msg.send() + + def check_attention(self): + self.core.xmpp.plugin['xep_0030'].get_info(jid=self.get_name(), block=False, timeout=5, callback=self.on_attention_checked) + + def on_attention_checked(self, iq): + if 'urn:xmpp:attention:0' in iq['disco_info'].get_features(): + self.core.information('Attention is supported!', 'Info') + self.remote_supports_attention = True + self.commands['attention'] = (self.command_attention, _('Usage: /attention [message]\nAttention: Require the attention of the contact. Can also send a message along with the attention.'), None) + else: + self.core.information('Attention is not supported. :(', 'Info') + self.remote_supports_attention = False + def command_unquery(self, arg): self.core.close_tab() diff --git a/src/theming.py b/src/theming.py index 25188f81..fba33366 100644 --- a/src/theming.py +++ b/src/theming.py @@ -124,15 +124,17 @@ class Theme(object): COLOR_TAB_NORMAL = (7, 4) COLOR_TAB_CURRENT = (7, 6) COLOR_TAB_NEW_MESSAGE = (7, 5) - COLOR_TAB_HIGHLIGHT = (7, 1) + COLOR_TAB_HIGHLIGHT = (7, 3) COLOR_TAB_PRIVATE = (7, 2) + COLOR_TAB_ATTENTION = (7, 1) COLOR_TAB_DISCONNECTED = (7, 8) COLOR_VERTICAL_TAB_NORMAL = (4, -1) COLOR_VERTICAL_TAB_CURRENT = (7, 4) COLOR_VERTICAL_TAB_NEW_MESSAGE = (5, -1) - COLOR_VERTICAL_TAB_HIGHLIGHT = (1, -1) + COLOR_VERTICAL_TAB_HIGHLIGHT = (3, -1) COLOR_VERTICAL_TAB_PRIVATE = (2, -1) + COLOR_VERTICAL_TAB_ATTENTION = (1, -1) COLOR_VERTICAL_TAB_DISCONNECTED = (8, -1) # Nickname colors -- cgit v1.2.3