From 90699130b9d239dd4a96d09bc98744868138f348 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 29 Sep 2011 02:08:47 +0200 Subject: [PATCH 01/28] =?UTF-8?q?=C2=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tabs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tabs.py b/src/tabs.py index 63fd2c96..bc656cdd 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -884,7 +884,7 @@ class MucTab(ChatTab): if by: kick_msg = _('\x191}%(spec)s \x193}%(nick)s\x195} has been banned by \x194}%(by)s') % {'spec':get_theme().CHAR_KICK, 'nick':from_nick, 'by':by} else: - kick_msg = _('\x191}%(spec)s \x193}%(nick)s\x195 has been banned') % {'spec':get_theme().CHAR_KICK, 'nick':from_nick.replace('"', '\\"')} + kick_msg = _('\x191}%(spec)s \x193}%(nick)s\x195} has been banned') % {'spec':get_theme().CHAR_KICK, 'nick':from_nick.replace('"', '\\"')} if reason is not None and reason.text: kick_msg += _('\x195} Reason: \x196}%(reason)s\x195}') % {'reason': reason.text} room.add_message(kick_msg) From c89d9a3aa4cefa881a6347878ec5c940160a1c33 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 29 Sep 2011 23:19:21 +0200 Subject: [PATCH 02/28] use getiterator if python < 3.2 --- src/xhtml.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/xhtml.py b/src/xhtml.py index 9bb2705d..c14382b8 100644 --- a/src/xhtml.py +++ b/src/xhtml.py @@ -249,7 +249,11 @@ def xhtml_to_poezio_colors(text): log.debug(text) xml = ET.fromstring(text) message = '' - for elem in xml.iter(): + if version_info[1] == 2: + elems = xml.iter() + else: + elems = xml.getiterator() + for elem in elems: if elem.tag == '{http://www.w3.org/1999/xhtml}a': if 'href' in elem.attrib and elem.attrib['href'] != elem.text: message += '\x19u%s\x19o (%s)' % (trim(elem.attrib['href']), trim(elem.text)) From fdf6a00bbc5b8fe6ee2882e7dfbcb061771ed9e3 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 30 Sep 2011 17:20:36 +0200 Subject: [PATCH 03/28] fixes #2185 completion can be done with the cursor ANYWHERE! --- src/tabs.py | 8 ++++---- src/windows.py | 51 +++++++++++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index bc656cdd..0fde715c 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -125,7 +125,7 @@ class Tab(object): # complete the command's name words = ['/%s'% (name) for name in self.core.commands] +\ ['/%s' % (name) for name in self.commands] - the_input.auto_completion(words, '') + the_input.auto_completion(words, ' ') return True return False @@ -725,12 +725,12 @@ class MucTab(ChatTab): word_list = [user.nick for user in sorted(self._room.users, key=compare_users, reverse=True)\ if user.nick != self._room.own_nick] after = config.get('after_completion', ',')+" " - if ' ' not in self.input.get_text() or (self.input.last_completion and\ - self.input.get_text()[:-len(after)] == self.input.last_completion): + input_pos = self.input.pos + self.input.line_pos + if ' ' not in self.input.get_text()[:input_pos] or (self.input.last_completion and\ + self.input.get_text()[:input_pos] == self.input.last_completion + after): add_after = after else: add_after = ' ' - self.input.auto_completion(word_list, add_after) empty_after = self.input.get_text() == '' or (self.input.get_text().startswith('/') and not self.input.get_text().startswith('//')) self.send_composing_chat_state(empty_after) diff --git a/src/windows.py b/src/windows.py index 2352a82a..03066857 100644 --- a/src/windows.py +++ b/src/windows.py @@ -883,26 +883,28 @@ class Input(Win): self.rewrite_text() return True - def key_left(self, jump=True): + def key_left(self, jump=True, reset=True): """ Move the cursor one char to the left """ - self.reset_completion() + if reset: + self.reset_completion() if self.pos == self.width-1 and self.line_pos > 0: self.line_pos -= 1 elif self.pos >= 1: self.pos -= 1 if jump and self.pos+self.line_pos >= 1 and self.text[self.pos+self.line_pos-1] == '\x19': self.key_left() - else: + elif reset: self.rewrite_text() return True - def key_right(self, jump=True): + def key_right(self, jump=True, reset=True): """ Move the cursor one char to the right """ - self.reset_completion() + if reset: + self.reset_completion() if self.pos == self.width-1: if self.line_pos + self.width-1 < len(self.text): self.line_pos += 1 @@ -910,7 +912,7 @@ class Input(Win): self.pos += 1 if jump and self.pos+self.line_pos < len(self.text) and self.text[self.pos+self.line_pos-1] == '\x19': self.key_right() - else: + elif reset: self.rewrite_text() return True @@ -936,8 +938,6 @@ class Input(Win): plus a space, after the completion. If it's a string, we use it after the completion (with no additional space) """ - if self.pos+self.line_pos != len(self.text): # or len(self.text) == 0 - return # we don't complete if cursor is not at the end of line completion_type = config.get('completion', 'normal') if completion_type == 'shell' and self.text != '': self.shell_completion(word_list, add_after) @@ -957,12 +957,15 @@ class Input(Win): Normal completion """ (y, x) = self._win.getyx() + pos = self.pos + self.line_pos + if pos < len(self.text) and after.endswith(' ') and self.text[pos] == ' ': + after = after[:-1] # remove the last space if we are already on a space if not self.last_completion: - # begin is the begining of the word we want to complete - if self.text.strip() and not self.text.endswith(' '): - begin = self.text.split()[-1].lower() + space_before_cursor = self.text.rfind(' ', 0, pos-1) + if space_before_cursor != -1: + begin = self.text[space_before_cursor+1:pos] else: - begin = '' + begin = self.text[:pos] hit_list = [] # list of matching nicks for word in word_list: if word.lower().startswith(begin): @@ -972,18 +975,24 @@ class Input(Win): self.hit_list = hit_list end = len(begin) else: - if after: - begin = self.text[-len(after)-len(self.last_completion):-len(after)] - else: - begin = self.last_completion - self.hit_list.append(self.hit_list.pop(0)) # rotate list + begin = self.last_completion end = len(begin) + len(after) - if end: - self.text = self.text[:-end] + self.hit_list.append(self.hit_list.pop(0)) # rotate list + + self.text = self.text[:pos-end] + self.text[pos:] + pos -= end nick = self.hit_list[0] # take the first hit + self.text = self.text[:pos] + nick + after + self.text[pos:] + for i in range(end): + try: + self.key_left(reset=False) + except: + pass + for i in range(len(nick + after)): + self.key_right(reset=False) + + self.rewrite_text() self.last_completion = nick - self.text += nick +after - self.key_end(False) def shell_completion(self, word_list, after): """ From 7683bf92a78e9cfeefdb35dfbd9e65e65597e4df Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 30 Sep 2011 17:30:06 +0200 Subject: [PATCH 04/28] fixed #2258 --- src/tabs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tabs.py b/src/tabs.py index 0fde715c..f7c0c9c4 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -1417,7 +1417,8 @@ class RosterInfoTab(Tab): self.input.do_command("/") # we add the slash def reset_help_message(self, _=None): - curses.curs_set(0) + if self.core.current_tab() is self: + curses.curs_set(0) self.input = self.default_help_message self.input.refresh() self.core.doupdate() From d02c764c477d900487a97f648260612046257a17 Mon Sep 17 00:00:00 2001 From: Todd Eisenberger Date: Sat, 1 Oct 2011 05:26:19 -0700 Subject: [PATCH 05/28] More contact management commands --- src/contact.py | 6 +++ src/roster.py | 1 + src/tabs.py | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/src/contact.py b/src/contact.py index 9d2885be..99c24a32 100644 --- a/src/contact.py +++ b/src/contact.py @@ -66,6 +66,12 @@ class Contact(object): self._ask = None self._groups = [] # a list of groups the contact is in + def get_groups(self): + """ + Return the groups the contact is in + """ + return self._groups + def get_bare_jid(self): """ Just get the bare_jid or the contact diff --git a/src/roster.py b/src/roster.py index fe68584b..4ef2da1b 100644 --- a/src/roster.py +++ b/src/roster.py @@ -90,6 +90,7 @@ class Roster(object): for group in contact._groups: if group not in groups: # the contact is not in the group anymore + contact._groups.remove(group) self.remove_contact_from_group(group, contact) def remove_contact_from_group(self, group_name, contact): diff --git a/src/tabs.py b/src/tabs.py index f7c0c9c4..1b6aeb7c 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -1211,6 +1211,9 @@ class RosterInfoTab(Tab): 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: /accept [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.commands['add'] = (self.command_add, _("Usage: /add \nAdd: Use this command to add the specified JID to your roster. The reverse authorization will automatically be accepted if the remote JID accepts your subscription, leading to a mutual presence subscription."), None) + self.commands['name'] = (self.command_name, _("Usage: /name \nSet the given JID's name"), self.completion_name) + self.commands['groupadd'] = (self.command_groupadd, _("Usage: /groupadd \nAdd the given JID to the given group"), self.completion_groupadd) + self.commands['groupremove'] = (self.command_groupremove, _("Usage: /groupremove \nRemove the given JID from the given group"), self.completion_groupremove) self.commands['remove'] = (self.command_remove, _("Usage: /remove [jid]\nRemove: Use this command to remove the specified JID from your roster. This wil unsubscribe you from its presence, cancel its subscription to yours, and remove the item from your roster"), self.completion_remove) self.commands['export'] = (self.command_export, _("Usage: /export [/path/to/file]\nExport: Use this command to export your contacts into /path/to/file if specified, or $HOME/poezio_contacts if not."), None) self.commands['import'] = (self.command_import, _("Usage: /import [/path/to/file]\nImport: Use this command to import your contacts from /path/to/file if specified, or $HOME/poezio_contacts if not."), None) @@ -1263,6 +1266,87 @@ class RosterInfoTab(Tab): return self.core.xmpp.sendPresence(pto=jid, ptype='subscribe') + def command_name(self, args): + """ + Set a name for the specified JID in your roster + """ + args = args.split(None, 1) + if len(args) < 1: + return + jid = JID(args[0]).bare + name = args[1] if len(args) == 2 else '' + + contact = roster.get_contact_by_jid(jid) + if not contact: + self.core.information(_('No such JID in roster'), 'Error') + return + + groups = set(contact.get_groups()) + subscription = contact.get_subscription() + if self.core.xmpp.update_roster(jid, name=name, groups=groups, subscription=subscription): + contact.set_name(name) + + def command_groupadd(self, args): + """ + Add the specified JID to the specified group + """ + args = args.split(None, 1) + if len(args) != 2: + return + jid = JID(args[0]).bare + group = args[1] + + contact = roster.get_contact_by_jid(jid) + if not contact: + self.core.information(_('No such JID in roster'), 'Error') + return + + new_groups = set(contact.get_groups()) + if group in new_groups: + self.core.information(_('JID already in group'), 'Error') + return + + new_groups.add(group) + try: + new_groups.remove('none') + except KeyError: + pass + + name = contact.get_name() + subscription = contact.get_subscription() + if self.core.xmpp.update_roster(jid, name=name, groups=new_groups, subscription=subscription): + roster.edit_groups_of_contact(contact, new_groups) + + def command_groupremove(self, args): + """ + Remove the specified JID to the specified group + """ + args = args.split(None, 1) + if len(args) != 2: + return + jid = JID(args[0]).bare + group = args[1] + + contact = roster.get_contact_by_jid(jid) + if not contact: + self.core.information(_('No such JID in roster'), 'Error') + return + + new_groups = set(contact.get_groups()) + try: + new_groups.remove('none') + except KeyError: + pass + if group not in new_groups: + self.core.information(_('JID not in group'), 'Error') + return + + new_groups.remove(group) + name = contact.get_name() + subscription = contact.get_subscription() + if self.core.xmpp.update_roster(jid, name=name, groups=new_groups, subscription=subscription): + roster.edit_groups_of_contact(contact, new_groups) + def command_remove(self, args): """ Remove the specified JID from the roster. i.e. : unsubscribe @@ -1338,6 +1422,53 @@ class RosterInfoTab(Tab): jids = [contact.get_bare_jid() for contact in roster.get_contacts()] return the_input.auto_completion(jids, '') + def completion_name(self, the_input): + text = the_input.get_text() + n = len(text.split()) + if text.endswith(' '): + n += 1 + + if n == 2: + jids = [contact.get_bare_jid() for contact in roster.get_contacts()] + return the_input.auto_completion(jids, '') + return False + + def completion_groupadd(self, the_input): + text = the_input.get_text() + n = len(text.split()) + if text.endswith(' '): + n += 1 + + if n == 2: + jids = [contact.get_bare_jid() for contact in roster.get_contacts()] + return the_input.auto_completion(jids, '') + elif n == 3: + groups = [group.name for group in roster.get_groups() if group.name != 'none'] + return the_input.auto_completion(groups, '') + return False + + def completion_groupremove(self, the_input): + text = the_input.get_text() + args = text.split() + n = len(args) + if text.endswith(' '): + n += 1 + + if n == 2: + jids = [contact.get_bare_jid() for contact in roster.get_contacts()] + return the_input.auto_completion(jids, '') + elif n == 3: + contact = roster.get_contact_by_jid(args[1]) + if not contact: + return False + groups = list(contact.get_groups()) + try: + groups.remove('none') + except ValueError: + pass + return the_input.auto_completion(groups, '') + return False + def completion_deny(self, the_input): """ Complete the first argument from the list of the From 347733804f8d61a01bc0a286f6f872f8dd14527d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 1 Oct 2011 20:46:20 +0200 Subject: [PATCH 06/28] Do not try to cycle completion on commands if there was only one possibily. You can now see by the space appended at the end if it was the only one. It lets you complete arguments without having to add a stupid space after the command name --- src/tabs.py | 10 ++++++++-- src/windows.py | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index 1b6aeb7c..fbcfc597 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -125,7 +125,13 @@ class Tab(object): # complete the command's name words = ['/%s'% (name) for name in self.core.commands] +\ ['/%s' % (name) for name in self.commands] - the_input.auto_completion(words, ' ') + the_input.auto_completion(words, '') + # Do not try to cycle command completion if there was only + # one possibily. The next tab will complete the argument. + # Otherwise we would need to add a useless space before being + # able to complete the arguments. + if len(the_input.hit_list) == 1: + the_input.do_command(' ') return True return False @@ -600,7 +606,7 @@ class MucTab(ChatTab): def completion_topic(self, the_input): current_topic = self.get_room().topic - return the_input.auto_completion([current_topic], ' ') + return the_input.auto_completion([current_topic], '') def command_kick(self, arg): """ diff --git a/src/windows.py b/src/windows.py index 03066857..fb99416c 100644 --- a/src/windows.py +++ b/src/windows.py @@ -122,7 +122,6 @@ class Win(object): self.move(y, x) next_attr_char = text.find('\x19') while next_attr_char != -1 and text: - log.debug('Addstr_Colored: [%s]' % text.replace('\x19', '\\x19')) if next_attr_char + 1 < len(text): attr_char = text[next_attr_char+1].lower() else: @@ -961,7 +960,7 @@ class Input(Win): if pos < len(self.text) and after.endswith(' ') and self.text[pos] == ' ': after = after[:-1] # remove the last space if we are already on a space if not self.last_completion: - space_before_cursor = self.text.rfind(' ', 0, pos-1) + space_before_cursor = self.text.rfind(' ', 0, pos) if space_before_cursor != -1: begin = self.text[space_before_cursor+1:pos] else: @@ -1043,7 +1042,8 @@ class Input(Win): return res if not key or len(key) > 1: return False # ignore non-handled keyboard shortcuts - self.reset_completion() + if reset: + self.reset_completion() self.text = self.text[:self.pos+self.line_pos]+key+self.text[self.pos+self.line_pos:] (y, x) = self._win.getyx() if x == self.width-1: From a5c067fd932f8f67a41556929b59587d0cb48332 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 2 Oct 2011 00:12:22 +0200 Subject: [PATCH 07/28] /clear command in MUC --- src/tabs.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/tabs.py b/src/tabs.py index fbcfc597..8ddf60ad 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -414,6 +414,8 @@ class MucTab(ChatTab): self.commands['configure'] = (self.command_configure, _('Usage: /configure\nConfigure: Configure the current room, through a form.'), None) self.commands['version'] = (self.command_version, _('Usage: /version \nVersion: get the software version of the given JID or nick in room (usually its XMPP client and Operating System)'), None) self.commands['names'] = (self.command_names, _('Usage: /names\nNames: get the list of the users in the room, and the list of the people assuming the different roles.'), None) + self.commands['clear'] = (self.command_clear, + _("""Usage: /clear\nClear: clears the current buffer'"""), None) self.resize() def scroll_user_list_up(self): @@ -461,6 +463,15 @@ class MucTab(ChatTab): self.core.xmpp.plugin['xep_0045'].configureRoom(self.get_name(), form) self.core.close_tab() + def command_clear(self, args): + """ + /clear + """ + self._room.messages = [] + self.text_win.rebuild_everything(self._room) + self.refresh() + self.core.doupdate() + def command_cycle(self, arg): if self.get_room().joined: muc.leave_groupchat(self.core.xmpp, self.get_name(), self.get_room().own_nick, arg) From 4dfe2229da7052985736bef93c7b02c179780548 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 1 Oct 2011 22:47:47 +0200 Subject: [PATCH 08/28] remove white from the nick colors --- src/theming.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/theming.py b/src/theming.py index 382a3146..4bfdad42 100644 --- a/src/theming.py +++ b/src/theming.py @@ -118,7 +118,7 @@ class Theme(object): # A list of colors randomly attributed to nicks in MUCs # Setting more colors makes it harder to have two nicks with the same color, # avoiding confusions. - LIST_COLOR_NICKNAMES = [(1, -1), (2, -1), (3, -1), (4, -1), (5, -1), (6, -1), (7, -1), (8, -1), (9, -1), (10, -1), (11, -1), (12, -1), (13, -1), (14, -1), (23, -1), (23, -1), (88, -1), (99, -1), (100, -1), (154, -1), (213, -1), (216, -1), (227, -1)] + LIST_COLOR_NICKNAMES = [(1, -1), (2, -1), (3, -1), (4, -1), (5, -1), (6, -1), (8, -1), (9, -1), (10, -1), (11, -1), (12, -1), (13, -1), (14, -1), (23, -1), (23, -1), (88, -1), (99, -1), (100, -1), (154, -1), (213, -1), (216, -1), (227, -1)] # This is your own nickname COLOR_OWN_NICK = (254, -1) From 341da5b18e6665406078f74fc56a1aad37bc38dc Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 1 Oct 2011 22:47:47 +0200 Subject: [PATCH 09/28] remove white from the nick colors --- src/theming.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/theming.py b/src/theming.py index 382a3146..4bfdad42 100644 --- a/src/theming.py +++ b/src/theming.py @@ -118,7 +118,7 @@ class Theme(object): # A list of colors randomly attributed to nicks in MUCs # Setting more colors makes it harder to have two nicks with the same color, # avoiding confusions. - LIST_COLOR_NICKNAMES = [(1, -1), (2, -1), (3, -1), (4, -1), (5, -1), (6, -1), (7, -1), (8, -1), (9, -1), (10, -1), (11, -1), (12, -1), (13, -1), (14, -1), (23, -1), (23, -1), (88, -1), (99, -1), (100, -1), (154, -1), (213, -1), (216, -1), (227, -1)] + LIST_COLOR_NICKNAMES = [(1, -1), (2, -1), (3, -1), (4, -1), (5, -1), (6, -1), (8, -1), (9, -1), (10, -1), (11, -1), (12, -1), (13, -1), (14, -1), (23, -1), (23, -1), (88, -1), (99, -1), (100, -1), (154, -1), (213, -1), (216, -1), (227, -1)] # This is your own nickname COLOR_OWN_NICK = (254, -1) From 5ae665b2535b2ff174bd9af357afc337748a57a3 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 2 Oct 2011 17:39:18 +0200 Subject: [PATCH 10/28] Fix completion case-sensitiveness --- src/windows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows.py b/src/windows.py index fb99416c..4f2c68c6 100644 --- a/src/windows.py +++ b/src/windows.py @@ -967,7 +967,7 @@ class Input(Win): begin = self.text[:pos] hit_list = [] # list of matching nicks for word in word_list: - if word.lower().startswith(begin): + if word.lower().startswith(begin.lower()): hit_list.append(word) if len(hit_list) == 0: return From bfcf20f301bb7029f2613122ffc6f4724a8e84dc Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 2 Oct 2011 21:18:25 +0200 Subject: [PATCH 11/28] By default, log only critical messages. This avoid warnings to be displayed on stdout if no debug file was specified --- src/poezio.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/poezio.py b/src/poezio.py index dc877626..7b55ce96 100644 --- a/src/poezio.py +++ b/src/poezio.py @@ -27,6 +27,8 @@ def main(): signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl-c if options.debug: logging.basicConfig(filename=options.debug, level=logging.DEBUG) + else: + logging.basicConfig(level=logging.CRITICAL) cocore = singleton.Singleton(core.Core) cocore.start() if not cocore.xmpp.start(): # Connect to remote server From e35bf19aed81ed48a1a3489b4ee3edba69a04b67 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 4 Oct 2011 18:56:02 +0200 Subject: [PATCH 12/28] fixes #2263 --- src/multiuserchat.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/multiuserchat.py b/src/multiuserchat.py index 10ea0daf..832b97a7 100644 --- a/src/multiuserchat.py +++ b/src/multiuserchat.py @@ -81,4 +81,8 @@ def eject_user(xmpp, jid, nick, reason): query.append(item) iq.append(query) iq['to'] = jid - return iq.send() + try: + iq.send() + except Exception as e: + return e.iq + From be2d66f8a2ce63800d41f296d502e1338f6f7bed Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 9 Oct 2011 19:54:13 +0200 Subject: [PATCH 13/28] Fixed #2268 --- src/core.py | 2 +- src/tabs.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.py b/src/core.py index 766be909..9f36b78a 100644 --- a/src/core.py +++ b/src/core.py @@ -1269,7 +1269,7 @@ class Core(object): """ /join [room][/nick] [password] """ - args = arg.split() + args = common.shell_split(arg) password = None if len(args) == 0: t = self.current_tab() diff --git a/src/tabs.py b/src/tabs.py index 8ddf60ad..60d91777 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -477,7 +477,7 @@ class MucTab(ChatTab): muc.leave_groupchat(self.core.xmpp, self.get_name(), self.get_room().own_nick, arg) self.get_room().disconnect() self.core.disable_private_tabs(self.get_room().name) - self.core.command_join('/%s' % self.core.get_bookmark_nickname(self.get_room().name), '0') + self.core.command_join('"/%s"' % self.core.get_bookmark_nickname(self.get_room().name), '0') self.user_win.pos = 0 def command_recolor(self, arg): From 2479201b306b73aec00d1968b47fc2014d6faa44 Mon Sep 17 00:00:00 2001 From: mathieui Date: Tue, 11 Oct 2011 23:00:29 +0200 Subject: [PATCH 14/28] Fix the data forms --- src/data_forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data_forms.py b/src/data_forms.py index 873aef85..a7bbe97f 100644 --- a/src/data_forms.py +++ b/src/data_forms.py @@ -408,7 +408,7 @@ class FormWin(object): self._win = curses.newwin(height, width, y, x) self.current_input = 0 self.inputs = [] # dict list - for (name, field) in self._form.getFields(): + for (name, field) in self._form.getFields().items(): if field['type'] == 'hidden': continue try: @@ -488,7 +488,7 @@ class FormWin(object): self._win.erase() y = 0 i = 0 - for name, field in self._form.getFields(): + for name, field in self._form.getFields().items(): if field['type'] == 'hidden': continue self.inputs[i]['label'].resize(1, self.width//3, y + 1, 0) From 14702b1806d9707524920416c6fc02b694bed10a Mon Sep 17 00:00:00 2001 From: mathieui Date: Tue, 11 Oct 2011 23:04:40 +0200 Subject: [PATCH 15/28] Fixed some typos --- src/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.py b/src/core.py index 9f36b78a..8abaec63 100644 --- a/src/core.py +++ b/src/core.py @@ -281,7 +281,7 @@ class Core(object): """ When a data form is received """ - self.information('%s' % messsage) + self.information('%s' % message) def on_chatstate_active(self, message): self.on_chatstate(message, "active") @@ -1036,7 +1036,7 @@ class Core(object): nick_from = message['mucnick'] room_from = message.getMucroom() if message['type'] == 'error': # Check if it's an error - return self.room_error(message, from_room) + return self.room_error(message, room_from) room = self.get_room_by_name(room_from) tab = self.get_tab_by_name(room_from, tabs.MucTab) if tab and tab.get_room() and tab.get_room().get_user_by_name(nick_from) and\ From ad45e89ded3ebeec3910df4c42d6b91402809a6d Mon Sep 17 00:00:00 2001 From: mathieui Date: Fri, 14 Oct 2011 01:32:14 +0200 Subject: [PATCH 16/28] User role management in MUC (ie /visitor /particpant /moderator) --- src/multiuserchat.py | 10 +++++----- src/tabs.py | 31 +++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/multiuserchat.py b/src/multiuserchat.py index 832b97a7..67fa32e6 100644 --- a/src/multiuserchat.py +++ b/src/multiuserchat.py @@ -67,13 +67,14 @@ def leave_groupchat(xmpp, jid, own_nick, msg): """ xmpp.plugin['xep_0045'].leaveMUC(jid, own_nick, msg) -def eject_user(xmpp, jid, nick, reason): +def set_user_role(xmpp, jid, nick, reason, role): """ - (try to) Eject an user from the room + (try to) Set the role of a MUC user + (role =) 'none': eject user) """ iq = xmpp.makeIqSet() query = ET.Element('{%s}query' % NS_MUC_ADMIN) - item = ET.Element('{%s}item' % NS_MUC_ADMIN, {'nick':nick, 'role':'none'}) + item = ET.Element('{%s}item' % NS_MUC_ADMIN, {'nick':nick, 'role':role}) if reason: reason_el = ET.Element('{%s}reason' % NS_MUC_ADMIN) reason_el.text = reason @@ -82,7 +83,6 @@ def eject_user(xmpp, jid, nick, reason): iq.append(query) iq['to'] = jid try: - iq.send() + return iq.send() except Exception as e: return e.iq - diff --git a/src/tabs.py b/src/tabs.py index 60d91777..3517c0c3 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -404,6 +404,9 @@ class MucTab(ChatTab): self.commands['ignore'] = (self.command_ignore, _("Usage: /ignore \nIgnore: Ignore a specified nickname."), None) self.commands['unignore'] = (self.command_unignore, _("Usage: /unignore \nUnignore: Remove the specified nickname from the ignore list."), self.completion_unignore) self.commands['kick'] = (self.command_kick, _("Usage: /kick [reason]\nKick: Kick the user with the specified nickname. You also can give an optional reason."), None) + self.commands['moderator'] = (self.command_moderator, _("Usage: /moderator [reason]\nModerator: Op the user with the specified nickname. You also can give an optional reason."), None) + self.commands['visitor'] = (self.command_visitor, _("Usage: /visitor [reason]\nVisitor: Mute the user with the specified nickname. You also can give an optional reason."), None) + self.commands['participant'] = (self.command_participant, _("Usage: /participant [reason]\nParticipant: Voice the user with the specified nickname. You also can give an optional reason."), None) self.commands['topic'] = (self.command_topic, _("Usage: /topic \nTopic: Change the subject of the room"), self.completion_topic) self.commands['query'] = (self.command_query, _('Usage: /query [message]\nQuery: Open a private conversation with . This nick has to be present in the room you\'re currently in. If you specified a message after the nickname, it will immediately be sent to this user'), None) self.commands['part'] = (self.command_part, _("Usage: /part [message]\nPart: disconnect from a room. You can specify an optional message."), None) @@ -623,9 +626,33 @@ class MucTab(ChatTab): """ /kick [reason] """ + self._command_change_role('none', 'kick', arg) + + def command_visitor(self, arg): + """ + /visitor [reason] + """ + self._command_change_role('visitor', 'visitor', arg) + + def command_participant(self, arg): + """ + /participant [reason] + """ + self._command_change_role('participant', 'participant', arg) + + def command_moderator(self, arg): + """ + /moderator [reason] + """ + self._command_change_role('moderator', 'moderator', arg) + + def _command_change_role(self, role, command, arg): + """ + Changes the role of the nick in args[0] + """ args = common.shell_split(arg) if len(args) < 1: - self.core.command_help('kick') + self.core.command_help('command') return nick = args[0] if len(args) >= 2: @@ -634,7 +661,7 @@ class MucTab(ChatTab): reason = '' if not self.get_room().joined: return - res = muc.eject_user(self.core.xmpp, self.get_name(), nick, reason) + res = muc.set_user_role(self.core.xmpp, self.get_name(), nick, reason, role) if res['type'] == 'error': self.core.room_error(res, self.get_name()) From d07b1d1e0d419ad3818efe2ee28a4dc914ca5218 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 16 Oct 2011 19:32:41 +0200 Subject: [PATCH 17/28] update update.sh --- update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update.sh b/update.sh index cc7b8962..4695a736 100755 --- a/update.sh +++ b/update.sh @@ -7,7 +7,7 @@ # Use launch.sh to start poezio directly from here echo 'Updating poezio' -hg pull -u +git pull if [ -e "SleekXMPP" ] then From 7e8c45787d51ecb573b156201c32fc1fa812de43 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 16 Oct 2011 19:34:17 +0200 Subject: [PATCH 18/28] =?UTF-8?q?Indent.=20That=E2=80=99s=20actually=20use?= =?UTF-8?q?less,=20but=20I=20want=20to=20test=20something.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 496d3d7b..31ccc5a6 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup (name = 'BuildLines', author = 'Florent Le Coz', author_email = 'louiz@louiz.org', long_description = """ - a python3 module for poezio, used to replace some time-critical - python functions that are too slow. If compiled, poezio will use this module, - otherwise it will just use the equivalent python functions. - """) + a python3 module for poezio, used to replace some time-critical + python functions that are too slow. If compiled, poezio will use this module, + otherwise it will just use the equivalent python functions. + """) From a4aeef558b1ffa54fadf24455dd44fc00ed29f53 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 16 Oct 2011 21:53:48 +0200 Subject: [PATCH 19/28] Add information on git in the README --- README | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/README b/README index 49d31384..70b19ec9 100644 --- a/README +++ b/README @@ -48,7 +48,7 @@ you can now simply launch `poezio' You can edit the config file (~/.config/poezio/poezio.cfg by default) or data/default_config.cfg (if you want to edit the config before the -first launch). The default config file is fully commented. +first launch). The default config file is fully commented. Please, see the online documentation for more information on installing, configuring or using poezio: @@ -85,6 +85,52 @@ Please read the COPYING file for details. The artwork logo was made by Gaëtan Ribémont and released under the Creative Commons BY license (http://creativecommons.org/licenses/by/2.0/) + +======================= + Hacking +======================= +If you want to contribute, you are invited on poezio@muc.poezio.eu to +announce your ideas, what you are going to do, or to seek help if you +have trouble understanding some of the code. +The preferred way to submit changes is through a public git repository. +But mercurial repositories or simple patches are also welcome. + +For contributors having commit access: + +This section explains how the git repository is organized. +The “master” branch is the branch where all recent development is made. This is +the unstable version, which can be broken, but we should try to keep it usable +and crash-free as much as possible (so, never push to it if you are adding a +*known* crash). + +New big features that take time to be complete should be developped in feature +branches (for example the “plugins” or the “opt” branches). +If it’s a really long feature, merge the “master” branch in that feature branch +from time to time, to avoid huge merges (and merge issues) when you’ll have to +merge your feature back in “master”. +Merge your work in master once it works and is usable, not necessarily when +it’s 100% finished. Polishing and last bug fixes can take place in “master”. + +Conflicts should be solved with *rebase* and not with merge. This means +that if two developpers commited one thing at the same time in their own +repository, the first pushes on the public public repos, and the other +has to pull before being able to push too. In that case, the second +developper should use the rebase command instead of merge. This avoids +creating unnecessary “branches” and visible merges. +On the contrary, when merging feature branches back to “master”, we should +use merge with the --no-ff tag (this makes sure the branch will always +distinctly appear in the logs), even if no conflict occured. + +Finally, when a release is ready, we should merge the “master” branch +into the releases branch, then tag it to that version number. +If an “urgent” bugfix has to be made for a release (for example +a security issue is discovered on the last stable version, and +the current master has evolved too much to be released in the current +state), we create a new bugfix branch from the “releases” branch, we fix +it and finally merge it back to the “releases” branch, and tag it (and +we merge it to “master” as well, of course). + + ======================= Thanks ======================= From 0764708f7b2ef832b3c7dba8eb3d788c67db51ff Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 16 Oct 2011 21:55:14 +0200 Subject: [PATCH 20/28] Set room to poezio@muc.poezio.eu --- README | 4 +++- data/default_config.cfg | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README b/README index 70b19ec9..5bfbe17a 100644 --- a/README +++ b/README @@ -66,13 +66,15 @@ feature you want. Florent Le Coz (louiz’) (main developper) Mathieu Pasquet (mathieui) (developper) + ======================= Contact/support ======================= -Jabber ChatRoom: poezio@kikoo.louiz.org +Jabber ChatRoom: poezio@muc.poezio.eu Forum: http://dev.louiz.org/project/poezio/forum Report a bug: http://dev.louiz.org/project/poezio/bugs/add + ======================= License ======================= diff --git a/data/default_config.cfg b/data/default_config.cfg index 0c16ef97..d2fe7f87 100644 --- a/data/default_config.cfg +++ b/data/default_config.cfg @@ -34,7 +34,7 @@ password = # the rooms you will join automatically on startup, with associated nickname or not # format : room@server.tld/nickname:room2@server.tld/nickname2 # default_nick will be used if "/nickname" is not specified -rooms = poezio@kikoo.louiz.org +rooms = poezio@muc.poezio.eu # the completion type you will use to complete nicknames # if "normal", complete the entire name to the first available completion From 778754783e3e0371161ea883b62128b108c4e994 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 16 Oct 2011 23:40:02 +0200 Subject: [PATCH 21/28] test --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 5bfbe17a..edbb8059 100644 --- a/README +++ b/README @@ -145,3 +145,4 @@ we merge it to “master” as well, of course). FlashCode (weechat dev) - Useful advices on how to use ncurses efficiently = Project = Gajim - send_vcard method and common.py + From 7d392c609348c28f9fae108955d79f150d4f47d5 Mon Sep 17 00:00:00 2001 From: Mathieu Pasquet Date: Mon, 17 Oct 2011 19:07:53 +0200 Subject: [PATCH 22/28] Typo --- src/tabs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tabs.py b/src/tabs.py index 3517c0c3..0ab6e1bb 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -652,7 +652,7 @@ class MucTab(ChatTab): """ args = common.shell_split(arg) if len(args) < 1: - self.core.command_help('command') + self.core.command_help(command) return nick = args[0] if len(args) >= 2: From 69c6b38894b8099a641ca431e47af6805eeab6b2 Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 17 Oct 2011 21:29:39 +0200 Subject: [PATCH 23/28] remove /visitor /participant /moderator and replace them with /role --- src/multiuserchat.py | 2 +- src/tabs.py | 43 ++++++++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/multiuserchat.py b/src/multiuserchat.py index 67fa32e6..b00b4599 100644 --- a/src/multiuserchat.py +++ b/src/multiuserchat.py @@ -70,7 +70,7 @@ def leave_groupchat(xmpp, jid, own_nick, msg): def set_user_role(xmpp, jid, nick, reason, role): """ (try to) Set the role of a MUC user - (role =) 'none': eject user) + (role = 'none': eject user) """ iq = xmpp.makeIqSet() query = ET.Element('{%s}query' % NS_MUC_ADMIN) diff --git a/src/tabs.py b/src/tabs.py index 0ab6e1bb..ad4b9ca9 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -404,9 +404,7 @@ class MucTab(ChatTab): self.commands['ignore'] = (self.command_ignore, _("Usage: /ignore \nIgnore: Ignore a specified nickname."), None) self.commands['unignore'] = (self.command_unignore, _("Usage: /unignore \nUnignore: Remove the specified nickname from the ignore list."), self.completion_unignore) self.commands['kick'] = (self.command_kick, _("Usage: /kick [reason]\nKick: Kick the user with the specified nickname. You also can give an optional reason."), None) - self.commands['moderator'] = (self.command_moderator, _("Usage: /moderator [reason]\nModerator: Op the user with the specified nickname. You also can give an optional reason."), None) - self.commands['visitor'] = (self.command_visitor, _("Usage: /visitor [reason]\nVisitor: Mute the user with the specified nickname. You also can give an optional reason."), None) - self.commands['participant'] = (self.command_participant, _("Usage: /participant [reason]\nParticipant: Voice the user with the specified nickname. You also can give an optional reason."), None) + self.commands['role'] = (self.command_role, _("Usage: /role [reason]\nRole: Set the role of an user. Roles can be: none, visitor, participant, moderator. You also can give an optional reason."), None) self.commands['topic'] = (self.command_topic, _("Usage: /topic \nTopic: Change the subject of the room"), self.completion_topic) self.commands['query'] = (self.command_query, _('Usage: /query [message]\nQuery: Open a private conversation with . This nick has to be present in the room you\'re currently in. If you specified a message after the nickname, it will immediately be sent to this user'), None) self.commands['part'] = (self.command_part, _("Usage: /part [message]\nPart: disconnect from a room. You can specify an optional message."), None) @@ -626,25 +624,32 @@ class MucTab(ChatTab): """ /kick [reason] """ - self._command_change_role('none', 'kick', arg) + args = common.shell_split(arg) + if not len(args): + self.core.command_help('kick') + self._command_change_role('kick '+arg) - def command_visitor(self, arg): + def command_role(self, arg): """ - /visitor [reason] + /role [reason] + Changes the role of an user + roles can be: none, visitor, participant, moderator """ - self._command_change_role('visitor', 'visitor', arg) - - def command_participant(self, arg): - """ - /participant [reason] - """ - self._command_change_role('participant', 'participant', arg) - - def command_moderator(self, arg): - """ - /moderator [reason] - """ - self._command_change_role('moderator', 'moderator', arg) + args = common.shell_split(arg) + if len(args) < 2: + self.core.command_help('role') + return + nick, role = args[0],args[1] + if len(args) > 2: + reason = ' '.join(args[2:]) + else: + reason = '' + if not self.get_room().joined or \ + not role in ('none', 'visitor', 'participant', 'moderator'): + return + res = muc.set_user_role(self.core.xmpp, self.get_name(), nick, reason, role) + if res['type'] == 'error': + self.core.room_error(res, self.get_name()) def _command_change_role(self, role, command, arg): """ From b29f11ce19188f277d8b94a640fe54c19f2b7972 Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 17 Oct 2011 21:30:36 +0200 Subject: [PATCH 24/28] /affiliation command (without the 'outcast' affiliation ATM) --- src/multiuserchat.py | 19 +++++++++++++++++++ src/tabs.py | 24 +++++++++++++++--------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/multiuserchat.py b/src/multiuserchat.py index b00b4599..264f0e4a 100644 --- a/src/multiuserchat.py +++ b/src/multiuserchat.py @@ -86,3 +86,22 @@ def set_user_role(xmpp, jid, nick, reason, role): return iq.send() except Exception as e: return e.iq + +def set_user_affiliation(xmpp, jid, nick, reason, affiliation): + """ + (try to) Set the affiliation of a MUC user + """ + iq = xmpp.makeIqSet() + query = ET.Element('{%s}query' % NS_MUC_ADMIN) + item = ET.Element('{%s}item' % NS_MUC_ADMIN, {'nick':nick, 'affiliation':affiliation}) + if reason: + reason_el = ET.Element('{%s}reason' % NS_MUC_ADMIN) + reason_el.text = reason + item.append(reason_el) + query.append(item) + iq.append(query) + iq['to'] = jid + try: + return iq.send() + except Exception as e: + return e.iq diff --git a/src/tabs.py b/src/tabs.py index ad4b9ca9..2b1b586a 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -405,6 +405,7 @@ class MucTab(ChatTab): self.commands['unignore'] = (self.command_unignore, _("Usage: /unignore \nUnignore: Remove the specified nickname from the ignore list."), self.completion_unignore) self.commands['kick'] = (self.command_kick, _("Usage: /kick [reason]\nKick: Kick the user with the specified nickname. You also can give an optional reason."), None) self.commands['role'] = (self.command_role, _("Usage: /role [reason]\nRole: Set the role of an user. Roles can be: none, visitor, participant, moderator. You also can give an optional reason."), None) + self.commands['affiliation'] = (self.command_affiliation, _("Usage: /affiliation [reason]\nAffiliation: Set the affiliation of an user. Affiliations can be: outcast, none, member, admin, owner. You also can give an optional reason."), None) self.commands['topic'] = (self.command_topic, _("Usage: /topic \nTopic: Change the subject of the room"), self.completion_topic) self.commands['query'] = (self.command_query, _('Usage: /query [message]\nQuery: Open a private conversation with . This nick has to be present in the room you\'re currently in. If you specified a message after the nickname, it will immediately be sent to this user'), None) self.commands['part'] = (self.command_part, _("Usage: /part [message]\nPart: disconnect from a room. You can specify an optional message."), None) @@ -651,22 +652,27 @@ class MucTab(ChatTab): if res['type'] == 'error': self.core.room_error(res, self.get_name()) - def _command_change_role(self, role, command, arg): + def command_affiliation(self, arg): """ - Changes the role of the nick in args[0] + /affiliation [reason] + Changes the affiliation of an user + roles can be: none, visitor, participant, moderator """ args = common.shell_split(arg) - if len(args) < 1: - self.core.command_help(command) + if len(args) < 2: + self.core.command_help('role') return - nick = args[0] - if len(args) >= 2: - reason = ' '.join(args[1:]) + nick, affiliation = args[0],args[1] + if len(args) > 2: + reason = ' '.join(args[2:]) else: reason = '' - if not self.get_room().joined: + if not self.get_room().joined or \ + not affiliation in ('none', 'member', 'admin', 'owner'): +# replace this ↑ with this ↓ when the ban list support is done +# not affiliation in ('outcast', 'none', 'member', 'admin', 'owner'): return - res = muc.set_user_role(self.core.xmpp, self.get_name(), nick, reason, role) + res = muc.set_user_affiliation(self.core.xmpp, self.get_name(), nick, reason, affiliation) if res['type'] == 'error': self.core.room_error(res, self.get_name()) From 20eeb00b9744eae068f894a98b3a355a0ef728ac Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 17 Oct 2011 21:42:22 +0200 Subject: [PATCH 25/28] test --- README | 1 - 1 file changed, 1 deletion(-) diff --git a/README b/README index edbb8059..5bfbe17a 100644 --- a/README +++ b/README @@ -145,4 +145,3 @@ we merge it to “master” as well, of course). FlashCode (weechat dev) - Useful advices on how to use ncurses efficiently = Project = Gajim - send_vcard method and common.py - From ce5fa543f24be83cf4dbbfe07266cba75350c6a7 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 17 Oct 2011 23:12:51 +0200 Subject: [PATCH 26/28] fix the git pull line --- update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update.sh b/update.sh index 4695a736..1b3ba3fa 100755 --- a/update.sh +++ b/update.sh @@ -13,7 +13,7 @@ if [ -e "SleekXMPP" ] then echo "Updating SleekXMPP" cd SleekXMPP - git pull + git pull origin master cd .. else echo "Downloading SleekXMPP" From 354006a850490cdbf9a598d237ac78f084114e72 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 17 Oct 2011 23:13:57 +0200 Subject: [PATCH 27/28] actually does it correctly --- update.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/update.sh b/update.sh index 1b3ba3fa..510bbb07 100755 --- a/update.sh +++ b/update.sh @@ -7,13 +7,13 @@ # Use launch.sh to start poezio directly from here echo 'Updating poezio' -git pull +git pull origin master if [ -e "SleekXMPP" ] then echo "Updating SleekXMPP" cd SleekXMPP - git pull origin master + git pull cd .. else echo "Downloading SleekXMPP" From aa6738800d67c5061d7e551b3d896f3366296045 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 20 Oct 2011 21:55:24 +0200 Subject: [PATCH 28/28] Fix crash on completion of recent words containing xhtml-im attributes fixes #2278 --- src/tabs.py | 10 +++++----- src/xhtml.py | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/tabs.py b/src/tabs.py index 2b1b586a..cd9450a7 100644 --- a/src/tabs.py +++ b/src/tabs.py @@ -289,7 +289,7 @@ class ChatTab(Tab): for msg in self._room.messages[:-40:-1]: if not msg: continue - txt = msg.txt + txt = xhtml.clean_text(msg.txt) for char in char_we_dont_want: txt = txt.replace(char, ' ') for word in txt.split(): @@ -300,7 +300,7 @@ class ChatTab(Tab): def on_enter(self): txt = self.input.key_enter() if txt: - clean_text = xhtml.clean_text(txt) + clean_text = xhtml.clean_text_simple(txt) if not self.execute_command(clean_text): if txt.startswith('//'): txt = txt[1:] @@ -683,7 +683,7 @@ class MucTab(ChatTab): if line.find('\x19') == -1: msg['body'] = line else: - msg['body'] = xhtml.clean_text(line) + msg['body'] = xhtml.clean_text_simple(line) msg['xhtml_im'] = xhtml.poezio_colors_to_html(line) if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates is not False: msg['chat_state'] = needed @@ -1075,7 +1075,7 @@ class PrivateTab(ChatTab): if line.find('\x19') == -1: msg['body'] = line else: - msg['body'] = xhtml.clean_text(line) + msg['body'] = xhtml.clean_text_simple(line) msg['xhtml_im'] = xhtml.poezio_colors_to_html(line) if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates is not False: needed = 'inactive' if self.core.status.show in ('xa', 'away') else 'active' @@ -1746,7 +1746,7 @@ class ConversationTab(ChatTab): if line.find('\x19') == -1: msg['body'] = line else: - msg['body'] = xhtml.clean_text(line) + msg['body'] = xhtml.clean_text_simple(line) msg['xhtml_im'] = xhtml.poezio_colors_to_html(line) if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates is not False: needed = 'inactive' if self.core.status.show in ('xa', 'away') else 'active' diff --git a/src/xhtml.py b/src/xhtml.py index c14382b8..38239d18 100644 --- a/src/xhtml.py +++ b/src/xhtml.py @@ -176,6 +176,8 @@ log = logging.getLogger(__name__) whitespace_re = re.compile(r'\s+') +xhtml_attr_re = re.compile(r'\x19\d{0,3}\}|\x19[buaio]') + def get_body_from_message_stanza(message): """ Returns a string with xhtml markups converted to @@ -321,9 +323,18 @@ def xhtml_to_poezio_colors(text): return message -def clean_text(string): +def clean_text(s): """ - Remove all \x19 from the string + Remove all xhtml-im attributes (\x19etc) from the string with the + complete color format, i.e \x19xxx} + """ + s = re.sub(xhtml_attr_re, "", s) + return s + +def clean_text_simple(string): + """ + Remove all \x19 from the string formatted with simple colors: + \x198 """ pos = string.find('\x19') while pos != -1: