2014-03-22 23:15:01 +00:00
|
|
|
|
"""
|
|
|
|
|
Module for the MucTab
|
|
|
|
|
|
|
|
|
|
A MucTab is a tab for multi-user chats as defined in XEP-0045.
|
|
|
|
|
|
|
|
|
|
It keeps track of many things such as part/joins, maintains an
|
|
|
|
|
user list, and updates private tabs when necessary.
|
|
|
|
|
"""
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
from gettext import gettext as _
|
|
|
|
|
|
|
|
|
|
import logging
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
import curses
|
|
|
|
|
import os
|
|
|
|
|
import random
|
2014-04-11 22:34:25 +00:00
|
|
|
|
import re
|
2014-04-03 22:24:16 +00:00
|
|
|
|
from datetime import datetime
|
2014-04-10 23:25:00 +00:00
|
|
|
|
from functools import reduce
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
from . import ChatTab, Tab
|
|
|
|
|
|
|
|
|
|
import common
|
|
|
|
|
import fixes
|
|
|
|
|
import multiuserchat as muc
|
|
|
|
|
import timed_events
|
|
|
|
|
import windows
|
|
|
|
|
import xhtml
|
|
|
|
|
from common import safeJID
|
|
|
|
|
from config import config
|
|
|
|
|
from decorators import refresh_wrapper
|
|
|
|
|
from logger import logger
|
|
|
|
|
from roster import roster
|
|
|
|
|
from theming import get_theme, dump_tuple
|
|
|
|
|
from user import User
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SHOW_NAME = {
|
|
|
|
|
'dnd': _('busy'),
|
|
|
|
|
'away': _('away'),
|
|
|
|
|
'xa': _('not available'),
|
|
|
|
|
'chat': _('chatty'),
|
|
|
|
|
'': _('available')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NS_MUC_USER = 'http://jabber.org/protocol/muc#user'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MucTab(ChatTab):
|
|
|
|
|
"""
|
|
|
|
|
The tab containing a multi-user-chat room.
|
|
|
|
|
It contains an userlist, an input, a topic, an information and a chat zone
|
|
|
|
|
"""
|
|
|
|
|
message_type = 'groupchat'
|
|
|
|
|
plugin_commands = {}
|
|
|
|
|
plugin_keys = {}
|
|
|
|
|
def __init__(self, jid, nick):
|
|
|
|
|
self.joined = False
|
|
|
|
|
ChatTab.__init__(self, jid)
|
|
|
|
|
if self.joined == False:
|
|
|
|
|
self._state = 'disconnected'
|
|
|
|
|
self.own_nick = nick
|
|
|
|
|
self.name = jid
|
|
|
|
|
self.users = []
|
|
|
|
|
self.privates = [] # private conversations
|
|
|
|
|
self.topic = ''
|
|
|
|
|
self.remote_wants_chatstates = True
|
|
|
|
|
# We send active, composing and paused states to the MUC because
|
|
|
|
|
# the chatstate may or may not be filtered by the MUC,
|
|
|
|
|
# that’s not our problem.
|
|
|
|
|
self.topic_win = windows.Topic()
|
|
|
|
|
self.text_win = windows.TextWin()
|
|
|
|
|
self._text_buffer.add_window(self.text_win)
|
|
|
|
|
self.v_separator = windows.VerticalSeparator()
|
|
|
|
|
self.user_win = windows.UserList()
|
|
|
|
|
self.info_header = windows.MucInfoWin()
|
|
|
|
|
self.input = windows.MessageInput()
|
|
|
|
|
self.ignores = [] # set of Users
|
|
|
|
|
# keys
|
|
|
|
|
self.key_func['^I'] = self.completion
|
|
|
|
|
self.key_func['M-u'] = self.scroll_user_list_down
|
|
|
|
|
self.key_func['M-y'] = self.scroll_user_list_up
|
|
|
|
|
self.key_func['M-n'] = self.go_to_next_hl
|
|
|
|
|
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'),
|
|
|
|
|
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.'),
|
|
|
|
|
completion=self.completion_unignore)
|
|
|
|
|
self.register_command('kick', self.command_kick,
|
|
|
|
|
usage=_('<nick> [reason]'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Kick the user with the specified nickname.'
|
|
|
|
|
' You also can give an optional reason.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
shortdesc=_('Kick someone.'),
|
|
|
|
|
completion=self.completion_quoted)
|
|
|
|
|
self.register_command('ban', self.command_ban,
|
|
|
|
|
usage=_('<nick> [reason]'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Ban the user with the specified nickname.'
|
|
|
|
|
' You also can give an optional reason.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
shortdesc='Ban someone',
|
|
|
|
|
completion=self.completion_quoted)
|
|
|
|
|
self.register_command('role', self.command_role,
|
|
|
|
|
usage=_('<nick> <role> [reason]'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Set the role of an user. Roles can be:'
|
|
|
|
|
' none, visitor, participant, moderator.'
|
|
|
|
|
' You also can give an optional reason.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
shortdesc=_('Set the role of an user.'),
|
|
|
|
|
completion=self.completion_role)
|
|
|
|
|
self.register_command('affiliation', self.command_affiliation,
|
|
|
|
|
usage=_('<nick or jid> <affiliation>'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Set the affiliation of an user. Affiliations can be:'
|
|
|
|
|
' outcast, none, member, admin, owner.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
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.'),
|
|
|
|
|
completion=self.completion_topic)
|
|
|
|
|
self.register_command('query', self.command_query,
|
|
|
|
|
usage=_('<nick> [message]'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
shortdesc=_('Query an user.'),
|
|
|
|
|
completion=self.completion_quoted)
|
|
|
|
|
self.register_command('part', self.command_part,
|
|
|
|
|
usage=_('[message]'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Disconnect from a room. You can'
|
|
|
|
|
' specify an optional message.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
shortdesc=_('Leave the room.'))
|
|
|
|
|
self.register_command('close', self.command_close,
|
|
|
|
|
usage=_('[message]'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Disconnect from a room and close the tab.'
|
|
|
|
|
' You can specify an optional message if '
|
|
|
|
|
'you are still connected.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
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.'),
|
|
|
|
|
completion=self.completion_nick)
|
|
|
|
|
self.register_command('recolor', self.command_recolor,
|
2014-04-26 12:41:19 +00:00
|
|
|
|
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.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
shortdesc=_('Change the nicks colors.'),
|
|
|
|
|
completion=self.completion_recolor)
|
|
|
|
|
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.'))
|
|
|
|
|
self.register_command('info', self.command_info,
|
|
|
|
|
usage=_('<nickname>'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Display some information about the user '
|
|
|
|
|
'in the MUC: its/his/her role, affiliation,'
|
|
|
|
|
' status and status message.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
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.'))
|
|
|
|
|
self.register_command('version', self.command_version,
|
|
|
|
|
usage=_('<jid or nick>'),
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Get the software version of the given JID'
|
|
|
|
|
' or nick in room (usually its XMPP client'
|
|
|
|
|
' and Operating System).'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
shortdesc=_('Get the software version of a jid.'),
|
|
|
|
|
completion=self.completion_version)
|
|
|
|
|
self.register_command('names', self.command_names,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
desc=_('Get the users in the room with their roles.'),
|
2014-03-19 01:22:25 +00:00
|
|
|
|
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'),
|
|
|
|
|
completion=self.completion_invite)
|
|
|
|
|
|
|
|
|
|
if self.core.xmpp.boundjid.server == "gmail.com": #gmail sucks
|
|
|
|
|
del self.commands["nick"]
|
|
|
|
|
|
|
|
|
|
self.resize()
|
|
|
|
|
self.update_commands()
|
|
|
|
|
self.update_keys()
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def general_jid(self):
|
2014-04-30 19:34:09 +00:00
|
|
|
|
return self.name
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def is_muc(self):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def last_connection(self):
|
|
|
|
|
last_message = self._text_buffer.last_message
|
|
|
|
|
if last_message:
|
|
|
|
|
return last_message.time
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
@refresh_wrapper.always
|
|
|
|
|
def go_to_next_hl(self):
|
|
|
|
|
"""
|
|
|
|
|
Go to the next HL in the room, or the last
|
|
|
|
|
"""
|
|
|
|
|
self.text_win.next_highlight()
|
|
|
|
|
|
|
|
|
|
@refresh_wrapper.always
|
|
|
|
|
def go_to_prev_hl(self):
|
|
|
|
|
"""
|
|
|
|
|
Go to the previous HL in the room, or the first
|
|
|
|
|
"""
|
|
|
|
|
self.text_win.previous_highlight()
|
|
|
|
|
|
|
|
|
|
def completion_version(self, the_input):
|
|
|
|
|
"""Completion for /version"""
|
|
|
|
|
compare_users = lambda x: x.last_talked
|
2014-04-26 21:49:52 +00:00
|
|
|
|
userlist = []
|
|
|
|
|
for user in sorted(self.users, key=compare_users, reverse=True):
|
|
|
|
|
if user.nick != self.own_nick:
|
|
|
|
|
userlist.append(user.nick)
|
|
|
|
|
comp = []
|
|
|
|
|
for jid in (jid for jid in roster.jids() if len(roster[jid])):
|
|
|
|
|
for resource in roster[jid].resources:
|
|
|
|
|
comp.append(resource.jid)
|
|
|
|
|
comp.sort()
|
2014-04-10 23:25:00 +00:00
|
|
|
|
userlist.extend(comp)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
|
|
|
|
|
return the_input.auto_completion(userlist, quotify=False)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def completion_info(self, the_input):
|
|
|
|
|
"""Completion for /info"""
|
|
|
|
|
compare_users = lambda x: x.last_talked
|
2014-04-26 21:49:52 +00:00
|
|
|
|
userlist = []
|
|
|
|
|
for user in sorted(self.users, key=compare_users, reverse=True):
|
|
|
|
|
userlist.append(user.nick)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
return the_input.auto_completion(userlist, quotify=False)
|
|
|
|
|
|
|
|
|
|
def completion_nick(self, the_input):
|
|
|
|
|
"""Completion for /nick"""
|
2014-04-26 21:49:52 +00:00
|
|
|
|
nicks = [os.environ.get('USER'),
|
|
|
|
|
config.get('default_nick', ''),
|
2014-04-30 19:34:09 +00:00
|
|
|
|
self.core.get_bookmark_nickname(self.name)]
|
2014-03-19 01:22:25 +00:00
|
|
|
|
nicks = [i for i in nicks if i]
|
|
|
|
|
return the_input.auto_completion(nicks, '', quotify=False)
|
|
|
|
|
|
|
|
|
|
def completion_recolor(self, the_input):
|
|
|
|
|
if the_input.get_argument_position() == 1:
|
|
|
|
|
return the_input.new_completion(['random'], 1, '', quotify=False)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def completion_ignore(self, the_input):
|
|
|
|
|
"""Completion for /ignore"""
|
|
|
|
|
userlist = [user.nick for user in self.users]
|
|
|
|
|
if self.own_nick in userlist:
|
|
|
|
|
userlist.remove(self.own_nick)
|
|
|
|
|
userlist.sort()
|
|
|
|
|
return the_input.auto_completion(userlist, quotify=False)
|
|
|
|
|
|
|
|
|
|
def completion_role(self, the_input):
|
|
|
|
|
"""Completion for /role"""
|
|
|
|
|
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:
|
|
|
|
|
possible_roles = ['none', 'visitor', 'participant', 'moderator']
|
2014-04-26 21:49:52 +00:00
|
|
|
|
return the_input.new_completion(possible_roles, 2, '',
|
|
|
|
|
quotify=True)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def completion_affiliation(self, the_input):
|
|
|
|
|
"""Completion for /affiliation"""
|
|
|
|
|
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)
|
|
|
|
|
jidlist = [user.jid.bare for user in self.users]
|
|
|
|
|
if self.core.xmpp.boundjid.bare in jidlist:
|
|
|
|
|
jidlist.remove(self.core.xmpp.boundjid.bare)
|
|
|
|
|
userlist.extend(jidlist)
|
|
|
|
|
return the_input.new_completion(userlist, 1, '', quotify=True)
|
|
|
|
|
elif n == 2:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
possible_affiliations = ['none', 'member', 'admin',
|
|
|
|
|
'owner', 'outcast']
|
|
|
|
|
return the_input.new_completion(possible_affiliations, 2, '',
|
|
|
|
|
quotify=True)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
return self.core.command_help('invite')
|
|
|
|
|
self.core.command_invite('%s %s "%s"' % (jid, self.name, reason))
|
|
|
|
|
|
|
|
|
|
def completion_invite(self, the_input):
|
|
|
|
|
"""Completion for /invite"""
|
|
|
|
|
n = the_input.get_argument_position(quoted=True)
|
|
|
|
|
if n == 1:
|
|
|
|
|
return the_input.new_completion(roster.jids(), 1, quotify=True)
|
|
|
|
|
|
|
|
|
|
def scroll_user_list_up(self):
|
|
|
|
|
self.user_win.scroll_up()
|
|
|
|
|
self.user_win.refresh(self.users)
|
|
|
|
|
self.input.refresh()
|
|
|
|
|
|
|
|
|
|
def scroll_user_list_down(self):
|
|
|
|
|
self.user_win.scroll_down()
|
|
|
|
|
self.user_win.refresh(self.users)
|
|
|
|
|
self.input.refresh()
|
|
|
|
|
|
|
|
|
|
def command_info(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/info <nick>
|
|
|
|
|
"""
|
|
|
|
|
if not arg:
|
|
|
|
|
return self.core.command_help('info')
|
|
|
|
|
user = self.get_user_by_name(arg)
|
|
|
|
|
if not user:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
return self.core.information(_("Unknown user: %s") % arg)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
theme = get_theme()
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if user.jid:
|
|
|
|
|
user_jid = ' (\x19%s}%s\x19o)' % (
|
|
|
|
|
dump_tuple(theme.COLOR_MUC_JID),
|
|
|
|
|
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') % (
|
2014-03-19 01:22:25 +00:00
|
|
|
|
dump_tuple(user.color),
|
|
|
|
|
arg,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
user_jid,
|
2014-03-19 01:22:25 +00:00
|
|
|
|
dump_tuple(theme.color_show(user.show)),
|
|
|
|
|
user.show or 'Available',
|
|
|
|
|
dump_tuple(theme.color_role(user.role)),
|
|
|
|
|
user.affiliation or 'None',
|
|
|
|
|
dump_tuple(theme.color_role(user.role)),
|
|
|
|
|
user.role or 'None',
|
|
|
|
|
'\n%s' % user.status if user.status else '')
|
|
|
|
|
self.core.information(info, 'Info')
|
|
|
|
|
|
|
|
|
|
def command_configure(self, arg):
|
2014-04-26 21:49:52 +00:00
|
|
|
|
"""
|
|
|
|
|
/configure
|
|
|
|
|
"""
|
2014-04-30 19:34:09 +00:00
|
|
|
|
form = fixes.get_room_form(self.core.xmpp, self.name)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if not form:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.information(
|
|
|
|
|
_('Could not retrieve the configuration form'),
|
|
|
|
|
_('Error'))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
return
|
|
|
|
|
self.core.open_new_form(form, self.cancel_config, self.send_config)
|
|
|
|
|
|
|
|
|
|
def cancel_config(self, form):
|
|
|
|
|
"""
|
|
|
|
|
The user do not want to send his/her config, send an iq cancel
|
|
|
|
|
"""
|
2014-04-30 19:34:09 +00:00
|
|
|
|
self.core.xmpp.plugin['xep_0045'].cancelConfig(self.name)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.core.close_tab()
|
|
|
|
|
|
|
|
|
|
def send_config(self, form):
|
|
|
|
|
"""
|
|
|
|
|
The user sends his/her config to the server
|
|
|
|
|
"""
|
2014-04-30 19:34:09 +00:00
|
|
|
|
self.core.xmpp.plugin['xep_0045'].configureRoom(self.name, form)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.core.close_tab()
|
|
|
|
|
|
|
|
|
|
def command_cycle(self, arg):
|
|
|
|
|
"""/cycle [reason]"""
|
2014-04-16 22:02:19 +00:00
|
|
|
|
self.command_part(arg)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.disconnect()
|
2014-04-16 22:02:19 +00:00
|
|
|
|
self.user_win.pos = 0
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.core.disable_private_tabs(self.name)
|
|
|
|
|
self.core.command_join('"/%s"' % self.own_nick)
|
|
|
|
|
|
|
|
|
|
def command_recolor(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/recolor [random]
|
|
|
|
|
Re-assign color to the participants of the room
|
|
|
|
|
"""
|
|
|
|
|
arg = arg.strip()
|
|
|
|
|
compare_users = lambda x: x.last_talked
|
|
|
|
|
users = list(self.users)
|
|
|
|
|
sorted_users = sorted(users, key=compare_users, reverse=True)
|
|
|
|
|
# search our own user, to remove it from the list
|
|
|
|
|
for user in sorted_users:
|
|
|
|
|
if user.nick == self.own_nick:
|
|
|
|
|
sorted_users.remove(user)
|
|
|
|
|
user.color = get_theme().COLOR_OWN_NICK
|
|
|
|
|
colors = list(get_theme().LIST_COLOR_NICKNAMES)
|
|
|
|
|
if arg and arg == 'random':
|
|
|
|
|
random.shuffle(colors)
|
|
|
|
|
for i, user in enumerate(sorted_users):
|
|
|
|
|
user.color = colors[i % len(colors)]
|
|
|
|
|
self.text_win.rebuild_everything(self._text_buffer)
|
|
|
|
|
self.user_win.refresh(self.users)
|
|
|
|
|
self.text_win.refresh()
|
|
|
|
|
self.input.refresh()
|
|
|
|
|
|
|
|
|
|
def command_version(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/version <jid or nick>
|
|
|
|
|
"""
|
|
|
|
|
def callback(res):
|
|
|
|
|
if not res:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
return self.core.information(_('Could not get the software '
|
|
|
|
|
'version from %s') % (jid,),
|
|
|
|
|
_('Warning'))
|
|
|
|
|
version = _('%s is running %s version %s on %s') % (
|
|
|
|
|
jid,
|
2014-03-19 01:22:25 +00:00
|
|
|
|
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:
|
|
|
|
|
return self.core.command_help('version')
|
|
|
|
|
if arg in [user.nick for user in self.users]:
|
|
|
|
|
jid = safeJID(self.name).bare
|
|
|
|
|
jid = safeJID(jid + '/' + arg)
|
|
|
|
|
else:
|
|
|
|
|
jid = safeJID(arg)
|
2014-03-22 23:15:01 +00:00
|
|
|
|
fixes.get_version(self.core.xmpp, jid,
|
|
|
|
|
callback=callback)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def command_nick(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/nick <nickname>
|
|
|
|
|
"""
|
|
|
|
|
if not arg:
|
|
|
|
|
return self.core.command_help('nick')
|
|
|
|
|
nick = arg
|
|
|
|
|
if not self.joined:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
return self.core.information(_('/nick only works in joined rooms'),
|
|
|
|
|
_('Info'))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
current_status = self.core.get_status()
|
2014-04-30 19:34:09 +00:00
|
|
|
|
if not safeJID(self.name + '/' + nick):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
return self.core.information('Invalid nick', 'Info')
|
2014-04-26 21:49:52 +00:00
|
|
|
|
muc.change_nick(self.core, self.name, nick,
|
|
|
|
|
current_status.message,
|
|
|
|
|
current_status.show)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def command_part(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/part [msg]
|
|
|
|
|
"""
|
|
|
|
|
arg = arg.strip()
|
|
|
|
|
msg = None
|
|
|
|
|
if self.joined:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
|
|
|
|
char_quit = get_theme().CHAR_QUIT
|
|
|
|
|
spec_col = dump_tuple(get_theme().COLOR_QUIT_CHAR)
|
|
|
|
|
|
|
|
|
|
if config.get_by_tabname('display_user_color_in_join_part', True,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.general_jid, True):
|
2014-04-16 21:07:00 +00:00
|
|
|
|
color = dump_tuple(get_theme().COLOR_OWN_NICK)
|
|
|
|
|
else:
|
|
|
|
|
color = 3
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if arg:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
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,
|
|
|
|
|
}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
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,
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.add_message(msg, typ=2)
|
2014-04-16 22:02:19 +00:00
|
|
|
|
self.disconnect()
|
|
|
|
|
muc.leave_groupchat(self.core.xmpp, self.name, self.own_nick, arg)
|
2014-04-14 20:59:40 +00:00
|
|
|
|
self.core.disable_private_tabs(self.name, reason=msg)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if self == self.core.current_tab():
|
|
|
|
|
self.refresh()
|
|
|
|
|
self.core.doupdate()
|
|
|
|
|
|
|
|
|
|
def command_close(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/close [msg]
|
|
|
|
|
"""
|
|
|
|
|
self.command_part(arg)
|
|
|
|
|
self.core.close_tab()
|
|
|
|
|
|
|
|
|
|
def command_query(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/query <nick> [message]
|
|
|
|
|
"""
|
|
|
|
|
args = common.shell_split(arg)
|
|
|
|
|
if len(args) < 1:
|
|
|
|
|
return
|
|
|
|
|
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:
|
|
|
|
|
msg = args[1]
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.current_tab().command_say(
|
|
|
|
|
xhtml.convert_simple_to_full_colors(msg))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if not r:
|
|
|
|
|
self.core.information(_("Cannot find user: %s" % nick), 'Error')
|
|
|
|
|
|
|
|
|
|
def command_topic(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/topic [new topic]
|
|
|
|
|
"""
|
|
|
|
|
if not arg.strip():
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self._text_buffer.add_message(
|
|
|
|
|
_("\x19%s}The subject of the room is: %s") %
|
2014-04-29 01:12:57 +00:00
|
|
|
|
(dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
|
|
|
|
|
self.topic))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.refresh()
|
|
|
|
|
return
|
|
|
|
|
subject = arg
|
|
|
|
|
muc.change_subject(self.core.xmpp, self.name, subject)
|
|
|
|
|
|
|
|
|
|
def command_names(self, arg=None):
|
|
|
|
|
"""
|
|
|
|
|
/names
|
|
|
|
|
"""
|
|
|
|
|
if not self.joined:
|
|
|
|
|
return
|
|
|
|
|
color_visitor = dump_tuple(get_theme().COLOR_USER_VISITOR)
|
|
|
|
|
color_other = dump_tuple(get_theme().COLOR_USER_NONE)
|
|
|
|
|
color_moderator = dump_tuple(get_theme().COLOR_USER_MODERATOR)
|
|
|
|
|
color_participant = dump_tuple(get_theme().COLOR_USER_PARTICIPANT)
|
|
|
|
|
visitors, moderators, participants, others = [], [], [], []
|
|
|
|
|
aff = {
|
|
|
|
|
'owner': get_theme().CHAR_AFFILIATION_OWNER,
|
|
|
|
|
'admin': get_theme().CHAR_AFFILIATION_ADMIN,
|
|
|
|
|
'member': get_theme().CHAR_AFFILIATION_MEMBER,
|
|
|
|
|
'none': get_theme().CHAR_AFFILIATION_NONE,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
users = self.users[:]
|
|
|
|
|
users.sort(key=lambda x: x.nick.lower())
|
|
|
|
|
for user in users:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
color = aff.get(user.affiliation,
|
|
|
|
|
get_theme().CHAR_AFFILIATION_NONE)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if user.role == 'visitor':
|
|
|
|
|
visitors.append((user, color))
|
|
|
|
|
elif user.role == 'participant':
|
|
|
|
|
participants.append((user, color))
|
|
|
|
|
elif user.role == 'moderator':
|
|
|
|
|
moderators.append((user, color))
|
|
|
|
|
else:
|
|
|
|
|
others.append((user, color))
|
|
|
|
|
|
|
|
|
|
buff = ['Users: %s \n' % len(self.users)]
|
|
|
|
|
for moderator in moderators:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
buff.append('\x19%s}%s\x19o\x19%s}%s\x19o' % (
|
|
|
|
|
color_moderator, moderator[1],
|
|
|
|
|
dump_tuple(moderator[0].color), moderator[0].nick))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
for participant in participants:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
buff.append('\x19%s}%s\x19o\x19%s}%s\x19o' % (
|
|
|
|
|
color_participant, participant[1],
|
|
|
|
|
dump_tuple(participant[0].color), participant[0].nick))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
for visitor in visitors:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
buff.append('\x19%s}%s\x19o\x19%s}%s\x19o' % (
|
|
|
|
|
color_visitor, visitor[1],
|
|
|
|
|
dump_tuple(visitor[0].color), visitor[0].nick))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
for other in others:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
buff.append('\x19%s}%s\x19o\x19%s}%s\x19o' % (
|
|
|
|
|
color_other, other[1],
|
|
|
|
|
dump_tuple(other[0].color), other[0].nick))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
buff.append('\n')
|
|
|
|
|
message = ' '.join(buff)
|
|
|
|
|
|
|
|
|
|
self._text_buffer.add_message(message)
|
|
|
|
|
self.text_win.refresh()
|
|
|
|
|
self.input.refresh()
|
|
|
|
|
|
|
|
|
|
def completion_topic(self, the_input):
|
|
|
|
|
if the_input.get_argument_position() == 1:
|
|
|
|
|
return the_input.auto_completion([self.topic], '', quotify=False)
|
|
|
|
|
|
|
|
|
|
def completion_quoted(self, the_input):
|
|
|
|
|
"""Nick completion, but with quotes"""
|
|
|
|
|
if the_input.get_argument_position(quoted=True) == 1:
|
|
|
|
|
compare_users = lambda x: x.last_talked
|
2014-04-26 21:49:52 +00:00
|
|
|
|
word_list = []
|
|
|
|
|
for user in sorted(self.users, key=compare_users, reverse=True):
|
|
|
|
|
if user.nick != self.own_nick:
|
|
|
|
|
word_list.append(user.nick)
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
return the_input.new_completion(word_list, 1, quotify=True)
|
|
|
|
|
|
|
|
|
|
def command_kick(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/kick <nick> [reason]
|
|
|
|
|
"""
|
|
|
|
|
args = common.shell_split(arg)
|
|
|
|
|
if not args:
|
|
|
|
|
self.core.command_help('kick')
|
|
|
|
|
else:
|
|
|
|
|
if len(args) > 1:
|
|
|
|
|
msg = ' "%s"' % args[1]
|
|
|
|
|
else:
|
|
|
|
|
msg = ''
|
|
|
|
|
self.command_role('"'+args[0]+ '" none'+msg)
|
|
|
|
|
|
|
|
|
|
def command_ban(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/ban <nick> [reason]
|
|
|
|
|
"""
|
|
|
|
|
def callback(iq):
|
|
|
|
|
if iq['type'] == 'error':
|
2014-04-30 19:34:09 +00:00
|
|
|
|
self.core.room_error(iq, self.name)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
args = common.shell_split(arg)
|
|
|
|
|
if not args:
|
|
|
|
|
return self.core.command_help('ban')
|
|
|
|
|
if len(args) > 1:
|
|
|
|
|
msg = args[1]
|
|
|
|
|
else:
|
|
|
|
|
msg = ''
|
|
|
|
|
nick = args[0]
|
|
|
|
|
|
|
|
|
|
if nick in [user.nick for user in self.users]:
|
2014-04-30 19:34:09 +00:00
|
|
|
|
res = muc.set_user_affiliation(self.core.xmpp, self.name,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
'outcast', nick=nick,
|
|
|
|
|
callback=callback, reason=msg)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-30 19:34:09 +00:00
|
|
|
|
res = muc.set_user_affiliation(self.core.xmpp, self.name,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
'outcast', jid=safeJID(nick),
|
|
|
|
|
callback=callback, reason=msg)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if not res:
|
|
|
|
|
self.core.information('Could not ban user', 'Error')
|
|
|
|
|
|
|
|
|
|
def command_role(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/role <nick> <role> [reason]
|
|
|
|
|
Changes the role of an user
|
|
|
|
|
roles can be: none, visitor, participant, moderator
|
|
|
|
|
"""
|
|
|
|
|
def callback(iq):
|
|
|
|
|
if iq['type'] == 'error':
|
2014-04-30 19:34:09 +00:00
|
|
|
|
self.core.room_error(iq, self.name)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
args = common.shell_split(arg)
|
|
|
|
|
if len(args) < 2:
|
|
|
|
|
self.core.command_help('role')
|
|
|
|
|
return
|
2014-03-22 23:15:01 +00:00
|
|
|
|
nick, role = args[0], args[1]
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if len(args) > 2:
|
|
|
|
|
reason = ' '.join(args[2:])
|
|
|
|
|
else:
|
|
|
|
|
reason = ''
|
|
|
|
|
if not self.joined or \
|
|
|
|
|
not role in ('none', 'visitor', 'participant', 'moderator'):
|
|
|
|
|
return
|
2014-04-30 19:34:09 +00:00
|
|
|
|
if not safeJID(self.name + '/' + nick):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
return self.core('Invalid nick', 'Info')
|
2014-04-30 19:34:09 +00:00
|
|
|
|
muc.set_user_role(self.core.xmpp, self.name, nick, reason, role,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
callback=callback)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def command_affiliation(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/affiliation <nick> <role>
|
|
|
|
|
Changes the affiliation of an user
|
|
|
|
|
affiliations can be: outcast, none, member, admin, owner
|
|
|
|
|
"""
|
|
|
|
|
def callback(iq):
|
|
|
|
|
if iq['type'] == 'error':
|
2014-04-30 19:34:09 +00:00
|
|
|
|
self.core.room_error(iq, self.name)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
args = common.shell_split(arg)
|
|
|
|
|
if len(args) < 2:
|
|
|
|
|
self.core.command_help('affiliation')
|
|
|
|
|
return
|
|
|
|
|
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
|
|
|
|
|
if nick in [user.nick for user in self.users]:
|
2014-04-30 19:34:09 +00:00
|
|
|
|
res = muc.set_user_affiliation(self.core.xmpp, self.name,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
affiliation, nick=nick,
|
|
|
|
|
callback=callback)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-30 19:34:09 +00:00
|
|
|
|
res = muc.set_user_affiliation(self.core.xmpp, self.name,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
affiliation, jid=safeJID(nick),
|
|
|
|
|
callback=callback)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if not res:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.information(_('Could not set affiliation'), _('Error'))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def command_say(self, line, correct=False):
|
|
|
|
|
"""
|
|
|
|
|
/say <message>
|
|
|
|
|
Or normal input + enter
|
|
|
|
|
"""
|
|
|
|
|
needed = 'inactive' if self.inactive else 'active'
|
2014-04-30 19:34:09 +00:00
|
|
|
|
msg = self.core.xmpp.make_message(self.name)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
msg['type'] = 'groupchat'
|
|
|
|
|
msg['body'] = line
|
|
|
|
|
# trigger the event BEFORE looking for colors.
|
|
|
|
|
# This lets a plugin insert \x19xxx} colors, that will
|
|
|
|
|
# be converted in xhtml.
|
|
|
|
|
self.core.events.trigger('muc_say', msg, self)
|
|
|
|
|
if not msg['body']:
|
|
|
|
|
self.cancel_paused_delay()
|
|
|
|
|
self.text_win.refresh()
|
|
|
|
|
self.input.refresh()
|
|
|
|
|
return
|
|
|
|
|
if msg['body'].find('\x19') != -1:
|
|
|
|
|
msg.enable('html')
|
|
|
|
|
msg['html']['body'] = xhtml.poezio_colors_to_html(msg['body'])
|
|
|
|
|
msg['body'] = xhtml.clean_text(msg['body'])
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if (config.get_by_tabname('send_chat_states', True, self.general_jid,
|
|
|
|
|
True) and self.remote_wants_chatstates is not False):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
msg['chat_state'] = needed
|
|
|
|
|
if correct:
|
|
|
|
|
msg['replace']['id'] = self.last_sent_message['id']
|
|
|
|
|
self.cancel_paused_delay()
|
|
|
|
|
self.core.events.trigger('muc_say_after', msg, self)
|
|
|
|
|
if not msg['body']:
|
|
|
|
|
self.cancel_paused_delay()
|
|
|
|
|
self.text_win.refresh()
|
|
|
|
|
self.input.refresh()
|
|
|
|
|
return
|
|
|
|
|
self.last_sent_message = msg
|
|
|
|
|
msg.send()
|
|
|
|
|
self.chat_state = needed
|
|
|
|
|
|
|
|
|
|
def command_xhtml(self, arg):
|
|
|
|
|
message = self.generate_xhtml_message(arg)
|
|
|
|
|
if message:
|
|
|
|
|
message['type'] = 'groupchat'
|
|
|
|
|
message.send()
|
|
|
|
|
|
|
|
|
|
def command_ignore(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/ignore <nick>
|
|
|
|
|
"""
|
|
|
|
|
if not arg:
|
|
|
|
|
self.core.command_help('ignore')
|
|
|
|
|
return
|
|
|
|
|
nick = arg
|
|
|
|
|
user = self.get_user_by_name(nick)
|
|
|
|
|
if not user:
|
|
|
|
|
self.core.information(_('%s is not in the room') % nick)
|
|
|
|
|
elif user in self.ignores:
|
|
|
|
|
self.core.information(_('%s is already ignored') % nick)
|
|
|
|
|
else:
|
|
|
|
|
self.ignores.append(user)
|
|
|
|
|
self.core.information(_("%s is now ignored") % nick, 'info')
|
|
|
|
|
|
|
|
|
|
def command_unignore(self, arg):
|
|
|
|
|
"""
|
|
|
|
|
/unignore <nick>
|
|
|
|
|
"""
|
|
|
|
|
if not arg:
|
|
|
|
|
self.core.command_help('unignore')
|
|
|
|
|
return
|
|
|
|
|
nick = arg
|
|
|
|
|
user = self.get_user_by_name(nick)
|
|
|
|
|
if not user:
|
|
|
|
|
self.core.information(_('%s is not in the room') % nick)
|
|
|
|
|
elif user not in self.ignores:
|
|
|
|
|
self.core.information(_('%s is not ignored') % nick)
|
|
|
|
|
else:
|
|
|
|
|
self.ignores.remove(user)
|
|
|
|
|
self.core.information(_('%s is now unignored') % nick)
|
|
|
|
|
|
|
|
|
|
def completion_unignore(self, the_input):
|
|
|
|
|
if the_input.get_argument_position() == 1:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
users = [user.nick for user in self.ignores]
|
|
|
|
|
return the_input.auto_completion(users, quotify=False)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def resize(self):
|
|
|
|
|
"""
|
|
|
|
|
Resize the whole window. i.e. all its sub-windows
|
|
|
|
|
"""
|
|
|
|
|
self.need_resize = False
|
2014-04-28 21:29:21 +00:00
|
|
|
|
if config.get("hide_user_list", False) or self.size.tab_degrade_x:
|
|
|
|
|
display_user_list = False
|
2014-03-19 01:22:25 +00:00
|
|
|
|
text_width = self.width
|
|
|
|
|
else:
|
2014-04-28 21:29:21 +00:00
|
|
|
|
display_user_list = True
|
|
|
|
|
text_width = (self.width // 10) * 9
|
|
|
|
|
|
|
|
|
|
if self.size.tab_degrade_y:
|
|
|
|
|
display_info_win = False
|
|
|
|
|
tab_win_height = 0
|
|
|
|
|
info_win_height = 0
|
|
|
|
|
else:
|
|
|
|
|
display_info_win = True
|
|
|
|
|
tab_win_height = Tab.tab_win_height()
|
|
|
|
|
info_win_height = self.core.information_win_size
|
|
|
|
|
|
|
|
|
|
|
2014-04-29 00:20:06 +00:00
|
|
|
|
self.user_win.resize(self.height - 3 - info_win_height
|
|
|
|
|
- tab_win_height,
|
|
|
|
|
self.width - (self.width // 10) * 9 - 1,
|
|
|
|
|
1,
|
|
|
|
|
(self.width // 10) * 9 + 1)
|
|
|
|
|
self.v_separator.resize(self.height - 3 - info_win_height - tab_win_height,
|
|
|
|
|
1, 1, 9 * (self.width // 10))
|
2014-04-28 21:29:21 +00:00
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.topic_win.resize(1, self.width, 0, 0)
|
2014-04-28 21:29:21 +00:00
|
|
|
|
|
|
|
|
|
self.text_win.resize(self.height - 3 - info_win_height
|
|
|
|
|
- tab_win_height,
|
|
|
|
|
text_width, 1, 0)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.text_win.rebuild_everything(self._text_buffer)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.info_header.resize(1, self.width,
|
2014-04-28 21:29:21 +00:00
|
|
|
|
self.height - 2 - info_win_height
|
|
|
|
|
- tab_win_height,
|
2014-04-26 21:49:52 +00:00
|
|
|
|
0)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.input.resize(1, self.width, self.height-1, 0)
|
|
|
|
|
|
|
|
|
|
def refresh(self):
|
|
|
|
|
if self.need_resize:
|
|
|
|
|
self.resize()
|
2014-03-22 23:15:01 +00:00
|
|
|
|
log.debug(' TAB Refresh: %s', self.__class__.__name__)
|
2014-04-28 21:29:21 +00:00
|
|
|
|
if config.get("hide_user_list", False) or self.size.tab_degrade_x:
|
|
|
|
|
display_user_list = False
|
|
|
|
|
else:
|
|
|
|
|
display_user_list = True
|
2014-04-28 21:37:42 +00:00
|
|
|
|
display_info_win = not self.size.tab_degrade_y
|
2014-04-28 21:29:21 +00:00
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.topic_win.refresh(self.get_single_line_topic())
|
|
|
|
|
self.text_win.refresh()
|
2014-04-28 21:29:21 +00:00
|
|
|
|
if display_user_list:
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.v_separator.refresh()
|
|
|
|
|
self.user_win.refresh(self.users)
|
|
|
|
|
self.info_header.refresh(self, self.text_win)
|
|
|
|
|
self.refresh_tab_win()
|
2014-04-28 21:29:21 +00:00
|
|
|
|
if display_info_win:
|
|
|
|
|
self.info_win.refresh()
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.input.refresh()
|
|
|
|
|
|
|
|
|
|
def on_input(self, key, raw):
|
|
|
|
|
if not raw and key in self.key_func:
|
|
|
|
|
self.key_func[key]()
|
|
|
|
|
return False
|
|
|
|
|
self.input.do_command(key, raw=raw)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
empty_after = self.input.get_text() == ''
|
|
|
|
|
empty_after = empty_after or (self.input.get_text().startswith('/')
|
|
|
|
|
and not
|
|
|
|
|
self.input.get_text().startswith('//'))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.send_composing_chat_state(empty_after)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def completion(self):
|
|
|
|
|
"""
|
|
|
|
|
Called when Tab is pressed, complete the nickname in the input
|
|
|
|
|
"""
|
|
|
|
|
if self.complete_commands(self.input):
|
|
|
|
|
return
|
|
|
|
|
|
2014-04-26 21:49:52 +00:00
|
|
|
|
# If we are not completing a command or a command argument,
|
|
|
|
|
# complete a nick
|
2014-03-19 01:22:25 +00:00
|
|
|
|
compare_users = lambda x: x.last_talked
|
2014-04-26 21:49:52 +00:00
|
|
|
|
word_list = []
|
|
|
|
|
for user in sorted(self.users, key=compare_users, reverse=True):
|
|
|
|
|
if user.nick != self.own_nick:
|
|
|
|
|
word_list.append(user.nick)
|
|
|
|
|
after = config.get('after_completion', ',') + ' '
|
2014-03-19 01:22:25 +00:00
|
|
|
|
input_pos = self.input.pos
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
add_after = after
|
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if not config.get('add_space_after_completion', True):
|
|
|
|
|
add_after = ''
|
|
|
|
|
else:
|
|
|
|
|
add_after = ' '
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.input.auto_completion(word_list, add_after, quotify=False)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
empty_after = self.input.get_text() == ''
|
|
|
|
|
empty_after = empty_after or (self.input.get_text().startswith('/')
|
|
|
|
|
and not
|
|
|
|
|
self.input.get_text().startswith('//'))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.send_composing_chat_state(empty_after)
|
|
|
|
|
|
|
|
|
|
def get_nick(self):
|
2014-03-24 22:25:06 +00:00
|
|
|
|
if not config.get('show_muc_jid', True):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
return safeJID(self.name).user
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
def get_text_window(self):
|
|
|
|
|
return self.text_win
|
|
|
|
|
|
|
|
|
|
def on_lose_focus(self):
|
|
|
|
|
if self.joined:
|
2014-04-02 19:33:17 +00:00
|
|
|
|
if self.input.text:
|
|
|
|
|
self.state = 'nonempty'
|
|
|
|
|
else:
|
|
|
|
|
self.state = 'normal'
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
|
|
|
|
self.state = 'disconnected'
|
|
|
|
|
self.text_win.remove_line_separator()
|
|
|
|
|
self.text_win.add_line_separator(self._text_buffer)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if config.get_by_tabname('send_chat_states', True,
|
|
|
|
|
self.general_jid, True) and not self.input.get_text():
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.send_chat_state('inactive')
|
|
|
|
|
self.check_scrolled()
|
|
|
|
|
|
|
|
|
|
def on_gain_focus(self):
|
|
|
|
|
self.state = 'current'
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if (self.text_win.built_lines and self.text_win.built_lines[-1] is None
|
|
|
|
|
and not config.get('show_useless_separator', False)):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.text_win.remove_line_separator()
|
|
|
|
|
curses.curs_set(1)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if self.joined and config.get_by_tabname('send_chat_states', True,
|
|
|
|
|
self.general_jid, True) and not self.input.get_text():
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.send_chat_state('active')
|
|
|
|
|
|
|
|
|
|
def on_info_win_size_changed(self):
|
|
|
|
|
if self.core.information_win_size >= self.height-3:
|
|
|
|
|
return
|
2014-03-24 22:25:06 +00:00
|
|
|
|
if config.get("hide_user_list", False):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
text_width = self.width
|
|
|
|
|
else:
|
|
|
|
|
text_width = (self.width//10)*9
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.user_win.resize(self.height - 3 - self.core.information_win_size
|
|
|
|
|
- Tab.tab_win_height(),
|
|
|
|
|
self.width - (self.width // 10) * 9 - 1,
|
|
|
|
|
1,
|
|
|
|
|
(self.width // 10) * 9 + 1)
|
2014-04-29 00:20:06 +00:00
|
|
|
|
self.v_separator.resize(self.height - 3 - self.core.information_win_size - Tab.tab_win_height(),
|
|
|
|
|
1, 1, 9 * (self.width // 10))
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.text_win.resize(self.height - 3 - self.core.information_win_size
|
|
|
|
|
- Tab.tab_win_height(),
|
|
|
|
|
text_width, 1, 0)
|
|
|
|
|
self.info_header.resize(1, self.width,
|
|
|
|
|
self.height-2-self.core.information_win_size
|
|
|
|
|
- Tab.tab_win_height(),
|
|
|
|
|
0)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def handle_presence(self, presence):
|
|
|
|
|
from_nick = presence['from'].resource
|
|
|
|
|
from_room = presence['from'].bare
|
2014-04-26 21:49:52 +00:00
|
|
|
|
xpath = '{%s}x/{%s}status' % (NS_MUC_USER, NS_MUC_USER)
|
|
|
|
|
status_codes = set()
|
|
|
|
|
for status_code in presence.findall(xpath):
|
|
|
|
|
status_codes.add(status_code.attrib['code'])
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
# Check if it's not an error presence.
|
|
|
|
|
if presence['type'] == 'error':
|
|
|
|
|
return self.core.room_error(presence, from_room)
|
|
|
|
|
affiliation = presence['muc']['affiliation']
|
|
|
|
|
show = presence['show']
|
|
|
|
|
status = presence['status']
|
|
|
|
|
role = presence['muc']['role']
|
|
|
|
|
jid = presence['muc']['jid']
|
|
|
|
|
typ = presence['type']
|
|
|
|
|
if not self.joined: # user in the room BEFORE us.
|
|
|
|
|
# ignore redondant presence message, see bug #1509
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.users.append(new_user)
|
|
|
|
|
self.core.events.trigger('muc_join', presence, self)
|
|
|
|
|
if '110' in status_codes or self.own_nick == from_nick:
|
|
|
|
|
# second part of the condition is a workaround for old
|
|
|
|
|
# ejabberd or every gateway in the world that just do
|
|
|
|
|
# not send a 110 status code with the presence
|
|
|
|
|
self.own_nick = from_nick
|
|
|
|
|
self.joined = True
|
2014-04-30 19:34:09 +00:00
|
|
|
|
if self.name in self.core.initial_joins:
|
|
|
|
|
self.core.initial_joins.remove(self.name)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self._state = 'normal'
|
|
|
|
|
elif self != self.core.current_tab():
|
|
|
|
|
self._state = 'joined'
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if (self.core.current_tab() is self
|
|
|
|
|
and self.core.status.show not in ('xa', 'away')):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.send_chat_state('active')
|
|
|
|
|
new_user.color = get_theme().COLOR_OWN_NICK
|
2014-04-16 21:07:00 +00:00
|
|
|
|
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if config.get_by_tabname('display_user_color_in_join_part',
|
|
|
|
|
True, self.general_jid, True):
|
2014-04-16 21:07:00 +00:00
|
|
|
|
color = dump_tuple(new_user.color)
|
|
|
|
|
else:
|
|
|
|
|
color = 3
|
|
|
|
|
|
|
|
|
|
info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
|
|
|
|
warn_col = dump_tuple(get_theme().COLOR_WARNING_TEXT)
|
|
|
|
|
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') %
|
|
|
|
|
{
|
|
|
|
|
'nick': from_nick,
|
|
|
|
|
'spec': get_theme().CHAR_JOIN,
|
|
|
|
|
'color_spec': spec_col,
|
|
|
|
|
'nick_col': color,
|
|
|
|
|
'info_col': info_col,
|
|
|
|
|
},
|
2014-03-19 01:22:25 +00:00
|
|
|
|
typ=2)
|
|
|
|
|
if '201' in status_codes:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
self.add_message(
|
|
|
|
|
_('\x19%(info_col)s}Info: The room '
|
|
|
|
|
'has been created') %
|
2014-04-26 21:49:52 +00:00
|
|
|
|
{'info_col': info_col},
|
2014-04-16 21:07:00 +00:00
|
|
|
|
typ=0)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if '170' in status_codes:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
self.add_message(
|
|
|
|
|
_('\x19%(warn_col)s}Warning:\x19%(info_col)s}'
|
|
|
|
|
' This room is publicly logged') %
|
2014-04-26 21:49:52 +00:00
|
|
|
|
{'info_col': info_col,
|
|
|
|
|
'warn_col': warn_col},
|
2014-04-16 21:07:00 +00:00
|
|
|
|
typ=0)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if '100' in status_codes:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
self.add_message(
|
|
|
|
|
_('\x19%(warn_col)s}Warning:\x19%(info_col)s}'
|
|
|
|
|
' This room is not anonymous.') %
|
2014-04-26 21:49:52 +00:00
|
|
|
|
{'info_col': info_col,
|
|
|
|
|
'warn_col': warn_col},
|
2014-04-16 21:07:00 +00:00
|
|
|
|
typ=0)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if self.core.current_tab() is not self:
|
|
|
|
|
self.refresh_tab_win()
|
|
|
|
|
self.core.current_tab().input.refresh()
|
|
|
|
|
self.core.doupdate()
|
2014-04-30 19:34:09 +00:00
|
|
|
|
self.core.enable_private_tabs(self.name)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
|
|
|
|
change_nick = '303' in status_codes
|
|
|
|
|
kick = '307' in status_codes and typ == 'unavailable'
|
|
|
|
|
ban = '301' in status_codes and typ == 'unavailable'
|
|
|
|
|
shutdown = '332' in status_codes and typ == 'unavailable'
|
|
|
|
|
non_member = '322' in status_codes and typ == 'unavailable'
|
|
|
|
|
user = self.get_user_by_name(from_nick)
|
|
|
|
|
# New user
|
|
|
|
|
if not user:
|
|
|
|
|
self.core.events.trigger('muc_join', presence, self)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.on_user_join(from_nick, affiliation, show, status, role,
|
|
|
|
|
jid)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
# nick change
|
|
|
|
|
elif change_nick:
|
|
|
|
|
self.core.events.trigger('muc_nickchange', presence, self)
|
|
|
|
|
self.on_user_nick_change(presence, user, from_nick, from_room)
|
|
|
|
|
elif ban:
|
|
|
|
|
self.core.events.trigger('muc_ban', presence, self)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.on_user_left_private_conversation(from_room,
|
|
|
|
|
from_nick, status)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.on_user_banned(presence, user, from_nick)
|
|
|
|
|
# kick
|
|
|
|
|
elif kick:
|
|
|
|
|
self.core.events.trigger('muc_kick', presence, self)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.on_user_left_private_conversation(from_room,
|
|
|
|
|
from_nick, status)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.on_user_kicked(presence, user, from_nick)
|
|
|
|
|
elif shutdown:
|
|
|
|
|
self.core.events.trigger('muc_shutdown', presence, self)
|
|
|
|
|
self.on_muc_shutdown()
|
|
|
|
|
elif non_member:
|
|
|
|
|
self.core.events.trigger('muc_shutdown', presence, self)
|
|
|
|
|
self.on_non_member_kicked()
|
|
|
|
|
# user quit
|
|
|
|
|
elif typ == 'unavailable':
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.on_user_leave_groupchat(user, jid, status,
|
|
|
|
|
from_nick, from_room)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
# status change
|
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.on_user_change_status(user, from_nick, from_room,
|
|
|
|
|
affiliation, role, show, status)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if self.core.current_tab() is self:
|
|
|
|
|
self.text_win.refresh()
|
|
|
|
|
self.user_win.refresh(self.users)
|
|
|
|
|
self.info_header.refresh(self, self.text_win)
|
|
|
|
|
self.input.refresh()
|
|
|
|
|
self.core.doupdate()
|
|
|
|
|
|
|
|
|
|
def on_non_member_kicked(self):
|
|
|
|
|
"""We have been kicked because the MUC is members-only"""
|
2014-04-16 21:07:00 +00:00
|
|
|
|
self.add_message(
|
|
|
|
|
_('\x19%(info_col)s}You have been kicked because you '
|
|
|
|
|
'are not a member and the room is now members-only.') % {
|
2014-03-19 01:22:25 +00:00
|
|
|
|
'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)},
|
|
|
|
|
typ=2)
|
|
|
|
|
self.disconnect()
|
|
|
|
|
|
|
|
|
|
def on_muc_shutdown(self):
|
|
|
|
|
"""We have been kicked because the MUC service is shutting down"""
|
2014-04-16 21:07:00 +00:00
|
|
|
|
self.add_message(
|
|
|
|
|
_('\x19%(info_col)s}You have been kicked because the'
|
|
|
|
|
' MUC service is shutting down.') % {
|
2014-03-19 01:22:25 +00:00
|
|
|
|
'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):
|
|
|
|
|
"""
|
|
|
|
|
When a new user joins the groupchat
|
|
|
|
|
"""
|
|
|
|
|
user = User(from_nick, affiliation,
|
|
|
|
|
show, status, role, jid)
|
|
|
|
|
self.users.append(user)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
hide_exit_join = config.get_by_tabname('hide_exit_join', -1,
|
|
|
|
|
self.general_jid, True)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if hide_exit_join != 0:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
if config.get_by_tabname('display_user_color_in_join_part', True,
|
|
|
|
|
self.general_jid, True):
|
|
|
|
|
color = dump_tuple(user.color)
|
|
|
|
|
else:
|
|
|
|
|
color = 3
|
|
|
|
|
info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
|
|
|
|
spec_col = dump_tuple(get_theme().COLOR_JOIN_CHAR)
|
|
|
|
|
char_join = get_theme().CHAR_JOIN
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if not jid.full:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
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,
|
|
|
|
|
}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
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,
|
|
|
|
|
'jid_color': dump_tuple(get_theme().COLOR_MUC_JID),
|
|
|
|
|
'color_spec': spec_col,
|
|
|
|
|
}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.add_message(msg, typ=2)
|
|
|
|
|
self.core.on_user_rejoined_private_conversation(self.name, from_nick)
|
|
|
|
|
|
|
|
|
|
def on_user_nick_change(self, presence, user, from_nick, from_room):
|
2014-04-26 21:49:52 +00:00
|
|
|
|
new_nick = presence.find('{%s}x/{%s}item' % (NS_MUC_USER, NS_MUC_USER)
|
|
|
|
|
).attrib['nick']
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if user.nick == self.own_nick:
|
|
|
|
|
self.own_nick = new_nick
|
|
|
|
|
# also change our nick in all private discussions of this room
|
|
|
|
|
self.core.on_muc_own_nickchange(self)
|
|
|
|
|
user.change_nick(new_nick)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
|
|
|
|
|
if config.get_by_tabname('display_user_color_in_join_part', True,
|
|
|
|
|
self.general_jid, True):
|
|
|
|
|
color = dump_tuple(user.color)
|
|
|
|
|
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') % {
|
|
|
|
|
'old':from_nick, 'new':new_nick,
|
|
|
|
|
'color':color, 'info_col': info_col},
|
|
|
|
|
typ=2)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
# rename the private tabs if needed
|
|
|
|
|
self.core.rename_private_tabs(self.name, from_nick, new_nick)
|
|
|
|
|
|
|
|
|
|
def on_user_banned(self, presence, user, from_nick):
|
|
|
|
|
"""
|
|
|
|
|
When someone is banned from a muc
|
|
|
|
|
"""
|
|
|
|
|
self.users.remove(user)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
by = presence.find('{%s}x/{%s}item/{%s}actor' %
|
|
|
|
|
(NS_MUC_USER, NS_MUC_USER, NS_MUC_USER))
|
|
|
|
|
reason = presence.find('{%s}x/{%s}item/{%s}reason' %
|
|
|
|
|
(NS_MUC_USER, NS_MUC_USER, NS_MUC_USER))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
by = by.attrib['jid'] if by is not None else None
|
2014-04-26 21:49:52 +00:00
|
|
|
|
|
|
|
|
|
info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
|
|
|
|
char_kick = get_theme().CHAR_KICK
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if from_nick == self.own_nick: # we are banned
|
|
|
|
|
if by:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
kick_msg = _('\x191}%(spec)s \x193}You\x19'
|
|
|
|
|
'%(info_col)s} have been banned.') % {
|
|
|
|
|
'spec': char_kick, 'info_col': info_col}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.core.disable_private_tabs(self.name, reason=kick_msg)
|
|
|
|
|
self.disconnect()
|
|
|
|
|
self.refresh_tab_win()
|
|
|
|
|
self.core.current_tab().input.refresh()
|
|
|
|
|
self.core.doupdate()
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if config.get_by_tabname('autorejoin', False,
|
|
|
|
|
self.general_jid, True):
|
|
|
|
|
delay = config.get_by_tabname('autorejoin_delay', '5',
|
|
|
|
|
self.general_jid, True)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
delay = common.parse_str_to_secs(delay)
|
|
|
|
|
if delay <= 0:
|
|
|
|
|
muc.join_groupchat(self.core, self.name, self.own_nick)
|
|
|
|
|
else:
|
|
|
|
|
self.core.add_timed_event(timed_events.DelayedEvent(
|
2014-04-26 21:49:52 +00:00
|
|
|
|
delay,
|
|
|
|
|
muc.join_groupchat,
|
|
|
|
|
self.core,
|
|
|
|
|
self.name,
|
|
|
|
|
self.own_nick))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if config.get_by_tabname('display_user_color_in_join_part',
|
|
|
|
|
True, self.general_jid, True):
|
|
|
|
|
color = dump_tuple(user.color)
|
|
|
|
|
else:
|
|
|
|
|
color = 3
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if by:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if reason is not None and reason.text:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
kick_msg += _('\x19%(info_col)s} Reason: \x196}'
|
|
|
|
|
'%(reason)s\x19%(info_col)s}') % {
|
|
|
|
|
'reason': reason.text, 'info_col': info_col}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.add_message(kick_msg, typ=2)
|
|
|
|
|
|
|
|
|
|
def on_user_kicked(self, presence, user, from_nick):
|
|
|
|
|
"""
|
|
|
|
|
When someone is kicked from a muc
|
|
|
|
|
"""
|
|
|
|
|
self.users.remove(user)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
actor_elem = presence.find('{%s}x/{%s}item/{%s}actor' %
|
|
|
|
|
(NS_MUC_USER, NS_MUC_USER, NS_MUC_USER))
|
|
|
|
|
reason = presence.find('{%s}x/{%s}item/{%s}reason' %
|
|
|
|
|
(NS_MUC_USER, NS_MUC_USER, NS_MUC_USER))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
by = None
|
2014-04-26 21:49:52 +00:00
|
|
|
|
info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
|
|
|
|
char_kick = get_theme().CHAR_KICK
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if actor_elem is not None:
|
|
|
|
|
by = actor_elem.get('nick') or actor_elem.get('jid')
|
|
|
|
|
if from_nick == self.own_nick: # we are kicked
|
|
|
|
|
if by:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
kick_msg = _('\x191}%(spec)s \x193}You\x19%(info_col)s}'
|
|
|
|
|
' have been kicked.') % {
|
|
|
|
|
'spec': char_kick,
|
|
|
|
|
'info_col': info_col}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.core.disable_private_tabs(self.name, reason=kick_msg)
|
|
|
|
|
self.disconnect()
|
|
|
|
|
self.refresh_tab_win()
|
|
|
|
|
self.core.current_tab().input.refresh()
|
|
|
|
|
self.core.doupdate()
|
|
|
|
|
# try to auto-rejoin
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if config.get_by_tabname('autorejoin', False,
|
|
|
|
|
self.general_jid, True):
|
|
|
|
|
delay = config.get_by_tabname('autorejoin_delay', "5",
|
|
|
|
|
self.general_jid, True)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
delay = common.parse_str_to_secs(delay)
|
|
|
|
|
if delay <= 0:
|
|
|
|
|
muc.join_groupchat(self.core, self.name, self.own_nick)
|
|
|
|
|
else:
|
|
|
|
|
self.core.add_timed_event(timed_events.DelayedEvent(
|
|
|
|
|
delay,
|
|
|
|
|
muc.join_groupchat,
|
|
|
|
|
self.core,
|
|
|
|
|
self.name,
|
|
|
|
|
self.own_nick))
|
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if config.get_by_tabname('display_user_color_in_join_part', True,
|
|
|
|
|
self.general_jid, True):
|
|
|
|
|
color = dump_tuple(user.color)
|
|
|
|
|
else:
|
|
|
|
|
color = 3
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if by:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
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}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if reason is not None and reason.text:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
kick_msg += _('\x19%(info_col)s} Reason: \x196}'
|
|
|
|
|
'%(reason)s') % {
|
|
|
|
|
'reason': reason.text, 'info_col': info_col}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.add_message(kick_msg, typ=2)
|
|
|
|
|
|
|
|
|
|
def on_user_leave_groupchat(self, user, jid, status, from_nick, from_room):
|
|
|
|
|
"""
|
|
|
|
|
When an user leaves a groupchat
|
|
|
|
|
"""
|
|
|
|
|
self.users.remove(user)
|
|
|
|
|
if self.own_nick == user.nick:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
# We are now out of the room.
|
|
|
|
|
# Happens with some buggy (? not sure) servers
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.disconnect()
|
|
|
|
|
self.core.disable_private_tabs(from_room)
|
|
|
|
|
self.refresh_tab_win()
|
2014-04-16 21:07:00 +00:00
|
|
|
|
|
2014-04-26 21:49:52 +00:00
|
|
|
|
hide_exit_join = max(config.get_by_tabname('hide_exit_join', -1,
|
|
|
|
|
self.general_jid, True),
|
|
|
|
|
-1)
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if hide_exit_join == -1 or user.has_talked_since(hide_exit_join):
|
2014-04-16 21:07:00 +00:00
|
|
|
|
if config.get_by_tabname('display_user_color_in_join_part', True,
|
|
|
|
|
self.general_jid, True):
|
|
|
|
|
color = dump_tuple(user.color)
|
|
|
|
|
else:
|
|
|
|
|
color = 3
|
|
|
|
|
info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT)
|
|
|
|
|
spec_col = dump_tuple(get_theme().COLOR_QUIT_CHAR)
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if not jid.full:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
leave_msg = _('\x19%(color_spec)s}%(spec)s \x19%(color)s}'
|
2014-04-26 21:49:52 +00:00
|
|
|
|
'%(nick)s\x19%(info_col)s} has left the '
|
|
|
|
|
'chatroom') % {
|
2014-04-16 21:07:00 +00:00
|
|
|
|
'nick':from_nick, 'color':color,
|
|
|
|
|
'spec':get_theme().CHAR_QUIT,
|
|
|
|
|
'info_col': info_col,
|
|
|
|
|
'color_spec': spec_col}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
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}'
|
2014-04-26 21:49:52 +00:00
|
|
|
|
'%(jid)s\x19%(info_col)s}) has left the '
|
|
|
|
|
'chatroom') % {
|
2014-04-16 21:07:00 +00:00
|
|
|
|
'spec':get_theme().CHAR_QUIT,
|
|
|
|
|
'nick':from_nick, 'color':color,
|
|
|
|
|
'jid':jid.full, 'info_col': info_col,
|
|
|
|
|
'color_spec': spec_col,
|
|
|
|
|
'jid_col': jid_col}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if status:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
leave_msg += ' (\x19o%s\x19%s})' % (status, info_col)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.add_message(leave_msg, typ=2)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.on_user_left_private_conversation(from_room, from_nick,
|
|
|
|
|
status)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
2014-04-26 21:49:52 +00:00
|
|
|
|
def on_user_change_status(
|
|
|
|
|
self, user, from_nick, from_room, affiliation, role, show, status):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
"""
|
|
|
|
|
When an user changes her status
|
|
|
|
|
"""
|
|
|
|
|
# build the message
|
|
|
|
|
display_message = False # flag to know if something significant enough
|
2014-04-16 21:07:00 +00:00
|
|
|
|
# to be displayed has changed
|
|
|
|
|
if config.get_by_tabname('display_user_color_in_join_part', True,
|
|
|
|
|
self.general_jid, True):
|
|
|
|
|
color = dump_tuple(user.color)
|
|
|
|
|
else:
|
|
|
|
|
color = 3
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if from_nick == self.own_nick:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
msg = _('\x19%(color)s}You\x19%(info_col)s} changed: ') % {
|
|
|
|
|
'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT),
|
|
|
|
|
'color': color}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
else:
|
2014-04-16 21:07:00 +00:00
|
|
|
|
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)}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if show not in SHOW_NAME:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.information(_("%s from room %s sent an invalid show: %s")
|
|
|
|
|
% (from_nick, from_room, show),
|
|
|
|
|
_("Warning"))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if affiliation != user.affiliation:
|
|
|
|
|
msg += _('affiliation: %s, ') % affiliation
|
|
|
|
|
display_message = True
|
|
|
|
|
if role != user.role:
|
|
|
|
|
msg += _('role: %s, ') % role
|
|
|
|
|
display_message = True
|
|
|
|
|
if show != user.show and show in SHOW_NAME:
|
|
|
|
|
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
|
|
|
|
|
display_message = True
|
|
|
|
|
elif show in SHOW_NAME and show == user.show:
|
|
|
|
|
msg += _('show: %s, ') % SHOW_NAME[show]
|
|
|
|
|
display_message = True
|
|
|
|
|
if not display_message:
|
|
|
|
|
return
|
|
|
|
|
msg = msg[:-2] # remove the last ", "
|
2014-04-26 21:49:52 +00:00
|
|
|
|
hide_status_change = config.get_by_tabname('hide_status_change', -1,
|
|
|
|
|
self.general_jid, True)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if hide_status_change < -1:
|
|
|
|
|
hide_status_change = -1
|
|
|
|
|
if ((hide_status_change == -1 or \
|
|
|
|
|
user.has_talked_since(hide_status_change) or\
|
|
|
|
|
user.nick == self.own_nick)\
|
|
|
|
|
and\
|
|
|
|
|
(affiliation != user.affiliation or\
|
|
|
|
|
role != user.role or\
|
|
|
|
|
show != user.show or\
|
|
|
|
|
status != user.status))\
|
|
|
|
|
or\
|
|
|
|
|
(affiliation != user.affiliation or\
|
|
|
|
|
role != user.role):
|
|
|
|
|
# display the message in the room
|
|
|
|
|
self._text_buffer.add_message(msg)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.on_user_changed_status_in_private('%s/%s' %
|
|
|
|
|
(from_room, from_nick),
|
|
|
|
|
msg)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
# finally, effectively change the user status
|
|
|
|
|
user.update(affiliation, show, status, role)
|
|
|
|
|
|
|
|
|
|
def disconnect(self):
|
|
|
|
|
"""
|
|
|
|
|
Set the state of the room as not joined, so
|
|
|
|
|
we can know if we can join it, send messages to it, etc
|
|
|
|
|
"""
|
|
|
|
|
self.users = []
|
|
|
|
|
if self is not self.core.current_tab():
|
|
|
|
|
self.state = 'disconnected'
|
|
|
|
|
self.joined = False
|
|
|
|
|
|
|
|
|
|
def get_single_line_topic(self):
|
|
|
|
|
"""
|
|
|
|
|
Return the topic as a single-line string (for the window header)
|
|
|
|
|
"""
|
|
|
|
|
return self.topic.replace('\n', '|')
|
|
|
|
|
|
|
|
|
|
def log_message(self, txt, nickname, time=None, typ=1):
|
|
|
|
|
"""
|
|
|
|
|
Log the messages in the archives, if it needs
|
|
|
|
|
to be
|
|
|
|
|
"""
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if time is None and self.joined: # don't log the history messages
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if not logger.log_message(self.name, nickname, txt, typ=typ):
|
2014-04-26 21:49:52 +00:00
|
|
|
|
self.core.information(_('Unable to write in the log file'),
|
|
|
|
|
_('Error'))
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
def do_highlight(self, txt, time, nickname):
|
|
|
|
|
"""
|
|
|
|
|
Set the tab color and returns the nick color
|
|
|
|
|
"""
|
|
|
|
|
highlighted = False
|
|
|
|
|
if not time and nickname and nickname != self.own_nick and self.joined:
|
2014-04-11 22:34:25 +00:00
|
|
|
|
|
|
|
|
|
if re.search(r'\b' + self.own_nick.lower() + r'\b', txt.lower()):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if self.state != 'current':
|
|
|
|
|
self.state = 'highlight'
|
|
|
|
|
highlighted = True
|
|
|
|
|
else:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
highlight_words = config.get_by_tabname('highlight_on', '',
|
|
|
|
|
self.general_jid,
|
|
|
|
|
True).split(':')
|
2014-03-19 01:22:25 +00:00
|
|
|
|
for word in highlight_words:
|
|
|
|
|
if word and word.lower() in txt.lower():
|
|
|
|
|
if self.state != 'current':
|
|
|
|
|
self.state = 'highlight'
|
|
|
|
|
highlighted = True
|
|
|
|
|
break
|
|
|
|
|
if highlighted:
|
|
|
|
|
beep_on = config.get('beep_on', 'highlight private').split()
|
|
|
|
|
if 'highlight' in beep_on and 'message' not in beep_on:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
if not config.get_by_tabname('disable_beep', False,
|
|
|
|
|
self.name, False):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
curses.beep()
|
|
|
|
|
return highlighted
|
|
|
|
|
|
|
|
|
|
def get_user_by_name(self, nick):
|
|
|
|
|
"""
|
|
|
|
|
Gets the user associated with the given nick, or None if not found
|
|
|
|
|
"""
|
|
|
|
|
for user in self.users:
|
|
|
|
|
if user.nick == nick:
|
|
|
|
|
return user
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def add_message(self, txt, time=None, nickname=None, **kwargs):
|
|
|
|
|
"""
|
|
|
|
|
Note that user can be None even if nickname is not None. It happens
|
|
|
|
|
when we receive an history message said by someone who is not
|
|
|
|
|
in the room anymore
|
|
|
|
|
Return True if the message highlighted us. False otherwise.
|
|
|
|
|
"""
|
|
|
|
|
self.log_message(txt, nickname, time=time, typ=kwargs.get('typ', 1))
|
2014-04-26 21:49:52 +00:00
|
|
|
|
args = dict()
|
|
|
|
|
for key, value in kwargs.items():
|
|
|
|
|
if key not in ('typ', 'forced_user'):
|
|
|
|
|
args[key] = value
|
|
|
|
|
if nickname is not None:
|
|
|
|
|
user = self.get_user_by_name(nickname)
|
|
|
|
|
else:
|
|
|
|
|
user = None
|
|
|
|
|
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if user:
|
|
|
|
|
user.set_last_talked(datetime.now())
|
|
|
|
|
args['user'] = user
|
|
|
|
|
if not user and kwargs.get('forced_user'):
|
|
|
|
|
args['user'] = kwargs['forced_user']
|
2014-04-26 21:49:52 +00:00
|
|
|
|
|
|
|
|
|
if (not time and nickname and nickname != self.own_nick
|
|
|
|
|
and self.state != 'current'):
|
|
|
|
|
if (self.state != 'highlight' and
|
|
|
|
|
config.get_by_tabname('notify_messages',
|
2014-04-30 19:34:09 +00:00
|
|
|
|
True, self.name)):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.state = 'message'
|
2014-04-06 23:25:30 +00:00
|
|
|
|
if time:
|
2014-04-26 21:49:52 +00:00
|
|
|
|
txt = '\x19%(info_col)s}%(txt)s' % {
|
|
|
|
|
'txt': txt,
|
|
|
|
|
'info_col': dump_tuple(get_theme().COLOR_LOG_MSG)}
|
2014-04-06 23:25:30 +00:00
|
|
|
|
elif (not nickname or time) and not txt.startswith('/me '):
|
2014-04-26 21:49:52 +00:00
|
|
|
|
txt = '\x19%(info_col)s}%(txt)s' % {
|
|
|
|
|
'txt': txt,
|
|
|
|
|
'info_col': dump_tuple(get_theme().COLOR_INFORMATION_TEXT)}
|
2014-03-19 01:22:25 +00:00
|
|
|
|
elif not kwargs.get('highlight'): # TODO
|
|
|
|
|
args['highlight'] = self.do_highlight(txt, time, nickname)
|
|
|
|
|
time = time or datetime.now()
|
|
|
|
|
self._text_buffer.add_message(txt, time, nickname, **args)
|
|
|
|
|
return args.get('highlight', False)
|
|
|
|
|
|
2014-04-26 21:49:52 +00:00
|
|
|
|
def modify_message(self, txt, old_id, new_id,
|
|
|
|
|
time=None, nickname=None, user=None, jid=None):
|
2014-03-19 01:22:25 +00:00
|
|
|
|
self.log_message(txt, nickname, time=time, typ=1)
|
|
|
|
|
highlight = self.do_highlight(txt, time, nickname)
|
2014-04-26 21:49:52 +00:00
|
|
|
|
message = self._text_buffer.modify_message(txt, old_id, new_id,
|
|
|
|
|
highlight=highlight,
|
|
|
|
|
time=time, user=user,
|
|
|
|
|
jid=jid)
|
2014-03-19 01:22:25 +00:00
|
|
|
|
if message:
|
|
|
|
|
self.text_win.modify_message(old_id, message)
|
|
|
|
|
self.core.refresh_window()
|
|
|
|
|
return highlight
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def matching_names(self):
|
2014-04-30 19:34:09 +00:00
|
|
|
|
return [(1, safeJID(self.name).user), (3, self.name)]
|
2014-03-19 01:22:25 +00:00
|
|
|
|
|
|
|
|
|
|