2010-01-10 20:14:17 +00:00
# -*- 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/>.
2010-01-31 05:33:54 +00:00
from gettext import ( bindtextdomain , textdomain , bind_textdomain_codeset ,
gettext as _ )
2010-06-13 15:40:03 +00:00
from os . path import isfile
2010-01-10 20:14:17 +00:00
2010-06-13 15:40:03 +00:00
from time import sleep
2010-01-31 05:33:54 +00:00
import sys
2010-06-30 09:56:03 +00:00
import os
2010-08-02 19:22:41 +00:00
import re
2010-01-31 05:33:54 +00:00
import curses
2010-08-02 19:22:41 +00:00
import webbrowser
2010-01-21 01:54:50 +00:00
from datetime import datetime
2010-03-19 03:30:51 +00:00
import common
2010-08-20 20:55:42 +00:00
import theme
2010-01-21 01:54:50 +00:00
2010-08-31 23:11:02 +00:00
import multiuserchat as muc
2010-01-31 05:33:54 +00:00
from handler import Handler
2010-01-30 02:50:24 +00:00
from config import config
2010-01-21 01:54:50 +00:00
from window import Window
2010-03-18 19:43:44 +00:00
from user import User
from room import Room
2010-06-10 01:17:59 +00:00
from message import Message
2010-07-08 19:27:53 +00:00
from keyboard import read_char
2010-08-31 23:11:02 +00:00
from common import is_jid_the_same , jid_get_domain , jid_get_resource , is_jid
2010-06-13 13:51:02 +00:00
2010-08-05 22:24:23 +00:00
# http://xmpp.org/extensions/xep-0045.html#errorstatus
ERROR_AND_STATUS_CODES = {
' 401 ' : ' A password is required ' ,
' 403 ' : ' You are banned from the room ' ,
' 404 ' : ' The room does \' nt exist ' ,
' 405 ' : ' Your are not allowed to create a new room ' ,
' 406 ' : ' A reserved nick must be used ' ,
' 407 ' : ' You are not in the member list ' ,
' 409 ' : ' This nickname is already in use or has been reserved ' ,
' 503 ' : ' The maximum number of users has been reached ' ,
}
2010-09-02 00:44:18 +00:00
SHOW_NAME = {
' dnd ' : _ ( ' busy ' ) ,
' away ' : _ ( ' away ' ) ,
' xa ' : _ ( ' not available ' ) ,
' chat ' : _ ( ' chatty ' ) ,
' ' : _ ( ' available ' )
}
2010-06-10 01:17:59 +00:00
def doupdate ( ) :
curses . doupdate ( )
2010-01-11 13:28:57 +00:00
2010-01-10 20:14:17 +00:00
class Gui ( object ) :
"""
2010-05-18 13:29:02 +00:00
User interface using ncurses
2010-01-10 20:14:17 +00:00
"""
2010-08-31 23:11:02 +00:00
def __init__ ( self , xmpp ) :
self . stdscr = curses . initscr ( )
self . init_curses ( self . stdscr )
self . xmpp = xmpp
self . window = Window ( self . stdscr )
2010-06-10 01:17:59 +00:00
self . rooms = [ Room ( ' Info ' , ' ' , self . window ) ]
2010-06-12 17:28:51 +00:00
self . ignores = { }
2010-02-11 04:59:58 +00:00
2010-01-13 01:04:30 +00:00
self . commands = {
2010-06-12 21:28:34 +00:00
' help ' : ( self . command_help , u ' \ _o< KOIN KOIN KOIN ' ) ,
2010-07-01 21:38:57 +00:00
' join ' : ( self . command_join , _ ( " Usage: /join [room_name][@server][/nick] [password] \n Join: 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 room_name without specifying a server, the server of the room you ' re currently in will be used. You can also provide a password to join the room. \n Examples: \n /join room@server.tld \n /join room@server.tld/John \n /join room2 \n /join /me_again \n /join \n /join room@server.tld/my_nick password \n /join / password " ) ) ,
2010-06-13 00:09:28 +00:00
' quit ' : ( self . command_quit , _ ( " Usage: /quit \n Quit: Just disconnect from the server and exit poezio. " ) ) ,
' exit ' : ( self . command_quit , _ ( " Usage: /exit \n Exit: Just disconnect from the server and exit poezio. " ) ) ,
' next ' : ( self . rotate_rooms_right , _ ( " Usage: /next \n Next: Go to the next room. " ) ) ,
' n ' : ( self . rotate_rooms_right , _ ( " Usage: /n \n N: Go to the next room. " ) ) ,
' prev ' : ( self . rotate_rooms_left , _ ( " Usage: /prev \n Prev: Go to the previous room. " ) ) ,
' p ' : ( self . rotate_rooms_left , _ ( " Usage: /p \n P: Go to the previous room. " ) ) ,
' win ' : ( self . command_win , _ ( " Usage: /win <number> \n Win: Go to the specified room. " ) ) ,
' w ' : ( self . command_win , _ ( " Usage: /w <number> \n W: Go to the specified room. " ) ) ,
2010-06-13 16:09:12 +00:00
' ignore ' : ( self . command_ignore , _ ( " Usage: /ignore <nickname> \n Ignore: Ignore a specified nickname. " ) ) ,
' unignore ' : ( self . command_unignore , _ ( " Usage: /unignore <nickname> \n Unignore: Remove the specified nickname from the ignore list. " ) ) ,
2010-06-13 00:09:28 +00:00
' 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] \n Show: 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] \n Away: 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] \n Busy: 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] \n Available: 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] \n Bookmark: 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) " ) ) ,
2010-06-21 08:46:06 +00:00
' unquery ' : ( self . command_unquery , _ ( " Usage: /unquery \n Close the private conversation window " ) ) ,
2010-06-13 00:09:28 +00:00
' set ' : ( self . command_set , _ ( " Usage: /set <option> [value] \n Set: 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] \n Kick: Kick the user with the specified nickname. You also can give an optional reason. " ) ) ,
' topic ' : ( self . command_topic , _ ( " Usage: /topic <subject> \n Topic: Change the subject of the room " ) ) ,
2010-08-02 19:22:41 +00:00
' link ' : ( self . command_link , _ ( " Usage: /link [option] [number] \n Link: Interact with a link in the conversation. Available options are ' open ' , ' copy ' . Open just opens the link in the browser if it ' s http://, Copy just copy the link in the clipboard. An optional number can be provided, it indicates which link to interact with. " ) ) ,
2010-07-01 21:48:49 +00:00
' query ' : ( self . command_query , _ ( ' Usage: /query <nick> [message] \n Query: Open a private conversation with <nick>. This nick has to be present in the room you \' re currently in. If you specified a message after the nickname, it will immediately be sent to this user ' ) ) ,
2010-08-05 22:37:55 +00:00
' nick ' : ( self . command_nick , _ ( " Usage: /nick <nickname> \n Nick: Change your nickname in the current room " ) ) ,
' say ' : ( self . command_say , _ ( ' Usage: /say <message> \n Say: Just send the message. Useful if you want your message to begin with a " / " ' ) ) ,
2010-08-07 00:28:47 +00:00
' whois ' : ( self . command_whois , _ ( ' Usage: /whois <nickname> \n Whois: Request many informations about the user. ' ) ) ,
2010-08-20 20:55:42 +00:00
' theme ' : ( self . command_theme , _ ( ' Usage: /theme \n Theme: Reload the theme defined in the config file. ' ) ) ,
2010-01-13 01:04:30 +00:00
}
2010-01-27 19:46:08 +00:00
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 ,
2010-06-10 01:17:59 +00:00
" KEY_PPAGE " : self . scroll_page_up ,
" KEY_NPAGE " : self . scroll_page_down ,
2010-01-27 22:29:28 +00:00
" KEY_DC " : self . window . input . key_dc ,
2010-01-28 00:55:02 +00:00
" KEY_F(5) " : self . rotate_rooms_left ,
2010-07-20 10:01:37 +00:00
" ^P " : self . rotate_rooms_left ,
2010-01-28 00:55:02 +00:00
" KEY_F(6) " : self . rotate_rooms_right ,
2010-07-20 10:01:37 +00:00
" ^N " : self . rotate_rooms_right ,
2010-07-08 20:42:01 +00:00
" \t " : self . completion ,
" ^I " : self . completion ,
2010-07-08 20:57:07 +00:00
" KEY_BTAB " : self . last_words_completion ,
2010-07-08 20:20:43 +00:00
" KEY_RESIZE " : self . resize_window ,
2010-07-08 19:27:53 +00:00
" KEY_BACKSPACE " : self . window . input . key_backspace ,
2010-07-20 17:25:41 +00:00
' ^? ' : self . window . input . key_backspace ,
2010-07-08 19:27:53 +00:00
' ^J ' : self . execute ,
' \n ' : self . execute ,
' ^D ' : self . window . input . key_dc ,
' ^W ' : self . window . input . delete_word ,
' ^K ' : self . window . input . delete_end_of_line ,
' ^U ' : self . window . input . delete_begining_of_line ,
' ^Y ' : self . window . input . paste_clipboard ,
' ^A ' : self . window . input . key_home ,
' ^E ' : self . window . input . key_end ,
' M-f ' : self . window . input . jump_word_right ,
' ^X ' : self . go_to_important_room ,
' M-b ' : self . window . input . jump_word_left
2010-01-27 19:46:08 +00:00
}
2010-08-31 23:11:02 +00:00
# Add handlers
self . xmpp . add_event_handler ( " session_start " , self . on_connected )
self . xmpp . add_event_handler ( " groupchat_presence " , self . on_groupchat_presence )
self . xmpp . add_event_handler ( " groupchat_message " , self . on_groupchat_message )
self . xmpp . add_event_handler ( " message " , self . on_message )
# 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)
# self.handler.connect('private-message', self.private_message)
# self.handler.connect('error-message', self.room_error)
# self.handler.connect('error', self.information)
def on_connected ( self , event ) :
"""
Called when we are connected and authenticated
"""
self . information ( _ ( " Welcome on Poezio \ o/! " ) )
self . information ( _ ( " Your JID is %s " ) % self . xmpp . fulljid )
rooms = config . get ( ' rooms ' , ' ' )
if rooms == ' ' or not isinstance ( rooms , str ) :
return
rooms = rooms . split ( ' : ' )
for room in rooms :
args = room . split ( ' / ' )
if args [ 0 ] == ' ' :
return
roomname = args [ 0 ]
if len ( args ) == 2 :
nick = args [ 1 ]
else :
default = os . environ . get ( ' USER ' ) if os . environ . get ( ' USER ' ) else ' poezio '
nick = config . get ( ' default_nick ' , ' ' )
if nick == ' ' :
nick = default
self . open_new_room ( roomname , nick )
muc . join_groupchat ( self . xmpp , roomname , nick )
# Todo: SEND VCARD
return
if config . get ( ' jid ' , ' ' ) == ' ' : # Don't send the vcard if we're not anonymous
self . vcard_sender . start ( ) # because the user ALREADY has one on the server
def on_groupchat_presence ( self , presence ) :
"""
Triggered whenever a presence stanza is received from a user in a multi - user chat room .
Display the presence on the room window and update the
presence information of the concerned user
"""
from_nick = presence [ ' from ' ] . resource
from_room = presence [ ' from ' ] . bare
room = self . get_room_by_name ( from_room )
code = presence . find ( ' { jabber:client}status ' )
status_codes = set ( [ s . attrib [ ' code ' ] for s in presence . findall ( ' { http://jabber.org/protocol/muc#user}x/ { http://jabber.org/protocol/muc#user}status ' ) ] )
# Check if it's not an error presence.
if presence [ ' type ' ] == ' error ' :
return self . room_error ( presence , from_room )
if not room :
return
2010-09-02 00:26:37 +00:00
msg = None
affiliation = presence [ ' muc ' ] [ ' affiliation ' ]
show = presence [ ' show ' ]
status = presence [ ' status ' ]
role = presence [ ' muc ' ] [ ' role ' ]
jid = presence [ ' muc ' ] [ ' jid ' ]
typ = presence [ ' type ' ]
if not room . joined : # user in the room BEFORE us.
# ignore redondant presence message, see bug #1509
if from_nick not in [ user . nick for user in room . users ] :
new_user = User ( from_nick , affiliation , show , status , role )
room . users . append ( new_user )
if from_nick . encode ( ' utf-8 ' ) == room . own_nick :
room . joined = True
new_user . color = theme . COLOR_OWN_NICK
self . add_message_to_room ( room , _ ( " Your nickname is %s " ) % ( from_nick ) )
if ' 170 ' in status_codes :
self . add_message_to_room ( room , ' Warning: this room is publicly logged ' )
2010-08-31 23:11:02 +00:00
else :
2010-09-02 00:26:37 +00:00
change_nick = ' 303 ' in status_codes
kick = ' 307 ' in status_codes and typ == ' unavailable '
user = room . get_user_by_name ( from_nick )
# New user
if not user :
self . on_user_join ( room , from_nick , affiliation , show , status , role , jid )
# nick change
elif change_nick :
2010-09-02 01:11:21 +00:00
self . on_user_nick_change ( room , presence , user , from_nick , from_room )
2010-09-02 00:26:37 +00:00
# kick
elif kick :
2010-09-02 01:16:17 +00:00
self . on_user_kicked ( room , presence , user , from_nick )
2010-09-02 00:26:37 +00:00
# user quit
elif typ == ' unavailable ' :
2010-09-02 01:19:08 +00:00
self . on_user_leave_groupchat ( room , user , jid , status , from_nick , from_room )
2010-09-02 00:26:37 +00:00
# status change
else :
2010-09-02 01:22:22 +00:00
self . on_user_change_status ( room , user , from_nick , from_room , affiliation , role , show , status )
2010-09-02 00:26:37 +00:00
if room == self . current_room ( ) :
self . window . user_win . refresh ( room . users )
2010-08-31 23:11:02 +00:00
self . window . input . refresh ( )
doupdate ( )
2010-09-02 00:26:37 +00:00
def on_user_join ( self , room , from_nick , affiliation , show , status , role , jid ) :
"""
When a new user joins a groupchat
"""
room . users . append ( User ( from_nick , affiliation ,
show , status , role ) )
hide_exit_join = config . get ( ' hide_exit_join ' , - 1 )
if hide_exit_join != 0 :
if not jid . full :
self . add_message_to_room ( room , _ ( " %(spec)s [ %(nick)s ] joined the room " ) % { ' nick ' : from_nick , ' spec ' : theme . CHAR_JOIN } , colorized = True )
else :
self . add_message_to_room ( room , _ ( " %(spec)s [ %(nick)s ] ( %(jid)s ) joined the room " ) % { ' spec ' : theme . CHAR_JOIN , ' nick ' : from_nick , ' jid ' : jid . full } , colorized = True )
2010-09-02 01:11:21 +00:00
def on_user_nick_change ( self , room , presence , user , from_nick , from_room ) :
new_nick = presence . find ( ' { http://jabber.org/protocol/muc#user}x/ { http://jabber.org/protocol/muc#user}item ' ) . attrib [ ' nick ' ]
if user . nick == room . own_nick :
room . own_nick = new_nick
# 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 ) :
_room . own_nick = new_nick
user . change_nick ( new_nick )
self . add_message_to_room ( room , _ ( ' [ %(old)s ] is now known as [ %(new)s ] ' ) % { ' old ' : from_nick , ' new ' : new_nick } , colorized = True )
# rename the private tabs if needed
private_room = self . get_room_by_name ( ' %s / %s ' % ( from_room , from_nick ) )
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 ' : new_nick } , colorized = True )
new_jid = private_room . name . split ( ' / ' ) [ 0 ] + ' / ' + new_nick
private_room . jid = private_room . name = new_jid
2010-09-02 01:16:17 +00:00
def on_user_kicked ( self , room , presence , user , from_nick ) :
"""
When someone is kicked
"""
room . users . remove ( user )
by = presence . find ( ' { http://jabber.org/protocol/muc#user}x/ { http://jabber.org/protocol/muc#user}item/ { http://jabber.org/protocol/muc#user}actor ' )
reason = presence . find ( ' { http://jabber.org/protocol/muc#user}x/ { http://jabber.org/protocol/muc#user}item/ { http://jabber.org/protocol/muc#user}reason ' )
by = by . attrib [ ' jid ' ] if by else ' '
reason = reason . text # if reason else ''
if from_nick == room . own_nick : # we are kicked
room . disconnect ( )
if by :
kick_msg = _ ( " % (spec) [You] have been kicked by [ %(by)s ]. " ) % { ' spec ' : theme . CHAR_KICK , ' by ' : by }
else :
kick_msg = _ ( " %(spec)s [You] have been kicked. " ) % { ' spec ' : theme . CHAR_KICK }
# try to auto-rejoin
if config . get ( ' autorejoin ' , ' false ' ) == ' true ' :
muc . join_groupchat ( self . xmpp , room . name , room . own_nick )
else :
if by :
kick_msg = _ ( " %(spec)s [ %(nick)s ] has been kicked by %(by)s . " ) % { ' spec ' : theme . CHAR_KICK , ' nick ' : from_nick , ' by ' : by }
else :
kick_msg = _ ( " %(spec)s [ %(nick)s ] has been kicked " ) % { ' spec ' : theme . CHAR_KICK , ' nick ' : from_nick }
if reason :
kick_msg + = _ ( ' Reason: %(reason)s ' ) % { ' reason ' : reason }
self . add_message_to_room ( room , kick_msg , colorized = True )
2010-09-02 01:19:08 +00:00
def on_user_leave_groupchat ( self , room , user , jid , status , from_nick , from_room ) :
"""
When an user leaves a groupchat
"""
room . users . remove ( user )
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 ) :
if not jid . full :
leave_msg = _ ( ' %(spec)s [ %(nick)s ] has left the room ' ) % { ' nick ' : from_nick , ' spec ' : theme . CHAR_QUIT }
else :
leave_msg = _ ( ' %(spec)s [ %(nick)s ] ( %(jid)s ) has left the room ' ) % { ' spec ' : theme . CHAR_QUIT , ' nick ' : from_nick , ' jid ' : jid . full }
if status :
leave_msg + = ' ( %s ) ' % status
self . add_message_to_room ( room , leave_msg , colorized = True )
private_room = self . get_room_by_name ( ' %s / %s ' % ( from_room , from_nick ) )
if private_room :
if not status :
self . add_message_to_room ( private_room , _ ( ' %(spec)s [ %(nick)s ] has left the room ' ) % { ' nick ' : from_nick , ' spec ' : theme . CHAR_QUIT } , colorized = True )
else :
self . add_message_to_room ( private_room , _ ( ' %(spec)s [ %(nick)s ] has left the room ( %(status)s ) ' ) % { ' nick ' : from_nick , ' spec ' : theme . CHAR_QUIT , ' status ' : status } , colorized = True )
2010-09-02 01:22:22 +00:00
def on_user_change_status ( self , room , user , from_nick , from_room , affiliation , role , show , status ) :
"""
When an user changes her status
"""
# 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 and show in SHOW_NAME . keys ( ) :
msg + = _ ( ' show: %s , ' ) % SHOW_NAME [ show ]
if status != user . status :
msg + = _ ( ' status: %s , ' ) % status
msg = msg [ : - 1 ] # remove the last ","
hide_status_change = config . get ( ' hide_status_change ' , - 1 ) if config . get ( ' hide_status_change ' , - 1 ) > = - 1 else - 1
if ( hide_status_change == - 1 or \
user . has_talked_since ( hide_status_change ) or \
user . nick == room . own_nick ) \
and \
( affiliation != user . affiliation or \
role != user . role or \
show != user . show or \
status != user . status ) :
# display the message in the room
self . add_message_to_room ( room , msg )
private_room = self . get_room_by_name ( ' %s / %s ' % ( from_room , from_nick ) )
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 )
2010-08-31 23:11:02 +00:00
def on_message ( self , message ) :
"""
When receiving private message from a muc OR a normal message
( from one of our contacts )
"""
if message [ ' type ' ] == ' groupchat ' :
return None
# Differentiate both type of messages, and call the appropriate handler.
jid_from = message [ ' from ' ]
for room in self . rooms :
if room . jid is None and room . name == jid_from . bare : # check all the MUC we are in
return self . on_groupchat_private_message ( message )
return self . on_normal_message ( message )
def on_groupchat_private_message ( self , message ) :
"""
We received a Private Message ( from someone in a Muc )
"""
jid = message [ ' from ' ]
2010-09-02 01:11:21 +00:00
nick_from = jid . resource
room_from = jid . bare
2010-08-31 23:11:02 +00:00
room = self . get_room_by_name ( jid . full ) # 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 . encode ( ' utf-8 ' ) , False )
if not room :
return
body = message [ ' body ' ]
self . add_message_to_room ( room , body , None , nick_from )
self . window . input . refresh ( )
doupdate ( )
def on_normal_message ( self , message ) :
"""
When receiving " normal " messages ( from someone in our roster )
"""
return
2010-01-21 01:54:50 +00:00
2010-07-08 20:20:43 +00:00
def resize_window ( self ) :
"""
Resize the whole screen
"""
self . window . resize ( self . stdscr )
self . window . refresh ( self . rooms )
2010-08-31 23:11:02 +00:00
def main_loop ( self ) :
2010-05-18 13:29:02 +00:00
"""
main loop waiting for the user to press a key
"""
2010-08-04 23:54:02 +00:00
self . refresh_window ( )
2010-07-08 19:27:53 +00:00
while True :
2010-06-10 01:17:59 +00:00
doupdate ( )
2010-08-31 23:11:02 +00:00
char = read_char ( self . stdscr )
2010-08-07 00:28:47 +00:00
try : # if this is not a valide utf-8 char, discard it
2010-08-07 00:36:49 +00:00
char . decode ( ' utf-8 ' )
2010-08-07 00:28:47 +00:00
except UnicodeDecodeError :
continue
2010-07-08 19:27:53 +00:00
# search for keyboard shortcut
if char in self . key_func . keys ( ) :
self . key_func [ char ] ( )
2010-01-27 19:46:08 +00:00
else :
2010-07-19 19:38:33 +00:00
if len ( char . decode ( ' utf-8 ' ) ) > 1 :
continue # ignore non-handled keyboard shortcuts
2010-07-08 19:27:53 +00:00
self . window . do_command ( char )
2010-01-27 19:46:08 +00:00
2010-01-26 17:10:37 +00:00
def current_room ( self ) :
2010-05-18 13:29:02 +00:00
"""
returns the current room , the one we are viewing
"""
2010-02-10 16:47:43 +00:00
return self . rooms [ 0 ]
2010-01-26 17:10:37 +00:00
def get_room_by_name ( self , name ) :
2010-05-18 13:29:02 +00:00
"""
returns the room that has this name
"""
for room in self . rooms :
2010-08-11 23:56:39 +00:00
try :
if room . name . decode ( ' utf-8 ' ) == name :
return room
except UnicodeEncodeError :
if room . name == name :
return room
2010-05-18 13:29:02 +00:00
return None
2010-01-26 17:10:37 +00:00
2010-01-21 01:54:50 +00:00
def init_curses ( self , stdscr ) :
2010-05-18 13:29:02 +00:00
"""
ncurses initialization
"""
2010-08-20 20:55:42 +00:00
theme . init_colors ( )
2010-01-21 01:54:50 +00:00
curses . noecho ( )
2010-06-10 01:17:59 +00:00
curses . curs_set ( 0 )
2010-01-27 19:46:08 +00:00
stdscr . keypad ( True )
2010-01-21 01:54:50 +00:00
2010-01-26 17:10:37 +00:00
def reset_curses ( self ) :
2010-05-18 13:29:02 +00:00
"""
Reset terminal capabilities to what they were before ncurses
init
"""
2010-08-31 23:11:02 +00:00
# TODO remove me?
2010-05-18 13:29:02 +00:00
curses . echo ( )
2010-02-14 04:18:34 +00:00
curses . nocbreak ( )
2010-01-27 17:02:13 +00:00
curses . endwin ( )
2010-01-26 17:10:37 +00:00
2010-08-04 00:17:53 +00:00
def refresh_window ( self ) :
"""
Refresh everything
"""
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_CURRENT )
2010-08-04 00:17:53 +00:00
self . window . refresh ( self . rooms )
2010-08-31 23:11:02 +00:00
def open_new_room ( self , room , nick , focus = True ) :
2010-05-18 13:29:02 +00:00
"""
2010-08-31 23:11:02 +00:00
Open a new Tab containing a Muc room , using the specified nick
2010-05-18 13:29:02 +00:00
"""
2010-06-10 01:17:59 +00:00
r = Room ( room , nick , self . window )
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_NORMAL )
2010-02-11 04:59:58 +00:00
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
2010-08-31 23:11:02 +00:00
if focus :
self . command_win ( " %s " % r . nb )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-01-21 01:54:50 +00:00
2010-07-08 20:42:01 +00:00
def completion ( self ) :
2010-05-18 13:29:02 +00:00
"""
Called when Tab is pressed , complete the nickname in the input
"""
2010-07-01 22:51:19 +00:00
def compare_users ( a , b ) :
"""
2010-08-07 19:18:36 +00:00
Used to sort users by their last_talked
2010-07-01 22:51:19 +00:00
"""
2010-08-07 19:18:36 +00:00
if not a . last_talked and b . last_talked :
2010-07-01 22:51:19 +00:00
return 0
2010-08-07 19:18:36 +00:00
elif not b . last_talked and a . last_talked :
return 1
if a . last_talked < b . last_talked :
return 1
else :
2010-07-01 22:51:19 +00:00
return - 1
2010-08-07 19:18:36 +00:00
self . window . input . auto_completion ( [ user . nick for user in sorted ( self . current_room ( ) . users , compare_users ) ] )
2010-07-08 20:42:01 +00:00
2010-07-08 20:57:07 +00:00
def last_words_completion ( self ) :
"""
Complete the input with words recently said
"""
# build the list of the recent words
char_we_dont_want = [ ' , ' , ' ( ' , ' ) ' , ' . ' ]
words = list ( )
2010-07-20 21:50:41 +00:00
for msg in self . current_room ( ) . messages [ : - 9 : - 1 ] :
2010-08-14 08:58:31 +00:00
if not msg :
continue
2010-07-08 20:57:07 +00:00
for word in msg . txt . split ( ) :
for char in char_we_dont_want : # remove the chars we don't want
word = word . replace ( char , ' ' )
if len ( word ) > 5 :
2010-07-20 20:02:12 +00:00
words . append ( word . encode ( ' utf-8 ' ) )
2010-07-08 20:57:07 +00:00
self . window . input . auto_completion ( words )
2010-07-08 19:27:53 +00:00
def go_to_important_room ( self ) :
"""
Go to the next room with activity , in this order :
- A personal conversation with a new message
- A Muc with an highlight
- A Muc with any new message
"""
for room in self . rooms :
2010-08-20 20:55:42 +00:00
if room . color_state == theme . COLOR_TAB_PRIVATE :
2010-08-04 00:17:53 +00:00
self . command_win ( ' %s ' % room . nb )
2010-07-08 19:27:53 +00:00
return
for room in self . rooms :
2010-08-20 20:55:42 +00:00
if room . color_state == theme . COLOR_TAB_HIGHLIGHT :
2010-08-04 00:17:53 +00:00
self . command_win ( ' %s ' % room . nb )
2010-07-08 19:27:53 +00:00
return
for room in self . rooms :
2010-08-20 20:55:42 +00:00
if room . color_state == theme . COLOR_TAB_NEW_MESSAGE :
2010-08-04 00:17:53 +00:00
self . command_win ( ' %s ' % room . nb )
return
2010-07-08 19:27:53 +00:00
2010-02-11 04:59:58 +00:00
def rotate_rooms_right ( self , args = None ) :
2010-05-18 13:29:02 +00:00
"""
rotate the rooms list to the right
"""
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_NORMAL )
2010-08-09 00:23:59 +00:00
self . current_room ( ) . remove_line_separator ( )
2010-01-21 01:54:50 +00:00
self . rooms . append ( self . rooms . pop ( 0 ) )
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_CURRENT )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-01-21 01:54:50 +00:00
2010-02-11 04:59:58 +00:00
def rotate_rooms_left ( self , args = None ) :
2010-05-18 13:29:02 +00:00
"""
rotate the rooms list to the right
"""
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_NORMAL )
2010-08-09 00:23:59 +00:00
self . current_room ( ) . remove_line_separator ( )
2010-01-21 01:54:50 +00:00
self . rooms . insert ( 0 , self . rooms . pop ( ) )
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_CURRENT )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-01-21 01:54:50 +00:00
2010-06-10 01:17:59 +00:00
def scroll_page_down ( self , args = None ) :
2010-08-04 00:48:50 +00:00
self . current_room ( ) . scroll_down ( self . window . text_win . height - 1 )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-06-10 01:17:59 +00:00
def scroll_page_up ( self , args = None ) :
2010-08-04 00:48:50 +00:00
self . current_room ( ) . scroll_up ( self . window . text_win . height - 1 )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-06-10 01:17:59 +00:00
2010-08-31 23:11:02 +00:00
def room_error ( self , error , room_name ) :
2010-05-18 13:29:02 +00:00
"""
Display the error on the room window
"""
2010-08-31 23:11:02 +00:00
room = self . get_room_by_name ( room_name )
2010-08-05 22:24:23 +00:00
if not room :
room = self . get_room_by_name ( ' Info ' )
2010-08-31 23:11:02 +00:00
msg = error [ ' error ' ] [ ' type ' ]
condition = error [ ' error ' ] [ ' condition ' ]
code = error [ ' error ' ] [ ' code ' ]
body = error [ ' error ' ] [ ' text ' ]
if not body :
2010-08-05 22:24:51 +00:00
if code in ERROR_AND_STATUS_CODES . keys ( ) :
body = ERROR_AND_STATUS_CODES [ code ]
else :
2010-08-31 23:11:02 +00:00
body = condition or _ ( ' Unknown error ' )
if code :
self . add_message_to_room ( room , _ ( ' Error: %(code)s - %(msg)s : %(body)s ' %
{ ' msg ' : msg , ' body ' : body , ' code ' : code } ) )
else :
self . add_message_to_room ( room , _ ( ' Error: %(msg)s : %(body)s ' %
{ ' msg ' : msg , ' body ' : body } ) )
2010-03-24 18:01:22 +00:00
if code == ' 401 ' :
2010-08-05 22:24:23 +00:00
self . add_message_to_room ( room , _ ( ' To provide a password in order to join the room, type " /join / password " (replace " password " by the real password) ' ) )
if code == ' 409 ' :
2010-08-07 00:57:36 +00:00
if config . get ( ' alternative_nickname ' , ' ' ) != ' ' :
self . command_join ( ' %s / %s ' % ( room . name , room . own_nick + config . get ( ' alternative_nickname ' , ' ' ) ) )
else :
2010-08-07 01:02:26 +00:00
self . add_message_to_room ( room , _ ( ' You can join the room with an other nick, by typing " /join /other_nick " ' ) )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-03-24 18:01:22 +00:00
2010-06-13 13:51:02 +00:00
def open_private_window ( self , room_name , user_nick , focus = True ) :
2010-08-11 23:56:39 +00:00
complete_jid = room_name . decode ( ' utf-8 ' ) + ' / ' + user_nick
2010-06-13 13:51:02 +00:00
for room in self . rooms : # if the room exists, focus it and return
if room . jid :
if room . jid == complete_jid :
2010-08-04 00:17:53 +00:00
self . command_win ( ' %s ' % room . nb )
2010-06-13 13:51:02 +00:00
return
# create the new tab
2010-09-02 01:11:21 +00:00
room = self . get_room_by_name ( room_name )
2010-07-19 19:38:33 +00:00
if not room :
return None
own_nick = room . own_nick
2010-06-13 13:51:02 +00:00
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
2010-08-11 19:14:36 +00:00
self . command_win ( ' %s ' % ( r . nb ) )
2010-06-13 13:51:02 +00:00
# self.window.new_room(r)
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-06-13 13:51:02 +00:00
return r
2010-08-31 23:11:02 +00:00
def on_groupchat_message ( self , message ) :
2010-05-18 13:29:02 +00:00
"""
2010-08-31 23:11:02 +00:00
Triggered whenever a message is received from a multi - user chat room .
2010-05-18 13:29:02 +00:00
"""
2010-08-31 23:11:02 +00:00
# FIXME: not receiving subjects? :/
delay_tag = message . find ( ' { urn:xmpp:delay}delay ' )
if delay_tag is not None :
2010-03-19 03:30:51 +00:00
delayed = True
2010-08-31 23:11:02 +00:00
date = common . datetime_tuple ( delay_tag . attrib [ ' stamp ' ] )
2010-03-19 03:30:51 +00:00
else :
2010-07-26 00:51:07 +00:00
# We support the OLD and deprecated XEP: http://xmpp.org/extensions/xep-0091.html
# But it sucks, please, Jabber servers, don't do this :(
2010-08-31 23:11:02 +00:00
delay_tag = message . find ( ' { jabber:x:delay}x ' )
if delay_tag is not None :
2010-07-26 00:51:07 +00:00
delayed = True
2010-08-31 23:11:02 +00:00
date = common . datetime_tuple ( delay_tag . attrib [ ' stamp ' ] )
2010-07-26 00:51:07 +00:00
else :
delayed = False
2010-08-31 23:11:02 +00:00
date = None
2010-09-02 00:44:18 +00:00
nick_from = message [ ' mucnick ' ]
2010-08-31 23:11:02 +00:00
room_from = message . getMucroom ( )
2010-09-02 00:44:18 +00:00
if nick_from == room_from :
nick_from = None
2010-08-31 23:11:02 +00:00
room = self . get_room_by_name ( room_from )
2010-06-12 17:28:51 +00:00
if ( self . ignores . has_key ( room_from ) ) and ( nick_from in self . ignores [ room_from ] ) :
return
2010-03-18 19:43:44 +00:00
room = self . get_room_by_name ( room_from )
2010-08-31 23:11:02 +00:00
if not room :
self . information ( _ ( " message received for a non-existing room: %s " ) % ( room_from ) )
2010-01-28 00:55:02 +00:00
return
2010-09-02 00:44:18 +00:00
body = message [ ' body ' ]
subject = message [ ' subject ' ]
2010-02-14 04:30:04 +00:00
if subject :
2010-02-14 04:41:14 +00:00
if nick_from :
2010-08-31 23:11:02 +00:00
self . add_message_to_room ( room , _ ( " %(nick)s changed the subject to: %(subject)s " ) % { ' nick ' : nick_from , ' subject ' : subject } , time = date )
2010-02-14 04:41:14 +00:00
else :
2010-08-31 23:11:02 +00:00
self . add_message_to_room ( room , _ ( " The subject is: %(subject)s " ) % { ' subject ' : subject } , time = date )
2010-02-14 04:30:04 +00:00
room . topic = subject . encode ( ' utf-8 ' ) . replace ( ' \n ' , ' | ' )
2010-01-28 00:55:02 +00:00
if room == self . current_room ( ) :
self . window . topic_win . refresh ( room . topic )
2010-05-11 16:45:14 +00:00
elif body :
2010-03-18 19:43:44 +00:00
if body . startswith ( ' /me ' ) :
2010-06-13 00:09:28 +00:00
self . add_message_to_room ( room , " * " + nick_from + ' ' + body [ 4 : ] , date )
2010-02-14 13:33:33 +00:00
else :
2010-06-10 01:17:59 +00:00
date = date if delayed == True else None
self . add_message_to_room ( room , body , date , nick_from )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-06-10 01:17:59 +00:00
doupdate ( )
2010-01-21 01:54:50 +00:00
2010-03-18 19:43:44 +00:00
2010-08-22 16:33:57 +00:00
def add_message_to_room ( self , room , txt , time = None , nickname = None , colorized = False ) :
2010-03-18 19:43:44 +00:00
"""
2010-06-10 01:17:59 +00:00
Add the message to the room and refresh the associated component
of the interface
2010-03-18 19:43:44 +00:00
"""
2010-08-09 00:23:59 +00:00
if room != self . current_room ( ) :
room . add_line_separator ( )
2010-08-22 16:33:57 +00:00
room . add_message ( txt , time , nickname , colorized )
2010-03-18 19:43:44 +00:00
if room == self . current_room ( ) :
2010-06-10 01:17:59 +00:00
self . window . text_win . refresh ( room )
else :
2010-03-19 02:06:51 +00:00
self . window . info_win . refresh ( self . rooms , self . current_room ( ) )
2010-06-21 08:38:48 +00:00
self . window . input . refresh ( )
2010-01-13 01:04:30 +00:00
def execute ( self ) :
2010-05-18 13:29:02 +00:00
"""
Execute the / command or just send the line on the current room
"""
2010-01-21 01:54:50 +00:00
line = self . window . input . get_text ( )
self . window . input . clear_text ( )
2010-01-30 03:06:38 +00:00
self . window . input . refresh ( )
2010-01-21 01:54:50 +00:00
if line == " " :
return
2010-06-13 14:09:50 +00:00
if line . startswith ( ' / ' ) and not line . startswith ( ' /me ' ) :
2010-01-13 01:04:30 +00:00
command = line . strip ( ) [ : ] . split ( ) [ 0 ] [ 1 : ]
2010-08-05 22:37:55 +00:00
arg = line [ 2 + len ( command ) : ] # jump the '/' and the ' '
2010-08-02 19:22:41 +00:00
# example. on "/link 0 open", command = "link" and arg = "0 open"
2010-01-13 01:04:30 +00:00
if command in self . commands . keys ( ) :
2010-01-30 04:42:29 +00:00
func = self . commands [ command ] [ 0 ]
2010-08-02 19:22:41 +00:00
func ( arg )
2010-01-27 22:29:28 +00:00
return
2010-02-16 02:03:23 +00:00
else :
2010-06-10 01:17:59 +00:00
self . add_message_to_room ( self . current_room ( ) , _ ( " Error: unknown command ( %s ) " ) % ( command ) )
2010-02-16 02:03:23 +00:00
elif self . current_room ( ) . name != ' Info ' :
2010-06-13 13:51:02 +00:00
if self . current_room ( ) . jid is not None :
2010-08-31 23:11:02 +00:00
muc . send_private_message ( self . xmpp , self . current_room ( ) . name , line )
2010-08-11 23:56:39 +00:00
self . add_message_to_room ( self . current_room ( ) , line . decode ( ' utf-8 ' ) , None , self . current_room ( ) . own_nick . decode ( ' utf-8 ' ) )
2010-06-13 13:51:02 +00:00
else :
2010-08-31 23:11:02 +00:00
muc . send_groupchat_message ( self . xmpp , self . current_room ( ) . name , line )
2010-03-18 19:43:44 +00:00
self . window . input . refresh ( )
2010-06-10 01:17:59 +00:00
doupdate ( )
2010-01-13 01:04:30 +00:00
2010-08-02 19:22:41 +00:00
def command_help ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ help < command_name >
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-01-30 04:42:29 +00:00
room = self . current_room ( )
if len ( args ) == 0 :
2010-06-13 00:09:28 +00:00
msg = _ ( ' Available commands are: ' )
2010-01-30 04:42:29 +00:00
for command in self . commands . keys ( ) :
msg + = " %s " % command
2010-01-31 05:33:54 +00:00
msg + = _ ( " \n Type /help <command_name> to know what each command does " )
2010-01-30 04:42:29 +00:00
if len ( args ) == 1 :
if args [ 0 ] in self . commands . keys ( ) :
msg = self . commands [ args [ 0 ] ] [ 1 ]
else :
2010-01-31 05:33:54 +00:00
msg = _ ( ' Unknown command: %s ' ) % args [ 0 ]
2010-06-10 01:17:59 +00:00
self . add_message_to_room ( room , msg )
2010-01-30 04:42:29 +00:00
2010-08-07 00:28:47 +00:00
def command_whois ( self , arg ) :
"""
/ whois < nickname >
"""
2010-08-31 23:11:02 +00:00
# TODO
return
2010-08-07 00:28:47 +00:00
args = arg . split ( )
room = self . current_room ( )
if len ( args ) != 1 :
self . add_message_to_room ( room , _ ( ' whois command takes exactly one argument ' ) )
return
# check if current room is a MUC
if room . jid or room . name == ' Info ' :
return
nickname = args [ 0 ]
self . muc . request_vcard ( room . name , nickname )
2010-08-20 20:55:42 +00:00
def command_theme ( self , arg ) :
"""
"""
theme . reload_theme ( )
2010-08-22 14:57:47 +00:00
self . resize_window ( )
2010-08-20 20:55:42 +00:00
2010-08-02 19:22:41 +00:00
def command_win ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ win < number >
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-02-12 02:50:07 +00:00
if len ( args ) != 1 :
2010-08-11 19:14:36 +00:00
self . command_help ( ' win ' )
2010-02-12 02:50:07 +00:00
return
try :
nb = int ( args [ 0 ] )
except ValueError :
2010-08-11 19:14:36 +00:00
self . command_help ( ' win ' )
2010-02-12 02:50:07 +00:00
return
if self . current_room ( ) . nb == nb :
return
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_NORMAL )
2010-08-09 00:23:59 +00:00
self . current_room ( ) . remove_line_separator ( )
2010-02-12 02:50:07 +00:00
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 :
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_CURRENT )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-02-12 02:50:07 +00:00
return
2010-08-20 20:55:42 +00:00
self . current_room ( ) . set_color_state ( theme . COLOR_TAB_CURRENT )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-02-12 02:50:07 +00:00
2010-08-02 19:22:41 +00:00
def command_kick ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ kick < nick > [ reason ]
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-02-02 23:57:32 +00:00
if len ( args ) < 1 :
2010-08-11 19:14:36 +00:00
self . command_help ( ' kick ' )
2010-02-02 23:57:32 +00:00
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
2010-08-31 23:11:02 +00:00
res = muc . eject_user ( self . xmpp , roomname , nick , reason )
if res [ ' type ' ] == ' error ' :
self . room_error ( res , roomname )
2010-02-02 23:57:32 +00:00
2010-08-05 22:37:55 +00:00
def command_say ( self , arg ) :
"""
/ say < message >
"""
line = arg
if self . current_room ( ) . name != ' Info ' :
if self . current_room ( ) . jid is not None :
2010-08-31 23:11:02 +00:00
muc . send_private_message ( self . xmpp , self . current_room ( ) . name , line )
2010-08-05 22:37:55 +00:00
self . add_message_to_room ( self . current_room ( ) , line . decode ( ' utf-8 ' ) , None , self . current_room ( ) . own_nick )
else :
2010-08-31 23:11:02 +00:00
muc . send_groupchat_message ( self . xmpp , self . current_room ( ) . name , line )
2010-08-05 22:37:55 +00:00
self . window . input . refresh ( )
doupdate ( )
2010-08-02 19:22:41 +00:00
def command_join ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ join [ room ] [ / nick ] [ password ]
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-03-24 18:01:22 +00:00
password = None
2010-01-30 04:02:23 +00:00
if len ( args ) == 0 :
r = self . current_room ( )
if r . name == ' Info ' :
return
room = r . name
nick = r . own_nick
2010-01-30 02:50:24 +00:00
else :
2010-01-30 04:02:23 +00:00
info = args [ 0 ] . split ( ' / ' )
if len ( info ) == 1 :
2010-06-30 09:56:03 +00:00
default = os . environ . get ( ' USER ' ) if os . environ . get ( ' USER ' ) else ' poezio '
nick = config . get ( ' default_nick ' , ' ' )
if nick == ' ' :
nick = default
2010-01-30 04:02:23 +00:00
else :
nick = info [ 1 ]
2010-01-31 03:07:30 +00:00
if info [ 0 ] == ' ' : # happens with /join /nickname, which is OK
2010-01-30 04:02:23 +00:00
r = self . current_room ( )
if r . name == ' Info ' :
return
room = r . name
2010-03-24 18:01:22 +00:00
if nick == ' ' :
nick = r . own_nick
2010-01-30 04:02:23 +00:00
else :
room = info [ 0 ]
2010-07-01 21:32:44 +00:00
if not is_jid ( room ) : # no server is provided, like "/join hello"
# use the server of the current room if available
# check if the current room's name has a server
if is_jid ( self . current_room ( ) . name ) :
2010-08-31 23:11:02 +00:00
room + = ' @ %s ' % jid_get_domain ( self . current_room ( ) . name )
2010-07-01 21:32:44 +00:00
else : # no server could be found, print a message and return
2010-07-14 17:04:50 +00:00
self . add_message_to_room ( self . current_room ( ) , _ ( " You didn ' t specify a server for the room you want to join " ) )
2010-07-01 21:32:44 +00:00
return
2010-01-30 04:02:23 +00:00
r = self . get_room_by_name ( room )
2010-03-24 18:01:22 +00:00
if len ( args ) == 2 : # a password is provided
password = args [ 1 ]
2010-07-01 21:32:44 +00:00
if r and r . joined : # if we are already in the room
2010-08-31 23:11:02 +00:00
self . command_win ( ' %s ' % ( r . nb ) )
2010-01-28 00:55:02 +00:00
return
2010-08-31 23:11:02 +00:00
room = room . lower ( )
self . xmpp . plugin [ ' xep_0045 ' ] . joinMUC ( room , nick , password )
2010-03-24 16:44:55 +00:00
if not r : # if the room window exists, we don't recreate it.
2010-08-31 23:11:02 +00:00
self . open_new_room ( room , nick )
2010-03-24 16:44:55 +00:00
else :
2010-07-08 20:05:06 +00:00
r . own_nick = nick
2010-03-24 16:44:55 +00:00
r . users = [ ]
2010-01-13 01:04:30 +00:00
2010-08-02 19:22:41 +00:00
def command_bookmark ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ bookmark [ room ] [ / nick ]
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-01-31 03:42:25 +00:00
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 ]
2010-02-14 04:10:13 +00:00
if roomname == ' ' :
roomname = self . current_room ( ) . name
2010-01-31 03:42:25 +00:00
if nick :
res = roomname + ' / ' + nick
else :
res = roomname
2010-02-14 04:10:13 +00:00
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 )
2010-07-14 17:04:50 +00:00
bookmarks = bookmarked + ' : ' + res
config . set_and_save ( ' rooms ' , bookmarks )
self . add_message_to_room ( self . current_room ( ) , _ ( ' Your bookmarks are now: %s ' ) % bookmarks )
2010-01-31 03:42:25 +00:00
2010-08-02 19:22:41 +00:00
def command_set ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ set < option > [ value ]
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-02-12 19:35:18 +00:00
if len ( args ) != 2 and len ( args ) != 1 :
2010-08-11 19:14:36 +00:00
self . command_help ( ' set ' )
2010-02-02 23:35:01 +00:00
return
option = args [ 0 ]
2010-02-12 19:35:18 +00:00
if len ( args ) == 2 :
value = args [ 1 ]
else :
value = ' '
2010-02-10 16:47:43 +00:00
config . set_and_save ( option , value )
2010-02-02 23:35:01 +00:00
msg = " %s = %s " % ( option , value )
room = self . current_room ( )
2010-06-10 01:17:59 +00:00
self . add_message_to_room ( room , msg )
2010-02-02 23:35:01 +00:00
2010-08-02 19:22:41 +00:00
def command_show ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ show < status > [ msg ]
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-07-22 17:47:34 +00:00
possible_show = { ' avail ' : None ,
' available ' : None ,
' ok ' : None ,
' here ' : None ,
2010-01-31 03:07:30 +00:00
' 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 ( ) :
2010-08-11 19:14:36 +00:00
self . command_help ( ' show ' )
2010-01-31 03:07:30 +00:00
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 :
2010-08-31 23:11:02 +00:00
muc . change_show ( self . xmpp , room . name , room . own_nick , show , msg )
2010-01-31 03:07:30 +00:00
2010-08-02 19:22:41 +00:00
def command_ignore ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ ignore < nick >
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-05-18 13:29:02 +00:00
if len ( args ) != 1 :
2010-08-11 19:14:36 +00:00
self . command_help ( ' ignore ' )
2010-06-12 17:28:51 +00:00
return
if self . current_room ( ) . name == ' Info ' or not self . current_room ( ) . joined :
2010-05-18 13:29:02 +00:00
return
2010-06-12 17:28:51 +00:00
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 )
2010-05-18 13:29:02 +00:00
2010-08-02 19:22:41 +00:00
def command_unignore ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ unignore < nick >
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-05-18 13:29:02 +00:00
if len ( args ) != 1 :
2010-08-11 19:14:36 +00:00
self . command_help ( ' unignore ' )
2010-06-12 17:28:51 +00:00
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 )
2010-05-18 13:29:02 +00:00
return
2010-06-12 17:28:51 +00:00
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 )
2010-05-18 13:29:02 +00:00
2010-08-02 19:22:41 +00:00
def command_away ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ away [ msg ]
"""
2010-08-02 19:22:41 +00:00
self . command_show ( " away " + arg )
2010-01-31 03:07:30 +00:00
2010-08-02 19:22:41 +00:00
def command_busy ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ busy [ msg ]
"""
2010-08-05 00:11:11 +00:00
self . command_show ( " busy " + arg )
2010-01-31 03:07:30 +00:00
2010-08-02 19:22:41 +00:00
def command_avail ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ avail [ msg ]
"""
2010-08-05 00:11:11 +00:00
self . command_show ( " available " + arg )
2010-01-31 00:25:17 +00:00
2010-08-02 19:22:41 +00:00
def command_part ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ part [ msg ]
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-01-30 04:02:23 +00:00
reason = None
room = self . current_room ( )
if room . name == ' Info ' :
return
if len ( args ) :
msg = ' ' . join ( args )
else :
msg = None
2010-01-30 04:42:29 +00:00
if room . joined :
2010-08-31 23:11:02 +00:00
muc . leave_groupchat ( self . xmpp , room . name , room . own_nick , arg )
2010-01-30 04:02:23 +00:00
self . rooms . remove ( self . current_room ( ) )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-01-30 04:02:23 +00:00
2010-08-02 19:22:41 +00:00
def command_unquery ( self , arg ) :
2010-06-21 08:46:06 +00:00
"""
/ unquery
"""
room = self . current_room ( )
if room . jid is not None :
self . rooms . remove ( room )
2010-08-04 00:17:53 +00:00
self . refresh_window ( )
2010-06-21 08:46:06 +00:00
2010-08-02 19:22:41 +00:00
def command_query ( self , arg ) :
2010-06-13 16:01:38 +00:00
"""
2010-07-01 21:48:49 +00:00
/ query < nick > [ message ]
2010-06-13 16:01:38 +00:00
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-07-01 21:48:49 +00:00
if len ( args ) < 1 :
2010-06-13 13:51:02 +00:00
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 :
2010-08-11 23:56:39 +00:00
r = self . open_private_window ( room . name , user . nick . decode ( ' utf-8 ' ) )
2010-08-11 19:14:36 +00:00
if r and len ( args ) > 1 :
msg = arg [ len ( nick ) + 1 : ]
2010-08-31 23:11:02 +00:00
muc . send_private_message ( r . name , msg )
2010-07-01 21:48:49 +00:00
self . add_message_to_room ( r , msg . decode ( ' utf-8 ' ) , None , r . own_nick )
2010-06-13 13:51:02 +00:00
2010-08-02 19:22:41 +00:00
def command_topic ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ topic [ new topic ]
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-03-19 03:37:34 +00:00
room = self . current_room ( )
2010-06-10 12:28:25 +00:00
if len ( args ) == 0 :
2010-06-13 16:06:48 +00:00
self . add_message_to_room ( room , _ ( " The subject of the room is: %s " ) % room . topic . decode ( ' utf-8 ' ) )
2010-07-26 00:13:47 +00:00
return
2010-06-10 12:28:25 +00:00
subject = ' ' . join ( args )
2010-03-19 03:37:34 +00:00
if not room . joined or room . name == " Info " :
return
2010-08-31 23:11:02 +00:00
muc . change_subject ( self . xmpp , room . name , subject )
2010-03-19 03:37:34 +00:00
2010-08-02 19:22:41 +00:00
def command_link ( self , arg ) :
"""
/ link < option > < nb >
Opens the link in a browser , or join the room , or add the JID , or
copy it in the clipboard
"""
args = arg . split ( )
if len ( args ) > 2 :
self . add_message_to_room ( self . current_room ( ) ,
_ ( " Link: This command takes at most 2 arguments " ) )
return
# set the default parameters
option = " open "
nb = 0
# check the provided parameters
if len ( args ) > = 1 :
try : # check if the argument is the number
nb = int ( args [ 0 ] )
except ValueError : # nope, it's the option
option = args [ 0 ]
if len ( args ) == 2 :
try :
nb = int ( args [ 0 ] )
except ValueError :
self . add_message_to_room ( self . current_room ( ) ,
_ ( " Link: 2nd parameter should be a number " ) )
return
# find the nb-th link in the current buffer
i = 0
link = None
for msg in self . current_room ( ) . messages [ : - 200 : - 1 ] :
2010-08-14 08:58:31 +00:00
if not msg :
continue
2010-08-02 19:22:41 +00:00
matches = re . findall ( ' " ((ftp|http|https|gopher|mailto|news|nntp|telnet|wais|file|prospero|aim|webcal):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])| % [A-Fa-f0-9] {2} ) { 2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~= % -]*))?([A-Za-z0-9$_+!*();/?:~-])) " ' , msg . txt )
for m in matches :
if i == nb :
url = m [ 0 ]
self . link_open ( url )
return
def url_open ( self , url ) :
"""
Use webbrowser to open the provided link
"""
webbrowser . open ( url )
def command_nick ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ nick < nickname >
"""
2010-08-02 19:22:41 +00:00
args = arg . split ( )
2010-01-30 03:06:38 +00:00
if len ( args ) != 1 :
return
nick = args [ 0 ]
room = self . current_room ( )
if not room . joined or room . name == " Info " :
return
2010-08-31 23:11:02 +00:00
muc . change_nick ( self . xmpp , room . name , nick )
2010-01-30 03:06:38 +00:00
2010-01-28 00:55:02 +00:00
def information ( self , msg ) :
2010-05-18 13:29:02 +00:00
"""
Displays an informational message in the " Info " room window
"""
2010-01-28 00:55:02 +00:00
room = self . get_room_by_name ( " Info " )
2010-06-10 01:17:59 +00:00
self . add_message_to_room ( room , msg )
2010-06-21 08:38:48 +00:00
self . window . input . refresh ( )
2010-01-28 00:55:02 +00:00
2010-08-02 19:22:41 +00:00
def command_quit ( self , arg ) :
2010-05-18 13:29:02 +00:00
"""
/ quit
"""
2010-08-02 19:22:41 +00:00
if len ( arg . strip ( ) ) != 0 :
msg = arg
2010-06-13 15:40:03 +00:00
else :
msg = None
2010-08-31 23:11:02 +00:00
for room in self . rooms :
if not room . jid and room . name != ' Info ' :
muc . leave_groupchat ( self . xmpp , room . name , room . own_nick , msg )
self . xmpp . disconnect ( )
self . reset_curses ( )
2010-01-13 01:04:30 +00:00
sys . exit ( )