From 2f4bdfee1bb4efd6bc390a4c97d27d40d88b8d3a Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Mon, 13 Dec 2010 15:58:59 -0500
Subject: Update some docs.

---
 sleekxmpp/plugins/xep_0030/disco.py        | 84 ++++++++++++++++++++++++------
 sleekxmpp/plugins/xep_0030/stanza/disco.py |  0
 sleekxmpp/plugins/xep_0030/stanza/items.py |  4 +-
 sleekxmpp/plugins/xep_0030/static.py       |  7 ++-
 4 files changed, 74 insertions(+), 21 deletions(-)
 delete mode 100644 sleekxmpp/plugins/xep_0030/stanza/disco.py

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/xep_0030/disco.py b/sleekxmpp/plugins/xep_0030/disco.py
index c323ba7c..c272929e 100644
--- a/sleekxmpp/plugins/xep_0030/disco.py
+++ b/sleekxmpp/plugins/xep_0030/disco.py
@@ -26,15 +26,23 @@ class xep_0030(base_plugin):
     """
     XEP-0030: Service Discovery
 
+    Service discovery in XMPP allows entities to discover information about
+    other agents in the network, such as the feature sets supported by a
+    client, or signposts to other, related entities.
+
+    Also see <http://www.xmpp.org/extensions/xep-0030.html>.
+
     Stream Handlers:
-        Disco Info  --
-        Disco Items --
+        Disco Info  -- Any Iq stanze that includes a query with the
+                       namespace http://jabber.org/protocol/disco#info.
+        Disco Items -- Any Iq stanze that includes a query with the
+                       namespace http://jabber.org/protocol/disco#items.
 
     Events:
-        disco_info         --
-        disco_items        --
-        disco_info_query   --
-        disco_items_query  --
+        disco_info         -- Received a disco#info Iq query result.
+        disco_items        -- Received a disco#items Iq query result.
+        disco_info_query   -- Received a disco#info Iq query request.
+        disco_items_query  -- Received a disco#items Iq query request.
 
     Methods:
         set_node_handler --
@@ -79,14 +87,45 @@ class xep_0030(base_plugin):
                                  'jid': {},
                                  'node': {}}
 
-
     def set_node_handler(self, htype, jid=None, node=None, handler=None):
         """
+        Add a node handler for the given hierarchy level and
+        handler type.
+
+        Node handlers are ordered in a hierarchy where the
+        most specific handler is executed. Thus, a fallback,
+        global handler can be used for the majority of cases
+        with a few node specific handler that override the
+        global behavior.
+
+        Node handler hierarchy:
+            JID   | Node  | Level
+            ---------------------
+            None  | None  | Global
+            Given | None  | All nodes for the JID
+            None  | Given | Node on self.xmpp.boundjid
+            Given | Given | A single node
+
+        Handler types:
+            get_info
+            get_items
+            set_identities
+            set_features
+            set_items
+            del_info
+            del_items
+            del_identity
+            del_feature
+            del_item
+            add_identity
+            add_feature
+            add_item
+ 
         Arguments:
-            htype
-            jid
-            node
-            handler
+            htype   -- The operation provided by the handler.
+            jid     --
+            node    --
+            handler --
         """
         if htype not in self._disco_ops:
             return
@@ -102,10 +141,24 @@ class xep_0030(base_plugin):
 
     def del_node_handler(self, htype, jid, node):
         """
+        Remove a handler type for a JID and node combination.
+
+        The next handler in the hierarchy will be used if one
+        exists. If removing the global handler, make sure that
+        other handlers exist to process existing nodes.
+
+        Node handler hierarchy:
+            JID   | Node  | Level
+            ---------------------
+            None  | None  | Global
+            Given | None  | All nodes for the JID
+            None  | Given | Node on self.xmpp.boundjid
+            Given | Given | A single node
+
         Arguments:
-            htype
-            jid
-            node
+            htype -- The type of handler to remove.
+            jid   -- The JID from which to remove the handler.
+            node  -- The node from which to remove the handler.
         """
         self.set_node_handler(htype, jid, node, None)
 
@@ -218,7 +271,7 @@ class xep_0030(base_plugin):
             htype -- The handler type to execute.
             jid   -- The JID requested.
             node  -- The node requested.
-            dat   -- Optional, custom data to pass to the handler.
+            data  -- Optional, custom data to pass to the handler.
         """
         if jid is None:
             jid = self.xmpp.boundjid.full
@@ -311,4 +364,3 @@ class xep_0030(base_plugin):
                           "Using default disco#info feature.")
                 info.add_feature(info.namespace)
         return info
-
diff --git a/sleekxmpp/plugins/xep_0030/stanza/disco.py b/sleekxmpp/plugins/xep_0030/stanza/disco.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/sleekxmpp/plugins/xep_0030/stanza/items.py b/sleekxmpp/plugins/xep_0030/stanza/items.py
index 319e666f..a1fb819c 100644
--- a/sleekxmpp/plugins/xep_0030/stanza/items.py
+++ b/sleekxmpp/plugins/xep_0030/stanza/items.py
@@ -12,8 +12,6 @@ from sleekxmpp.xmlstream import ElementBase, ET
 class DiscoItems(ElementBase):
 
     """
-             
-
     Example disco#items stanzas:
         <iq type="get">
           <query xmlns="http://jabber.org/protocol/disco#items" />
@@ -74,7 +72,7 @@ class DiscoItems(ElementBase):
 
         Arguments:
             jid  -- The JID for the item.
-            node -- Optional additional information to reference 
+            node -- Optional additional information to reference
                     non-addressable items.
             name -- Optional human readable name for the item.
         """
diff --git a/sleekxmpp/plugins/xep_0030/static.py b/sleekxmpp/plugins/xep_0030/static.py
index f3693228..e2d03315 100644
--- a/sleekxmpp/plugins/xep_0030/static.py
+++ b/sleekxmpp/plugins/xep_0030/static.py
@@ -35,6 +35,11 @@ class StaticDisco(object):
 
     def __init__(self, xmpp):
         """
+        Create a static disco interface. Sets of disco#info and
+        disco#items are maintained for every given JID and node
+        combination. These stanzas are used to store disco
+        information in memory without any additional processing.
+
         Arguments:
             xmpp -- The main SleekXMPP object.
         """
@@ -101,7 +106,6 @@ class StaticDisco(object):
                 data.get('name', None),
                 data.get('lang', None))
 
-
     def add_feature(self, jid, node, data=None):
         self.add_node(jid, node)
         self.nodes[(jid, node)]['info'].add_feature(data.get('feature', ''))
@@ -124,4 +128,3 @@ class StaticDisco(object):
     def del_item(self, jid, node, data=None):
         if (jid, node) in self.nodes:
             self.nodes[(jid, node)]['items'].del_item(**data)
-
-- 
cgit v1.2.3


From d8aae885266f5e57fd8c04713e63bbf1ff213089 Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Wed, 15 Dec 2010 17:58:15 -0500
Subject: The documentation effort continues.

Also, need to start working on a replacement for the XEP-30 page in the
wiki since the API has changed significantly.
---
 sleekxmpp/plugins/xep_0030/disco.py | 67 +++++++++++++++++++++++++++----------
 1 file changed, 49 insertions(+), 18 deletions(-)

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/xep_0030/disco.py b/sleekxmpp/plugins/xep_0030/disco.py
index c272929e..78820b45 100644
--- a/sleekxmpp/plugins/xep_0030/disco.py
+++ b/sleekxmpp/plugins/xep_0030/disco.py
@@ -120,12 +120,15 @@ class xep_0030(base_plugin):
             add_identity
             add_feature
             add_item
- 
+
         Arguments:
             htype   -- The operation provided by the handler.
-            jid     --
-            node    --
-            handler --
+            jid     -- The JID the handler applies to. May be narrowed
+                       further if a node is given.
+            node    -- The particular node the handler is for. If no JID
+                       is given, then the self.xmpp.boundjid.full is
+                       assumed.
+            handler -- The handler function to use.
         """
         if htype not in self._disco_ops:
             return
@@ -185,14 +188,28 @@ class xep_0030(base_plugin):
 
     def get_info(self, jid=None, node=None, local=False, **kwargs):
         """
+        Retrieve the disco#info results from a given JID/node combination.
+
+        Info may be retrieved from both local resources and remote agents;
+        the local parameter indicates if the information should be gathered
+        by executing the local node handlers, or if a disco#info stanza
+        must be generated and sent.
+
         Arguments:
-            jid      --
-            node     --
-            local    --
-            dfrom    --
-            block    --
-            timeout  --
-            callback --
+            jid      -- Request info from this JID.
+            node     -- The particular node to query.
+            local    -- If true, then the query is for a JID/node
+                        combination handled by this Sleek instance and
+                        no stanzas need to be sent.
+                        Otherwise, a disco stanza must be sent to the
+                        remove JID to retrieve the info.
+            dfrom    -- Specifiy the sender's JID.
+            block    -- If true, block and wait for the stanzas' reply.
+            timeout  -- The time in seconds to block while waiting for
+                        a reply. If None, then wait indefinitely.
+            callback -- Optional callback to execute when a reply is
+                        received instead of blocking and waiting for
+                        the reply.
         """
         if local or jid is None:
             log.debug("Looking up local disco#info data " + \
@@ -211,14 +228,28 @@ class xep_0030(base_plugin):
 
     def get_items(self, jid=None, node=None, local=False, **kwargs):
         """
+        Retrieve the disco#items results from a given JID/node combination.
+
+        Items may be retrieved from both local resources and remote agents;
+        the local parameter indicates if the items should be gathered by
+        executing the local node handlers, or if a disco#items stanza must
+        be generated and sent.
+
         Arguments:
-            jid      --
-            node     --
-            local    --
-            dfrom    --
-            block    --
-            timeout  --
-            callback --
+            jid      -- Request info from this JID.
+            node     -- The particular node to query.
+            local    -- If true, then the query is for a JID/node
+                        combination handled by this Sleek instance and
+                        no stanzas need to be sent.
+                        Otherwise, a disco stanza must be sent to the
+                        remove JID to retrieve the items.
+            dfrom    -- Specifiy the sender's JID.
+            block    -- If true, block and wait for the stanzas' reply.
+            timeout  -- The time in seconds to block while waiting for
+                        a reply. If None, then wait indefinitely.
+            callback -- Optional callback to execute when a reply is
+                        received instead of blocking and waiting for
+                        the reply.
         """
         if local or jid is None:
             return self._run_node_handler('get_items', jid, node, kwargs)
-- 
cgit v1.2.3


From 2c5b77ae2e7502cbb681e9449d09150a063ec7fd Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Wed, 15 Dec 2010 18:57:45 -0500
Subject: And some more docs.

---
 sleekxmpp/plugins/xep_0030/disco.py | 223 ++++++++++++++++++++++++++++++------
 1 file changed, 191 insertions(+), 32 deletions(-)

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/xep_0030/disco.py b/sleekxmpp/plugins/xep_0030/disco.py
index 78820b45..783eddb3 100644
--- a/sleekxmpp/plugins/xep_0030/disco.py
+++ b/sleekxmpp/plugins/xep_0030/disco.py
@@ -32,6 +32,21 @@ class xep_0030(base_plugin):
 
     Also see <http://www.xmpp.org/extensions/xep-0030.html>.
 
+    The XEP-0030 plugin works using a hierarchy of dynamic
+    node handlers, ranging from global handlers to specific
+    JID+node handlers. The default set of handlers operate
+    in a static manner, storing disco information in memory.
+    However, custom handlers may use any available backend
+    storage mechanism desired, such as SQLite or Redis.
+
+    Node handler hierarchy:
+        JID   | Node  | Level
+        ---------------------
+        None  | None  | Global
+        Given | None  | All nodes for the JID
+        None  | Given | Node on self.xmpp.boundjid
+        Given | Given | A single node
+
     Stream Handlers:
         Disco Info  -- Any Iq stanze that includes a query with the
                        namespace http://jabber.org/protocol/disco#info.
@@ -44,20 +59,33 @@ class xep_0030(base_plugin):
         disco_info_query   -- Received a disco#info Iq query request.
         disco_items_query  -- Received a disco#items Iq query request.
 
+    Attributes:
+        stanza -- A reference to the module containing the stanza classes
+                  provided by this plugin.
+        static -- Object containing the default set of static node handlers.
+        xmpp   -- The main SleekXMPP object.
+
     Methods:
-        set_node_handler --
-        del_node_handler --
-        add_identity     --
+        set_node_handler -- Assign a handler to a JID/node combination.
+        del_node_handler -- Remove a handler from a JID/node combination.
+        get_info         -- Retrieve disco#info data, locally or remote.
+        get_items        -- Retrieve disco#items data, locally or remote.
+        set_identities   --
+        set_features     --
+        set_items        --
+        del_items        --
         del_identity     --
-        add_feature      --
         del_feature      --
-        add_item         --
         del_item         --
-        get_info         --
-        get_items        --
+        add_identity     --
+        add_feature      --
+        add_item         --
     """
 
     def plugin_init(self):
+        """
+        Start the XEP-0030 plugin.
+        """
         self.xep = '0030'
         self.description = 'Service Discovery'
         self.stanza = sleekxmpp.plugins.xep_0030.stanza
@@ -78,14 +106,14 @@ class xep_0030(base_plugin):
         self.static = StaticDisco(self.xmpp)
 
         self._disco_ops = ['get_info', 'set_identities', 'set_features',
-                           'del_info', 'get_items', 'set_items', 'del_items',
+                           'get_items', 'set_items', 'del_items',
                            'add_identity', 'del_identity', 'add_feature',
                            'del_feature', 'add_item', 'del_item']
-        self.handlers = {}
+        self._handlers = {}
         for op in self._disco_ops:
-            self.handlers[op] = {'global': getattr(self.static, op),
-                                 'jid': {},
-                                 'node': {}}
+            self._handlers[op] = {'global': getattr(self.static, op),
+                                  'jid': {},
+                                  'node': {}}
 
     def set_node_handler(self, htype, jid=None, node=None, handler=None):
         """
@@ -112,7 +140,6 @@ class xep_0030(base_plugin):
             set_identities
             set_features
             set_items
-            del_info
             del_items
             del_identity
             del_feature
@@ -133,14 +160,14 @@ class xep_0030(base_plugin):
         if htype not in self._disco_ops:
             return
         if jid is None and node is None:
-            self.handlers[htype]['global'] = handler
+            self._handlers[htype]['global'] = handler
         elif node is None:
-            self.handlers[htype]['jid'][jid] = handler
+            self._handlers[htype]['jid'][jid] = handler
         elif jid is None:
             jid = self.xmpp.boundjid.full
-            self.handlers[htype]['node'][(jid, node)] = handler
+            self._handlers[htype]['node'][(jid, node)] = handler
         else:
-            self.handlers[htype]['node'][(jid, node)] = handler
+            self._handlers[htype]['node'][(jid, node)] = handler
 
     def del_node_handler(self, htype, jid, node):
         """
@@ -263,35 +290,167 @@ class xep_0030(base_plugin):
                        block=kwargs.get('block', None),
                        callback=kwargs.get('callback', None))
 
-    def set_info(self, jid=None, node=None, **kwargs):
-        self._run_node_handler('set_info', jid, node, kwargs)
+    def set_items(self, jid=None, node=None, **kwargs):
+        """
+        Set or replace all items for the specified JID/node combination.
 
-    def del_info(self, jid=None, node=None, **kwargs):
-        self._run_node_handler('del_info', jid, node, kwargs)
+        The given items must be in a list or set where each item is a
+        tuple of the form: (jid, node, name).
 
-    def set_items(self, jid=None, node=None, **kwargs):
+        Arguments:
+            jid   -- The JID to modify.
+            node  -- Optional node to modify.
+            items -- A series of items in tuple format.
+        """
         self._run_node_handler('set_items', jid, node, kwargs)
 
     def del_items(self, jid=None, node=None, **kwargs):
+        """
+        Remove all items from the given JID/node combination.
+
+        Arguments:
+            jid  -- The JID to modify.
+            node -- Optional node to modify.
+        """
         self._run_node_handler('del_items', jid, node, kwargs)
 
+    def add_item(self, jid=None, node=None, **kwargs):
+        """
+        Add a new item element to the given JID/node combination.
+
+        Each item is required to have a JID, but may also specify
+        a node value to reference non-addressable entities.
+
+        Arguments:
+            jid   -- The JID to modify.
+            node  -- The node to modify.
+            ijid  -- The JID for the item.
+            inode -- Optional node for the item.
+            name  -- Optional name for the item.
+        """
+        self._run_node_handler('add_item', jid, node, kwargs)
+
+    def del_item(self, jid=None, node=None, **kwargs):
+        """
+        Remove a single item from the given JID/node combination.
+
+        Arguments:
+            jid   -- The JID to modify.
+            node  -- The node to modify.
+            ijid  -- The item's JID.
+            inode -- The item's node.
+        """
+        self._run_node_handler('del_item', jid, node, kwargs)
+
     def add_identity(self, jid=None, node=None, **kwargs):
+        """
+        Add a new identity to the given JID/node combination.
+
+        Each identity must be unique in terms of all four identity
+        components: category, type, name, and language.
+
+        Multiple, identical category/type pairs are allowed only
+        if the xml:lang values are different. Likewise, multiple
+        category/type/xml:lang pairs are allowed so long as the
+        names are different. A category and type is always required.
+
+        Arguments:
+            jid      -- The JID to modify.
+            node     -- The node to modify.
+            category -- The identity's category.
+            itype    -- The identity's type.
+            name     -- Optional name for the identity.
+            lang     -- Optional two-letter language code.
+        """
         self._run_node_handler('add_identity', jid, node, kwargs)
 
     def add_feature(self, jid=None, node=None, **kwargs):
+        """
+        Add a feature to a JID/node combination.
+
+        Arguments:
+            jid     -- The JID to modify.
+            node    -- The node to modify.
+            feature -- The namespace of the supported feature.
+        """
         self._run_node_handler('add_feature', jid, node, kwargs)
 
     def del_identity(self, jid=None, node=None, **kwargs):
+        """
+        Remove an identity from the given JID/node combination.
+
+        Arguments:
+            jid      -- The JID to modify.
+            node     -- The node to modify.
+            category -- The identity's category.
+            itype    -- The identity's type value.
+            name     -- Optional, human readable name for the identity.
+            lang     -- Optional, the identity's xml:lang value.
+        """
         self._run_node_handler('del_identity', jid, node, kwargs)
 
     def del_feature(self, jid=None, node=None, **kwargs):
+        """
+        Remove a feature from a given JID/node combination.
+
+        Arguments:
+            jid     -- The JID to modify.
+            node    -- The node to modify.
+            feature -- The feature's namespace.
+        """
         self._run_node_handler('del_feature', jid, node, kwargs)
 
-    def add_item(self, jid=None, node=None, **kwargs):
-        self._run_node_handler('add_item', jid, node, kwargs)
+    def set_identities(self, jid=None, node=None, **kwargs):
+        """
+        Add or replace all identities for the given JID/node combination.
 
-    def del_item(self, jid=None, node=None, **kwargs):
-        self._run_node_handler('del_item', jid, node, kwargs)
+        The identities must be in a set where each identity is a tuple
+        of the form: (category, type, lang, name)
+
+        Arguments:
+            jid        -- The JID to modify.
+            node       -- The node to modify.
+            identities -- A set of identities in tuple form.
+            lang       -- Optional, xml:lang value.
+        """
+        self._run_node_handler('set_identities', jid, node, kwargs)
+
+    def del_identities(self, jid=None, node=None, **kwargs):
+        """
+        Remove all identities for a JID/node combination.
+
+        If a language is specified, only identities using that
+        language will be removed.
+
+        Arguments:
+            jid  -- The JID to modify.
+            node -- The node to modify.
+            lang -- Optional. If given, only remove identities
+                    using this xml:lang value.
+        """
+        self._run_node_handler('del_identities', jid, node, kwargs)
+
+    def set_features(self, jid=None, node=None, **kwargs):
+        """
+        Add or replace the set of supported features
+        for a JID/node combination.
+
+        Arguments:
+            jid      -- The JID to modify.
+            node     -- The node to modify.
+            features -- The new set of supported features.
+        """
+        self._run_node_handler('set_features', jid, node, kwargs)
+
+    def del_features(self, jid=None, node=None, **kwargs):
+        """
+        Remove all features from a JID/node combination.
+
+        Arguments:
+            jid  -- The JID to modify.
+            node -- The node to modify.
+        """
+        self._run_node_handler('del_features', jid, node, kwargs)
 
     def _run_node_handler(self, htype, jid, node, data=None):
         """
@@ -309,12 +468,12 @@ class xep_0030(base_plugin):
         if node is None:
             node = ''
 
-        if self.handlers[htype]['node'].get((jid, node), False):
-            return self.handlers[htype]['node'][(jid, node)](jid, node, data)
-        elif self.handlers[htype]['jid'].get(jid, False):
-            return self.handlers[htype]['jid'][jid](jid, node, data)
-        elif self.handlers[htype]['global']:
-            return self.handlers[htype]['global'](jid, node, data)
+        if self._handlers[htype]['node'].get((jid, node), False):
+            return self._handlers[htype]['node'][(jid, node)](jid, node, data)
+        elif self._handlers[htype]['jid'].get(jid, False):
+            return self._handlers[htype]['jid'][jid](jid, node, data)
+        elif self._handlers[htype]['global']:
+            return self._handlers[htype]['global'](jid, node, data)
         else:
             return None
 
-- 
cgit v1.2.3


From 1ebc7f4d4bef38261111f16af4946d77d584d293 Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Wed, 15 Dec 2010 19:22:21 -0500
Subject: Implement a few more static node handlers.

---
 sleekxmpp/plugins/xep_0030/disco.py  |  2 +-
 sleekxmpp/plugins/xep_0030/static.py | 42 +++++++++++++++++++++---------------
 2 files changed, 26 insertions(+), 18 deletions(-)

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/xep_0030/disco.py b/sleekxmpp/plugins/xep_0030/disco.py
index 783eddb3..ad3d0ae2 100644
--- a/sleekxmpp/plugins/xep_0030/disco.py
+++ b/sleekxmpp/plugins/xep_0030/disco.py
@@ -452,7 +452,7 @@ class xep_0030(base_plugin):
         """
         self._run_node_handler('del_features', jid, node, kwargs)
 
-    def _run_node_handler(self, htype, jid, node, data=None):
+    def _run_node_handler(self, htype, jid, node, data={}):
         """
         Execute the most specific node handler for the given
         JID/node combination.
diff --git a/sleekxmpp/plugins/xep_0030/static.py b/sleekxmpp/plugins/xep_0030/static.py
index e2d03315..b0e931b4 100644
--- a/sleekxmpp/plugins/xep_0030/static.py
+++ b/sleekxmpp/plugins/xep_0030/static.py
@@ -57,7 +57,7 @@ class StaticDisco(object):
             self.nodes[(jid, node)]['info']['node'] = node
             self.nodes[(jid, node)]['items']['node'] = node
 
-    def get_info(self, jid, node, data=None):
+    def get_info(self, jid, node, data):
         if (jid, node) not in self.nodes:
             if not node:
                 return DiscoInfo()
@@ -66,11 +66,11 @@ class StaticDisco(object):
         else:
             return self.nodes[(jid, node)]['info']
 
-    def del_info(self, jid, node, data=None):
+    def del_info(self, jid, node, data):
         if (jid, node) in self.nodes:
             self.nodes[(jid, node)]['info'] = DiscoInfo()
 
-    def get_items(self, jid, node, data=None):
+    def get_items(self, jid, node, data):
         if (jid, node) not in self.nodes:
             if not node:
                 return DiscoInfo()
@@ -79,14 +79,16 @@ class StaticDisco(object):
         else:
             return self.nodes[(jid, node)]['items']
 
-    def set_items(self, jid, node, data=None):
-        pass
+    def set_items(self, jid, node, data):
+        items = data.get('items', set())
+        self.add_node(jid, node)
+        self.nodes[(jid, node)]['items']['items'] = items
 
-    def del_items(self, jid, node, data=None):
+    def del_items(self, jid, node, data):
         if (jid, node) in self.nodes:
             self.nodes[(jid, node)]['items'] = DiscoItems()
 
-    def add_identity(self, jid, node, data={}):
+    def add_identity(self, jid, node, data):
         self.add_node(jid, node)
         self.nodes[(jid, node)]['info'].add_identity(
                 data.get('category', ''),
@@ -94,10 +96,12 @@ class StaticDisco(object):
                 data.get('name', None),
                 data.get('lang', None))
 
-    def set_identities(self, jid, node, data=None):
-        pass
+    def set_identities(self, jid, node, data):
+        identities = data.get('identities', set())
+        self.add_node(jid, node)
+        self.nodes[(jid, node)]['info']['identities'] = identities
 
-    def del_identity(self, jid, node, data=None):
+    def del_identity(self, jid, node, data):
         if (jid, node) not in self.nodes:
             return
         self.nodes[(jid, node)]['info'].del_identity(
@@ -106,25 +110,29 @@ class StaticDisco(object):
                 data.get('name', None),
                 data.get('lang', None))
 
-    def add_feature(self, jid, node, data=None):
+    def add_feature(self, jid, node, data):
         self.add_node(jid, node)
         self.nodes[(jid, node)]['info'].add_feature(data.get('feature', ''))
 
-    def set_features(self, jid, node, data=None):
-        pass
+    def set_features(self, jid, node, data):
+        features = data.get('features', set())
+        self.add_node(jid, node)
+        self.nodes[(jid, node)]['info']['features'] = features
 
-    def del_feature(self, jid, node, data=None):
+    def del_feature(self, jid, node, data):
         if (jid, node) not in self.nodes:
             return
         self.nodes[(jid, node)]['info'].del_feature(data.get('feature', ''))
 
-    def add_item(self, jid, node, data=None):
+    def add_item(self, jid, node, data):
         self.add_node(jid, node)
         self.nodes[(jid, node)]['items'].add_item(
                 data.get('ijid', ''),
                 node=data.get('inode', None),
                 name=data.get('name', None))
 
-    def del_item(self, jid, node, data=None):
+    def del_item(self, jid, node, data):
         if (jid, node) in self.nodes:
-            self.nodes[(jid, node)]['items'].del_item(**data)
+            self.nodes[(jid, node)]['items'].del_item(
+                    data.get('ijid', ''),
+                    node=data.get('inode', None))
-- 
cgit v1.2.3


From e81683beeee5e7e03e05ad10320ebd1adb30269f Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Thu, 16 Dec 2010 15:29:17 -0500
Subject: Some Python 3.1+ compatibility fixes.

Originally contributed by filipegiusti.
---
 sleekxmpp/plugins/jobs.py     | 3 +--
 sleekxmpp/plugins/xep_0004.py | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/jobs.py b/sleekxmpp/plugins/jobs.py
index 0b93d62e..0f1f7fb1 100644
--- a/sleekxmpp/plugins/jobs.py
+++ b/sleekxmpp/plugins/jobs.py
@@ -1,7 +1,6 @@
 from . import base
 import logging
 from xml.etree import cElementTree as ET
-import types
 
 
 log = logging.getLogger(__name__)
@@ -43,7 +42,7 @@ class jobs(base.base_plugin):
 		iq['psstate']['item'] = jobid
 		iq['psstate']['payload'] = state
 		result = iq.send()
-		if result is None or type(result) == types.BooleanType or result['type'] != 'result':
+		if result is None or type(result) == bool or result['type'] != 'result':
 			log.error("Unable to change %s:%s to %s" % (node, jobid, state))
 			return False
 		return True
diff --git a/sleekxmpp/plugins/xep_0004.py b/sleekxmpp/plugins/xep_0004.py
index b8b7ebfa..5d41d269 100644
--- a/sleekxmpp/plugins/xep_0004.py
+++ b/sleekxmpp/plugins/xep_0004.py
@@ -13,7 +13,6 @@ from .. xmlstream.handler.callback import Callback
 from .. xmlstream.matcher.xpath import MatchXPath
 from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID
 from .. stanza.message import Message
-import types
 
 
 log = logging.getLogger(__name__)
@@ -203,7 +202,7 @@ class Form(ElementBase):
 
 	def merge(self, other):
 		new = copy.copy(self)
-		if type(other) == types.DictType:
+		if type(other) == dict:
 			new.setValues(other)
 			return new
 		nfields = new.getFields(use_dict=True)
-- 
cgit v1.2.3


From 67775fb8bdd806517864354564cb30aa0a6b4d66 Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Thu, 16 Dec 2010 15:38:00 -0500
Subject: Use boundjid in plugins instead of the deprecated accessors.

Originally contributed by skinkie, with a few modifications.
---
 sleekxmpp/plugins/gmail_notify.py |  2 +-
 sleekxmpp/plugins/xep_0045.py     |  6 +++---
 sleekxmpp/plugins/xep_0050.py     |  2 +-
 sleekxmpp/plugins/xep_0060.py     | 30 +++++++++++++++---------------
 sleekxmpp/plugins/xep_0092.py     |  2 +-
 5 files changed, 21 insertions(+), 21 deletions(-)

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/gmail_notify.py b/sleekxmpp/plugins/gmail_notify.py
index 7e888b90..9a94a413 100644
--- a/sleekxmpp/plugins/gmail_notify.py
+++ b/sleekxmpp/plugins/gmail_notify.py
@@ -143,7 +143,7 @@ class gmail_notify(base.base_plugin):
             log.info('Gmail: Searching for emails matching: "%s"' % query)
         iq = self.xmpp.Iq()
         iq['type'] = 'get'
-        iq['to'] = self.xmpp.jid
+        iq['to'] = self.xmpp.boundjid.bare
         iq['gmail']['q'] = query
         iq['gmail']['newer-than-time'] = newer
         return iq.send()
diff --git a/sleekxmpp/plugins/xep_0045.py b/sleekxmpp/plugins/xep_0045.py
index db41cdb3..e7f8c7ec 100644
--- a/sleekxmpp/plugins/xep_0045.py
+++ b/sleekxmpp/plugins/xep_0045.py
@@ -271,7 +271,7 @@ class xep_0045(base.base_plugin):
 	def invite(self, room, jid, reason=''):
 		""" Invite a jid to a room."""
 		msg = self.xmpp.makeMessage(room)
-		msg['from'] = self.xmpp.jid
+		msg['from'] = self.xmpp.boundjid.bare
 		x = ET.Element('{http://jabber.org/protocol/muc#user}x')
 		invite = ET.Element('{http://jabber.org/protocol/muc#user}invite', {'to': jid})
 		if reason:
@@ -294,7 +294,7 @@ class xep_0045(base.base_plugin):
 	def getRoomConfig(self, room):
 		iq = self.xmpp.makeIqGet('http://jabber.org/protocol/muc#owner')
 		iq['to'] = room
-		iq['from'] = self.xmpp.jid
+		iq['from'] = self.xmpp.boundjid.bare
 		result = iq.send()
 		if result is None or result['type'] != 'result':
 			raise ValueError
@@ -316,7 +316,7 @@ class xep_0045(base.base_plugin):
 		query.append(x)
 		iq = self.xmpp.makeIqSet(query)
 		iq['to'] = room
-		iq['from'] = self.xmpp.jid
+		iq['from'] = self.xmpp.boundjid.bare
 		iq.send()
 
 	def getJoinedRooms(self):
diff --git a/sleekxmpp/plugins/xep_0050.py b/sleekxmpp/plugins/xep_0050.py
index 5efb9116..439bebb9 100644
--- a/sleekxmpp/plugins/xep_0050.py
+++ b/sleekxmpp/plugins/xep_0050.py
@@ -110,7 +110,7 @@ class xep_0050(base.base_plugin):
 		if not id:
 			id = self.xmpp.getNewId()
 		iq = self.xmpp.makeIqResult(id)
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		iq.attrib['to'] = to
 		command = ET.Element('{http://jabber.org/protocol/commands}command')
 		command.attrib['node'] = node
diff --git a/sleekxmpp/plugins/xep_0060.py b/sleekxmpp/plugins/xep_0060.py
index a7c6d023..93124fca 100644
--- a/sleekxmpp/plugins/xep_0060.py
+++ b/sleekxmpp/plugins/xep_0060.py
@@ -51,7 +51,7 @@ class xep_0060(base.base_plugin):
 		pubsub.append(configure)
 		iq = self.xmpp.makeIqSet(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is False or result is None or result['type'] == 'error': return False
@@ -63,15 +63,15 @@ class xep_0060(base.base_plugin):
 		subscribe.attrib['node'] = node
 		if subscribee is None:
 			if bare:
-				subscribe.attrib['jid'] = self.xmpp.jid
+				subscribe.attrib['jid'] = self.xmpp.boundjid.bare
 			else:
-				subscribe.attrib['jid'] = self.xmpp.fulljid
+				subscribe.attrib['jid'] = self.xmpp.boundjid.full
 		else:
 			subscribe.attrib['jid'] = subscribee
 		pubsub.append(subscribe)
 		iq = self.xmpp.makeIqSet(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is False or result is None or result['type'] == 'error': return False
@@ -83,15 +83,15 @@ class xep_0060(base.base_plugin):
 		unsubscribe.attrib['node'] = node
 		if subscribee is None:
 			if bare:
-				unsubscribe.attrib['jid'] = self.xmpp.jid
+				unsubscribe.attrib['jid'] = self.xmpp.boundjid.bare
 			else:
-				unsubscribe.attrib['jid'] = self.xmpp.fulljid
+				unsubscribe.attrib['jid'] = self.xmpp.boundjid.full
 		else:
 			unsubscribe.attrib['jid'] = subscribee
 		pubsub.append(unsubscribe)
 		iq = self.xmpp.makeIqSet(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is False or result is None or result['type'] == 'error': return False
@@ -109,7 +109,7 @@ class xep_0060(base.base_plugin):
 		iq = self.xmpp.makeIqGet()
 		iq.append(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		#self.xmpp.add_handler("<iq id='%s'/>" % id, self.handlerCreateNodeResponse)
 		result = iq.send()
@@ -133,7 +133,7 @@ class xep_0060(base.base_plugin):
 		iq = self.xmpp.makeIqGet()
 		iq.append(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is None or result == False or result['type'] == 'error':
@@ -156,7 +156,7 @@ class xep_0060(base.base_plugin):
 		iq = self.xmpp.makeIqGet()
 		iq.append(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is None or result == False or result['type'] == 'error':
@@ -179,7 +179,7 @@ class xep_0060(base.base_plugin):
 		pubsub.append(delete)
 		iq.append(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		result = iq.send()
 		if result is not None and result is not False and result['type'] != 'error':
 			return True
@@ -196,7 +196,7 @@ class xep_0060(base.base_plugin):
 		pubsub.append(configure)
 		iq = self.xmpp.makeIqSet(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is None or result['type'] == 'error':
@@ -217,7 +217,7 @@ class xep_0060(base.base_plugin):
 		pubsub.append(publish)
 		iq = self.xmpp.makeIqSet(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is None or result is False or result['type'] == 'error': return False
@@ -236,7 +236,7 @@ class xep_0060(base.base_plugin):
 		pubsub.append(retract)
 		iq = self.xmpp.makeIqSet(pubsub)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is None or result is False or result['type'] == 'error': return False
@@ -287,7 +287,7 @@ class xep_0060(base.base_plugin):
 		pubsub.append(affs)
 		iq = self.xmpp.makeIqSet(pubsub)
 		iq.attrib['to'] = ps_jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq['id']
 		result = iq.send()
 		if result is None or result is False or result['type'] == 'error':
diff --git a/sleekxmpp/plugins/xep_0092.py b/sleekxmpp/plugins/xep_0092.py
index ca02c4a8..c9b418ff 100644
--- a/sleekxmpp/plugins/xep_0092.py
+++ b/sleekxmpp/plugins/xep_0092.py
@@ -42,7 +42,7 @@ class xep_0092(base.base_plugin):
 		query = ET.Element('{jabber:iq:version}query')
 		iq.append(query)
 		iq.attrib['to'] = jid
-		iq.attrib['from'] = self.xmpp.fulljid
+		iq.attrib['from'] = self.xmpp.boundjid.full
 		id = iq.get('id')
 		result = iq.send()
 		if result and result is not None and result.get('type', 'error') != 'error':
-- 
cgit v1.2.3


From 988a90a17644a943704811ac6cd28e27fcc00066 Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Thu, 16 Dec 2010 16:18:49 -0500
Subject: Added MUC invite handler to XEP-0045 plugin.

Originally contributed by damium/romeira, with some
modifications.

Also, converted tabs to spaces to prepare for future cleanup.
---
 sleekxmpp/plugins/xep_0045.py | 648 +++++++++++++++++++++---------------------
 1 file changed, 328 insertions(+), 320 deletions(-)

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/xep_0045.py b/sleekxmpp/plugins/xep_0045.py
index e7f8c7ec..d5fbf003 100644
--- a/sleekxmpp/plugins/xep_0045.py
+++ b/sleekxmpp/plugins/xep_0045.py
@@ -20,325 +20,333 @@ log = logging.getLogger(__name__)
 
 
 class MUCPresence(ElementBase):
-	name = 'x'
-	namespace = 'http://jabber.org/protocol/muc#user'
-	plugin_attrib = 'muc'
-	interfaces = set(('affiliation', 'role', 'jid', 'nick', 'room'))
-	affiliations = set(('', ))
-	roles = set(('', ))
-
-	def getXMLItem(self):
-		item = self.xml.find('{http://jabber.org/protocol/muc#user}item')
-		if item is None:
-			item = ET.Element('{http://jabber.org/protocol/muc#user}item')
-			self.xml.append(item)
-		return item
-
-	def getAffiliation(self):
-		#TODO if no affilation, set it to the default and return default
-		item = self.getXMLItem()
-		return item.get('affiliation', '')
-
-	def setAffiliation(self, value):
-		item = self.getXMLItem()
-		#TODO check for valid affiliation
-		item.attrib['affiliation'] = value
-		return self
-
-	def delAffiliation(self):
-		item = self.getXMLItem()
-		#TODO set default affiliation
-		if 'affiliation' in item.attrib: del item.attrib['affiliation']
-		return self
-
-	def getJid(self):
-		item = self.getXMLItem()
-		return JID(item.get('jid', ''))
-
-	def setJid(self, value):
-		item = self.getXMLItem()
-		if not isinstance(value, str):
-			value = str(value)
-		item.attrib['jid'] = value
-		return self
-
-	def delJid(self):
-		item = self.getXMLItem()
-		if 'jid' in item.attrib: del item.attrib['jid']
-		return self
-
-	def getRole(self):
-		item = self.getXMLItem()
-		#TODO get default role, set default role if none
-		return item.get('role', '')
-
-	def setRole(self, value):
-		item = self.getXMLItem()
-		#TODO check for valid role
-		item.attrib['role'] = value
-		return self
-
-	def delRole(self):
-		item = self.getXMLItem()
-		#TODO set default role
-		if 'role' in item.attrib: del item.attrib['role']
-		return self
-
-	def getNick(self):
-		return self.parent()['from'].resource
-
-	def getRoom(self):
-		return self.parent()['from'].bare
-
-	def setNick(self, value):
-		log.warning("Cannot set nick through mucpresence plugin.")
-		return self
-
-	def setRoom(self, value):
-		log.warning("Cannot set room through mucpresence plugin.")
-		return self
-
-	def delNick(self):
-		log.warning("Cannot delete nick through mucpresence plugin.")
-		return self
-
-	def delRoom(self):
-		log.warning("Cannot delete room through mucpresence plugin.")
-		return self
+    name = 'x'
+    namespace = 'http://jabber.org/protocol/muc#user'
+    plugin_attrib = 'muc'
+    interfaces = set(('affiliation', 'role', 'jid', 'nick', 'room'))
+    affiliations = set(('', ))
+    roles = set(('', ))
+
+    def getXMLItem(self):
+        item = self.xml.find('{http://jabber.org/protocol/muc#user}item')
+        if item is None:
+            item = ET.Element('{http://jabber.org/protocol/muc#user}item')
+            self.xml.append(item)
+        return item
+
+    def getAffiliation(self):
+        #TODO if no affilation, set it to the default and return default
+        item = self.getXMLItem()
+        return item.get('affiliation', '')
+
+    def setAffiliation(self, value):
+        item = self.getXMLItem()
+        #TODO check for valid affiliation
+        item.attrib['affiliation'] = value
+        return self
+
+    def delAffiliation(self):
+        item = self.getXMLItem()
+        #TODO set default affiliation
+        if 'affiliation' in item.attrib: del item.attrib['affiliation']
+        return self
+
+    def getJid(self):
+        item = self.getXMLItem()
+        return JID(item.get('jid', ''))
+
+    def setJid(self, value):
+        item = self.getXMLItem()
+        if not isinstance(value, str):
+            value = str(value)
+        item.attrib['jid'] = value
+        return self
+
+    def delJid(self):
+        item = self.getXMLItem()
+        if 'jid' in item.attrib: del item.attrib['jid']
+        return self
+
+    def getRole(self):
+        item = self.getXMLItem()
+        #TODO get default role, set default role if none
+        return item.get('role', '')
+
+    def setRole(self, value):
+        item = self.getXMLItem()
+        #TODO check for valid role
+        item.attrib['role'] = value
+        return self
+
+    def delRole(self):
+        item = self.getXMLItem()
+        #TODO set default role
+        if 'role' in item.attrib: del item.attrib['role']
+        return self
+
+    def getNick(self):
+        return self.parent()['from'].resource
+
+    def getRoom(self):
+        return self.parent()['from'].bare
+
+    def setNick(self, value):
+        log.warning("Cannot set nick through mucpresence plugin.")
+        return self
+
+    def setRoom(self, value):
+        log.warning("Cannot set room through mucpresence plugin.")
+        return self
+
+    def delNick(self):
+        log.warning("Cannot delete nick through mucpresence plugin.")
+        return self
+
+    def delRoom(self):
+        log.warning("Cannot delete room through mucpresence plugin.")
+        return self
 
 class xep_0045(base.base_plugin):
-	"""
-	Impliments XEP-0045 Multi User Chat
-	"""
-
-	def plugin_init(self):
-		self.rooms = {}
-		self.ourNicks = {}
-		self.xep = '0045'
-		self.description = 'Multi User Chat'
-		# load MUC support in presence stanzas
-		registerStanzaPlugin(Presence, MUCPresence)
-		self.xmpp.registerHandler(Callback('MUCPresence', MatchXMLMask("<presence xmlns='%s' />" % self.xmpp.default_ns), self.handle_groupchat_presence))
-		self.xmpp.registerHandler(Callback('MUCMessage', MatchXMLMask("<message xmlns='%s' type='groupchat'><body/></message>" % self.xmpp.default_ns), self.handle_groupchat_message))
-		self.xmpp.registerHandler(Callback('MUCSubject', MatchXMLMask("<message xmlns='%s' type='groupchat'><subject/></message>" % self.xmpp.default_ns), self.handle_groupchat_subject))
-
-	def handle_groupchat_presence(self, pr):
-		""" Handle a presence in a muc.
-		"""
-		got_offline = False
-		got_online = False
-		if pr['muc']['room'] not in self.rooms.keys():
-			return
-		entry = pr['muc'].getStanzaValues()
-		entry['show'] = pr['show']
-		entry['status'] = pr['status']
-		if pr['type'] == 'unavailable':
-			if entry['nick'] in self.rooms[entry['room']]:
-				del self.rooms[entry['room']][entry['nick']]
-			got_offline = True
-		else:
-			if entry['nick'] not in self.rooms[entry['room']]:
-				got_online = True
-			self.rooms[entry['room']][entry['nick']] = entry
-		log.debug("MUC presence from %s/%s : %s" % (entry['room'],entry['nick'], entry))
-		self.xmpp.event("groupchat_presence", pr)
-		self.xmpp.event("muc::%s::presence" % entry['room'], pr)
-		if got_offline:
-			self.xmpp.event("muc::%s::got_offline" % entry['room'], pr)
-		if got_online:
-			self.xmpp.event("muc::%s::got_online" % entry['room'], pr)
-
-	def handle_groupchat_message(self, msg):
-		""" Handle a message event in a muc.
-		"""
-		self.xmpp.event('groupchat_message', msg)
-		self.xmpp.event("muc::%s::message" % msg['from'].bare, msg)
-
-	def handle_groupchat_subject(self, msg):
-		""" Handle a message coming from a muc indicating
-		a change of subject (or announcing it when joining the room)
-		"""
-		self.xmpp.event('groupchat_subject', msg)
-
-	def jidInRoom(self, room, jid):
-		for nick in self.rooms[room]:
-			entry = self.rooms[room][nick]
-			if entry is not None and entry['jid'].full == jid:
-				return True
-		return False
-
-	def getNick(self, room, jid):
-		for nick in self.rooms[room]:
-			entry = self.rooms[room][nick]
-			if entry is not None and entry['jid'].full == jid:
-				return nick
-
-	def getRoomForm(self, room, ifrom=None):
-		iq = self.xmpp.makeIqGet()
-		iq['to'] = room
-		if ifrom is not None:
-			iq['from'] = ifrom
-		query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
-		iq.append(query)
-		result = iq.send()
-		if result['type'] == 'error':
-			return False
-		xform = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
-		if xform is None: return False
-		form = self.xmpp.plugin['old_0004'].buildForm(xform)
-		return form
-
-	def configureRoom(self, room, form=None, ifrom=None):
-		if form is None:
-			form = self.getRoomForm(room, ifrom=ifrom)
-			#form = self.xmpp.plugin['old_0004'].makeForm(ftype='submit')
-			#form.addField('FORM_TYPE', value='http://jabber.org/protocol/muc#roomconfig')
-		iq = self.xmpp.makeIqSet()
-		iq['to'] = room
-		if ifrom is not None:
-			iq['from'] = ifrom
-		query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
-		form = form.getXML('submit')
-		query.append(form)
-		iq.append(query)
-		result = iq.send()
-		if result['type'] == 'error':
-			return False
-		return True
-
-	def joinMUC(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None):
-		""" Join the specified room, requesting 'maxhistory' lines of history.
-		"""
-		stanza = self.xmpp.makePresence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow)
-		x = ET.Element('{http://jabber.org/protocol/muc}x')
-		if password:
-			passelement = ET.Element('password')
-			passelement.text = password
-			x.append(passelement)
-		if maxhistory:
-			history = ET.Element('history')
-			if maxhistory ==  "0":
-				history.attrib['maxchars'] = maxhistory
-			else:
-				history.attrib['maxstanzas'] = maxhistory
-			x.append(history)
-		stanza.append(x)
-		if not wait:
-			self.xmpp.send(stanza)
-		else:
-			#wait for our own room presence back
-			expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)})
-			self.xmpp.send(stanza, expect)
-		self.rooms[room] = {}
-		self.ourNicks[room] = nick
-
-	def destroy(self, room, reason='', altroom = '', ifrom=None):
-		iq = self.xmpp.makeIqSet()
-		if ifrom is not None:
-			iq['from'] = ifrom
-		iq['to'] = room
-		query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
-		destroy = ET.Element('destroy')
-		if altroom:
-			destroy.attrib['jid'] = altroom
-		xreason = ET.Element('reason')
-		xreason.text = reason
-		destroy.append(xreason)
-		query.append(destroy)
-		iq.append(query)
-		r = iq.send()
-		if r is False or r['type'] == 'error':
-			return False
-		return True
-
-	def setAffiliation(self, room, jid=None, nick=None, affiliation='member'):
-		""" Change room affiliation."""
-		if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'):
-			raise TypeError
-		query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
-		if nick is not None:
-			item = ET.Element('item', {'affiliation':affiliation, 'nick':nick})
-		else:
-			item = ET.Element('item', {'affiliation':affiliation, 'jid':jid})
-		query.append(item)
-		iq = self.xmpp.makeIqSet(query)
-		iq['to'] = room
-		result = iq.send()
-		if result is False or result['type'] != 'result':
-			raise ValueError
-		return True
-
-	def invite(self, room, jid, reason=''):
-		""" Invite a jid to a room."""
-		msg = self.xmpp.makeMessage(room)
-		msg['from'] = self.xmpp.boundjid.bare
-		x = ET.Element('{http://jabber.org/protocol/muc#user}x')
-		invite = ET.Element('{http://jabber.org/protocol/muc#user}invite', {'to': jid})
-		if reason:
-			rxml = ET.Element('reason')
-			rxml.text = reason
-			invite.append(rxml)
-		x.append(invite)
-		msg.append(x)
-		self.xmpp.send(msg)
-
-	def leaveMUC(self, room, nick, msg=''):
-		""" Leave the specified room.
-		"""
-		if msg:
-			self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick), pstatus=msg)
-		else:
-			self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick))
-		del self.rooms[room]
-
-	def getRoomConfig(self, room):
-		iq = self.xmpp.makeIqGet('http://jabber.org/protocol/muc#owner')
-		iq['to'] = room
-		iq['from'] = self.xmpp.boundjid.bare
-		result = iq.send()
-		if result is None or result['type'] != 'result':
-			raise ValueError
-		form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
-		if form is None:
-			raise ValueError
-		return self.xmpp.plugin['xep_0004'].buildForm(form)
-
-	def cancelConfig(self, room):
-		query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
-		x = ET.Element('{jabber:x:data}x', type='cancel')
-		query.append(x)
-		iq = self.xmpp.makeIqSet(query)
-		iq.send()
-
-	def setRoomConfig(self, room, config):
-		query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
-		x = config.getXML('submit')
-		query.append(x)
-		iq = self.xmpp.makeIqSet(query)
-		iq['to'] = room
-		iq['from'] = self.xmpp.boundjid.bare
-		iq.send()
-
-	def getJoinedRooms(self):
-		return self.rooms.keys()
-
-	def getOurJidInRoom(self, roomJid):
-		""" Return the jid we're using in a room.
-		"""
-		return "%s/%s" % (roomJid, self.ourNicks[roomJid])
-
-	def getJidProperty(self, room, nick, jidProperty):
-		""" Get the property of a nick in a room, such as its 'jid' or 'affiliation'
-			If not found, return None.
-		"""
-		if room in self.rooms and nick in self.rooms[room] and jidProperty in self.rooms[room][nick]:
-			return self.rooms[room][nick][jidProperty]
-		else:
-			return None
-
-	def getRoster(self, room):
-		""" Get the list of nicks in a room.
-		"""
-		if room not in self.rooms.keys():
-			return None
-		return self.rooms[room].keys()
+    """
+    Implements XEP-0045 Multi User Chat
+    """
+
+    def plugin_init(self):
+        self.rooms = {}
+        self.ourNicks = {}
+        self.xep = '0045'
+        self.description = 'Multi User Chat'
+        # load MUC support in presence stanzas
+        registerStanzaPlugin(Presence, MUCPresence)
+        self.xmpp.registerHandler(Callback('MUCPresence', MatchXMLMask("<presence xmlns='%s' />" % self.xmpp.default_ns), self.handle_groupchat_presence))
+        self.xmpp.registerHandler(Callback('MUCMessage', MatchXMLMask("<message xmlns='%s' type='groupchat'><body/></message>" % self.xmpp.default_ns), self.handle_groupchat_message))
+        self.xmpp.registerHandler(Callback('MUCSubject', MatchXMLMask("<message xmlns='%s' type='groupchat'><subject/></message>" % self.xmpp.default_ns), self.handle_groupchat_subject))
+        self.xmpp.registerHandler(Callback('MUCInvite', MatchXPath("{%s}message/{http://jabber.org/protocol/muc#user}x/invite" % self.xmpp.default_ns), self.handle_groupchat_invite))
+
+    def handle_groupchat_invite(self, inv):
+        """ Handle an invite into a muc.
+        """
+        logging.debug("MUC invite to %s from %s: %s" % (inv['from'], inv["from"], inv))
+        if inv['from'] not in self.rooms.keys():
+            self.xmpp.event("groupchat_invite", inv)
+
+    def handle_groupchat_presence(self, pr):
+        """ Handle a presence in a muc.
+        """
+        got_offline = False
+        got_online = False
+        if pr['muc']['room'] not in self.rooms.keys():
+            return
+        entry = pr['muc'].getStanzaValues()
+        entry['show'] = pr['show']
+        entry['status'] = pr['status']
+        if pr['type'] == 'unavailable':
+            if entry['nick'] in self.rooms[entry['room']]:
+                del self.rooms[entry['room']][entry['nick']]
+            got_offline = True
+        else:
+            if entry['nick'] not in self.rooms[entry['room']]:
+                got_online = True
+            self.rooms[entry['room']][entry['nick']] = entry
+        log.debug("MUC presence from %s/%s : %s" % (entry['room'],entry['nick'], entry))
+        self.xmpp.event("groupchat_presence", pr)
+        self.xmpp.event("muc::%s::presence" % entry['room'], pr)
+        if got_offline:
+            self.xmpp.event("muc::%s::got_offline" % entry['room'], pr)
+        if got_online:
+            self.xmpp.event("muc::%s::got_online" % entry['room'], pr)
+
+    def handle_groupchat_message(self, msg):
+        """ Handle a message event in a muc.
+        """
+        self.xmpp.event('groupchat_message', msg)
+        self.xmpp.event("muc::%s::message" % msg['from'].bare, msg)
+
+    def handle_groupchat_subject(self, msg):
+        """ Handle a message coming from a muc indicating
+        a change of subject (or announcing it when joining the room)
+        """
+        self.xmpp.event('groupchat_subject', msg)
+
+    def jidInRoom(self, room, jid):
+        for nick in self.rooms[room]:
+            entry = self.rooms[room][nick]
+            if entry is not None and entry['jid'].full == jid:
+                return True
+        return False
+
+    def getNick(self, room, jid):
+        for nick in self.rooms[room]:
+            entry = self.rooms[room][nick]
+            if entry is not None and entry['jid'].full == jid:
+                return nick
+
+    def getRoomForm(self, room, ifrom=None):
+        iq = self.xmpp.makeIqGet()
+        iq['to'] = room
+        if ifrom is not None:
+            iq['from'] = ifrom
+        query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
+        iq.append(query)
+        result = iq.send()
+        if result['type'] == 'error':
+            return False
+        xform = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
+        if xform is None: return False
+        form = self.xmpp.plugin['old_0004'].buildForm(xform)
+        return form
+
+    def configureRoom(self, room, form=None, ifrom=None):
+        if form is None:
+            form = self.getRoomForm(room, ifrom=ifrom)
+            #form = self.xmpp.plugin['old_0004'].makeForm(ftype='submit')
+            #form.addField('FORM_TYPE', value='http://jabber.org/protocol/muc#roomconfig')
+        iq = self.xmpp.makeIqSet()
+        iq['to'] = room
+        if ifrom is not None:
+            iq['from'] = ifrom
+        query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
+        form = form.getXML('submit')
+        query.append(form)
+        iq.append(query)
+        result = iq.send()
+        if result['type'] == 'error':
+            return False
+        return True
+
+    def joinMUC(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None):
+        """ Join the specified room, requesting 'maxhistory' lines of history.
+        """
+        stanza = self.xmpp.makePresence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow)
+        x = ET.Element('{http://jabber.org/protocol/muc}x')
+        if password:
+            passelement = ET.Element('password')
+            passelement.text = password
+            x.append(passelement)
+        if maxhistory:
+            history = ET.Element('history')
+            if maxhistory ==  "0":
+                history.attrib['maxchars'] = maxhistory
+            else:
+                history.attrib['maxstanzas'] = maxhistory
+            x.append(history)
+        stanza.append(x)
+        if not wait:
+            self.xmpp.send(stanza)
+        else:
+            #wait for our own room presence back
+            expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)})
+            self.xmpp.send(stanza, expect)
+        self.rooms[room] = {}
+        self.ourNicks[room] = nick
+
+    def destroy(self, room, reason='', altroom = '', ifrom=None):
+        iq = self.xmpp.makeIqSet()
+        if ifrom is not None:
+            iq['from'] = ifrom
+        iq['to'] = room
+        query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
+        destroy = ET.Element('destroy')
+        if altroom:
+            destroy.attrib['jid'] = altroom
+        xreason = ET.Element('reason')
+        xreason.text = reason
+        destroy.append(xreason)
+        query.append(destroy)
+        iq.append(query)
+        r = iq.send()
+        if r is False or r['type'] == 'error':
+            return False
+        return True
+
+    def setAffiliation(self, room, jid=None, nick=None, affiliation='member'):
+        """ Change room affiliation."""
+        if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'):
+            raise TypeError
+        query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
+        if nick is not None:
+            item = ET.Element('item', {'affiliation':affiliation, 'nick':nick})
+        else:
+            item = ET.Element('item', {'affiliation':affiliation, 'jid':jid})
+        query.append(item)
+        iq = self.xmpp.makeIqSet(query)
+        iq['to'] = room
+        result = iq.send()
+        if result is False or result['type'] != 'result':
+            raise ValueError
+        return True
+
+    def invite(self, room, jid, reason=''):
+        """ Invite a jid to a room."""
+        msg = self.xmpp.makeMessage(room)
+        msg['from'] = self.xmpp.boundjid.bare
+        x = ET.Element('{http://jabber.org/protocol/muc#user}x')
+        invite = ET.Element('{http://jabber.org/protocol/muc#user}invite', {'to': jid})
+        if reason:
+            rxml = ET.Element('reason')
+            rxml.text = reason
+            invite.append(rxml)
+        x.append(invite)
+        msg.append(x)
+        self.xmpp.send(msg)
+
+    def leaveMUC(self, room, nick, msg=''):
+        """ Leave the specified room.
+        """
+        if msg:
+            self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick), pstatus=msg)
+        else:
+            self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick))
+        del self.rooms[room]
+
+    def getRoomConfig(self, room):
+        iq = self.xmpp.makeIqGet('http://jabber.org/protocol/muc#owner')
+        iq['to'] = room
+        iq['from'] = self.xmpp.boundjid.bare
+        result = iq.send()
+        if result is None or result['type'] != 'result':
+            raise ValueError
+        form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x')
+        if form is None:
+            raise ValueError
+        return self.xmpp.plugin['xep_0004'].buildForm(form)
+
+    def cancelConfig(self, room):
+        query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
+        x = ET.Element('{jabber:x:data}x', type='cancel')
+        query.append(x)
+        iq = self.xmpp.makeIqSet(query)
+        iq.send()
+
+    def setRoomConfig(self, room, config):
+        query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
+        x = config.getXML('submit')
+        query.append(x)
+        iq = self.xmpp.makeIqSet(query)
+        iq['to'] = room
+        iq['from'] = self.xmpp.boundjid.bare
+        iq.send()
+
+    def getJoinedRooms(self):
+        return self.rooms.keys()
+
+    def getOurJidInRoom(self, roomJid):
+        """ Return the jid we're using in a room.
+        """
+        return "%s/%s" % (roomJid, self.ourNicks[roomJid])
+
+    def getJidProperty(self, room, nick, jidProperty):
+        """ Get the property of a nick in a room, such as its 'jid' or 'affiliation'
+            If not found, return None.
+        """
+        if room in self.rooms and nick in self.rooms[room] and jidProperty in self.rooms[room][nick]:
+            return self.rooms[room][nick][jidProperty]
+        else:
+            return None
+
+    def getRoster(self, room):
+        """ Get the list of nicks in a room.
+        """
+        if room not in self.rooms.keys():
+            return None
+        return self.rooms[room].keys()
-- 
cgit v1.2.3


From 62b190d0ff61541d35f3b9f30c44a58ce20af014 Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Thu, 16 Dec 2010 18:14:33 -0500
Subject: Fixed specifying 'from' values in XEP-0045 plugin.

Methods now accept either an ifrom or mfrom parameter
to specify a 'from' value. Client connections should not
need to use these, but component connections must use them.
---
 sleekxmpp/plugins/xep_0045.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/xep_0045.py b/sleekxmpp/plugins/xep_0045.py
index d5fbf003..feec70db 100644
--- a/sleekxmpp/plugins/xep_0045.py
+++ b/sleekxmpp/plugins/xep_0045.py
@@ -276,10 +276,10 @@ class xep_0045(base.base_plugin):
             raise ValueError
         return True
 
-    def invite(self, room, jid, reason=''):
+    def invite(self, room, jid, reason='', mfrom=''):
         """ Invite a jid to a room."""
         msg = self.xmpp.makeMessage(room)
-        msg['from'] = self.xmpp.boundjid.bare
+        msg['from'] = mfrom
         x = ET.Element('{http://jabber.org/protocol/muc#user}x')
         invite = ET.Element('{http://jabber.org/protocol/muc#user}invite', {'to': jid})
         if reason:
@@ -299,10 +299,10 @@ class xep_0045(base.base_plugin):
             self.xmpp.sendPresence(pshow='unavailable', pto="%s/%s" % (room, nick))
         del self.rooms[room]
 
-    def getRoomConfig(self, room):
+    def getRoomConfig(self, room, ifrom=''):
         iq = self.xmpp.makeIqGet('http://jabber.org/protocol/muc#owner')
         iq['to'] = room
-        iq['from'] = self.xmpp.boundjid.bare
+        iq['from'] = ifrom
         result = iq.send()
         if result is None or result['type'] != 'result':
             raise ValueError
@@ -318,13 +318,13 @@ class xep_0045(base.base_plugin):
         iq = self.xmpp.makeIqSet(query)
         iq.send()
 
-    def setRoomConfig(self, room, config):
+    def setRoomConfig(self, room, config, ifrom=''):
         query = ET.Element('{http://jabber.org/protocol/muc#owner}query')
         x = config.getXML('submit')
         query.append(x)
         iq = self.xmpp.makeIqSet(query)
         iq['to'] = room
-        iq['from'] = self.xmpp.boundjid.bare
+        iq['from'] = ifrom
         iq.send()
 
     def getJoinedRooms(self):
-- 
cgit v1.2.3


From 0ea014fe41c131629a39b785d23c3e6b7112644a Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Thu, 16 Dec 2010 18:29:56 -0500
Subject: Updated the list of plugins in sleekxmpp.plugins.__init__

---
 sleekxmpp/plugins/__init__.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'sleekxmpp/plugins')

diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py
index 427ab04e..d27937ae 100644
--- a/sleekxmpp/plugins/__init__.py
+++ b/sleekxmpp/plugins/__init__.py
@@ -5,6 +5,6 @@
 
     See the file LICENSE for copying permission.
 """
-__all__ = ['xep_0004', 'xep_0012', 'xep_0030', 'xep_0033', 'xep_0045',
-           'xep_0050', 'xep_0085', 'xep_0092', 'xep_0199', 'gmail_notify',
-           'xep_0060', 'xep_0202']
+__all__ = ['xep_0004', 'xep_0009', 'xep_0012', 'xep_0030', 'xep_0033',
+           'xep_0045', 'xep_0050', 'xep_0060', 'xep_0085', 'xep_0086',
+           'xep_0092', 'xep_0128', 'xep_0199', 'xep_0202', 'gmail_notify']
-- 
cgit v1.2.3