Add initial XEP-0054 plugin.

This commit is contained in:
Lance Stout 2012-04-07 20:50:02 -04:00
parent 7391288668
commit 259c84e99a
4 changed files with 646 additions and 0 deletions

View file

@ -24,6 +24,7 @@ __all__ = [
'xep_0045', # Multi-User Chat (Client)
'xep_0047', # In-Band Bytestreams
'xep_0050', # Ad-hoc Commands
'xep_0054', # vcard-temp
'xep_0059', # Result Set Management
'xep_0060', # Pubsub (Client)
'xep_0066', # Out of Band Data

View file

@ -0,0 +1,15 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.plugins.base import register_plugin
from sleekxmpp.plugins.xep_0054.stanza import VCardTemp
from sleekxmpp.plugins.xep_0054.vcard_temp import XEP_0054
register_plugin(XEP_0054)

View file

@ -0,0 +1,512 @@
import base64
import datetime as dt
from sleekxmpp.thirdparty.suelta.util import bytes
from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin, JID
from sleekxmpp.plugins import xep_0082
class VCardTemp(ElementBase):
name = 'vCard'
namespace = 'vcard-temp'
plugin_attrib = 'vcard_temp'
interfaces = set(['FN', 'VERSION'])
sub_interfaces = set(['FN', 'VERSION'])
class Name(ElementBase):
name = 'N'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['FAMILY', 'GIVEN', 'MIDDLE', 'PREFIX', 'SUFFIX'])
sub_interfaces = interfaces
def _set_component(self, name, value):
if isinstance(value, list):
value = ','.join(value)
if value is not None:
self._set_sub_text(name, value, keep=True)
else:
self._del_sub(name)
def _get_component(self, name):
value = self._get_sub_text(name, '')
if ',' in value:
value = [v.strip() for v in value.split(',')]
return value
def set_family(self, value):
self._set_component('FAMILY', value)
def get_family(self):
return self._get_component('FAMILY')
def set_given(self, value):
self._set_component('GIVEN', value)
def get_given(self):
return self._get_component('GIVEN')
def set_middle(self, value):
print(value)
self._set_component('MIDDLE', value)
def get_middle(self):
return self._get_component('MIDDLE')
def set_prefix(self, value):
self._set_component('PREFIX', value)
def get_prefix(self):
return self._get_component('PREFIX')
def set_suffix(self, value):
self._set_component('SUFFIX', value)
def get_suffix(self):
return self._get_component('SUFFIX')
class Email(ElementBase):
name = 'EMAIL'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400', 'USERID'])
sub_interfaces = set(['USERID'])
bool_interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400'])
class Address(ElementBase):
name = 'ADR'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL',
'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY',
'REGION', 'PCODE', 'CTRY'])
sub_interfaces = set(['POBOX', 'EXTADD', 'STREET', 'LOCALITY',
'REGION', 'PCODE', 'CTRY'])
bool_interfaces = set(['HOME', 'WORK', 'DOM', 'INTL', 'PREF'])
class Telephone(ElementBase):
name = 'TEL'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', 'MSG',
'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS',
'PREF', 'NUMBER'])
sub_interfaces = set(['NUMBER'])
bool_interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER',
'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM',
'ISDN', 'PCS', 'PREF'])
def setup(self, xml=None):
super(Telephone, self).setup(xml=xml)
self._set_sub_text('NUMBER', '', keep=True)
def set_number(self, value):
self._set_sub_text('NUMBER', value, keep=True)
def del_number(self):
self._set_sub_text('NUMBER', '', keep=True)
class Label(ElementBase):
name = 'LABEL'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT',
'PREF', 'lines'])
bool_interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM',
'INT', 'PREF'])
def add_line(self, value):
line = ET.Element('{%s}LINE' % self.namespace)
line.text = value
self.xml.append(line)
def get_lines(self):
lines = self.xml.find('{%s}LINE' % self.namespace)
if lines is None:
return []
return [line.text for line in lines]
def set_lines(self, values):
self.del_lines()
for line in values:
self.add_line(line)
def del_lines(self):
lines = self.xml.find('{%s}LINE' % self.namespace)
if lines is None:
return
for line in lines:
self.xml.remove(line)
class Geo(ElementBase):
name = 'GEO'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['LAT', 'LON'])
sub_interfaces = interfaces
class Org(ElementBase):
name = 'ORG'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['ORGNAME', 'ORGUNIT', 'orgunits'])
sub_interfaces = set(['ORGNAME', 'ORGUNIT'])
def add_orgunit(self, value):
orgunit = ET.Element('{%s}ORGUNIT' % self.namespace)
orgunit.text = value
self.xml.append(orgunit)
def get_orgunits(self):
orgunits = self.xml.find('{%s}ORGUNIT' % self.namespace)
if orgunits is None:
return []
return [orgunit.text for orgunit in orgunits]
def set_orgunits(self, values):
self.del_orgunits()
for orgunit in values:
self.add_orgunit(orgunit)
def del_orgunits(self):
orgunits = self.xml.find('{%s}ORGUNIT' % self.namespace)
if orgunits is None:
return
for orgunit in orgunits:
self.xml.remove(orgunit)
class Photo(ElementBase):
name = 'PHOTO'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['TYPE', 'EXTVAL'])
sub_interfaces = interfaces
class Logo(ElementBase):
name = 'LOGO'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['TYPE', 'EXTVAL'])
sub_interfaces = interfaces
class Sound(ElementBase):
name = 'LOGO'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['PHONETC', 'EXTVAL'])
sub_interfaces = interfaces
class BinVal(ElementBase):
name = 'BINVAL'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['BINVAL'])
is_extension = True
def setup(self, xml=None):
self.xml = ET.Element('')
return True
def set_binval(self, value):
self.del_binval()
parent = self.parent()
if value:
xml = ET.Element('{%s}BINVAL' % self.namespace)
xml.text = bytes(base64.b64encode(value)).decode('utf-8')
parent.append(xml)
def get_binval(self):
parent = self.parent()
xml = parent.find('{%s}BINVAL' % self.namespace)
if xml is not None:
return base64.b64decode(bytes(xml.text))
return b''
def del_binval(self):
self.parent()._del_sub('{%s}BINVAL' % self.namespace)
class Classification(ElementBase):
name = 'CLASS'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['PUBLIC', 'PRIVATE', 'CONFIDENTIAL'])
bool_interfaces = interfaces
class Categories(ElementBase):
name = 'CATEGORIES'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_categories(self, values):
self.del_categories()
for keyword in values:
item = ET.Element('{%s}KEYWORD' % self.namespace)
item.text = keyword
self.xml.append(item)
def get_categories(self):
items = self.xml.findall('{%s}KEYWORD' % self.namespace)
if items is None:
return []
keywords = []
for item in items:
keywords.append(item.text)
return keywords
def del_categories(self):
items = self.xml.findall('{%s}KEYWORD' % self.namespace)
for item in items:
self.xml.remove(item)
class Birthday(ElementBase):
name = 'BDAY'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_bday(self, value):
if isinstance(value, dt.datetime):
value = xep_0082.format_datetime(value)
self.xml.text = value
def get_bday(self):
if not self.xml.text:
return None
return xep_0082.parse(self.xml.text)
class Rev(ElementBase):
name = 'REV'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_rev(self, value):
if isinstance(value, dt.datetime):
value = xep_0082.format_datetime(value)
self.xml.text = value
def get_rev(self):
if not self.xml.text:
return None
return xep_0082.parse(self.xml.text)
class Title(ElementBase):
name = 'TITLE'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_title(self, value):
self.xml.text = value
def get_title(self):
return self.xml.text
class Role(ElementBase):
name = 'ROLE'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_role(self, value):
self.xml.text = value
def get_role(self):
return self.xml.text
class Note(ElementBase):
name = 'NOTE'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_note(self, value):
self.xml.text = value
def get_note(self):
return self.xml.text
class Desc(ElementBase):
name = 'DESC'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_desc(self, value):
self.xml.text = value
def get_desc(self):
return self.xml.text
class URL(ElementBase):
name = 'URL'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_url(self, value):
self.xml.text = value
def get_url(self):
return self.xml.text
class UID(ElementBase):
name = 'UID'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_uid(self, value):
self.xml.text = value
def get_uid(self):
return self.xml.text
class ProdID(ElementBase):
name = 'PRODID'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_prodid(self, value):
self.xml.text = value
def get_prodid(self):
return self.xml.text
class Mailer(ElementBase):
name = 'MAILER'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_mailer(self, value):
self.xml.text = value
def get_mailer(self):
return self.xml.text
class SortString(ElementBase):
name = 'SORT-STRING'
namespace = 'vcard-temp'
plugin_attrib = 'SORT_STRING'
interfaces = set([name])
is_extension = True
def set_sort_string(self, value):
self.xml.text = value
def get_sort_string(self):
return self.xml.text
class Agent(ElementBase):
name = 'AGENT'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set(['EXTVAL'])
sub_interfaces = interfaces
class JabberID(ElementBase):
name = 'JABBERID'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_jabberid(self, value):
self.xml.text = JID(value).bare
def get_jabberid(self):
return JID(self.xml.text)
class TimeZone(ElementBase):
name = 'TZ'
namespace = 'vcard-temp'
plugin_attrib = name
interfaces = set([name])
is_extension = True
def set_tz(self, value):
time = xep_0082.time(offset=value)
if time[-1] == 'Z':
self.xml.text = 'Z'
else:
self.xml.text = time[-6:]
def get_tz(self):
if not self.xml.text:
return xep_0082.tzutc()
time = xep_0082.parse('00:00:00%s' % self.xml.text)
return time.tzinfo
register_stanza_plugin(VCardTemp, Name)
register_stanza_plugin(VCardTemp, Address, iterable=True)
register_stanza_plugin(VCardTemp, Agent, iterable=True)
register_stanza_plugin(VCardTemp, Birthday, iterable=True)
register_stanza_plugin(VCardTemp, Categories, iterable=True)
register_stanza_plugin(VCardTemp, Desc, iterable=True)
register_stanza_plugin(VCardTemp, Email, iterable=True)
register_stanza_plugin(VCardTemp, Geo, iterable=True)
register_stanza_plugin(VCardTemp, JabberID, iterable=True)
register_stanza_plugin(VCardTemp, Label, iterable=True)
register_stanza_plugin(VCardTemp, Logo, iterable=True)
register_stanza_plugin(VCardTemp, Mailer, iterable=True)
register_stanza_plugin(VCardTemp, Note, iterable=True)
register_stanza_plugin(VCardTemp, Photo, iterable=True)
register_stanza_plugin(VCardTemp, ProdID, iterable=True)
register_stanza_plugin(VCardTemp, Rev, iterable=True)
register_stanza_plugin(VCardTemp, Role, iterable=True)
register_stanza_plugin(VCardTemp, SortString, iterable=True)
register_stanza_plugin(VCardTemp, Sound, iterable=True)
register_stanza_plugin(VCardTemp, Telephone, iterable=True)
register_stanza_plugin(VCardTemp, Title, iterable=True)
register_stanza_plugin(VCardTemp, TimeZone, iterable=True)
register_stanza_plugin(VCardTemp, UID, iterable=True)
register_stanza_plugin(VCardTemp, URL, iterable=True)
register_stanza_plugin(Photo, BinVal)
register_stanza_plugin(Logo, BinVal)
register_stanza_plugin(Sound, BinVal)
register_stanza_plugin(Agent, VCardTemp)

View file

@ -0,0 +1,118 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
from sleekxmpp import Iq
from sleekxmpp.exceptions import XMPPError
from sleekxmpp.xmlstream import register_stanza_plugin
from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.xmlstream.matcher import StanzaPath
from sleekxmpp.plugins import BasePlugin
from sleekxmpp.plugins.xep_0054 import VCardTemp, stanza
log = logging.getLogger(__name__)
class XEP_0054(BasePlugin):
"""
XEP-0054: vcard-temp
"""
name = 'xep_0054'
description = 'XEP-0054: vcard-temp'
dependencies = set(['xep_0030', 'xep_0082'])
stanza = stanza
def plugin_init(self):
"""
Start the XEP-0054 plugin.
"""
register_stanza_plugin(Iq, VCardTemp)
self.xmpp['xep_0030'].add_feature('vcard-temp')
self.api.register(self._set_vcard, 'set_vcard', default=True)
self.api.register(self._get_vcard, 'get_vcard', default=True)
self.api.register(self._del_vcard, 'del_vcard', default=True)
self._vcard_cache = {}
self.xmpp.register_handler(
Callback('VCardTemp',
StanzaPath('iq/vcard_temp'),
self._handle_get_vcard))
def make_vcard(self):
return VCardTemp()
def get_vcard(self, jid=None, ifrom=None, local=False, cached=False,
block=True, callback=None, timeout=None):
if self.xmpp.is_component and jid.bare == self.xmpp.boundjid.bare:
local = True
if local or cached:
vcard = self.api['get_vcard'](jid, None, ifrom)
if not isinstance(vcard, Iq):
iq = self.xmpp.Iq()
iq.append(vcard)
return iq
return vcard
iq = self.xmpp.Iq()
iq['to'] = jid
iq['from'] = ifrom
iq['type'] = 'get'
iq.enable('vcard_temp')
vcard = iq.send(block=block, callback=callback, timeout=timeout)
self.api['set_vcard'](vcard['from'], args=vcard['vcard_temp'])
return vcard
def publish_vcard(self, vcard=None, jid=None, block=True, ifrom=None,
callback=None, timeout=None):
if self.xmpp.is_component:
self.api['set_vcard'](jid, None, ifrom, vcard)
return
iq = self.xmpp.Iq()
iq['to'] = jid
iq['from'] = ifrom
iq['type'] = 'set'
iq.append(vcard)
return iq.send(block=block, callback=callback, timeout=timeout)
def _handle_get_vcard(self, iq):
if iq['type'] == 'result':
self.api['set_vcard'](jid=iq['from'], args=iq['vcard_temp'])
return
elif iq['type'] == 'get':
vcard = self.api['get_vard'](iq['from'].bare)
if isinstance(vcard, Iq):
vcard.send()
else:
iq.reply()
iq.append(vcard)
iq.send()
else:
raise XMPPError('service-unavailable')
# =================================================================
def _set_vcard(self, jid, node, ifrom, vcard):
self._vcard_cache[jid.bare] = vcard
def _get_vcard(self, jid, node, ifrom, vcard):
return self._vcard_cache.get(jid.bare, VCardTemp())
def _del_vcard(self, jid, node, ifrom, vcard):
if jid.bare in self._vcard_cache:
del self._vcard_cache[jid.bare]