summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client.py26
-rw-r--r--src/common.py13
-rw-r--r--src/connection.py19
-rw-r--r--src/gui.py259
-rw-r--r--src/handler.py4
-rw-r--r--src/logging.py21
-rw-r--r--src/window.py6
7 files changed, 156 insertions, 192 deletions
diff --git a/src/client.py b/src/client.py
index 9840d259..9616be1c 100644
--- a/src/client.py
+++ b/src/client.py
@@ -18,10 +18,10 @@
# along with Poezio. If not, see <http://www.gnu.org/licenses/>.
import sys
+
# disable any printout (this would mess the display)
-stderr = sys.stderr
-sys.stdout = open('/dev/null', 'w')
-sys.stderr = open('/dev/null', 'w')
+# sys.stdout = open('/dev/null', 'w')
+# sys.stderr = open('/dev/null', 'w')
from connection import Connection
from multiuserchat import MultiUserChat
@@ -30,22 +30,12 @@ from handler import Handler
from gui import Gui
from curses import initscr
import curses
+import threading
+from common import exception_handler
import signal
signal.signal(signal.SIGINT, signal.SIG_IGN)
-import traceback
-
-def exception_handler(type_, value, trace):
- """
- on any traceback: exit ncurses and print the traceback
- then exit the program
- """
- curses.echo()
- curses.endwin()
- traceback.print_exception(type_, value, trace, None, stderr)
- sys.exit()
-
sys.excepthook = exception_handler
class Client(object):
@@ -59,10 +49,12 @@ class Client(object):
self.resource = config.get('resource', 'poezio')
self.server = config.get('server', 'louiz.org')
self.connection = Connection(self.server, self.resource)
- self.stdscr = initscr()
-
+ # self.connection.demon = True
self.connection.start()
+ # self.connection.run()
+ self.stdscr = initscr()
self.gui = Gui(self.stdscr, MultiUserChat(self.connection.client))
+ # thread.start_new_thread(self.launch, ())
def launch(self):
"""
diff --git a/src/common.py b/src/common.py
index e4026efb..421aada2 100644
--- a/src/common.py
+++ b/src/common.py
@@ -37,6 +37,19 @@ import os
import mimetypes
import hashlib
import subprocess
+import curses
+import traceback
+import sys
+
+def exception_handler(type_, value, trace):
+ """
+ on any traceback: exit ncurses and print the traceback
+ then exit the program
+ """
+ curses.echo()
+ curses.endwin()
+ traceback.print_exception(type_, value, trace, None, sys.stderr)
+ sys.exit(2)
def get_base64_from_file(path):
if not os.path.isfile(path):
diff --git a/src/connection.py b/src/connection.py
index 1876cdb6..5aa9f838 100644
--- a/src/connection.py
+++ b/src/connection.py
@@ -23,7 +23,9 @@ import xmpp
from config import config
from logging import logger
from handler import Handler
+from common import exception_handler
import threading
+import thread
class Connection(threading.Thread):
"""
@@ -33,7 +35,7 @@ class Connection(threading.Thread):
def __init__(self, server, resource):
threading.Thread.__init__(self)
self.handler = Handler()
-
+ self.daemon = True # exit the program when this exits
self.server = server
self.resource = resource
self.online = 0 # 1:connected, 2:auth confirmed
@@ -46,6 +48,7 @@ class Connection(threading.Thread):
run in a thread
connect to server
"""
+ sys.excepthook = exception_handler
if not self.connect_to_server(self.server, self.port):
logger.error('Could not connect to server')
sys.exit(-1)
@@ -59,7 +62,6 @@ class Connection(threading.Thread):
self.process()
def connect_to_server(self, server, port):
- # TODO proxy stuff
if config.get('use_proxy','false') == 'true':
return self.client.connect((server, port),
{'host': config.get("proxy_server", ""),
@@ -81,10 +83,11 @@ class Connection(threading.Thread):
"""
register handlers from xmpppy signals
"""
- self.client.RegisterHandler('message', self.handler_message)
- self.client.RegisterHandler('presence', self.handler_presence)
self.client.RegisterHandler('iq', self.on_get_time, typ='get', ns="urn:xmpp:time")
self.client.RegisterHandler('iq', self.on_get_version, typ='get', ns=xmpp.NS_VERSION)
+ self.client.RegisterHandler('presence', self.handler_presence)
+ self.client.RegisterHandler('message', self.handler_delayed_message, ns=xmpp.NS_DELAY, makefirst=True)
+ self.client.RegisterHandler('message', self.handler_message)
def handler_presence(self, connection, presence):
fro = presence.getFrom()
@@ -96,6 +99,9 @@ class Connection(threading.Thread):
return
self.handler.emit('room-presence', stanza=presence)
+ def handler_delayed_message(self, connection, message):
+ pass
+
def handler_message(self, connection, message):
self.handler.emit('room-message', stanza=message)
@@ -104,10 +110,7 @@ class Connection(threading.Thread):
def process(self, timeout=10):
if self.online:
- try:
- self.client.Process(timeout)
- except:
- pass # FIXME
+ self.client.Process(timeout)
else:
log.warning('disconnecting...')
sys.exit()
diff --git a/src/gui.py b/src/gui.py
index a55e6cc7..b4a5546a 100644
--- a/src/gui.py
+++ b/src/gui.py
@@ -36,140 +36,8 @@ from logging import logger
from random import randrange
from config import config
from window import Window
-
-class User(object):
- """
- keep trace of an user in a Room
- """
- def __init__(self, nick, affiliation, show, status, role):
- self.update(affiliation, show, status, role)
- self.change_nick(nick)
- self.color = randrange(2, 10)
-
- def update(self, affiliation, show, status, role):
- self.affiliation = affiliation
- self.show = show
- self.status = status
- self.role = role
-
- def change_nick(self, nick):
- self.nick = nick.encode('utf-8')
-
-class Room(object):
- """
- """
- def __init__(self, name, nick, number):
- self.name = name
- self.own_nick = nick
- self.color_state = 11 # color used in RoomInfo
- self.nb = number # number used in RoomInfo
- self.joined = False # false until self presence is received
- self.users = []
- self.lines = [] # (time, nick, msg) or (time, info)
- self.topic = ''
-
- def disconnect(self):
- self.joined = False
- self.users = []
-
- def add_message(self, nick, msg):
- color = None
- self.set_color_state(12)
- if nick != self.own_nick:
- if self.own_nick in msg:
- self.set_color_state(13)
- color = 3
- else:
- highlight_words = config.get('highlight_on', '').split(':')
- for word in highlight_words:
- if word.lower() in msg.lower() and word != '':
- self.set_color_state(13)
- color = 3
- if not msg:
- logger.info('msg is None..., %s' % (nick))
- return
- self.lines.append((datetime.now(), nick.encode('utf-8'),
- msg.encode('utf-8'), color))
- return color
-
- def add_info(self, info):
- """ info, like join/quit/status messages"""
- try:
- self.lines.append((datetime.now(), info.encode('utf-8')))
- return info.encode('utf-8')
- except:
- self.lines.append((datetime.now(), info))
- return info
-
- def get_user_by_name(self, nick):
- for user in self.users:
- if user.nick == nick.encode('utf-8'):
- return user
- return None
-
- def set_color_state(self, color):
- if self.color_state < color or color == 11:
- self.color_state = color
-
- def on_presence(self, stanza, nick):
- """
- """
- affiliation = stanza.getAffiliation()
- show = stanza.getShow()
- status = stanza.getStatus()
- role = stanza.getRole()
- if not self.joined: # user in the room BEFORE us.
- self.users.append(User(nick, affiliation, show, status, role))
- if nick.encode('utf-8') == self.own_nick:
- self.joined = True
- return self.add_info(_("Your nickname is %s") % (nick))
- return self.add_info(_("%s is in the room") % (nick.encode-('utf-8')))
- change_nick = stanza.getStatusCode() == '303'
- kick = stanza.getStatusCode() == '307'
- user = self.get_user_by_name(nick)
- # New user
- if not user:
- self.users.append(User(nick, affiliation, show, status, role))
- if not config.get('hide_enter_join', "false") == "true":
- return self.add_info(_('%(nick)s joined the room %(roomname)s') % {'nick':nick, 'roomname': self.name})
- return None
- # nick change
- if change_nick:
- if user.nick == self.own_nick:
- self.own_nick = stanza.getNick().encode('utf-8')
- user.change_nick(stanza.getNick())
- return self.add_info(_('%(old_nick)s is now known as %(new_nick)s') % {'old_nick':nick, 'new_nick':stanza.getNick()})
- # kick
- if kick:
- self.users.remove(user)
- reason = stanza.getReason().encode('utf-8') or ''
- try:
- by = stanza.getActor().encode('utf-8')
- except:
- by = None
- if nick == self.own_nick:
- self.disconnect()
- if by:
- return self.add_info(_('You have been kicked by %(by)s. Reason: %(reason)s') % {'by':by, 'reason':reason})
- else:
- return self.add_info(_('You have been kicked. Reason: %s') % (reason))
- else:
- if by:
- return self.add_info(_('%(nick)s has been kicked by %(by)s. Reason: %(reason)s') % {'nick':nick, 'by':by, 'reason':reason})
- else:
- return self.add_info(_('%(nick)s has been kicked. Reason: %(reason)s') % {'nick':nick, 'reason':reason})
- # user quit
- if status == 'offline' or role == 'none':
- self.users.remove(user)
- if not config.get('hide_enter_join', "false") == "true":
- return self.add_info(_('%s has left the room') % (nick))
- return None
- # status change
- user.update(affiliation, show, status, role)
- if not config.get('hide_status_change', "false") == "true":
- return self.add_info(_('%(nick)s changed his/her status : %(a)s, %(b)s, %(c)s, %(d)s') % {'nick':nick, 'a':affiliation, 'b':role, 'c':show, 'd':status})
- return None
-
+from user import User
+from room import Room
class Gui(object):
"""
@@ -184,7 +52,6 @@ class Gui(object):
self.window.new_room(self.current_room())
self.window.refresh(self.rooms)
-
self.muc = muc
self.commands = {
@@ -231,6 +98,7 @@ class Gui(object):
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('room-delayed-message', self.room_delayed_message)
def main_loop(self, stdscr):
while 1:
@@ -285,8 +153,8 @@ class Gui(object):
def init_curses(self, stdscr):
curses.start_color()
curses.noecho()
- curses.cbreak()
- curses.raw()
+ # curses.cbreak()
+ # curses.raw()
curses.use_default_colors()
stdscr.keypad(True)
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
@@ -342,16 +210,19 @@ class Gui(object):
self.rooms.insert(0, self.rooms.pop())
self.window.refresh(self.rooms)
- def room_message(self, stanza):
+ def room_delayed_message(self, stanza):
+ self.room_message(stanza)
+
+ def room_message(self, stanza, date=None):
if len(sys.argv) > 1:
self.information(str(stanza).encode('utf-8'))
if stanza.getType() != 'groupchat':
return # ignore all messages not comming from a MUC
- room_from = stanza.getFrom().getStripped()
+ if not date:
+ date = datetime.now()
nick_from = stanza.getFrom().getResource()
- if not nick_from:
- nick_from = ''
- room = self.get_room_by_name(room_from)
+ room_from = stanza.getFrom().getStripped()
+ room = self.get_room_by_name(room_from)
if not room:
self.information(_("message received for a non-existing room: %s") % (room_from))
return
@@ -359,26 +230,17 @@ class Gui(object):
subject = stanza.getSubject()
if subject:
if nick_from:
- info = room.add_info(_("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject})
+ self.add_info(room, _("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject}, date)
else:
- info = room.add_info(_("The subject is: %(subject)s") % {'subject':subject})
- self.window.text_win.add_line(room, (datetime.now(), info))
+ self.add_info(room, _("The subject is: %(subject)s") % {'subject':subject}, date)
room.topic = subject.encode('utf-8').replace('\n', '|')
if room == self.current_room():
self.window.topic_win.refresh(room.topic)
- self.window.text_win.refresh(room.name)
else:
- if body.startswith('/me'):
- info = room.add_info(nick_from + ' ' + body[4:])
- self.window.text_win.add_line(room, (datetime.now(), info))
+ if body.startswith('/me '):
+ self.add_info(room, nick_from + ' ' + body[4:], date)
else:
- color = room.add_message(nick_from, body)
- self.window.text_win.add_line(room, (datetime.now(), nick_from.encode('utf-8'), body.encode('utf-8'), color))
- if room.name == self.current_room().name:
- self.window.text_win.refresh(room.name)
- self.window.input.refresh()
- else:
- self.window.info_win.refresh(self.rooms, self.current_room())
+ self.add_message(room, nick_from, body, date)
curses.doupdate()
def room_presence(self, stanza):
@@ -392,14 +254,85 @@ class Gui(object):
if stanza.getType() == 'error':
msg = _("Error: %s") % stanza.getError()
else:
- msg = room.on_presence(stanza, from_nick)
+ msg = None
+ affiliation = stanza.getAffiliation()
+ show = stanza.getShow()
+ status = stanza.getStatus()
+ role = stanza.getRole()
+ if not room.joined: # user in the room BEFORE us.
+ room.users.append(User(from_nick, affiliation, show, status, role))
+ if from_nick.encode('utf-8') == room.own_nick:
+ room.joined = True
+ self.add_info(room, _("Your nickname is %s") % (from_nick))
+ else:
+ self.add_info(room, _("%s is in the room") % (from_nick.encode('utf-8')))
+ else:
+ change_nick = stanza.getStatusCode() == '303'
+ kick = stanza.getStatusCode() == '307'
+ user = room.get_user_by_name(from_nick)
+ # New user
+ if not user:
+ room.users.append(User(from_nick, affiliation, show, status, role))
+ if not config.get('hide_enter_join', "false") == "true":
+ self.add_info(room, _('%(nick)s joined the room %(roomname)s') % {'nick':from_nick, 'roomname': room.name})
+ # nick change
+ elif change_nick:
+ if user.nick == room.own_nick:
+ room.own_nick = stanza.getNick().encode('utf-8')
+ user.change_nick(stanza.getNick())
+ self.add_info(room, _('%(old_nick)s is now known as %(new_nick)s') % {'old_nick':from_nick, 'new_nick':stanza.getNick()})
+ # kick
+ elif kick:
+ room.users.remove(user)
+ reason = stanza.getReason().encode('utf-8') or ''
+ try:
+ by = stanza.getActor().encode('utf-8')
+ except:
+ by = None
+ if from_nick == room.own_nick: # we are kicked
+ room.disconnect()
+ if by:
+ self.add_info(room, _('You have been kicked by %(by)s. Reason: %(reason)s') % {'by':by, 'reason':reason})
+ else:
+ self.add_info(room, _('You have been kicked. Reason: %s') % (reason))
+ else:
+ if by:
+ self.add_info(room, _('%(nick)s has been kicked by %(by)s. Reason: %(reason)s') % {'nick':from_nick, 'by':by, 'reason':reason})
+ else:
+ self.add_info(room, _('%(nick)s has been kicked. Reason: %(reason)s') % {'nick':from_nick, 'reason':reason})
+ # user quit
+ elif status == 'offline' or role == 'none':
+ room.users.remove(user)
+ if not config.get('hide_enter_join', "false") == "true":
+ self.add_info(room, _('%s has left the room') % (from_nick))
+ # status change
+ else:
+ user.update(affiliation, show, status, role)
+ if not config.get('hide_status_change', "false") == "true":
+ self.add_info(room, _('%(nick)s changed his/her status : %(a)s, %(b)s, %(c)s, %(d)s') % {'nick':from_nick, 'a':affiliation, 'b':role, 'c':show, 'd':status})
if room == self.current_room():
self.window.user_win.refresh(room.users)
- if room == self.current_room() and msg:
- self.window.text_win.add_line(room, (datetime.now(), msg))
+
+ def add_info(self, room, info, date=None):
+ """
+ add a new information in the specified room
+ (displays it immediately AND saves it for redisplay
+ in futur refresh)
+ """
+ msg = room.add_info(info, date)
+ self.window.text_win.add_line(room, (datetime.now(), msg))
+ if room.name == self.current_room().name:
self.window.text_win.refresh(room.name)
self.window.input.refresh()
- curses.doupdate()
+ curses.doupdate()
+ else:
+ self.window.info_win.refresh(self.rooms, self.current_room())
+
+ def add_message(self, room, nick_from, body, date):
+ color = room.add_message(nick_from, body, date)
+ self.window.text_win.add_line(room, (date, nick_from.encode('utf-8'), body.encode('utf-8'), color))
+ if room == self.current_room():
+ self.window.text_win.refresh(room.name)
def execute(self):
line = self.window.input.get_text()
@@ -415,13 +348,11 @@ class Gui(object):
func(args)
return
else:
- info = self.current_room().add_info(_("Error: unknown command (%s)") % (command))
- self.window.text_win.add_line(self.current_room(), (datetime.now(), info))
- self.window.text_win.refresh(self.current_room().name)
+ self.add_info(self.current_room(), _("Error: unknown command (%s)") % (command))
elif self.current_room().name != 'Info':
self.muc.send_message(self.current_room().name, line)
+ self.window.input.refresh()
curses.doupdate()
- self.window.input.refresh()
def command_help(self, args):
room = self.current_room()
diff --git a/src/handler.py b/src/handler.py
index 4fa6cca8..1911d7fa 100644
--- a/src/handler.py
+++ b/src/handler.py
@@ -46,6 +46,10 @@ class Handler(Singleton):
# A message is received
# Args: the stanza object
+ 'room-delayed-message': list(),
+ # A message is received
+ # Args: the stanza object
+
'send-version': list(),
# We send our version
# Args: the stanza we reply to
diff --git a/src/logging.py b/src/logging.py
index bb22e5c9..aa466348 100644
--- a/src/logging.py
+++ b/src/logging.py
@@ -18,8 +18,15 @@
# along with Poezio. If not, see <http://www.gnu.org/licenses/>.
import sys
+from os import environ, makedirs
from datetime import datetime
from config import config
+
+CONFIG_HOME = environ.get("XDG_CONFIG_HOME")
+if not CONFIG_HOME:
+ CONFIG_HOME = environ.get('HOME')+'/.config'
+CONFIG_PATH = CONFIG_HOME + '/poezio/'
+
class Logger(object):
"""
Appends things to files. Error/information/warning logs
@@ -50,4 +57,18 @@ class Logger(object):
fd.close()
sys.exit(-1)
+ def message(self, room, nick, msg):
+ """
+ log the message in the appropriate room
+ """
+ if config.get('use_log', 'false') == 'false':
+ return
+ dir = CONFIG_PATH+'logs/'
+ try:
+ makedirs(dir)
+ except:pass
+ fd = open(dir+room, 'a')
+ fd.write(datetime.now().strftime('%d-%m-%y [%H:%M:%S] ')+nick+': '+msg+'\n')
+ fd.close()
+
logger = Logger()
diff --git a/src/window.py b/src/window.py
index c6588da4..81902f4e 100644
--- a/src/window.py
+++ b/src/window.py
@@ -94,7 +94,7 @@ class Topic(Win):
return
self.win.clear()
try:
- self.win.addnstr(0, 0, room_name + " "*(self.width-len(room_name)-1), self.width-1
+ self.win.addnstr(0, 0, room_name + " "*(self.width-len(room_name)), self.width
, curses.color_pair(1))
except:pass
self.win.refresh()
@@ -113,7 +113,7 @@ class RoomInfo(Win):
def compare_room(a, b):
return a.nb - b.nb
self.win.clear()
- self.win.addnstr(0, 0, current.name+" [", self.width-1
+ self.win.addnstr(0, 0, current.name+" [", self.width
,curses.color_pair(1))
sorted_rooms = sorted(rooms, compare_room)
for room in sorted_rooms:
@@ -128,7 +128,7 @@ class RoomInfo(Win):
break
(y, x) = self.win.getyx()
try:
- self.win.addstr(y, x-1, ']'+(' '*((self.width-1)-x)), curses.color_pair(1))
+ self.win.addstr(y, x-1, ']'+(' '*((self.width)-x)), curses.color_pair(1))
except:
pass
self.win.refresh()