gui.py 32.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 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 126 127 128 129 130 131
            '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"""))
132 133
            }

134 135 136 137 138 139 140
        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,
141 142
            "KEY_PPAGE": self.scroll_page_up,
            "KEY_NPAGE": self.scroll_page_down,
143
            "KEY_DC": self.window.input.key_dc,
144 145 146 147
            "KEY_F(5)": self.rotate_rooms_left,
            "KEY_F(6)": self.rotate_rooms_right,
            "kLFT5": self.rotate_rooms_left,
            "kRIT5": self.rotate_rooms_right,
148
            "\t": self.auto_completion,
149 150 151
            "KEY_BACKSPACE": self.window.input.key_backspace
            }

152 153 154 155 156
        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)
157
        self.handler.connect('error-message', self.room_error)
158
        self.handler.connect('error', self.information)
159

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

199 200 201 202 203 204 205
    # def next_room_number(self):
    #     """
    #     Increments the room number and returns the new number
    #     """
    #     nb = self.room_number
    #     self.room_number += 1
    #     return nb
206

207
    def current_room(self):
208 209 210
        """
        returns the current room, the one we are viewing
        """
211
        return self.rooms[0]
212 213

    def get_room_by_name(self, name):
214 215 216 217 218 219 220
        """
        returns the room that has this name
        """
        for room in self.rooms:
            if room.name == name:
                return room
        return None
221

222
    def init_curses(self, stdscr):
223 224 225
        """
        ncurses initialization
        """
226 227
        curses.start_color()
        curses.noecho()
228
        curses.curs_set(0)
229 230
        # curses.cbreak()
        # curses.raw()
231
        curses.use_default_colors()
232
        stdscr.keypad(True)
233 234
        curses.init_pair(1, curses.COLOR_WHITE,
                         curses.COLOR_BLUE)
235 236 237
        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
238 239 240 241 242
        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)
243 244 245 246 247 248 249 250 251 252 253 254
        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)
255

256
    def reset_curses(self):
257 258 259 260 261
        """
        Reset terminal capabilities to what they were before ncurses
        init
        """
        curses.echo()
262
        curses.nocbreak()
263
        curses.endwin()
264

265
    def on_connected(self, jid):
266
        """
267
        We are connected when authentification confirmation is received
268
        """
269 270
        self.information(_("Welcome on Poezio \o/!"))
        self.information(_("Your JID is %s") % jid)
271 272

    def join_room(self, room, nick):
273 274 275
        """
        join the specified room (muc), using the specified nick
        """
276
        r = Room(room, nick, self.window)
277 278 279 280 281 282 283 284 285 286
        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())
287
        # self.window.new_room(r)
288
        self.window.refresh(self.rooms)
289

290
    def auto_completion(self):
291 292 293
        """
        Called when Tab is pressed, complete the nickname in the input
        """
294 295
        self.window.input.auto_completion(self.current_room().users)

296
    def rotate_rooms_right(self, args=None):
297 298 299
        """
        rotate the rooms list to the right
        """
300
        self.current_room().set_color_state(11)
301
        self.rooms.append(self.rooms.pop(0))
302
        self.window.refresh(self.rooms)
303

304
    def rotate_rooms_left(self, args=None):
305 306 307
        """
        rotate the rooms list to the right
        """
308
        self.current_room().set_color_state(11)
309
        self.rooms.insert(0, self.rooms.pop())
310
        self.window.refresh(self.rooms)
311

312 313 314 315 316
    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):
317
        self.current_room().scroll_up(self.window.size)
318 319
        self.window.text_win.refresh(self.current_room())

320
    def room_error(self, room, error, msg):
321 322 323
        """
        Display the error on the room window
        """
324 325
        if not error:
            return
326
        room = self.get_room_by_name(room)
327 328 329
        code = error.getAttr('code')
        typ = error.getAttr('type')
        body = error.getTag('text').getData()
330 331
        self.add_message_to_room(room, _('Error: %(code)s-%(msg)s: %(body)s' %
                                   {'msg':msg, 'code':code, 'body':body}))
332
        if code == '401':
333
            room.add(_('To provide a password in order to join the room, type "/join / password" (replace "password" by the real password)'))
334

335
    def room_message(self, stanza, date=None):
336 337 338
        """
        Display the message on the room window
        """
339 340 341 342 343 344
        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
345 346 347
        if stanza.getType() != 'groupchat':
            return  # ignore all messages not comming from a MUC
        nick_from = stanza.getFrom().getResource()
348
        room_from = stanza.getFrom().getStripped()
349 350
        if (self.ignores.has_key(room_from)) and (nick_from in self.ignores[room_from]):
            return
351
        room = self.get_room_by_name(room_from)
352
	if not room:
353
	    self.information(_("message received for a non-existing room: %s") % (room_from))
354
            return
355
        body = stanza.getBody()
356 357
        subject = stanza.getSubject()
        if subject:
358
            if nick_from:
359 360 361
                self.add_message_to_room(room, _("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject}, date)
 #                self.add_info(room, _("""%(nick)s changed the subject to:
 # %(subject)s""") % {'nick':nick_from, 'subject':subject}, date)
362
            else:
363 364 365
                self.add_message_to_room(room, _("The subject is: %(subject)s") % {'subject':subject}, date)
                # self.add_info(room, _("The subject is: %(subject)s") %
                #               {'subject':subject}, date)
366
            room.topic = subject.encode('utf-8').replace('\n', '|')
367 368
            if room == self.current_room():
                self.window.topic_win.refresh(room.topic)
369
        elif body:
370
            if body.startswith('/me '):
371 372 373
                # FIXME, it should be LIKE an information
                self.add_message_to_room(room, nick_from + ' ' + body[4:], date)
                # self.add_info(room, nick_from + ' ' + body[4:], date)
374
            else:
375 376 377
                date = date if delayed == True else None
                self.add_message_to_room(room, body, date, nick_from)
                # self.add_message(room, nick_from, body, date, delayed)
378
        self.window.input.refresh()
379
        doupdate()
380 381

    def room_presence(self, stanza):
382 383 384 385
        """
        Display the presence on the room window and update the
        presence information of the concerned user
        """
386 387
        if len(sys.argv) > 1:
            self.information(str(stanza))
388 389
        from_nick = stanza.getFrom().getResource()
        from_room = stanza.getFrom().getStripped()
390
	room = self.get_room_by_name(from_room)
391
	if not room:
392
            return
393
        else:
394 395 396 397 398 399
            msg = None
            affiliation = stanza.getAffiliation()
            show = stanza.getShow()
            status = stanza.getStatus()
            role = stanza.getRole()
            if not room.joined:     # user in the room BEFORE us.
400 401
                room.users.append(User(from_nick, affiliation, show, status,
                                       role))
402 403
                if from_nick.encode('utf-8') == room.own_nick:
                    room.joined = True
404 405
                    self.add_message_to_room(room, _("Your nickname is %s") % (from_nick))
                    # self.add_info(room, _("Your nickname is %s") % (from_nick))
406
                else:
407 408 409 410 411
                    self.add_message_to_room(room, _("%s is in the room") %
                                  (from_nick# .encode('utf-8')
                                   ))
                    # self.add_info(room, _("%s is in the room") %
                    #               (from_nick.encode('utf-8')))
412 413 414 415 416 417
            else:
                change_nick = stanza.getStatusCode() == '303'
                kick = stanza.getStatusCode() == '307'
                user = room.get_user_by_name(from_nick)
                # New user
                if not user:
418 419
                    room.users.append(User(from_nick, affiliation,
                                           show, status, role))
420 421
                    hide_exit_join = config.get('hide_exit_join', -1)
                    if hide_exit_join != 0:
422 423
                        self.add_message_to_room(room, _("%(nick)s joined the room %(roomname)s") % {'nick':from_nick, 'roomname': room.name})
                        # self.add_info(room, _("%(nick)s joined the room %(roomname)s") % {'nick':from_nick, 'roomname': room.name})
424 425 426 427 428
                # nick change
                elif change_nick:
                    if user.nick == room.own_nick:
                        room.own_nick = stanza.getNick().encode('utf-8')
                    user.change_nick(stanza.getNick())
429 430 431 432 433
                    self.add_message_to_room(room, _('%(old)s is now known as %(new)s') % {'old':from_nick, 'new':stanza.getNick()})
                    # self.add_info(room,
                    #               _('%(old)s is now known as %(new)s') %
                    #               {'old':from_nick,
                    #                  'new':stanza.getNick()})
434 435 436
                # kick
                elif kick:
                    room.users.remove(user)
437 438 439 440
                    try:
                        reason = stanza.getReason().encode('utf-8')
                    except:
                        reason = ''
441 442 443 444 445 446 447
                    try:
                        by = stanza.getActor().encode('utf-8')
                    except:
                        by = None
                    if from_nick == room.own_nick: # we are kicked
                        room.disconnect()
                        if by:
448 449 450
                            self.add_message_to_room(room,  _("You have been kicked by %(by)s. Reason: %(reason)s") % {'by':by, 'reason':reason})
 #                            self.add_info(room, _("""You have been kicked by
 # %(by)s. Reason: %(reason)s""") % {'by':by, 'reason':reason})
451
                        else:
452 453 454
                            self.add_message_to_room(room, _("You have been kicked. Reason: %s") % (reason))
 #                            self.add_info(room, _("""You have been
 # kicked. Reason: %s""") % (reason))
455 456
                    else:
                        if by:
457 458 459 460
                            self.add_message_to_room(room, _("%(nick)s has been kicked by %(by)s. Reason: %(reason)s") % {'nick':from_nick, 'by':by, 'reason':reason})
                            # self.add_info(room, _("""%(nick)s has been kicked
                            #              by %(by)s. Reason: %(reason)s""") %
                            #               {'nick':from_nick, 'by':by, 'reason':reason})
461
                        else:
462 463 464 465
                            self.add_message_to_room(room, _("%(nick)s has been kicked. Reason: %(reason)s") % {'nick':from_nick, 'reason':reason})
                            # self.add_info(room, _("""%(nick)s has been kicked.
                            #                      Reason: %(reason)s""") %
                            #               {'nick':from_nick, 'reason':reason})
466 467 468
                # user quit
                elif status == 'offline' or role == 'none':
                    room.users.remove(user)
469 470 471 472
                    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))
                        # self.add_info(room, _('%s has left the room') % (from_nick))
473 474 475
                # status change
                else:
                    user.update(affiliation, show, status, role)
476
                    hide_status_change = config.get('hide_status_change', -1) if config.get('hide_status_change', -1) >= -1 else -1
477 478 479
                    if hide_status_change == -1 or \
                            user.has_talked_since(hide_status_change) or\
                            user.nick == room.own_nick:
480 481
                        self.add_message_to_room(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})
                        # 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})
482 483
            if room == self.current_room():
                self.window.user_win.refresh(room.users)
484
        self.window.input.refresh()
485
        doupdate()
486

487
    def add_message_to_room(self, room, txt, time=None, nickname=None):
488
        """
489 490
        Add the message to the room and refresh the associated component
        of the interface
491
        """
492
        room.add_message(txt, time, nickname)
493
        if room == self.current_room():
494 495 496
            self.window.text_win.refresh(room)
        # elif not delayed:
        else:
497
            self.window.info_win.refresh(self.rooms, self.current_room())
498

499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
        # TODO

    # 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)
    #     """
    #     if not date:
    #         date = datetime.now()
    #     msg = room.add_info(info, date)
    #     self.window.text_win.add_line(room, (date, msg))
    #     if room.name == self.current_room().name:
    #         self.window.text_win.refresh(room.name)
    #         self.window.input.refresh()
    #         doupdate()

    # def add_message(self, room, nick_from, body, date=None, delayed=False):
    #     """
    #     Just add a message
    #     """
    #     if not date:
    #         date = datetime.now()
    #     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)
    #     elif not delayed:
    #         self.window.info_win.refresh(self.rooms, self.current_room())

529
    def execute(self):
530 531 532
        """
        Execute the /command or just send the line on the current room
        """
533 534
        line = self.window.input.get_text()
        self.window.input.clear_text()
535
        self.window.input.refresh()
536 537
        if line == "":
            return
538
        if line.startswith('/'):
539 540 541
            command = line.strip()[:].split()[0][1:]
            args = line.strip()[:].split()[1:]
            if command in self.commands.keys():
542
                func = self.commands[command][0]
543
                func(args)
544
                return
545
            else:
546 547
                self.add_message_to_room(self.current_room(), _("Error: unknown command (%s)") % (command))
                # self.add_info(self.current_room(), _("Error: unknown command (%s)") % (command))
548
        elif self.current_room().name != 'Info':
549
            self.muc.send_message(self.current_room().name, line)
550
        self.window.input.refresh()
551
        doupdate()
552

553
    def command_help(self, args):
554 555 556
        """
        /help <command_name>
        """
557 558
        room = self.current_room()
        if len(args) == 0:
559
            msg = _('Available commands are:')
560 561
            for command in self.commands.keys():
                msg += "%s " % command
562
            msg += _("\nType /help <command_name> to know what each command does")
563 564 565 566
        if len(args) == 1:
            if args[0] in self.commands.keys():
                msg = self.commands[args[0]][1]
            else:
567
                msg = _('Unknown command: %s') % args[0]
568 569
        self.add_message_to_room(room, msg)
        # self.add_info(room, msg)
570

571
    def command_win(self, args):
572 573 574
        """
        /win <number>
        """
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
        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)

595
    def command_kick(self, args):
596 597 598
        """
        /kick <nick> [reason]
        """
599 600 601 602 603 604 605 606 607 608 609 610 611
        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)

612
    def command_join(self, args):
613 614 615
        """
        /join [room][/nick] [password]
        """
616
        password = None
617 618 619 620 621 622
        if len(args) == 0:
            r = self.current_room()
            if r.name == 'Info':
                return
            room = r.name
            nick = r.own_nick
623
        else:
624 625 626 627 628
            info = args[0].split('/')
            if len(info) == 1:
                nick = config.get('default_nick', 'Poezio')
            else:
                nick = info[1]
629
            if info[0] == '':   # happens with /join /nickname, which is OK
630 631 632 633
                r = self.current_room()
                if r.name == 'Info':
                    return
                room = r.name
634 635
                if nick == '':
                    nick = r.own_nick
636 637 638
            else:
                room = info[0]
            r = self.get_room_by_name(room)
639 640
        if len(args) == 2:       # a password is provided
            password = args[1]
641
        if r and r.joined:                   # if we are already in the room
642
            self.information(_("already in room [%s]") % room)
643
            return
644
        self.muc.join_room(room, nick, password)
645
        if not r:   # if the room window exists, we don't recreate it.
646
            self.join_room(room, nick)
647
        else:
648
            r.own_nick = nick
649
            r.users = []
650

651
    def command_bookmark(self, args):
652 653 654
        """
        /bookmark [room][/nick]
        """
655 656 657 658 659 660 661 662 663 664 665 666 667
        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]
668 669
            if roomname == '':
                roomname = self.current_room().name
670 671 672 673
        if nick:
            res = roomname+'/'+nick
        else:
            res = roomname
674 675 676 677 678 679 680 681 682
        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)
683
        config.set_and_save('rooms', bookmarked+':'+res)
684

685
    def command_set(self, args):
686 687 688
        """
        /set <option> [value]
        """
689
        if len(args) != 2 and len(args) != 1:
690 691 692
            self.command_help(['set'])
            return
        option = args[0]
693 694 695 696
        if len(args) == 2:
            value = args[1]
        else:
            value = ''
697
        config.set_and_save(option, value)
698 699
        msg = "%s=%s" % (option, value)
        room = self.current_room()
700 701
        self.add_message_to_room(room, msg)
        # self.add_info(room, msg)
702

703
    def command_show(self, args):
704 705 706
        """
        /show <status> [msg]
        """
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
        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)

732 733 734 735 736
    def command_ignore(self, args):
        """
        /ignore <nick>
        """
        if len(args) != 1:
737 738 739
            self.command_help(['ignore'])
            return
        if self.current_room().name == 'Info' or not self.current_room().joined:
740
            return
741 742 743 744 745 746 747 748 749
        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)
750 751 752 753 754 755 756

    def command_unignore(self, args):
        """
        /unignore <nick>
        """
        # TODO
        if len(args) != 1:
757 758 759 760 761 762 763 764
            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)
765
            return
766 767 768 769
        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)
770

771
    def command_away(self, args):
772 773 774
        """
        /away [msg]
        """
775 776 777 778
        args.insert(0, 'away')
        self.command_show(args)

    def command_busy(self, args):
779 780 781
        """
        /busy [msg]
        """
782 783 784 785
        args.insert(0, 'busy')
        self.command_show(args)

    def command_avail(self, args):
786 787 788
        """
        /avail [msg]
        """
789 790
        args.insert(0, 'available')
        self.command_show(args)
791

792
    def command_part(self, args):
793 794 795
        """
        /part [msg]
        """
796 797 798 799 800 801 802 803
        reason = None
        room = self.current_room()
        if room.name == 'Info':
            return
        if len(args):
            msg = ' '.join(args)
        else:
            msg = None
804 805
        if room.joined:
            self.muc.quit_room(room.name, room.own_nick, msg)
806
        self.rooms.remove(self.current_room())
807
        self.window.refresh(self.rooms)
808

809
    def command_topic(self, args):
810 811 812
        """
        /topic [new topic]
        """
813
        room = self.current_room()
814
        if len(args) == 0:
815
            self.add_message_to_room(room, _("The subject of the room is: %s") % room.topic)
816
        subject = ' '.join(args)
817 818 819 820
        if not room.joined or room.name == "Info":
            return
        self.muc.change_subject(room.name, subject)

821
    def command_nick(self, args):
822 823 824
        """
        /nick <nickname>
        """
825 826 827 828 829 830 831 832
        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)

833
    def information(self, msg):
834 835 836
        """
        Displays an informational message in the "Info" room window
        """
837
        room = self.get_room_by_name("Info")
838 839
        self.add_message_to_room(room, msg)
        # self.add_info(room, msg)
840

841
    def command_quit(self, args):
842 843 844
        """
        /quit
        """
845
	self.reset_curses()
846
        sys.exit()