From 378a42889fb59bba9f638203d914707040bfcad9 Mon Sep 17 00:00:00 2001
From: Lance Stout <lancestout@gmail.com>
Date: Mon, 18 Jun 2012 22:03:03 -0700
Subject: [PATCH] Simplify and update XEP-0033 to latest plugin format.

---
 setup.py                                |   1 +
 sleekxmpp/plugins/xep_0033.py           | 169 ------------------------
 sleekxmpp/plugins/xep_0033/__init__.py  |  20 +++
 sleekxmpp/plugins/xep_0033/addresses.py |  32 +++++
 sleekxmpp/plugins/xep_0033/stanza.py    | 131 ++++++++++++++++++
 5 files changed, 184 insertions(+), 169 deletions(-)
 delete mode 100644 sleekxmpp/plugins/xep_0033.py
 create mode 100644 sleekxmpp/plugins/xep_0033/__init__.py
 create mode 100644 sleekxmpp/plugins/xep_0033/addresses.py
 create mode 100644 sleekxmpp/plugins/xep_0033/stanza.py

diff --git a/setup.py b/setup.py
index de89021b..759dc235 100755
--- a/setup.py
+++ b/setup.py
@@ -61,6 +61,7 @@ packages     = [ 'sleekxmpp',
                  'sleekxmpp/plugins/xep_0027',
                  'sleekxmpp/plugins/xep_0030',
                  'sleekxmpp/plugins/xep_0030/stanza',
+                 'sleekxmpp/plugins/xep_0033',
                  'sleekxmpp/plugins/xep_0047',
                  'sleekxmpp/plugins/xep_0050',
                  'sleekxmpp/plugins/xep_0054',
diff --git a/sleekxmpp/plugins/xep_0033.py b/sleekxmpp/plugins/xep_0033.py
deleted file mode 100644
index 9276b807..00000000
--- a/sleekxmpp/plugins/xep_0033.py
+++ /dev/null
@@ -1,169 +0,0 @@
-"""
-    SleekXMPP: The Sleek XMPP Library
-    Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
-    This file is part of SleekXMPP.
-
-    See the file LICENSE for copying permission.
-"""
-
-import logging
-from sleekxmpp import Message
-from sleekxmpp.xmlstream.handler.callback import Callback
-from sleekxmpp.xmlstream.matcher.xpath import MatchXPath
-from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase, ET, JID
-from sleekxmpp.plugins import BasePlugin, register_plugin
-
-
-class Addresses(ElementBase):
-    namespace = 'http://jabber.org/protocol/address'
-    name = 'addresses'
-    plugin_attrib = 'addresses'
-    interfaces = set(('addresses', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'))
-
-    def addAddress(self, atype='to', jid='', node='', uri='', desc='', delivered=False):
-        address = Address(parent=self)
-        address['type'] = atype
-        address['jid'] = jid
-        address['node'] = node
-        address['uri'] = uri
-        address['desc'] = desc
-        address['delivered'] = delivered
-        return address
-
-    def getAddresses(self, atype=None):
-        addresses = []
-        for addrXML in self.xml.findall('{%s}address' % Address.namespace):
-            # ElementTree 1.2.6 does not support [@attr='value'] in findall
-            if atype is None or addrXML.attrib.get('type') == atype:
-                addresses.append(Address(xml=addrXML, parent=None))
-        return addresses
-
-    def setAddresses(self, addresses, set_type=None):
-        self.delAddresses(set_type)
-        for addr in addresses:
-            addr = dict(addr)
-            if 'lang' in addr:
-                del addr['lang']
-            # Remap 'type' to 'atype' to match the add method
-            if set_type is not None:
-                addr['type'] = set_type
-            curr_type = addr.get('type', None)
-            if curr_type is not None:
-                del addr['type']
-                addr['atype'] = curr_type
-            self.addAddress(**addr)
-
-    def delAddresses(self, atype=None):
-        if atype is None:
-            return
-        for addrXML in self.xml.findall('{%s}address' % Address.namespace):
-            # ElementTree 1.2.6 does not support [@attr='value'] in findall
-            if addrXML.attrib.get('type') == atype:
-                self.xml.remove(addrXML)
-
-    # --------------------------------------------------------------
-
-    def delBcc(self):
-        self.delAddresses('bcc')
-
-    def delCc(self):
-        self.delAddresses('cc')
-
-    def delNoreply(self):
-        self.delAddresses('noreply')
-
-    def delReplyroom(self):
-        self.delAddresses('replyroom')
-
-    def delReplyto(self):
-        self.delAddresses('replyto')
-
-    def delTo(self):
-        self.delAddresses('to')
-
-    # --------------------------------------------------------------
-
-    def getBcc(self):
-        return self.getAddresses('bcc')
-
-    def getCc(self):
-        return self.getAddresses('cc')
-
-    def getNoreply(self):
-        return self.getAddresses('noreply')
-
-    def getReplyroom(self):
-        return self.getAddresses('replyroom')
-
-    def getReplyto(self):
-        return self.getAddresses('replyto')
-
-    def getTo(self):
-        return self.getAddresses('to')
-
-    # --------------------------------------------------------------
-
-    def setBcc(self, addresses):
-        self.setAddresses(addresses, 'bcc')
-
-    def setCc(self, addresses):
-        self.setAddresses(addresses, 'cc')
-
-    def setNoreply(self, addresses):
-        self.setAddresses(addresses, 'noreply')
-
-    def setReplyroom(self, addresses):
-        self.setAddresses(addresses, 'replyroom')
-
-    def setReplyto(self, addresses):
-        self.setAddresses(addresses, 'replyto')
-
-    def setTo(self, addresses):
-        self.setAddresses(addresses, 'to')
-
-
-class Address(ElementBase):
-    namespace = 'http://jabber.org/protocol/address'
-    name = 'address'
-    plugin_attrib = 'address'
-    interfaces = set(('delivered', 'desc', 'jid', 'node', 'type', 'uri'))
-    address_types = set(('bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'))
-
-    def getDelivered(self):
-        return self.xml.attrib.get('delivered', False)
-
-    def setDelivered(self, delivered):
-        if delivered:
-            self.xml.attrib['delivered'] = "true"
-        else:
-            del self['delivered']
-
-    def setUri(self, uri):
-        if uri:
-            del self['jid']
-            del self['node']
-            self.xml.attrib['uri'] = uri
-        elif 'uri' in self.xml.attrib:
-            del self.xml.attrib['uri']
-
-
-class XEP_0033(BasePlugin):
-
-    """
-    XEP-0033: Extended Stanza Addressing
-    """
-
-    name = 'xep_0033'
-    description = 'XEP-0033: Extended Stanza Addressing'
-    dependencies = set(['xep_0033'])
-
-    def plugin_init(self):
-        self.xep = '0033'
-
-        register_stanza_plugin(Message, Addresses)
-
-        self.xmpp.plugin['xep_0030'].add_feature(Addresses.namespace)
-
-
-xep_0033 = XEP_0033
-register_plugin(XEP_0033)
diff --git a/sleekxmpp/plugins/xep_0033/__init__.py b/sleekxmpp/plugins/xep_0033/__init__.py
new file mode 100644
index 00000000..ba8152c4
--- /dev/null
+++ b/sleekxmpp/plugins/xep_0033/__init__.py
@@ -0,0 +1,20 @@
+"""
+    SleekXMPP: The Sleek XMPP Library
+    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
+    This file is part of SleekXMPP.
+
+    See the file LICENSE for copying permission.
+"""
+
+from sleekxmpp.plugins.base import register_plugin
+
+from sleekxmpp.plugins.xep_0033 import stanza
+from sleekxmpp.plugins.xep_0033.stanza import Addresses, Address
+from sleekxmpp.plugins.xep_0033.addresses import XEP_0033
+
+
+register_plugin(XEP_0033)
+
+# Retain some backwards compatibility
+xep_0033 = XEP_0033
+Addresses.addAddress = Addresses.add_address
diff --git a/sleekxmpp/plugins/xep_0033/addresses.py b/sleekxmpp/plugins/xep_0033/addresses.py
new file mode 100644
index 00000000..78b9fbb5
--- /dev/null
+++ b/sleekxmpp/plugins/xep_0033/addresses.py
@@ -0,0 +1,32 @@
+"""
+    SleekXMPP: The Sleek XMPP Library
+    Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
+    This file is part of SleekXMPP.
+
+    See the file LICENSE for copying permission.
+"""
+
+import logging
+
+from sleekxmpp import Message, Presence
+from sleekxmpp.xmlstream import register_stanza_plugin
+from sleekxmpp.plugins import BasePlugin
+from sleekxmpp.plugins.xep_0033 import stanza, Addresses
+
+
+class XEP_0033(BasePlugin):
+
+    """
+    XEP-0033: Extended Stanza Addressing
+    """
+
+    name = 'xep_0033'
+    description = 'XEP-0033: Extended Stanza Addressing'
+    dependencies = set(['xep_0030'])
+    stanza = stanza
+
+    def plugin_init(self):
+        self.xmpp['xep_0030'].add_feature(Addresses.namespace)
+
+        register_stanza_plugin(Message, Addresses)
+        register_stanza_plugin(Presence, Addresses)
diff --git a/sleekxmpp/plugins/xep_0033/stanza.py b/sleekxmpp/plugins/xep_0033/stanza.py
new file mode 100644
index 00000000..501f6fa6
--- /dev/null
+++ b/sleekxmpp/plugins/xep_0033/stanza.py
@@ -0,0 +1,131 @@
+"""
+    SleekXMPP: The Sleek XMPP Library
+    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
+    This file is part of SleekXMPP.
+
+    See the file LICENSE for copying permission.
+"""
+
+from sleekxmpp.xmlstream import JID, ElementBase, ET, register_stanza_plugin
+
+
+class Addresses(ElementBase):
+
+    name = 'addresses'
+    namespace = 'http://jabber.org/protocol/address'
+    plugin_attrib = 'addresses'
+    interfaces = set()
+
+    def add_address(self, atype='to', jid='', node='', uri='', 
+                          desc='', delivered=False):
+        addr = Address(parent=self)
+        addr['type'] = atype
+        addr['jid'] = jid
+        addr['node'] = node
+        addr['uri'] = uri
+        addr['desc'] = desc
+        addr['delivered'] = delivered
+
+        return addr
+
+    # Additional methods for manipulating sets of addresses
+    # based on type are generated below.
+
+
+class Address(ElementBase):
+
+    name = 'address'
+    namespace = 'http://jabber.org/protocol/address'
+    plugin_attrib = 'address'
+    interfaces = set(['type', 'jid', 'node', 'uri', 'desc', 'delivered'])
+
+    address_types = set(('bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'))
+
+    def get_jid(self):
+        return JID(self._get_attr('jid'))
+
+    def set_jid(self, value):
+        self._set_attr('jid', str(value))
+
+    def get_delivered(self):
+        value = self._get_attr('delivered', False)
+        return value and value.lower() in ('true', '1')
+
+    def set_delivered(self, delivered):
+        if delivered:
+            self._set_attr('delivered', 'true')
+        else:
+            del self['delivered']
+
+    def set_uri(self, uri):
+        if uri:
+            del self['jid']
+            del self['node']
+            self._set_attr('uri', uri)
+        else:
+            self._del_attr('uri')
+
+
+# =====================================================================
+# Auto-generate address type filters for the Addresses class.
+
+def _addr_filter(atype):
+    def _type_filter(addr):
+        if isinstance(addr, Address):
+            if atype == 'all' or addr['type'] == atype:
+                return True
+        return False
+    return _type_filter
+
+
+def _build_methods(atype):
+
+    def get_multi(self):
+        return list(filter(_addr_filter(atype), self))
+
+    def set_multi(self, value):
+        del self[atype]
+        for addr in value:
+
+            # Support assigning dictionary versions of addresses
+            # instead of full Address objects.
+            if not isinstance(addr, Address):
+                if atype != 'all':
+                    addr['type'] = atype
+                elif 'atype' in addr and 'type' not in addr:
+                    addr['type'] = addr['atype']
+                addrObj = Address()
+                addrObj.values = addr
+                addr = addrObj
+
+            self.append(addr)
+
+    def del_multi(self):
+        res = list(filter(_addr_filter(atype), self))
+        for addr in res:
+            self.iterables.remove(addr)
+            self.xml.remove(addr.xml)
+
+    return get_multi, set_multi, del_multi
+
+
+for atype in ('all', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'):
+    get_multi, set_multi, del_multi = _build_methods(atype)
+
+    Addresses.interfaces.add(atype)
+    setattr(Addresses, "get_%s" % atype, get_multi)
+    setattr(Addresses, "set_%s" % atype, set_multi)
+    setattr(Addresses, "del_%s" % atype, del_multi)
+    
+    # To retain backwards compatibility:
+    setattr(Addresses, "get%s" % atype.title(), get_multi)
+    setattr(Addresses, "set%s" % atype.title(), set_multi)
+    setattr(Addresses, "del%s" % atype.title(), del_multi)
+    if atype == 'all':
+        Addresses.interfaces.add('addresses')
+        setattr(Addresses, "getAddresses", get_multi)
+        setattr(Addresses, "setAddresses", set_multi)
+        setattr(Addresses, "delAddresses", del_multi)
+
+
+register_stanza_plugin(Addresses, Address, iterable=True)