diff options
Diffstat (limited to 'src/tabs/muctab.py')
-rw-r--r-- | src/tabs/muctab.py | 674 |
1 files changed, 398 insertions, 276 deletions
diff --git a/src/tabs/muctab.py b/src/tabs/muctab.py index 8ac9b7e2..d4b13258 100644 --- a/src/tabs/muctab.py +++ b/src/tabs/muctab.py @@ -7,8 +7,6 @@ It keeps track of many things such as part/joins, maintains an user list, and updates private tabs when necessary. """ -from gettext import gettext as _ - import logging log = logging.getLogger(__name__) @@ -29,7 +27,7 @@ import windows import xhtml from common import safeJID from config import config -from decorators import refresh_wrapper +from decorators import refresh_wrapper, command_args_parser from logger import logger from roster import roster from theming import get_theme, dump_tuple @@ -37,11 +35,11 @@ from user import User SHOW_NAME = { - 'dnd': _('busy'), - 'away': _('away'), - 'xa': _('not available'), - 'chat': _('chatty'), - '': _('available') + 'dnd': 'busy', + 'away': 'away', + 'xa': 'not available', + 'chat': 'chatty', + '': 'available' } NS_MUC_USER = 'http://jabber.org/protocol/muc#user' @@ -55,13 +53,14 @@ class MucTab(ChatTab): message_type = 'groupchat' plugin_commands = {} plugin_keys = {} - def __init__(self, jid, nick): + def __init__(self, jid, nick, password=None): self.joined = False ChatTab.__init__(self, jid) if self.joined == False: self._state = 'disconnected' self.own_nick = nick self.name = jid + self.password = password self.users = [] self.privates = [] # private conversations self.topic = '' @@ -88,106 +87,112 @@ class MucTab(ChatTab): self.key_func['M-p'] = self.go_to_prev_hl # commands self.register_command('ignore', self.command_ignore, - usage=_('<nickname>'), - desc=_('Ignore a specified nickname.'), - shortdesc=_('Ignore someone'), + usage='<nickname>', + desc='Ignore a specified nickname.', + shortdesc='Ignore someone', completion=self.completion_ignore) self.register_command('unignore', self.command_unignore, - usage=_('<nickname>'), - desc=_('Remove the specified nickname from the ignore list.'), - shortdesc=_('Unignore someone.'), + usage='<nickname>', + desc='Remove the specified nickname from the ignore list.', + shortdesc='Unignore someone.', completion=self.completion_unignore) self.register_command('kick', self.command_kick, - usage=_('<nick> [reason]'), - desc=_('Kick the user with the specified nickname.' - ' You also can give an optional reason.'), - shortdesc=_('Kick someone.'), + usage='<nick> [reason]', + desc='Kick the user with the specified nickname.' + ' You also can give an optional reason.', + shortdesc='Kick someone.', completion=self.completion_quoted) self.register_command('ban', self.command_ban, - usage=_('<nick> [reason]'), - desc=_('Ban the user with the specified nickname.' - ' You also can give an optional reason.'), + usage='<nick> [reason]', + desc='Ban the user with the specified nickname.' + ' You also can give an optional reason.', shortdesc='Ban someone', completion=self.completion_quoted) self.register_command('role', self.command_role, - usage=_('<nick> <role> [reason]'), - desc=_('Set the role of an user. Roles can be:' - ' none, visitor, participant, moderator.' - ' You also can give an optional reason.'), - shortdesc=_('Set the role of an user.'), + usage='<nick> <role> [reason]', + desc='Set the role of an user. Roles can be:' + ' none, visitor, participant, moderator.' + ' You also can give an optional reason.', + shortdesc='Set the role of an user.', completion=self.completion_role) self.register_command('affiliation', self.command_affiliation, - usage=_('<nick or jid> <affiliation>'), - desc=_('Set the affiliation of an user. Affiliations can be:' - ' outcast, none, member, admin, owner.'), - shortdesc=_('Set the affiliation of an user.'), + usage='<nick or jid> <affiliation>', + desc='Set the affiliation of an user. Affiliations can be:' + ' outcast, none, member, admin, owner.', + shortdesc='Set the affiliation of an user.', completion=self.completion_affiliation) self.register_command('topic', self.command_topic, - usage=_('<subject>'), - desc=_('Change the subject of the room.'), - shortdesc=_('Change the subject.'), + usage='<subject>', + desc='Change the subject of the room.', + shortdesc='Change the subject.', completion=self.completion_topic) self.register_command('query', self.command_query, - usage=_('<nick> [message]'), - desc=_('Open a private conversation with <nick>. 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.'), - shortdesc=_('Query an user.'), + usage='<nick> [message]', + desc='Open a private conversation with <nick>. 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.', + shortdesc='Query an user.', completion=self.completion_quoted) self.register_command('part', self.command_part, - usage=_('[message]'), - desc=_('Disconnect from a room. You can' - ' specify an optional message.'), - shortdesc=_('Leave the room.')) + usage='[message]', + desc='Disconnect from a room. You can' + ' specify an optional message.', + shortdesc='Leave the room.') self.register_command('close', self.command_close, - usage=_('[message]'), - desc=_('Disconnect from a room and close the tab.' - ' You can specify an optional message if ' - 'you are still connected.'), - shortdesc=_('Close the tab.')) + usage='[message]', + desc='Disconnect from a room and close the tab.' + ' You can specify an optional message if ' + 'you are still connected.', + shortdesc='Close the tab.') self.register_command('nick', self.command_nick, - usage=_('<nickname>'), - desc=_('Change your nickname in the current room.'), - shortdesc=_('Change your nickname.'), + usage='<nickname>', + desc='Change your nickname in the current room.', + shortdesc='Change your nickname.', completion=self.completion_nick) self.register_command('recolor', self.command_recolor, - usage=_('[random]'), - desc=_('Re-assign a color to all participants of the' - ' current room, based on the last time they talked.' - ' Use this if the participants currently talking ' - 'have too many identical colors. Use /recolor random' - ' for a non-deterministic result.'), - shortdesc=_('Change the nicks colors.'), + usage='[random]', + desc='Re-assign a color to all participants of the' + ' current room, based on the last time they talked.' + ' Use this if the participants currently talking ' + 'have too many identical colors. Use /recolor random' + ' for a non-deterministic result.', + shortdesc='Change the nicks colors.', completion=self.completion_recolor) + self.register_command('color', self.command_color, + usage='<nick> <color>', + desc='Fix a color for a nick. Use "unset" instead of a color' + ' to remove the attribution', + shortdesc='Fix a color for a nick.', + completion=self.completion_color) self.register_command('cycle', self.command_cycle, - usage=_('[message]'), - desc=_('Leave the current room and rejoin it immediately.'), - shortdesc=_('Leave and re-join the room.')) + usage='[message]', + desc='Leave the current room and rejoin it immediately.', + shortdesc='Leave and re-join the room.') self.register_command('info', self.command_info, - usage=_('<nickname>'), - desc=_('Display some information about the user ' - 'in the MUC: its/his/her role, affiliation,' - ' status and status message.'), - shortdesc=_('Show an user\'s infos.'), + usage='<nickname>', + desc='Display some information about the user ' + 'in the MUC: its/his/her role, affiliation,' + ' status and status message.', + shortdesc='Show an user\'s infos.', completion=self.completion_info) self.register_command('configure', self.command_configure, - desc=_('Configure the current room, through a form.'), - shortdesc=_('Configure the room.')) + desc='Configure the current room, through a form.', + shortdesc='Configure the room.') self.register_command('version', self.command_version, - usage=_('<jid or nick>'), - desc=_('Get the software version of the given JID' - ' or nick in room (usually its XMPP client' - ' and Operating System).'), - shortdesc=_('Get the software version of a jid.'), + usage='<jid or nick>', + desc='Get the software version of the given JID' + ' or nick in room (usually its XMPP client' + ' and Operating System).', + shortdesc='Get the software version of a jid.', completion=self.completion_version) self.register_command('names', self.command_names, - desc=_('Get the users in the room with their roles.'), - shortdesc=_('List the users.')) + desc='Get the users in the room with their roles.', + shortdesc='List the users.') self.register_command('invite', self.command_invite, - desc=_('Invite a contact to this room'), - usage=_('<jid> [reason]'), - shortdesc=_('Invite a contact to this room'), + desc='Invite a contact to this room', + usage='<jid> [reason]', + shortdesc='Invite a contact to this room', completion=self.completion_invite) if self.core.xmpp.boundjid.server == "gmail.com": #gmail sucks @@ -263,6 +268,21 @@ class MucTab(ChatTab): return the_input.new_completion(['random'], 1, '', quotify=False) return True + def completion_color(self, the_input): + """Completion for /color""" + n = the_input.get_argument_position(quoted=True) + if n == 1: + userlist = [user.nick for user in self.users] + if self.own_nick in userlist: + userlist.remove(self.own_nick) + return the_input.new_completion(userlist, 1, '', quotify=True) + elif n == 2: + colors = [i for i in xhtml.colors if i] + colors.sort() + colors.append('unset') + colors.append('random') + return the_input.new_completion(colors, 2, '', quotify=False) + def completion_ignore(self, the_input): """Completion for /ignore""" userlist = [user.nick for user in self.users] @@ -302,15 +322,12 @@ class MucTab(ChatTab): return the_input.new_completion(possible_affiliations, 2, '', quotify=True) + @command_args_parser.quoted(1, 1, ['']) def command_invite(self, args): """/invite <jid> [reason]""" - args = common.shell_split(args) - if len(args) == 1: - jid, reason = args[0], '' - elif len(args) == 2: - jid, reason = args - else: + if args is None: return self.core.command_help('invite') + jid, reason = args self.core.command_invite('%s %s "%s"' % (jid, self.name, reason)) def completion_invite(self, the_input): @@ -329,15 +346,17 @@ class MucTab(ChatTab): self.user_win.refresh(self.users) self.input.refresh() - def command_info(self, arg): + @command_args_parser.quoted(1) + def command_info(self, args): """ /info <nick> """ - if not arg: + if args is None: return self.core.command_help('info') - user = self.get_user_by_name(arg) + nick = args[0] + user = self.get_user_by_name(nick) if not user: - return self.core.information(_("Unknown user: %s") % arg) + return self.core.information("Unknown user: %s" % nick) theme = get_theme() if user.jid: user_jid = ' (\x19%s}%s\x19o)' % ( @@ -345,10 +364,10 @@ class MucTab(ChatTab): user.jid) else: user_jid = '' - info = _('\x19%s}%s\x19o%s: show: \x19%s}%s\x19o, affiliation:' - ' \x19%s}%s\x19o, role: \x19%s}%s\x19o%s') % ( + info = ('\x19%s}%s\x19o%s: show: \x19%s}%s\x19o, affiliation:' + ' \x19%s}%s\x19o, role: \x19%s}%s\x19o%s') % ( dump_tuple(user.color), - arg, + nick, user_jid, dump_tuple(theme.color_show(user.show)), user.show or 'Available', @@ -360,19 +379,20 @@ class MucTab(ChatTab): self.add_message(info, typ=0) self.core.refresh_window() - def command_configure(self, arg): + @command_args_parser.quoted(0) + def command_configure(self, ignored): """ /configure """ def on_form_received(form): if not form: self.core.information( - _('Could not retrieve the configuration form'), - _('Error')) + 'Could not retrieve the configuration form', + 'Error') return self.core.open_new_form(form, self.cancel_config, self.send_config) - form = fixes.get_room_form(self.core.xmpp, self.name, on_form_received) + fixes.get_room_form(self.core.xmpp, self.name, on_form_received) def cancel_config(self, form): """ @@ -388,30 +408,53 @@ class MucTab(ChatTab): muc.configure_room(self.core.xmpp, self.name, form) self.core.close_tab() - def command_cycle(self, arg): + @command_args_parser.raw + def command_cycle(self, msg): """/cycle [reason]""" - self.command_part(arg) + self.command_part(msg) self.disconnect() self.user_win.pos = 0 self.core.disable_private_tabs(self.name) self.core.command_join('"/%s"' % self.own_nick) - def command_recolor(self, arg): + @command_args_parser.quoted(0, 1, ['']) + def command_recolor(self, args): """ /recolor [random] Re-assign color to the participants of the room """ - arg = arg.strip() + deterministic = config.get_by_tabname('deterministic_nick_colors', self.name) + if deterministic: + for user in self.users: + if user.nick == self.own_nick: + continue + color = self.search_for_color(user.nick) + if color != '': + continue + user.set_deterministic_color() + if args[0] == 'random': + self.core.information('"random" was provided, but poezio is ' + 'configured to use deterministic colors', + 'Warning') + self.user_win.refresh(self.users) + self.input.refresh() + return compare_users = lambda x: x.last_talked users = list(self.users) sorted_users = sorted(users, key=compare_users, reverse=True) + full_sorted_users = sorted_users[:] # search our own user, to remove it from the list - for user in sorted_users: + # Also remove users whose color is fixed + for user in full_sorted_users: + color = self.search_for_color(user.nick) if user.nick == self.own_nick: sorted_users.remove(user) user.color = get_theme().COLOR_OWN_NICK + elif color != '': + sorted_users.remove(user) + user.change_color(color, deterministic) colors = list(get_theme().LIST_COLOR_NICKNAMES) - if arg and arg == 'random': + if args[0] == 'random': random.shuffle(colors) for i, user in enumerate(sorted_users): user.color = colors[i % len(colors)] @@ -420,41 +463,86 @@ class MucTab(ChatTab): self.text_win.refresh() self.input.refresh() - def command_version(self, arg): + @command_args_parser.quoted(2, 2, ['']) + def command_color(self, args): + """ + /color <nick> <color> + Fix a color for a nick. + Use "unset" instead of a color to remove the attribution. + User "random" to attribute a random color. + """ + if args is None: + return self.core.command_help('color') + nick = args[0] + color = args[1].lower() + user = self.get_user_by_name(nick) + if not color in xhtml.colors and color not in ('unset', 'random'): + return self.core.information("Unknown color: %s" % color, 'Error') + if user and user.nick == self.own_nick: + return self.core.information("You cannot change the color of your" + " own nick.", 'Error') + if color == 'unset': + if config.remove_and_save(nick, 'muc_colors'): + self.core.information('Color for nick %s unset' % (nick)) + else: + if color == 'random': + color = random.choice(list(xhtml.colors)) + if user: + user.change_color(color) + config.set_and_save(nick, color, 'muc_colors') + nick_color_aliases = config.get_by_tabname('nick_color_aliases', self.name) + if nick_color_aliases: + # if any user in the room has a nick which is an alias of the + # nick, update its color + for tab in self.core.get_tabs(MucTab): + for u in tab.users: + nick_alias = re.sub('^_*', '', u.nick) + nick_alias = re.sub('_*$', '', nick_alias) + if nick_alias == nick: + u.change_color(color) + self.text_win.rebuild_everything(self._text_buffer) + self.user_win.refresh(self.users) + self.text_win.refresh() + self.input.refresh() + + @command_args_parser.quoted(1) + def command_version(self, args): """ /version <jid or nick> """ def callback(res): if not res: - return self.core.information(_('Could not get the software ' - 'version from %s') % (jid,), - _('Warning')) - version = _('%s is running %s version %s on %s') % ( + return self.core.information('Could not get the software ' + 'version from %s' % (jid,), + 'Warning') + version = '%s is running %s version %s on %s' % ( jid, - res.get('name') or _('an unknown software'), - res.get('version') or _('unknown'), - res.get('os') or _('an unknown platform')) + res.get('name') or 'an unknown software', + res.get('version') or 'unknown', + res.get('os') or 'an unknown platform') self.core.information(version, 'Info') - if not arg: + if args is None: return self.core.command_help('version') - if arg in [user.nick for user in self.users]: + nick = args[0] + if nick in [user.nick for user in self.users]: jid = safeJID(self.name).bare - jid = safeJID(jid + '/' + arg) + jid = safeJID(jid + '/' + nick) else: - jid = safeJID(arg) + jid = safeJID(nick) fixes.get_version(self.core.xmpp, jid, - callback=callback) + callback=callback) - def command_nick(self, arg): + @command_args_parser.quoted(1) + def command_nick(self, args): """ /nick <nickname> """ - if not arg: + if args is None: return self.core.command_help('nick') - nick = arg + nick = args[0] if not self.joined: - return self.core.information(_('/nick only works in joined rooms'), - _('Info')) + return self.core.information('/nick only works in joined rooms', + 'Info') current_status = self.core.get_status() if not safeJID(self.name + '/' + nick): return self.core.information('Invalid nick', 'Info') @@ -462,11 +550,12 @@ class MucTab(ChatTab): current_status.message, current_status.show) - def command_part(self, arg): + @command_args_parser.quoted(0, 1, ['']) + def command_part(self, args): """ /part [msg] """ - arg = arg.strip() + arg = args[0] msg = None if self.joined: info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT) @@ -480,24 +569,24 @@ class MucTab(ChatTab): color = 3 if arg: - msg = _('\x19%(color_spec)s}%(spec)s\x19%(info_col)s} ' - 'You (\x19%(color)s}%(nick)s\x19%(info_col)s})' - ' left the chatroom' - ' (\x19o%(reason)s\x19%(info_col)s})') % { - 'info_col': info_col, 'reason': arg, - 'spec': char_quit, 'color': color, - 'color_spec': spec_col, - 'nick': self.own_nick, - } + msg = ('\x19%(color_spec)s}%(spec)s\x19%(info_col)s} ' + 'You (\x19%(color)s}%(nick)s\x19%(info_col)s})' + ' left the chatroom' + ' (\x19o%(reason)s\x19%(info_col)s})') % { + 'info_col': info_col, 'reason': arg, + 'spec': char_quit, 'color': color, + 'color_spec': spec_col, + 'nick': self.own_nick, + } else: - msg = _('\x19%(color_spec)s}%(spec)s\x19%(info_col)s} ' - 'You (\x19%(color)s}%(nick)s\x19%(info_col)s})' - ' left the chatroom') % { - 'info_col': info_col, - 'spec': char_quit, 'color': color, - 'color_spec': spec_col, - 'nick': self.own_nick, - } + msg = ('\x19%(color_spec)s}%(spec)s\x19%(info_col)s} ' + 'You (\x19%(color)s}%(nick)s\x19%(info_col)s})' + ' left the chatroom') % { + 'info_col': info_col, + 'spec': char_quit, 'color': color, + 'color_spec': spec_col, + 'nick': self.own_nick, + } self.add_message(msg, typ=2) self.disconnect() @@ -507,49 +596,52 @@ class MucTab(ChatTab): self.refresh() self.core.doupdate() - def command_close(self, arg): + @command_args_parser.raw + def command_close(self, msg): """ /close [msg] """ - self.command_part(arg) + self.command_part(msg) self.core.close_tab() - def command_query(self, arg): + @command_args_parser.quoted(1, 1) + def command_query(self, args): """ /query <nick> [message] """ - args = common.shell_split(arg) - if len(args) < 1: - return + if args is None: + return self.core.command_help('query') nick = args[0] r = None for user in self.users: if user.nick == nick: r = self.core.open_private_window(self.name, user.nick) - if r and len(args) > 1: + if r and len(args) == 2: msg = args[1] self.core.current_tab().command_say( xhtml.convert_simple_to_full_colors(msg)) if not r: - self.core.information(_("Cannot find user: %s" % nick), 'Error') + self.core.information("Cannot find user: %s" % nick, 'Error') - def command_topic(self, arg): + @command_args_parser.raw + def command_topic(self, subject): """ /topic [new topic] """ - if not arg.strip(): + if not subject: self._text_buffer.add_message( - _("\x19%s}The subject of the room is: %s %s") % + "\x19%s}The subject of the room is: %s %s" % (dump_tuple(get_theme().COLOR_INFORMATION_TEXT), self.topic, '(set by %s)' % self.topic_from if self.topic_from else '')) self.refresh() return - subject = arg + muc.change_subject(self.core.xmpp, self.name, subject) - def command_names(self, arg=None): + @command_args_parser.quoted(0) + def command_names(self, args): """ /names """ @@ -620,29 +712,28 @@ class MucTab(ChatTab): return the_input.new_completion(word_list, 1, quotify=True) - def command_kick(self, arg): + @command_args_parser.quoted(1, 1) + def command_kick(self, args): """ /kick <nick> [reason] """ - args = common.shell_split(arg) - if not args: - self.core.command_help('kick') + if args is None: + return self.core.command_help('kick') + if len(args) == 2: + msg = ' "%s"' % args[1] else: - if len(args) > 1: - msg = ' "%s"' % args[1] - else: - msg = '' - self.command_role('"'+args[0]+ '" none'+msg) + msg = '' + self.command_role('"'+args[0]+ '" none'+msg) - def command_ban(self, arg): + @command_args_parser.quoted(1, 1) + def command_ban(self, args): """ /ban <nick> [reason] """ def callback(iq): if iq['type'] == 'error': self.core.room_error(iq, self.name) - args = common.shell_split(arg) - if not args: + if args is None: return self.core.command_help('ban') if len(args) > 1: msg = args[1] @@ -661,7 +752,8 @@ class MucTab(ChatTab): if not res: self.core.information('Could not ban user', 'Error') - def command_role(self, arg): + @command_args_parser.quoted(2, 1, ['']) + def command_role(self, args): """ /role <nick> <role> [reason] Changes the role of an user @@ -670,24 +762,25 @@ class MucTab(ChatTab): def callback(iq): if iq['type'] == 'error': self.core.room_error(iq, self.name) - 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.joined or \ - not role in ('none', 'visitor', 'participant', 'moderator'): - return + + if args is None: + return self.core.command_help('role') + + nick, role, reason = args[0], args[1].lower(), args[2] + + valid_roles = ('none', 'visitor', 'participant', 'moderator') + + if not self.joined or role not in valid_roles: + return self.core.information('The role must be one of ' + ', '.join(valid_roles), + 'Error') + if not safeJID(self.name + '/' + nick): - return self.core('Invalid nick', 'Info') + return self.core.information('Invalid nick', 'Info') muc.set_user_role(self.core.xmpp, self.name, nick, reason, role, callback=callback) - def command_affiliation(self, arg): + @command_args_parser.quoted(2) + def command_affiliation(self, args): """ /affiliation <nick> <role> Changes the affiliation of an user @@ -696,16 +789,20 @@ class MucTab(ChatTab): def callback(iq): if iq['type'] == 'error': self.core.room_error(iq, self.name) - args = common.shell_split(arg) - if len(args) < 2: - self.core.command_help('affiliation') - return + + if args is None: + return self.core.command_help('affiliation') + nick, affiliation = args[0], args[1].lower() + if not self.joined: return - if affiliation not in ('outcast', 'none', 'member', 'admin', 'owner'): - self.core.command_help('affiliation') - return + + valid_affiliations = ('outcast', 'none', 'member', 'admin', 'owner') + if affiliation not in valid_affiliations: + return self.core.information('The affiliation must be one of ' + ', '.join(valid_affiliations), + 'Error') + if nick in [user.nick for user in self.users]: res = muc.set_user_affiliation(self.core.xmpp, self.name, affiliation, nick=nick, @@ -715,8 +812,9 @@ class MucTab(ChatTab): affiliation, jid=safeJID(nick), callback=callback) if not res: - self.core.information(_('Could not set affiliation'), _('Error')) + self.core.information('Could not set affiliation', 'Error') + @command_args_parser.raw def command_say(self, line, correct=False): """ /say <message> @@ -755,45 +853,48 @@ class MucTab(ChatTab): msg.send() self.chat_state = needed - def command_xhtml(self, arg): - message = self.generate_xhtml_message(arg) + @command_args_parser.raw + def command_xhtml(self, msg): + message = self.generate_xhtml_message(msg) if message: message['type'] = 'groupchat' message.send() - def command_ignore(self, arg): + @command_args_parser.quoted(1) + def command_ignore(self, args): """ /ignore <nick> """ - if not arg: - self.core.command_help('ignore') - return - nick = arg + if args is None: + return self.core.command_help('ignore') + + nick = args[0] user = self.get_user_by_name(nick) if not user: - self.core.information(_('%s is not in the room') % nick) + self.core.information('%s is not in the room' % nick) elif user in self.ignores: - self.core.information(_('%s is already ignored') % nick) + self.core.information('%s is already ignored' % nick) else: self.ignores.append(user) - self.core.information(_("%s is now ignored") % nick, 'info') + self.core.information("%s is now ignored" % nick, 'info') - def command_unignore(self, arg): + @command_args_parser.quoted(1) + def command_unignore(self, args): """ /unignore <nick> """ - if not arg: - self.core.command_help('unignore') - return - nick = arg + if args is None: + return self.core.command_help('unignore') + + nick = args[0] user = self.get_user_by_name(nick) if not user: - self.core.information(_('%s is not in the room') % nick) + self.core.information('%s is not in the room' % nick) elif user not in self.ignores: - self.core.information(_('%s is not ignored') % nick) + self.core.information('%s is not ignored' % nick) else: self.ignores.remove(user) - self.core.information(_('%s is now unignored') % nick) + self.core.information('%s is now unignored' % nick) def completion_unignore(self, the_input): if the_input.get_argument_position() == 1: @@ -980,12 +1081,14 @@ class MucTab(ChatTab): role = presence['muc']['role'] jid = presence['muc']['jid'] typ = presence['type'] + deterministic = config.get_by_tabname('deterministic_nick_colors', self.name) + color = self.search_for_color(from_nick) if not self.joined: # user in the room BEFORE us. # ignore redondant presence message, see bug #1509 if (from_nick not in [user.nick for user in self.users] and typ != "unavailable"): new_user = User(from_nick, affiliation, show, - status, role, jid) + status, role, jid, deterministic, color) self.users.append(new_user) self.core.events.trigger('muc_join', presence, self) if '110' in status_codes or self.own_nick == from_nick: @@ -1015,9 +1118,9 @@ class MucTab(ChatTab): spec_col = dump_tuple(get_theme().COLOR_JOIN_CHAR) self.add_message( - _('\x19%(color_spec)s}%(spec)s\x19%(info_col)s} You ' - '(\x19%(nick_col)s}%(nick)s\x19%(info_col)s}) joined' - ' the chatroom') % + '\x19%(color_spec)s}%(spec)s\x19%(info_col)s} You ' + '(\x19%(nick_col)s}%(nick)s\x19%(info_col)s}) joined' + ' the chatroom' % { 'nick': from_nick, 'spec': get_theme().CHAR_JOIN, @@ -1028,21 +1131,21 @@ class MucTab(ChatTab): typ=2) if '201' in status_codes: self.add_message( - _('\x19%(info_col)s}Info: The room ' - 'has been created') % + '\x19%(info_col)s}Info: The room ' + 'has been created' % {'info_col': info_col}, typ=0) if '170' in status_codes: self.add_message( - _('\x19%(warn_col)s}Warning:\x19%(info_col)s}' - ' This room is publicly logged') % + '\x19%(warn_col)s}Warning:\x19%(info_col)s}' + ' This room is publicly logged' % {'info_col': info_col, 'warn_col': warn_col}, typ=0) if '100' in status_codes: self.add_message( - _('\x19%(warn_col)s}Warning:\x19%(info_col)s}' - ' This room is not anonymous.') % + '\x19%(warn_col)s}Warning:\x19%(info_col)s}' + ' This room is not anonymous.' % {'info_col': info_col, 'warn_col': warn_col}, typ=0) @@ -1065,7 +1168,7 @@ class MucTab(ChatTab): if not user: self.core.events.trigger('muc_join', presence, self) self.on_user_join(from_nick, affiliation, show, status, role, - jid) + jid, color) # nick change elif change_nick: self.core.events.trigger('muc_nickchange', presence, self) @@ -1105,8 +1208,8 @@ class MucTab(ChatTab): def on_non_member_kicked(self): """We have been kicked because the MUC is members-only""" self.add_message( - _('\x19%(info_col)s}You have been kicked because you ' - 'are not a member and the room is now members-only.') % { + '\x19%(info_col)s}You have been kicked because you ' + 'are not a member and the room is now members-only.' % { 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)}, typ=2) self.disconnect() @@ -1114,18 +1217,19 @@ class MucTab(ChatTab): def on_muc_shutdown(self): """We have been kicked because the MUC service is shutting down""" self.add_message( - _('\x19%(info_col)s}You have been kicked because the' - ' MUC service is shutting down.') % { + '\x19%(info_col)s}You have been kicked because the' + ' MUC service is shutting down.' % { 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)}, typ=2) self.disconnect() - def on_user_join(self, from_nick, affiliation, show, status, role, jid): + def on_user_join(self, from_nick, affiliation, show, status, role, jid, color): """ When a new user joins the groupchat """ + deterministic = config.get_by_tabname('deterministic_nick_colors', self.name) user = User(from_nick, affiliation, - show, status, role, jid) + show, status, role, jid, deterministic, color) self.users.append(user) hide_exit_join = config.get_by_tabname('hide_exit_join', self.general_jid) @@ -1139,17 +1243,17 @@ class MucTab(ChatTab): spec_col = dump_tuple(get_theme().COLOR_JOIN_CHAR) char_join = get_theme().CHAR_JOIN if not jid.full: - msg = _('\x19%(color_spec)s}%(spec)s \x19%(color)s}%(nick)s' - '\x19%(info_col)s} joined the chatroom') % { + msg = ('\x19%(color_spec)s}%(spec)s \x19%(color)s}%(nick)s' + '\x19%(info_col)s} joined the chatroom') % { 'nick': from_nick, 'spec': char_join, 'color': color, 'info_col': info_col, 'color_spec': spec_col, } else: - msg = _('\x19%(color_spec)s}%(spec)s \x19%(color)s}%(nick)s ' - '\x19%(info_col)s}(\x19%(jid_color)s}%(jid)s\x19' - '%(info_col)s}) joined the chatroom') % { + msg = ('\x19%(color_spec)s}%(spec)s \x19%(color)s}%(nick)s ' + '\x19%(info_col)s}(\x19%(jid_color)s}%(jid)s\x19' + '%(info_col)s}) joined the chatroom') % { 'spec': char_join, 'nick': from_nick, 'color':color, 'jid':jid.full, 'info_col': info_col, @@ -1166,6 +1270,12 @@ class MucTab(ChatTab): self.own_nick = new_nick # also change our nick in all private discussions of this room self.core.on_muc_own_nickchange(self) + else: + color = config.get_by_tabname(new_nick, 'muc_colors') + if color != '': + deterministic = config.get_by_tabname('deterministic_nick_colors', + self.name) + user.change_color(color, deterministic) user.change_nick(new_nick) if config.get_by_tabname('display_user_color_in_join_part', @@ -1174,8 +1284,8 @@ class MucTab(ChatTab): else: color = 3 info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT) - self.add_message(_('\x19%(color)s}%(old)s\x19%(info_col)s} is' - ' now known as \x19%(color)s}%(new)s') % { + self.add_message('\x19%(color)s}%(old)s\x19%(info_col)s} is' + ' now known as \x19%(color)s}%(new)s' % { 'old':from_nick, 'new':new_nick, 'color':color, 'info_col': info_col}, typ=2) @@ -1198,13 +1308,13 @@ class MucTab(ChatTab): if from_nick == self.own_nick: # we are banned if by: - kick_msg = _('\x191}%(spec)s \x193}You\x19%(info_col)s}' - ' have been banned by \x194}%(by)s') % { + kick_msg = ('\x191}%(spec)s \x193}You\x19%(info_col)s}' + ' have been banned by \x194}%(by)s') % { 'spec': char_kick, 'by': by, 'info_col': info_col} else: - kick_msg = _('\x191}%(spec)s \x193}You\x19' - '%(info_col)s} have been banned.') % { + kick_msg = ('\x191}%(spec)s \x193}You\x19' + '%(info_col)s} have been banned.') % { 'spec': char_kick, 'info_col': info_col} self.core.disable_private_tabs(self.name, reason=kick_msg) self.disconnect() @@ -1233,20 +1343,20 @@ class MucTab(ChatTab): color = 3 if by: - kick_msg = _('\x191}%(spec)s \x19%(color)s}' - '%(nick)s\x19%(info_col)s} ' - 'has been banned by \x194}%(by)s') % { + kick_msg = ('\x191}%(spec)s \x19%(color)s}' + '%(nick)s\x19%(info_col)s} ' + 'has been banned by \x194}%(by)s') % { 'spec': char_kick, 'nick': from_nick, 'color': color, 'by': by, 'info_col': info_col} else: - kick_msg = _('\x191}%(spec)s \x19%(color)s}%(nick)s' - '\x19%(info_col)s} has been banned') % { + kick_msg = ('\x191}%(spec)s \x19%(color)s}%(nick)s' + '\x19%(info_col)s} has been banned') % { 'spec': char_kick, 'nick': from_nick, 'color': color, 'info_col': info_col} if reason is not None and reason.text: - kick_msg += _('\x19%(info_col)s} Reason: \x196}' - '%(reason)s\x19%(info_col)s}') % { + kick_msg += ('\x19%(info_col)s} Reason: \x196}' + '%(reason)s\x19%(info_col)s}') % { 'reason': reason.text, 'info_col': info_col} self.add_message(kick_msg, typ=2) @@ -1266,14 +1376,14 @@ class MucTab(ChatTab): by = actor_elem.get('nick') or actor_elem.get('jid') if from_nick == self.own_nick: # we are kicked if by: - kick_msg = _('\x191}%(spec)s \x193}You\x19' - '%(info_col)s} have been kicked' - ' by \x193}%(by)s') % { + kick_msg = ('\x191}%(spec)s \x193}You\x19' + '%(info_col)s} have been kicked' + ' by \x193}%(by)s') % { 'spec': char_kick, 'by': by, 'info_col': info_col} else: - kick_msg = _('\x191}%(spec)s \x193}You\x19%(info_col)s}' - ' have been kicked.') % { + kick_msg = ('\x191}%(spec)s \x193}You\x19%(info_col)s}' + ' have been kicked.') % { 'spec': char_kick, 'info_col': info_col} self.core.disable_private_tabs(self.name, reason=kick_msg) @@ -1302,19 +1412,19 @@ class MucTab(ChatTab): else: color = 3 if by: - kick_msg = _('\x191}%(spec)s \x19%(color)s}%(nick)s' - '\x19%(info_col)s} has been kicked by ' - '\x193}%(by)s') % { + kick_msg = ('\x191}%(spec)s \x19%(color)s}%(nick)s' + '\x19%(info_col)s} has been kicked by ' + '\x193}%(by)s') % { 'spec': char_kick, 'nick':from_nick, 'color':color, 'by':by, 'info_col': info_col} else: - kick_msg = _('\x191}%(spec)s \x19%(color)s}%(nick)s' - '\x19%(info_col)s} has been kicked') % { + kick_msg = ('\x191}%(spec)s \x19%(color)s}%(nick)s' + '\x19%(info_col)s} has been kicked') % { 'spec': char_kick, 'nick': from_nick, 'color':color, 'info_col': info_col} if reason is not None and reason.text: - kick_msg += _('\x19%(info_col)s} Reason: \x196}' - '%(reason)s') % { + kick_msg += ('\x19%(info_col)s} Reason: \x196}' + '%(reason)s') % { 'reason': reason.text, 'info_col': info_col} self.add_message(kick_msg, typ=2) @@ -1343,19 +1453,19 @@ class MucTab(ChatTab): spec_col = dump_tuple(get_theme().COLOR_QUIT_CHAR) if not jid.full: - leave_msg = _('\x19%(color_spec)s}%(spec)s \x19%(color)s}' - '%(nick)s\x19%(info_col)s} has left the ' - 'chatroom') % { + leave_msg = ('\x19%(color_spec)s}%(spec)s \x19%(color)s}' + '%(nick)s\x19%(info_col)s} has left the ' + 'chatroom') % { 'nick':from_nick, 'color':color, 'spec':get_theme().CHAR_QUIT, 'info_col': info_col, 'color_spec': spec_col} else: jid_col = dump_tuple(get_theme().COLOR_MUC_JID) - leave_msg = _('\x19%(color_spec)s}%(spec)s \x19%(color)s}' - '%(nick)s\x19%(info_col)s} (\x19%(jid_col)s}' - '%(jid)s\x19%(info_col)s}) has left the ' - 'chatroom') % { + leave_msg = ('\x19%(color_spec)s}%(spec)s \x19%(color)s}' + '%(nick)s\x19%(info_col)s} (\x19%(jid_col)s}' + '%(jid)s\x19%(info_col)s}) has left the ' + 'chatroom') % { 'spec':get_theme().CHAR_QUIT, 'nick':from_nick, 'color':color, 'jid':jid.full, 'info_col': info_col, @@ -1381,33 +1491,29 @@ class MucTab(ChatTab): else: color = 3 if from_nick == self.own_nick: - msg = _('\x19%(color)s}You\x19%(info_col)s} changed: ') % { - 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT), - 'color': color} + msg = '\x19%(color)s}You\x19%(info_col)s} changed: ' % { + 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT), + 'color': color} else: - msg = _('\x19%(color)s}%(nick)s\x19%(info_col)s} changed: ') % { - 'nick': from_nick, 'color': color, - 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)} - if show not in SHOW_NAME: - self.core.information(_("%s from room %s sent an invalid show: %s") - % (from_nick, from_room, show), - _("Warning")) + msg = '\x19%(color)s}%(nick)s\x19%(info_col)s} changed: ' % { + 'nick': from_nick, 'color': color, + 'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)} if affiliation != user.affiliation: - msg += _('affiliation: %s, ') % affiliation + msg += 'affiliation: %s, ' % affiliation display_message = True if role != user.role: - msg += _('role: %s, ') % role + msg += 'role: %s, ' % role display_message = True if show != user.show and show in SHOW_NAME: - msg += _('show: %s, ') % SHOW_NAME[show] + msg += 'show: %s, ' % SHOW_NAME[show] display_message = True if status != user.status: # if the user sets his status to nothing if status: - msg += _('status: %s, ') % status + msg += 'status: %s, ' % status display_message = True elif show in SHOW_NAME and show == user.show: - msg += _('show: %s, ') % SHOW_NAME[show] + msg += 'show: %s, ' % SHOW_NAME[show] display_message = True if not display_message: return @@ -1461,8 +1567,8 @@ class MucTab(ChatTab): """ if time is None and self.joined: # don't log the history messages if not logger.log_message(self.name, nickname, txt, typ=typ): - self.core.information(_('Unable to write in the log file'), - _('Error')) + self.core.information('Unable to write in the log file', + 'Error') def do_highlight(self, txt, time, nickname): """ @@ -1581,6 +1687,22 @@ class MucTab(ChatTab): else: # Re-send a self-ping in a few seconds self.enable_self_ping_event() + def search_for_color(self, nick): + """ + Search for the color of a nick in the config file. + Also, look at the colors of its possible aliases if nick_color_aliases + is set. + """ + color = config.get_by_tabname(nick, 'muc_colors') + if color != '': + return color + nick_color_aliases = config.get_by_tabname('nick_color_aliases', self.name) + if nick_color_aliases: + nick_alias = re.sub('^_*', '', nick) + nick_alias = re.sub('_*$', '', nick_alias) + color = config.get_by_tabname(nick_alias, 'muc_colors') + return color + def on_self_ping_failed(self, iq): self.command_part("the MUC server is not responding") self.core.refresh_window() |