frontends, core, plugin XEP-0045: leave implementation + better nick change

- memory: individual entity cache can be deleted
	- plugin XEP-0045: nick change are now detected and userChangedNick signal is sent instead of joined/left
	- plugin XEP-0045: leave implementation
	- frontends: userChangedNick signal management
	- Primitivus: an alert is shown in notification bar in case of error in sendMessage
This commit is contained in:
Goffi 2012-09-28 00:26:24 +02:00
commit c520325941

View file

@ -20,24 +20,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from logging import debug, info, warning, error
from twisted.words.xish import domish
from twisted.internet import protocol, defer, threads, reactor
from twisted.words.protocols.jabber import client, jid, xmlstream
from twisted.words.protocols.jabber import error as jab_error
from twisted.words.protocols.jabber.xmlstream import IQ
from twisted.internet import defer
from twisted.words.protocols.jabber import jid
from sat.core import exceptions
import os.path
import uuid
from zope.interface import implements
from wokkel import muc
from wokkel import disco, iwokkel, muc
from base64 import b64decode
from hashlib import sha1
from time import sleep
try:
from twisted.words.protocols.xmlstream import XMPPHandler
@ -65,15 +56,19 @@ class XEP_0045():
self.host = host
self.clients={}
host.bridge.addMethod("joinMUC", ".plugin", in_sign='ssa{ss}s', out_sign='', method=self._join)
host.bridge.addMethod("changeNick", ".plugin", in_sign='sss', out_sign='', method=self.changeNick)
host.bridge.addMethod("mucNick", ".plugin", in_sign='sss', out_sign='', method=self.mucNick)
host.bridge.addMethod("mucLeave", ".plugin", in_sign='ss', out_sign='', method=self.leave)
host.bridge.addMethod("getRoomsJoined", ".plugin", in_sign='s', out_sign='a(sass)', method=self.getRoomsJoined)
host.bridge.addMethod("getRoomsSubjects", ".plugin", in_sign='s', out_sign='a(ss)', method=self.getRoomsSubjects)
host.bridge.addMethod("getUniqueRoomName", ".plugin", in_sign='s', out_sign='s', method=self.getUniqueName)
host.bridge.addSignal("roomJoined", ".plugin", signature='sasss') #args: room_jid, room_nicks, user_nick, profile
host.bridge.addSignal("roomLeft", ".plugin", signature='ss') #args: room_jid, profile
host.bridge.addSignal("roomUserJoined", ".plugin", signature='ssa{ss}s') #args: room_jid, user_nick, user_data, profile
host.bridge.addSignal("roomUserLeft", ".plugin", signature='ssa{ss}s') #args: room_jid, user_nick, user_data, profile
host.bridge.addSignal("roomUserChangedNick", ".plugin", signature='ssss') #args: room_jid, old_nick, new_nick, profile
host.bridge.addSignal("roomNewSubject", ".plugin", signature='sss') #args: room_jid, subject, profile
def __check_profile(self, profile):
"""check if profile is used and connected
if profile known but disconnected, remove it from known profiles
@ -179,18 +174,30 @@ class XEP_0045():
d = self.join(room_jid, nick, options, profile)
d.addErrback(lambda x: warning(_('Error while joining room'))) #TODO: error management + signal in bridge
def nick(self, room_jid, nick, profile_key='@DEFAULT@'):
def nick(self, room_jid, nick, profile_key):
profile = self.host.memory.getProfileName(profile_key)
if not self.__check_profile(profile):
raise exceptions.UnknownProfileError("Unknown or disconnected profile")
if not self.clients[profile].joined_rooms.has_key(room_jid.userhost()):
raise UnknownRoom("This room has not been joined")
return self.clients[profile].nick(room_jid, nick)
def changeNick(self, room_jid_s, nick, profile_key='@DEFAULT@'):
def leave(self, room_jid, profile_key):
profile = self.host.memory.getProfileName(profile_key)
if not self.__check_profile(profile):
raise exceptions.UnknownProfileError("Unknown or disconnected profile")
if not self.clients[profile].joined_rooms.has_key(room_jid.userhost()):
raise UnknownRoom("This room has not been joined")
return self.clients[profile].leave(room_jid)
def mucNick(self, room_jid_s, nick, profile_key='@DEFAULT@'):
"""Change nickname in a room"""
return self.nick(jid.JID(room_jid_s), nick, profile_key)
def mucLeave(self, room_jid_s, profile_key='@DEFAULT@'):
"""Leave a room"""
return self.leave(jid.JID(room_jid_s), profile_key)
def getHandler(self, profile):
self.clients[profile] = SatMUCClient(self)
return self.clients[profile]
@ -206,22 +213,62 @@ class SatMUCClient (muc.MUCClient):
muc.MUCClient.__init__(self)
self.joined_rooms = {}
self.rec_subjects = {}
self.__changing_nicks = set() # used to keep trace of who is changing nick,
# and to discard userJoinedRoom signal in this case
print "init SatMUCClient OK"
def unavailableReceived(self, presence):
#XXX: we override this method to manage nickname change
#TODO: feed this back to Wokkel
"""
Unavailable presence was received.
If this was received from a MUC room occupant JID, that occupant has
left the room.
"""
room, user = self._getRoomUser(presence)
if room is None or user is None:
return
room.removeUser(user)
if muc.STATUS_CODE.NEW_NICK in presence.mucStatuses:
self.__changing_nicks.add(presence.nick)
self.userChangedNick(room, user, presence.nick)
else:
self.__changing_nicks.discard(presence.nick)
self.userLeftRoom(room, user)
def receivedGroupChat(self, room, user, body):
debug('receivedGroupChat: room=%s user=%s body=%s', room, user, body)
def userJoinedRoom(self, room, user):
debug (_("user %(nick)s has joined room (%(room_id)s)") % {'nick':user.nick, 'room_id':room.occupantJID.userhost()})
if not self.host.trigger.point("MUC user joined", room, user, self.parent.profile):
return
user_data={'entity':user.entity.full() if user.entity else '', 'affiliation':user.affiliation, 'role':user.role}
self.host.bridge.roomUserJoined(room.roomJID.userhost(), user.nick, user_data, self.parent.profile)
if user.nick in self.__changing_nicks:
self.__changing_nicks.remove(user.nick)
else:
debug (_("user %(nick)s has joined room (%(room_id)s)") % {'nick':user.nick, 'room_id':room.occupantJID.userhost()})
if not self.host.trigger.point("MUC user joined", room, user, self.parent.profile):
return
user_data={'entity':user.entity.full() if user.entity else '', 'affiliation':user.affiliation, 'role':user.role}
self.host.bridge.roomUserJoined(room.roomJID.userhost(), user.nick, user_data, self.parent.profile)
def userLeftRoom(self, room, user):
debug (_("user %(nick)s left room (%(room_id)s)") % {'nick':user.nick, 'room_id':room.occupantJID.userhost()})
user_data={'entity':user.entity.full() if user.entity else '', 'affiliation':user.affiliation, 'role':user.role}
self.host.bridge.roomUserLeft(room.roomJID.userhost(), user.nick, user_data, self.parent.profile)
if user.nick == room.nick:
# we left the room
room_jid_s = room.roomJID.userhost()
info (_("Room [%(room)s] left (%(profile)s))") % { "room": room_jid_s,
"profile": self.parent.profile })
self.host.memory.delEntityCache(room.roomJID, self.parent.profile)
del self.plugin_parent.clients[self.parent.profile].joined_rooms[room_jid_s]
self.host.bridge.roomLeft(room.roomJID.userhost(), self.parent.profile)
else:
debug (_("user %(nick)s left room (%(room_id)s)") % {'nick':user.nick, 'room_id':room.occupantJID.userhost()})
user_data={'entity':user.entity.full() if user.entity else '', 'affiliation':user.affiliation, 'role':user.role}
self.host.bridge.roomUserLeft(room.roomJID.userhost(), user.nick, user_data, self.parent.profile)
def userChangedNick(self, room, user, new_nick):
self.host.bridge.roomUserChangedNick(room.roomJID.userhost(), user.nick, new_nick, self.parent.profile)
def userUpdatedStatus(self, room, user, show, status):
print("FIXME: MUC status not managed yet")
@ -232,6 +279,7 @@ class SatMUCClient (muc.MUCClient):
self.rec_subjects[room.roomJID.userhost()] = (room.roomJID.userhost(), subject)
self.host.bridge.roomNewSubject(room.roomJID.userhost(), subject, self.parent.profile)
#def connectionInitialized(self):
#pass