diff src/plugins/plugin_xep_0045.py @ 944:e1842ebcb2f3

core, plugin XEP-0115: discovery refactoring: - hashing algorithm of XEP-0115 has been including in core - our own hash is still calculated by XEP-0115 and can be regenerated with XEP_0115.recalculateHash - old discovery methods have been removed. Now the following methods are used: - hasFeature: tell if a feature is available for an entity - getDiscoInfos: self explaining - getDiscoItems: self explaining - findServiceEntities: return all available items of an entity which given (category, type) - findFeaturesSet: search for a set of features in entity + entity's items all these methods are asynchronous, and manage cache automatically - XEP-0115 manage in a better way hashes, and now use a trigger for presence instead of monkey patch - new FeatureNotFound exception, when we want to do something which is not available - refactored client initialisation sequence, removed client.initialized Deferred - added constant APP_URL - test_plugin_xep_0033.py has been temporarly deactivated, the time to adapt it - lot of cleaning
author Goffi <goffi@goffi.org>
date Fri, 28 Mar 2014 18:07:22 +0100
parents 73873e9b56f7
children 5e8e8a034411
line wrap: on
line diff
--- a/src/plugins/plugin_xep_0045.py	Fri Mar 28 18:07:17 2014 +0100
+++ b/src/plugins/plugin_xep_0045.py	Fri Mar 28 18:07:22 2014 +0100
@@ -32,11 +32,6 @@
 from sat.tools import xml_tools
 
 
-try:
-    from twisted.words.protocols.xmlstream import XMPPHandler
-except ImportError:
-    from wokkel.subprotocols import XMPPHandler
-
 PLUGIN_INFO = {
     "name": "XEP 0045 Plugin",
     "import_name": "XEP-0045",
@@ -53,6 +48,8 @@
 class UnknownRoom(Exception):
     pass
 
+class NotReadyYet(Exception):
+    pass
 
 class XEP_0045(object):
     # TODO: this plugin is messy, need a big cleanup/refactoring
@@ -67,7 +64,7 @@
         host.bridge.addMethod("mucLeave", ".plugin", in_sign='ss', out_sign='', method=self.mucLeave, async=True)
         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='ss', out_sign='s', method=self.getUniqueName)
+        host.bridge.addMethod("getUniqueRoomName", ".plugin", in_sign='ss', out_sign='s', method=self._getUniqueName)
         host.bridge.addMethod("configureRoom", ".plugin", in_sign='ss', out_sign='s', method=self._configureRoom, async=True)
         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
@@ -82,8 +79,15 @@
         except KeyError:
             info(_("Text commands not available"))
 
+    def profileConnected(self, profile):
+        def assign_service(service):
+            client = self.host.getClient(profile)
+            client.muc_service = service
+        self.getMUCService(profile_key=profile).addCallback(assign_service)
+
     def __check_profile(self, profile):
         """check if profile is used and connected
+
         if profile known but disconnected, remove it from known profiles
         @param profile: profile to check
         @return: True if the profile is known and connected, else False"""
@@ -136,6 +140,7 @@
 
     def getRoomNick(self, room_jid_s, profile_key=C.PROF_KEY_NONE):
         """return nick used in room by user
+
         @param room_jid_s: unicode room id
         @profile_key: profile
         @return: nick or empty string in case of error"""
@@ -146,6 +151,7 @@
 
     def getRoomNickOfUser(self, room, user_jid, secure=True):
         """Returns the nick of the given user in the room.
+
         @room: instance of wokkel.muc.Room
         @user: JID or unicode (JID userhost).
         @param secure: set to True for a secure check
@@ -166,6 +172,7 @@
 
     def getRoomNicksOfUsers(self, room, users=[], secure=True):
         """Returns the nicks of the given users in the room.
+
         @room: instance of wokkel.muc.Room
         @users: list of JID or unicode (JID userhost).
         @param secure: set to True for a secure check
@@ -189,10 +196,10 @@
 
     def configureRoom(self, room_jid, profile_key=C.PROF_KEY_NONE):
         """ return the room configuration form
+
         @param room: jid of the room to configure
         @param profile_key: %(doc_profile_key)s
         @return: configuration form as XMLUI
-
         """
         profile = self.host.memory.getProfileName(profile_key)
         if not self.__check_profile(profile):
@@ -243,38 +250,47 @@
             return []
         return self.clients[profile].rec_subjects.values()
 
-    def getMUCService(self, profile):
-        """Return the MUC service or None"""
+    @defer.inlineCallbacks
+    def getMUCService(self, jid_=None, profile_key=C.PROF_KEY_NONE):
+        """Return first found MUC service of an entity
+
+        @param jid_: entity which may have a MUC service, or None for our own server
+        @param profile_key: %(doc_profile_key)s
+        """
         muc_service = None
-        for service in self.host.memory.getServerServiceEntities("conference", "text", profile=profile):
+        services = yield self.host.findServiceEntities("conference", "text", jid_, profile_key=profile_key)
+        for service in services:
             if not ".irc." in service.userhost():
-                #FIXME:
-                #This awfull ugly hack is here to avoid an issue with openfire: the irc gateway
-                #use "conference/text" identity (instead of "conference/irc"), there is certainly a better way
-                #to manage this, but this hack fill do it for test purpose
+                # FIXME:
+                # This ugly hack is here to avoid an issue with openfire: the IRC gateway
+                # use "conference/text" identity (instead of "conference/irc")
                 muc_service = service
                 break
-        return muc_service
+        defer.returnValue(muc_service)
 
-    def getUniqueName(self, muc_service="", profile_key=C.PROF_KEY_NONE):
-        """Return unique name for room, avoiding collision
+    def _getUniqueName(self, muc_service="", profile_key=C.PROF_KEY_NONE):
+        return self.getUniqueName(muc_service or None, profile_key).full()
+
+    def getUniqueName(self, muc_service=None, profile_key=C.PROF_KEY_NONE):
+        """Return unique name for a room, avoiding collision
+
         @param muc_service: leave empty string to use the default service
         @return: unique room userhost, or '' if an error occured.
         """
         #TODO: we should use #RFC-0045 10.1.4 when available here
-        profile = self.host.memory.getProfileName(profile_key)
-        if not profile:
-            error(_("Unknown profile"))
-            return ""
+        client = self.host.getClient(profile_key)
         room_name = uuid.uuid1()
-        print "\n\n===> room_name:", room_name
-        if muc_service == "":
-            muc_service = self.getMUCService(profile)
-            if not muc_service:
-                error(_("Can't find a MUC service"))
-                return ""
-            muc_service = muc_service.userhost()
-        return "%s@%s" % (room_name, muc_service)
+        if muc_service is None:
+            try:
+                muc_service = client.muc_service
+            except AttributeError:
+                raise NotReadyYet("Main server MUC service has not been checked yet")
+            if muc_service is None:
+                warning(_("No MUC service found on main server"))
+                raise exceptions.FeatureNotFound
+
+        muc_service = muc_service.userhost()
+        return jid.JID("%s@%s" % (room_name, muc_service))
 
     def join(self, room_jid, nick, options, profile_key=C.PROF_KEY_NONE):
         def _errDeferred(exc_obj=Exception, txt='Error while joining room'):
@@ -315,7 +331,7 @@
             warning(mess)
             self.host.bridge.newAlert(mess, _("Group chat error"), "ERROR", profile)
             return
-        d = self.join(room_jid, nick, options, profile)
+        self.join(room_jid, nick, options, profile)
         # TODO: error management + signal in bridge
         return room_jid_s