2010-01-10 20:14:17 +00:00
|
|
|
#!/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/>.
|
|
|
|
|
|
|
|
from handler import Handler
|
|
|
|
import curses
|
|
|
|
from curses import textpad
|
|
|
|
|
2010-01-13 01:04:30 +00:00
|
|
|
import locale
|
2010-01-21 01:54:50 +00:00
|
|
|
from datetime import datetime
|
|
|
|
|
2010-01-26 17:10:37 +00:00
|
|
|
from logging import logger
|
|
|
|
|
2010-01-26 19:33:40 +00:00
|
|
|
from random import randrange
|
|
|
|
|
2010-01-13 01:04:30 +00:00
|
|
|
locale.setlocale(locale.LC_ALL, '')
|
|
|
|
code = locale.getpreferredencoding()
|
|
|
|
|
2010-01-12 11:52:26 +00:00
|
|
|
import sys
|
|
|
|
|
2010-01-12 14:57:58 +00:00
|
|
|
from connection import *
|
2010-01-21 01:54:50 +00:00
|
|
|
from window import Window
|
2010-01-12 14:57:58 +00:00
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
class User(object):
|
2010-01-12 14:16:13 +00:00
|
|
|
"""
|
2010-01-21 01:54:50 +00:00
|
|
|
keep trace of an user in a Room
|
2010-01-12 14:16:13 +00:00
|
|
|
"""
|
2010-01-21 01:54:50 +00:00
|
|
|
def __init__(self, nick, affiliation, show, status, role):
|
|
|
|
self.update(affiliation, show, status, role)
|
|
|
|
self.change_nick(nick)
|
2010-01-26 19:33:40 +00:00
|
|
|
self.color = randrange(2, 10)
|
2010-01-13 01:04:30 +00:00
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
def update(self, affiliation, show, status, role):
|
|
|
|
self.affiliation = None
|
|
|
|
self.show = None
|
|
|
|
self.status = status
|
|
|
|
self.role = role
|
2010-01-13 01:04:30 +00:00
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
def change_nick(self, nick):
|
2010-01-21 04:41:54 +00:00
|
|
|
self.nick = nick.encode('utf-8')
|
2010-01-13 01:04:30 +00:00
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
class Room(object):
|
2010-01-11 13:28:57 +00:00
|
|
|
"""
|
|
|
|
"""
|
2010-01-21 01:54:50 +00:00
|
|
|
def __init__(self, name, nick):
|
2010-01-11 13:28:57 +00:00
|
|
|
self.name = name
|
2010-01-21 01:54:50 +00:00
|
|
|
self.own_nick = nick
|
|
|
|
self.joined = False # false until self presence is received
|
|
|
|
self.users = []
|
|
|
|
self.lines = [] # (time, nick, msg) or (time, info)
|
|
|
|
self.topic = ''
|
2010-01-12 14:16:13 +00:00
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
def add_message(self, nick, msg):
|
2010-01-26 19:33:40 +00:00
|
|
|
if not msg:
|
|
|
|
logger.info('msg is None..., %s' % (nick))
|
|
|
|
return
|
|
|
|
lines = msg.split('\n')
|
|
|
|
# first line has the nick and timestamp but others don't
|
|
|
|
self.lines.append((datetime.now(), nick.encode('utf-8'), lines.pop(0).encode('utf-8')))
|
|
|
|
if len(lines) > 0:
|
|
|
|
for line in lines:
|
|
|
|
self.lines.append((line.encode('utf-8')))
|
2010-01-12 14:16:13 +00:00
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
def add_info(self, info):
|
|
|
|
""" info, like join/quit/status messages"""
|
|
|
|
self.lines.append((datetime.now(), info.encode('utf-8')))
|
2010-01-11 13:28:57 +00:00
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
def on_presence(self, stanza, nick):
|
2010-01-11 13:28:57 +00:00
|
|
|
"""
|
|
|
|
"""
|
2010-01-21 01:54:50 +00:00
|
|
|
affiliation = stanza.getAffiliation()
|
|
|
|
show = stanza.getShow()
|
|
|
|
status = stanza.getStatus()
|
|
|
|
role = stanza.getRole()
|
|
|
|
if not self.joined:
|
|
|
|
self.users.append(User(nick, affiliation, show, status, role))
|
|
|
|
if nick == self.own_nick:
|
|
|
|
self.joined = True
|
|
|
|
self.add_info("%s is in the room" % (nick))
|
|
|
|
return
|
|
|
|
change_nick = stanza.getStatusCode() == '303'
|
|
|
|
for user in self.users:
|
|
|
|
if user.nick == nick:
|
|
|
|
if change_nick:
|
|
|
|
user.change_nick(stanza.getNick())
|
|
|
|
self.add_info('%s is now known as %s' % (nick, stanza.getNick()))
|
|
|
|
return
|
2010-01-26 19:33:40 +00:00
|
|
|
if status == 'offline' or role == 'none':
|
2010-01-21 01:54:50 +00:00
|
|
|
self.users.remove(user)
|
|
|
|
self.add_info('%s has left the room' % (nick))
|
|
|
|
return
|
|
|
|
user.update(affiliation, show, status, role)
|
|
|
|
self.add_info('%s, status : %s, %s, %s, %s' % (nick, affiliation, role, show, status))
|
|
|
|
return
|
|
|
|
self.users.append(User(nick, affiliation, show, status, role))
|
|
|
|
self.add_info('%s joined the room %s' % (nick, self.name))
|
2010-01-11 13:28:57 +00:00
|
|
|
|
2010-01-10 20:14:17 +00:00
|
|
|
class Gui(object):
|
|
|
|
"""
|
|
|
|
Graphical user interface using ncurses
|
|
|
|
"""
|
2010-01-21 01:54:50 +00:00
|
|
|
def __init__(self, stdscr=None, muc=None):
|
|
|
|
|
|
|
|
self.init_curses(stdscr)
|
|
|
|
self.stdscr = stdscr
|
|
|
|
self.stdscr.leaveok(True)
|
|
|
|
self.rooms = [Room('Info', '')] # current_room is self.rooms[0]
|
|
|
|
self.window = Window(stdscr)
|
|
|
|
self.window.refresh(self.rooms[0])
|
|
|
|
|
|
|
|
self.muc = muc
|
2010-01-10 20:14:17 +00:00
|
|
|
|
2010-01-13 01:04:30 +00:00
|
|
|
self.commands = {
|
|
|
|
'join': self.command_join,
|
|
|
|
'quit': self.command_quit,
|
2010-01-21 01:54:50 +00:00
|
|
|
'next': self.rotate_rooms_left,
|
|
|
|
'prev': self.rotate_rooms_right,
|
2010-01-13 01:04:30 +00:00
|
|
|
}
|
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
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)
|
|
|
|
|
2010-01-26 17:10:37 +00:00
|
|
|
def current_room(self):
|
|
|
|
return self.rooms[0]
|
|
|
|
|
|
|
|
def get_room_by_name(self, name):
|
|
|
|
for room in self.rooms:
|
|
|
|
if room.name == name:
|
|
|
|
return room
|
|
|
|
return None
|
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
def init_curses(self, stdscr):
|
|
|
|
curses.start_color()
|
|
|
|
curses.noecho()
|
|
|
|
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
|
|
|
|
curses.init_pair(2, curses.COLOR_BLUE, curses.COLOR_BLACK)
|
2010-01-21 04:41:54 +00:00
|
|
|
curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK) # Admin
|
|
|
|
curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_BLACK) # Participant
|
|
|
|
curses.init_pair(5, curses.COLOR_WHITE, curses.COLOR_BLACK) # Visitor
|
2010-01-26 19:33:40 +00:00
|
|
|
curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK)
|
|
|
|
curses.init_pair(7, curses.COLOR_GREEN, curses.COLOR_BLACK)
|
|
|
|
curses.init_pair(8, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
|
|
|
|
curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK)
|
2010-01-21 01:54:50 +00:00
|
|
|
|
2010-01-26 17:10:37 +00:00
|
|
|
def reset_curses(self):
|
|
|
|
curses.echo()
|
|
|
|
|
2010-01-21 01:54:50 +00:00
|
|
|
def on_connected(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def join_room(self, room, nick):
|
|
|
|
self.rooms.insert(0, Room(room, nick))
|
2010-01-26 17:10:37 +00:00
|
|
|
self.window.refresh(self.current_room())
|
2010-01-21 01:54:50 +00:00
|
|
|
|
|
|
|
def rotate_rooms_left(self, args):
|
|
|
|
self.rooms.append(self.rooms.pop(0))
|
2010-01-26 17:10:37 +00:00
|
|
|
self.window.refresh(self.current_room())
|
2010-01-21 01:54:50 +00:00
|
|
|
|
|
|
|
def rotate_rooms_right(self, args):
|
|
|
|
self.rooms.insert(0, self.rooms.pop())
|
2010-01-26 17:10:37 +00:00
|
|
|
self.window.refresh(self.current_room())
|
2010-01-21 01:54:50 +00:00
|
|
|
|
|
|
|
def room_message(self, stanza):
|
|
|
|
if stanza.getType() != 'groupchat':
|
|
|
|
return # ignore all messages not comming from a MUC
|
|
|
|
room_from = stanza.getFrom().getStripped()
|
|
|
|
nick_from = stanza.getFrom().getResource()
|
2010-01-26 19:33:40 +00:00
|
|
|
if not nick_from:
|
|
|
|
nick_from = ''
|
|
|
|
room = self.get_room_by_name(room_from)
|
2010-01-26 17:10:37 +00:00
|
|
|
if not room:
|
|
|
|
return logger.warning("message received for a non-existing room: %s" % (name))
|
2010-01-26 19:33:40 +00:00
|
|
|
body = stanza.getBody()
|
|
|
|
if not body:
|
|
|
|
body = stanza.getSubject()
|
|
|
|
room.add_info("%s changed the subject to: %s" % (nick_from, stanza.getSubject()))
|
|
|
|
else:
|
|
|
|
room.add_message(nick_from, body)
|
2010-01-26 17:10:37 +00:00
|
|
|
if room == self.current_room():
|
2010-01-26 19:33:40 +00:00
|
|
|
self.window.text_win.refresh(room.lines, room.users)
|
2010-01-26 17:10:37 +00:00
|
|
|
self.window.user_win.refresh(room.users)
|
|
|
|
self.window.input.refresh()
|
|
|
|
curses.doupdate()
|
2010-01-21 01:54:50 +00:00
|
|
|
|
|
|
|
def room_presence(self, stanza):
|
|
|
|
from_nick = stanza.getFrom().getResource()
|
|
|
|
from_room = stanza.getFrom().getStripped()
|
2010-01-26 19:33:40 +00:00
|
|
|
room = self.get_room_by_name(from_room)
|
2010-01-26 17:10:37 +00:00
|
|
|
if not room:
|
|
|
|
return logger.warning("presence received for a non-existing room: %s" % (name))
|
|
|
|
room.on_presence(stanza, from_nick)
|
2010-01-26 19:33:40 +00:00
|
|
|
if room == self.current_room():
|
|
|
|
self.window.text_win.refresh(room.lines, room.users)
|
2010-01-26 17:10:37 +00:00
|
|
|
self.window.user_win.refresh(room.users)
|
|
|
|
curses.doupdate()
|
2010-01-13 01:04:30 +00:00
|
|
|
|
|
|
|
def execute(self):
|
2010-01-21 01:54:50 +00:00
|
|
|
line = self.window.input.get_text()
|
|
|
|
self.window.input.clear_text()
|
|
|
|
if line == "":
|
|
|
|
return
|
2010-01-13 01:04:30 +00:00
|
|
|
if line.strip().startswith('/'):
|
|
|
|
command = line.strip()[:].split()[0][1:]
|
|
|
|
args = line.strip()[:].split()[1:]
|
|
|
|
if command in self.commands.keys():
|
|
|
|
func = self.commands[command]
|
|
|
|
func(args)
|
|
|
|
return
|
2010-01-26 17:10:37 +00:00
|
|
|
if self.current_room().name != 'Info':
|
|
|
|
self.muc.send_message(self.current_room().name, line)
|
|
|
|
self.window.input.refresh()
|
2010-01-13 01:04:30 +00:00
|
|
|
|
|
|
|
def command_join(self, args):
|
|
|
|
room = args[0]
|
2010-01-21 01:54:50 +00:00
|
|
|
self.muc.join_room(room, "poezio")
|
|
|
|
self.join_room(room, 'poezio')
|
2010-01-13 01:04:30 +00:00
|
|
|
|
|
|
|
def command_quit(self, args):
|
2010-01-26 17:10:37 +00:00
|
|
|
self.reset_curses()
|
2010-01-13 01:04:30 +00:00
|
|
|
sys.exit()
|
2010-01-10 20:14:17 +00:00
|
|
|
|
2010-01-11 13:28:57 +00:00
|
|
|
def main_loop(self, stdscr):
|
|
|
|
while 1:
|
2010-01-21 13:10:33 +00:00
|
|
|
curses.doupdate()
|
2010-01-11 13:28:57 +00:00
|
|
|
key = stdscr.getch()
|
|
|
|
if key == curses.KEY_RESIZE:
|
2010-01-21 01:54:50 +00:00
|
|
|
self.window.resize(stdscr)
|
2010-01-12 14:16:13 +00:00
|
|
|
elif key == 10:
|
2010-01-13 01:04:30 +00:00
|
|
|
self.execute()
|
|
|
|
else:
|
2010-01-21 01:54:50 +00:00
|
|
|
self.window.do_command(key)
|