gui.py 29.7 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 44 45 46
from message import Message

from common import debug
def doupdate():
    debug("doupdate")
    curses.doupdate()
47

48 49
class Gui(object):
    """
50
    User interface using ncurses
51
    """
52 53 54 55
    def __init__(self, stdscr=None, muc=None):
        self.init_curses(stdscr)
        self.stdscr = stdscr
        self.window = Window(stdscr)
56 57 58
        # self.window.new_room(self.current_room())
        # self.window.refresh(self.rooms)
        self.rooms = [Room('Info', '', self.window)]
59
        self.ignores = {}
60

61
        self.muc = muc
62

63
        self.commands = {
64
            'help': (self.command_help, u'\_o< KOIN KOIN KOIN'),
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
            '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]\nAvail: 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"))
87 88
            }

89 90 91 92 93 94 95
        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,
96 97
            "KEY_PPAGE": self.scroll_page_up,
            "KEY_NPAGE": self.scroll_page_down,
98
            "KEY_DC": self.window.input.key_dc,
99 100 101 102
            "KEY_F(5)": self.rotate_rooms_left,
            "KEY_F(6)": self.rotate_rooms_right,
            "kLFT5": self.rotate_rooms_left,
            "kRIT5": self.rotate_rooms_right,
103
            "\t": self.auto_completion,
104 105 106
            "KEY_BACKSPACE": self.window.input.key_backspace
            }

107 108 109 110 111
        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)
112
        self.handler.connect('error-message', self.room_error)
113
        self.handler.connect('error', self.information)
114

115
    def main_loop(self, stdscr):
116 117 118
        """
        main loop waiting for the user to press a key
        """
119
        while 1:
120 121
            # stdscr.leaveok(1)
            doupdate()
122 123 124
            try:
                key = stdscr.getkey()
            except:
125
                continue
126 127
            from common import debug
            # debug(str(key))
128
            if str(key) in self.key_func.keys():
129
                self.key_func[key]()
130 131
            elif str(key) == 'KEY_RESIZE':
                self.window.resize(stdscr)
132
                self.window.refresh(self.rooms)
133 134
            elif len(key) >= 4:
                continue
135 136
            elif ord(key) == 10:
                self.execute()
137
            elif ord(key) == 8 or ord(key) == 127:
138
                self.window.input.key_backspace()
139 140
            elif ord(key) < 32:
                continue
141
            else:
142
                if ord(key) == 27 and ord(stdscr.getkey()) == 91:
143
                    last = ord(stdscr.getkey()) # FIXME: ugly ugly workaround.
144 145 146
                    if last == 51:
                        self.window.input.key_dc()
                    continue
147
                elif ord(key) > 190 and ord(key) < 225:
148 149 150 151 152 153
                    key = key+stdscr.getkey()
                elif ord(key) == 226:
                    key = key+stdscr.getkey()
                    key = key+stdscr.getkey()
                self.window.do_command(key)

154
    def current_room(self):
155 156 157
        """
        returns the current room, the one we are viewing
        """
158
        return self.rooms[0]
159 160

    def get_room_by_name(self, name):
161 162 163 164 165 166 167
        """
        returns the room that has this name
        """
        for room in self.rooms:
            if room.name == name:
                return room
        return None
168

169
    def init_curses(self, stdscr):
170 171 172
        """
        ncurses initialization
        """
173 174
        curses.start_color()
        curses.noecho()
175
        curses.curs_set(0)
176
        curses.use_default_colors()
177
        stdscr.keypad(True)
178 179
        curses.init_pair(1, curses.COLOR_WHITE,
                         curses.COLOR_BLUE)
180 181 182
        curses.init_pair(4, curses.COLOR_CYAN, -1)
        curses.init_pair(2, curses.COLOR_RED, -1) # Admin
        curses.init_pair(3, curses.COLOR_BLUE, -1) # Participant
183 184 185 186 187
        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)
188 189 190 191 192 193 194 195 196 197 198 199
        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)
200

201
    def reset_curses(self):
202 203 204 205 206
        """
        Reset terminal capabilities to what they were before ncurses
        init
        """
        curses.echo()
207
        curses.nocbreak()
208
        curses.endwin()
209

210
    def on_connected(self, jid):
211
        """
212
        We are connected when authentification confirmation is received
213
        """
214 215
        self.information(_("Welcome on Poezio \o/!"))
        self.information(_("Your JID is %s") % jid)
216 217

    def join_room(self, room, nick):
218 219 220
        """
        join the specified room (muc), using the specified nick
        """
221
        r = Room(room, nick, self.window)
222 223 224 225 226 227 228 229 230 231 232
        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.refresh(self.rooms)
233

234
    def auto_completion(self):
235 236 237
        """
        Called when Tab is pressed, complete the nickname in the input
        """
238 239
        self.window.input.auto_completion(self.current_room().users)

240
    def rotate_rooms_right(self, args=None):
241 242 243
        """
        rotate the rooms list to the right
        """
244
        self.current_room().set_color_state(11)
245
        self.rooms.append(self.rooms.pop(0))
246
        self.window.refresh(self.rooms)
247

248
    def rotate_rooms_left(self, args=None):
249 250 251
        """
        rotate the rooms list to the right
        """
252
        self.current_room().set_color_state(11)
253
        self.rooms.insert(0, self.rooms.pop())
254
        self.window.refresh(self.rooms)
255

256 257 258 259 260
    def scroll_page_down(self, args=None):
        self.current_room().scroll_down()
        self.window.text_win.refresh(self.current_room())

    def scroll_page_up(self, args=None):
261
        self.current_room().scroll_up(self.window.size)
262 263
        self.window.text_win.refresh(self.current_room())

264
    def room_error(self, room, error, msg):
265 266 267
        """
        Display the error on the room window
        """
268 269
        if not error:
            return
270
        room = self.get_room_by_name(room)
271 272 273
        code = error.getAttr('code')
        typ = error.getAttr('type')
        body = error.getTag('text').getData()
274 275
        self.add_message_to_room(room, _('Error: %(code)s-%(msg)s: %(body)s' %
                                   {'msg':msg, 'code':code, 'body':body}))
276
        if code == '401':
277
            room.add(_('To provide a password in order to join the room, type "/join / password" (replace "password" by the real password)'))
278

279
    def room_message(self, stanza, date=None):
280 281 282
        """
        Display the message on the room window
        """
283 284 285 286 287 288
        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
289 290 291
        if stanza.getType() != 'groupchat':
            return  # ignore all messages not comming from a MUC
        nick_from = stanza.getFrom().getResource()
292
        room_from = stanza.getFrom().getStripped()
293 294
        if (self.ignores.has_key(room_from)) and (nick_from in self.ignores[room_from]):
            return
295
        room = self.get_room_by_name(room_from)
296
	if not room:
297
	    self.information(_("message received for a non-existing room: %s") % (room_from))
298
            return
299
        body = stanza.getBody()
300 301
        subject = stanza.getSubject()
        if subject:
302
            if nick_from:
303
                self.add_message_to_room(room, _("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject}, date)
304
            else:
305
                self.add_message_to_room(room, _("The subject is: %(subject)s") % {'subject':subject}, date)
306
            room.topic = subject.encode('utf-8').replace('\n', '|')
307 308
            if room == self.current_room():
                self.window.topic_win.refresh(room.topic)
309
        elif body:
310
            if body.startswith('/me '):
311
                self.add_message_to_room(room, "* "+nick_from + ' ' + body[4:], date)
312
            else:
313 314
                date = date if delayed == True else None
                self.add_message_to_room(room, body, date, nick_from)
315
        self.window.input.refresh()
316
        doupdate()
317 318

    def room_presence(self, stanza):
319 320 321 322
        """
        Display the presence on the room window and update the
        presence information of the concerned user
        """
323 324
        if len(sys.argv) > 1:
            self.information(str(stanza))
325 326
        from_nick = stanza.getFrom().getResource()
        from_room = stanza.getFrom().getStripped()
327
	room = self.get_room_by_name(from_room)
328
	if not room:
329
            return
330
        else:
331 332 333 334 335 336
            msg = None
            affiliation = stanza.getAffiliation()
            show = stanza.getShow()
            status = stanza.getStatus()
            role = stanza.getRole()
            if not room.joined:     # user in the room BEFORE us.
337 338
                room.users.append(User(from_nick, affiliation, show, status,
                                       role))
339 340
                if from_nick.encode('utf-8') == room.own_nick:
                    room.joined = True
341
                    self.add_message_to_room(room, _("Your nickname is %s") % (from_nick))
342
                else:
343
                    self.add_message_to_room(room, _("%s is in the room") % (from_nick))
344 345 346 347 348 349
            else:
                change_nick = stanza.getStatusCode() == '303'
                kick = stanza.getStatusCode() == '307'
                user = room.get_user_by_name(from_nick)
                # New user
                if not user:
350 351
                    room.users.append(User(from_nick, affiliation,
                                           show, status, role))
352 353
                    hide_exit_join = config.get('hide_exit_join', -1)
                    if hide_exit_join != 0:
354
                        self.add_message_to_room(room, _("%(nick)s joined the room %(roomname)s") % {'nick':from_nick, 'roomname': room.name})
355 356 357 358 359
                # nick change
                elif change_nick:
                    if user.nick == room.own_nick:
                        room.own_nick = stanza.getNick().encode('utf-8')
                    user.change_nick(stanza.getNick())
360
                    self.add_message_to_room(room, _('%(old)s is now known as %(new)s') % {'old':from_nick, 'new':stanza.getNick()})
361 362 363
                # kick
                elif kick:
                    room.users.remove(user)
364 365 366 367
                    try:
                        reason = stanza.getReason().encode('utf-8')
                    except:
                        reason = ''
368 369 370 371 372 373 374
                    try:
                        by = stanza.getActor().encode('utf-8')
                    except:
                        by = None
                    if from_nick == room.own_nick: # we are kicked
                        room.disconnect()
                        if by:
375
                            self.add_message_to_room(room,  _("You have been kicked by %(by)s. Reason: %(reason)s") % {'by':by, 'reason':reason})
376
                        else:
377
                            self.add_message_to_room(room, _("You have been kicked. Reason: %s") % (reason))
378 379
                    else:
                        if by:
380
                            self.add_message_to_room(room, _("%(nick)s has been kicked by %(by)s. Reason: %(reason)s") % {'nick':from_nick, 'by':by, 'reason':reason})
381
                        else:
382
                            self.add_message_to_room(room, _("%(nick)s has been kicked. Reason: %(reason)s") % {'nick':from_nick, 'reason':reason})
383 384 385
                # user quit
                elif status == 'offline' or role == 'none':
                    room.users.remove(user)
386 387 388
                    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):
                        self.add_message_to_room(room, _('%s has left the room') % (from_nick))
389 390
                # status change
                else:
391
                    hide_status_change = config.get('hide_status_change', -1) if config.get('hide_status_change', -1) >= -1 else -1
392
                    if (hide_status_change == -1 or \
393
                            user.has_talked_since(hide_status_change) or\
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
                            user.nick == room.own_nick)\
                            and\
                            (affiliation != user.affiliation or\
                                role != user.role or\
                                show != user.show or\
                                status != user.status):
                        msg = _('%s changed his/her status: ')% from_nick
                        if affiliation != user.affiliation:
                            msg += _('affiliation: %s,') % affiliation
                        if role != user.role:
                            msg += _('role: %s,') % role
                        if show != user.show:
                            msg += _('show: %s,') % show
                        if status != user.status:
                            msg += _('status: %s,') % status
                        # (a)s, %(b)s, %(c)s, %(d)s') % {'nick':from_nick, 'a':affiliation, 'b':role, 'c':show, 'd':status})
                        user.update(affiliation, show, status, role)
                        msg = msg[:-1] # remove the last ","
                        self.add_message_to_room(room, msg)

414 415
            if room == self.current_room():
                self.window.user_win.refresh(room.users)
416
        self.window.input.refresh()
417
        doupdate()
418

419
    def add_message_to_room(self, room, txt, time=None, nickname=None):
420
        """
421 422
        Add the message to the room and refresh the associated component
        of the interface
423
        """
424
        room.add_message(txt, time, nickname)
425
        if room == self.current_room():
426 427
            self.window.text_win.refresh(room)
        else:
428
            self.window.info_win.refresh(self.rooms, self.current_room())
429 430

    def execute(self):
431 432 433
        """
        Execute the /command or just send the line on the current room
        """
434 435
        line = self.window.input.get_text()
        self.window.input.clear_text()
436
        self.window.input.refresh()
437 438
        if line == "":
            return
439
        if line.startswith('/'):
440 441 442
            command = line.strip()[:].split()[0][1:]
            args = line.strip()[:].split()[1:]
            if command in self.commands.keys():
443
                func = self.commands[command][0]
444
                func(args)
445
                return
446
            else:
447
                self.add_message_to_room(self.current_room(), _("Error: unknown command (%s)") % (command))
448
        elif self.current_room().name != 'Info':
449
            self.muc.send_message(self.current_room().name, line)
450
        self.window.input.refresh()
451
        doupdate()
452

453
    def command_help(self, args):
454 455 456
        """
        /help <command_name>
        """
457 458
        room = self.current_room()
        if len(args) == 0:
459
            msg = _('Available commands are: ')
460 461
            for command in self.commands.keys():
                msg += "%s " % command
462
            msg += _("\nType /help <command_name> to know what each command does")
463 464 465 466
        if len(args) == 1:
            if args[0] in self.commands.keys():
                msg = self.commands[args[0]][1]
            else:
467
                msg = _('Unknown command: %s') % args[0]
468
        self.add_message_to_room(room, msg)
469

470
    def command_win(self, args):
471 472 473
        """
        /win <number>
        """
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
        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)

494
    def command_kick(self, args):
495 496 497
        """
        /kick <nick> [reason]
        """
498 499 500 501 502 503 504 505 506 507 508 509 510
        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)

511
    def command_join(self, args):
512 513 514
        """
        /join [room][/nick] [password]
        """
515
        password = None
516 517 518 519 520 521
        if len(args) == 0:
            r = self.current_room()
            if r.name == 'Info':
                return
            room = r.name
            nick = r.own_nick
522
        else:
523 524 525 526 527
            info = args[0].split('/')
            if len(info) == 1:
                nick = config.get('default_nick', 'Poezio')
            else:
                nick = info[1]
528
            if info[0] == '':   # happens with /join /nickname, which is OK
529 530 531 532
                r = self.current_room()
                if r.name == 'Info':
                    return
                room = r.name
533 534
                if nick == '':
                    nick = r.own_nick
535 536 537
            else:
                room = info[0]
            r = self.get_room_by_name(room)
538 539
        if len(args) == 2:       # a password is provided
            password = args[1]
540
        if r and r.joined:                   # if we are already in the room
541
            self.information(_("already in room [%s]") % room)
542
            return
543
        self.muc.join_room(room, nick, password)
544
        if not r:   # if the room window exists, we don't recreate it.
545
            self.join_room(room, nick)
546
        else:
547
            # r.own_nick = nick
548
            r.users = []
549

550
    def command_bookmark(self, args):
551 552 553
        """
        /bookmark [room][/nick]
        """
554 555 556 557 558 559 560 561 562 563 564 565 566
        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]
567 568
            if roomname == '':
                roomname = self.current_room().name
569 570 571 572
        if nick:
            res = roomname+'/'+nick
        else:
            res = roomname
573 574 575 576 577 578 579 580 581
        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)
582
        config.set_and_save('rooms', bookmarked+':'+res)
583

584
    def command_set(self, args):
585 586 587
        """
        /set <option> [value]
        """
588
        if len(args) != 2 and len(args) != 1:
589 590 591
            self.command_help(['set'])
            return
        option = args[0]
592 593 594 595
        if len(args) == 2:
            value = args[1]
        else:
            value = ''
596
        config.set_and_save(option, value)
597 598
        msg = "%s=%s" % (option, value)
        room = self.current_room()
599
        self.add_message_to_room(room, msg)
600

601
    def command_show(self, args):
602 603 604
        """
        /show <status> [msg]
        """
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
        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)

630 631 632 633 634
    def command_ignore(self, args):
        """
        /ignore <nick>
        """
        if len(args) != 1:
635 636 637
            self.command_help(['ignore'])
            return
        if self.current_room().name == 'Info' or not self.current_room().joined:
638
            return
639 640 641 642 643 644 645 646 647
        roomname = self.current_room().name
        nick = args[0]
        if not self.ignores.has_key(roomname):
            self.ignores[roomname] = set() # no need for any order
        if nick not in self.ignores[roomname]:
            self.ignores[roomname].add(nick)
            self.add_message_to_room(self.current_room(), _("%s is now ignored") % nick)
        else:
            self.add_message_to_room(self.current_room(), _("%s is already ignored") % nick)
648 649 650 651 652 653

    def command_unignore(self, args):
        """
        /unignore <nick>
        """
        if len(args) != 1:
654 655 656 657 658 659 660 661
            self.command_help(['unignore'])
            return
        if self.current_room().name == 'Info' or not self.current_room().joined:
            return
        roomname = self.current_room().name
        nick = args[0]
        if not self.ignores.has_key(roomname) or (nick not in self.ignores[roomname]):
            self.add_message_to_room(self.current_room(), _("%s was not ignored") % nick)
662
            return
663 664 665 666
        self.ignores[roomname].remove(nick)
        if self.ignores[roomname] == set():
            del self.ignores[roomname]
        self.add_message_to_room(self.current_room(), _("%s is now unignored") % nick)
667

668
    def command_away(self, args):
669 670 671
        """
        /away [msg]
        """
672 673 674 675
        args.insert(0, 'away')
        self.command_show(args)

    def command_busy(self, args):
676 677 678
        """
        /busy [msg]
        """
679 680 681 682
        args.insert(0, 'busy')
        self.command_show(args)

    def command_avail(self, args):
683 684 685
        """
        /avail [msg]
        """
686 687
        args.insert(0, 'available')
        self.command_show(args)
688

689
    def command_part(self, args):
690 691 692
        """
        /part [msg]
        """
693 694 695 696 697 698 699 700
        reason = None
        room = self.current_room()
        if room.name == 'Info':
            return
        if len(args):
            msg = ' '.join(args)
        else:
            msg = None
701 702
        if room.joined:
            self.muc.quit_room(room.name, room.own_nick, msg)
703
        self.rooms.remove(self.current_room())
704
        self.window.refresh(self.rooms)
705

706
    def command_topic(self, args):
707 708 709
        """
        /topic [new topic]
        """
710
        room = self.current_room()
711
        if len(args) == 0:
712
            self.add_message_to_room(room, _("The subject of the room is: %s") % room.topic)
713
        subject = ' '.join(args)
714 715 716 717
        if not room.joined or room.name == "Info":
            return
        self.muc.change_subject(room.name, subject)

718
    def command_nick(self, args):
719 720 721
        """
        /nick <nickname>
        """
722 723 724 725 726 727 728 729
        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)

730
    def information(self, msg):
731 732 733
        """
        Displays an informational message in the "Info" room window
        """
734
        room = self.get_room_by_name("Info")
735
        self.add_message_to_room(room, msg)
736

737
    def command_quit(self, args):
738 739 740
        """
        /quit
        """
741
	self.reset_curses()
742
        sys.exit()