summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common.py42
-rw-r--r--src/connection.py208
-rw-r--r--src/gui.py522
-rw-r--r--src/handler.py2
-rw-r--r--src/logger.py (renamed from src/logging.py)0
-rw-r--r--src/multiuserchat.py392
-rw-r--r--src/poezio.py41
-rw-r--r--src/room.py2
8 files changed, 412 insertions, 797 deletions
diff --git a/src/common.py b/src/common.py
index 93eca601..75a0b940 100644
--- a/src/common.py
+++ b/src/common.py
@@ -47,8 +47,6 @@ import errno
import time
import traceback
-import xmpp
-
ROOM_STATE_NONE = 11
ROOM_STATE_CURRENT = 10
ROOM_STATE_PRIVATE = 15
@@ -120,20 +118,11 @@ def is_in_path(command, return_abs_path=False):
pass
return False
-def get_stripped_jid(jid):
- """
- Return the stripped JID (bare representation)
- nick@server/resource -> nick@server
- """
- if isinstance(jid, basestring):
- jid = xmpp.JID(jid)
- return jid.getStripped()
-
def is_jid(jid):
"""
Return True if this is a valid JID
"""
- if xmpp.JID(jid).getNode() != '':
+ if jid.find('@') != -1:
return True
return False
@@ -141,35 +130,34 @@ def jid_get_node(jid):
"""
nick@server/resource -> nick
"""
- if isinstance(jid, basestring):
- jid = xmpp.JID(jid)
- return jid.getNode()
+ return jid.split('@', 1)[0]
def jid_get_domain(jid):
"""
nick@server/resource -> server
"""
- if isinstance(jid, basestring):
- jid = xmpp.JID(jid)
- return jid.getDomain()
+ return jid.split('@',1)[-1].split('/', 1)[0]
-def jid_get_resource(jid):
+def jid_get_resource(fulljid):
"""
nick@server/resource -> resource
"""
- if isinstance(jid, basestring):
- jid = xmpp.JID(jid)
- return jid.getResource()
+ if '/' in fulljid:
+ return fulljid.split('/', 1)[-1]
+ else:
+ return ''
+
+def jid_get_bare(fulljid):
+ """
+ nick@server/resource -> nick@server
+ """
+ return '%s@%s' % (jid_get_domain(fulljid), jid_get_node(fulljid))
def is_jid_the_same(a, b):
"""
Compare two bare jids
"""
- if isinstance(a, basestring):
- a = xmpp.JID(a)
- if isinstance(b, basestring):
- b = xmpp.JID(b)
- return a.bareMatch(b)
+ return jid_get_bare(a) == jid_get_bare(a)
DISTRO_INFO = {
'Arch Linux': '/etc/arch-release',
diff --git a/src/connection.py b/src/connection.py
index 83631da0..9b315539 100644
--- a/src/connection.py
+++ b/src/connection.py
@@ -24,205 +24,27 @@ from gettext import (bindtextdomain, textdomain, bind_textdomain_codeset,
gettext as _)
import sys
-import threading
+import sleekxmpp
-import xmpp
from config import config
-from logging import logger
+from logger import logger
from handler import Handler
from common import jid_get_node, jid_get_domain, is_jid_the_same
-class Connection(threading.Thread):
+import logging
+
+class Connection(sleekxmpp.ClientXMPP):
"""
Receives everything from Jabber and emits the
appropriate signals
"""
- def __init__(self, server, resource):
- threading.Thread.__init__(self)
- self.handler = Handler()
- self.daemon = True # exit the program when this thread exits
- if config.get('jid', '') == '':
- self.server = server
- else:
- self.server = jid_get_domain(config.get('jid', ''))
- self.resource = resource
- self.online = 0 # 1:connected, 2:auth confirmed
- self.jid = '' # we don't know our jid yet (anon account)
- self.port = config.get('port', 5222)
- self.client = xmpp.Client(self.server, debug=[])
-
- def run(self):
- """
- run in a thread
- connect to server
- """
- if not self.connect_to_server(self.server, self.port):
- self.handler.emit('error', msg='Could not connect to server')
- sys.exit(-1)
- if not self.authenticate(config.get('jid', '') == ''):
- self.handler.emit('error', msg='Could not authenticate to server')
- sys.exit(-1)
- # TODO, become invisible before sendInitPresence
- self.client.sendInitPresence(requestRoster=0)
- self.register_handlers()
-
- self.online = 1 # 2 when confirmation of our auth is received
- while 1:
- self.process()
-
- def connect_to_server(self, server, port):
- """
- Connect to the server
- """
- if config.get('use_proxy','false') == 'true':
- return self.client.connect((server, port),
- {'host': config.get("proxy_server", ""),
- 'port': config.get("proxy_port", 1080),
- 'user': config.get("proxy_user", ""),
- 'password': config.get("proxy_password",
- "")
- })
- else:
- return self.client.connect((server, port))
-
- def authenticate(self, anon=True):
- """
- Authenticate to the server
- """
- if anon:
- try:
- self.client.auth(None, "", self.resource)
- return True
- except TypeError:
- self.handler.emit('error', msg=_('Error: Could not authenticate. Please make sure the server you chose (%s) supports anonymous authentication' % (config.get('server', ''))))
- return False
- else:
- password = config.get('password', '')
- jid = config.get('jid', '')
- auth = self.client.auth(jid_get_node(jid), password, "salut")
- return True
-
- def register_handlers(self):
- """
- registers handlers from xmpppy signals
- """
- self.client.RegisterHandler('iq', self.on_get_time, typ='get',
- ns="urn:xmpp:time")
- self.client.RegisterHandler('iq', self.on_get_vcard)
- 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_message)
-
- def error_message(self, stanza):
- """
- handles the error messages
- """
- from_ = stanza.getFrom()
- if not from_:
- room_name = ''
- else:
- room_name = from_.getStripped()
- self.handler.emit('error-message', room=room_name,
- error=stanza.getTag('error'),
- msg=stanza.getError())
- raise xmpp.protocol.NodeProcessed
-
- def handler_presence(self, connection, presence):
- """
- check if it's a normal or a muc presence
- """
- is_muc = False
- tags = presence.getTags('x')
- for tag in tags:
- if tag.getAttr('xmlns') == 'http://jabber.org/protocol/muc#user':
- is_muc = True
- if is_muc:
- self.handler_muc_presence(connection, presence)
- else:
- self.handler_normal_presence(connection, presence)
-
- def handler_normal_presence(self, connection, presence):
- """
- handles the non-MUC presences
- """
- fro = presence.getFrom()
- toj = presence.getAttr('to')
- if presence.getType() == 'error':
- self.error_message(presence)
- return
- if not toj or fro == toj: # own presence
- self.online = 2
- self.jid = toj
- self.handler.emit('on-connected', jid=fro)
-
- def handler_muc_presence(self, connection, presence):
- """
- handles the presence messages
- """
- if not connection:
- return
- self.handler.emit('room-presence', stanza=presence)
- raise xmpp.protocol.NodeProcessed
-
- def handler_delayed_message(self, connection, message):
- """
- handles the delayed messages
- These are received when we join a muc and we are sent the
- recent history
- """
- if not connection:
- return
- self.handler.emit('room-delayed-message', stanza=message)
- raise xmpp.protocol.NodeProcessed
-
- def handler_message(self, connection, message):
- """
- handles the common messages
- """
- if not connection:
- return
- if message.getType() == 'error':
- self.error_message(message)
- return
- if message.getType() == 'groupchat':
- self.handler.emit('room-message', stanza=message)
- else:
- self.handler.emit('private-message', stanza=message)
-
- raise xmpp.protocol.NodeProcessed
-
- def process(self, timeout=10):
- """
- Main connection loop
- It just waits for something to process (something is received
- or something has to be sent)
- """
- if self.online:
- self.client.Process(timeout)
- else:
- logger.warning('disconnecting...')
- sys.exit()
-
- def on_get_version(self, connection, iq):
- """
- Handles the iq requesting our software version
- """
- if not connection:
- return
- self.handler.emit('send-version', iq_obj=iq)
-
- def on_get_time(self, connection, iq):
- """
- handles the iq requesting our time
- """
- if not connection:
- return
- self.handler.emit('send-time', iq_obj=iq)
-
- def on_get_vcard(self, connection, iq):
- """
- we received a vcard
- """
- from common import debug
- debug('\n====\n%s\n\n' % iq)
+ def __init__(self):
+ sleekxmpp.ClientXMPP.__init__(self, None, None, ssl=True,
+ resource=config.get('resource', 'poezio'))
+ self.registerPlugin('xep_0045')
+
+ def start(self):
+ # TODO, try multiple servers
+ if self.connect((config.get('server', 'anon.louiz.org'),
+ config.get('port', 5222))):
+ self.process(threaded=True)
diff --git a/src/gui.py b/src/gui.py
index 8f515ebc..ee4f9f1c 100644
--- a/src/gui.py
+++ b/src/gui.py
@@ -33,6 +33,7 @@ from datetime import datetime
import common
import theme
+import multiuserchat as muc
from handler import Handler
from config import config
from window import Window
@@ -40,7 +41,7 @@ from user import User
from room import Room
from message import Message
from keyboard import read_char
-from common import is_jid_the_same, jid_get_domain, is_jid
+from common import is_jid_the_same, jid_get_domain, jid_get_resource, is_jid
# http://xmpp.org/extensions/xep-0045.html#errorstatus
ERROR_AND_STATUS_CODES = {
@@ -61,15 +62,14 @@ class Gui(object):
"""
User interface using ncurses
"""
- def __init__(self, stdscr=None, muc=None):
- self.init_curses(stdscr)
- self.stdscr = stdscr
- self.window = Window(stdscr)
+ def __init__(self, xmpp):
+ self.stdscr = curses.initscr()
+ self.init_curses(self.stdscr)
+ self.xmpp = xmpp
+ self.window = Window(self.stdscr)
self.rooms = [Room('Info', '', self.window)]
self.ignores = {}
- self.muc = muc
-
self.commands = {
'help': (self.command_help, u'\_o< KOIN KOIN KOIN'),
'join': (self.command_join, _("Usage: /join [room_name][@server][/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 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.\nExamples:\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")),
@@ -136,14 +136,230 @@ class Gui(object):
'M-b': self.window.input.jump_word_left
}
- 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)
+ # 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
+ else:
+ msg = None
+ affiliation = presence['muc']['affiliation']
+ show = presence['muc']['type']
+ 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')
+ else:
+ 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:
+ 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)
+ # nick change
+ elif change_nick:
+ 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
+
+ # kick
+ elif kick:
+ 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)
+
+ # user quit
+ elif typ == 'unavailable':
+ 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)
+ # status change
+ else:
+ # 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 ","
+ 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(from_room)
+ 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)
+ if room == self.current_room():
+ self.window.user_win.refresh(room.users)
+ self.window.input.refresh()
+ doupdate()
+
+ 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']
+ nick_from = jid.user
+ room_from = jid.server
+ 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
def resize_window(self):
"""
@@ -152,14 +368,14 @@ class Gui(object):
self.window.resize(self.stdscr)
self.window.refresh(self.rooms)
- def main_loop(self, stdscr):
+ def main_loop(self):
"""
main loop waiting for the user to press a key
"""
self.refresh_window()
while True:
doupdate()
- char=read_char(stdscr)
+ char=read_char(self.stdscr)
try: # if this is not a valide utf-8 char, discard it
char.decode('utf-8')
except UnicodeDecodeError:
@@ -205,17 +421,11 @@ class Gui(object):
Reset terminal capabilities to what they were before ncurses
init
"""
+ # TODO remove me?
curses.echo()
curses.nocbreak()
curses.endwin()
- def on_connected(self, jid):
- """
- We are connected when authentification confirmation is received
- """
- self.information(_("Welcome on Poezio \o/!"))
- self.information(_("Your JID is %s") % jid)
-
def refresh_window(self):
"""
Refresh everything
@@ -223,9 +433,9 @@ class Gui(object):
self.current_room().set_color_state(theme.COLOR_TAB_CURRENT)
self.window.refresh(self.rooms)
- def join_room(self, room, nick):
+ def open_new_room(self, room, nick, focus=True):
"""
- join the specified room (muc), using the specified nick
+ Open a new Tab containing a Muc room, using the specified nick
"""
r = Room(room, nick, self.window)
self.current_room().set_color_state(theme.COLOR_TAB_NORMAL)
@@ -236,7 +446,8 @@ class Gui(object):
if ro.nb == 0:
self.rooms.insert(self.rooms.index(ro), r)
break
- self.command_win("%s" % r.nb)
+ if focus:
+ self.command_win("%s" % r.nb)
self.refresh_window()
def completion(self):
@@ -322,27 +533,28 @@ class Gui(object):
self.current_room().scroll_up(self.window.text_win.height-1)
self.refresh_window()
- def room_error(self, room, error, msg):
+ def room_error(self, error, room_name):
"""
Display the error on the room window
"""
- if not error:
- return
- room = self.get_room_by_name(room)
+ room = self.get_room_by_name(room_name)
if not room:
room = self.get_room_by_name('Info')
- code = error.getAttr('code')
- typ = error.getAttr('type')
- if error.getTag('text'):
- body = error.getTag('text').getData()
- else: # No description of the error is provided in the stanza
- # If it's a standard error, use our own messages
+ msg = error['error']['type']
+ condition = error['error']['condition']
+ code = error['error']['code']
+ body = error['error']['text']
+ if not body:
if code in ERROR_AND_STATUS_CODES.keys():
body = ERROR_AND_STATUS_CODES[code]
else:
- body = _('Unknown error')
- self.add_message_to_room(room, _('Error: %(code)s-%(msg)s: %(body)s' %
- {'msg':msg, 'code':code, 'body':body}))
+ 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}))
if code == '401':
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':
@@ -352,23 +564,6 @@ class Gui(object):
self.add_message_to_room(room, _('You can join the room with an other nick, by typing "/join /other_nick"'))
self.refresh_window()
- 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.encode('utf-8'), False)
- if not room:
- return
- 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.decode('utf-8')+'/'+user_nick
for room in self.rooms: # if the room exists, focus it and return
@@ -396,40 +591,41 @@ class Gui(object):
self.refresh_window()
return r
- def room_message(self, stanza, date=None):
+ def on_groupchat_message(self, message):
"""
- Display the message on the room window
+ Triggered whenever a message is received from a multi-user chat room.
"""
- delay_tag = stanza.getTag('delay', namespace='urn:xmpp:delay')
- if delay_tag:
+ # FIXME: not receiving subjects? :/
+ delay_tag = message.find('{urn:xmpp:delay}delay')
+ if delay_tag is not None:
delayed = True
- date = common.datetime_tuple(delay_tag.getAttr('stamp'))
+ date = common.datetime_tuple(delay_tag.attrib['stamp'])
else:
# We support the OLD and deprecated XEP: http://xmpp.org/extensions/xep-0091.html
# But it sucks, please, Jabber servers, don't do this :(
- delay_tag = stanza.getTag('x', namespace='jabber:x:delay')
- if delay_tag:
+ delay_tag = message.find('{jabber:x:delay}x')
+ if delay_tag is not None:
delayed = True
- date = common.datetime_tuple(delay_tag.getAttr('stamp'))
+ date = common.datetime_tuple(delay_tag.attrib['stamp'])
else:
delayed = False
- if stanza.getType() != 'groupchat':
- return # ignore all messages not comming from a MUC
- nick_from = stanza.getFrom().getResource()
- room_from = stanza.getFrom().getStripped()
+ date = None
+ nick_from = message['from'].resource
+ room_from = message.getMucroom()
+ room = self.get_room_by_name(room_from)
if (self.ignores.has_key(room_from)) and (nick_from in self.ignores[room_from]):
return
room = self.get_room_by_name(room_from)
- if not room:
- self.information(_("message received for a non-existing room: %s") % (room_from))
+ if not room:
+ self.information(_("message received for a non-existing room: %s") % (room_from))
return
- body = stanza.getBody()
- subject = stanza.getSubject()
+ body = message['body']#stanza.getBody()
+ subject = message['subject']#stanza.getSubject()
if subject:
if nick_from:
- self.add_message_to_room(room, _("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject}, date)
+ self.add_message_to_room(room, _("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject}, time=date)
else:
- self.add_message_to_room(room, _("The subject is: %(subject)s") % {'subject':subject}, date)
+ self.add_message_to_room(room, _("The subject is: %(subject)s") % {'subject':subject}, time=date)
room.topic = subject.encode('utf-8').replace('\n', '|')
if room == self.current_room():
self.window.topic_win.refresh(room.topic)
@@ -442,139 +638,6 @@ class Gui(object):
self.refresh_window()
doupdate()
- def room_presence(self, stanza):
- """
- Display the presence on the room window and update the
- presence information of the concerned user
- """
- from_nick = stanza.getFrom().getResource()
- from_room = stanza.getFrom().getStripped()
- room = self.get_room_by_name(from_room)
- if not room:
- return
- else:
- msg = None
- affiliation = stanza.getAffiliation()
- show = stanza.getShow()
- status = stanza.getStatus()
- role = stanza.getRole()
- jid = stanza.getJid()
- 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
- self.add_message_to_room(room, _("Your nickname is %s") % (from_nick))
- # Check for a 170 status code
- for xtag in stanza.getTags('x'):
- for child in xtag.getTags('status'):
- if child.getAttr('code') == '170':
- self.add_message_to_room(room, 'Warning: this room is publicly logged')
- new_user.color = theme.COLOR_OWN_NICK
- 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))
- hide_exit_join = config.get('hide_exit_join', -1)
- if hide_exit_join != 0:
- if not jid:
- 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}, colorized=True)
- # nick change
- elif change_nick:
- if user.nick == room.own_nick:
- room.own_nick = stanza.getNick().encode('utf-8')
- # 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 = stanza.getNick()
- user.change_nick(stanza.getNick())
- self.add_message_to_room(room, _('[%(old)s] is now known as [%(new)s]') % {'old':from_nick, 'new':stanza.getNick()}, colorized=True)
- # 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()}, colorized=True)
- new_jid = private_room.name.split('/')[0]+'/'+stanza.getNick()
- private_room.jid = new_jid
- private_room.name = new_jid
-
- # kick
- elif kick:
- room.users.remove(user)
- try:
- reason = stanza.getReason()
- except:
- reason = ''
- try:
- by = stanza.getActor()
- except:
- by = None
- if from_nick == room.own_nick: # we are kicked
- room.disconnect()
- if by:
- self.add_message_to_room(room, _("%(spec) [You] have been kicked by [%(by)s]. Reason: {%(reason)s}") % {'spec': theme.CHAR_KICK, 'by':by, 'reason':reason}, colorized=True)
- else:
- self.add_message_to_room(room, _("%(spec)s [You] have been kicked. Reason: %(reason)s") % {'reason':reason, 'spec':theme.CHAR_KICK}, colorized=True)
- # try to auto-rejoin
- if config.get('autorejoin', 'false') == 'true':
- self.muc.join_room(room.name, room.own_nick)
- else:
- if by:
- self.add_message_to_room(room, _("%(spec)s [%(nick)s] has been kicked by %(by)s. Reason: %(reason)s") % {'spec':theme.CHAR_KICK, 'nick':from_nick, 'by':by, 'reason':reason}, colorized=True)
- else:
- self.add_message_to_room(room, _("%(spec)s [%(nick)s] has been kicked. Reason: %(reason)s") % {'nick':from_nick, 'reason':reason, 'spec':theme.CHAR_KICK}, colorized=True)
- # user quit
- elif status == 'offline' or role == 'none':
- 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:
- self.add_message_to_room(room, _('%(spec)s [%(nick)s] has left the room') % {'nick':from_nick, 'spec':theme.CHAR_QUIT}, colorized=True)
- else:
- self.add_message_to_room(room, _('%(spec)s [%(nick)s] (%(jid)s) has left the room') % {'spec':theme.CHAR_QUIT, 'nick':from_nick, 'jid':jid}, colorized=True)
- private_room = self.get_room_by_name(stanza.getFrom())
- if private_room:
- self.add_message_to_room(private_room, _('%(spec)s [%(nick)s] has left the room') % {'nick':from_nick, 'spec':theme.CHAR_KICK}, colorized=True)
- # status change
- else:
- # 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 ","
- 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(stanza.getFrom())
- 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)
- if room == self.current_room():
- self.window.user_win.refresh(room.users)
- self.window.input.refresh()
- doupdate()
def add_message_to_room(self, room, txt, time=None, nickname=None, colorized=False):
"""
@@ -611,10 +674,10 @@ class Gui(object):
self.add_message_to_room(self.current_room(), _("Error: unknown command (%s)") % (command))
elif self.current_room().name != 'Info':
if self.current_room().jid is not None:
- self.muc.send_private_message(self.current_room().name, line)
+ muc.send_private_message(self.xmpp, self.current_room().name, line)
self.add_message_to_room(self.current_room(), line.decode('utf-8'), None, self.current_room().own_nick.decode('utf-8'))
else:
- self.muc.send_message(self.current_room().name, line)
+ muc.send_groupchat_message(self.xmpp, self.current_room().name, line)
self.window.input.refresh()
doupdate()
@@ -640,6 +703,8 @@ class Gui(object):
"""
/whois <nickname>
"""
+ # TODO
+ return
args = arg.split()
room = self.current_room()
if len(args) != 1:
@@ -701,7 +766,9 @@ class Gui(object):
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)
+ res = muc.eject_user(self.xmpp, roomname, nick, reason)
+ if res['type'] == 'error':
+ self.room_error(res, roomname)
def command_say(self, arg):
"""
@@ -710,10 +777,10 @@ class Gui(object):
line = arg
if self.current_room().name != 'Info':
if self.current_room().jid is not None:
- self.muc.send_private_message(self.current_room().name, line)
+ muc.send_private_message(self.xmpp, 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)
+ muc.send_groupchat_message(self.xmpp, self.current_room().name, line)
self.window.input.refresh()
doupdate()
@@ -751,7 +818,7 @@ class Gui(object):
# 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):
- room += '@%s' % jid_get_domain(self.current_room().name.encode('utf-8'))
+ room += '@%s' % jid_get_domain(self.current_room().name)
else: # no server could be found, print a message and return
self.add_message_to_room(self.current_room(), _("You didn't specify a server for the room you want to join"))
return
@@ -759,14 +826,14 @@ class Gui(object):
if len(args) == 2: # a password is provided
password = args[1]
if r and r.joined: # if we are already in the room
- self.add_message_to_room(self.current_room(), _("already in room [%s]") % room)
+ self.command_win('%s' % (r.nb))
return
- self.muc.join_room(room, nick, password)
+ room = room.lower()
+ self.xmpp.plugin['xep_0045'].joinMUC(room, nick, password)
if not r: # if the room window exists, we don't recreate it.
- self.join_room(room, nick)
+ self.open_new_room(room, nick)
else:
r.own_nick = nick
- # r.own_nick = nick
r.users = []
def command_bookmark(self, arg):
@@ -852,7 +919,7 @@ class Gui(object):
msg = None
for room in self.rooms:
if room.joined:
- self.muc.change_show(room.name, room.own_nick, show, msg)
+ muc.change_show(self.xmpp, room.name, room.own_nick, show, msg)
def command_ignore(self, arg):
"""
@@ -926,7 +993,7 @@ class Gui(object):
else:
msg = None
if room.joined:
- self.muc.quit_room(room.name, room.own_nick, msg)
+ muc.leave_groupchat(self.xmpp, room.name, room.own_nick, arg)
self.rooms.remove(self.current_room())
self.refresh_window()
@@ -955,7 +1022,7 @@ class Gui(object):
r = self.open_private_window(room.name, user.nick.decode('utf-8'))
if r and len(args) > 1:
msg = arg[len(nick)+1:]
- self.muc.send_private_message(r.name, msg)
+ muc.send_private_message(r.name, msg)
self.add_message_to_room(r, msg.decode('utf-8'), None, r.own_nick)
def command_topic(self, arg):
@@ -970,7 +1037,7 @@ class Gui(object):
subject = ' '.join(args)
if not room.joined or room.name == "Info":
return
- self.muc.change_subject(room.name, subject)
+ muc.change_subject(self.xmpp, room.name, subject)
def command_link(self, arg):
"""
@@ -1029,7 +1096,7 @@ class Gui(object):
room = self.current_room()
if not room.joined or room.name == "Info":
return
- self.muc.change_nick(room.name, nick)
+ muc.change_nick(self.xmpp, room.name, nick)
def information(self, msg):
"""
@@ -1047,8 +1114,9 @@ class Gui(object):
msg = arg
else:
msg = None
- if msg:
- self.muc.disconnect(self.rooms, msg)
- sleep(0.2) # :(
- self.reset_curses()
+ 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()
sys.exit()
diff --git a/src/handler.py b/src/handler.py
index a8bebe23..5542a7a1 100644
--- a/src/handler.py
+++ b/src/handler.py
@@ -17,6 +17,8 @@
from singleton import Singleton
+#Todo, it's not a singleton. Oh, also, remove-me
+
class Handler(Singleton):
"""
This class is the global handler for the software's signals.
diff --git a/src/logging.py b/src/logger.py
index 1134244f..1134244f 100644
--- a/src/logging.py
+++ b/src/logger.py
diff --git a/src/multiuserchat.py b/src/multiuserchat.py
index bd60641e..41b1ebd5 100644
--- a/src/multiuserchat.py
+++ b/src/multiuserchat.py
@@ -1,4 +1,3 @@
-# Copyright 2009, 2010 Erwan Briand
# Copyright 2010, Florent Le Coz <louizatakk@fedoraproject.org>
# This program is free software: you can redistribute it and/or modify
@@ -13,331 +12,92 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# Implementation of the XEP-0045: Multi-User Chat.
+"""
+Implementation of the XEP-0045: Multi-User Chat.
+Add some facilities that are not available on the XEP_0045
+sleek plugin
+"""
-from xmpp import NS_MUC_ADMIN, NS_MUC
-from xmpp.protocol import Presence, Iq, Message, JID
-import xmpp
-import common
-import threading
-import os
+import sleekxmpp
-from time import (altzone, gmtime, localtime, strftime, timezone)
+from xml.etree import cElementTree as ET
-from handler import Handler
-from config import config
-from common import get_stripped_jid
-from common import is_jid
+from common import debug
-class VcardSender(threading.Thread):
+def send_private_message(xmpp, jid, line):
"""
- avatar sending is really slow (don't know why...)
- use a thread to send it...
+ Send a private message
"""
- def __init__(self, connection):
- threading.Thread.__init__(self)
- self.connection = connection
- self.handler = Handler()
+ msg = xmpp.makeMessage(jid)
+ msg['to'] = jid
+ msg['type'] = 'chat'
+ msg['body'] = line
+ msg.send()
- def run(self):
- self.send_vcard()
-
- def send_vcard(self):
- """
- Method stolen from Gajim (thanks)
- ## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
- ## Junglecow J <junglecow AT gmail.com>
- ## Copyright (C) 2006-2007 Tomasz Melcer <liori AT exroot.org>
- ## Travis Shirk <travis AT pobox.com>
- ## Nikos Kouremenos <kourem AT gmail.com>
- ## Copyright (C) 2006-2008 Yann Leboulanger <asterix AT lagaule.org>
- ## Copyright (C) 2007 Julien Pivotto <roidelapluie AT gmail.com>
- ## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
- ## Jean-Marie Traissard <jim AT lapin.org>
- ## Stephan Erb <steve-e AT h3c.de>
- ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
- (one of these people coded this method, probably)
- """
- if not self.connection:
- return
- vcard = {
- "FN":config.get('full_name', ''),
- "URL":config.get('website', ''),
- "EMAIL":{
- "USERID":config.get('email', '')
- },
- "DESC":config.get('comment', 'A proud Poezio user')
- }
- photo_file_path = config.get('photo', '../data/poezio_80.png')
- (image, mime_type, sha1) = common.get_base64_from_file(photo_file_path)
- if image:
- vcard['PHOTO'] = {"TYPE":mime_type,"BINVAL":image}
- iq = xmpp.Iq(typ = 'set')
- iq2 = iq.addChild('vCard', namespace=xmpp.NS_VCARD)
- for i in vcard:
- if i == 'jid':
- continue
- if isinstance(vcard[i], dict):
- iq3 = iq2.addChild(i)
- for j in vcard[i]:
- iq3.addChild(j).setData(vcard[i][j])
- elif isinstance(vcard[i], list):
- for j in vcard[i]:
- iq3 = iq2.addChild(i)
- for k in j:
- iq3.addChild(k).setData(j[k])
- else:
- iq2.addChild(i).setData(vcard[i])
- self.connection.send(iq)
- iq = xmpp.Iq(typ = 'set')
- iq2 = iq.addChild('vCard', namespace=xmpp.NS_VCARD_UPDATE)
- iq2.addChild('PHOTO').setData(sha1)
- self.connection.send(iq)
-
-class MultiUserChat(object):
- def __init__(self, connection):
- self.connection = connection
- self.vcard_sender = VcardSender(self.connection)
-
- self.rooms = []
- self.rn = {}
-
- self.own_jid = None
-
- self.handler = Handler()
- self.handler.connect('join-room', self.join_room)
- self.handler.connect('on-connected', self.on_connected)
- self.handler.connect('send-version', self.send_version)
- self.handler.connect('send-time', self.send_time)
-
- def on_connected(self, jid):
- self.own_jid = jid
- rooms = config.get('rooms', '')
- if rooms == '' or type(rooms) != str:
- return
- else:
- 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.handler.emit('join-room', room=roomname, nick=nick)
- 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 send_message(self, room, message):
- mes = Message(to=room)
- mes.setBody(message)
- mes.setType('groupchat')
- self.connection.send(mes)
-
- def send_private_message(self, user_jid, message):
- mes = Message(to=user_jid)
- mes.setBody(message)
- mes.setType('chat')
- self.connection.send(mes)
-
- def request_vcard(self, room_name, nickname):
- """
- Request the vCard of an user, over a MUC or not
- """
- request = Iq(typ='get', to='%s/%s'% (room_name, nickname))
- vcard_tag = request.addChild(name='vCard', namespace='vcard-temp')
- self.connection.send(request)
-
- def join_room(self, room, nick, password=None):
- """Join a new room"""
- pres = Presence(to='%s/%s' % (room, nick))
- pres.setFrom('%s'%self.own_jid)
- x_tag = pres.addChild(name='x', namespace=NS_MUC)
- if password:
- passwd = x_tag.addChild(name='password')
- passwd.setData(password)
- muc_history_length = config.get('muc_history_length', -1)
- if muc_history_length >= 0:
- history_tag = x_tag.addChild(name='history')
- if muc_history_length == 0:
- history_tag.setAttr('maxchars', 0)
- else:
- history_tag.setAttr('maxstanzas', muc_history_length)
- self.connection.send(pres)
-
- def quit_room(self, room, nick, msg=None):
- """Quit a room"""
- if room is None and nick is None:
- self.on_disconnect()
- return
-
- pres = Presence(to='%s/%s' % (room, nick), typ='unavailable')
- if msg:
- pres.setStatus(msg)
- self.connection.send(pres)
-
- def disconnect(self, rooms, msg):
- """
- """
- for room in rooms:
- if room.jid is None and room.joined:
- pres = Presence(to='%s' % room.name,
- typ='unavailable')
- pres.setStatus(msg)
- self.connection.send(pres)
-
- def on_disconnect(self):
- """Called at disconnection"""
- for room in self.rooms:
- pres = Presence(to='%s/%s' % (room, self.rn[room]),
- typ='unavailable')
- self.connection.send(pres)
-
- def on_iq(self, iq):
- """Receive a MUC iq notification"""
- from_ = iq.getFrom().__str__()
-
- if get_stripped_jid(from_) in self.rooms:
- children = iq.getChildren()
- for child in children:
- if child.getName() == 'error':
- code = int(child.getAttr('code'))
- msg = None
-
- echildren = child.getChildren()
- for echild in echildren:
- if echild.getName() == 'text':
- msg = echild.getData()
-
- self.handler.emit('on-muc-error',
- room=from_,
- code=code,
- msg=msg)
-
- def on_presence(self, presence):
- """Receive a MUC presence notification"""
- from_ = presence.getFrom().__str__()
- if get_stripped_jid(from_) in self.rooms:
- self.handler.emit('on-muc-presence-changed',
- jid=from_.encode('utf-8'),
- priority=presence.getPriority(),
- show=presence.getShow(),
- status=presence.getStatus(),
- stanza=presence
- )
-
- def on_message(self, message):
- """Receive a MUC message notification"""
- from_ = message.getFrom().__str__().encode('utf-8')
-
- if get_stripped_jid(from_) in self.rooms:
- body_ = message.getBody()
- type_ = message.getType()
- subj_ = message.getSubject()
- self.handler.emit('on-muc-message-received',
- jid=from_, msg=body_, subject=subj_,
- typ=type_, stanza=message)
-
- def eject_user(self, room, action, nick, reason):
- """Eject an user from a room"""
- iq = Iq(typ='set', to=room)
- query = iq.addChild('query', namespace=NS_MUC_ADMIN)
- item = query.addChild('item')
-
- if action == 'kick':
- item.setAttr('role', 'none')
- if is_jid(nick):
- item.setAttr('jid', nick)
- else:
- item.setAttr('nick', nick)
- elif action == 'ban':
- item.setAttr('affiliation', 'outcast')
- item.setAttr('jid', nick)
-
- if reason is not None:
- rson = item.addChild('reason')
- rson.setData(reason)
-
- self.connection.send(iq)
-
- def change_role(self, room, nick, role):
- """Change the role of an user"""
- iq = Iq(typ='set', to=room)
- query = iq.addChild('query', namespace=NS_MUC_ADMIN)
- item = query.addChild('item')
- item.setAttr('nick', nick)
- item.setAttr('role', role)
-
- self.connection.send(iq)
-
- def change_aff(self, room, jid, aff):
- """Change the affiliation of an user"""
- iq = Iq(typ='set', to=room)
- query = iq.addChild('query', namespace=NS_MUC_ADMIN)
- item = query.addChild('item')
- item.setAttr('jid', jid)
- item.setAttr('affiliation', aff)
-
- self.connection.send(iq)
-
- def change_subject(self, room, subject):
- """Change the subject of a room"""
- message = Message(typ='groupchat', to=room)
- subj = message.addChild('subject')
- subj.setData(subject)
+def send_groupchat_message(xmpp, jid, line):
+ """
+ Send a message to the groupchat
+ """
+ msg = xmpp.makeMessage(jid)
+ msg['type'] = 'groupchat'
+ msg['body'] = line
+ msg.send()
- self.connection.send(message)
+def change_show(xmpp, jid, own_nick, show, status):
+ """
+ Change our 'Show'
+ """
+ pres = xmpp.makePresence(pto='%s/%s' % (jid, own_nick),
+ pfrom=xmpp.fulljid)
+ if show: # if show is None, don't put a <show /> tag. It means "online"
+ pres['type'] = show
+ if status:
+ pres['status'] = status
+ debug('Change presence: %s\n' % (pres))
+ pres.send()
+
+def change_subject(xmpp, jid, subject):
+ """
+ Change the room subject
+ """
+ msg = xmpp.makeMessage(jid)
+ msg['type'] = 'groupchat'
+ msg['subject'] = subject
+ msg['from'] = xmpp.jid
+ msg.send()
- def change_nick(self, room, nick):
- """Change the nickname"""
- pres = Presence(to='%s/%s' % (room, nick))
- self.connection.send(pres)
+def change_nick(xmpp, jid, nick):
+ """
+ Change our own nick in a room
+ """
+ xmpp.makePresence(pto='%s/%s' % (jid, nick),
+ pfrom=xmpp.jid).send()
- def change_show(self, room, nick, show, status):
- pres = Presence(to='%s/%s' % (room, nick))
- if show: # if show is None, don't put a <show /> tag. It means "online"
- pres.setShow(show)
- if status:
- pres.setStatus(status)
- self.connection.send(pres)
+def join_groupchat(xmpp, jid, nick, password=None):
+ """
+ Join the groupchat
+ """
+ xmpp.plugin['xep_0045'].joinMUC(jid, nick, password)
- def send_version(self, iq_obj):
- """
- from gajim and modified
- """
- iq_obj = iq_obj.buildReply('result')
- qp = iq_obj.getTag('query')
- if config.get('send_poezio_info', 'true') == 'true':
- qp.setTagData('name', 'Poezio')
- qp.setTagData('version', '0.6.3 dev')
- else:
- qp.setTagData('name', 'Unknown')
- qp.setTagData('version', 'Unknown')
- if config.get('send_os_info', 'true') == 'true':
- qp.setTagData('os', common.get_os_info())
- else:
- qp.setTagData('os', 'Unknown')
- self.connection.send(iq_obj)
- raise xmpp.protocol.NodeProcessed
+def leave_groupchat(xmpp, jid, own_nick, msg):
+ """
+ Leave the groupchat
+ """
+ xmpp.plugin['xep_0045'].leaveMUC(jid, own_nick, msg)
- def send_time(self, iq_obj):
- """
- from gajim
- """
- iq_obj = iq_obj.buildReply('result')
- qp = iq_obj.setTag('time',
- namespace="urn:xmpp:time")
- if config.get('send_time', 'true') == 'true':
- qp.setTagData('utc', strftime('%Y-%m-%dT%H:%M:%SZ', gmtime()))
- isdst = localtime().tm_isdst
- zone = -(timezone, altzone)[isdst] / 60
- tzo = (zone / 60, abs(zone % 60))
- qp.setTagData('tzo', '%+03d:%02d' % (tzo))
- self.connection.send(iq_obj)
- raise xmpp.protocol.NodeProcessed
+def eject_user(xmpp, jid, nick, reason):
+ """
+ (try to) Eject an user from the room
+ """
+ iq = xmpp.makeIqSet()
+ query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
+ item = ET.Element('{http://jabber.org/protocol/muc#admin}item', {'nick':nick, 'role':'none'})
+ if reason:
+ reason_el = ET.Element('{http://jabber.org/protocol/muc#admin}reason')
+ reason_el.text = reason
+ item.append(reason_el)
+ query.append(item)
+ iq.append(query)
+ iq['to'] = jid
+ return iq.send()
diff --git a/src/poezio.py b/src/poezio.py
index a37e28b3..22af358e 100644
--- a/src/poezio.py
+++ b/src/poezio.py
@@ -25,26 +25,6 @@ import threading
import sys
import traceback
-def installThreadExcepthook():
- """
- Workaround for sys.excepthook thread bug
- See http://bugs.python.org/issue1230540
- Python, you made me sad :(
- """
- init_old = threading.Thread.__init__
- def init(self, *args, **kwargs):
- init_old(self, *args, **kwargs)
- run_old = self.run
- def run_with_except_hook(*args, **kw):
- try:
- run_old(*args, **kw)
- except (KeyboardInterrupt, SystemExit):
- raise
- except:
- sys.excepthook(*sys.exc_info())
- self.run = run_with_except_hook
- threading.Thread.__init__ = init
-
class MyStdErr(object):
def __init__(self, fd):
"""
@@ -59,6 +39,7 @@ class MyStdErr(object):
Restaure the good ol' sys.stderr, because we need
it in order to print the tracebacks
"""
+ sys.stderr.close()
sys.stderr = self.old_stderr
my_stderr = MyStdErr(open('/dev/null', 'a'))
@@ -77,30 +58,24 @@ def exception_handler(type_, value, trace):
sys.excepthook = exception_handler
-import sys
-import curses
import signal
from connection import Connection
-from multiuserchat import MultiUserChat
from config import config
from gui import Gui
-from curses import initscr
signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl-c
def main():
"""
- main function
+ The main function consist of the Connection initialization
+ then the gui (ncurses) init, connection handlers and then the
+ connection is "started"
"""
- resource = config.get('resource', 'poezio')
- server = config.get('server', 'anon.louiz.org:jeproteste.info')
- connection = Connection(server, resource)
- connection.start()
- stdscr = initscr()
- gui = Gui(stdscr, MultiUserChat(connection.client))
- gui.main_loop(stdscr)
+ xmpp = Connection() # Connection init
+ gui = Gui(xmpp) # Gui init.
+ xmpp.start() # Connect to remote server
+ gui.main_loop() # Refresh the screen, wait for user events etc
if __name__ == '__main__':
- installThreadExcepthook()
main()
diff --git a/src/room.py b/src/room.py
index 02aa336f..4fd7a799 100644
--- a/src/room.py
+++ b/src/room.py
@@ -19,7 +19,7 @@
from datetime import datetime
from random import randrange
from config import config
-from logging import logger
+from logger import logger
from message import Message
import common