summaryrefslogtreecommitdiff
path: root/sleekxmpp/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'sleekxmpp/plugins')
-rw-r--r--sleekxmpp/plugins/__init__.py4
-rw-r--r--sleekxmpp/plugins/gmail_notify.py25
-rw-r--r--sleekxmpp/plugins/jobs.py10
-rw-r--r--sleekxmpp/plugins/old_0004.py80
-rw-r--r--sleekxmpp/plugins/xep_0004.py27
-rw-r--r--sleekxmpp/plugins/xep_0012.py7
-rw-r--r--sleekxmpp/plugins/xep_0030.py608
-rw-r--r--sleekxmpp/plugins/xep_0045.py89
-rw-r--r--sleekxmpp/plugins/xep_0060.py40
-rw-r--r--sleekxmpp/plugins/xep_0078.py17
-rw-r--r--sleekxmpp/plugins/xep_0085.py23
-rw-r--r--sleekxmpp/plugins/xep_0199.py98
-rw-r--r--sleekxmpp/plugins/xep_0202.py7
13 files changed, 541 insertions, 494 deletions
diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py
index 4dcec8f0..427ab04e 100644
--- a/sleekxmpp/plugins/__init__.py
+++ b/sleekxmpp/plugins/__init__.py
@@ -6,5 +6,5 @@
See the file LICENSE for copying permission.
"""
__all__ = ['xep_0004', 'xep_0012', 'xep_0030', 'xep_0033', 'xep_0045',
- 'xep_0050', 'xep_0078', 'xep_0085', 'xep_0092', 'xep_0199',
- 'gmail_notify', 'xep_0060', 'xep_0202']
+ 'xep_0050', 'xep_0085', 'xep_0092', 'xep_0199', 'gmail_notify',
+ 'xep_0060', 'xep_0202']
diff --git a/sleekxmpp/plugins/gmail_notify.py b/sleekxmpp/plugins/gmail_notify.py
index 7e442346..7e888b90 100644
--- a/sleekxmpp/plugins/gmail_notify.py
+++ b/sleekxmpp/plugins/gmail_notify.py
@@ -14,6 +14,9 @@ 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'
@@ -34,12 +37,12 @@ class MailBox(ElementBase):
namespace = 'google:mail:notify'
name = 'mailbox'
plugin_attrib = 'mailbox'
- interfaces = set(('result-time', 'total-matched', 'total-estimate',
+ 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,
+ for threadXML in self.xml.findall('{%s}%s' % (MailThread.namespace,
MailThread.name)):
threads.append(MailThread(xml=threadXML, parent=None))
return threads
@@ -55,10 +58,10 @@ class MailThread(ElementBase):
namespace = 'google:mail:notify'
name = 'mail-thread-info'
plugin_attrib = 'thread'
- interfaces = set(('tid', 'participation', 'messages', 'date',
+ 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)
@@ -91,13 +94,13 @@ 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,
+ MatchXPath('{%s}iq/{%s}%s' % (self.xmpp.default_ns,
MailBox.namespace,
MailBox.name)),
self.handle_gmail))
@@ -108,7 +111,7 @@ class gmail_notify(base.base_plugin):
NewMail.namespace,
NewMail.name)),
self.handle_new_mail))
-
+
registerStanzaPlugin(Iq, GmailQuery)
registerStanzaPlugin(Iq, MailBox)
registerStanzaPlugin(Iq, NewMail)
@@ -118,12 +121,12 @@ class gmail_notify(base.base_plugin):
def handle_gmail(self, iq):
mailbox = iq['mailbox']
approx = ' approximately' if mailbox['estimated'] else ''
- logging.info('Gmail: Received%s %s emails' % (approx, mailbox['total-matched']))
+ 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):
- logging.info("Gmail: New emails received!")
+ log.info("Gmail: New emails received!")
self.xmpp.event('gmail_notify')
self.checkEmail()
@@ -135,9 +138,9 @@ class gmail_notify(base.base_plugin):
def search(self, query=None, newer=None):
if query is None:
- logging.info("Gmail: Checking for new emails")
+ log.info("Gmail: Checking for new emails")
else:
- logging.info('Gmail: Searching for emails matching: "%s"' % query)
+ log.info('Gmail: Searching for emails matching: "%s"' % query)
iq = self.xmpp.Iq()
iq['type'] = 'get'
iq['to'] = self.xmpp.jid
diff --git a/sleekxmpp/plugins/jobs.py b/sleekxmpp/plugins/jobs.py
index c52e524e..0b93d62e 100644
--- a/sleekxmpp/plugins/jobs.py
+++ b/sleekxmpp/plugins/jobs.py
@@ -3,15 +3,19 @@ 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
@@ -40,7 +44,7 @@ class jobs(base.base_plugin):
iq['psstate']['payload'] = state
result = iq.send()
if result is None or type(result) == types.BooleanType or result['type'] != 'result':
- logging.error("Unable to change %s:%s to %s" % (node, jobid, state))
+ 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
index 651408ae..ade3d682 100644
--- a/sleekxmpp/plugins/old_0004.py
+++ b/sleekxmpp/plugins/old_0004.py
@@ -2,42 +2,46 @@
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 logging
+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')
- logging.warning("This implementation of XEP-0004 is deprecated.")
-
+ 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)
@@ -51,12 +55,12 @@ class FieldContainer(object):
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__')])
@@ -66,13 +70,13 @@ class FieldContainer(object):
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=''):
@@ -85,7 +89,7 @@ class Form(FieldContainer):
self.instructions = instructions
self.reported = []
self.items = []
-
+
def merge(self, form2):
form1 = Form(ftype=self.type)
form1.fromXML(self.getXML(self.type))
@@ -98,18 +102,18 @@ class Form(FieldContainer):
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:
@@ -118,7 +122,7 @@ class Form(FieldContainer):
value = value[0]
result[field.var] = value
return result
-
+
def setValues(self, values={}):
for field in values:
if field in self.field:
@@ -127,10 +131,10 @@ class Form(FieldContainer):
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)
@@ -148,21 +152,21 @@ class Form(FieldContainer):
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:
@@ -175,7 +179,7 @@ class Form(FieldContainer):
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:
@@ -199,7 +203,7 @@ class Form(FieldContainer):
#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:
@@ -217,8 +221,8 @@ class Form(FieldContainer):
for field in self.items:
form.append(field.getXHTML())
return form
-
-
+
+
def makeSubmit(self):
self.setType('submit')
@@ -246,13 +250,13 @@ class FormField(object):
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]
@@ -263,10 +267,10 @@ class FormField(object):
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'):
@@ -291,10 +295,10 @@ class FormField(object):
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', '')
@@ -306,7 +310,7 @@ class FormField(object):
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':
@@ -342,7 +346,7 @@ class FormField(object):
valuexml.text = value
field.append(valuexml)
return field
-
+
def getXHTML(self):
field = ET.Element('div', {'class': 'xmpp-xforms-%s' % self.type})
if self.label:
@@ -414,4 +418,4 @@ class FormField(object):
pass
label.append(formf)
return field
-
+
diff --git a/sleekxmpp/plugins/xep_0004.py b/sleekxmpp/plugins/xep_0004.py
index e8dba74c..b8b7ebfa 100644
--- a/sleekxmpp/plugins/xep_0004.py
+++ b/sleekxmpp/plugins/xep_0004.py
@@ -16,6 +16,9 @@ from .. stanza.message import Message
import types
+log = logging.getLogger(__name__)
+
+
class Form(ElementBase):
namespace = 'jabber:x:data'
name = 'x'
@@ -33,7 +36,7 @@ class Form(ElementBase):
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'
@@ -55,11 +58,11 @@ class Form(ElementBase):
return field
def getXML(self, type='submit'):
- logging.warning("Form.getXML() is deprecated API compatibility with plugins/old_0004.py")
+ log.warning("Form.getXML() is deprecated API compatibility with plugins/old_0004.py")
return self.xml
-
+
def fromXML(self, xml):
- logging.warning("Form.fromXML() is deprecated API compatibility with plugins/old_0004.py")
+ log.warning("Form.fromXML() is deprecated API compatibility with plugins/old_0004.py")
n = Form(xml=xml)
return n
@@ -113,10 +116,10 @@ class Form(ElementBase):
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)
+ fieldsXML = self.xml.findall('{%s}field' % FormField.namespace)
for fieldXML in fieldsXML:
field = FormField(xml=fieldXML)
if use_dict:
@@ -144,7 +147,7 @@ class Form(ElementBase):
def getReported(self):
fields = {}
- fieldsXML = self.xml.findall('{%s}reported/{%s}field' % (self.namespace,
+ fieldsXML = self.xml.findall('{%s}reported/{%s}field' % (self.namespace,
FormField.namespace))
for fieldXML in fieldsXML:
field = FormField(xml=fieldXML)
@@ -197,7 +200,7 @@ class Form(ElementBase):
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:
@@ -212,7 +215,7 @@ class Form(ElementBase):
class FieldAccessor(object):
def __init__(self, form):
self.form = form
-
+
def __getitem__(self, key):
return self.form.getFields(use_dict=True)[key]
@@ -366,21 +369,21 @@ class xep_0004(base.base_plugin):
self.xmpp.registerHandler(
Callback('Data Form',
- MatchXPath('{%s}message/{%s}x' % (self.xmpp.default_ns,
+ 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')
diff --git a/sleekxmpp/plugins/xep_0012.py b/sleekxmpp/plugins/xep_0012.py
index 45ca8a00..d636d4d7 100644
--- a/sleekxmpp/plugins/xep_0012.py
+++ b/sleekxmpp/plugins/xep_0012.py
@@ -16,6 +16,9 @@ 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'
@@ -68,10 +71,10 @@ class xep_0012(base.base_plugin):
def handle_last_activity_query(self, iq):
if iq['type'] == 'get':
- logging.debug("Last activity requested by %s" % iq['from'])
+ log.debug("Last activity requested by %s" % iq['from'])
self.xmpp.event('last_activity_request', iq)
elif iq['type'] == 'result':
- logging.debug("Last activity result from %s" % iq['from'])
+ log.debug("Last activity result from %s" % iq['from'])
self.xmpp.event('last_activity', iq)
def handle_last_activity(self, iq):
diff --git a/sleekxmpp/plugins/xep_0030.py b/sleekxmpp/plugins/xep_0030.py
index a9d8d6a7..a3fac346 100644
--- a/sleekxmpp/plugins/xep_0030.py
+++ b/sleekxmpp/plugins/xep_0030.py
@@ -13,315 +13,317 @@ 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)
+ 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)
-
+ 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))
+ """
+ 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':
- logging.debug("Items requested by %s" % iq['from'])
- self.xmpp.event('disco_items_request', iq)
- elif iq['type'] == 'result':
- logging.debug("Items result from %s" % iq['from'])
- self.xmpp.event('disco_items', iq)
-
- def handle_info_query(self, iq):
- if iq['type'] == 'get':
- logging.debug("Info requested by %s" % iq['from'])
- self.xmpp.event('disco_info_request', iq)
- elif iq['type'] == 'result':
- logging.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.
- """
- handlers = self.xmpp.event_handlers['disco_info_request']
- if not forwarded and len(handlers) > 1:
- return
-
- node_name = iq['disco_info']['node']
- if not node_name:
- node_name = 'main'
-
- logging.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:
- logging.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.
- """
- handlers = self.xmpp.event_handlers['disco_items_request']
- if not forwarded and len(handlers) > 1:
- return
-
- node_name = iq['disco_items']['node']
- if not node_name:
- node_name = 'main'
-
- logging.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:
- logging.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)
+ """
+ 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_0045.py b/sleekxmpp/plugins/xep_0045.py
index bf472a46..db41cdb3 100644
--- a/sleekxmpp/plugins/xep_0045.py
+++ b/sleekxmpp/plugins/xep_0045.py
@@ -2,7 +2,7 @@
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
@@ -15,6 +15,10 @@ 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'
@@ -34,79 +38,79 @@ class MUCPresence(ElementBase):
#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):
- logging.warning("Cannot set nick through mucpresence plugin.")
+ log.warning("Cannot set nick through mucpresence plugin.")
return self
-
+
def setRoom(self, value):
- logging.warning("Cannot set room through mucpresence plugin.")
+ log.warning("Cannot set room through mucpresence plugin.")
return self
-
+
def delNick(self):
- logging.warning("Cannot delete nick through mucpresence plugin.")
+ log.warning("Cannot delete nick through mucpresence plugin.")
return self
-
+
def delRoom(self):
- logging.warning("Cannot delete room through mucpresence plugin.")
+ 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 = {}
@@ -116,7 +120,8 @@ class xep_0045(base.base_plugin):
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.
"""
@@ -135,27 +140,33 @@ class xep_0045(base.base_plugin):
if entry['nick'] not in self.rooms[entry['room']]:
got_online = True
self.rooms[entry['room']][entry['nick']] = entry
- logging.debug("MUC presence from %s/%s : %s" % (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]
@@ -176,12 +187,12 @@ class xep_0045(base.base_plugin):
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')
+ #form.addField('FORM_TYPE', value='http://jabber.org/protocol/muc#roomconfig')
iq = self.xmpp.makeIqSet()
iq['to'] = room
if ifrom is not None:
@@ -194,7 +205,7 @@ class xep_0045(base.base_plugin):
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.
"""
@@ -220,7 +231,7 @@ class xep_0045(base.base_plugin):
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:
@@ -246,9 +257,9 @@ class xep_0045(base.base_plugin):
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})
+ item = ET.Element('item', {'affiliation':affiliation, 'nick':nick})
else:
- item = ET.Element('item', {'affiliation':affiliation, 'jid':jid})
+ item = ET.Element('item', {'affiliation':affiliation, 'jid':jid})
query.append(item)
iq = self.xmpp.makeIqSet(query)
iq['to'] = room
@@ -256,7 +267,7 @@ class xep_0045(base.base_plugin):
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)
@@ -279,7 +290,7 @@ class xep_0045(base.base_plugin):
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
@@ -291,14 +302,14 @@ class xep_0045(base.base_plugin):
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')
@@ -307,15 +318,15 @@ class xep_0045(base.base_plugin):
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.
@@ -324,7 +335,7 @@ class xep_0045(base.base_plugin):
return self.rooms[room][nick][jidProperty]
else:
return None
-
+
def getRoster(self, room):
""" Get the list of nicks in a room.
"""
diff --git a/sleekxmpp/plugins/xep_0060.py b/sleekxmpp/plugins/xep_0060.py
index 0b056f0b..a7c6d023 100644
--- a/sleekxmpp/plugins/xep_0060.py
+++ b/sleekxmpp/plugins/xep_0060.py
@@ -6,6 +6,10 @@ 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
@@ -14,7 +18,7 @@ class xep_0060(base.base_plugin):
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')
@@ -52,7 +56,7 @@ class xep_0060(base.base_plugin):
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')
@@ -72,7 +76,7 @@ class xep_0060(base.base_plugin):
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')
@@ -92,7 +96,7 @@ class xep_0060(base.base_plugin):
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:
@@ -110,17 +114,17 @@ class xep_0060(base.base_plugin):
#self.xmpp.add_handler("<iq id='%s'/>" % id, self.handlerCreateNodeResponse)
result = iq.send()
if result is None or result == False or result['type'] == 'error':
- logging.warning("got error instead of config")
+ 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:
- logging.error("No form found.")
+ 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')
@@ -133,7 +137,7 @@ class xep_0060(base.base_plugin):
id = iq['id']
result = iq.send()
if result is None or result == False or result['type'] == 'error':
- logging.warning("got error instead of config")
+ 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')
@@ -156,7 +160,7 @@ class xep_0060(base.base_plugin):
id = iq['id']
result = iq.send()
if result is None or result == False or result['type'] == 'error':
- logging.warning("got error instead of config")
+ 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')
@@ -181,8 +185,8 @@ class xep_0060(base.base_plugin):
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')
@@ -195,10 +199,10 @@ class xep_0060(base.base_plugin):
iq.attrib['from'] = self.xmpp.fulljid
id = iq['id']
result = iq.send()
- if result is None or result['type'] == 'error':
+ 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')
@@ -218,7 +222,7 @@ class xep_0060(base.base_plugin):
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)
@@ -237,7 +241,7 @@ class xep_0060(base.base_plugin):
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')
@@ -246,7 +250,7 @@ class xep_0060(base.base_plugin):
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')
@@ -264,7 +268,7 @@ class xep_0060(base.base_plugin):
try:
config.field['pubsub#collection'].setValue(parent)
except KeyError:
- logging.warning("pubsub#collection doesn't exist in config, trying to add it")
+ 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
@@ -298,7 +302,7 @@ class xep_0060(base.base_plugin):
try:
config.field['pubsub#collection'].setValue(parent)
except KeyError:
- logging.warning("pubsub#collection doesn't exist in config, trying to add it")
+ 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
diff --git a/sleekxmpp/plugins/xep_0078.py b/sleekxmpp/plugins/xep_0078.py
index 4b3ab829..d2c81b16 100644
--- a/sleekxmpp/plugins/xep_0078.py
+++ b/sleekxmpp/plugins/xep_0078.py
@@ -2,7 +2,7 @@
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
@@ -12,6 +12,9 @@ import hashlib
from . import base
+log = logging.getLogger(__name__)
+
+
class xep_0078(base.base_plugin):
"""
XEP-0078 NON-SASL Authentication
@@ -23,14 +26,14 @@ class xep_0078(base.base_plugin):
#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):
- logging.debug("Starting jabber:iq:auth Authentication")
+ 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
@@ -47,12 +50,12 @@ class xep_0078(base.base_plugin):
query.append(username)
query.append(resource)
if rquery.find('{jabber:iq:auth}digest') is None:
- logging.warning("Authenticating via jabber:iq:auth Plain.")
+ log.warning("Authenticating via jabber:iq:auth Plain.")
password = ET.Element('password')
password.text = self.xmpp.password
query.append(password)
else:
- logging.debug("Authenticating via jabber:iq:auth Digest")
+ 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)
@@ -64,6 +67,6 @@ class xep_0078(base.base_plugin):
self.xmpp.sessionstarted = True
self.xmpp.event("session_start")
else:
- logging.info("Authentication failed")
+ 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
index b7b5d6dd..3627e718 100644
--- a/sleekxmpp/plugins/xep_0085.py
+++ b/sleekxmpp/plugins/xep_0085.py
@@ -14,15 +14,18 @@ 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')
@@ -67,11 +70,11 @@ 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'),
@@ -79,10 +82,10 @@ class xep_0085(base.base_plugin):
('Paused Chat State', 'paused')]
for handler in handlers:
self.xmpp.registerHandler(
- Callback(handler[0],
- MatchXPath("{%s}message/{%s}%s" % (self.xmpp.default_ns,
+ Callback(handler[0],
+ MatchXPath("{%s}message/{%s}%s" % (self.xmpp.default_ns,
ChatState.namespace,
- handler[1])),
+ handler[1])),
self._handleChatState))
registerStanzaPlugin(Message, Active)
@@ -90,12 +93,12 @@ class xep_0085(base.base_plugin):
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
- logging.debug("Chat State: %s, %s" % (state, msg['from'].jid))
+ log.debug("Chat State: %s, %s" % (state, msg['from'].jid))
self.xmpp.event('chatstate_%s' % state, msg)
diff --git a/sleekxmpp/plugins/xep_0199.py b/sleekxmpp/plugins/xep_0199.py
index 3fc62f55..2e99ae76 100644
--- a/sleekxmpp/plugins/xep_0199.py
+++ b/sleekxmpp/plugins/xep_0199.py
@@ -2,7 +2,7 @@
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
@@ -10,50 +10,54 @@ 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='http://www.xmpp.org/extensions/xep-0199.html#ns'/></iq>" % self.xmpp.default_ns, self.handler_ping, name='XMPP Ping')
- self.running = False
- #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('http://www.xmpp.org/extensions/xep-0199.html#ns')
-
- def handler_pingserver(self, xml):
- if not self.running:
- time.sleep(self.config.get('frequency', 300))
- while self.sendPing(self.xmpp.server, self.config.get('timeout', 30)) is not False:
- time.sleep(self.config.get('frequency', 300))
- logging.debug("Did not recieve ping back in time. Requesting Reconnect.")
- self.xmpp.disconnect(reconnect=True)
-
- def handler_ping(self, xml):
- iq = self.xmpp.makeIqResult(xml.get('id', 'unknown'))
- iq.attrib['to'] = xml.get('from', self.xmpp.server)
- 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('{http://www.xmpp.org/extensions/xep-0199.html#ns}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
+ """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
index c3f81b2e..fe1191ea 100644
--- a/sleekxmpp/plugins/xep_0202.py
+++ b/sleekxmpp/plugins/xep_0202.py
@@ -17,6 +17,9 @@ 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'
@@ -84,10 +87,10 @@ class xep_0202(base.base_plugin):
def handle_entity_time_query(self, iq):
if iq['type'] == 'get':
- logging.debug("Entity time requested by %s" % iq['from'])
+ log.debug("Entity time requested by %s" % iq['from'])
self.xmpp.event('entity_time_request', iq)
elif iq['type'] == 'result':
- logging.debug("Entity time result from %s" % iq['from'])
+ log.debug("Entity time result from %s" % iq['from'])
self.xmpp.event('entity_time', iq)
def handle_entity_time(self, iq):