Rename to slixmpp
This commit is contained in:
22
slixmpp/plugins/xep_0004/__init__.py
Normal file
22
slixmpp/plugins/xep_0004/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.plugins.base import register_plugin
|
||||
|
||||
from slixmpp.plugins.xep_0004.stanza import Form
|
||||
from slixmpp.plugins.xep_0004.stanza import FormField, FieldOption
|
||||
from slixmpp.plugins.xep_0004.dataforms import XEP_0004
|
||||
|
||||
|
||||
register_plugin(XEP_0004)
|
||||
|
||||
|
||||
# Retain some backwards compatibility
|
||||
xep_0004 = XEP_0004
|
||||
xep_0004.makeForm = xep_0004.make_form
|
||||
xep_0004.buildForm = xep_0004.build_form
|
||||
57
slixmpp/plugins/xep_0004/dataforms.py
Normal file
57
slixmpp/plugins/xep_0004/dataforms.py
Normal file
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp import Message
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
from slixmpp.xmlstream.matcher import StanzaPath
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.plugins.xep_0004 import stanza
|
||||
from slixmpp.plugins.xep_0004.stanza import Form, FormField, FieldOption
|
||||
|
||||
|
||||
class XEP_0004(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0004: Data Forms
|
||||
"""
|
||||
|
||||
name = 'xep_0004'
|
||||
description = 'XEP-0004: Data Forms'
|
||||
dependencies = set(['xep_0030'])
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
self.xmpp.register_handler(
|
||||
Callback('Data Form',
|
||||
StanzaPath('message/form'),
|
||||
self.handle_form))
|
||||
|
||||
register_stanza_plugin(FormField, FieldOption, iterable=True)
|
||||
register_stanza_plugin(Form, FormField, iterable=True)
|
||||
register_stanza_plugin(Message, Form)
|
||||
|
||||
def plugin_end(self):
|
||||
self.xmpp.remove_handler('Data Form')
|
||||
self.xmpp['xep_0030'].del_feature(feature='jabber:x:data')
|
||||
|
||||
def session_bind(self, jid):
|
||||
self.xmpp['xep_0030'].add_feature('jabber:x:data')
|
||||
|
||||
def make_form(self, ftype='form', title='', instructions=''):
|
||||
f = Form()
|
||||
f['type'] = ftype
|
||||
f['title'] = title
|
||||
f['instructions'] = instructions
|
||||
return f
|
||||
|
||||
def handle_form(self, message):
|
||||
self.xmpp.event("message_xform", message)
|
||||
|
||||
def build_form(self, xml):
|
||||
return Form(xml=xml)
|
||||
10
slixmpp/plugins/xep_0004/stanza/__init__.py
Normal file
10
slixmpp/plugins/xep_0004/stanza/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.plugins.xep_0004.stanza.field import FormField, FieldOption
|
||||
from slixmpp.plugins.xep_0004.stanza.form import Form
|
||||
183
slixmpp/plugins/xep_0004/stanza/field.py
Normal file
183
slixmpp/plugins/xep_0004/stanza/field.py
Normal file
@@ -0,0 +1,183 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.xmlstream import ElementBase, ET
|
||||
|
||||
|
||||
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',))
|
||||
plugin_tag_map = {}
|
||||
plugin_attrib_map = {}
|
||||
|
||||
field_types = set(('boolean', 'fixed', 'hidden', 'jid-multi',
|
||||
'jid-single', 'list-multi', 'list-single',
|
||||
'text-multi', 'text-private', 'text-single'))
|
||||
|
||||
true_values = set((True, '1', 'true'))
|
||||
option_types = set(('list-multi', 'list-single'))
|
||||
multi_line_types = set(('hidden', 'text-multi'))
|
||||
multi_value_types = set(('hidden', 'jid-multi',
|
||||
'list-multi', 'text-multi'))
|
||||
|
||||
def setup(self, xml=None):
|
||||
if ElementBase.setup(self, xml):
|
||||
self._type = None
|
||||
else:
|
||||
self._type = self['type']
|
||||
|
||||
def set_type(self, value):
|
||||
self._set_attr('type', value)
|
||||
if value:
|
||||
self._type = value
|
||||
|
||||
def add_option(self, label='', value=''):
|
||||
if self._type is None or self._type in self.option_types:
|
||||
opt = FieldOption()
|
||||
opt['label'] = label
|
||||
opt['value'] = value
|
||||
self.append(opt)
|
||||
else:
|
||||
raise ValueError("Cannot add options to " + \
|
||||
"a %s field." % self['type'])
|
||||
|
||||
def del_options(self):
|
||||
optsXML = self.xml.findall('{%s}option' % self.namespace)
|
||||
for optXML in optsXML:
|
||||
self.xml.remove(optXML)
|
||||
|
||||
def del_required(self):
|
||||
reqXML = self.xml.find('{%s}required' % self.namespace)
|
||||
if reqXML is not None:
|
||||
self.xml.remove(reqXML)
|
||||
|
||||
def del_value(self):
|
||||
valsXML = self.xml.findall('{%s}value' % self.namespace)
|
||||
for valXML in valsXML:
|
||||
self.xml.remove(valXML)
|
||||
|
||||
def get_answer(self):
|
||||
return self['value']
|
||||
|
||||
def get_options(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 get_required(self):
|
||||
reqXML = self.xml.find('{%s}required' % self.namespace)
|
||||
return reqXML is not None
|
||||
|
||||
def get_value(self, convert=True):
|
||||
valsXML = self.xml.findall('{%s}value' % self.namespace)
|
||||
if len(valsXML) == 0:
|
||||
return None
|
||||
elif self._type == 'boolean':
|
||||
if convert:
|
||||
return valsXML[0].text in self.true_values
|
||||
return valsXML[0].text
|
||||
elif self._type in self.multi_value_types or len(valsXML) > 1:
|
||||
values = []
|
||||
for valXML in valsXML:
|
||||
if valXML.text is None:
|
||||
valXML.text = ''
|
||||
values.append(valXML.text)
|
||||
if self._type == 'text-multi' and convert:
|
||||
values = "\n".join(values)
|
||||
return values
|
||||
else:
|
||||
if valsXML[0].text is None:
|
||||
return ''
|
||||
return valsXML[0].text
|
||||
|
||||
def set_answer(self, answer):
|
||||
self['value'] = answer
|
||||
|
||||
def set_false(self):
|
||||
self['value'] = False
|
||||
|
||||
def set_options(self, options):
|
||||
for value in options:
|
||||
if isinstance(value, dict):
|
||||
self.add_option(**value)
|
||||
else:
|
||||
self.add_option(value=value)
|
||||
|
||||
def set_required(self, required):
|
||||
exists = self['required']
|
||||
if not exists and required:
|
||||
self.xml.append(ET.Element('{%s}required' % self.namespace))
|
||||
elif exists and not required:
|
||||
del self['required']
|
||||
|
||||
def set_true(self):
|
||||
self['value'] = True
|
||||
|
||||
def set_value(self, value):
|
||||
del self['value']
|
||||
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 isinstance(value, bool):
|
||||
value = [value]
|
||||
if not isinstance(value, list):
|
||||
value = value.replace('\r', '')
|
||||
value = value.split('\n')
|
||||
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',))
|
||||
|
||||
|
||||
FormField.addOption = FormField.add_option
|
||||
FormField.delOptions = FormField.del_options
|
||||
FormField.delRequired = FormField.del_required
|
||||
FormField.delValue = FormField.del_value
|
||||
FormField.getAnswer = FormField.get_answer
|
||||
FormField.getOptions = FormField.get_options
|
||||
FormField.getRequired = FormField.get_required
|
||||
FormField.getValue = FormField.get_value
|
||||
FormField.setAnswer = FormField.set_answer
|
||||
FormField.setFalse = FormField.set_false
|
||||
FormField.setOptions = FormField.set_options
|
||||
FormField.setRequired = FormField.set_required
|
||||
FormField.setTrue = FormField.set_true
|
||||
FormField.setValue = FormField.set_value
|
||||
257
slixmpp/plugins/xep_0004/stanza/form.py
Normal file
257
slixmpp/plugins/xep_0004/stanza/form.py
Normal file
@@ -0,0 +1,257 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import logging
|
||||
|
||||
from slixmpp.thirdparty import OrderedDict
|
||||
|
||||
from slixmpp.xmlstream import ElementBase, ET
|
||||
from slixmpp.plugins.xep_0004.stanza import FormField
|
||||
|
||||
|
||||
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
|
||||
|
||||
def setup(self, xml=None):
|
||||
if ElementBase.setup(self, xml):
|
||||
# If we had to generate xml
|
||||
self['type'] = 'form'
|
||||
|
||||
@property
|
||||
def field(self):
|
||||
return self['fields']
|
||||
|
||||
def set_type(self, ftype):
|
||||
self._set_attr('type', ftype)
|
||||
if ftype == 'submit':
|
||||
fields = self['fields']
|
||||
for var in fields:
|
||||
field = fields[var]
|
||||
del field['type']
|
||||
del field['label']
|
||||
del field['desc']
|
||||
del field['required']
|
||||
del field['options']
|
||||
elif ftype == 'cancel':
|
||||
del self['fields']
|
||||
|
||||
def add_field(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()
|
||||
field['var'] = var
|
||||
field['type'] = kwtype
|
||||
field['value'] = value
|
||||
if self['type'] in ('form', 'result'):
|
||||
field['label'] = label
|
||||
field['desc'] = desc
|
||||
field['required'] = required
|
||||
if options is not None:
|
||||
field['options'] = options
|
||||
else:
|
||||
del field['type']
|
||||
self.append(field)
|
||||
return field
|
||||
|
||||
def getXML(self, type='submit'):
|
||||
self['type'] = type
|
||||
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 add_item(self, values):
|
||||
itemXML = ET.Element('{%s}item' % self.namespace)
|
||||
self.xml.append(itemXML)
|
||||
reported_vars = self['reported'].keys()
|
||||
for var in reported_vars:
|
||||
field = FormField()
|
||||
field._type = self['reported'][var]['type']
|
||||
field['var'] = var
|
||||
field['value'] = values.get(var, None)
|
||||
itemXML.append(field.xml)
|
||||
|
||||
def add_reported(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 del_fields(self):
|
||||
fieldsXML = self.xml.findall('{%s}field' % FormField.namespace)
|
||||
for fieldXML in fieldsXML:
|
||||
self.xml.remove(fieldXML)
|
||||
|
||||
def del_instructions(self):
|
||||
instsXML = self.xml.findall('{%s}instructions')
|
||||
for instXML in instsXML:
|
||||
self.xml.remove(instXML)
|
||||
|
||||
def del_items(self):
|
||||
itemsXML = self.xml.find('{%s}item' % self.namespace)
|
||||
for itemXML in itemsXML:
|
||||
self.xml.remove(itemXML)
|
||||
|
||||
def del_reported(self):
|
||||
reportedXML = self.xml.find('{%s}reported' % self.namespace)
|
||||
if reportedXML is not None:
|
||||
self.xml.remove(reportedXML)
|
||||
|
||||
def get_fields(self, use_dict=False):
|
||||
fields = OrderedDict()
|
||||
for stanza in self['substanzas']:
|
||||
if isinstance(stanza, FormField):
|
||||
fields[stanza['var']] = stanza
|
||||
return fields
|
||||
|
||||
def get_instructions(self):
|
||||
instructions = ''
|
||||
instsXML = self.xml.findall('{%s}instructions' % self.namespace)
|
||||
return "\n".join([instXML.text for instXML in instsXML])
|
||||
|
||||
def get_items(self):
|
||||
items = []
|
||||
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
||||
for itemXML in itemsXML:
|
||||
item = OrderedDict()
|
||||
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 get_reported(self):
|
||||
fields = OrderedDict()
|
||||
xml = self.xml.findall('{%s}reported/{%s}field' % (self.namespace,
|
||||
FormField.namespace))
|
||||
for field in xml:
|
||||
field = FormField(xml=field)
|
||||
fields[field['var']] = field
|
||||
return fields
|
||||
|
||||
def get_values(self):
|
||||
values = OrderedDict()
|
||||
fields = self['fields']
|
||||
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 set_fields(self, fields):
|
||||
del self['fields']
|
||||
if not isinstance(fields, list):
|
||||
fields = fields.items()
|
||||
for var, field in fields:
|
||||
field['var'] = var
|
||||
self.add_field(**field)
|
||||
|
||||
def set_instructions(self, instructions):
|
||||
del self['instructions']
|
||||
if instructions in [None, '']:
|
||||
return
|
||||
if not isinstance(instructions, list):
|
||||
instructions = instructions.split('\n')
|
||||
for instruction in instructions:
|
||||
inst = ET.Element('{%s}instructions' % self.namespace)
|
||||
inst.text = instruction
|
||||
self.xml.append(inst)
|
||||
|
||||
def set_items(self, items):
|
||||
for item in items:
|
||||
self.add_item(item)
|
||||
|
||||
def set_reported(self, reported):
|
||||
for var in reported:
|
||||
field = reported[var]
|
||||
field['var'] = var
|
||||
self.add_reported(var, **field)
|
||||
|
||||
def set_values(self, values):
|
||||
fields = self['fields']
|
||||
for field in values:
|
||||
if field not in fields:
|
||||
fields[field] = self.add_field(var=field)
|
||||
fields[field]['value'] = values[field]
|
||||
|
||||
def merge(self, other):
|
||||
new = copy.copy(self)
|
||||
if type(other) == dict:
|
||||
new['values'] = other
|
||||
return new
|
||||
nfields = new['fields']
|
||||
ofields = other['fields']
|
||||
nfields.update(ofields)
|
||||
new['fields'] = nfields
|
||||
return new
|
||||
|
||||
|
||||
Form.setType = Form.set_type
|
||||
Form.addField = Form.add_field
|
||||
Form.addItem = Form.add_item
|
||||
Form.addReported = Form.add_reported
|
||||
Form.delFields = Form.del_fields
|
||||
Form.delInstructions = Form.del_instructions
|
||||
Form.delItems = Form.del_items
|
||||
Form.delReported = Form.del_reported
|
||||
Form.getFields = Form.get_fields
|
||||
Form.getInstructions = Form.get_instructions
|
||||
Form.getItems = Form.get_items
|
||||
Form.getReported = Form.get_reported
|
||||
Form.getValues = Form.get_values
|
||||
Form.setFields = Form.set_fields
|
||||
Form.setInstructions = Form.set_instructions
|
||||
Form.setItems = Form.set_items
|
||||
Form.setReported = Form.set_reported
|
||||
Form.setValues = Form.set_values
|
||||
Reference in New Issue
Block a user