gui.py 33.8 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
from message import Message

43 44
from connection import is_jid_the_same

45 46 47 48
from common import debug
def doupdate():
    debug("doupdate")
    curses.doupdate()
49

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

63
        self.muc = muc
64

65
        self.commands = {
66
            'help': (self.command_help, u'\_o< KOIN KOIN KOIN'),
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
            '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")),
88 89
            'query': (self.command_query, _('Usage: /query <nick>\nQuery: Open a private conversation with <nick>. This nick has to be present in the room you\'re currently in.')),

90
            'nick': (self.command_nick, _("Usage: /nick <nickname> \nNick: Change your nickname in the current room"))
91 92
            }

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

111 112 113 114 115
        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)
116
        self.handler.connect('private-message', self.private_message)
117
        self.handler.connect('error-message', self.room_error)
118
        self.handler.connect('error', self.information)
119

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

159
    def current_room(self):
160 161 162
        """
        returns the current room, the one we are viewing
        """
163
        return self.rooms[0]
164 165

    def get_room_by_name(self, name):
166 167 168 169 170 171 172
        """
        returns the room that has this name
        """
        for room in self.rooms:
            if room.name == name:
                return room
        return None
173

174
    def init_curses(self, stdscr):
175 176 177
        """
        ncurses initialization
        """
178 179
        curses.start_color()
        curses.noecho()
180
        curses.curs_set(0)
181
        curses.use_default_colors()
182
        stdscr.keypad(True)
183 184
        curses.init_pair(1, curses.COLOR_WHITE,
                         curses.COLOR_BLUE)
185 186 187
        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
188 189 190 191 192
        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)
193 194 195 196 197 198 199 200 201 202
        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)
203
        curses.init_pair(15, curses.COLOR_WHITE, # new message in private room
204
                         curses.COLOR_GREEN)
205

206
    def reset_curses(self):
207 208 209 210 211
        """
        Reset terminal capabilities to what they were before ncurses
        init
        """
        curses.echo()
212
        curses.nocbreak()
213
        curses.endwin()
214

215
    def on_connected(self, jid):
216
        """
217
        We are connected when authentification confirmation is received
218
        """
219 220
        self.information(_("Welcome on Poezio \o/!"))
        self.information(_("Your JID is %s") % jid)
221 222

    def join_room(self, room, nick):
223 224 225
        """
        join the specified room (muc), using the specified nick
        """
226
        r = Room(room, nick, self.window)
227 228 229 230 231 232 233 234 235 236 237
        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)
238

239
    def auto_completion(self):
240 241 242
        """
        Called when Tab is pressed, complete the nickname in the input
        """
243 244
        self.window.input.auto_completion(self.current_room().users)

245
    def rotate_rooms_right(self, args=None):
246 247 248
        """
        rotate the rooms list to the right
        """
249
        self.current_room().set_color_state(11)
250
        self.rooms.append(self.rooms.pop(0))
251
        self.window.refresh(self.rooms)
252

253
    def rotate_rooms_left(self, args=None):
254 255 256
        """
        rotate the rooms list to the right
        """
257
        self.current_room().set_color_state(11)
258
        self.rooms.insert(0, self.rooms.pop())
259
        self.window.refresh(self.rooms)
260

261 262 263 264 265
    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):
266
        self.current_room().scroll_up(self.window.size)
267 268
        self.window.text_win.refresh(self.current_room())

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

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    def private_message(self, stanza):
        """
        When a private message is received
        """
        jid = stanza.getFrom()
        nick_from = stanza.getFrom().getResource()
        room_from = stanza.getFrom().getStripped()
        room = self.get_room_by_name(jid) # get the tab with the private conversation
        if not room: # It's the first message we receive: create the tab
            room = self.open_private_window(room_from, nick_from, False)
        body = stanza.getBody()
        self.add_message_to_room(room, body, None, nick_from)
        self.window.input.refresh()
        doupdate()

    def open_private_window(self, room_name, user_nick, focus=True):
        complete_jid = room_name+'/'+user_nick
        for room in self.rooms: # if the room exists, focus it and return
            if room.jid:
                if room.jid == complete_jid:
                    self.command_win(str(room.nb))
                    return
        # create the new tab
        own_nick = self.get_room_by_name(room_name).own_nick
        r = Room(complete_jid, own_nick, self.window, complete_jid)
        # insert it in the rooms
        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
        if focus:               # focus the room if needed
            while self.current_room().nb != r.nb:
                self.rooms.insert(0, self.rooms.pop())
        # self.window.new_room(r)
        self.window.refresh(self.rooms)
        return r

327
    def room_message(self, stanza, date=None):
328 329 330
        """
        Display the message on the room window
        """
331 332 333 334 335 336
        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
337 338 339
        if stanza.getType() != 'groupchat':
            return  # ignore all messages not comming from a MUC
        nick_from = stanza.getFrom().getResource()
340
        room_from = stanza.getFrom().getStripped()
341 342
        if (self.ignores.has_key(room_from)) and (nick_from in self.ignores[room_from]):
            return
343
        room = self.get_room_by_name(room_from)
344
	if not room:
345
	    self.information(_("message received for a non-existing room: %s") % (room_from))
346
            return
347
        body = stanza.getBody()
348 349
        subject = stanza.getSubject()
        if subject:
350
            if nick_from:
351
                self.add_message_to_room(room, _("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject}, date)
352
            else:
353
                self.add_message_to_room(room, _("The subject is: %(subject)s") % {'subject':subject}, date)
354
            room.topic = subject.encode('utf-8').replace('\n', '|')
355 356
            if room == self.current_room():
                self.window.topic_win.refresh(room.topic)
357
        elif body:
358
            if body.startswith('/me '):
359
                self.add_message_to_room(room, "* "+nick_from + ' ' + body[4:], date)
360
            else:
361 362
                date = date if delayed == True else None
                self.add_message_to_room(room, body, date, nick_from)
363
        self.window.input.refresh()
364
        doupdate()
365 366

    def room_presence(self, stanza):
367 368 369 370
        """
        Display the presence on the room window and update the
        presence information of the concerned user
        """
371 372
        if len(sys.argv) > 1:
            self.information(str(stanza))
373 374
        from_nick = stanza.getFrom().getResource()
        from_room = stanza.getFrom().getStripped()
375
	room = self.get_room_by_name(from_room)
376
	if not room:
377
            return
378
        else:
379 380 381 382 383 384
            msg = None
            affiliation = stanza.getAffiliation()
            show = stanza.getShow()
            status = stanza.getStatus()
            role = stanza.getRole()
            if not room.joined:     # user in the room BEFORE us.
385 386
                room.users.append(User(from_nick, affiliation, show, status,
                                       role))
387 388
                if from_nick.encode('utf-8') == room.own_nick:
                    room.joined = True
389
                    self.add_message_to_room(room, _("Your nickname is %s") % (from_nick))
390
                else:
391
                    self.add_message_to_room(room, _("%s is in the room") % (from_nick))
392 393 394 395 396 397
            else:
                change_nick = stanza.getStatusCode() == '303'
                kick = stanza.getStatusCode() == '307'
                user = room.get_user_by_name(from_nick)
                # New user
                if not user:
398 399
                    room.users.append(User(from_nick, affiliation,
                                           show, status, role))
400 401
                    hide_exit_join = config.get('hide_exit_join', -1)
                    if hide_exit_join != 0:
402
                        self.add_message_to_room(room, _("%(nick)s joined the room %(roomname)s") % {'nick':from_nick, 'roomname': room.name})
403 404 405 406
                # nick change
                elif change_nick:
                    if user.nick == room.own_nick:
                        room.own_nick = stanza.getNick().encode('utf-8')
407 408 409 410 411 412
                        # also change our nick in all private discussion of this room
                        for _room in self.rooms:
                            if _room.jid is not None and is_jid_the_same(_room.jid, room.name):
                                debug(_room.jid)
                                debug(room.name)
                                _room.own_nick = stanza.getNick()
413
                    user.change_nick(stanza.getNick())
414
                    self.add_message_to_room(room, _('%(old)s is now known as %(new)s') % {'old':from_nick, 'new':stanza.getNick()})
415 416 417 418 419 420 421 422
                    # rename the private tabs if needed
                    private_room = self.get_room_by_name(stanza.getFrom())
                    if private_room:
                        self.add_message_to_room(private_room, _('%(old_nick)s is now known as %(new_nick)s') % {'old_nick':from_nick, 'new_nick':stanza.getNick()})
                        new_jid = private_room.name.split('/')[0]+'/'+stanza.getNick()
                        private_room.jid = new_jid
                        private_room.name = new_jid

423 424 425
                # kick
                elif kick:
                    room.users.remove(user)
426 427 428 429
                    try:
                        reason = stanza.getReason().encode('utf-8')
                    except:
                        reason = ''
430 431 432 433 434 435 436
                    try:
                        by = stanza.getActor().encode('utf-8')
                    except:
                        by = None
                    if from_nick == room.own_nick: # we are kicked
                        room.disconnect()
                        if by:
437
                            self.add_message_to_room(room,  _("You have been kicked by %(by)s. Reason: %(reason)s") % {'by':by, 'reason':reason})
438
                        else:
439
                            self.add_message_to_room(room, _("You have been kicked. Reason: %s") % (reason))
440 441
                    else:
                        if by:
442
                            self.add_message_to_room(room, _("%(nick)s has been kicked by %(by)s. Reason: %(reason)s") % {'nick':from_nick, 'by':by, 'reason':reason})
443
                        else:
444
                            self.add_message_to_room(room, _("%(nick)s has been kicked. Reason: %(reason)s") % {'nick':from_nick, 'reason':reason})
445 446 447
                # user quit
                elif status == 'offline' or role == 'none':
                    room.users.remove(user)
448 449 450
                    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))
451 452 453
                    private_room = self.get_room_by_name(stanza.getFrom())
                    if private_room:
                        self.add_message_to_room(private_room, _('%s has left the room') % (from_nick))
454 455
                # status change
                else:
456 457 458 459 460 461 462 463 464 465 466
                    # build the message
                    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
                    msg = msg[:-1] # remove the last ","
467
                    hide_status_change = config.get('hide_status_change', -1) if config.get('hide_status_change', -1) >= -1 else -1
468
                    if (hide_status_change == -1 or \
469
                            user.has_talked_since(hide_status_change) or\
470 471 472 473 474 475
                            user.nick == room.own_nick)\
                            and\
                            (affiliation != user.affiliation or\
                                role != user.role or\
                                show != user.show or\
                                status != user.status):
476
                        # display the message in the room
477
                        self.add_message_to_room(room, msg)
478 479 480 481 482 483
                    private_room = self.get_room_by_name(stanza.getFrom())
                    # debug('status change: ' + stanza.getFrom()+'\n')
                    if private_room: # display the message in private
                        self.add_message_to_room(private_room, msg)
                    # finally, effectively change the user status
                    user.update(affiliation, show, status, role)
484 485
            if room == self.current_room():
                self.window.user_win.refresh(room.users)
486
        self.window.input.refresh()
487
        self.window.info_win.refresh(self.rooms, self.current_room())
488
        doupdate()
489

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

    def execute(self):
502 503 504
        """
        Execute the /command or just send the line on the current room
        """
505 506
        line = self.window.input.get_text()
        self.window.input.clear_text()
507
        self.window.input.refresh()
508 509
        if line == "":
            return
510
        if line.startswith('/') and not line.startswith('/me '):
511 512 513
            command = line.strip()[:].split()[0][1:]
            args = line.strip()[:].split()[1:]
            if command in self.commands.keys():
514
                func = self.commands[command][0]
515
                func(args)
516
                return
517
            else:
518
                self.add_message_to_room(self.current_room(), _("Error: unknown command (%s)") % (command))
519
        elif self.current_room().name != 'Info':
520 521 522 523 524
            if self.current_room().jid is not None:
                self.muc.send_private_message(self.current_room().name, line)
                self.add_message_to_room(self.current_room(), line.decode('utf-8'), None, self.current_room().own_nick)
            else:
                self.muc.send_message(self.current_room().name, line)
525
        self.window.input.refresh()
526
        doupdate()
527

528
    def command_help(self, args):
529 530 531
        """
        /help <command_name>
        """
532 533
        room = self.current_room()
        if len(args) == 0:
534
            msg = _('Available commands are: ')
535 536
            for command in self.commands.keys():
                msg += "%s " % command
537
            msg += _("\nType /help <command_name> to know what each command does")
538 539 540 541
        if len(args) == 1:
            if args[0] in self.commands.keys():
                msg = self.commands[args[0]][1]
            else:
542
                msg = _('Unknown command: %s') % args[0]
543
        self.add_message_to_room(room, msg)
544

545
    def command_win(self, args):
546 547 548
        """
        /win <number>
        """
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
        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)

569
    def command_kick(self, args):
570 571 572
        """
        /kick <nick> [reason]
        """
573 574 575 576 577 578 579 580 581 582 583 584 585
        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)

586
    def command_join(self, args):
587 588 589
        """
        /join [room][/nick] [password]
        """
590
        password = None
591 592 593 594 595 596
        if len(args) == 0:
            r = self.current_room()
            if r.name == 'Info':
                return
            room = r.name
            nick = r.own_nick
597
        else:
598 599 600 601 602
            info = args[0].split('/')
            if len(info) == 1:
                nick = config.get('default_nick', 'Poezio')
            else:
                nick = info[1]
603
            if info[0] == '':   # happens with /join /nickname, which is OK
604 605 606 607
                r = self.current_room()
                if r.name == 'Info':
                    return
                room = r.name
608 609
                if nick == '':
                    nick = r.own_nick
610 611 612
            else:
                room = info[0]
            r = self.get_room_by_name(room)
613 614
        if len(args) == 2:       # a password is provided
            password = args[1]
615
        if r and r.joined:                   # if we are already in the room
616
            self.information(_("already in room [%s]") % room)
617
            return
618
        self.muc.join_room(room, nick, password)
619
        if not r:   # if the room window exists, we don't recreate it.
620
            self.join_room(room, nick)
621
        else:
622
            # r.own_nick = nick
623
            r.users = []
624

625
    def command_bookmark(self, args):
626 627 628
        """
        /bookmark [room][/nick]
        """
629 630 631 632 633 634 635 636 637 638 639 640 641
        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]
642 643
            if roomname == '':
                roomname = self.current_room().name
644 645 646 647
        if nick:
            res = roomname+'/'+nick
        else:
            res = roomname
648 649 650 651 652 653 654 655 656
        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)
657
        config.set_and_save('rooms', bookmarked+':'+res)
658

659
    def command_set(self, args):
660 661 662
        """
        /set <option> [value]
        """
663
        if len(args) != 2 and len(args) != 1:
664 665 666
            self.command_help(['set'])
            return
        option = args[0]
667 668 669 670
        if len(args) == 2:
            value = args[1]
        else:
            value = ''
671
        config.set_and_save(option, value)
672 673
        msg = "%s=%s" % (option, value)
        room = self.current_room()
674
        self.add_message_to_room(room, msg)
675

676
    def command_show(self, args):
677 678 679
        """
        /show <status> [msg]
        """
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
        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)

705 706 707 708 709
    def command_ignore(self, args):
        """
        /ignore <nick>
        """
        if len(args) != 1:
710 711 712
            self.command_help(['ignore'])
            return
        if self.current_room().name == 'Info' or not self.current_room().joined:
713
            return
714 715 716 717 718 719 720 721 722
        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)
723 724 725 726 727 728

    def command_unignore(self, args):
        """
        /unignore <nick>
        """
        if len(args) != 1:
729 730 731 732 733 734 735 736
            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)
737
            return
738 739 740 741
        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)
742

743
    def command_away(self, args):
744 745 746
        """
        /away [msg]
        """
747 748 749 750
        args.insert(0, 'away')
        self.command_show(args)

    def command_busy(self, args):
751 752 753
        """
        /busy [msg]
        """
754 755 756 757
        args.insert(0, 'busy')
        self.command_show(args)

    def command_avail(self, args):
758 759 760
        """
        /avail [msg]
        """
761 762
        args.insert(0, 'available')
        self.command_show(args)
763

764
    def command_part(self, args):
765 766 767
        """
        /part [msg]
        """
768 769 770 771 772 773 774 775
        reason = None
        room = self.current_room()
        if room.name == 'Info':
            return
        if len(args):
            msg = ' '.join(args)
        else:
            msg = None
776 777
        if room.joined:
            self.muc.quit_room(room.name, room.own_nick, msg)
778
        self.rooms.remove(self.current_room())
779
        self.window.refresh(self.rooms)
780

781 782 783 784 785 786 787 788 789 790 791
    def command_query(self, args):
        if len(args) != 1:
            return
        nick = args[0]
        room = self.current_room()
        if room.name == "Info" or room.jid is not None:
            return
        for user in room.users:
            if user.nick == nick:
                self.open_private_window(room.name, user.nick)

792
    def command_topic(self, args):
793 794 795
        """
        /topic [new topic]
        """
796
        room = self.current_room()
797
        if len(args) == 0:
798
            self.add_message_to_room(room, _("The subject of the room is: %s") % room.topic)
799
        subject = ' '.join(args)
800 801 802 803
        if not room.joined or room.name == "Info":
            return
        self.muc.change_subject(room.name, subject)

804
    def command_nick(self, args):
805 806 807
        """
        /nick <nickname>
        """
808 809 810 811 812 813 814 815
        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)

816
    def information(self, msg):
817 818 819
        """
        Displays an informational message in the "Info" room window
        """
820
        room = self.get_room_by_name("Info")
821
        self.add_message_to_room(room, msg)
822

823
    def command_quit(self, args):
824 825 826
        """
        /quit
        """
827
	self.reset_curses()
828
        sys.exit()