diff options
Diffstat (limited to 'sleekxmpp/plugins')
| -rw-r--r-- | sleekxmpp/plugins/__init__.py | 10 | ||||
| -rw-r--r-- | sleekxmpp/plugins/base.py | 26 | ||||
| -rw-r--r-- | sleekxmpp/plugins/gmail_notify.py | 149 | ||||
| -rw-r--r-- | sleekxmpp/plugins/jobs.py | 50 | ||||
| -rw-r--r-- | sleekxmpp/plugins/old_0004.py | 421 | ||||
| -rw-r--r-- | sleekxmpp/plugins/stanza_pubsub.py | 555 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0004.py | 395 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0009.py | 277 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0012.py | 118 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0030.py | 329 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0033.py | 161 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0045.py | 344 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0050.py | 133 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0060.py | 313 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0078.py | 72 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0085.py | 104 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0086.py | 49 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0092.py | 56 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0128.py | 51 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0199.py | 63 | ||||
| -rw-r--r-- | sleekxmpp/plugins/xep_0202.py | 115 |
21 files changed, 0 insertions, 3791 deletions
diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py deleted file mode 100644 index 427ab04..0000000 --- a/sleekxmpp/plugins/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - 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'] diff --git a/sleekxmpp/plugins/base.py b/sleekxmpp/plugins/base.py deleted file mode 100644 index 254397e..0000000 --- a/sleekxmpp/plugins/base.py +++ /dev/null @@ -1,26 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" - - -class base_plugin(object): - - def __init__(self, xmpp, config): - self.xep = 'base' - self.description = 'Base Plugin' - self.xmpp = xmpp - self.config = config - self.post_inited = False - self.enable = config.get('enable', True) - if self.enable: - self.plugin_init() - - def plugin_init(self): - pass - - def post_init(self): - self.post_inited = True diff --git a/sleekxmpp/plugins/gmail_notify.py b/sleekxmpp/plugins/gmail_notify.py deleted file mode 100644 index 7e888b9..0000000 --- a/sleekxmpp/plugins/gmail_notify.py +++ /dev/null @@ -1,149 +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 . import base -from .. xmlstream.handler.callback import Callback -from .. xmlstream.matcher.xpath import MatchXPath -from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID -from .. stanza.iq import Iq - - -log = logging.getLogger(__name__) - - -class GmailQuery(ElementBase): - namespace = 'google:mail:notify' - name = 'query' - plugin_attrib = 'gmail' - interfaces = set(('newer-than-time', 'newer-than-tid', 'q', 'search')) - - def getSearch(self): - return self['q'] - - def setSearch(self, search): - self['q'] = search - - def delSearch(self): - del self['q'] - - -class MailBox(ElementBase): - namespace = 'google:mail:notify' - name = 'mailbox' - plugin_attrib = 'mailbox' - interfaces = set(('result-time', 'total-matched', 'total-estimate', - 'url', 'threads', 'matched', 'estimate')) - - def getThreads(self): - threads = [] - for threadXML in self.xml.findall('{%s}%s' % (MailThread.namespace, - MailThread.name)): - threads.append(MailThread(xml=threadXML, parent=None)) - return threads - - def getMatched(self): - return self['total-matched'] - - def getEstimate(self): - return self['total-estimate'] == '1' - - -class MailThread(ElementBase): - namespace = 'google:mail:notify' - name = 'mail-thread-info' - plugin_attrib = 'thread' - interfaces = set(('tid', 'participation', 'messages', 'date', - 'senders', 'url', 'labels', 'subject', 'snippet')) - sub_interfaces = set(('labels', 'subject', 'snippet')) - - def getSenders(self): - senders = [] - sendersXML = self.xml.find('{%s}senders' % self.namespace) - if sendersXML is not None: - for senderXML in sendersXML.findall('{%s}sender' % self.namespace): - senders.append(MailSender(xml=senderXML, parent=None)) - return senders - - -class MailSender(ElementBase): - namespace = 'google:mail:notify' - name = 'sender' - plugin_attrib = 'sender' - interfaces = set(('address', 'name', 'originator', 'unread')) - - def getOriginator(self): - return self.xml.attrib.get('originator', '0') == '1' - - def getUnread(self): - return self.xml.attrib.get('unread', '0') == '1' - - -class NewMail(ElementBase): - namespace = 'google:mail:notify' - name = 'new-mail' - plugin_attrib = 'new-mail' - - -class gmail_notify(base.base_plugin): - """ - Google Talk: Gmail Notifications - """ - - def plugin_init(self): - self.description = 'Google Talk: Gmail Notifications' - - self.xmpp.registerHandler( - Callback('Gmail Result', - MatchXPath('{%s}iq/{%s}%s' % (self.xmpp.default_ns, - MailBox.namespace, - MailBox.name)), - self.handle_gmail)) - - self.xmpp.registerHandler( - Callback('Gmail New Mail', - MatchXPath('{%s}iq/{%s}%s' % (self.xmpp.default_ns, - NewMail.namespace, - NewMail.name)), - self.handle_new_mail)) - - registerStanzaPlugin(Iq, GmailQuery) - registerStanzaPlugin(Iq, MailBox) - registerStanzaPlugin(Iq, NewMail) - - self.last_result_time = None - - def handle_gmail(self, iq): - mailbox = iq['mailbox'] - approx = ' approximately' if mailbox['estimated'] else '' - log.info('Gmail: Received%s %s emails' % (approx, mailbox['total-matched'])) - self.last_result_time = mailbox['result-time'] - self.xmpp.event('gmail_messages', iq) - - def handle_new_mail(self, iq): - log.info("Gmail: New emails received!") - self.xmpp.event('gmail_notify') - self.checkEmail() - - def getEmail(self, query=None): - return self.search(query) - - def checkEmail(self): - return self.search(newer=self.last_result_time) - - def search(self, query=None, newer=None): - if query is None: - log.info("Gmail: Checking for new emails") - else: - log.info('Gmail: Searching for emails matching: "%s"' % query) - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['to'] = self.xmpp.jid - iq['gmail']['q'] = query - iq['gmail']['newer-than-time'] = newer - return iq.send() diff --git a/sleekxmpp/plugins/jobs.py b/sleekxmpp/plugins/jobs.py deleted file mode 100644 index 0b93d62..0000000 --- a/sleekxmpp/plugins/jobs.py +++ /dev/null @@ -1,50 +0,0 @@ -from . import base -import logging -from xml.etree import cElementTree as ET -import types - - -log = logging.getLogger(__name__) - - -class jobs(base.base_plugin): - def plugin_init(self): - self.xep = 'pubsubjob' - self.description = "Job distribution over Pubsub" - - def post_init(self): - pass - #TODO add event - - def createJobNode(self, host, jid, node, config=None): - pass - - def createJob(self, host, node, jobid=None, payload=None): - return self.xmpp.plugin['xep_0060'].setItem(host, node, ((jobid, payload),)) - - def claimJob(self, host, node, jobid, ifrom=None): - return self._setState(host, node, jobid, ET.Element('{http://andyet.net/protocol/pubsubjob}claimed')) - - def unclaimJob(self, host, node, jobid): - return self._setState(host, node, jobid, ET.Element('{http://andyet.net/protocol/pubsubjob}unclaimed')) - - def finishJob(self, host, node, jobid, payload=None): - finished = ET.Element('{http://andyet.net/protocol/pubsubjob}finished') - if payload is not None: - finished.append(payload) - return self._setState(host, node, jobid, finished) - - def _setState(self, host, node, jobid, state, ifrom=None): - iq = self.xmpp.Iq() - iq['to'] = host - if ifrom: iq['from'] = ifrom - iq['type'] = 'set' - iq['psstate']['node'] = node - iq['psstate']['item'] = jobid - iq['psstate']['payload'] = state - result = iq.send() - if result is None or type(result) == types.BooleanType 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/old_0004.py b/sleekxmpp/plugins/old_0004.py deleted file mode 100644 index ade3d68..0000000 --- a/sleekxmpp/plugins/old_0004.py +++ /dev/null @@ -1,421 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" -from . import base -import log -from xml.etree import cElementTree as ET -import copy -import logging -#TODO support item groups and results - - -log = logging.getLogger(__name__) - - -class old_0004(base.base_plugin): - - def plugin_init(self): - self.xep = '0004' - self.description = '*Deprecated Data Forms' - self.xmpp.add_handler("<message><x xmlns='jabber:x:data' /></message>", self.handler_message_xform, name='Old Message Form') - - def post_init(self): - base.base_plugin.post_init(self) - self.xmpp.plugin['xep_0030'].add_feature('jabber:x:data') - log.warning("This implementation of XEP-0004 is deprecated.") - - def handler_message_xform(self, xml): - object = self.handle_form(xml) - self.xmpp.event("message_form", object) - - def handler_presence_xform(self, xml): - object = self.handle_form(xml) - self.xmpp.event("presence_form", object) - - def handle_form(self, xml): - xmlform = xml.find('{jabber:x:data}x') - object = self.buildForm(xmlform) - self.xmpp.event("message_xform", object) - return object - - def buildForm(self, xml): - form = Form(ftype=xml.attrib['type']) - form.fromXML(xml) - return form - - def makeForm(self, ftype='form', title='', instructions=''): - return Form(self.xmpp, ftype, title, instructions) - -class FieldContainer(object): - def __init__(self, stanza = 'form'): - self.fields = [] - self.field = {} - self.stanza = stanza - - def addField(self, var, ftype='text-single', label='', desc='', required=False, value=None): - self.field[var] = FormField(var, ftype, label, desc, required, value) - self.fields.append(self.field[var]) - return self.field[var] - - def buildField(self, xml): - self.field[xml.get('var', '__unnamed__')] = FormField(xml.get('var', '__unnamed__'), xml.get('type', 'text-single')) - self.fields.append(self.field[xml.get('var', '__unnamed__')]) - self.field[xml.get('var', '__unnamed__')].buildField(xml) - - def buildContainer(self, xml): - self.stanza = xml.tag - for field in xml.findall('{jabber:x:data}field'): - self.buildField(field) - - def getXML(self, ftype): - container = ET.Element(self.stanza) - for field in self.fields: - container.append(field.getXML(ftype)) - return container - -class Form(FieldContainer): - types = ('form', 'submit', 'cancel', 'result') - def __init__(self, xmpp=None, ftype='form', title='', instructions=''): - if not ftype in self.types: - raise ValueError("Invalid Form Type") - FieldContainer.__init__(self) - self.xmpp = xmpp - self.type = ftype - self.title = title - self.instructions = instructions - self.reported = [] - self.items = [] - - def merge(self, form2): - form1 = Form(ftype=self.type) - form1.fromXML(self.getXML(self.type)) - for field in form2.fields: - if not field.var in form1.field: - form1.addField(field.var, field.type, field.label, field.desc, field.required, field.value) - else: - form1.field[field.var].value = field.value - for option, label in field.options: - if (option, label) not in form1.field[field.var].options: - form1.fields[field.var].addOption(option, label) - return form1 - - def copy(self): - newform = Form(ftype=self.type) - newform.fromXML(self.getXML(self.type)) - return newform - - def update(self, form): - values = form.getValues() - for var in values: - if var in self.fields: - self.fields[var].setValue(self.fields[var]) - - def getValues(self): - result = {} - for field in self.fields: - value = field.value - if len(value) == 1: - value = value[0] - result[field.var] = value - return result - - def setValues(self, values={}): - for field in values: - if field in self.field: - if isinstance(values[field], list) or isinstance(values[field], tuple): - for value in values[field]: - self.field[field].setValue(value) - else: - self.field[field].setValue(values[field]) - - def fromXML(self, xml): - self.buildForm(xml) - - def addItem(self): - newitem = FieldContainer('item') - self.items.append(newitem) - return newitem - - def buildItem(self, xml): - newitem = self.addItem() - newitem.buildContainer(xml) - - def addReported(self): - reported = FieldContainer('reported') - self.reported.append(reported) - return reported - - def buildReported(self, xml): - reported = self.addReported() - reported.buildContainer(xml) - - def setTitle(self, title): - self.title = title - - def setInstructions(self, instructions): - self.instructions = instructions - - def setType(self, ftype): - self.type = ftype - - def getXMLMessage(self, to): - msg = self.xmpp.makeMessage(to) - msg.append(self.getXML()) - return msg - - def buildForm(self, xml): - self.type = xml.get('type', 'form') - if xml.find('{jabber:x:data}title') is not None: - self.setTitle(xml.find('{jabber:x:data}title').text) - if xml.find('{jabber:x:data}instructions') is not None: - self.setInstructions(xml.find('{jabber:x:data}instructions').text) - for field in xml.findall('{jabber:x:data}field'): - self.buildField(field) - for reported in xml.findall('{jabber:x:data}reported'): - self.buildReported(reported) - for item in xml.findall('{jabber:x:data}item'): - self.buildItem(item) - - #def getXML(self, tostring = False): - def getXML(self, ftype=None): - if ftype: - self.type = ftype - form = ET.Element('{jabber:x:data}x') - form.attrib['type'] = self.type - if self.title and self.type in ('form', 'result'): - title = ET.Element('{jabber:x:data}title') - title.text = self.title - form.append(title) - if self.instructions and self.type == 'form': - instructions = ET.Element('{jabber:x:data}instructions') - instructions.text = self.instructions - form.append(instructions) - for field in self.fields: - form.append(field.getXML(self.type)) - for reported in self.reported: - form.append(reported.getXML('{jabber:x:data}reported')) - for item in self.items: - form.append(item.getXML(self.type)) - #if tostring: - # form = self.xmpp.tostring(form) - return form - - def getXHTML(self): - form = ET.Element('{http://www.w3.org/1999/xhtml}form') - if self.title: - title = ET.Element('h2') - title.text = self.title - form.append(title) - if self.instructions: - instructions = ET.Element('p') - instructions.text = self.instructions - form.append(instructions) - for field in self.fields: - form.append(field.getXHTML()) - for field in self.reported: - form.append(field.getXHTML()) - for field in self.items: - form.append(field.getXHTML()) - return form - - - def makeSubmit(self): - self.setType('submit') - -class FormField(object): - types = ('boolean', 'fixed', 'hidden', 'jid-multi', 'jid-single', 'list-multi', 'list-single', 'text-multi', 'text-private', 'text-single') - listtypes = ('jid-multi', 'jid-single', 'list-multi', 'list-single') - lbtypes = ('fixed', 'text-multi') - def __init__(self, var, ftype='text-single', label='', desc='', required=False, value=None): - if not ftype in self.types: - raise ValueError("Invalid Field Type") - self.type = ftype - self.var = var - self.label = label - self.desc = desc - self.options = [] - self.required = False - self.value = [] - if self.type in self.listtypes: - self.islist = True - else: - self.islist = False - if self.type in self.lbtypes: - self.islinebreak = True - else: - self.islinebreak = False - if value: - self.setValue(value) - - def addOption(self, value, label): - if self.islist: - self.options.append((value, label)) - else: - raise ValueError("Cannot add options to non-list type field.") - - def setTrue(self): - if self.type == 'boolean': - self.value = [True] - - def setFalse(self): - if self.type == 'boolean': - self.value = [False] - - def require(self): - self.required = True - - def setDescription(self, desc): - self.desc = desc - - def setValue(self, value): - if self.type == 'boolean': - if value in ('1', 1, True, 'true', 'True', 'yes'): - value = True - else: - value = False - if self.islinebreak and value is not None: - self.value += value.split('\n') - else: - if len(self.value) and (not self.islist or self.type == 'list-single'): - self.value = [value] - else: - self.value.append(value) - - def delValue(self, value): - if type(self.value) == type([]): - try: - idx = self.value.index(value) - if idx != -1: - self.value.pop(idx) - except ValueError: - pass - else: - self.value = '' - - def setAnswer(self, value): - self.setValue(value) - - def buildField(self, xml): - self.type = xml.get('type', 'text-single') - self.label = xml.get('label', '') - for option in xml.findall('{jabber:x:data}option'): - self.addOption(option.find('{jabber:x:data}value').text, option.get('label', '')) - for value in xml.findall('{jabber:x:data}value'): - self.setValue(value.text) - if xml.find('{jabber:x:data}required') is not None: - self.require() - if xml.find('{jabber:x:data}desc') is not None: - self.setDescription(xml.find('{jabber:x:data}desc').text) - - def getXML(self, ftype): - field = ET.Element('{jabber:x:data}field') - if ftype != 'result': - field.attrib['type'] = self.type - if self.type != 'fixed': - if self.var: - field.attrib['var'] = self.var - if self.label: - field.attrib['label'] = self.label - if ftype == 'form': - for option in self.options: - optionxml = ET.Element('{jabber:x:data}option') - optionxml.attrib['label'] = option[1] - optionval = ET.Element('{jabber:x:data}value') - optionval.text = option[0] - optionxml.append(optionval) - field.append(optionxml) - if self.required: - required = ET.Element('{jabber:x:data}required') - field.append(required) - if self.desc: - desc = ET.Element('{jabber:x:data}desc') - desc.text = self.desc - field.append(desc) - for value in self.value: - valuexml = ET.Element('{jabber:x:data}value') - if value is True or value is False: - if value: - valuexml.text = '1' - else: - valuexml.text = '0' - else: - valuexml.text = value - field.append(valuexml) - return field - - def getXHTML(self): - field = ET.Element('div', {'class': 'xmpp-xforms-%s' % self.type}) - if self.label: - label = ET.Element('p') - label.text = "%s: " % self.label - else: - label = ET.Element('p') - label.text = "%s: " % self.var - field.append(label) - if self.type == 'boolean': - formf = ET.Element('input', {'type': 'checkbox', 'name': self.var}) - if len(self.value) and self.value[0] in (True, 'true', '1'): - formf.attrib['checked'] = 'checked' - elif self.type == 'fixed': - formf = ET.Element('p') - try: - formf.text = ', '.join(self.value) - except: - pass - field.append(formf) - formf = ET.Element('input', {'type': 'hidden', 'name': self.var}) - try: - formf.text = ', '.join(self.value) - except: - pass - elif self.type == 'hidden': - formf = ET.Element('input', {'type': 'hidden', 'name': self.var}) - try: - formf.text = ', '.join(self.value) - except: - pass - elif self.type in ('jid-multi', 'list-multi'): - formf = ET.Element('select', {'name': self.var}) - for option in self.options: - optf = ET.Element('option', {'value': option[0], 'multiple': 'multiple'}) - optf.text = option[1] - if option[1] in self.value: - optf.attrib['selected'] = 'selected' - formf.append(option) - elif self.type in ('jid-single', 'text-single'): - formf = ET.Element('input', {'type': 'text', 'name': self.var}) - try: - formf.attrib['value'] = ', '.join(self.value) - except: - pass - elif self.type == 'list-single': - formf = ET.Element('select', {'name': self.var}) - for option in self.options: - optf = ET.Element('option', {'value': option[0]}) - optf.text = option[1] - if not optf.text: - optf.text = option[0] - if option[1] in self.value: - optf.attrib['selected'] = 'selected' - formf.append(optf) - elif self.type == 'text-multi': - formf = ET.Element('textarea', {'name': self.var}) - try: - formf.text = ', '.join(self.value) - except: - pass - if not formf.text: - formf.text = ' ' - elif self.type == 'text-private': - formf = ET.Element('input', {'type': 'password', 'name': self.var}) - try: - formf.attrib['value'] = ', '.join(self.value) - except: - pass - label.append(formf) - return field - diff --git a/sleekxmpp/plugins/stanza_pubsub.py b/sleekxmpp/plugins/stanza_pubsub.py deleted file mode 100644 index 2d809a3..0000000 --- a/sleekxmpp/plugins/stanza_pubsub.py +++ /dev/null @@ -1,555 +0,0 @@ -from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID -from .. stanza.iq import Iq -from .. stanza.message import Message -from .. basexmpp import basexmpp -from .. xmlstream.xmlstream import XMLStream -import logging -from . import xep_0004 - - -class PubsubState(ElementBase): - namespace = 'http://jabber.org/protocol/psstate' - name = 'state' - plugin_attrib = 'psstate' - interfaces = set(('node', 'item', 'payload')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setPayload(self, value): - self.xml.append(value) - - def getPayload(self): - childs = self.xml.getchildren() - if len(childs) > 0: - return childs[0] - - def delPayload(self): - for child in self.xml.getchildren(): - self.xml.remove(child) - -registerStanzaPlugin(Iq, PubsubState) - -class PubsubStateEvent(ElementBase): - namespace = 'http://jabber.org/protocol/psstate#event' - name = 'event' - plugin_attrib = 'psstate_event' - intefaces = set(tuple()) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Message, PubsubStateEvent) -registerStanzaPlugin(PubsubStateEvent, PubsubState) - -class Pubsub(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'pubsub' - plugin_attrib = 'pubsub' - interfaces = set(tuple()) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Iq, Pubsub) - -class PubsubOwner(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'pubsub' - plugin_attrib = 'pubsub_owner' - interfaces = set(tuple()) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Iq, PubsubOwner) - -class Affiliation(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'affiliation' - plugin_attrib = name - interfaces = set(('node', 'affiliation')) - plugin_attrib_map = {} - plugin_tag_map = {} - -class Affiliations(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'affiliations' - plugin_attrib = 'affiliations' - interfaces = set(tuple()) - plugin_attrib_map = {} - plugin_tag_map = {} - subitem = (Affiliation,) - - def append(self, affiliation): - if not isinstance(affiliation, Affiliation): - raise TypeError - self.xml.append(affiliation.xml) - return self.iterables.append(affiliation) - -registerStanzaPlugin(Pubsub, Affiliations) - - -class Subscription(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'subscription' - plugin_attrib = name - interfaces = set(('jid', 'node', 'subscription', 'subid')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setjid(self, value): - self._setattr('jid', str(value)) - - def getjid(self): - return jid(self._getattr('jid')) - -registerStanzaPlugin(Pubsub, Subscription) - -class Subscriptions(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'subscriptions' - plugin_attrib = 'subscriptions' - interfaces = set(tuple()) - plugin_attrib_map = {} - plugin_tag_map = {} - subitem = (Subscription,) - -registerStanzaPlugin(Pubsub, Subscriptions) - -class OptionalSetting(object): - interfaces = set(('required',)) - - def setRequired(self, value): - value = bool(value) - if value and not self['required']: - self.xml.append(ET.Element("{%s}required" % self.namespace)) - elif not value and self['required']: - self.delRequired() - - def getRequired(self): - required = self.xml.find("{%s}required" % self.namespace) - if required is not None: - return True - else: - return False - - def delRequired(self): - required = self.xml.find("{%s}required" % self.namespace) - if required is not None: - self.xml.remove(required) - - -class SubscribeOptions(ElementBase, OptionalSetting): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'subscribe-options' - plugin_attrib = 'suboptions' - plugin_attrib_map = {} - plugin_tag_map = {} - interfaces = set(('required',)) - -registerStanzaPlugin(Subscription, SubscribeOptions) - -class Item(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'item' - plugin_attrib = name - interfaces = set(('id', 'payload')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setPayload(self, value): - self.xml.append(value) - - def getPayload(self): - childs = self.xml.getchildren() - if len(childs) > 0: - return childs[0] - - def delPayload(self): - for child in self.xml.getchildren(): - self.xml.remove(child) - -class Items(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'items' - plugin_attrib = 'items' - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - subitem = (Item,) - -registerStanzaPlugin(Pubsub, Items) - -class Create(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'create' - plugin_attrib = name - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Pubsub, Create) - -#class Default(ElementBase): -# namespace = 'http://jabber.org/protocol/pubsub' -# name = 'default' -# plugin_attrib = name -# interfaces = set(('node', 'type')) -# plugin_attrib_map = {} -# plugin_tag_map = {} -# -# def getType(self): -# t = self._getAttr('type') -# if not t: t == 'leaf' -# return t -# -#registerStanzaPlugin(Pubsub, Default) - -class Publish(Items): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'publish' - plugin_attrib = name - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - subitem = (Item,) - -registerStanzaPlugin(Pubsub, Publish) - -class Retract(Items): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'retract' - plugin_attrib = name - interfaces = set(('node', 'notify')) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Pubsub, Retract) - -class Unsubscribe(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'unsubscribe' - plugin_attrib = name - interfaces = set(('node', 'jid')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setJid(self, value): - self._setAttr('jid', str(value)) - - def getJid(self): - return JID(self._getAttr('jid')) - -class Subscribe(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'subscribe' - plugin_attrib = name - interfaces = set(('node', 'jid')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setJid(self, value): - self._setAttr('jid', str(value)) - - def getJid(self): - return JID(self._getAttr('jid')) - -registerStanzaPlugin(Pubsub, Subscribe) - -class Configure(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'configure' - plugin_attrib = name - interfaces = set(('node', 'type')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def getType(self): - t = self._getAttr('type') - if not t: t == 'leaf' - return t - -registerStanzaPlugin(Pubsub, Configure) -registerStanzaPlugin(Configure, xep_0004.Form) - -class DefaultConfig(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'default' - plugin_attrib = 'default' - interfaces = set(('node', 'type', 'config')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def __init__(self, *args, **kwargs): - ElementBase.__init__(self, *args, **kwargs) - - def getType(self): - t = self._getAttr('type') - if not t: t = 'leaf' - return t - - def getConfig(self): - return self['form'] - - def setConfig(self, value): - self['form'].setStanzaValues(value.getStanzaValues()) - return self - -registerStanzaPlugin(PubsubOwner, DefaultConfig) -registerStanzaPlugin(DefaultConfig, xep_0004.Form) - -class Options(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub' - name = 'options' - plugin_attrib = 'options' - interfaces = set(('jid', 'node', 'options')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def __init__(self, *args, **kwargs): - ElementBase.__init__(self, *args, **kwargs) - - def getOptions(self): - config = self.xml.find('{jabber:x:data}x') - form = xep_0004.Form() - if config is not None: - form.fromXML(config) - return form - - def setOptions(self, value): - self.xml.append(value.getXML()) - return self - - def delOptions(self): - config = self.xml.find('{jabber:x:data}x') - self.xml.remove(config) - - def setJid(self, value): - self._setAttr('jid', str(value)) - - def getJid(self): - return JID(self._getAttr('jid')) - -registerStanzaPlugin(Pubsub, Options) -registerStanzaPlugin(Subscribe, Options) - -class OwnerAffiliations(Affiliations): - namespace = 'http://jabber.org/protocol/pubsub#owner' - interfaces = set(('node')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def append(self, affiliation): - if not isinstance(affiliation, OwnerAffiliation): - raise TypeError - self.xml.append(affiliation.xml) - return self.affiliations.append(affiliation) - -registerStanzaPlugin(PubsubOwner, OwnerAffiliations) - -class OwnerAffiliation(Affiliation): - namespace = 'http://jabber.org/protocol/pubsub#owner' - interfaces = set(('affiliation', 'jid')) - plugin_attrib_map = {} - plugin_tag_map = {} - -class OwnerConfigure(Configure): - namespace = 'http://jabber.org/protocol/pubsub#owner' - interfaces = set(('node', 'config')) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(PubsubOwner, OwnerConfigure) - -class OwnerDefault(OwnerConfigure): - namespace = 'http://jabber.org/protocol/pubsub#owner' - interfaces = set(('node', 'config')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def getConfig(self): - return self['form'] - - def setConfig(self, value): - self['form'].setStanzaValues(value.getStanzaValues()) - return self - -registerStanzaPlugin(PubsubOwner, OwnerDefault) -registerStanzaPlugin(OwnerDefault, xep_0004.Form) - -class OwnerDelete(ElementBase, OptionalSetting): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'delete' - plugin_attrib = 'delete' - plugin_attrib_map = {} - plugin_tag_map = {} - interfaces = set(('node',)) - -registerStanzaPlugin(PubsubOwner, OwnerDelete) - -class OwnerPurge(ElementBase, OptionalSetting): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'purge' - plugin_attrib = name - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(PubsubOwner, OwnerPurge) - -class OwnerRedirect(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'redirect' - plugin_attrib = name - interfaces = set(('node', 'jid')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setJid(self, value): - self._setAttr('jid', str(value)) - - def getJid(self): - return JID(self._getAttr('jid')) - -registerStanzaPlugin(OwnerDelete, OwnerRedirect) - -class OwnerSubscriptions(Subscriptions): - namespace = 'http://jabber.org/protocol/pubsub#owner' - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - - def append(self, subscription): - if not isinstance(subscription, OwnerSubscription): - raise TypeError - self.xml.append(subscription.xml) - return self.subscriptions.append(subscription) - -registerStanzaPlugin(PubsubOwner, OwnerSubscriptions) - -class OwnerSubscription(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#owner' - name = 'subscription' - plugin_attrib = name - interfaces = set(('jid', 'subscription')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setJid(self, value): - self._setAttr('jid', str(value)) - - def getJid(self): - return JID(self._getAttr('from')) - -class Event(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'event' - plugin_attrib = 'pubsub_event' - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Message, Event) - -class EventItem(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'item' - plugin_attrib = 'item' - interfaces = set(('id', 'payload')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setPayload(self, value): - self.xml.append(value) - - def getPayload(self): - childs = self.xml.getchildren() - if len(childs) > 0: - return childs[0] - - def delPayload(self): - for child in self.xml.getchildren(): - self.xml.remove(child) - - -class EventRetract(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'retract' - plugin_attrib = 'retract' - interfaces = set(('id',)) - plugin_attrib_map = {} - plugin_tag_map = {} - -class EventItems(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'items' - plugin_attrib = 'items' - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - subitem = (EventItem, EventRetract) - -registerStanzaPlugin(Event, EventItems) - -class EventCollection(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'collection' - plugin_attrib = name - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Event, EventCollection) - -class EventAssociate(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'associate' - plugin_attrib = name - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(EventCollection, EventAssociate) - -class EventDisassociate(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'disassociate' - plugin_attrib = name - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(EventCollection, EventDisassociate) - -class EventConfiguration(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'configuration' - plugin_attrib = name - interfaces = set(('node', 'config')) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Event, EventConfiguration) -registerStanzaPlugin(EventConfiguration, xep_0004.Form) - -class EventPurge(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'purge' - plugin_attrib = name - interfaces = set(('node',)) - plugin_attrib_map = {} - plugin_tag_map = {} - -registerStanzaPlugin(Event, EventPurge) - -class EventSubscription(ElementBase): - namespace = 'http://jabber.org/protocol/pubsub#event' - name = 'subscription' - plugin_attrib = name - interfaces = set(('node','expiry', 'jid', 'subid', 'subscription')) - plugin_attrib_map = {} - plugin_tag_map = {} - - def setJid(self, value): - self._setAttr('jid', str(value)) - - def getJid(self): - return JID(self._getAttr('jid')) - -registerStanzaPlugin(Event, EventSubscription) diff --git a/sleekxmpp/plugins/xep_0004.py b/sleekxmpp/plugins/xep_0004.py deleted file mode 100644 index b8b7ebf..0000000 --- a/sleekxmpp/plugins/xep_0004.py +++ /dev/null @@ -1,395 +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 -import copy -from . import base -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__) - - -class Form(ElementBase): - namespace = 'jabber:x:data' - name = 'x' - plugin_attrib = 'form' - interfaces = set(('fields', 'instructions', 'items', 'reported', 'title', 'type', 'values')) - sub_interfaces = set(('title',)) - form_types = set(('cancel', 'form', 'result', 'submit')) - - def __init__(self, *args, **kwargs): - title = None - if 'title' in kwargs: - title = kwargs['title'] - del kwargs['title'] - ElementBase.__init__(self, *args, **kwargs) - if title is not None: - self['title'] = title - self.field = FieldAccessor(self) - - def setup(self, xml=None): - if ElementBase.setup(self, xml): #if we had to generate xml - self['type'] = 'form' - - def addField(self, var='', ftype=None, label='', desc='', required=False, value=None, options=None, **kwargs): - kwtype = kwargs.get('type', None) - if kwtype is None: - kwtype = ftype - - field = FormField(parent=self) - field['var'] = var - field['type'] = kwtype - field['label'] = label - field['desc'] = desc - field['required'] = required - field['value'] = value - if options is not None: - field['options'] = options - return field - - def getXML(self, type='submit'): - log.warning("Form.getXML() is deprecated API compatibility with plugins/old_0004.py") - return self.xml - - def fromXML(self, xml): - log.warning("Form.fromXML() is deprecated API compatibility with plugins/old_0004.py") - n = Form(xml=xml) - return n - - def addItem(self, values): - itemXML = ET.Element('{%s}item' % self.namespace) - self.xml.append(itemXML) - reported_vars = self['reported'].keys() - for var in reported_vars: - fieldXML = ET.Element('{%s}field' % FormField.namespace) - itemXML.append(fieldXML) - field = FormField(xml=fieldXML) - field['var'] = var - field['value'] = values.get(var, None) - - def addReported(self, var, ftype=None, label='', desc='', **kwargs): - kwtype = kwargs.get('type', None) - if kwtype is None: - kwtype = ftype - reported = self.xml.find('{%s}reported' % self.namespace) - if reported is None: - reported = ET.Element('{%s}reported' % self.namespace) - self.xml.append(reported) - fieldXML = ET.Element('{%s}field' % FormField.namespace) - reported.append(fieldXML) - field = FormField(xml=fieldXML) - field['var'] = var - field['type'] = kwtype - field['label'] = label - field['desc'] = desc - return field - - def cancel(self): - self['type'] = 'cancel' - - def delFields(self): - fieldsXML = self.xml.findall('{%s}field' % FormField.namespace) - for fieldXML in fieldsXML: - self.xml.remove(fieldXML) - - def delInstructions(self): - instsXML = self.xml.findall('{%s}instructions') - for instXML in instsXML: - self.xml.remove(instXML) - - def delItems(self): - itemsXML = self.xml.find('{%s}item' % self.namespace) - for itemXML in itemsXML: - self.xml.remove(itemXML) - - def delReported(self): - reportedXML = self.xml.find('{%s}reported' % self.namespace) - if reportedXML is not None: - self.xml.remove(reportedXML) - - def getFields(self, use_dict=False): - fields = {} if use_dict else [] - fieldsXML = self.xml.findall('{%s}field' % FormField.namespace) - for fieldXML in fieldsXML: - field = FormField(xml=fieldXML) - if use_dict: - fields[field['var']] = field - else: - fields.append((field['var'], field)) - return fields - - def getInstructions(self): - instructions = '' - instsXML = self.xml.findall('{%s}instructions' % self.namespace) - return "\n".join([instXML.text for instXML in instsXML]) - - def getItems(self): - items = [] - itemsXML = self.xml.findall('{%s}item' % self.namespace) - for itemXML in itemsXML: - item = {} - fieldsXML = itemXML.findall('{%s}field' % FormField.namespace) - for fieldXML in fieldsXML: - field = FormField(xml=fieldXML) - item[field['var']] = field['value'] - items.append(item) - return items - - def getReported(self): - fields = {} - fieldsXML = self.xml.findall('{%s}reported/{%s}field' % (self.namespace, - FormField.namespace)) - for fieldXML in fieldsXML: - field = FormField(xml=fieldXML) - fields[field['var']] = field - return fields - - def getValues(self): - values = {} - fields = self.getFields(use_dict=True) - for var in fields: - values[var] = fields[var]['value'] - return values - - def reply(self): - if self['type'] == 'form': - self['type'] = 'submit' - elif self['type'] == 'submit': - self['type'] = 'result' - - def setFields(self, fields, default=None): - del self['fields'] - for field_data in fields: - var = field_data[0] - field = field_data[1] - field['var'] = var - - self.addField(**field) - - def setInstructions(self, instructions): - del self['instructions'] - if instructions in [None, '']: - return - instructions = instructions.split('\n') - for instruction in instructions: - inst = ET.Element('{%s}instructions' % self.namespace) - inst.text = instruction - self.xml.append(inst) - - def setItems(self, items): - for item in items: - self.addItem(item) - - def setReported(self, reported, default=None): - for var in reported: - field = reported[var] - field['var'] = var - self.addReported(var, **field) - - def setValues(self, values): - fields = self.getFields(use_dict=True) - for field in values: - fields[field]['value'] = values[field] - - def merge(self, other): - new = copy.copy(self) - if type(other) == types.DictType: - new.setValues(other) - return new - nfields = new.getFields(use_dict=True) - ofields = other.getFields(use_dict=True) - nfields.update(ofields) - new.setFields([(x, nfields[x]) for x in nfields]) - return new - -class FieldAccessor(object): - def __init__(self, form): - self.form = form - - def __getitem__(self, key): - return self.form.getFields(use_dict=True)[key] - - def __contains__(self, key): - return key in self.form.getFields(use_dict=True) - - def has_key(self, key): - return key in self.form.getFields(use_dict=True) - - -class FormField(ElementBase): - namespace = 'jabber:x:data' - name = 'field' - plugin_attrib = 'field' - interfaces = set(('answer', 'desc', 'required', 'value', 'options', 'label', 'type', 'var')) - sub_interfaces = set(('desc',)) - field_types = set(('boolean', 'fixed', 'hidden', 'jid-multi', 'jid-single', 'list-multi', - 'list-single', 'text-multi', 'text-private', 'text-single')) - multi_value_types = set(('hidden', 'jid-multi', 'list-multi', 'text-multi')) - multi_line_types = set(('hidden', 'text-multi')) - option_types = set(('list-multi', 'list-single')) - true_values = set((True, '1', 'true')) - - def addOption(self, label='', value=''): - if self['type'] in self.option_types: - opt = FieldOption(parent=self) - opt['label'] = label - opt['value'] = value - else: - raise ValueError("Cannot add options to a %s field." % self['type']) - - def delOptions(self): - optsXML = self.xml.findall('{%s}option' % self.namespace) - for optXML in optsXML: - self.xml.remove(optXML) - - def delRequired(self): - reqXML = self.xml.find('{%s}required' % self.namespace) - if reqXML is not None: - self.xml.remove(reqXML) - - def delValue(self): - valsXML = self.xml.findall('{%s}value' % self.namespace) - for valXML in valsXML: - self.xml.remove(valXML) - - def getAnswer(self): - return self.getValue() - - def getOptions(self): - options = [] - optsXML = self.xml.findall('{%s}option' % self.namespace) - for optXML in optsXML: - opt = FieldOption(xml=optXML) - options.append({'label': opt['label'], 'value':opt['value']}) - return options - - def getRequired(self): - reqXML = self.xml.find('{%s}required' % self.namespace) - return reqXML is not None - - def getValue(self): - valsXML = self.xml.findall('{%s}value' % self.namespace) - if len(valsXML) == 0: - return None - elif self['type'] == 'boolean': - return valsXML[0].text in self.true_values - elif self['type'] in self.multi_value_types: - values = [] - for valXML in valsXML: - if valXML.text is None: - valXML.text = '' - values.append(valXML.text) - if self['type'] == 'text-multi': - values = "\n".join(values) - return values - else: - return valsXML[0].text - - def setAnswer(self, answer): - self.setValue(answer) - - def setFalse(self): - self.setValue(False) - - def setOptions(self, options): - for value in options: - if isinstance(value, dict): - self.addOption(**value) - else: - self.addOption(value=value) - - def setRequired(self, required): - exists = self.getRequired() - if not exists and required: - self.xml.append(ET.Element('{%s}required' % self.namespace)) - elif exists and not required: - self.delRequired() - - def setTrue(self): - self.setValue(True) - - def setValue(self, value): - self.delValue() - valXMLName = '{%s}value' % self.namespace - - if self['type'] == 'boolean': - if value in self.true_values: - valXML = ET.Element(valXMLName) - valXML.text = '1' - self.xml.append(valXML) - else: - valXML = ET.Element(valXMLName) - valXML.text = '0' - self.xml.append(valXML) - elif self['type'] in self.multi_value_types or self['type'] in ['', None]: - if self['type'] in self.multi_line_types and isinstance(value, str): - value = value.split('\n') - if not isinstance(value, list): - value = [value] - for val in value: - if self['type'] in ['', None] and val in self.true_values: - val = '1' - valXML = ET.Element(valXMLName) - valXML.text = val - self.xml.append(valXML) - else: - if isinstance(value, list): - raise ValueError("Cannot add multiple values to a %s field." % self['type']) - valXML = ET.Element(valXMLName) - valXML.text = value - self.xml.append(valXML) - - -class FieldOption(ElementBase): - namespace = 'jabber:x:data' - name = 'option' - plugin_attrib = 'option' - interfaces = set(('label', 'value')) - sub_interfaces = set(('value',)) - - -class xep_0004(base.base_plugin): - """ - XEP-0004: Data Forms - """ - - def plugin_init(self): - self.xep = '0004' - self.description = 'Data Forms' - - self.xmpp.registerHandler( - Callback('Data Form', - MatchXPath('{%s}message/{%s}x' % (self.xmpp.default_ns, - Form.namespace)), - self.handle_form)) - - registerStanzaPlugin(FormField, FieldOption) - registerStanzaPlugin(Form, FormField) - registerStanzaPlugin(Message, Form) - - def makeForm(self, ftype='form', title='', instructions=''): - f = Form() - f['type'] = ftype - f['title'] = title - f['instructions'] = instructions - return f - - def post_init(self): - base.base_plugin.post_init(self) - self.xmpp.plugin['xep_0030'].add_feature('jabber:x:data') - - def handle_form(self, message): - self.xmpp.event("message_xform", message) - - def buildForm(self, xml): - return Form(xml=xml) diff --git a/sleekxmpp/plugins/xep_0009.py b/sleekxmpp/plugins/xep_0009.py deleted file mode 100644 index 625b03f..0000000 --- a/sleekxmpp/plugins/xep_0009.py +++ /dev/null @@ -1,277 +0,0 @@ -"""
-XEP-0009 XMPP Remote Procedure Calls
-"""
-from __future__ import with_statement
-from . import base
-import logging
-from xml.etree import cElementTree as ET
-import copy
-import time
-import base64
-
-def py2xml(*args):
- params = ET.Element("params")
- for x in args:
- param = ET.Element("param")
- param.append(_py2xml(x))
- params.append(param) #<params><param>...
- return params
-
-def _py2xml(*args):
- for x in args:
- val = ET.Element("value")
- if type(x) is int:
- i4 = ET.Element("i4")
- i4.text = str(x)
- val.append(i4)
- if type(x) is bool:
- boolean = ET.Element("boolean")
- boolean.text = str(int(x))
- val.append(boolean)
- elif type(x) is str:
- string = ET.Element("string")
- string.text = x
- val.append(string)
- elif type(x) is float:
- double = ET.Element("double")
- double.text = str(x)
- val.append(double)
- elif type(x) is rpcbase64:
- b64 = ET.Element("Base64")
- b64.text = x.encoded()
- val.append(b64)
- elif type(x) is rpctime:
- iso = ET.Element("dateTime.iso8601")
- iso.text = str(x)
- val.append(iso)
- elif type(x) is list:
- array = ET.Element("array")
- data = ET.Element("data")
- for y in x:
- data.append(_py2xml(y))
- array.append(data)
- val.append(array)
- elif type(x) is dict:
- struct = ET.Element("struct")
- for y in x.keys():
- member = ET.Element("member")
- name = ET.Element("name")
- name.text = y
- member.append(name)
- member.append(_py2xml(x[y]))
- struct.append(member)
- val.append(struct)
- return val
-
-def xml2py(params):
- vals = []
- for param in params.findall('param'):
- vals.append(_xml2py(param.find('value')))
- return vals
-
-def _xml2py(value):
- if value.find('i4') is not None:
- return int(value.find('i4').text)
- if value.find('int') is not None:
- return int(value.find('int').text)
- if value.find('boolean') is not None:
- return bool(value.find('boolean').text)
- if value.find('string') is not None:
- return value.find('string').text
- if value.find('double') is not None:
- return float(value.find('double').text)
- if value.find('Base64') is not None:
- return rpcbase64(value.find('Base64').text)
- if value.find('dateTime.iso8601') is not None:
- return rpctime(value.find('dateTime.iso8601'))
- if value.find('struct') is not None:
- struct = {}
- for member in value.find('struct').findall('member'):
- struct[member.find('name').text] = _xml2py(member.find('value'))
- return struct
- if value.find('array') is not None:
- array = []
- for val in value.find('array').find('data').findall('value'):
- array.append(_xml2py(val))
- return array
- raise ValueError()
-
-class rpcbase64(object):
- def __init__(self, data):
- #base 64 encoded string
- self.data = data
-
- def decode(self):
- return base64.decodestring(data)
-
- def __str__(self):
- return self.decode()
-
- def encoded(self):
- return self.data
-
-class rpctime(object):
- def __init__(self,data=None):
- #assume string data is in iso format YYYYMMDDTHH:MM:SS
- if type(data) is str:
- self.timestamp = time.strptime(data,"%Y%m%dT%H:%M:%S")
- elif type(data) is time.struct_time:
- self.timestamp = data
- elif data is None:
- self.timestamp = time.gmtime()
- else:
- raise ValueError()
-
- def iso8601(self):
- #return a iso8601 string
- return time.strftime("%Y%m%dT%H:%M:%S",self.timestamp)
-
- def __str__(self):
- return self.iso8601()
-
-class JabberRPCEntry(object):
- def __init__(self,call):
- self.call = call
- self.result = None
- self.error = None
- self.allow = {} #{'<jid>':['<resource1>',...],...}
- self.deny = {}
-
- def check_acl(self, jid, resource):
- #Check for deny
- if jid in self.deny.keys():
- if self.deny[jid] == None or resource in self.deny[jid]:
- return False
- #Check for allow
- if allow == None:
- return True
- if jid in self.allow.keys():
- if self.allow[jid] == None or resource in self.allow[jid]:
- return True
- return False
-
- def acl_allow(self, jid, resource):
- if jid == None:
- self.allow = None
- elif resource == None:
- self.allow[jid] = None
- elif jid in self.allow.keys():
- self.allow[jid].append(resource)
- else:
- self.allow[jid] = [resource]
-
- def acl_deny(self, jid, resource):
- if jid == None:
- self.deny = None
- elif resource == None:
- self.deny[jid] = None
- elif jid in self.deny.keys():
- self.deny[jid].append(resource)
- else:
- self.deny[jid] = [resource]
-
- def call_method(self, args):
- ret = self.call(*args)
-
-class xep_0009(base.base_plugin):
-
- def plugin_init(self):
- self.xep = '0009'
- self.description = 'Jabber-RPC'
- self.xmpp.add_handler("<iq type='set'><query xmlns='jabber:iq:rpc' /></iq>",
- self._callMethod, name='Jabber RPC Call')
- self.xmpp.add_handler("<iq type='result'><query xmlns='jabber:iq:rpc' /></iq>",
- self._callResult, name='Jabber RPC Result')
- self.xmpp.add_handler("<iq type='error'><query xmlns='jabber:iq:rpc' /></iq>",
- self._callError, name='Jabber RPC Error')
- self.entries = {}
- self.activeCalls = []
-
- def post_init(self):
- base.base_plugin.post_init(self)
- self.xmpp.plugin['xep_0030'].add_feature('jabber:iq:rpc')
- self.xmpp.plugin['xep_0030'].add_identity('automatition','rpc')
-
- def register_call(self, method, name=None):
- #@returns an string that can be used in acl commands.
- with self.lock:
- if name is None:
- self.entries[method.__name__] = JabberRPCEntry(method)
- return method.__name__
- else:
- self.entries[name] = JabberRPCEntry(method)
- return name
-
- def acl_allow(self, entry, jid=None, resource=None):
- #allow the method entry to be called by the given jid and resource.
- #if jid is None it will allow any jid/resource.
- #if resource is None it will allow any resource belonging to the jid.
- with self.lock:
- if self.entries[entry]:
- self.entries[entry].acl_allow(jid,resource)
- else:
- raise ValueError()
-
- def acl_deny(self, entry, jid=None, resource=None):
- #Note: by default all requests are denied unless allowed with acl_allow.
- #If you deny an entry it will not be allowed regardless of acl_allow
- with self.lock:
- if self.entries[entry]:
- self.entries[entry].acl_deny(jid,resource)
- else:
- raise ValueError()
-
- def unregister_call(self, entry):
- #removes the registered call
- with self.lock:
- if self.entries[entry]:
- del self.entries[entry]
- else:
- raise ValueError()
-
- def makeMethodCallQuery(self,pmethod,params):
- query = self.xmpp.makeIqQuery(iq,"jabber:iq:rpc")
- methodCall = ET.Element('methodCall')
- methodName = ET.Element('methodName')
- methodName.text = pmethod
- methodCall.append(methodName)
- methodCall.append(params)
- query.append(methodCall)
- return query
-
- def makeIqMethodCall(self,pto,pmethod,params):
- iq = self.xmpp.makeIqSet()
- iq.set('to',pto)
- iq.append(self.makeMethodCallQuery(pmethod,params))
- return iq
-
- def makeIqMethodResponse(self,pto,pid,params):
- iq = self.xmpp.makeIqResult(pid)
- iq.set('to',pto)
- query = self.xmpp.makeIqQuery(iq,"jabber:iq:rpc")
- methodResponse = ET.Element('methodResponse')
- methodResponse.append(params)
- query.append(methodResponse)
- return iq
-
- def makeIqMethodError(self,pto,id,pmethod,params,condition):
- iq = self.xmpp.makeIqError(id)
- iq.set('to',pto)
- iq.append(self.makeMethodCallQuery(pmethod,params))
- iq.append(self.xmpp['xep_0086'].makeError(condition))
- return iq
-
-
-
- def call_remote(self, pto, pmethod, *args):
- #calls a remote method. Returns the id of the Iq.
- pass
-
- def _callMethod(self,xml):
- pass
-
- def _callResult(self,xml):
- pass
-
- def _callError(self,xml):
- pass
diff --git a/sleekxmpp/plugins/xep_0012.py b/sleekxmpp/plugins/xep_0012.py deleted file mode 100644 index d636d4d..0000000 --- a/sleekxmpp/plugins/xep_0012.py +++ /dev/null @@ -1,118 +0,0 @@ -"""
- SleekXMPP: The Sleek XMPP Library
- Copyright (C) 2010 Nathanael C. Fritz
- This file is part of SleekXMPP.
-
- See the file LICENSE for copying permission.
-"""
-
-from datetime import datetime
-import logging
-
-from . import base
-from .. stanza.iq import Iq
-from .. xmlstream.handler.callback import Callback
-from .. xmlstream.matcher.xpath import MatchXPath
-from .. xmlstream import ElementBase, ET, JID, register_stanza_plugin
-
-
-log = logging.getLogger(__name__)
-
-
-class LastActivity(ElementBase):
- name = 'query'
- namespace = 'jabber:iq:last'
- plugin_attrib = 'last_activity'
- interfaces = set(('seconds', 'status'))
-
- def get_seconds(self):
- return int(self._get_attr('seconds'))
-
- def set_seconds(self, value):
- self._set_attr('seconds', str(value))
-
- def get_status(self):
- return self.xml.text
-
- def set_status(self, value):
- self.xml.text = str(value)
-
- def del_status(self):
- self.xml.text = ''
-
-class xep_0012(base.base_plugin):
- """
- XEP-0012 Last Activity
- """
- def plugin_init(self):
- self.description = "Last Activity"
- self.xep = "0012"
-
- self.xmpp.registerHandler(
- Callback('Last Activity',
- MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns,
- LastActivity.namespace)),
- self.handle_last_activity_query))
- register_stanza_plugin(Iq, LastActivity)
-
- self.xmpp.add_event_handler('last_activity_request', self.handle_last_activity)
-
-
- def post_init(self):
- base.base_plugin.post_init(self)
- if self.xmpp.is_component:
- # We are a component, so we track the uptime
- self.xmpp.add_event_handler("session_start", self._reset_uptime)
- self._start_datetime = datetime.now()
- self.xmpp.plugin['xep_0030'].add_feature('jabber:iq:last')
-
- def _reset_uptime(self, event):
- self._start_datetime = datetime.now()
-
- def handle_last_activity_query(self, iq):
- if iq['type'] == 'get':
- log.debug("Last activity requested by %s" % iq['from'])
- self.xmpp.event('last_activity_request', iq)
- elif iq['type'] == 'result':
- log.debug("Last activity result from %s" % iq['from'])
- self.xmpp.event('last_activity', iq)
-
- def handle_last_activity(self, iq):
- jid = iq['from']
-
- if self.xmpp.is_component:
- # Send the uptime
- result = LastActivity()
- td = (datetime.now() - self._start_datetime)
- result['seconds'] = td.seconds + td.days * 24 * 3600
- reply = iq.reply().setPayload(result.xml).send()
- else:
- barejid = JID(jid).bare
- if barejid in self.xmpp.roster and ( self.xmpp.roster[barejid]['subscription'] in ('from', 'both') or
- barejid == self.xmpp.boundjid.bare ):
- # We don't know how to calculate it
- iq.reply().error().setPayload(iq['last_activity'].xml)
- iq['error']['code'] = '503'
- iq['error']['type'] = 'cancel'
- iq['error']['condition'] = 'service-unavailable'
- iq.send()
- else:
- iq.reply().error().setPayload(iq['last_activity'].xml)
- iq['error']['code'] = '403'
- iq['error']['type'] = 'auth'
- iq['error']['condition'] = 'forbidden'
- iq.send()
-
- def get_last_activity(self, jid):
- """Query the LastActivity of jid and return it in seconds"""
- iq = self.xmpp.makeIqGet()
- query = LastActivity()
- iq.append(query.xml)
- iq.attrib['to'] = jid
- 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':
- return result['last_activity']['seconds']
- else:
- return False
diff --git a/sleekxmpp/plugins/xep_0030.py b/sleekxmpp/plugins/xep_0030.py deleted file mode 100644 index a3fac34..0000000 --- a/sleekxmpp/plugins/xep_0030.py +++ /dev/null @@ -1,329 +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 . import base -from .. xmlstream.handler.callback import Callback -from .. xmlstream.matcher.xpath import MatchXPath -from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID -from .. stanza.iq import Iq - - -log = logging.getLogger(__name__) - - -class DiscoInfo(ElementBase): - namespace = 'http://jabber.org/protocol/disco#info' - name = 'query' - plugin_attrib = 'disco_info' - interfaces = set(('node', 'features', 'identities')) - - def getFeatures(self): - features = [] - featuresXML = self.xml.findall('{%s}feature' % self.namespace) - for feature in featuresXML: - features.append(feature.attrib['var']) - return features - - def setFeatures(self, features): - self.delFeatures() - for name in features: - self.addFeature(name) - - def delFeatures(self): - featuresXML = self.xml.findall('{%s}feature' % self.namespace) - for feature in featuresXML: - self.xml.remove(feature) - - def addFeature(self, feature): - featureXML = ET.Element('{%s}feature' % self.namespace, - {'var': feature}) - self.xml.append(featureXML) - - def delFeature(self, feature): - featuresXML = self.xml.findall('{%s}feature' % self.namespace) - for featureXML in featuresXML: - if featureXML.attrib['var'] == feature: - self.xml.remove(featureXML) - - def getIdentities(self): - ids = [] - idsXML = self.xml.findall('{%s}identity' % self.namespace) - for idXML in idsXML: - idData = (idXML.attrib['category'], - idXML.attrib['type'], - idXML.attrib.get('name', '')) - ids.append(idData) - return ids - - def setIdentities(self, ids): - self.delIdentities() - for idData in ids: - self.addIdentity(*idData) - - def delIdentities(self): - idsXML = self.xml.findall('{%s}identity' % self.namespace) - for idXML in idsXML: - self.xml.remove(idXML) - - def addIdentity(self, category, id_type, name=''): - idXML = ET.Element('{%s}identity' % self.namespace, - {'category': category, - 'type': id_type, - 'name': name}) - self.xml.append(idXML) - - def delIdentity(self, category, id_type, name=''): - idsXML = self.xml.findall('{%s}identity' % self.namespace) - for idXML in idsXML: - idData = (idXML.attrib['category'], - idXML.attrib['type']) - delId = (category, id_type) - if idData == delId: - self.xml.remove(idXML) - - -class DiscoItems(ElementBase): - namespace = 'http://jabber.org/protocol/disco#items' - name = 'query' - plugin_attrib = 'disco_items' - interfaces = set(('node', 'items')) - - def getItems(self): - items = [] - itemsXML = self.xml.findall('{%s}item' % self.namespace) - for item in itemsXML: - itemData = (item.attrib['jid'], - item.attrib.get('node'), - item.attrib.get('name')) - items.append(itemData) - return items - - def setItems(self, items): - self.delItems() - for item in items: - self.addItem(*item) - - def delItems(self): - itemsXML = self.xml.findall('{%s}item' % self.namespace) - for item in itemsXML: - self.xml.remove(item) - - def addItem(self, jid, node='', name=''): - itemXML = ET.Element('{%s}item' % self.namespace, {'jid': jid}) - if name: - itemXML.attrib['name'] = name - if node: - itemXML.attrib['node'] = node - self.xml.append(itemXML) - - def delItem(self, jid, node=''): - itemsXML = self.xml.findall('{%s}item' % self.namespace) - for itemXML in itemsXML: - itemData = (itemXML.attrib['jid'], - itemXML.attrib.get('node', '')) - itemDel = (jid, node) - if itemData == itemDel: - self.xml.remove(itemXML) - - -class DiscoNode(object): - """ - Collection object for grouping info and item information - into nodes. - """ - def __init__(self, name): - self.name = name - self.info = DiscoInfo() - self.items = DiscoItems() - - self.info['node'] = name - self.items['node'] = name - - # This is a bit like poor man's inheritance, but - # to simplify adding information to the node we - # map node functions to either the info or items - # stanza objects. - # - # We don't want to make DiscoNode inherit from - # DiscoInfo and DiscoItems because DiscoNode is - # not an actual stanza, and doing so would create - # confusion and potential bugs. - - self._map(self.items, 'items', ['get', 'set', 'del']) - self._map(self.items, 'item', ['add', 'del']) - self._map(self.info, 'identities', ['get', 'set', 'del']) - self._map(self.info, 'identity', ['add', 'del']) - self._map(self.info, 'features', ['get', 'set', 'del']) - self._map(self.info, 'feature', ['add', 'del']) - - def isEmpty(self): - """ - Test if the node contains any information. Useful for - determining if a node can be deleted. - """ - ids = self.getIdentities() - features = self.getFeatures() - items = self.getItems() - - if not ids and not features and not items: - return True - return False - - def _map(self, obj, interface, access): - """ - Map functions of the form obj.accessInterface - to self.accessInterface for each given access type. - """ - interface = interface.title() - for access_type in access: - method = access_type + interface - if hasattr(obj, method): - setattr(self, method, getattr(obj, method)) - - -class xep_0030(base.base_plugin): - """ - XEP-0030 Service Discovery - """ - - def plugin_init(self): - self.xep = '0030' - self.description = 'Service Discovery' - - self.xmpp.registerHandler( - Callback('Disco Items', - MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns, - DiscoItems.namespace)), - self.handle_item_query)) - - self.xmpp.registerHandler( - Callback('Disco Info', - MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns, - DiscoInfo.namespace)), - self.handle_info_query)) - - registerStanzaPlugin(Iq, DiscoInfo) - registerStanzaPlugin(Iq, DiscoItems) - - self.xmpp.add_event_handler('disco_items_request', self.handle_disco_items) - self.xmpp.add_event_handler('disco_info_request', self.handle_disco_info) - - self.nodes = {'main': DiscoNode('main')} - - def add_node(self, node): - if node not in self.nodes: - self.nodes[node] = DiscoNode(node) - - def del_node(self, node): - if node in self.nodes: - del self.nodes[node] - - def handle_item_query(self, iq): - if iq['type'] == 'get': - log.debug("Items requested by %s" % iq['from']) - self.xmpp.event('disco_items_request', iq) - elif iq['type'] == 'result': - log.debug("Items result from %s" % iq['from']) - self.xmpp.event('disco_items', iq) - - def handle_info_query(self, iq): - if iq['type'] == 'get': - log.debug("Info requested by %s" % iq['from']) - self.xmpp.event('disco_info_request', iq) - elif iq['type'] == 'result': - log.debug("Info result from %s" % iq['from']) - self.xmpp.event('disco_info', iq) - - def handle_disco_info(self, iq, forwarded=False): - """ - A default handler for disco#info requests. If another - handler is registered, this one will defer and not run. - """ - if not forwarded and self.xmpp.event_handled('disco_info_request'): - return - - node_name = iq['disco_info']['node'] - if not node_name: - node_name = 'main' - - log.debug("Using default handler for disco#info on node '%s'." % node_name) - - if node_name in self.nodes: - node = self.nodes[node_name] - iq.reply().setPayload(node.info.xml).send() - else: - log.debug("Node %s requested, but does not exist." % node_name) - iq.reply().error().setPayload(iq['disco_info'].xml) - iq['error']['code'] = '404' - iq['error']['type'] = 'cancel' - iq['error']['condition'] = 'item-not-found' - iq.send() - - def handle_disco_items(self, iq, forwarded=False): - """ - A default handler for disco#items requests. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('disco_items_request'): - return - - node_name = iq['disco_items']['node'] - if not node_name: - node_name = 'main' - - log.debug("Using default handler for disco#items on node '%s'." % node_name) - - if node_name in self.nodes: - node = self.nodes[node_name] - iq.reply().setPayload(node.items.xml).send() - else: - log.debug("Node %s requested, but does not exist." % node_name) - iq.reply().error().setPayload(iq['disco_items'].xml) - iq['error']['code'] = '404' - iq['error']['type'] = 'cancel' - iq['error']['condition'] = 'item-not-found' - iq.send() - - # Older interface methods for backwards compatibility - - def getInfo(self, jid, node='', dfrom=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['to'] = jid - iq['from'] = dfrom - iq['disco_info']['node'] = node - return iq.send() - - def getItems(self, jid, node='', dfrom=None): - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['to'] = jid - iq['from'] = dfrom - iq['disco_items']['node'] = node - return iq.send() - - def add_feature(self, feature, node='main'): - self.add_node(node) - self.nodes[node].addFeature(feature) - - def add_identity(self, category='', itype='', name='', node='main'): - self.add_node(node) - self.nodes[node].addIdentity(category=category, - id_type=itype, - name=name) - - def add_item(self, jid=None, name='', node='main', subnode=''): - self.add_node(node) - self.add_node(subnode) - if jid is None: - jid = self.xmpp.fulljid - self.nodes[node].addItem(jid=jid, name=name, node=subnode) diff --git a/sleekxmpp/plugins/xep_0033.py b/sleekxmpp/plugins/xep_0033.py deleted file mode 100644 index c0c4d89..0000000 --- a/sleekxmpp/plugins/xep_0033.py +++ /dev/null @@ -1,161 +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 . import base -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 - - -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) - # 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(base.base_plugin): - """ - XEP-0033: Extended Stanza Addressing - """ - - def plugin_init(self): - self.xep = '0033' - self.description = 'Extended Stanza Addressing' - - registerStanzaPlugin(Message, Addresses) - - def post_init(self): - base.base_plugin.post_init(self) - self.xmpp.plugin['xep_0030'].add_feature(Addresses.namespace) diff --git a/sleekxmpp/plugins/xep_0045.py b/sleekxmpp/plugins/xep_0045.py deleted file mode 100644 index db41cdb..0000000 --- a/sleekxmpp/plugins/xep_0045.py +++ /dev/null @@ -1,344 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" -from __future__ import with_statement -from . import base -import logging -from xml.etree import cElementTree as ET -from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, JID -from .. stanza.presence import Presence -from .. xmlstream.handler.callback import Callback -from .. xmlstream.matcher.xpath import MatchXPath -from .. xmlstream.matcher.xmlmask import MatchXMLMask - - -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 - -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.jid - 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.jid - 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.jid - 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() diff --git a/sleekxmpp/plugins/xep_0050.py b/sleekxmpp/plugins/xep_0050.py deleted file mode 100644 index 5efb911..0000000 --- a/sleekxmpp/plugins/xep_0050.py +++ /dev/null @@ -1,133 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" -from __future__ import with_statement -from . import base -import logging -from xml.etree import cElementTree as ET -import time - -class xep_0050(base.base_plugin): - """ - XEP-0050 Ad-Hoc Commands - """ - - def plugin_init(self): - self.xep = '0050' - self.description = 'Ad-Hoc Commands' - self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='__None__'/></iq>" % self.xmpp.default_ns, self.handler_command, name='Ad-Hoc None') - self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='execute'/></iq>" % self.xmpp.default_ns, self.handler_command, name='Ad-Hoc Execute') - self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='next'/></iq>" % self.xmpp.default_ns, self.handler_command_next, name='Ad-Hoc Next', threaded=True) - self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='cancel'/></iq>" % self.xmpp.default_ns, self.handler_command_cancel, name='Ad-Hoc Cancel') - self.xmpp.add_handler("<iq type='set' xmlns='%s'><command xmlns='http://jabber.org/protocol/commands' action='complete'/></iq>" % self.xmpp.default_ns, self.handler_command_complete, name='Ad-Hoc Complete') - self.commands = {} - self.sessions = {} - self.sd = self.xmpp.plugin['xep_0030'] - - def post_init(self): - base.base_plugin.post_init(self) - self.sd.add_feature('http://jabber.org/protocol/commands') - - def addCommand(self, node, name, form, pointer=None, multi=False): - self.sd.add_item(None, name, 'http://jabber.org/protocol/commands', node) - self.sd.add_identity('automation', 'command-node', name, node) - self.sd.add_feature('http://jabber.org/protocol/commands', node) - self.sd.add_feature('jabber:x:data', node) - self.commands[node] = (name, form, pointer, multi) - - def getNewSession(self): - return str(time.time()) + '-' + self.xmpp.getNewId() - - def handler_command(self, xml): - in_command = xml.find('{http://jabber.org/protocol/commands}command') - sessionid = in_command.get('sessionid', None) - node = in_command.get('node') - sessionid = self.getNewSession() - name, form, pointer, multi = self.commands[node] - self.sessions[sessionid] = {} - self.sessions[sessionid]['jid'] = xml.get('from') - self.sessions[sessionid]['to'] = xml.get('to') - self.sessions[sessionid]['past'] = [(form, None)] - self.sessions[sessionid]['next'] = pointer - npointer = pointer - if multi: - actions = ['next'] - status = 'executing' - else: - if pointer is None: - status = 'completed' - actions = [] - else: - status = 'executing' - actions = ['complete'] - self.xmpp.send(self.makeCommand(xml.attrib['from'], in_command.attrib['node'], form=form, id=xml.attrib['id'], sessionid=sessionid, status=status, actions=actions)) - - def handler_command_complete(self, xml): - in_command = xml.find('{http://jabber.org/protocol/commands}command') - sessionid = in_command.get('sessionid', None) - pointer = self.sessions[sessionid]['next'] - results = self.xmpp.plugin['old_0004'].makeForm('result') - results.fromXML(in_command.find('{jabber:x:data}x')) - pointer(results,sessionid) - self.xmpp.send(self.makeCommand(xml.attrib['from'], in_command.attrib['node'], form=None, id=xml.attrib['id'], sessionid=sessionid, status='completed', actions=[])) - del self.sessions[in_command.get('sessionid')] - - - def handler_command_next(self, xml): - in_command = xml.find('{http://jabber.org/protocol/commands}command') - sessionid = in_command.get('sessionid', None) - pointer = self.sessions[sessionid]['next'] - results = self.xmpp.plugin['old_0004'].makeForm('result') - results.fromXML(in_command.find('{jabber:x:data}x')) - form, npointer, next = pointer(results,sessionid) - self.sessions[sessionid]['next'] = npointer - self.sessions[sessionid]['past'].append((form, pointer)) - actions = [] - actions.append('prev') - if npointer is None: - status = 'completed' - else: - status = 'executing' - if next: - actions.append('next') - else: - actions.append('complete') - self.xmpp.send(self.makeCommand(xml.attrib['from'], in_command.attrib['node'], form=form, id=xml.attrib['id'], sessionid=sessionid, status=status, actions=actions)) - - def handler_command_cancel(self, xml): - command = xml.find('{http://jabber.org/protocol/commands}command') - try: - del self.sessions[command.get('sessionid')] - except: - pass - self.xmpp.send(self.makeCommand(xml.attrib['from'], command.attrib['node'], id=xml.attrib['id'], sessionid=command.attrib['sessionid'], status='canceled')) - - def makeCommand(self, to, node, id=None, form=None, sessionid=None, status='executing', actions=[]): - if not id: - id = self.xmpp.getNewId() - iq = self.xmpp.makeIqResult(id) - iq.attrib['from'] = self.xmpp.fulljid - iq.attrib['to'] = to - command = ET.Element('{http://jabber.org/protocol/commands}command') - command.attrib['node'] = node - command.attrib['status'] = status - xmlactions = ET.Element('actions') - for action in actions: - xmlactions.append(ET.Element(action)) - if xmlactions: - command.append(xmlactions) - if not sessionid: - sessionid = self.getNewSession() - else: - iq.attrib['from'] = self.sessions[sessionid]['to'] - command.attrib['sessionid'] = sessionid - if form is not None: - if hasattr(form,'getXML'): - form = form.getXML() - command.append(form) - iq.append(command) - return iq diff --git a/sleekxmpp/plugins/xep_0060.py b/sleekxmpp/plugins/xep_0060.py deleted file mode 100644 index a7c6d02..0000000 --- a/sleekxmpp/plugins/xep_0060.py +++ /dev/null @@ -1,313 +0,0 @@ -from __future__ import with_statement -from . import base -import logging -#from xml.etree import cElementTree as ET -from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET -from . import stanza_pubsub -from . xep_0004 import Form - - -log = logging.getLogger(__name__) - - -class xep_0060(base.base_plugin): - """ - XEP-0060 Publish Subscribe - """ - - def plugin_init(self): - self.xep = '0060' - self.description = 'Publish-Subscribe' - - def create_node(self, jid, node, config=None, collection=False, ntype=None): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub}pubsub') - create = ET.Element('create') - create.set('node', node) - pubsub.append(create) - configure = ET.Element('configure') - if collection: - ntype = 'collection' - #if config is None: - # submitform = self.xmpp.plugin['xep_0004'].makeForm('submit') - #else: - if config is not None: - submitform = config - if 'FORM_TYPE' in submitform.field: - submitform.field['FORM_TYPE'].setValue('http://jabber.org/protocol/pubsub#node_config') - else: - submitform.addField('FORM_TYPE', 'hidden', value='http://jabber.org/protocol/pubsub#node_config') - if ntype: - if 'pubsub#node_type' in submitform.field: - submitform.field['pubsub#node_type'].setValue(ntype) - else: - submitform.addField('pubsub#node_type', value=ntype) - else: - if 'pubsub#node_type' in submitform.field: - submitform.field['pubsub#node_type'].setValue('leaf') - else: - submitform.addField('pubsub#node_type', value='leaf') - submitform['type'] = 'submit' - configure.append(submitform.xml) - pubsub.append(configure) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is False or result is None or result['type'] == 'error': return False - return True - - def subscribe(self, jid, node, bare=True, subscribee=None): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub}pubsub') - subscribe = ET.Element('subscribe') - subscribe.attrib['node'] = node - if subscribee is None: - if bare: - subscribe.attrib['jid'] = self.xmpp.jid - else: - subscribe.attrib['jid'] = self.xmpp.fulljid - else: - subscribe.attrib['jid'] = subscribee - pubsub.append(subscribe) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is False or result is None or result['type'] == 'error': return False - return True - - def unsubscribe(self, jid, node, bare=True, subscribee=None): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub}pubsub') - unsubscribe = ET.Element('unsubscribe') - unsubscribe.attrib['node'] = node - if subscribee is None: - if bare: - unsubscribe.attrib['jid'] = self.xmpp.jid - else: - unsubscribe.attrib['jid'] = self.xmpp.fulljid - else: - unsubscribe.attrib['jid'] = subscribee - pubsub.append(unsubscribe) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is False or result is None or result['type'] == 'error': return False - return True - - def getNodeConfig(self, jid, node=None): # if no node, then grab default - pubsub = ET.Element('{http://jabber.org/protocol/pubsub#owner}pubsub') - if node is not None: - configure = ET.Element('configure') - configure.attrib['node'] = node - else: - configure = ET.Element('default') - pubsub.append(configure) - #TODO: Add configure support. - iq = self.xmpp.makeIqGet() - iq.append(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - #self.xmpp.add_handler("<iq id='%s'/>" % id, self.handlerCreateNodeResponse) - result = iq.send() - if result is None or result == False or result['type'] == 'error': - log.warning("got error instead of config") - return False - if node is not None: - form = result.find('{http://jabber.org/protocol/pubsub#owner}pubsub/{http://jabber.org/protocol/pubsub#owner}configure/{jabber:x:data}x') - else: - form = result.find('{http://jabber.org/protocol/pubsub#owner}pubsub/{http://jabber.org/protocol/pubsub#owner}default/{jabber:x:data}x') - if not form or form is None: - log.error("No form found.") - return False - return Form(xml=form) - - def getNodeSubscriptions(self, jid, node): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub#owner}pubsub') - subscriptions = ET.Element('subscriptions') - subscriptions.attrib['node'] = node - pubsub.append(subscriptions) - iq = self.xmpp.makeIqGet() - iq.append(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is None or result == False or result['type'] == 'error': - log.warning("got error instead of config") - return False - else: - results = result.findall('{http://jabber.org/protocol/pubsub#owner}pubsub/{http://jabber.org/protocol/pubsub#owner}subscriptions/{http://jabber.org/protocol/pubsub#owner}subscription') - if results is None: - return False - subs = {} - for sub in results: - subs[sub.get('jid')] = sub.get('subscription') - return subs - - def getNodeAffiliations(self, jid, node): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub#owner}pubsub') - affiliations = ET.Element('affiliations') - affiliations.attrib['node'] = node - pubsub.append(affiliations) - iq = self.xmpp.makeIqGet() - iq.append(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is None or result == False or result['type'] == 'error': - log.warning("got error instead of config") - return False - else: - results = result.findall('{http://jabber.org/protocol/pubsub#owner}pubsub/{http://jabber.org/protocol/pubsub#owner}affiliations/{http://jabber.org/protocol/pubsub#owner}affiliation') - if results is None: - return False - subs = {} - for sub in results: - subs[sub.get('jid')] = sub.get('affiliation') - return subs - - def deleteNode(self, jid, node): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub#owner}pubsub') - iq = self.xmpp.makeIqSet() - delete = ET.Element('delete') - delete.attrib['node'] = node - pubsub.append(delete) - iq.append(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - result = iq.send() - if result is not None and result is not False and result['type'] != 'error': - return True - else: - return False - - - def setNodeConfig(self, jid, node, config): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub#owner}pubsub') - configure = ET.Element('configure') - configure.attrib['node'] = node - config = config.getXML('submit') - configure.append(config) - pubsub.append(configure) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is None or result['type'] == 'error': - return False - return True - - def setItem(self, jid, node, items=[]): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub}pubsub') - publish = ET.Element('publish') - publish.attrib['node'] = node - for pub_item in items: - id, payload = pub_item - item = ET.Element('item') - if id is not None: - item.attrib['id'] = id - item.append(payload) - publish.append(item) - pubsub.append(publish) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is None or result is False or result['type'] == 'error': return False - return True - - def addItem(self, jid, node, items=[]): - return self.setItem(jid, node, items) - - def deleteItem(self, jid, node, item): - pubsub = ET.Element('{http://jabber.org/protocol/pubsub}pubsub') - retract = ET.Element('retract') - retract.attrib['node'] = node - itemn = ET.Element('item') - itemn.attrib['id'] = item - retract.append(itemn) - pubsub.append(retract) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is None or result is False or result['type'] == 'error': return False - return True - - def getNodes(self, jid): - response = self.xmpp.plugin['xep_0030'].getItems(jid) - items = response.findall('{http://jabber.org/protocol/disco#items}query/{http://jabber.org/protocol/disco#items}item') - nodes = {} - if items is not None and items is not False: - for item in items: - nodes[item.get('node')] = item.get('name') - return nodes - - def getItems(self, jid, node): - response = self.xmpp.plugin['xep_0030'].getItems(jid, node) - items = response.findall('{http://jabber.org/protocol/disco#items}query/{http://jabber.org/protocol/disco#items}item') - nodeitems = [] - if items is not None and items is not False: - for item in items: - nodeitems.append(item.get('node')) - return nodeitems - - def addNodeToCollection(self, jid, child, parent=''): - config = self.getNodeConfig(jid, child) - if not config or config is None: - self.lasterror = "Config Error" - return False - try: - config.field['pubsub#collection'].setValue(parent) - except KeyError: - log.warning("pubsub#collection doesn't exist in config, trying to add it") - config.addField('pubsub#collection', value=parent) - if not self.setNodeConfig(jid, child, config): - return False - return True - - def modifyAffiliation(self, ps_jid, node, user_jid, affiliation): - if affiliation not in ('owner', 'publisher', 'member', 'none', 'outcast'): - raise TypeError - pubsub = ET.Element('{http://jabber.org/protocol/pubsub#owner}pubsub') - affs = ET.Element('affiliations') - affs.attrib['node'] = node - aff = ET.Element('affiliation') - aff.attrib['jid'] = user_jid - aff.attrib['affiliation'] = affiliation - affs.append(aff) - pubsub.append(affs) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = ps_jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq['id'] - result = iq.send() - if result is None or result is False or result['type'] == 'error': - return False - return True - - def addNodeToCollection(self, jid, child, parent=''): - config = self.getNodeConfig(jid, child) - if not config or config is None: - self.lasterror = "Config Error" - return False - try: - config.field['pubsub#collection'].setValue(parent) - except KeyError: - log.warning("pubsub#collection doesn't exist in config, trying to add it") - config.addField('pubsub#collection', value=parent) - if not self.setNodeConfig(jid, child, config): - return False - return True - - def removeNodeFromCollection(self, jid, child): - self.addNodeToCollection(jid, child, '') - diff --git a/sleekxmpp/plugins/xep_0078.py b/sleekxmpp/plugins/xep_0078.py deleted file mode 100644 index d2c81b1..0000000 --- a/sleekxmpp/plugins/xep_0078.py +++ /dev/null @@ -1,72 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" -from __future__ import with_statement -from xml.etree import cElementTree as ET -import logging -import hashlib -from . import base - - -log = logging.getLogger(__name__) - - -class xep_0078(base.base_plugin): - """ - XEP-0078 NON-SASL Authentication - """ - def plugin_init(self): - self.description = "Non-SASL Authentication (broken)" - self.xep = "0078" - self.xmpp.add_event_handler("session_start", self.check_stream) - #disabling until I fix conflict with PLAIN - #self.xmpp.registerFeature("<auth xmlns='http://jabber.org/features/iq-auth'/>", self.auth) - self.streamid = '' - - def check_stream(self, xml): - self.streamid = xml.attrib['id'] - if xml.get('version', '0') != '1.0': - self.auth() - - def auth(self, xml=None): - log.debug("Starting jabber:iq:auth Authentication") - auth_request = self.xmpp.makeIqGet() - auth_request_query = ET.Element('{jabber:iq:auth}query') - auth_request.attrib['to'] = self.xmpp.server - username = ET.Element('username') - username.text = self.xmpp.username - auth_request_query.append(username) - auth_request.append(auth_request_query) - result = auth_request.send() - rquery = result.find('{jabber:iq:auth}query') - attempt = self.xmpp.makeIqSet() - query = ET.Element('{jabber:iq:auth}query') - resource = ET.Element('resource') - resource.text = self.xmpp.resource - query.append(username) - query.append(resource) - if rquery.find('{jabber:iq:auth}digest') is None: - log.warning("Authenticating via jabber:iq:auth Plain.") - password = ET.Element('password') - password.text = self.xmpp.password - query.append(password) - else: - log.debug("Authenticating via jabber:iq:auth Digest") - digest = ET.Element('digest') - digest.text = hashlib.sha1(b"%s%s" % (self.streamid, self.xmpp.password)).hexdigest() - query.append(digest) - attempt.append(query) - result = attempt.send() - if result.attrib['type'] == 'result': - with self.xmpp.lock: - self.xmpp.authenticated = True - self.xmpp.sessionstarted = True - self.xmpp.event("session_start") - else: - log.info("Authentication failed") - self.xmpp.disconnect() - self.xmpp.event("failed_auth") diff --git a/sleekxmpp/plugins/xep_0085.py b/sleekxmpp/plugins/xep_0085.py deleted file mode 100644 index 3627e71..0000000 --- a/sleekxmpp/plugins/xep_0085.py +++ /dev/null @@ -1,104 +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 permissio -""" - -import logging -from . import base -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 - - -log = logging.getLogger(__name__) - - -class ChatState(ElementBase): - namespace = 'http://jabber.org/protocol/chatstates' - plugin_attrib = 'chat_state' - interface = set(('state',)) - states = set(('active', 'composing', 'gone', 'inactive', 'paused')) - - def active(self): - self.setState('active') - - def composing(self): - self.setState('composing') - - def gone(self): - self.setState('gone') - - def inactive(self): - self.setState('inactive') - - def paused(self): - self.setState('paused') - - def setState(self, state): - if state in self.states: - self.name = state - self.xml.tag = '{%s}%s' % (self.namespace, state) - else: - raise ValueError('Invalid chat state') - - def getState(self): - return self.name - -# In order to match the various chat state elements, -# we need one stanza object per state, even though -# they are all the same except for the initial name -# value. Do not depend on the type of the chat state -# stanza object for the actual state. - -class Active(ChatState): - name = 'active' -class Composing(ChatState): - name = 'composing' -class Gone(ChatState): - name = 'gone' -class Inactive(ChatState): - name = 'inactive' -class Paused(ChatState): - name = 'paused' - - -class xep_0085(base.base_plugin): - """ - XEP-0085 Chat State Notifications - """ - - def plugin_init(self): - self.xep = '0085' - self.description = 'Chat State Notifications' - - handlers = [('Active Chat State', 'active'), - ('Composing Chat State', 'composing'), - ('Gone Chat State', 'gone'), - ('Inactive Chat State', 'inactive'), - ('Paused Chat State', 'paused')] - for handler in handlers: - self.xmpp.registerHandler( - Callback(handler[0], - MatchXPath("{%s}message/{%s}%s" % (self.xmpp.default_ns, - ChatState.namespace, - handler[1])), - self._handleChatState)) - - registerStanzaPlugin(Message, Active) - registerStanzaPlugin(Message, Composing) - registerStanzaPlugin(Message, Gone) - registerStanzaPlugin(Message, Inactive) - registerStanzaPlugin(Message, Paused) - - def post_init(self): - base.base_plugin.post_init(self) - self.xmpp.plugin['xep_0030'].add_feature('http://jabber.org/protocol/chatstates') - - def _handleChatState(self, msg): - state = msg['chat_state'].name - log.debug("Chat State: %s, %s" % (state, msg['from'].jid)) - self.xmpp.event('chatstate_%s' % state, msg) diff --git a/sleekxmpp/plugins/xep_0086.py b/sleekxmpp/plugins/xep_0086.py deleted file mode 100644 index e6c18c7..0000000 --- a/sleekxmpp/plugins/xep_0086.py +++ /dev/null @@ -1,49 +0,0 @@ -
-from __future__ import with_statement
-from . import base
-import logging
-from xml.etree import cElementTree as ET
-import copy
-
-class xep_0086(base.base_plugin):
- """
- XEP-0086 Error Condition Mappings
- """
-
- def plugin_init(self):
- self.xep = '0086'
- self.description = 'Error Condition Mappings'
- self.error_map = {
- 'bad-request':('modify','400'),
- 'conflict':('cancel','409'),
- 'feature-not-implemented':('cancel','501'),
- 'forbidden':('auth','403'),
- 'gone':('modify','302'),
- 'internal-server-error':('wait','500'),
- 'item-not-found':('cancel','404'),
- 'jid-malformed':('modify','400'),
- 'not-acceptable':('modify','406'),
- 'not-allowed':('cancel','405'),
- 'not-authorized':('auth','401'),
- 'payment-required':('auth','402'),
- 'recipient-unavailable':('wait','404'),
- 'redirect':('modify','302'),
- 'registration-required':('auth','407'),
- 'remote-server-not-found':('cancel','404'),
- 'remote-server-timeout':('wait','504'),
- 'resource-constraint':('wait','500'),
- 'service-unavailable':('cancel','503'),
- 'subscription-required':('auth','407'),
- 'undefined-condition':(None,'500'),
- 'unexpected-request':('wait','400')
- }
-
-
- def makeError(self, condition, cdata=None, errorType=None, text=None, customElem=None):
- conditionElem = self.xmpp.makeStanzaErrorCondition(condition, cdata)
- if errorType is None:
- error = self.xmpp.makeStanzaError(conditionElem, self.error_map[condition][0], self.error_map[condition][1], text, customElem)
- else:
- error = self.xmpp.makeStanzaError(conditionElem, errorType, self.error_map[condition][1], text, customElem)
- error.append(conditionElem)
- return error
diff --git a/sleekxmpp/plugins/xep_0092.py b/sleekxmpp/plugins/xep_0092.py deleted file mode 100644 index ca02c4a..0000000 --- a/sleekxmpp/plugins/xep_0092.py +++ /dev/null @@ -1,56 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" -from xml.etree import cElementTree as ET -from . import base -from .. xmlstream.handler.xmlwaiter import XMLWaiter - -class xep_0092(base.base_plugin): - """ - XEP-0092 Software Version - """ - def plugin_init(self): - self.description = "Software Version" - self.xep = "0092" - self.name = self.config.get('name', 'SleekXMPP') - self.version = self.config.get('version', '0.1-dev') - self.xmpp.add_handler("<iq type='get' xmlns='%s'><query xmlns='jabber:iq:version' /></iq>" % self.xmpp.default_ns, self.report_version, name='Sofware Version') - - def post_init(self): - base.base_plugin.post_init(self) - self.xmpp.plugin['xep_0030'].add_feature('jabber:iq:version') - - def report_version(self, xml): - iq = self.xmpp.makeIqResult(xml.get('id', 'unknown')) - iq.attrib['to'] = xml.get('from', self.xmpp.server) - query = ET.Element('{jabber:iq:version}query') - name = ET.Element('name') - name.text = self.name - version = ET.Element('version') - version.text = self.version - query.append(name) - query.append(version) - iq.append(query) - self.xmpp.send(iq) - - def getVersion(self, jid): - iq = self.xmpp.makeIqGet() - query = ET.Element('{jabber:iq:version}query') - iq.append(query) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.fulljid - id = iq.get('id') - result = iq.send() - if result and result is not None and result.get('type', 'error') != 'error': - qry = result.find('{jabber:iq:version}query') - version = {} - for child in qry.getchildren(): - version[child.tag.split('}')[-1]] = child.text - return version - else: - return False - diff --git a/sleekxmpp/plugins/xep_0128.py b/sleekxmpp/plugins/xep_0128.py deleted file mode 100644 index 824977b..0000000 --- a/sleekxmpp/plugins/xep_0128.py +++ /dev/null @@ -1,51 +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 . import base -from .. xmlstream.handler.callback import Callback -from .. xmlstream.matcher.xpath import MatchXPath -from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID -from .. stanza.iq import Iq -from . xep_0030 import DiscoInfo, DiscoItems -from . xep_0004 import Form - - -class xep_0128(base.base_plugin): - """ - XEP-0128 Service Discovery Extensions - """ - - def plugin_init(self): - self.xep = '0128' - self.description = 'Service Discovery Extensions' - - registerStanzaPlugin(DiscoInfo, Form) - registerStanzaPlugin(DiscoItems, Form) - - def extend_info(self, node, data=None): - if data is None: - data = {} - node = self.xmpp['xep_0030'].nodes.get(node, None) - if node is None: - self.xmpp['xep_0030'].add_node(node) - - info = node.info - info['form']['type'] = 'result' - info['form'].setFields(data, default=None) - - def extend_items(self, node, data=None): - if data is None: - data = {} - node = self.xmpp['xep_0030'].nodes.get(node, None) - if node is None: - self.xmpp['xep_0030'].add_node(node) - - items = node.items - items['form']['type'] = 'result' - items['form'].setFields(data, default=None) diff --git a/sleekxmpp/plugins/xep_0199.py b/sleekxmpp/plugins/xep_0199.py deleted file mode 100644 index 2e99ae7..0000000 --- a/sleekxmpp/plugins/xep_0199.py +++ /dev/null @@ -1,63 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" -from xml.etree import cElementTree as ET -from . import base -import time -import logging - - -log = logging.getLogger(__name__) - - -class xep_0199(base.base_plugin): - """XEP-0199 XMPP Ping""" - - def plugin_init(self): - self.description = "XMPP Ping" - self.xep = "0199" - self.xmpp.add_handler("<iq type='get' xmlns='%s'><ping xmlns='urn:xmpp:ping'/></iq>" % self.xmpp.default_ns, self.handler_ping, name='XMPP Ping') - if self.config.get('keepalive', True): - self.xmpp.add_event_handler('session_start', self.handler_pingserver, threaded=True) - - def post_init(self): - base.base_plugin.post_init(self) - self.xmpp.plugin['xep_0030'].add_feature('urn:xmpp:ping') - - def handler_pingserver(self, xml): - self.xmpp.schedule("xep-0119 ping", float(self.config.get('frequency', 300)), self.scheduled_ping, repeat=True) - - def scheduled_ping(self): - log.debug("pinging...") - if self.sendPing(self.xmpp.server, self.config.get('timeout', 30)) is False: - log.debug("Did not recieve ping back in time. Requesting Reconnect.") - self.xmpp.reconnect() - - def handler_ping(self, xml): - iq = self.xmpp.makeIqResult(xml.get('id', 'unknown')) - iq.attrib['to'] = xml.get('from', self.xmpp.boundjid.domain) - self.xmpp.send(iq) - - def sendPing(self, jid, timeout = 30): - """ sendPing(jid, timeout) - Sends a ping to the specified jid, returning the time (in seconds) - to receive a reply, or None if no reply is received in timeout seconds. - """ - id = self.xmpp.getNewId() - iq = self.xmpp.makeIq(id) - iq.attrib['type'] = 'get' - iq.attrib['to'] = jid - ping = ET.Element('{urn:xmpp:ping}ping') - iq.append(ping) - startTime = time.clock() - #pingresult = self.xmpp.send(iq, self.xmpp.makeIq(id), timeout) - pingresult = iq.send() - endTime = time.clock() - if pingresult == False: - #self.xmpp.disconnect(reconnect=True) - return False - return endTime - startTime diff --git a/sleekxmpp/plugins/xep_0202.py b/sleekxmpp/plugins/xep_0202.py deleted file mode 100644 index fe1191e..0000000 --- a/sleekxmpp/plugins/xep_0202.py +++ /dev/null @@ -1,115 +0,0 @@ -"""
- SleekXMPP: The Sleek XMPP Library
- Copyright (C) 2010 Nathanael C. Fritz
- This file is part of SleekXMPP.
-
- See the file LICENSE for copying permission.
-"""
-
-from datetime import datetime, tzinfo
-import logging
-import time
-
-from . import base
-from .. stanza.iq import Iq
-from .. xmlstream.handler.callback import Callback
-from .. xmlstream.matcher.xpath import MatchXPath
-from .. xmlstream import ElementBase, ET, JID, register_stanza_plugin
-
-
-log = logging.getLogger(__name__)
-
-
-class EntityTime(ElementBase):
- name = 'time'
- namespace = 'urn:xmpp:time'
- plugin_attrib = 'entity_time'
- interfaces = set(('tzo', 'utc'))
- sub_interfaces = set(('tzo', 'utc'))
-
- #def get_utc(self): # TODO: return a datetime.tzinfo object?
- #pass
-
- def set_tzo(self, tzo): # TODO: support datetime.tzinfo objects?
- if isinstance(tzo, tzinfo):
- td = datetime.now(tzo).utcoffset() # What if we are faking the time? datetime.now() shouldn't be used here'
- seconds = td.seconds + td.days * 24 * 3600
- sign = ('+' if seconds >= 0 else '-')
- minutes = abs(seconds // 60)
- tzo = '{sign}{hours:02d}:{minutes:02d}'.format(sign=sign, hours=minutes//60, minutes=minutes%60)
- elif not isinstance(tzo, str):
- raise TypeError('The time should be a string or a datetime.tzinfo object.')
- self._set_sub_text('tzo', tzo)
-
- def get_utc(self):
- # Returns a datetime object instead the string. Is this a good idea?
- value = self._get_sub_text('utc')
- if '.' in value:
- return datetime.strptime(value, '%Y-%m-%d.%fT%H:%M:%SZ')
- else:
- return datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ')
-
- def set_utc(self, tim=None):
- if isinstance(tim, datetime):
- if tim.utcoffset():
- tim = tim - tim.utcoffset()
- tim = tim.strftime('%Y-%m-%dT%H:%M:%SZ')
- elif isinstance(tim, time.struct_time):
- tim = time.strftime('%Y-%m-%dT%H:%M:%SZ', tim)
- elif not isinstance(tim, str):
- raise TypeError('The time should be a string or a datetime.datetime or time.struct_time object.')
-
- self._set_sub_text('utc', tim)
-
-
-class xep_0202(base.base_plugin):
- """
- XEP-0202 Entity Time
- """
- def plugin_init(self):
- self.description = "Entity Time"
- self.xep = "0202"
-
- self.xmpp.registerHandler(
- Callback('Time Request',
- MatchXPath('{%s}iq/{%s}time' % (self.xmpp.default_ns,
- EntityTime.namespace)),
- self.handle_entity_time_query))
- register_stanza_plugin(Iq, EntityTime)
-
- self.xmpp.add_event_handler('entity_time_request', self.handle_entity_time)
-
-
- def post_init(self):
- base.base_plugin.post_init(self)
-
- self.xmpp.plugin['xep_0030'].add_feature('urn:xmpp:time')
-
- def handle_entity_time_query(self, iq):
- if iq['type'] == 'get':
- log.debug("Entity time requested by %s" % iq['from'])
- self.xmpp.event('entity_time_request', iq)
- elif iq['type'] == 'result':
- log.debug("Entity time result from %s" % iq['from'])
- self.xmpp.event('entity_time', iq)
-
- def handle_entity_time(self, iq):
- iq = iq.reply()
- iq.enable('entity_time')
- tzo = time.strftime('%z') # %z is not on all ANSI C libraries
- tzo = tzo[:3] + ':' + tzo[3:]
- iq['entity_time']['tzo'] = tzo
- iq['entity_time']['utc'] = datetime.utcnow()
- iq.send()
-
- def get_entity_time(self, jid):
- iq = self.xmpp.makeIqGet()
- iq.enable('entity_time')
- iq.attrib['to'] = jid
- 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':
- return {'utc': result['entity_time']['utc'], 'tzo': result['entity_time']['tzo']}
- else:
- return False
|
