summaryrefslogtreecommitdiff
path: root/src/tabs/muctab.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/tabs/muctab.py')
-rw-r--r--src/tabs/muctab.py674
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()