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:
parent
4e40bead7c
commit
c520325941
8 changed files with 145 additions and 50 deletions
|
|
@ -203,10 +203,10 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
self.present_wid.changeValues(nicks)
|
||||
self.host.redraw()
|
||||
|
||||
def replaceUser(self, param_nick):
|
||||
def replaceUser(self, param_nick, show_info=True):
|
||||
"""Add user if it is not in the group list"""
|
||||
nick = unicode(param_nick) #FIXME: should be done in DBus bridge
|
||||
QuickChat.replaceUser(self, nick)
|
||||
QuickChat.replaceUser(self, nick, show_info)
|
||||
presents = self.present_wid.getAllValues()
|
||||
if nick not in presents:
|
||||
presents.append(nick)
|
||||
|
|
@ -214,10 +214,10 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
self.present_wid.changeValues(presents)
|
||||
self.host.redraw()
|
||||
|
||||
def removeUser(self, param_nick):
|
||||
def removeUser(self, param_nick, show_info=True):
|
||||
"""Remove a user from the group list"""
|
||||
nick = unicode(param_nick) #FIXME: should be done in DBus bridge
|
||||
QuickChat.removeUser(self, nick)
|
||||
QuickChat.removeUser(self, nick, show_info)
|
||||
self.present_wid.deleteValue(nick)
|
||||
self.host.redraw()
|
||||
|
||||
|
|
@ -234,11 +234,11 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
#as that mean that he is probably watching discussion history
|
||||
self.text_list.set_focus(len(self.content)-1)
|
||||
self.host.redraw()
|
||||
if not self.host.notify.hasFocus():
|
||||
if not self.host.x_notify.hasFocus():
|
||||
if self.type=="one2one":
|
||||
self.host.notify.sendNotification(_("Primitivus: %s is talking to you") % from_jid)
|
||||
self.host.x_notify.sendNotification(_("Primitivus: %s is talking to you") % from_jid)
|
||||
elif self.getUserNick().lower() in msg.lower():
|
||||
self.host.notify.sendNotification(_("Primitivus: Somebody pinged your name in %s room") % self.target)
|
||||
self.host.x_notify.sendNotification(_("Primitivus: Somebody pinged your name in %s room") % self.target)
|
||||
|
||||
def printInfo(self, msg, type='normal'):
|
||||
"""Print general info
|
||||
|
|
@ -253,11 +253,11 @@ class Chat(urwid.WidgetWrap, QuickChat):
|
|||
#as that mean that he is probably watching discussion history
|
||||
self.text_list.set_focus(len(self.content)-1)
|
||||
self.host.redraw()
|
||||
if not self.host.notify.hasFocus():
|
||||
if not self.host.x_notify.hasFocus():
|
||||
if self.type=="one2one":
|
||||
self.host.notify.sendNotification(_("Primitivus: there is a message about you"))
|
||||
self.host.x_notify.sendNotification(_("Primitivus: there is a message about you"))
|
||||
elif self.getUserNick().lower() in msg.lower():
|
||||
self.host.notify.sendNotification(_("Primitivus: Somebody is talking about you in %s room") % self.target)
|
||||
self.host.x_notify.sendNotification(_("Primitivus: Somebody is talking about you in %s room") % self.target)
|
||||
|
||||
def startGame(self, game_type, referee, players):
|
||||
"""Configure the chat window to start a game"""
|
||||
|
|
|
|||
|
|
@ -239,6 +239,10 @@ class ContactList(urwid.WidgetWrap, QuickContactList):
|
|||
groups_to_remove.append(group)
|
||||
for group in groups_to_remove:
|
||||
del self.groups[group]
|
||||
try:
|
||||
del self.special[jid.short]
|
||||
except KeyError:
|
||||
pass
|
||||
self.update()
|
||||
|
||||
def add(self, jid, param_groups=[None]):
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class PrimitivusApp(QuickApp):
|
|||
urwid.connect_signal(self.notBar.progress,'click',lambda x:self.addWindow(self.progress_wid))
|
||||
self.__saved_overlay = None
|
||||
|
||||
self.notify = Notify()
|
||||
self.x_notify = Notify()
|
||||
|
||||
def debug(self):
|
||||
"""convenient method to reset screen and launch p(u)db"""
|
||||
|
|
@ -299,10 +299,13 @@ class PrimitivusApp(QuickApp):
|
|||
contact = self.contact_list.getContact() ###Based on the fact that there is currently only one contact selectableat once
|
||||
if contact:
|
||||
chat = self.chat_wins[contact]
|
||||
self.bridge.sendMessage(contact,
|
||||
try:
|
||||
self.bridge.sendMessage(contact,
|
||||
editBar.get_edit_text(),
|
||||
mess_type = "groupchat" if chat.type == 'group' else "chat",
|
||||
profile_key=self.profile)
|
||||
except:
|
||||
self.notify(_("Error while sending message"))
|
||||
editBar.set_edit_text('')
|
||||
|
||||
def newMessage(self, from_jid, msg, type, to_jid, profile):
|
||||
|
|
|
|||
|
|
@ -57,8 +57,10 @@ class QuickApp():
|
|||
self.bridge.register("actionResult", self.actionResult)
|
||||
self.bridge.register("actionResultExt", self.actionResult)
|
||||
self.bridge.register("roomJoined", self.roomJoined, "plugin")
|
||||
self.bridge.register("roomLeft", self.roomLeft, "plugin")
|
||||
self.bridge.register("roomUserJoined", self.roomUserJoined, "plugin")
|
||||
self.bridge.register("roomUserLeft", self.roomUserLeft, "plugin")
|
||||
self.bridge.register("roomUserChangedNick", self.roomUserChangedNick, "plugin")
|
||||
self.bridge.register("roomNewSubject", self.roomNewSubject, "plugin")
|
||||
self.bridge.register("tarotGameStarted", self.tarotGameStarted, "plugin")
|
||||
self.bridge.register("tarotGameNew", self.tarotGameNew, "plugin")
|
||||
|
|
@ -290,6 +292,13 @@ class QuickApp():
|
|||
self.chat_wins[room_jid].setPresents(list(set([user_nick]+room_nicks)))
|
||||
self.contact_list.setSpecial(JID(room_jid), "MUC")
|
||||
|
||||
def roomLeft(self, room_jid, profile):
|
||||
"""Called when a MUC room is left"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
debug (_("Room [%(room_jid)s] left by %(profile)s") % {'room_jid':room_jid, 'profile': profile})
|
||||
del self.chat_wins[room_jid]
|
||||
self.contact_list.remove(room_jid)
|
||||
|
||||
def roomUserJoined(self, room_jid, user_nick, user_data, profile):
|
||||
"""Called when an user joined a MUC room"""
|
||||
|
|
@ -307,6 +316,14 @@ class QuickApp():
|
|||
self.chat_wins[room_jid].removeUser(user_nick)
|
||||
debug (_("user [%(user_nick)s] left room [%(room_jid)s]") % {'user_nick':user_nick, 'room_jid':room_jid})
|
||||
|
||||
def roomUserChangedNick(self, room_jid, old_nick, new_nick, profile):
|
||||
"""Called when an user joined a MUC room"""
|
||||
if not self.check_profile(profile):
|
||||
return
|
||||
if self.chat_wins.has_key(room_jid):
|
||||
self.chat_wins[room_jid].changeUserNick(old_nick, new_nick)
|
||||
debug (_("user [%(old_nick)s] is now known as [%(new_nick)s] in room [%(room_jid)s]") % {'old_nick':old_nick, 'new_nick':new_nick, 'room_jid':room_jid})
|
||||
|
||||
def roomNewSubject(self, room_jid, subject, profile):
|
||||
"""Called when subject of MUC room change"""
|
||||
if not self.check_profile(profile):
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class QuickChat():
|
|||
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
|
||||
self.occupants.update(nicks)
|
||||
|
||||
def replaceUser(self, nick):
|
||||
def replaceUser(self, nick, show_info=True):
|
||||
"""Add user if it is not in the group list"""
|
||||
debug (_("Replacing user %s") % nick)
|
||||
if self.type != "group":
|
||||
|
|
@ -58,24 +58,35 @@ class QuickChat():
|
|||
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
|
||||
len_before = len(self.occupants)
|
||||
self.occupants.add(nick)
|
||||
if len_before != len(self.occupants):
|
||||
if len_before != len(self.occupants) and show_info:
|
||||
self.printInfo("=> %s has joined the room" % nick)
|
||||
|
||||
def setUserNick(self, nick):
|
||||
"""Set the nick of the user, usefull for e.g. change the color of the user"""
|
||||
self.nick = nick
|
||||
|
||||
def getUserNick(self):
|
||||
return unicode(self.nick)
|
||||
|
||||
def removeUser(self, nick):
|
||||
def removeUser(self, nick, show_info=True):
|
||||
"""Remove a user from the group list"""
|
||||
debug(_("Removing user %s") % nick)
|
||||
if self.type != "group":
|
||||
error (_("[INTERNAL] trying to remove user for a non group chat window"))
|
||||
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
|
||||
self.occupants.remove(nick)
|
||||
self.printInfo("<= %s has left the room" % nick)
|
||||
if show_info:
|
||||
self.printInfo("<= %s has left the room" % nick)
|
||||
|
||||
def setUserNick(self, nick):
|
||||
"""Set the nick of the user, usefull for e.g. change the color of the user"""
|
||||
self.nick = nick
|
||||
|
||||
def getUserNick(self):
|
||||
return unicode(self.nick)
|
||||
|
||||
def changeUserNick(self, old_nick, new_nick):
|
||||
"""Change nick of a user in group list"""
|
||||
debug(_("Changing nick of user %(old_nick)s to %(new_nick)s") % {"old_nick": old_nick, "new_nick": new_nick})
|
||||
if self.type != "group":
|
||||
error (_("[INTERNAL] trying to change user nick for a non group chat window"))
|
||||
raise Exception("INTERNAL ERROR") #TODO: raise proper Exception here
|
||||
self.removeUser(old_nick, show_info=False)
|
||||
self.replaceUser(new_nick, show_info=False)
|
||||
self.printInfo("%s is now known as %s" % (old_nick, new_nick))
|
||||
|
||||
def setSubject(self, subject):
|
||||
"""Set title for a group chat"""
|
||||
|
|
|
|||
|
|
@ -142,18 +142,18 @@ class Chat(wx.Frame, QuickChat):
|
|||
for nick in nicks:
|
||||
self.present_panel.presents.replace(nick)
|
||||
|
||||
def replaceUser(self, nick):
|
||||
def replaceUser(self, nick, show_info=True):
|
||||
"""Add user if it is not in the group list"""
|
||||
debug (_("Replacing user %s") % nick)
|
||||
if self.type != "group":
|
||||
error (_("[INTERNAL] trying to replace user for a non group chat window"))
|
||||
return
|
||||
QuickChat.replaceUser(self, nick)
|
||||
QuickChat.replaceUser(self, nick, show_info)
|
||||
self.present_panel.presents.replace(nick)
|
||||
|
||||
def removeUser(self, nick):
|
||||
def removeUser(self, nick, show_info=True):
|
||||
"""Remove a user from the group list"""
|
||||
QuickChat.removeUser(self, nick)
|
||||
QuickChat.removeUser(self, nick, show_info)
|
||||
self.present_panel.presents.remove(nick)
|
||||
|
||||
def setSubject(self, subject):
|
||||
|
|
|
|||
|
|
@ -750,6 +750,18 @@ class Memory:
|
|||
ret[key] = entity_data[key]
|
||||
return ret
|
||||
|
||||
def delEntityCache(self, entity_jid, profile_key):
|
||||
"""Remove cached data for entity
|
||||
@param entity_jid: JID of the entity
|
||||
"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
try:
|
||||
del self.entitiesCache[profile][entity_jid.userhost()]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def addWaitingSub(self, _type, entity_jid, profile_key):
|
||||
"""Called when a subcription request is received"""
|
||||
profile = self.getProfileName(profile_key)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue