From e27c6d74ada2dbe81c41b991a26028a4d9436ee4 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sat, 4 Jun 2011 20:15:18 +0200 Subject: fix the display of the action 'emptying the status', and some few minor changes --- src/config.py | 6 +++--- src/contact.py | 2 +- src/multiuserchat.py | 8 +++++--- src/room.py | 6 ++++++ src/tabs.py | 33 +++++++++++++++++++-------------- src/xhtml.py | 7 ++++--- 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/config.py b/src/config.py index 4776e7d3..af6e05e6 100644 --- a/src/config.py +++ b/src/config.py @@ -134,15 +134,15 @@ class Config(RawConfigParser): # and copy the default config in it CONFIG_HOME = environ.get("XDG_CONFIG_HOME") if not CONFIG_HOME: - CONFIG_HOME = environ.get('HOME')+'/.config' -CONFIG_PATH = CONFIG_HOME + '/poezio/' + CONFIG_HOME = path.join(environ.get('HOME'), '/.config') +CONFIG_PATH = path.join(CONFIG_HOME, 'poezio') try: makedirs(CONFIG_PATH) except OSError: pass if not path.isfile(CONFIG_PATH+'poezio.cfg'): - copy2(path.join(path.dirname(__file__), '../data/default_config.cfg'), CONFIG_PATH+'poezio.cfg') + copy2(path.join(path.dirname(__file__), '../data/default_config.cfg'), path.join(CONFIG_PATH, 'poezio.cfg')) parser = OptionParser() parser.add_option("-f", "--file", dest="filename", default=CONFIG_PATH+'poezio.cfg', diff --git a/src/contact.py b/src/contact.py index 804a7068..ee0e1e80 100644 --- a/src/contact.py +++ b/src/contact.py @@ -166,5 +166,5 @@ class Contact(object): def __repr__(self): ret = '\n' diff --git a/src/multiuserchat.py b/src/multiuserchat.py index 87443e07..dd936039 100644 --- a/src/multiuserchat.py +++ b/src/multiuserchat.py @@ -25,6 +25,8 @@ from xml.etree import cElementTree as ET import logging log = logging.getLogger(__name__) +NS_MUC_ADMIN = 'http://jabber.org/protocol/muc#admin' + def send_private_message(xmpp, jid, line): """ Send a private message @@ -77,10 +79,10 @@ def eject_user(xmpp, jid, nick, reason): (try to) Eject an user from the room """ iq = xmpp.makeIqSet() - query = ET.Element('{http://jabber.org/protocol/muc#admin}query') - item = ET.Element('{http://jabber.org/protocol/muc#admin}item', {'nick':nick, 'role':'none'}) + query = ET.Element('{%s}query' % NS_MUC_ADMIN) + item = ET.Element('{%s}item' % NS_MUC_ADMIN, {'nick':nick, 'role':'none'}) if reason: - reason_el = ET.Element('{http://jabber.org/protocol/muc#admin}reason') + reason_el = ET.Element('{%s}reason' % NS_MUC_ADMIN) reason_el.text = reason item.append(reason_el) query.append(item) diff --git a/src/room.py b/src/room.py index a5a05845..45ebddbd 100644 --- a/src/room.py +++ b/src/room.py @@ -46,6 +46,9 @@ class Room(TextBuffer): self.joined = False def get_single_line_topic(self): + """ + Return the topic as a single-line string (for the window header) + """ return self.topic.replace('\n', '|') def log_message(self, txt, time, nickname): @@ -77,6 +80,9 @@ class Room(TextBuffer): return color def get_user_by_name(self, nick): + """ + Gets the user associated with the given nick, or None if not found + """ for user in self.users: if user.nick == nick: return user diff --git a/src/tabs.py b/src/tabs.py index 12bf08be..4ea3c280 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -63,6 +63,8 @@ SHOW_NAME = { '': _('available') } +NS_MUC_USER = 'http://jabber.org/protocol/muc#user' + class Tab(object): number = 0 tab_core = None @@ -119,8 +121,8 @@ class Tab(object): return command[2](the_input) else: # complete the command's name - words = ['/%s'%(name) for name in self.core.commands] +\ - ['/%s'% (name) for name in self.commands] + words = ['/%s'% (name) for name in self.core.commands] +\ + ['/%s' % (name) for name in self.commands] the_input.auto_completion(words, '') return True return False @@ -767,12 +769,10 @@ class MucTab(ChatTab): def handle_presence(self, presence): from_nick = presence['from'].resource from_room = presence['from'].bare - code = presence.find('{jabber:client}status') - status_codes = set([s.attrib['code'] for s in presence.findall('{http://jabber.org/protocol/muc#user}x/{http://jabber.org/protocol/muc#user}status')]) + status_codes = set([s.attrib['code'] for s in presence.findall('{%s}x/{%s}status' % (NS_MUC_USER, NS_MUC_USER))]) # Check if it's not an error presence. if presence['type'] == 'error': return self.core.room_error(presence, from_room) - msg = None affiliation = presence['muc']['affiliation'] show = presence['show'] status = presence['status'] @@ -834,7 +834,7 @@ class MucTab(ChatTab): room.add_message('\x194%(spec)s \x193%(nick)s \x195(\x194%(jid)s\x195) joined the room' % {'spec':theme.CHAR_JOIN, 'nick':from_nick, 'jid':jid.full}) def on_user_nick_change(self, room, presence, user, from_nick, from_room): - new_nick = presence.find('{http://jabber.org/protocol/muc#user}x/{http://jabber.org/protocol/muc#user}item').attrib['nick'] + new_nick = presence.find('{%s}x/{%s}item' % (NS_MUC_USER, NS_MUC_USER)).attrib['nick'] if user.nick == room.own_nick: room.own_nick = new_nick # also change our nick in all private discussion of this room @@ -851,8 +851,8 @@ class MucTab(ChatTab): When someone is banned from a muc """ room.users.remove(user) - by = presence.find('{http://jabber.org/protocol/muc#user}x/{http://jabber.org/protocol/muc#user}item/{http://jabber.org/protocol/muc#user}actor') - reason = presence.find('{http://jabber.org/protocol/muc#user}x/{http://jabber.org/protocol/muc#user}item/{http://jabber.org/protocol/muc#user}reason') + by = presence.find('{%s}x/{%s}item/{%s}actor' % (NS_MUC_USER, NS_MUC_USER, NS_MUC_USER)) + reason = presence.find('{%s}x/{%s}item/{%s}reason' % (NS_MUC_USER, NS_MUC_USER, NS_MUC_USER)) by = by.attrib['jid'] if by is not None else None if from_nick == room.own_nick: # we are banned room.disconnect() @@ -874,8 +874,8 @@ class MucTab(ChatTab): When someone is kicked from a muc """ room.users.remove(user) - by = presence.find('{http://jabber.org/protocol/muc#user}x/{http://jabber.org/protocol/muc#user}item/{http://jabber.org/protocol/muc#user}actor') - reason = presence.find('{http://jabber.org/protocol/muc#user}x/{http://jabber.org/protocol/muc#user}item/{http://jabber.org/protocol/muc#user}reason') + by = presence.find('{%s}x/{%s}item/{%s}actor' % (NS_MUC_USER, NS_MUC_USER, NS_MUC_USER)) + reason = presence.find('{%s}x/{%s}item/{%s}reason' % (NS_MUC_USER, NS_MUC_USER, NS_MUC_USER)) by = by.attrib['jid'] if by is not None else None if from_nick == room.own_nick: # we are kicked room.disconnect() @@ -931,9 +931,14 @@ class MucTab(ChatTab): if show != user.show and show in SHOW_NAME: msg += _('show: %s, ') % SHOW_NAME[show] display_message = True - if status and status != user.status: - msg += _('status: %s, ') % status + if status != user.status: + # if the user sets his status to nothing + if not status: + msg += _('show: %s, ') % SHOW_NAME[show] + else: + msg += _('status: %s, ') % status display_message = True + if not display_message: return msg = msg[:-2] # remove the last ", " @@ -1571,7 +1576,7 @@ class MucListTab(Tab): self.name = server self.upper_message = windows.Topic() self.upper_message.set_message('Chatroom list on server %s (Loading)' % self.name) - columns = ('node-part','name', 'users') + columns = ('node-part', 'name', 'users') self.list_header = windows.ColumnHeaderWin(columns) self.listview = windows.ListWin(columns) self.tab_win = windows.GlobalInfoBar() @@ -1764,6 +1769,7 @@ def diffmatch(search, string): def jid_and_name_match(contact, txt): """ + Match jid with text precisely """ if not txt: return True @@ -1776,7 +1782,6 @@ def jid_and_name_match_slow(contact, txt): A function used to know if a contact in the roster should be shown in the roster """ - ratio = 0.7 if not txt: return True # Everything matches when search is empty user = JID(contact.get_bare_jid()).user diff --git a/src/xhtml.py b/src/xhtml.py index d755229f..16972b65 100644 --- a/src/xhtml.py +++ b/src/xhtml.py @@ -28,11 +28,12 @@ import subprocess from sleekxmpp.xmlstream import ET from xml.etree.ElementTree import ElementTree from sys import version_info -from string import digits from config import config import logging +digits = '0123456789' # never trust the modules + log = logging.getLogger(__name__) shell_colors_re = re.compile(r'(\[(?:\d+;)*(?:\d+m))') @@ -73,9 +74,9 @@ def convert_links_to_plaintext(text): if child.tag == '{http://www.w3.org/1999/xhtml}a': if child.attrib['href'] != child.text: if child.text is None and 'title' in child.attrib: - link_text = '\n%s (%s)'%(child.attrib['href'], child.attrib['title']) + link_text = '\n%s (%s)' % (child.attrib['href'], child.attrib['title']) else: - link_text = '\n%s (%s)'%(child.attrib['href'], child.text) + link_text = '\n%s (%s)' % (child.attrib['href'], child.text) else: link_text = child.text if previous_child is not None: -- cgit v1.2.3 From 7d82a4fb19f8c180073c4313b2c5a9c8ec31b253 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sat, 4 Jun 2011 20:44:14 +0200 Subject: =?UTF-8?q?some=20path.join=20forgotten=20causing=20the=20config?= =?UTF-8?q?=20file=20to=20be=20overwritten=20an=20not=20taken=20into=20acc?= =?UTF-8?q?ount=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config.py b/src/config.py index af6e05e6..9cedcac7 100644 --- a/src/config.py +++ b/src/config.py @@ -134,18 +134,18 @@ class Config(RawConfigParser): # and copy the default config in it CONFIG_HOME = environ.get("XDG_CONFIG_HOME") if not CONFIG_HOME: - CONFIG_HOME = path.join(environ.get('HOME'), '/.config') + CONFIG_HOME = path.join(environ.get('HOME'), '.config') CONFIG_PATH = path.join(CONFIG_HOME, 'poezio') try: makedirs(CONFIG_PATH) except OSError: pass -if not path.isfile(CONFIG_PATH+'poezio.cfg'): +if not path.isfile(path.join(CONFIG_PATH, 'poezio.cfg')): copy2(path.join(path.dirname(__file__), '../data/default_config.cfg'), path.join(CONFIG_PATH, 'poezio.cfg')) parser = OptionParser() -parser.add_option("-f", "--file", dest="filename", default=CONFIG_PATH+'poezio.cfg', +parser.add_option("-f", "--file", dest="filename", default=path.join(CONFIG_PATH, 'poezio.cfg'), help="The config file you want to use", metavar="CONFIG_FILE") parser.add_option("-d", "--debug", dest="debug", help="The file where debug will be written", metavar="DEBUG_FILE") -- cgit v1.2.3 From da5623094d443f0bc1991414a4eafbaaf8964830 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sat, 18 Jun 2011 11:17:20 +0200 Subject: hopefully fix chat states --- src/tabs.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tabs.py b/src/tabs.py index 4ea3c280..7f6c91ff 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -269,6 +269,7 @@ class ChatTab(Tab): self.commands['say'] = (self.command_say, _("""Usage: /say \nSay: Just send the message. Useful if you want your message to begin with a '/'"""), None) + self.chat_state = None def last_words_completion(self): """ @@ -308,6 +309,7 @@ class ChatTab(Tab): msg = self.core.xmpp.make_message(self.get_name()) msg['type'] = self.message_type msg['chat_state'] = state + self.chat_state = state msg.send() def send_composing_chat_state(self, empty_before, empty_after): @@ -316,8 +318,13 @@ class ChatTab(Tab): on the the current status of the input """ if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates: - if empty_after: + if self.chat_state == "composing" and not empty_after: + self.cancel_paused_delay() + self.set_paused_delay(True) + elif empty_after and not self.chat_state == 'active': + self.cancel_paused_delay() self.send_chat_state("active") + elif empty_after: self.cancel_paused_delay() elif empty_before or (self.timed_event_paused is not None and not self.timed_event_paused()): self.cancel_paused_delay() -- cgit v1.2.3 From 07ce4dcb10e8aa093ef37f9f79930d0e74104b7d Mon Sep 17 00:00:00 2001 From: mathieui Date: Sat, 18 Jun 2011 12:00:28 +0200 Subject: Fix /connect (and renamed it to /reconnect) --- src/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core.py b/src/core.py index e096b65c..0bebc25f 100644 --- a/src/core.py +++ b/src/core.py @@ -127,7 +127,7 @@ class Core(object): 'list': (self.command_list, _('Usage: /list\nList: get the list of public chatrooms on the specified server'), self.completion_list), 'message': (self.command_message, _('Usage: /message [optional message]\nMessage: Open a conversation with the specified JID (even if it is not in our roster), and send a message to it, if specified'), None), 'version': (self.command_version, _('Usage: /version \nVersion: get the software version of the given JID (usually its XMPP client and Operating System)'), None), - 'connect': (self.command_reconnect, _('Usage: /connect\nConnect: disconnect from the remote server if you are currently connected and then connect to it again'), None), + 'reconnect': (self.command_reconnect, _('Usage: /connect\nConnect: disconnect from the remote server if you are currently connected and then connect to it again'), None), 'server_cycle': (self.command_server_cycle, _('Usage: /server_cycle [domain] [message]\nServer Cycle: disconnect and reconnects in all the rooms in domain.'), None), } @@ -1072,7 +1072,7 @@ class Core(object): """ /reconnect """ - self.disconnect(True) + self.disconnect(reconnect=True) def command_list(self, arg): """ @@ -1385,7 +1385,7 @@ class Core(object): popup_time = config.get('popup_time', 4) + (nb_lines - 1) * 2 self.pop_information_win_up(nb_lines, popup_time) - def disconnect(self, msg=None): + def disconnect(self, msg=None, reconnect=False): """ Disconnect from remote server and correctly set the states of all parts of the client (for example, set the MucTabs as not joined, etc) @@ -1397,7 +1397,7 @@ class Core(object): # Ugly fix thanks to gmail servers try: sys.stderr = None - self.xmpp.disconnect(False) + self.xmpp.disconnect(reconnect) except: pass -- cgit v1.2.3 From c93815737ffce901c4c35a4def2e3fe0aaaeec99 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 18 Jun 2011 12:52:58 +0200 Subject: Empty roster on disconnect --- src/core.py | 7 ++----- src/roster.py | 4 ++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core.py b/src/core.py index 0bebc25f..1351914c 100644 --- a/src/core.py +++ b/src/core.py @@ -1393,13 +1393,10 @@ class Core(object): for tab in self.tabs: if isinstance(tab, tabs.MucTab): muc.leave_groupchat(self.xmpp, tab.get_room().name, tab.get_room().own_nick, msg) + roster.empty() self.save_config() # Ugly fix thanks to gmail servers - try: - sys.stderr = None - self.xmpp.disconnect(reconnect) - except: - pass + self.xmpp.disconnect(reconnect) def command_quit(self, arg): """ diff --git a/src/roster.py b/src/roster.py index aed5f5a0..afe83c9e 100644 --- a/src/roster.py +++ b/src/roster.py @@ -45,6 +45,10 @@ class Roster(object): except IOError: return + def empty(self): + self._contacts = {} + self._roster_groups = [] + def add_contact(self, contact, jid): """ Add a contact to the contact list -- cgit v1.2.3 From c51559b14f492d44664f3e9f8951943654c6e034 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sat, 18 Jun 2011 14:28:49 +0200 Subject: Fixes #2209 --- src/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core.py b/src/core.py index 1351914c..1c675410 100644 --- a/src/core.py +++ b/src/core.py @@ -767,7 +767,8 @@ class Core(object): def refresh_tab_win(self): self.current_tab().tab_win.refresh() - self.current_tab().input.refresh() + if self.current_tab().input: + self.current_tab().input.refresh() self.doupdate() def add_tab(self, new_tab, focus=False): -- cgit v1.2.3 From 77a2165639e3ba49c84496a4b7ae22908fb2bc9c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 18 Jun 2011 15:48:19 +0200 Subject: Handler error messages even when not comming from a room --- src/core.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/core.py b/src/core.py index 1c675410..3f24fb1b 100644 --- a/src/core.py +++ b/src/core.py @@ -550,6 +550,8 @@ class Core(object): jid = message['from'] body = xhtml.get_body_from_message_stanza(message) if not body: + if message['type'] == 'error': + self.information(self.get_error_message_from_error_stanza(message), 'Error') return conversation = self.get_tab_of_conversation_with_jid(jid, create=True) if roster.get_contact_by_jid(jid.bare): @@ -851,26 +853,34 @@ class Core(object): self.current_tab().on_scroll_up() self.refresh_window() - def room_error(self, error, room_name): + def get_error_message_from_error_stanza(self, stanza): """ - Display the error on the room window + Takes a stanza of the form + and return a well formed string containing the error informations """ - room = self.get_room_by_name(room_name) - msg = error['error']['type'] - condition = error['error']['condition'] - code = error['error']['code'] - body = error['error']['text'] + msg = stanza['error']['type'] + condition = stanza['error']['condition'] + code = stanza['error']['code'] + body = stanza['error']['text'] if not body: if code in ERROR_AND_STATUS_CODES: body = ERROR_AND_STATUS_CODES[code] else: body = condition or _('Unknown error') if code: - msg = _('Error: %(code)s - %(msg)s: %(body)s') % {'msg':msg, 'body':body, 'code':code} - self.add_message_to_text_buffer(room, msg) + message = _('Error: %(code)s - %(msg)s: %(body)s') % {'msg':msg, 'body':body, 'code':code} else: - msg = _('Error: %(msg)s: %(body)s') % {'msg':msg, 'body':body} - self.add_message_to_text_buffer(room, msg) + message = _('Error: %(msg)s: %(body)s') % {'msg':msg, 'body':body} + return message + + def room_error(self, error, room_name): + """ + Display the error on the room window + """ + room = self.get_room_by_name(room_name) + error_message = self.get_error_message_from_error_stanza(error) + self.add_message_to_text_buffer(room, error_message) + code = error['error']['code'] if code == '401': msg = _('To provide a password in order to join the room, type "/join / password" (replace "password" by the real password)') self.add_message_to_text_buffer(room, msg) -- cgit v1.2.3 From 53ee85ea6dea76f8f12acc5f5faf4b1171102ea0 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 18 Jun 2011 16:09:34 +0200 Subject: Fix colors in private quit messages --- src/tabs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index 7f6c91ff..f69ef919 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -919,6 +919,7 @@ class MucTab(ChatTab): if status: leave_msg += ' (%s)' % status room.add_message(leave_msg) + self.refresh_window() self.core.on_user_left_private_conversation(from_room, from_nick, status) def on_user_change_status(self, room, user, from_nick, from_room, affiliation, role, show, status): @@ -1096,9 +1097,9 @@ class PrivateTab(ChatTab): The user left the associated MUC """ if not status_message: - self.get_room().add_message(_('%(spec)s "[%(nick)s]" has left the room') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT.replace('"', '\\"')}) + self.get_room().add_message(_('\x191%(spec)s \x193%(nick)s\x195 has left the room') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT.replace('"', '\\"')}) else: - self.get_room().add_message(_('%(spec)s "[%(nick)s]" has left the room "(%(status)s)"') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT, 'status': status_message.replace('"', '\\"')}) + self.get_room().add_message(_('\x191%(spec)s \x193%(nick)s\x195 has left the room (%(status)s)"') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT, 'status': status_message.replace('"', '\\"')}) class RosterInfoTab(Tab): """ -- cgit v1.2.3 From f4c24380466fa54924a925a12817e28d603fd4d1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 18 Jun 2011 16:23:41 +0200 Subject: Oups. --- src/tabs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tabs.py b/src/tabs.py index f69ef919..801e0793 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -919,7 +919,7 @@ class MucTab(ChatTab): if status: leave_msg += ' (%s)' % status room.add_message(leave_msg) - self.refresh_window() + self.core.refresh_window() self.core.on_user_left_private_conversation(from_room, from_nick, status) def on_user_change_status(self, room, user, from_nick, from_room, affiliation, role, show, status): -- cgit v1.2.3