gui.py 28.2 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
from datetime import datetime
33 34

import common
35

36
from handler import Handler
37
from config import config
38
from window import Window
39 40
from user import User
from room import Room
41

42 43
class Gui(object):
    """
44
    User interface using ncurses
45
    """
46
    def __init__(self, stdscr=None, muc=None):
47
        self.room_number = 0
48 49
        self.init_curses(stdscr)
        self.stdscr = stdscr
50
        self.rooms = [Room('Info', '', self.next_room_number())]
51
        self.window = Window(stdscr)
52 53 54
        self.window.new_room(self.current_room())
        self.window.refresh(self.rooms)

55
        self.muc = muc
56

57
        self.commands = {
58
            'help': (self.command_help, _('OLOL, this is SOOO recursive')),
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
            'join': (self.command_join, _("""Usage: /join [room_name][/nick]
[password]\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). You can also provide a password
 to join the room.\nExamples:\n/join room@server.tld\n/join room@server.tld/
 John\n/join /me_again\n/join\n/join room@server.tld/my_nick password\n/join /
 pass""")),
            '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.""")),
            'next': (self.rotate_rooms_right, _("""Usage: /next\nNext:
 Go to the next room.""")),
            'n': (self.rotate_rooms_right, _("""Usage: /n\nN: Go to the
 next room.""")),
            'prev': (self.rotate_rooms_left, _("""Usage: /prev\nPrev:
 Go to the previous room.""")),
            'p': (self.rotate_rooms_left, _("""Usage: /p\nP: Go to the
 previous room.""")),
            '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.""")),
            'ignore': (self.command_ignore, _("""Usage: /ignore <nickname>
\Ignore: Ignore a specified nickname.""")),
            'unignore': (self.command_unignore, _("""Usage: /unignore
 <nickname>\Unignore: Remove the specified nickname from the ignore list.""")),
            'part': (self.command_part, _("""Usage: /part [message]\n
Part: disconnect from a room. You can specify an optional message.""")),
            'show': (self.command_show, _("""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""")),
            '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]\n
Avail: Sets your availability to available and (optional) sets your status
 message. This is equivalent to '/show available [message]'""")),
            '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)""")),
            '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>.""")),
            'kick': (self.command_kick, _("""Usage: /kick <nick>
 [reason]\nKick: Kick the user with the specified nickname.
 You also can give an optional reason.""")),
            'topic': (self.command_topic, _("""Usage: /topic <subject>
\nTopic: Change the subject of the room""")),
            'nick': (self.command_nick, _("""Usage: /nick <nickname>
\nNick: Change your nickname in the current room"""))
126 127
            }

128 129 130 131 132 133 134
        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,
135
            "KEY_DC": self.window.input.key_dc,
136 137 138 139
            "KEY_F(5)": self.rotate_rooms_left,
            "KEY_F(6)": self.rotate_rooms_right,
            "kLFT5": self.rotate_rooms_left,
            "kRIT5": self.rotate_rooms_right,
140
            "\t": self.auto_completion,
141 142 143
            "KEY_BACKSPACE": self.window.input.key_backspace
            }

144 145 146 147 148
        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)
149
        self.handler.connect('error-message', self.room_error)
150
        self.handler.connect('error', self.information)
151

152
    def main_loop(self, stdscr):
153 154 155
        """
        main loop waiting for the user to press a key
        """
156
        while 1:
157
            stdscr.leaveok(1)
158
            curses.doupdate()
159 160 161
            try:
                key = stdscr.getkey()
            except:
162
                continue
163
            if str(key) in self.key_func.keys():
164
                self.key_func[key]()
165 166
            elif str(key) == 'KEY_RESIZE':
                self.window.resize(stdscr)
167
                self.window.refresh(self.rooms)
168 169
            elif len(key) >= 4:
                continue
170 171
            elif ord(key) == 10:
                self.execute()
172
            elif ord(key) == 8 or ord(key) == 127:
173
                self.window.input.key_backspace()
174 175
            elif ord(key) < 32:
                continue
176
            else:
177
                if ord(key) == 27 and ord(stdscr.getkey()) == 91:
178
                    last = ord(stdscr.getkey()) # FIXME: ugly ugly workaround.
179 180 181
                    if last == 51:
                        self.window.input.key_dc()
                    continue
182
                elif ord(key) > 190 and ord(key) < 225:
183 184 185 186 187 188
                    key = key+stdscr.getkey()
                elif ord(key) == 226:
                    key = key+stdscr.getkey()
                    key = key+stdscr.getkey()
                self.window.do_command(key)

189
    def next_room_number(self):
190 191 192
        """
        Increments the room number and returns the new number
        """
193 194 195 196
        nb = self.room_number
        self.room_number += 1
        return nb

197
    def current_room(self):
198 199 200
        """
        returns the current room, the one we are viewing
        """
201
        return self.rooms[0]
202 203

    def get_room_by_name(self, name):
204 205 206 207 208 209 210
        """
        returns the room that has this name
        """
        for room in self.rooms:
            if room.name == name:
                return room
        return None
211

212
    def init_curses(self, stdscr):
213 214 215
        """
        ncurses initialization
        """
216 217
        curses.start_color()
        curses.noecho()
218 219
        # curses.cbreak()
        # curses.raw()
220
        curses.use_default_colors()
221
        stdscr.keypad(True)
222 223
        curses.init_pair(1, curses.COLOR_WHITE,
                         curses.COLOR_BLUE)
224 225 226 227 228 229 230 231
        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)
232 233 234 235 236 237 238 239 240 241 242 243
        curses.init_pair(10, curses.COLOR_WHITE,
                         curses.COLOR_CYAN) # current room
        curses.init_pair(11, curses.COLOR_WHITE,
                         curses.COLOR_BLUE) # normal room
        curses.init_pair(12, curses.COLOR_WHITE,
                         curses.COLOR_MAGENTA) # new message room
        curses.init_pair(13, curses.COLOR_WHITE,
                         curses.COLOR_RED) # highlight room
        curses.init_pair(14, curses.COLOR_WHITE,
                         curses.COLOR_YELLOW)
        curses.init_pair(15, curses.COLOR_WHITE,
                         curses.COLOR_GREEN)
244

245
    def reset_curses(self):
246 247 248 249 250
        """
        Reset terminal capabilities to what they were before ncurses
        init
        """
        curses.echo()
251
        curses.nocbreak()
252
        curses.endwin()
253

254
    def on_connected(self, jid):
255 256 257
        """
        When we are connected authentification confirmation is received
        """
258 259
        self.information(_("Welcome on Poezio \o/!"))
        self.information(_("Your JID is %s") % jid)
260 261

    def join_room(self, room, nick):
262 263 264
        """
        join the specified room (muc), using the specified nick
        """
265 266 267 268 269 270 271 272 273 274 275 276 277
        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)
278

279
    def auto_completion(self):
280 281 282
        """
        Called when Tab is pressed, complete the nickname in the input
        """
283 284
        self.window.input.auto_completion(self.current_room().users)

285
    def rotate_rooms_right(self, args=None):
286 287 288
        """
        rotate the rooms list to the right
        """
289
        self.current_room().set_color_state(11)
290
        self.rooms.append(self.rooms.pop(0))
291
        self.window.refresh(self.rooms)
292

293
    def rotate_rooms_left(self, args=None):
294 295 296
        """
        rotate the rooms list to the right
        """
297
        self.current_room().set_color_state(11)
298
        self.rooms.insert(0, self.rooms.pop())
299
        self.window.refresh(self.rooms)
300

301
    def room_error(self, room, error, msg):
302 303 304 305
        """
        Display the error on the room window
        """
        room = self.get_room_by_name(room)
306 307 308
        code = error.getAttr('code')
        typ = error.getAttr('type')
        body = error.getTag('text').getData()
309
        self.add_info(room, _('Error: %(code)s-%(msg)s: %(body)s' %
310
                           {'msg':msg, 'code':code, 'body':body}))
311
        if code == '401':
312 313 314
            self.add_info(room, _("""To provide a password in order
 to join the room, type "/join / password" (replace "password"
 by the real password)"""))
315

316
    def room_message(self, stanza, date=None):
317 318 319
        """
        Display the message on the room window
        """
320 321 322 323 324 325
        delay_tag = stanza.getTag('delay', namespace='urn:xmpp:delay')
        if delay_tag and not date:
            delayed = True
            date = common.datetime_tuple(delay_tag.getAttr('stamp'))
        else:
            delayed = False
326 327 328
        if stanza.getType() != 'groupchat':
            return  # ignore all messages not comming from a MUC
        nick_from = stanza.getFrom().getResource()
329 330
        room_from = stanza.getFrom().getStripped()
        room = self.get_room_by_name(room_from)
331
	if not room:
332
	    self.information(_("message received for a non-existing room: %s") % (room_from))
333
            return
334
        body = stanza.getBody()
335 336
        subject = stanza.getSubject()
        if subject:
337
            if nick_from:
338 339
                self.add_info(room, _("""%(nick)s changed the subject to:
 %(subject)s""") % {'nick':nick_from, 'subject':subject}, date)
340
            else:
341 342
                self.add_info(room, _("The subject is: %(subject)s") %
                              {'subject':subject}, date)
343
            room.topic = subject.encode('utf-8').replace('\n', '|')
344 345
            if room == self.current_room():
                self.window.topic_win.refresh(room.topic)
346
        elif body:
347 348
            if body.startswith('/me '):
                self.add_info(room, nick_from + ' ' + body[4:], date)
349
            else:
350
                self.add_message(room, nick_from, body, date, delayed)
351
        self.window.input.refresh()
352
        curses.doupdate()
353 354

    def room_presence(self, stanza):
355 356 357 358
        """
        Display the presence on the room window and update the
        presence information of the concerned user
        """
359 360
        if len(sys.argv) > 1:
            self.information(str(stanza))
361 362
        from_nick = stanza.getFrom().getResource()
        from_room = stanza.getFrom().getStripped()
363
	room = self.get_room_by_name(from_room)
364
	if not room:
365
            return
366
        else:
367 368 369 370 371 372
            msg = None
            affiliation = stanza.getAffiliation()
            show = stanza.getShow()
            status = stanza.getStatus()
            role = stanza.getRole()
            if not room.joined:     # user in the room BEFORE us.
373 374
                room.users.append(User(from_nick, affiliation, show, status,
                                       role))
375 376 377 378
                if from_nick.encode('utf-8') == room.own_nick:
                    room.joined = True
                    self.add_info(room, _("Your nickname is %s") % (from_nick))
                else:
379 380
                    self.add_info(room, _("%s is in the room") %
                                  (from_nick.encode('utf-8')))
381 382 383 384 385 386
            else:
                change_nick = stanza.getStatusCode() == '303'
                kick = stanza.getStatusCode() == '307'
                user = room.get_user_by_name(from_nick)
                # New user
                if not user:
387 388
                    room.users.append(User(from_nick, affiliation,
                                           show, status, role))
389 390
                    hide_exit_join = config.get('hide_exit_join', -1)
                    if hide_exit_join != 0:
391 392
                        self.add_info(room, _("""%(nick)s joined the
 room %(roomname)s""") % {'nick':from_nick, 'roomname': room.name})
393 394 395 396 397
                # nick change
                elif change_nick:
                    if user.nick == room.own_nick:
                        room.own_nick = stanza.getNick().encode('utf-8')
                    user.change_nick(stanza.getNick())
398 399 400 401
                    self.add_info(room,
                                  _('%(old)s is now known as %(new)s') %
                                  {'old':from_nick,
                                     'new':stanza.getNick()})
402 403 404
                # kick
                elif kick:
                    room.users.remove(user)
405 406 407 408
                    try:
                        reason = stanza.getReason().encode('utf-8')
                    except:
                        reason = ''
409 410 411 412 413 414 415
                    try:
                        by = stanza.getActor().encode('utf-8')
                    except:
                        by = None
                    if from_nick == room.own_nick: # we are kicked
                        room.disconnect()
                        if by:
416 417
                            self.add_info(room, _("""You have been kicked by
 %(by)s. Reason: %(reason)s""") % {'by':by, 'reason':reason})
418
                        else:
419 420
                            self.add_info(room, _("""You have been
 kicked. Reason: %s""") % (reason))
421 422
                    else:
                        if by:
423 424 425
                            self.add_info(room, _("""%(nick)s has been kicked
                                         by %(by)s. Reason: %(reason)s""") %
                                          {'nick':from_nick, 'by':by, 'reason':reason})
426
                        else:
427 428 429
                            self.add_info(room, _("""%(nick)s has been kicked.
                                                 Reason: %(reason)s""") %
                                          {'nick':from_nick, 'reason':reason})
430 431 432
                # user quit
                elif status == 'offline' or role == 'none':
                    room.users.remove(user)
433 434 435 436 437
                    hide_exit_join = config.get('hide_exit_join', -1)\
                        if config.get('hide_exit_join', -1) >= -1\
                        else -1
                    if hide_exit_join == -1 or \
                            user.has_talked_since(hide_exit_join):
438 439 440 441
                        self.add_info(room, _('%s has left the room') % (from_nick))
                # status change
                else:
                    user.update(affiliation, show, status, role)
442 443 444 445 446 447
                    hide_status_change = config.get('hide_status_change', -1)\
                        if config.get('hide_status_change', -1) >= -1\
                        else -1
                    if hide_status_change == -1 or \
                            user.has_talked_since(hide_status_change) or\
                            user.nick == room.own_nick:
448
                        self.add_info(room, _('%(nick)s changed his/her status : %(a)s, %(b)s, %(c)s, %(d)s') % {'nick':from_nick, 'a':affiliation, 'b':role, 'c':show, 'd':status})
449 450
            if room == self.current_room():
                self.window.user_win.refresh(room.users)
451 452
        self.window.input.refresh()
        curses.doupdate()
453 454 455 456 457 458 459

    def add_info(self, room, info, date=None):
        """
        add a new information in the specified room
        (displays it immediately AND saves it for redisplay
        in futur refresh)
        """
460 461
        if not date:
            date = datetime.now()
462
        msg = room.add_info(info, date)
463
        self.window.text_win.add_line(room, (date, msg))
464
        if room.name == self.current_room().name:
465
            self.window.text_win.refresh(room.name)
louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13's avatar
?  
466
            self.window.input.refresh()
467 468
            curses.doupdate()

469
    def add_message(self, room, nick_from, body, date=None, delayed=False):
470 471 472
        """
        Just add a message
        """
473 474
        if not date:
            date = datetime.now()
475 476 477 478
        color = room.add_message(nick_from, body, date)
        self.window.text_win.add_line(room, (date, nick_from.encode('utf-8'), body.encode('utf-8'), color))
        if room == self.current_room():
            self.window.text_win.refresh(room.name)
479
        elif not delayed:
480
            self.window.info_win.refresh(self.rooms, self.current_room())
481 482

    def execute(self):
483 484 485
        """
        Execute the /command or just send the line on the current room
        """
486 487
        line = self.window.input.get_text()
        self.window.input.clear_text()
488
        self.window.input.refresh()
489 490
        if line == "":
            return
491
        if line.startswith('/'):
492 493 494
            command = line.strip()[:].split()[0][1:]
            args = line.strip()[:].split()[1:]
            if command in self.commands.keys():
495
                func = self.commands[command][0]
496
                func(args)
497
                return
498
            else:
499
                self.add_info(self.current_room(), _("Error: unknown command (%s)") % (command))
500
        elif self.current_room().name != 'Info':
501
            self.muc.send_message(self.current_room().name, line)
502
        self.window.input.refresh()
503
        curses.doupdate()
504

505
    def command_help(self, args):
506 507 508
        """
        /help <command_name>
        """
509 510
        room = self.current_room()
        if len(args) == 0:
511
            msg = _('Available commands are:')
512 513
            for command in self.commands.keys():
                msg += "%s " % command
514
            msg += _("\nType /help <command_name> to know what each command does")
515 516 517 518
        if len(args) == 1:
            if args[0] in self.commands.keys():
                msg = self.commands[args[0]][1]
            else:
519
                msg = _('Unknown command: %s') % args[0]
520
        self.add_info(room, msg)
521

522
    def command_win(self, args):
523 524 525
        """
        /win <number>
        """
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
        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)

546
    def command_kick(self, args):
547 548 549
        """
        /kick <nick> [reason]
        """
550 551 552 553 554 555 556 557 558 559 560 561 562
        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)

563
    def command_join(self, args):
564 565 566
        """
        /join [room][/nick] [password]
        """
567
        password = None
568 569 570 571 572 573
        if len(args) == 0:
            r = self.current_room()
            if r.name == 'Info':
                return
            room = r.name
            nick = r.own_nick
574
        else:
575 576 577 578 579
            info = args[0].split('/')
            if len(info) == 1:
                nick = config.get('default_nick', 'Poezio')
            else:
                nick = info[1]
580
            if info[0] == '':   # happens with /join /nickname, which is OK
581 582 583 584
                r = self.current_room()
                if r.name == 'Info':
                    return
                room = r.name
585 586
                if nick == '':
                    nick = r.own_nick
587 588 589
            else:
                room = info[0]
            r = self.get_room_by_name(room)
590 591
        if len(args) == 2:       # a password is provided
            password = args[1]
592
        if r and r.joined:                   # if we are already in the room
593
            self.information(_("already in room [%s]") % room)
594
            return
595
        self.muc.join_room(room, nick, password)
596
        if not r:   # if the room window exists, we don't recreate it.
597
            self.join_room(room, nick)
598
        else:
599
            r.own_nick = nick
600
            r.users = []
601

602
    def command_bookmark(self, args):
603 604 605
        """
        /bookmark [room][/nick]
        """
606 607 608 609 610 611 612 613 614 615 616 617 618
        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]
619 620
            if roomname == '':
                roomname = self.current_room().name
621 622 623 624
        if nick:
            res = roomname+'/'+nick
        else:
            res = roomname
625 626 627 628 629 630 631 632 633
        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)
634
        config.set_and_save('rooms', bookmarked+':'+res)
635

636
    def command_set(self, args):
637 638 639
        """
        /set <option> [value]
        """
640
        if len(args) != 2 and len(args) != 1:
641 642 643
            self.command_help(['set'])
            return
        option = args[0]
644 645 646 647
        if len(args) == 2:
            value = args[1]
        else:
            value = ''
648
        config.set_and_save(option, value)
649 650
        msg = "%s=%s" % (option, value)
        room = self.current_room()
651
        self.add_info(room, msg)
652

653
    def command_show(self, args):
654 655 656
        """
        /show <status> [msg]
        """
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
        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)

682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
    def command_ignore(self, args):
        """
        /ignore <nick>
        """
        # TODO
        if len(args) != 1:
            self.command_help([ignore])
            return

    def command_unignore(self, args):
        """
        /unignore <nick>
        """
        # TODO
        if len(args) != 1:
            self.command_help([ignore])
            return

700
    def command_away(self, args):
701 702 703
        """
        /away [msg]
        """
704 705 706 707
        args.insert(0, 'away')
        self.command_show(args)

    def command_busy(self, args):
708 709 710
        """
        /busy [msg]
        """
711 712 713 714
        args.insert(0, 'busy')
        self.command_show(args)

    def command_avail(self, args):
715 716 717
        """
        /avail [msg]
        """
718 719
        args.insert(0, 'available')
        self.command_show(args)
720

721
    def command_part(self, args):
722 723 724
        """
        /part [msg]
        """
725 726 727 728 729 730 731 732
        reason = None
        room = self.current_room()
        if room.name == 'Info':
            return
        if len(args):
            msg = ' '.join(args)
        else:
            msg = None
733 734
        if room.joined:
            self.muc.quit_room(room.name, room.own_nick, msg)
735
        self.rooms.remove(self.current_room())
736
        self.window.refresh(self.rooms)
737

738
    def command_topic(self, args):
739 740 741
        """
        /topic [new topic]
        """
742 743 744 745 746 747
        subject = ' '.join(args)
        room = self.current_room()
        if not room.joined or room.name == "Info":
            return
        self.muc.change_subject(room.name, subject)

748
    def command_nick(self, args):
749 750 751
        """
        /nick <nickname>
        """
752 753 754 755 756 757 758 759
        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)

760
    def information(self, msg):
761 762 763
        """
        Displays an informational message in the "Info" room window
        """
764
        room = self.get_room_by_name("Info")
765
        self.add_info(room, msg)
766

767
    def command_quit(self, args):
768 769 770
        """
        /quit
        """
771
	self.reset_curses()
772
        sys.exit()