From 122d700ac3584eb2c93c0963b2c3ba078f9279d5 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 28 Nov 2011 22:32:44 +0100 Subject: We can now configure each conversation independently, for some options. Fixed #2039. --- doc/en/configure.txt | 56 +++++++++++++++++++++++++++++++++++++++++---- src/config.py | 18 ++++++++++++++- src/core.py | 9 +++++--- src/tabs.py | 64 ++++++++++++++++++++++++++++++++-------------------- 4 files changed, 114 insertions(+), 33 deletions(-) diff --git a/doc/en/configure.txt b/doc/en/configure.txt index cad24be3..4e93a2c5 100644 --- a/doc/en/configure.txt +++ b/doc/en/configure.txt @@ -11,8 +11,9 @@ in the _keys_ documentation file. That file is read at each startup and the configuration is saved when poezio is closed. -This configuration file *requires* all the options to be in a section -named [Poezio]. +This configuration file *requires* all global options to be in a section +named [Poezio]. Some other options can be in optional sections and will +apply only to tabs having the option’s name. An option is formatted with the form ====================== @@ -29,6 +30,13 @@ and their default value. Configuration options --------------------- +Global section options +~~~~~~~~~~~~~~~~~~~~~~ + +These option have a sense when they are in the global section. Some of +them can also be in an optional configuration section, see the next +section of this documentation. + [horizontal] *server*:: anon.louiz.org @@ -67,8 +75,6 @@ Configuration options A password is needed only if you specified a jid. It will be ignored otherwise If you leave this empty, the password will be asked at each startup - - *rooms*:: poezio@muc.poezio.eu the rooms you will join automatically on startup, with associated nickname or not @@ -137,6 +143,10 @@ Configuration options Default setting means: - all quit and join notices will be displayed +*display_user_color_in_join_part*:: false + + If set to true, the color of the nick will be used in MUCs information + messages, instead of the default color from the theme. *information_buffer_popup_on*:: error roster warning help info @@ -309,3 +319,41 @@ Configuration options You can specify another directory to use. It will be created if it does not exist. +Optional section options +~~~~~~~~~~~~~~~~~~~~~~~~ +These option can appear in optional sections. These section are named +after a JID. These option will apply only for the given JID. For example +if an option appears in a section named [user@example.com], it will +apply only for the conversations with user@example.com. + +Note that some of these options can also appear in the global section, +they will be used as a fallback value when no JID-specific option is +found. + +.foo is _true_ for *user@example.com* but is _false_ for everyone else +============================================ +[source,conf] +------------- +[Poezio] +foo = false +[user@example.com] +foo = true +------------- +============================================ + +*disable_beep*:: false + + Disable the beeps triggered by this conversation. Works in MucTab, + PrivateTab and ConversationTab. + +*send_chat_states*:: true + + Lets you disable/enable chatstates per-JID. Works in MucTab, PrivateTab and ConversationTab. + +*display_user_color_in_join_part*:: false + +*hide_exit_join*:: -1 + +*hide_status_change*:: 120 + +*highlight_on*:: [empty] diff --git a/src/config.py b/src/config.py index 8bc0d863..af9c9fbe 100644 --- a/src/config.py +++ b/src/config.py @@ -46,10 +46,26 @@ class Config(RawConfigParser): res = self.getboolean(option, section) else: res = self.getstr(option, section) - except( NoOptionError, NoSectionError): + except (NoOptionError, NoSectionError): return default return res + def get_by_tabname(self, option, default, tabname, fallback=True): + """ + Try to get the value for the option. First we look in + a section named `tabname`, if the option is not present + in the section, we search for the global option if fallback is + True. And we return `default` as a fallback as a last resort. + """ + if tabname in self.sections(): + if option in self.options(tabname): + # We go the tab-specific option + return self.get(option, default, tabname) + if fallback: + # We fallback to the global option + return self.get(option, default) + return default + def __get(self, option, section=DEFSECTION): """ facility for RawConfigParser.get diff --git a/src/core.py b/src/core.py index 8704563c..b940bb73 100644 --- a/src/core.py +++ b/src/core.py @@ -687,7 +687,8 @@ class Core(object): else: conversation.remote_wants_chatstates = False if 'private' in config.get('beep_on', 'highlight private').split(): - curses.beep() + if config.get_by_tabname('disable_beep', 'false', jid.full, False).lower() != 'true': + curses.beep() logger.log_message(jid.full.replace('/', '\\'), nick_from, body) if conversation is self.current_tab(): self.refresh_window() @@ -745,7 +746,8 @@ class Core(object): conversation.remote_wants_chatstates = False logger.log_message(jid.bare, remote_nick, body) if 'private' in config.get('beep_on', 'highlight private').split(): - curses.beep() + if config.get_by_tabname('disable_beep', 'false', jid.bare, False).lower() != 'true': + curses.beep() if self.current_tab() is not conversation: conversation.state = 'private' self.refresh_tab_win() @@ -1207,7 +1209,8 @@ class Core(object): tab.info_header.refresh(tab, tab.text_win) self.refresh_tab_win() if 'message' in config.get('beep_on', 'highlight private').split(): - curses.beep() + if config.get_by_tabname('disable_beep', 'false', jid.bare, False).lower() != 'true': + curses.beep() def add_message_to_text_buffer(self, buff, txt, time=None, nickname=None, history=None): """ diff --git a/src/tabs.py b/src/tabs.py index f9940d82..e75989a7 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -440,7 +440,8 @@ class ChatTab(Tab): Send the "active" or "composing" chatstate, depending on the the current status of the input """ - if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates: + name = self.general_jid + if config.get_by_tabname('send_chat_states', 'true', name, True) == 'true' and self.remote_wants_chatstates: needed = 'inactive' if self.core.status.show in ('xa', 'away') else 'active' self.cancel_paused_delay() if not empty_after: @@ -455,7 +456,7 @@ class ChatTab(Tab): we create a timed event that will put us to paused in a few seconds """ - if config.get('send_chat_states', 'true') != 'true': + if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) != 'true': return if self.timed_event_paused: # check the weakref @@ -546,6 +547,10 @@ class MucTab(ChatTab): self.update_commands() self.update_keys() + @property + def general_jid(self): + return self.get_name() + def completion_version(self, the_input): """Completion for /version""" compare_users = lambda x: x.last_talked @@ -880,7 +885,7 @@ class MucTab(ChatTab): if msg['body'].find('\x19') != -1: msg['xhtml_im'] = xhtml.poezio_colors_to_html(msg['body']) msg['body'] = xhtml.clean_text(msg['body']) - if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates is not False: + if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and self.remote_wants_chatstates is not False: msg['chat_state'] = needed self.cancel_paused_delay() self.core.events.trigger('muc_say_after', msg, self) @@ -1002,7 +1007,7 @@ class MucTab(ChatTab): self.state = 'normal' self.text_win.remove_line_separator() self.text_win.add_line_separator() - if config.get('send_chat_states', 'true') == 'true' and not self.input.get_text(): + if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text(): self.send_chat_state('inactive') def on_gain_focus(self): @@ -1010,7 +1015,7 @@ class MucTab(ChatTab): if self.text_win.built_lines and self.text_win.built_lines[-1] is None: self.text_win.remove_line_separator() curses.curs_set(1) - if self.joined and config.get('send_chat_states', 'true') == 'true' and not self.input.get_text(): + if self.joined and config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text(): self.send_chat_state('active') def on_scroll_up(self): @@ -1089,9 +1094,9 @@ class MucTab(ChatTab): user = User(from_nick, affiliation, show, status, role, jid) self.users.append(user) - hide_exit_join = config.get('hide_exit_join', -1) + hide_exit_join = config.get_by_tabname('hide_exit_join', -1, self.general_jid, True) if hide_exit_join != 0: - color = user.color[0] if config.get('display_user_color_in_join_part', '') == 'true' else 3 + color = user.color[0] if config.get_by_tabname('display_user_color_in_join_part', '', self.general_jid, True) == 'true' else 3 if not jid.full: self.add_message('\x194}%(spec)s \x19%(color)d}%(nick)s\x195} joined the room' % {'nick':from_nick, 'color':color, 'spec':get_theme().CHAR_JOIN}) else: @@ -1107,7 +1112,7 @@ class MucTab(ChatTab): if isinstance(_tab, PrivateTab) and JID(_tab.get_name()).bare == self.name: _tab.own_nick = new_nick user.change_nick(new_nick) - color = user.color[0] if config.get('display_user_color_in_join_part', '') == 'true' else 3 + color = user.color[0] if config.get_by_tabname('display_user_color_in_join_part', '', self.general_jid, True) == 'true' else 3 self.add_message('\x19%(color)d}%(old)s\x195} is now known as \x19%(color)d}%(new)s' % {'old':from_nick, 'new':new_nick, 'color':color}) # rename the private tabs if needed self.core.rename_private_tabs(self.name, from_nick, new_nick) @@ -1130,7 +1135,7 @@ class MucTab(ChatTab): else: kick_msg = _('\x191}%(spec)s \x193}You\x195} have been banned.') % {'spec':get_theme().CHAR_KICK} else: - color = user.color[0] if config.get('display_user_color_in_join_part', '') == 'true' else 3 + color = user.color[0] if config.get_by_tabname('display_user_color_in_join_part', '', self.general_jid, True) == 'true' else 3 if by: kick_msg = _('\x191}%(spec)s \x19%(color)d}%(nick)s\x195} has been banned by \x194}%(by)s') % {'spec':get_theme().CHAR_KICK, 'nick':from_nick, 'color':color, 'by':by} else: @@ -1157,10 +1162,10 @@ class MucTab(ChatTab): else: kick_msg = _('\x191}%(spec)s \x193}You\x195} have been kicked.') % {'spec':get_theme().CHAR_KICK} # try to auto-rejoin - if config.get('autorejoin', 'false') == 'true': + if config.get_by_tabname('autorejoin', 'false', self.general_jid, True) == 'true': muc.join_groupchat(self.core.xmpp, self.name, self.own_nick) else: - color = user.color[0] if config.get('display_user_color_in_join_part', '') == 'true' else 3 + color = user.color[0] if config.get_by_tabname('display_user_color_in_join_part', '', self.general_jid, True) == 'true' else 3 if by: kick_msg = _('\x191}%(spec)s \x19%(color)d}%(nick)s\x195} has been kicked by \x193}%(by)s') % {'spec':get_theme().CHAR_KICK.replace('"', '\\"'), 'nick':from_nick.replace('"', '\\"'), 'color':color, 'by':by.replace('"', '\\"')} else: @@ -1180,9 +1185,9 @@ class MucTab(ChatTab): self.core.disable_private_tabs(from_room) self.refresh_tab_win() self.core.doupdate() - hide_exit_join = config.get('hide_exit_join', -1) if config.get('hide_exit_join', -1) >= -1 else -1 + hide_exit_join = config.get_by_tabname('hide_exit_join', -1, self.general_jid, True) if config.get_by_tabname('hide_exit_join', -1, self.general_jid, True) >= -1 else -1 if hide_exit_join == -1 or user.has_talked_since(hide_exit_join): - color = user.color[0] if config.get('display_user_color_in_join_part', '') == 'true' else 3 + color = user.color[0] if config.get_by_tabname('display_user_color_in_join_part', '', self.general_jid, True) == 'true' else 3 if not jid.full: leave_msg = _('\x191}%(spec)s \x19%(color)d}%(nick)s\x195} has left the room') % {'nick':from_nick, 'color':color, 'spec':get_theme().CHAR_QUIT} else: @@ -1200,7 +1205,7 @@ class MucTab(ChatTab): # build the message display_message = False # flag to know if something significant enough # to be displayed has changed - color = user.color[0] if config.get('display_user_color_in_join_part', '') == 'true' else 3 + color = user.color[0] if config.get_by_tabname('display_user_color_in_join_part', '', self.general_jid, True) == 'true' else 3 if from_nick == self.own_nick: msg = _('\x193}You\x195} changed: ') else: @@ -1228,7 +1233,7 @@ class MucTab(ChatTab): if not display_message: return msg = msg[:-2] # remove the last ", " - hide_status_change = config.get('hide_status_change', -1) + hide_status_change = config.get_by_tabname('hide_status_change', -1, self.general_jid, True) if hide_status_change < -1: hide_status_change = -1 if (hide_status_change == -1 or \ @@ -1279,7 +1284,7 @@ class MucTab(ChatTab): self.state = 'highlight' color = get_theme().COLOR_HIGHLIGHT_NICK else: - highlight_words = config.get('highlight_on', '').split(':') + highlight_words = config.get_by_tabname('highlight_on', '', self.general_jid, True).split(':') for word in highlight_words: if word and word.lower() in txt.lower(): if self.state != 'current': @@ -1289,7 +1294,8 @@ class MucTab(ChatTab): if color: beep_on = config.get('beep_on', 'highlight private').split() if 'highlight' in beep_on and 'message' not in beep_on: - curses.beep() + if config.get_by_tabname('disable_beep', 'false', self.name, False).lower() != 'true': + curses.beep() return color def get_user_by_name(self, nick): @@ -1356,6 +1362,10 @@ class PrivateTab(ChatTab): self.update_commands() self.update_keys() + @property + def general_jid(self): + return self.get_name() + def completion(self): self.complete_commands(self.input) @@ -1373,7 +1383,7 @@ class PrivateTab(ChatTab): if msg['body'].find('\x19') != -1: msg['xhtml_im'] = xhtml.poezio_colors_to_html(msg['body']) msg['body'] = xhtml.clean_text(msg['body']) - if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates is not False: + 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 self.core.events.trigger('private_say_after', msg, self) @@ -1457,14 +1467,14 @@ class PrivateTab(ChatTab): self.text_win.remove_line_separator() self.text_win.add_line_separator() tab = self.core.get_tab_by_name(JID(self.name).bare, MucTab) - if tab.joined and config.get('send_chat_states', 'true') == 'true' and not self.input.get_text(): + if tab.joined and config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text(): self.send_chat_state('inactive') def on_gain_focus(self): self.state = 'current' curses.curs_set(1) tab = self.core.get_tab_by_name(JID(self.name).bare, MucTab) - if tab.joined and config.get('send_chat_states', 'true') == 'true' and not self.input.get_text(): + if tab.joined and config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text(): self.send_chat_state('active') def on_scroll_up(self): @@ -1511,7 +1521,7 @@ class PrivateTab(ChatTab): self.activate() tab = self.core.get_tab_by_name(JID(self.name).bare, MucTab) color = 3 - if tab and config.get('display_user_color_in_join_part', ''): + if tab and config.get_by_tabname('display_user_color_in_join_part', '', self.general_jid, True): user = tab.get_user_by_name(nick) if user: color = user.color[0] @@ -2085,6 +2095,10 @@ class ConversationTab(ChatTab): self.update_commands() self.update_keys() + @property + def general_jid(self): + return JID(self.get_name()).bare + @staticmethod def add_information_element(plugin_name, callback): """ @@ -2112,7 +2126,7 @@ class ConversationTab(ChatTab): if msg['body'].find('\x19') != -1: msg['xhtml_im'] = xhtml.poezio_colors_to_html(msg['body']) msg['body'] = xhtml.clean_text(msg['body']) - if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates is not False: + 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 self.core.events.trigger('conversation_say_after', msg, self) @@ -2202,7 +2216,7 @@ class ConversationTab(ChatTab): self.state = 'normal' self.text_win.remove_line_separator() self.text_win.add_line_separator() - if config.get('send_chat_states', 'true') == 'true' and (not self.input.get_text() or not self.input.get_text().startswith('//')): + if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and (not self.input.get_text() or not self.input.get_text().startswith('//')): if resource: self.send_chat_state('inactive') @@ -2219,7 +2233,7 @@ class ConversationTab(ChatTab): self.state = 'current' curses.curs_set(1) - if config.get('send_chat_states', 'true') == 'true' and (not self.input.get_text() or not self.input.get_text().startswith('//')): + if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and (not self.input.get_text() or not self.input.get_text().startswith('//')): if resource: self.send_chat_state('active') @@ -2241,7 +2255,7 @@ class ConversationTab(ChatTab): def on_close(self): Tab.on_close(self) - if config.get('send_chat_states', 'true') == 'true': + if config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true': self.send_chat_state('gone') def add_message(self, txt, time=None, nickname=None, forced_user=None): -- cgit v1.2.3 From 2f8f4eccb8fe9bc8b34f47c80c9e963866f21628 Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 28 Nov 2011 16:46:20 +0100 Subject: Curses operations must operate within the lock --- src/windows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows.py b/src/windows.py index 81153239..80a8bbb1 100644 --- a/src/windows.py +++ b/src/windows.py @@ -660,8 +660,8 @@ class TextWin(Win): lines = self.built_lines[-self.height:] else: lines = self.built_lines[-self.height-self.pos:-self.pos] - self._win.move(0, 0) with g_lock: + self._win.move(0, 0) self._win.erase() for y, line in enumerate(lines): if line: -- cgit v1.2.3 From 178ab2d9902cf399203defdfd8632e9b983507fc Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 28 Nov 2011 17:15:06 +0100 Subject: Add the doc to the installed files --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0dcfd755..343e52c6 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ prefix=/usr/local LIBDIR=$(prefix)/lib BINDIR=$(prefix)/bin DATADIR=$(prefix)/share +DOCDIR=$(DATADIR)/doc LOCALEDIR=$(DATADIR)/locale MANDIR=$(DATADIR)/man @@ -16,11 +17,14 @@ clean: install: all mkdir -p $(DESTDIR)$(prefix) - install -d $(DESTDIR)$(LOCALEDIR) $(DESTDIR)$(BINDIR) $(DESTDIR)$(DATADIR)/poezio $(DESTDIR)$(DATADIR)/poezio/data $(DESTDIR)$(DATADIR)/poezio/src/ $(DESTDIR)$(DATADIR)/poezio/src $(DESTDIR)$(DATADIR)/poezio/data/themes $(DESTDIR)$(MANDIR)/man1 + install -d $(DESTDIR)$(LOCALEDIR) $(DESTDIR)$(BINDIR) $(DESTDIR)$(DATADIR)/poezio $(DESTDIR)$(DATADIR)/poezio/data $(DESTDIR)$(DATADIR)/poezio/src/ $(DESTDIR)$(DATADIR)/poezio/src $(DESTDIR)$(DATADIR)/poezio/data/themes $(DESTDIR)$(MANDIR)/man1 $(DESTDIR)$(DOCDIR)/poezio cp -R data/* $(DESTDIR)$(DATADIR)/poezio/data/ rm $(DESTDIR)$(DATADIR)/poezio/data/poezio.1 + cp -R doc/* $(DESTDIR)$(DOCDIR)/poezio/ + cp README CHANGELOG COPYING $(DESTDIR)$(DOCDIR)/poezio/ + install -m644 data/poezio.1 $(DESTDIR)$(MANDIR)/man1/ for sourcefile in `ls -1 src/*.py src/*.so` ; do \ install -m644 $$sourcefile $(DESTDIR)$(DATADIR)/poezio/src; \ -- cgit v1.2.3 From 4b549406cebab1ef175cb80d66169123ff762445 Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 28 Nov 2011 21:27:40 +0100 Subject: Python 3.0/.1 compatibility --- src/bookmark.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/bookmark.py b/src/bookmark.py index dbd8855a..45616d93 100644 --- a/src/bookmark.py +++ b/src/bookmark.py @@ -1,9 +1,16 @@ import os +from sys import version_info from sleekxmpp.plugins.xep_0048 import * from core import JID from config import config +def iter(xml, tag=''): + if version_info[1] >= 2: + return xml.iter(tag) + else: + return xml.getiterator(tag) + preferred = config.get('use_bookmarks_method', 'pep').lower() if preferred not in ('pep', 'privatexml'): preferred = 'privatexml' @@ -73,10 +80,10 @@ class Bookmark(object): name = el.get('name') autojoin = True if el.get('autojoin', False) == 'true' else False nick = None - for n in el.iter('nick'): + for n in iter(el, 'nick'): nick = nick.text password = None - for p in el.iter('password'): + for p in iter(el, 'password'): password = p.text return Bookmark(jid, name, autojoin, nick, password, method) @@ -150,7 +157,7 @@ def get_pep(xmpp): iq = xmpp.plugin['xep_0048'].get_bookmarks() except: return False - for conf in iq.xml.iter('{storage:bookmarks}conference'): + for conf in iter(iq.xml, '{storage:bookmarks}conference'): b = Bookmark.parse_from_element(conf, method='pep') if not get_by_jid(b.jid): bookmarks.append(b) @@ -162,7 +169,7 @@ def get_privatexml(xmpp): iq = xmpp.plugin['xep_0048'].get_bookmarks_old() except: return False - for conf in iq.xml.iter('{storage:bookmarks}conference'): + for conf in iter(iq.xml, '{storage:bookmarks}conference'): b = Bookmark.parse_from_element(conf, method='privatexml') if not get_by_jid(b.jid): bookmarks.append(b) -- cgit v1.2.3 From f92e875611c6f38cc1529c46869ac92a003d19a8 Mon Sep 17 00:00:00 2001 From: mathieui Date: Tue, 29 Nov 2011 00:00:47 +0100 Subject: Add an XML tab (/xml_tab) to view incoming/outgoing stanzas Fixes #2074 --- src/connection.py | 13 +++++++++ src/core.py | 22 +++++++++++++++ src/tabs.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/src/connection.py b/src/connection.py index ffa6590e..352a1d5b 100644 --- a/src/connection.py +++ b/src/connection.py @@ -41,6 +41,7 @@ class Connection(sleekxmpp.ClientXMPP): jid = '%s/%s' % (config.get('server', 'anon.louiz.org'), resource) password = None sleekxmpp.ClientXMPP.__init__(self, jid, password, ssl=True) + self.core = None self.auto_reconnect = False self.auto_authorize = None self.register_plugin('xep_0030') @@ -75,3 +76,15 @@ class Connection(sleekxmpp.ClientXMPP): return False self.process(threaded=True) return True + + def send_raw(self, data, now=False, reconnect=None): + """ + Overrides XMLStream.send_raw, with an event added + """ + if self.core: + self.core.outgoing_stanza(data) + sleekxmpp.ClientXMPP.send_raw(self, data, now, reconnect) + +class MatchAll(sleekxmpp.xmlstream.matcher.base.MatcherBase): + def match(self, xml): + return True diff --git a/src/core.py b/src/core.py index b940bb73..15126c08 100644 --- a/src/core.py +++ b/src/core.py @@ -27,6 +27,7 @@ import collections from sleekxmpp.xmlstream.stanzabase import JID from sleekxmpp.xmlstream.stanzabase import StanzaBase +from sleekxmpp.xmlstream.handler import Callback log = logging.getLogger(__name__) @@ -91,6 +92,7 @@ class Core(object): self.running = True self.events = events.EventHandler() self.xmpp = singleton.Singleton(connection.Connection) + self.xmpp.core = self self.remote_fifo = None # a unique buffer used to store global informations # that are displayed in almost all tabs, in an @@ -98,6 +100,7 @@ class Core(object): self.information_buffer = TextBuffer() self.information_win_size = config.get('info_win_height', 2, 'var') self.information_win = windows.TextWin(300) + self.xml_buffer = TextBuffer() self.tab_win = windows.GlobalInfoBar() self.information_buffer.add_window(self.information_win) self.tabs = [] @@ -142,6 +145,7 @@ class Core(object): 'decline': (self.command_decline, _("Usage: /decline [reason]\nDecline: Decline the invitation to room with or without reason."), self.completion_decline), 'bookmarks': (self.command_bookmarks, _("Usage: /bookmarks\nBookmarks: Show the current bookmarks."), None), 'remove_bookmark': (self.command_remove_bookmark, _("Usage: /remove_bookmark [jid]\nRemove Bookmark: Remove the specified bookmark, or the bookmark on the current tab, if any."), self.completion_remove_bookmark), + 'xml_tab': (self.command_xml_tab, _("Usage: /xml_tab\nXML Tab: Open an XML tab."), None), } self.key_func = { @@ -188,6 +192,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.register_handler(Callback('ALL THE STANZAS', connection.MatchAll(None), self.incoming_stanza)) self.timed_events = set() @@ -228,6 +233,23 @@ class Core(object): self.information_win.resize(self.information_win_size, tabs.Tab.width, tabs.Tab.height - 1 - self.information_win_size - tabs.Tab.tab_win_height(), 0) + def outgoing_stanza(self, stanza): + self.add_message_to_text_buffer(self.xml_buffer, '\x191}<--\x19o %s' % stanza) + if isinstance(self.current_tab(), tabs.XMLTab): + self.current_tab().refresh() + self.doupdate() + + def incoming_stanza(self, stanza): + self.add_message_to_text_buffer(self.xml_buffer, '\x192}-->\x19o %s' % stanza) + if isinstance(self.current_tab(), tabs.XMLTab): + self.current_tab().refresh() + self.doupdate() + + def command_xml_tab(self, arg): + """/xml_tab""" + tab = tabs.XMLTab() + self.add_tab(tab, True) + def resize_global_info_bar(self): """ Resize the GlobalInfoBar only once at each resize diff --git a/src/tabs.py b/src/tabs.py index e75989a7..802640b1 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -2399,6 +2399,88 @@ class MucListTab(Tab): def on_scroll_down(self): self.listview.scroll_down() +class XMLTab(Tab): + + def __init__(self): + Tab.__init__(self) + self.state = 'normal' + self.text_win = windows.TextWin() + self.core.xml_buffer.add_window(self.text_win) + self.default_help_message = windows.HelpText("/ to enter a command") + self.commands['close'] = (self.close, _("Usage: /close\nClose: Just close this tab."), None) + self.input = self.default_help_message + self.key_func['^T'] = self.close + self.key_func['^I'] = self.completion + self.key_func["KEY_DOWN"] = self.on_scroll_down + self.key_func["KEY_UP"] = self.on_scroll_up + self.key_func["/"] = self.on_slash + self.resize() + + def on_slash(self): + """ + '/' is pressed, activate the input + """ + curses.curs_set(1) + self.input = windows.CommandInput("", self.reset_help_message, self.execute_slash_command) + self.input.resize(1, self.width, self.height-1, 0) + self.input.do_command("/") # we add the slash + + def reset_help_message(self, _=None): + if self.core.current_tab() is self: + curses.curs_set(0) + self.input = self.default_help_message + self.input.refresh() + self.core.doupdate() + return True + + def on_scroll_up(self): + self.text_win.scroll_up(self.text_win.height-1) + + def on_scroll_down(self): + self.text_win.scroll_down(self.text_win.height-1) + + def execute_slash_command(self, txt): + if txt.startswith('/'): + self.input.key_enter() + self.execute_command(txt) + return self.reset_help_message() + + def completion(self): + if isinstance(self.input, windows.CommandInput): + self.complete_commands(self.input) + + def on_input(self, key, raw): + res = self.input.do_command(key, raw=raw) + if res: + return True + if not raw and key in self.key_func: + return self.key_func[key]() + + def close(self, arg=None): + self.core.close_tab() + + def resize(self): + if not self.visible: + return + self.need_resize = False + self.text_win.resize(self.height-2, self.width, 0, 0) + self.input.resize(1, self.width, self.height-1, 0) + + def refresh(self): + if self.need_resize: + self.resize() + log.debug(' TAB Refresh: %s',self.__class__.__name__) + self.text_win.refresh() + self.refresh_tab_win() + self.input.refresh() + + def on_lose_focus(self): + self.state = 'normal' + + def on_gain_focus(self): + self.state = 'current' + curses.curs_set(0) + class SimpleTextTab(Tab): """ A very simple tab, with just a text displaying some -- cgit v1.2.3 From 1e8383c3e3ba717b45d69a978361bbae34f8fd39 Mon Sep 17 00:00:00 2001 From: mathieui Date: Tue, 29 Nov 2011 00:18:31 +0100 Subject: =?UTF-8?q?Fix=20a=20traceback=20when=20using=20^W=20with=20xhtml-?= =?UTF-8?q?im=20(it=20does=20not=20work=20perfectly=20as=20it=20should,=20?= =?UTF-8?q?but=20it=20doesn=E2=80=99t=20crash=20anymore,=20at=20least)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/windows.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/windows.py b/src/windows.py index 80a8bbb1..f2ffc8a7 100644 --- a/src/windows.py +++ b/src/windows.py @@ -852,9 +852,9 @@ class Input(Win): if not len(self.text) or self.pos == 0: return separators = string.punctuation+' ' - while self.pos > 0 and self.text[self.pos+self.line_pos-1] in separators: + while self.pos <= len(self.text) and self.pos > 0 and self.text[self.pos+self.line_pos-1] in separators: self.key_backspace() - while self.pos > 0 and self.text[self.pos+self.line_pos-1] not in separators: + while self.pos <= len(self.text) and self.pos > 0 and self.text[self.pos+self.line_pos-1] not in separators: self.key_backspace() return True -- cgit v1.2.3 From cb32f6d30a1974f05b5378acc6fe46fcf0d53f4d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 30 Nov 2011 23:25:22 +0100 Subject: show_tab_names option lets you display the name of the tabs in the horizontal bar --- src/windows.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/windows.py b/src/windows.py index f2ffc8a7..a13efdf5 100644 --- a/src/windows.py +++ b/src/windows.py @@ -303,6 +303,8 @@ class GlobalInfoBar(Win): continue try: self.addstr("%s" % str(tab.nb), to_curses_attr(color)) + if config.get('show_tab_names', 'false') == 'true': + self.addstr(" %s" % str(tab.get_name()), to_curses_attr(color)) self.addstr("|", to_curses_attr(get_theme().COLOR_INFORMATION_BAR)) except: # end of line break -- cgit v1.2.3 From fcbe84e5a69a61a8c58ff1c8a2ef86aa8a5ac8a4 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sat, 3 Dec 2011 17:50:40 +0100 Subject: Fixes #2241 --- src/tabs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tabs.py b/src/tabs.py index 802640b1..06e89f44 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -2349,7 +2349,7 @@ class MucListTab(Tab): if iq['type'] == 'error': self.set_error(iq['error']['type'], iq['error']['code'], iq['error']['text']) return - items = [{'node-part':JID(item[0]).user, + items = [{'node-part': JID(item[0]).user if JID(item[0]).server == self.name else JID(item[0]).bare, 'jid': item[0], 'name': item[2]} for item in iq['disco_items'].get_items()] self.listview.add_lines(items) -- cgit v1.2.3 From a0404f3077c9ec932f0272b770a9c985ccda25cc Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 6 Nov 2011 20:30:41 +0100 Subject: Fix a crash on empty command in muclisttab --- src/tabs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tabs.py b/src/tabs.py index 06e89f44..d41bf9d3 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -2369,7 +2369,9 @@ class MucListTab(Tab): return True def execute_slash_command(self, txt): - self.execute_command(txt) + if txt.startswith('/'): + self.input.key_enter() + self.execute_command(txt) return self.reset_help_message() def get_name(self): -- cgit v1.2.3 From 02099123b0f2272954e91b737f50a797e4df0420 Mon Sep 17 00:00:00 2001 From: manfraid Date: Thu, 8 Dec 2011 16:22:43 +0100 Subject: Fixe 2104 --- src/tabs.py | 22 ++++++++++++++++---- src/theming.py | 3 +++ src/windows.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index d41bf9d3..ab803553 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -2286,6 +2286,9 @@ class MucListTab(Tab): self.key_func['j'] = self.join_selected self.key_func['J'] = self.join_selected_no_focus self.key_func['^M'] = self.join_selected + self.key_func['KEY_LEFT'] = self.list_header.sel_column_left + self.key_func['KEY_RIGHT'] = self.list_header.sel_column_right + self.key_func[' '] = self.sort_by self.commands['close'] = (self.close, _("Usage: /close\nClose: Just close this tab."), None) self.resize() self.update_keys() @@ -2307,9 +2310,9 @@ class MucListTab(Tab): return self.need_resize = False self.upper_message.resize(1, self.width, 0, 0) - column_size = {'node-part': (self.width-5)//4, - 'name': (self.width-5)//4*3, - 'users': 5} + column_size = {'node-part': int(self.width*2/8) , + 'name': int(self.width*5/8), + 'users': self.width-int(self.width*2/8)-int(self.width*5/8)} self.list_header.resize_columns(column_size) self.list_header.resize(1, self.width, 1, 0) self.listview.resize_columns(column_size) @@ -2351,12 +2354,23 @@ class MucListTab(Tab): return items = [{'node-part': JID(item[0]).user if JID(item[0]).server == self.name else JID(item[0]).bare, 'jid': item[0], - 'name': item[2]} for item in iq['disco_items'].get_items()] + 'name': item[2],'users': ''} for item in iq['disco_items'].get_items()] self.listview.add_lines(items) self.upper_message.set_message('Chatroom list on server %s' % self.name) self.upper_message.refresh() curses.doupdate() + def sort_by(self): + if self.list_header.get_order(): + self.listview.sort_by_column(col_name=self.list_header.get_sel_column(),asc=False) + self.list_header.set_order(False) + self.list_header.refresh() + else: + self.listview.sort_by_column(col_name=self.list_header.get_sel_column(),asc=True) + self.list_header.set_order(True) + self.list_header.refresh() + curses.doupdate() + def join_selected(self): row = self.listview.get_selected_row() if not row: diff --git a/src/theming.py b/src/theming.py index e09d4530..7e90a5a7 100644 --- a/src/theming.py +++ b/src/theming.py @@ -154,12 +154,15 @@ class Theme(object): COLOR_CONVERSATION_NAME = (2, 4) COLOR_GROUPCHAT_NAME = (7, 4) COLOR_COLUMN_HEADER = (36, 4) + COLOR_COLUMN_HEADER_SEL = (4, 36) # Strings for special messages (like join, quit, nick change, etc) # Special messages CHAR_JOIN = '--->' CHAR_QUIT = '<---' CHAR_KICK = '-!-' + CHAR_COLUMN_ASC = ' ▲' + CHAR_COLUMN_DESC =' ▼' COLOR_JOIN_CHAR = (4, -1) COLOR_QUIT_CHAR = (1, -1) diff --git a/src/windows.py b/src/windows.py index a13efdf5..6c3c8b5c 100644 --- a/src/windows.py +++ b/src/windows.py @@ -1642,6 +1642,12 @@ class ListWin(Win): """ Sort the list by the given column, ascendant or descendant """ + if asc: + self.lines.sort(key=lambda x: x[col_name]) + else: + self.lines.sort(key=lambda x: x[col_name],reverse=True) + self.refresh() + curses.doupdate() pass # TODO def add_lines(self, lines): @@ -1741,6 +1747,9 @@ class ColumnHeaderWin(Win): Win.__init__(self) self._columns = columns self._columns_sizes = {} + self._column_sel = '' + self._column_order = '' + self._column_order_asc = False def resize_columns(self, dic): self._columns_sizes = dic @@ -1755,12 +1764,65 @@ class ColumnHeaderWin(Win): x = 0 for col in self._columns: txt = col + if col in self._column_order: + if self._column_order_asc: + txt += get_theme().CHAR_COLUMN_ASC + else: + txt += get_theme().CHAR_COLUMN_DESC + #⇓⇑↑↓⇧⇩▲▼ size = self._columns_sizes[col] txt += ' ' * (size-len(txt)) - self.addstr(0, x, txt, to_curses_attr(get_theme().COLOR_COLUMN_HEADER)) + if col in self._column_sel: + self.addstr(0, x, txt, to_curses_attr(get_theme().COLOR_COLUMN_HEADER_SEL)) + else: + self.addstr(0, x, txt, to_curses_attr(get_theme().COLOR_COLUMN_HEADER)) x += size self._refresh() + def sel_column(self,dic): + self._column_sel = dic + + def get_sel_column(self): + return self._column_sel + + def set_order(self,order): + self._column_order = self._column_sel + self._column_order_asc = order + + def get_order(self): + if self._column_sel == self._column_order: + return self._column_order_asc + else: + return False + + def sel_column_left(self): + if self._column_sel in self._columns: + index = self._columns.index(self._column_sel) + if index > 1: + index = index -1 + else: + index = 0 + else: + index = 0 + self._column_sel = self._columns[index] + self.refresh() + return + + def sel_column_right(self): + if self._column_sel in self._columns: + index = self._columns.index(self._column_sel) + if index < len(self._columns)-2: + index = index +1 + else: + index = len(self._columns) -1 + else: + index = len(self._columns) - 1 + self._column_sel = self._columns[index] + self.refresh() + return + + + class SimpleTextWin(Win): def __init__(self, text): Win.__init__(self) -- cgit v1.2.3 From 77ecd70274e5da6aed05729c73a2b37247c7b338 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 9 Dec 2011 13:44:38 +0100 Subject: /recolor random works correctly. --- src/tabs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index ab803553..37dd7a1a 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -666,17 +666,17 @@ class MucTab(ChatTab): compare_users = lambda x: x.last_talked users = list(self.users) sorted_users = sorted(users, key=compare_users, reverse=True) - if len(args) >= 1: - if args[0] == 'random': - random.shuffle(sorted_users) # search our own user, to remove it from the list for user in sorted_users: if user.nick == self.own_nick: sorted_users.remove(user) user.color = get_theme().COLOR_OWN_NICK - nb_color = len(get_theme().LIST_COLOR_NICKNAMES) + colors = list(get_theme().LIST_COLOR_NICKNAMES) + if len(args) >= 1: + if args[0] == 'random': + random.shuffle(colors) for i, user in enumerate(sorted_users): - user.color = get_theme().LIST_COLOR_NICKNAMES[i % nb_color] + user.color = colors[i % len(colors)] self.text_win.rebuild_everything(self._text_buffer) self.text_win.refresh() self.input.refresh() -- cgit v1.2.3 From a25b39777c69698163d80575aa623004ed465d2b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 9 Dec 2011 13:56:14 +0100 Subject: Fix sorting columns when a room has no name. (we use '' instead of None) --- src/tabs.py | 2 +- src/windows.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index 37dd7a1a..dc7aa22d 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -2354,7 +2354,7 @@ class MucListTab(Tab): return items = [{'node-part': JID(item[0]).user if JID(item[0]).server == self.name else JID(item[0]).bare, 'jid': item[0], - 'name': item[2],'users': ''} for item in iq['disco_items'].get_items()] + 'name': item[2] or '' ,'users': ''} for item in iq['disco_items'].get_items()] self.listview.add_lines(items) self.upper_message.set_message('Chatroom list on server %s' % self.name) self.upper_message.refresh() diff --git a/src/windows.py b/src/windows.py index 6c3c8b5c..1b833290 100644 --- a/src/windows.py +++ b/src/windows.py @@ -1648,7 +1648,6 @@ class ListWin(Win): self.lines.sort(key=lambda x: x[col_name],reverse=True) self.refresh() curses.doupdate() - pass # TODO def add_lines(self, lines): """ -- cgit v1.2.3 From 3958b112ad304d807041b4d0de18f95e6646896c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 9 Dec 2011 14:06:57 +0100 Subject: Add manfraid to thanks section. --- README | 3 ++- src/tabs.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README b/README index 752693d3..8ebd13e9 100644 --- a/README +++ b/README @@ -144,13 +144,14 @@ we merge it to “master” as well, of course). ======================= = People = - Todd Eisenberger (todd@teisen.be) - Plugin system + - Jérôme Parment (Manfraid) - Code, testing - Link Mauve - Code, testing - Gaëtan Ribémont (http://www.bonbref.com) - Logo design - Ovart - Testing - Koshie - Donation - Gapan - Makefile - FlashCode (weechat dev) - Useful advices on how to use ncurses efficiently - - And all the people using and testing poezio, and especially the one present + - And all the people using and testing poezio, and especially the ones present on the jabber chatroom doing bug reports and/or feature requests. = Project = Gajim - send_vcard method and common.py diff --git a/src/tabs.py b/src/tabs.py index dc7aa22d..b1d5bec2 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -2365,7 +2365,7 @@ class MucListTab(Tab): self.listview.sort_by_column(col_name=self.list_header.get_sel_column(),asc=False) self.list_header.set_order(False) self.list_header.refresh() - else: + else: self.listview.sort_by_column(col_name=self.list_header.get_sel_column(),asc=True) self.list_header.set_order(True) self.list_header.refresh() -- cgit v1.2.3 From 1b30cd09a7937c5ee0021e9eb62b9ccd065916e6 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sat, 10 Dec 2011 16:36:18 +0100 Subject: Improve /names command --- src/tabs.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index b1d5bec2..14af2206 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -781,7 +781,12 @@ class MucTab(ChatTab): """ if not self.joined: return - users, visitors, moderators, participants, others = [], [], [], [], [] + color_visitor = get_theme().COLOR_USER_VISITOR[0] + color_other = get_theme().COLOR_USER_NONE[0] + color_moderator = get_theme().COLOR_USER_MODERATOR[0] + color_participant = get_theme().COLOR_USER_PARTICIPANT[0] + color_information = get_theme().COLOR_INFORMATION_TEXT[0] + visitors, moderators, participants, others = [], [], [], [] for user in self.users: if user.role == 'visitor': visitors.append(user.nick) @@ -791,20 +796,18 @@ class MucTab(ChatTab): moderators.append(user.nick) else: others.append(user.nick) - users.append(user.nick) - - message = '' - roles = (('Users', users), ('Visitors', visitors), ('Participants', participants), ('Moderators', moderators), ('Others', others)) - for role in roles: - if role[1]: - role[1].sort() - message += '%s: %i\n ' % (role[0], len(role[1])) - last = role[1].pop() - for item in role[1]: - message += '%s, ' % item - message += '%s\n' % last - - # self.core.add_message_to_text_buffer(room, message) + + message = 'Users: %s \n' % len(self.users) + for moderator in moderators: + message += ' \x19%s}%s\x19o -' % (color_moderator, moderator) + for participant in participants: + message += ' \x19%s}%s\x19o -' % (color_participant, participant) + for visitor in visitors: + message += ' \x19%s}%s\x19o -' % (color_visitor, visitor) + for other in others: + message += ' \x19%s}%s\x19o -' % (color_other, other) + message = message[:-2] + self._text_buffer.add_message(message) self.text_win.refresh() self.input.refresh() -- cgit v1.2.3 From df6a8a0cc3b1543775bdb4e3d56dc5772b0653de Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 12 Dec 2011 20:03:42 +0100 Subject: Avoid a traceback on focusing a PrivateTab from a MucTab we already left. fixed #2308 --- src/tabs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index 14af2206..661b4112 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -1470,14 +1470,14 @@ class PrivateTab(ChatTab): self.text_win.remove_line_separator() self.text_win.add_line_separator() tab = self.core.get_tab_by_name(JID(self.name).bare, MucTab) - if tab.joined and config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text(): + if tab and tab.joined and config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text(): self.send_chat_state('inactive') def on_gain_focus(self): self.state = 'current' curses.curs_set(1) tab = self.core.get_tab_by_name(JID(self.name).bare, MucTab) - if tab.joined and config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text(): + if tab and tab.joined and config.get_by_tabname('send_chat_states', 'true', self.general_jid, True) == 'true' and not self.input.get_text(): self.send_chat_state('active') def on_scroll_up(self): -- cgit v1.2.3 From a6b1a1d4d8dc2523d1764a55a924566591232a31 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 12 Dec 2011 20:31:05 +0100 Subject: ALWAYS display affiliation or role changes, in MucTabs. fixes #2309 --- src/tabs.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index 661b4112..e696f46d 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -1239,14 +1239,17 @@ class MucTab(ChatTab): hide_status_change = config.get_by_tabname('hide_status_change', -1, self.general_jid, True) if hide_status_change < -1: hide_status_change = -1 - if (hide_status_change == -1 or \ + if ((hide_status_change == -1 or \ user.has_talked_since(hide_status_change) or\ user.nick == self.own_nick)\ and\ (affiliation != user.affiliation or\ role != user.role or\ show != user.show or\ - status != user.status): + status != user.status))\ + or\ + (affiliation != user.affiliation or\ + role != user.role): # display the message in the room self._text_buffer.add_message(msg) self.core.on_user_changed_status_in_private('%s/%s' % (from_room, from_nick), msg) -- cgit v1.2.3 From 0b2037a67c60c860dd50f572cca34e9e0595c1e4 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 15 Dec 2011 20:29:20 +0100 Subject: Make non-remote commands work. --- src/core.py | 4 +++- src/daemon.py | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/core.py b/src/core.py index 15126c08..3bb0436e 100644 --- a/src/core.py +++ b/src/core.py @@ -54,6 +54,7 @@ from keyboard import read_char from theming import get_theme from fifo import Fifo from windows import g_lock +from daemon import Executor # http://xmpp.org/extensions/xep-0045.html#errorstatus ERROR_AND_STATUS_CODES = { @@ -2143,7 +2144,8 @@ class Core(object): self.information('Could not execute [%s]: %s' % (command.strip(), e,), 'Error') self.remote_fifo = None else: - pass + e = Executor(command.strip()) + e.start() def get_conversation_messages(self): """ diff --git a/src/daemon.py b/src/daemon.py index f23d6b5f..b413f465 100755 --- a/src/daemon.py +++ b/src/daemon.py @@ -23,6 +23,10 @@ import sys import threading import subprocess +import logging + +log = logging.getLogger(__name__) + class Executor(threading.Thread): """ Just a class to execute commands in a thread. @@ -35,7 +39,7 @@ class Executor(threading.Thread): self.command = command def run(self): - print('executing %s' % (self.command.strip(),)) + log.info('executing %s' % (self.command.strip(),)) subprocess.call(self.command.split()) def main(): -- cgit v1.2.3 From 9e7842d0146d64f6a99aa5950a3f4308bb1d8a16 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 18 Dec 2011 20:16:19 +0100 Subject: Beep when receiving a MUC invitation (by default) --- data/default_config.cfg | 3 ++- src/core.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/data/default_config.cfg b/data/default_config.cfg index 540e021e..9763765b 100644 --- a/data/default_config.cfg +++ b/data/default_config.cfg @@ -170,7 +170,8 @@ show_inactive_tabs = true # - private (when a new private message is received, from your contacts or # someone from a MUC) # - message (any message from a MUC) -beep_on = highlight private +# - invite (when you receive an invitation for joining a MUC) +beep_on = highlight private invite # Theme diff --git a/src/core.py b/src/core.py index 3bb0436e..d0f6c4de 100644 --- a/src/core.py +++ b/src/core.py @@ -371,6 +371,8 @@ class Core(object): if password: msg += ". The password is \"%s\"." % password self.information(msg, 'Info') + if 'invite' in config.get('beep_on', 'invite').split(): + curses.beep() self.pending_invites[jid.bare] = inviter.full def command_invite(self, arg): -- cgit v1.2.3 From 2ed6b205940c65206a7732795727fc2ed2338ef4 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 18 Dec 2011 20:35:19 +0100 Subject: Add a /invites command --- src/core.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/core.py b/src/core.py index d0f6c4de..e3d655d5 100644 --- a/src/core.py +++ b/src/core.py @@ -144,6 +144,7 @@ class Core(object): 'set_plugin': (self.command_set_plugin, _("Usage: /set_plugin