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)