gui.py 25.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#!/usr/bin/python
# -*- coding:utf-8 -*-
#
# Copyright 2010 Le Coz Florent <louizatakk@fedoraproject.org>
#
# This file is part of Poezio.
#
# Poezio is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Poezio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Poezio.  If not, see <http://www.gnu.org/licenses/>.

20 21
from gettext import (bindtextdomain, textdomain, bind_textdomain_codeset,
                     gettext as _)
22

23 24 25 26
bindtextdomain('poezio')
textdomain('poezio')
bind_textdomain_codeset('poezio', 'utf-8')

27
import locale
28 29 30 31
locale.setlocale(locale.LC_ALL, '')
import sys

import curses
32 33
from datetime import datetime

34
from handler import Handler
35
from logging import logger
36
from random import randrange
37
from config import config
38
from window import Window
39

40
class User(object):
41
    """
42
    keep trace of an user in a Room
43
    """
44 45 46
    def __init__(self, nick, affiliation, show, status, role):
        self.update(affiliation, show, status, role)
        self.change_nick(nick)
47
        self.color = randrange(2, 10)
48

49
    def update(self, affiliation, show, status, role):
50 51
        self.affiliation = affiliation
        self.show = show
52 53
        self.status = status
        self.role = role
54

55
    def change_nick(self, nick):
56
        self.nick = nick.encode('utf-8')
57

58
class Room(object):
59 60
    """
    """
61
    def __init__(self, name, nick, number):
62
        self.name = name
63
        self.own_nick = nick
64 65
        self.color_state = 11   # color used in RoomInfo
        self.nb = number       # number used in RoomInfo
66 67 68 69
        self.joined = False     # false until self presence is received
        self.users = []
        self.lines = []         # (time, nick, msg) or (time, info)
        self.topic = ''
70

71 72 73 74
    def disconnect(self):
        self.joined = False
        self.users = []

75
    def add_message(self, nick, msg):
76
        color = None
77
        self.set_color_state(12)
78 79 80 81 82 83 84 85 86 87
        if nick != self.own_nick:
            if self.own_nick in msg:
                self.set_color_state(13)
                color = 3
            else:
                highlight_words = config.get('highlight_on', '').split(':')
                for word in highlight_words:
                    if word.lower() in msg.lower() and word != '':
                        self.set_color_state(13)
                        color = 3
88 89 90
        if not msg:
            logger.info('msg is None..., %s' % (nick))
            return
91
        self.lines.append((datetime.now(), nick.encode('utf-8'),
92 93
                           msg.encode('utf-8'), color))
        return color
94

95 96
    def add_info(self, info):
        """ info, like join/quit/status messages"""
97 98 99
        try:
            self.lines.append((datetime.now(), info.encode('utf-8')))
            return info.encode('utf-8')
100
        except:
101
            self.lines.append((datetime.now(), info))
102
            return info
103

104 105
    def get_user_by_name(self, nick):
        for user in self.users:
106
            if user.nick == nick.encode('utf-8'):
107 108 109
                return user
        return None

110
    def set_color_state(self, color):
111 112
        if self.color_state < color or color == 11:
            self.color_state = color
113

114
    def on_presence(self, stanza, nick):
115 116
        """
        """
117 118 119 120
        affiliation = stanza.getAffiliation()
        show = stanza.getShow()
        status = stanza.getStatus()
        role = stanza.getRole()
121
        if not self.joined:     # user in the room BEFORE us.
122 123 124 125 126
            self.users.append(User(nick, affiliation, show, status, role))
            if nick.encode('utf-8') == self.own_nick:
                self.joined = True
                return self.add_info(_("Your nickname is %s") % (nick))
            return self.add_info(_("%s is in the room") % (nick.encode-('utf-8')))
127
        change_nick = stanza.getStatusCode() == '303'
128
        kick = stanza.getStatusCode() == '307'
129 130 131 132
        user = self.get_user_by_name(nick)
        # New user
        if not user:
            self.users.append(User(nick, affiliation, show, status, role))
133 134 135
            if not config.get('hide_enter_join', "false") == "true":
                return self.add_info(_('%(nick)s joined the room %(roomname)s') % {'nick':nick, 'roomname': self.name})
            return None
136 137 138 139 140
        # nick change
        if change_nick:
            if user.nick == self.own_nick:
                self.own_nick = stanza.getNick().encode('utf-8')
            user.change_nick(stanza.getNick())
141
            return self.add_info(_('%(old_nick)s is now known as %(new_nick)s') % {'old_nick':nick, 'new_nick':stanza.getNick()})
142 143 144 145 146 147 148 149 150 151 152
        # kick
        if kick:
            self.users.remove(user)
            reason = stanza.getReason().encode('utf-8') or ''
            try:
                by = stanza.getActor().encode('utf-8')
            except:
                by = None
            if nick == self.own_nick:
                self.disconnect()
                if by:
153
                    return self.add_info(_('You have been kicked by %(by)s. Reason: %(reason)s') % {'by':by, 'reason':reason})
154
                else:
155
                    return self.add_info(_('You have been kicked. Reason: %s') % (reason))
156 157
            else:
                if by:
158
                    return self.add_info(_('%(nick)s has been kicked by %(by)s. Reason: %(reason)s') % {'nick':nick, 'by':by, 'reason':reason})
159
                else:
160
                    return self.add_info(_('%(nick)s has been kicked. Reason: %(reason)s') % {'nick':nick, 'reason':reason})
161 162 163
        # user quit
        if status == 'offline' or role == 'none':
            self.users.remove(user)
164 165 166
            if not config.get('hide_enter_join', "false") == "true":
                return self.add_info(_('%s has left the room') % (nick))
            return None
167 168
        # status change
        user.update(affiliation, show, status, role)
169 170 171
        if not config.get('hide_status_change', "false") == "true":
            return self.add_info(_('%(nick)s changed his/her status : %(a)s, %(b)s, %(c)s, %(d)s') % {'nick':nick, 'a':affiliation, 'b':role, 'c':show, 'd':status})
        return None
172

173

174 175 176 177
class Gui(object):
    """
    Graphical user interface using ncurses
    """
178
    def __init__(self, stdscr=None, muc=None):
179
        self.room_number = 0
180 181
        self.init_curses(stdscr)
        self.stdscr = stdscr
182
        self.rooms = [Room('Info', '', self.next_room_number())]         # current_room is self.rooms[0]
183
        self.window = Window(stdscr)
184 185 186
        self.window.new_room(self.current_room())
        self.window.refresh(self.rooms)

187 188

        self.muc = muc
189

190
        self.commands = {
191 192 193 194
            'help': (self.command_help, _('OLOL, this is SOOO recursive')),
            'join': (self.command_join, _('Usage: /join [room_name][/nick]\nJoin: Join the specified room. You can specify a nickname after a slash (/). If no nickname is specified, you will use the default_nick in the configuration file. You can omit the room name: you will then join the room you\'re looking at (useful if you were kicked). Examples:\n/join room@server.tld\n/join room@server.tld/John\n/join /me_again\n/join')),
            'quit': (self.command_quit, _('Usage: /quit\nQuit: Just disconnect from the server and exit poezio.')),
            'exit': (self.command_quit, _('Usage: /exit\nExit: Just disconnect from the server and exit poezio.')),
195
            'next': (self.rotate_rooms_right, _('Usage: /next\nNext: Go to the next room.')),
196
            'n': (self.rotate_rooms_right, _('Usage: /n\nN: Go to the next room.')),
197
            'prev': (self.rotate_rooms_left, _('Usage: /prev\nPrev: Go to the previous room.')),
198
            'p': (self.rotate_rooms_left, _('Usage: /p\nP: Go to the previous room.')),
199 200
            'win': (self.command_win, _('Usage: /win <number>\nWin: Go to the specified room.')),
            'w': (self.command_win, _('Usage: /w <number>\nW: Go to the specified room.')),
201
            'part': (self.command_part, _('Usage: /part [message]\nPart: disconnect from a room. You can specify an optional message.')),
202
            'show': (self.command_show, _(u'Usage: /show <availability> [status]\nShow: Change your availability and (optionaly) your status. The <availability> argument is one of "avail, available, ok, here, chat, away, afk, dnd, busy, xa" and the optional [message] argument will be your status message')),
203 204 205
            'away': (self.command_away, _('Usage: /away [message]\nAway: Sets your availability to away and (optional) sets your status message. This is equivalent to "/show away [message]"')),
            'busy': (self.command_busy, _('Usage: /busy [message]\nBusy: Sets your availability to busy and (optional) sets your status message. This is equivalent to "/show busy [message]"')),
            'avail': (self.command_avail, _('Usage: /avail [message]\nAvail: Sets your availability to available and (optional) sets your status message. This is equivalent to "/show available [message]"')),
206 207
            'available': (self.command_avail, _('Usage: /available [message]\nAvailable: Sets your availability to available and (optional) sets your status message. This is equivalent to "/show available [message]"')), 
           'bookmark': (self.command_bookmark, _('Usage: /bookmark [roomname][/nick]\nBookmark: Bookmark the specified room (you will then auto-join it on each poezio start). This commands uses the same syntaxe as /join. Type /help join for syntaxe examples. Note that when typing "/bookmark" on its own, the room will be bookmarked with the nickname you\'re currently using in this room (instead of default_nick)')),
208
            'set': (self.command_set, _('Usage: /set <option> [value]\nSet: Sets the value to the option in your configuration file. You can, for example, change your default nickname by doing `/set default_nick toto` or your resource with `/set resource blabla`. You can also set an empty value (nothing) by providing no [value] after <option>.')),
209
            'kick': (self.command_kick, _('Usage: /kick <nick> [reason]\nKick: Kick the user with the specified nickname. You also can give an optional reason.')),
210
            'nick': (self.command_nick, _('Usage: /nick <nickname>\nNick: Change your nickname in the current room'))
211 212
            }

213 214 215 216 217 218 219
        self.key_func = {
            "KEY_LEFT": self.window.input.key_left,
            "KEY_RIGHT": self.window.input.key_right,
            "KEY_UP": self.window.input.key_up,
            "KEY_END": self.window.input.key_end,
            "KEY_HOME": self.window.input.key_home,
            "KEY_DOWN": self.window.input.key_down,
220
            "KEY_DC": self.window.input.key_dc,
221 222 223 224
            "KEY_F(5)": self.rotate_rooms_left,
            "KEY_F(6)": self.rotate_rooms_right,
            "kLFT5": self.rotate_rooms_left,
            "kRIT5": self.rotate_rooms_right,
225
            "\t": self.auto_completion,
226 227 228
            "KEY_BACKSPACE": self.window.input.key_backspace
            }

229 230 231 232 233 234
        self.handler = Handler()
        self.handler.connect('on-connected', self.on_connected)
        self.handler.connect('join-room', self.join_room)
        self.handler.connect('room-presence', self.room_presence)
        self.handler.connect('room-message', self.room_message)

235 236
    def main_loop(self, stdscr):
        while 1:
237
            stdscr.leaveok(1)
238
            curses.doupdate()
239 240 241 242
            try:
                key = stdscr.getkey()
            except:
                self.window.resize(stdscr)
243
                self.window.refresh(self.rooms)
244
                continue
245
            if str(key) in self.key_func.keys():
246
                self.key_func[key]()
247 248
            elif str(key) == 'KEY_RESIZE':
                self.window.resize(stdscr)
249
                self.window.refresh(self.rooms)
250 251
            elif len(key) >= 4:
                continue
252 253
            elif ord(key) == 10:
                self.execute()
254
            elif ord(key) == 8 or ord(key) == 127:
255
                self.window.input.key_backspace()
256 257
            elif ord(key) < 32:
                continue
258
            else:
259 260 261 262 263
                if ord(key) == 27 and ord(stdscr.getkey()) == 91:
                    last = ord(stdscr.getkey()) # FIXME: ugly ugly workaroung.
                    if last == 51:
                        self.window.input.key_dc()
                    continue
264
                elif ord(key) > 190 and ord(key) < 225:
265 266 267 268 269 270
                    key = key+stdscr.getkey()
                elif ord(key) == 226:
                    key = key+stdscr.getkey()
                    key = key+stdscr.getkey()
                self.window.do_command(key)

271 272 273 274 275
    def next_room_number(self):
        nb = self.room_number
        self.room_number += 1
        return nb

276
    def current_room(self):
277
        return self.rooms[0]
278 279 280 281 282 283 284

    def get_room_by_name(self, name):
	for room in self.rooms:
	    if room.name == name:
		return room
	return None

285 286 287
    def init_curses(self, stdscr):
        curses.start_color()
        curses.noecho()
288 289 290
        curses.cbreak()
        curses.raw()
        curses.use_default_colors()
291
        stdscr.keypad(True)
292
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
293 294 295 296 297 298 299 300
        curses.init_pair(2, curses.COLOR_BLUE, -1)
        curses.init_pair(3, curses.COLOR_RED, -1) # Admin
        curses.init_pair(4, curses.COLOR_BLUE, -1) # Participant
        curses.init_pair(5, curses.COLOR_WHITE, -1) # Visitor
        curses.init_pair(6, curses.COLOR_CYAN, -1)
        curses.init_pair(7, curses.COLOR_GREEN, -1)
        curses.init_pair(8, curses.COLOR_MAGENTA, -1)
        curses.init_pair(9, curses.COLOR_YELLOW, -1)
301
        curses.init_pair(10, curses.COLOR_WHITE, curses.COLOR_CYAN) # current room
302
        curses.init_pair(11, curses.COLOR_WHITE, curses.COLOR_BLUE) # normal room
303
        curses.init_pair(12, curses.COLOR_WHITE, curses.COLOR_MAGENTA) # new message room
304
        curses.init_pair(13, curses.COLOR_WHITE, curses.COLOR_RED) # highlight room
305 306
        curses.init_pair(14, curses.COLOR_WHITE, curses.COLOR_YELLOW)
        curses.init_pair(15, curses.COLOR_WHITE, curses.COLOR_GREEN)
307

308 309
    def reset_curses(self):
	curses.echo()
310
        curses.nocbreak()
311
        curses.endwin()
312

313
    def on_connected(self, jid):
314 315
        self.information(_("Welcome on Poezio \o/!"))
        self.information(_("Your JID is %s") % jid)
316 317

    def join_room(self, room, nick):
318 319 320 321 322 323 324 325 326 327 328 329 330
        r = Room(room, nick, self.next_room_number())
        self.current_room().set_color_state(11)
        if self.current_room().nb == 0:
            self.rooms.append(r)
        else:
            for ro in self.rooms:
                if ro.nb == 0:
                    self.rooms.insert(self.rooms.index(ro), r)
                    break
        while self.current_room().nb != r.nb:
            self.rooms.insert(0, self.rooms.pop())
        self.window.new_room(r)
        self.window.refresh(self.rooms)
331

332 333 334
    def auto_completion(self):
        self.window.input.auto_completion(self.current_room().users)

335 336
    def rotate_rooms_right(self, args=None):
        self.current_room().set_color_state(11)
337
        self.rooms.append(self.rooms.pop(0))
338
        self.window.refresh(self.rooms)
339

340 341
    def rotate_rooms_left(self, args=None):
        self.current_room().set_color_state(11)
342
        self.rooms.insert(0, self.rooms.pop())
343
        self.window.refresh(self.rooms)
344 345

    def room_message(self, stanza):
346
        if len(sys.argv) > 1:
louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13's avatar
?  
347
            self.information(str(stanza).encode('utf-8'))
348 349 350 351
        if stanza.getType() != 'groupchat':
            return  # ignore all messages not comming from a MUC
        room_from = stanza.getFrom().getStripped()
        nick_from = stanza.getFrom().getResource()
352 353 354
        if not nick_from:
            nick_from = ''
	room = self.get_room_by_name(room_from)
355
	if not room:
356
	    self.information(_("message received for a non-existing room: %s") % (room_from))
357
            return
358
        body = stanza.getBody()
359 360
        subject = stanza.getSubject()
        if subject:
361 362 363 364
            if nick_from:
                info = room.add_info(_("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject})
            else:
                info = room.add_info(_("The subject is: %(subject)s") % {'subject':subject})
365
            self.window.text_win.add_line(room, (datetime.now(), info))
366
            room.topic = subject.encode('utf-8').replace('\n', '|')
367 368
            if room == self.current_room():
                self.window.topic_win.refresh(room.topic)
369
                self.window.text_win.refresh(room.name)
370
        else:
371 372 373 374 375 376
            if body.startswith('/me'):
                info = room.add_info(nick_from + ' ' + body[4:])
                self.window.text_win.add_line(room, (datetime.now(), info))
            else:
                color = room.add_message(nick_from, body)
                self.window.text_win.add_line(room, (datetime.now(), nick_from.encode('utf-8'), body.encode('utf-8'), color))
louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13's avatar
?  
377
        if room.name == self.current_room().name:
378
            self.window.text_win.refresh(room.name)
379
            self.window.input.refresh()
380 381
        else:
            self.window.info_win.refresh(self.rooms, self.current_room())
382
        curses.doupdate()
383 384

    def room_presence(self, stanza):
385 386
        if len(sys.argv) > 1:
            self.information(str(stanza))
387 388
        from_nick = stanza.getFrom().getResource()
        from_room = stanza.getFrom().getStripped()
389
	room = self.get_room_by_name(from_room)
390
	if not room:
391
	    self.information(_("presence received for a non-existing room: %s") % (from_room))
392
        if stanza.getType() == 'error':
393
            msg = _("Error: %s") % stanza.getError()
394 395
        else:
            msg = room.on_presence(stanza, from_nick)
396 397 398
            if room == self.current_room():
                self.window.user_win.refresh(room.users)
        if room == self.current_room() and msg:
399
            self.window.text_win.add_line(room, (datetime.now(), msg))
400
            self.window.text_win.refresh(room.name)
louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13's avatar
?  
401
            self.window.input.refresh()
402
        curses.doupdate()
403 404

    def execute(self):
405 406
        line = self.window.input.get_text()
        self.window.input.clear_text()
407
        self.window.input.refresh()
408 409
        if line == "":
            return
410
        if line.startswith('/'):
411 412 413
            command = line.strip()[:].split()[0][1:]
            args = line.strip()[:].split()[1:]
            if command in self.commands.keys():
414
                func = self.commands[command][0]
415
                func(args)
416
                return
417 418 419 420 421
            else:
                info = self.current_room().add_info(_("Error: unknown command (%s)") % (command))
                self.window.text_win.add_line(self.current_room(), (datetime.now(), info))
                self.window.text_win.refresh(self.current_room().name)
        elif self.current_room().name != 'Info':
422
            self.muc.send_message(self.current_room().name, line)
423
        curses.doupdate()
424
	self.window.input.refresh()
425

426 427 428
    def command_help(self, args):
        room = self.current_room()
        if len(args) == 0:
429
            msg = _('Available commands are:')
430 431
            for command in self.commands.keys():
                msg += "%s " % command
432
            msg += _("\nType /help <command_name> to know what each command does")
433 434 435 436
        if len(args) == 1:
            if args[0] in self.commands.keys():
                msg = self.commands[args[0]][1]
            else:
437
                msg = _('Unknown command: %s') % args[0]
438
        room.add_info(msg)
439
        self.window.text_win.add_line(room, (datetime.now(), msg))
440 441 442
        self.window.text_win.refresh(room.name)
        self.window.input.refresh()

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
    def command_win(self, args):
        if len(args) != 1:
            self.command_help(['win'])
            return
        try:
            nb = int(args[0])
        except ValueError:
            self.command_help(['win'])
            return
        if self.current_room().nb == nb:
            return
        self.current_room().set_color_state(11)
        start = self.current_room()
        self.rooms.append(self.rooms.pop(0))
        while self.current_room().nb != nb:
            self.rooms.append(self.rooms.pop(0))
            if self.current_room() == start:
                self.window.refresh(self.rooms)
                return
        self.window.refresh(self.rooms)


465 466 467 468 469 470 471 472 473 474 475 476 477 478
    def command_kick(self, args):
        if len(args) < 1:
            self.command_help(['kick'])
            return
        nick = args[0]
        if len(args) >= 2:
            reason = ' '.join(args[1:])
        else:
            reason = ''
        if self.current_room().name == 'Info' or not self.current_room().joined:
            return
        roomname = self.current_room().name
        self.muc.eject_user(roomname, 'kick', nick, reason)

479
    def command_join(self, args):
480 481 482 483 484 485
        if len(args) == 0:
            r = self.current_room()
            if r.name == 'Info':
                return
            room = r.name
            nick = r.own_nick
486
        else:
487 488 489 490 491
            info = args[0].split('/')
            if len(info) == 1:
                nick = config.get('default_nick', 'Poezio')
            else:
                nick = info[1]
492
            if info[0] == '':   # happens with /join /nickname, which is OK
493 494 495 496 497 498 499
                r = self.current_room()
                if r.name == 'Info':
                    return
                room = r.name
            else:
                room = info[0]
            r = self.get_room_by_name(room)
500
        if r and r.joined:                   # if we are already in the room
501
            self.information(_("already in room [%s]") % room)
502
            return
503
        self.muc.join_room(room, nick)
504
        if not r: # if the room window exists, we don't recreate it.
505
            self.join_room(room, nick)
506

507 508 509 510 511 512 513 514 515 516 517 518 519 520
    def command_bookmark(self, args):
        nick = None
        if len(args) == 0:
            room = self.current_room()
            if room.name == 'Info':
                return
            roomname = room.name
            if room.joined:
                nick = room.own_nick
        else:
            info = args[0].split('/')
            if len(info) == 2:
                nick = info[1]
            roomname = info[0]
521 522
            if roomname == '':
                roomname = self.current_room().name
523 524 525 526
        if nick:
            res = roomname+'/'+nick
        else:
            res = roomname
527 528 529 530 531 532 533 534 535
        bookmarked = config.get('rooms', '')
        # check if the room is already bookmarked.
        # if yes, replace it (i.e., update the associated nick)
        bookmarked = bookmarked.split(':')
        for room in bookmarked:
            if room.split('/')[0] == roomname:
                bookmarked.remove(room)
                break
        bookmarked = ':'.join(bookmarked)
536
        config.set_and_save('rooms', bookmarked+':'+res)
537

538
    def command_set(self, args):
539
        if len(args) != 2 and len(args) != 1:
540 541 542
            self.command_help(['set'])
            return
        option = args[0]
543 544 545 546
        if len(args) == 2:
            value = args[1]
        else:
            value = ''
547
        config.set_and_save(option, value)
548 549 550
        msg = "%s=%s" % (option, value)
        room = self.current_room()
        room.add_info(msg)
551
        self.window.text_win.add_line(room, (datetime.now(), msg))
552 553 554
        self.window.text_win.refresh(room.name)
        self.window.input.refresh()

555
    def command_show(self, args):
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
        possible_show = {'avail':'None',
                         'available':'None',
                         'ok':'None',
                         'here':'None',
                         'chat':'chat',
                         'away':'away',
                         'afk':'away',
                         'dnd':'dnd',
                         'busy':'dnd',
                         'xa':'xa'
                         }
        if len(args) < 1:
            return
        if not args[0] in possible_show.keys():
            self.command_help(['show'])
            return
        show = possible_show[args[0]]
        if len(args) > 1:
            msg = ' '.join(args[1:])
        else:
            msg = None
        for room in self.rooms:
            if room.joined:
                self.muc.change_show(room.name, room.own_nick, show, msg)

    def command_away(self, args):
        args.insert(0, 'away')
        self.command_show(args)

    def command_busy(self, args):
        args.insert(0, 'busy')
        self.command_show(args)

    def command_avail(self, args):
        args.insert(0, 'available')
        self.command_show(args)
592

593 594 595 596 597 598 599 600 601
    def command_part(self, args):
        reason = None
        room = self.current_room()
        if room.name == 'Info':
            return
        if len(args):
            msg = ' '.join(args)
        else:
            msg = None
602 603
        if room.joined:
            self.muc.quit_room(room.name, room.own_nick, msg)
604
        self.rooms.remove(self.current_room())
605
        self.window.refresh(self.rooms)
606

607 608 609 610 611 612 613 614 615
    def command_nick(self, args):
        if len(args) != 1:
            return
        nick = args[0]
        room = self.current_room()
        if not room.joined or room.name == "Info":
            return
        self.muc.change_nick(room.name, nick)

616 617 618
    def information(self, msg):
        room = self.get_room_by_name("Info")
        info = room.add_info(msg)
619
        if self.current_room() == room:
620
            self.window.text_win.add_line(room, (datetime.now(), info))
621 622
            self.window.text_win.refresh(room.name)
            curses.doupdate()
623

624
    def command_quit(self, args):
625
	self.reset_curses()
626
        sys.exit()