diff options
author | Lance Stout <lancestout@gmail.com> | 2013-01-21 02:34:22 -0800 |
---|---|---|
committer | Lance Stout <lancestout@gmail.com> | 2013-01-21 02:34:22 -0800 |
commit | bad405bea96405eb952888dc6996b8b40be85ac4 (patch) | |
tree | b5998707d5d8d836eaa807f1e755047c1aed5c48 /sleekxmpp/plugins | |
parent | 648f3f978a84445ed188be055453ac4cab3ed4f5 (diff) | |
parent | 4f9a95b011277ab64a137aceeb4df2e9fc0f1e25 (diff) | |
download | slixmpp-bad405bea96405eb952888dc6996b8b40be85ac4.tar.gz slixmpp-bad405bea96405eb952888dc6996b8b40be85ac4.tar.bz2 slixmpp-bad405bea96405eb952888dc6996b8b40be85ac4.tar.xz slixmpp-bad405bea96405eb952888dc6996b8b40be85ac4.zip |
Merge branch 'master' into develop
Diffstat (limited to 'sleekxmpp/plugins')
-rw-r--r-- | sleekxmpp/plugins/__init__.py | 2 | ||||
-rw-r--r-- | sleekxmpp/plugins/gmail/__init__.py | 15 | ||||
-rw-r--r-- | sleekxmpp/plugins/gmail/notifications.py | 77 | ||||
-rw-r--r-- | sleekxmpp/plugins/gmail/stanza.py | 101 | ||||
-rw-r--r-- | sleekxmpp/plugins/gmail_notify.py | 149 | ||||
-rw-r--r-- | sleekxmpp/plugins/google_nosave/__init__.py | 15 | ||||
-rw-r--r-- | sleekxmpp/plugins/google_nosave/nosave.py | 83 | ||||
-rw-r--r-- | sleekxmpp/plugins/google_nosave/stanza.py | 59 | ||||
-rw-r--r-- | sleekxmpp/plugins/google_settings/__init__.py | 15 | ||||
-rw-r--r-- | sleekxmpp/plugins/google_settings/settings.py | 68 | ||||
-rw-r--r-- | sleekxmpp/plugins/google_settings/stanza.py | 110 | ||||
-rw-r--r-- | sleekxmpp/plugins/jobs.py | 49 | ||||
-rw-r--r-- | sleekxmpp/plugins/old_0050.py | 133 | ||||
-rw-r--r-- | sleekxmpp/plugins/old_0060.py | 313 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0092/version.py | 14 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0199/ping.py | 141 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0231/bob.py | 4 |
17 files changed, 622 insertions, 726 deletions
diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py index e240a0d6..c2d89c46 100644 --- a/sleekxmpp/plugins/__init__.py +++ b/sleekxmpp/plugins/__init__.py @@ -12,7 +12,7 @@ from sleekxmpp.plugins.base import register_plugin, load_plugin __all__ = [ # Non-standard - 'gmail_notify', # Gmail searching and notifications + 'gmail', # Gmail searching and notifications # XEPS 'xep_0004', # Data Forms diff --git a/sleekxmpp/plugins/gmail/__init__.py b/sleekxmpp/plugins/gmail/__init__.py new file mode 100644 index 00000000..a87c78bb --- /dev/null +++ b/sleekxmpp/plugins/gmail/__init__.py @@ -0,0 +1,15 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 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.gmail import stanza +from sleekxmpp.plugins.gmail.notifications import Gmail + + +register_plugin(Gmail) diff --git a/sleekxmpp/plugins/gmail/notifications.py b/sleekxmpp/plugins/gmail/notifications.py new file mode 100644 index 00000000..dbc68162 --- /dev/null +++ b/sleekxmpp/plugins/gmail/notifications.py @@ -0,0 +1,77 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import logging + +from sleekxmpp.stanza import Iq +from sleekxmpp.xmlstream.handler import Callback +from sleekxmpp.xmlstream.matcher import MatchXPath +from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.plugins import BasePlugin +from sleekxmpp.plugins.gmail import stanza + + +log = logging.getLogger(__name__) + + +class Gmail(BasePlugin): + + """ + Google: Gmail Notifications + + Also see <https://developers.google.com/talk/jep_extensions/gmail>. + """ + + name = 'gmail' + description = 'Google: Gmail Notifications' + dependencies = set() + stanza = stanza + + def plugin_init(self): + register_stanza_plugin(Iq, stanza.GmailQuery) + register_stanza_plugin(Iq, stanza.MailBox) + register_stanza_plugin(Iq, stanza.NewMail) + + self.xmpp.register_handler( + Callback('Gmail New Mail', + MatchXPath('{%s}iq/{%s}%s' % ( + self.xmpp.default_ns, + stanza.NewMail.namespace, + stanza.NewMail.name)), + self._handle_new_mail)) + + self._last_result_time = None + + def plugin_end(self): + self.xmpp.remove_handler('Gmail New Mail') + + def _handle_new_mail(self, iq): + log.info("Gmail: New email!") + iq.reply().send() + self.xmpp.event('gmail_notification') + + def check(self, block=True, timeout=None, callback=None): + last_time = self._last_result_time + self._last_result_time = str(int(time.time() * 1000)) + return self.search(newer=last_time, + block=block, + timeout=timeout, + callback=callback) + + def search(self, query=None, newer=None, block=True, + timeout=None, callback=None): + if not query: + log.info('Gmail: Checking for new email') + else: + log.info('Gmail: Searching for emails matching: "%s"', query) + iq = self.xmpp.Iq() + iq['type'] = 'get' + iq['to'] = self.xmpp.boundjid.bare + iq['gmail']['search'] = query + iq['gmail']['newer_than_time'] = newer + return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/gmail/stanza.py b/sleekxmpp/plugins/gmail/stanza.py new file mode 100644 index 00000000..e7e308e1 --- /dev/null +++ b/sleekxmpp/plugins/gmail/stanza.py @@ -0,0 +1,101 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin + + +class GmailQuery(ElementBase): + namespace = 'google:mail:notify' + name = 'query' + plugin_attrib = 'gmail' + interfaces = set(['newer_than_time', 'newer_than_tid', 'search']) + + def get_search(self): + return self._get_attr('q', '') + + def set_search(self, search): + self._set_attr('q', search) + + def del_search(self): + self._del_attr('q') + + def get_newer_than_time(self): + return self._get_attr('newer-than-time', '') + + def set_newer_than_time(self, value): + self._set_attr('newer-than-time', value) + + def del_newer_than_time(self): + self._del_attr('newer-than-time') + + def get_newer_than_tid(self): + return self._get_attr('newer-than-tid', '') + + def set_newer_than_tid(self, value): + self._set_attr('newer-than-tid', value) + + def del_newer_than_tid(self): + self._del_attr('newer-than-tid') + + +class MailBox(ElementBase): + namespace = 'google:mail:notify' + name = 'mailbox' + plugin_attrib = 'gmail_messages' + interfaces = set(['result_time', 'url', 'matched', 'estimate']) + + def get_matched(self): + return self._get_attr('total-matched', '') + + def get_estimate(self): + return self._get_attr('total-estimate', '') == '1' + + def get_result_time(self): + return self._get_attr('result-time', '') + + +class MailThread(ElementBase): + namespace = 'google:mail:notify' + name = 'mail-thread-info' + plugin_attrib = 'thread' + plugin_multi_attrib = 'threads' + interfaces = set(['tid', 'participation', 'messages', 'date', + 'senders', 'url', 'labels', 'subject', 'snippet']) + sub_interfaces = set(['labels', 'subject', 'snippet']) + + def get_senders(self): + result = [] + senders = self.xml.findall('{%s}senders/{%s}sender' % ( + self.namespace, self.namespace)) + + for sender in senders: + result.append(MailSender(xml=sender)) + + return result + + +class MailSender(ElementBase): + namespace = 'google:mail:notify' + name = 'sender' + plugin_attrib = name + interfaces = set(['address', 'name', 'originator', 'unread']) + + def get_originator(self): + return self.xml.attrib.get('originator', '0') == '1' + + def get_unread(self): + return self.xml.attrib.get('unread', '0') == '1' + + +class NewMail(ElementBase): + namespace = 'google:mail:notify' + name = 'new-mail' + plugin_attrib = 'gmail_notification' + + +register_stanza_plugin(MailBox, MailThread, iterable=True) diff --git a/sleekxmpp/plugins/gmail_notify.py b/sleekxmpp/plugins/gmail_notify.py deleted file mode 100644 index fc97a2ab..00000000 --- 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.boundjid.bare - iq['gmail']['q'] = query - iq['gmail']['newer-than-time'] = newer - return iq.send() diff --git a/sleekxmpp/plugins/google_nosave/__init__.py b/sleekxmpp/plugins/google_nosave/__init__.py new file mode 100644 index 00000000..eba50a35 --- /dev/null +++ b/sleekxmpp/plugins/google_nosave/__init__.py @@ -0,0 +1,15 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 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.google_nosave import stanza +from sleekxmpp.plugins.google_nosave.nosave import GoogleNoSave + + +register_plugin(GoogleNoSave) diff --git a/sleekxmpp/plugins/google_nosave/nosave.py b/sleekxmpp/plugins/google_nosave/nosave.py new file mode 100644 index 00000000..1d3b36db --- /dev/null +++ b/sleekxmpp/plugins/google_nosave/nosave.py @@ -0,0 +1,83 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import logging + +from sleekxmpp.stanza import Iq, Message +from sleekxmpp.xmlstream.handler import Callback +from sleekxmpp.xmlstream.matcher import StanzaPath +from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.plugins import BasePlugin +from sleekxmpp.plugins.google_nosave import stanza + + +log = logging.getLogger(__name__) + + +class GoogleNoSave(BasePlugin): + + """ + Google: Off the Record Chats + + NOTE: This is NOT an encryption method. + + Also see <https://developers.google.com/talk/jep_extensions/otr>. + """ + + name = 'google_nosave' + description = 'Google: Off the Record Chats' + dependencies = set(['google_settings']) + stanza = stanza + + def plugin_init(self): + register_stanza_plugin(Message, stanza.NoSave) + register_stanza_plugin(Iq, stanza.NoSaveQuery) + + self.xmpp.register_handler( + Callback('Google Nosave', + StanzaPath('iq@type=set/google_nosave'), + self._handle_nosave_change)) + + def plugin_end(self): + self.xmpp.remove_handler('Google Nosave') + + def enable(self, jid=None, block=True, timeout=None, callback=None): + if jid is None: + self.xmpp['google_settings'].update({'archiving_enabled': False}, + block=block, timeout=timeout, callback=callback) + else: + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq['google_nosave']['item']['jid'] = jid + iq['google_nosave']['item']['value'] = True + return iq.send(block=block, timeout=timeout, callback=callback) + + def disable(self, jid=None, block=True, timeout=None, callback=None): + if jid is None: + self.xmpp['google_settings'].update({'archiving_enabled': True}, + block=block, timeout=timeout, callback=callback) + else: + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq['google_nosave']['item']['jid'] = jid + iq['google_nosave']['item']['value'] = False + return iq.send(block=block, timeout=timeout, callback=callback) + + def get(self, block=True, timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'get' + iq.enable('google_nosave') + return iq.send(block=block, timeout=timeout, callback=callback) + + def _handle_nosave_change(self, iq): + reply = self.xmpp.Iq() + reply['type'] = 'result' + reply['id'] = iq['id'] + reply['to'] = iq['from'] + reply.send() + self.xmpp.event('google_nosave_change', iq) diff --git a/sleekxmpp/plugins/google_nosave/stanza.py b/sleekxmpp/plugins/google_nosave/stanza.py new file mode 100644 index 00000000..d8701322 --- /dev/null +++ b/sleekxmpp/plugins/google_nosave/stanza.py @@ -0,0 +1,59 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.jid import JID +from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin + + +class NoSave(ElementBase): + name = 'x' + namespace = 'google:nosave' + plugin_attrib = 'google_nosave' + interfaces = set(['value']) + + def get_value(self): + return self._get_attr('value', '') == 'enabled' + + def set_value(self, value): + self._set_attr('value', 'enabled' if value else 'disabled') + + +class NoSaveQuery(ElementBase): + name = 'query' + namespace = 'google:nosave' + plugin_attrib = 'google_nosave' + interfaces = set() + + +class Item(ElementBase): + name = 'item' + namespace = 'google:nosave' + plugin_attrib = 'item' + plugin_multi_attrib = 'items' + interfaces = set(['jid', 'source', 'value']) + + def get_value(self): + return self._get_attr('value', '') == 'enabled' + + def set_value(self, value): + self._set_attr('value', 'enabled' if value else 'disabled') + + def get_jid(self): + return JID(self._get_attr('jid', '')) + + def set_jid(self, value): + self._set_attr('jid', str(value)) + + def get_source(self): + return JID(self._get_attr('source', '')) + + def set_source(self): + self._set_attr('source', str(value)) + + +register_stanza_plugin(NoSaveQuery, Item) diff --git a/sleekxmpp/plugins/google_settings/__init__.py b/sleekxmpp/plugins/google_settings/__init__.py new file mode 100644 index 00000000..ef4b2342 --- /dev/null +++ b/sleekxmpp/plugins/google_settings/__init__.py @@ -0,0 +1,15 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 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.google_settings import stanza +from sleekxmpp.plugins.google_settings.settings import GoogleSettings + + +register_plugin(GoogleSettings) diff --git a/sleekxmpp/plugins/google_settings/settings.py b/sleekxmpp/plugins/google_settings/settings.py new file mode 100644 index 00000000..6bd209c7 --- /dev/null +++ b/sleekxmpp/plugins/google_settings/settings.py @@ -0,0 +1,68 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import logging + +from sleekxmpp.stanza import Iq +from sleekxmpp.xmlstream.handler import Callback +from sleekxmpp.xmlstream.matcher import StanzaPath +from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.plugins import BasePlugin +from sleekxmpp.plugins.google_settings import stanza + + +log = logging.getLogger(__name__) + + +class GoogleSettings(BasePlugin): + + """ + Google: Gmail Notifications + + Also see <https://developers.google.com/talk/jep_extensions/usersettings>. + """ + + name = 'google_settings' + description = 'Google: User Settings' + dependencies = set() + stanza = stanza + + def plugin_init(self): + register_stanza_plugin(Iq, stanza.UserSettings) + + self.xmpp.register_handler( + Callback('Google Settings', + StanzaPath('iq@type=set/google_settings'), + self._handle_settings_change)) + + def plugin_end(self): + self.xmpp.remove_handler('Google Settings') + + def get(self, block=True, timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'get' + iq.enable('google_settings') + return iq.send(block=block, timeout=timeout, callback=callback) + + def update(self, settings, block=True, timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq.enable('google_settings') + + for setting, value in settings.items(): + iq['google_settings'][setting] = value + + return iq.send(block=block, timeout=timeout, callback=callback) + + def _handle_settings_change(self, iq): + reply = self.xmpp.Iq() + reply['type'] = 'result' + reply['id'] = iq['id'] + reply['to'] = iq['from'] + reply.send() + self.xmpp.event('google_settings_change', iq) diff --git a/sleekxmpp/plugins/google_settings/stanza.py b/sleekxmpp/plugins/google_settings/stanza.py new file mode 100644 index 00000000..d8161770 --- /dev/null +++ b/sleekxmpp/plugins/google_settings/stanza.py @@ -0,0 +1,110 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin + + +class UserSettings(ElementBase): + name = 'usersetting' + namespace = 'google:setting' + plugin_attrib = 'google_settings' + interfaces = set(['auto_accept_suggestions', + 'mail_notifications', + 'archiving_enabled', + 'gmail', + 'email_verified', + 'domain_privacy_notice', + 'display_name']) + + def _get_setting(self, setting): + xml = self.xml.find('{%s}%s' % (self.namespace, setting)) + if xml is not None: + return xml.attrib.get('value', '') == 'true' + return False + + def _set_setting(self, setting, value): + self._del_setting(setting) + if value in (True, False): + xml = ET.Element('{%s}%s' % (self.namespace, setting)) + xml.attrib['value'] = 'true' if value else 'false' + self.xml.append(xml) + + def _del_setting(self, setting): + xml = self.xml.find('{%s}%s' % (self.namespace, setting)) + if xml is not None: + self.xml.remove(xml) + + def get_display_name(self): + xml = self.xml.find('{%s}%s' % (self.namespace, 'displayname')) + if xml is not None: + return xml.attrib.get('value', '') + return '' + + def set_display_name(self, value): + self._del_setting(setting) + if value: + xml = ET.Element('{%s}%s' % (self.namespace, 'displayname')) + xml.attrib['value'] = value + self.xml.append(xml) + + def del_display_name(self): + self._del_setting('displayname') + + def get_auto_accept_suggestions(self): + return self._get_setting('autoacceptsuggestions') + + def get_mail_notifications(self): + return self._get_setting('mailnotifications') + + def get_archiving_enabled(self): + return self._get_setting('archivingenabled') + + def get_gmail(self): + return self._get_setting('gmail') + + def get_email_verified(self): + return self._get_setting('emailverified') + + def get_domain_privacy_notice(self): + return self._get_setting('domainprivacynotice') + + def set_auto_accept_suggestions(self, value): + self._set_setting('autoacceptsuggestions', value) + + def set_mail_notifications(self, value): + self._set_setting('mailnotifications', value) + + def set_archiving_enabled(self, value): + self._set_setting('archivingenabled', value) + + def set_gmail(self, value): + self._set_setting('gmail', value) + + def set_email_verified(self, value): + self._set_setting('emailverified', value) + + def set_domain_privacy_notice(self, value): + self._set_setting('domainprivacynotice', value) + + def del_auto_accept_suggestions(self): + self._del_setting('autoacceptsuggestions') + + def del_mail_notifications(self): + self._del_setting('mailnotifications') + + def del_archiving_enabled(self): + self._del_setting('archivingenabled') + + def del_gmail(self): + self._del_setting('gmail') + + def del_email_verified(self): + self._del_setting('emailverified') + + def del_domain_privacy_notice(self): + self._del_setting('domainprivacynotice') diff --git a/sleekxmpp/plugins/jobs.py b/sleekxmpp/plugins/jobs.py deleted file mode 100644 index cb9deba8..00000000 --- a/sleekxmpp/plugins/jobs.py +++ /dev/null @@ -1,49 +0,0 @@ -from . import base -import logging -from xml.etree import cElementTree as ET - - -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) == bool 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_0050.py b/sleekxmpp/plugins/old_0050.py deleted file mode 100644 index 6e969a51..00000000 --- a/sleekxmpp/plugins/old_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 old_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.boundjid.full - 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/old_0060.py b/sleekxmpp/plugins/old_0060.py deleted file mode 100644 index 93124fca..00000000 --- a/sleekxmpp/plugins/old_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.boundjid.full - 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.boundjid.bare - else: - subscribe.attrib['jid'] = self.xmpp.boundjid.full - else: - subscribe.attrib['jid'] = subscribee - pubsub.append(subscribe) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.boundjid.full - 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.boundjid.bare - else: - unsubscribe.attrib['jid'] = self.xmpp.boundjid.full - else: - unsubscribe.attrib['jid'] = subscribee - pubsub.append(unsubscribe) - iq = self.xmpp.makeIqSet(pubsub) - iq.attrib['to'] = jid - iq.attrib['from'] = self.xmpp.boundjid.full - 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.boundjid.full - 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.boundjid.full - 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.boundjid.full - 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.boundjid.full - 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.boundjid.full - 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.boundjid.full - 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.boundjid.full - 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.boundjid.full - 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_0092/version.py b/sleekxmpp/plugins/xep_0092/version.py index 35813e1d..b16ad516 100644 --- a/sleekxmpp/plugins/xep_0092/version.py +++ b/sleekxmpp/plugins/xep_0092/version.py @@ -70,7 +70,7 @@ class XEP_0092(BasePlugin): iq['software_version']['os'] = self.os iq.send() - def get_version(self, jid, ifrom=None): + def get_version(self, jid, ifrom=None, block=True, timeout=None, callback=None): """ Retrieve the software version of a remote agent. @@ -82,14 +82,4 @@ class XEP_0092(BasePlugin): iq['from'] = ifrom iq['type'] = 'get' iq['query'] = Version.namespace - - result = iq.send() - - if result and result['type'] != 'error': - values = result['software_version'].values - del values['lang'] - return values - return False - - -XEP_0092.getVersion = XEP_0092.get_version + return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/xep_0199/ping.py b/sleekxmpp/plugins/xep_0199/ping.py index 0bdeabf3..e095a551 100644 --- a/sleekxmpp/plugins/xep_0199/ping.py +++ b/sleekxmpp/plugins/xep_0199/ping.py @@ -9,8 +9,8 @@ import time import logging -import sleekxmpp -from sleekxmpp import Iq +from sleekxmpp.jid import JID +from sleekxmpp.stanza import Iq from sleekxmpp.exceptions import IqError, IqTimeout from sleekxmpp.xmlstream import register_stanza_plugin from sleekxmpp.xmlstream.matcher import StanzaPath @@ -38,7 +38,7 @@ class XEP_0199(BasePlugin): keepalive -- If True, periodically send ping requests to the server. If a ping is not answered, the connection will be reset. - frequency -- Time in seconds between keepalive pings. + interval -- Time in seconds between keepalive pings. Defaults to 300 seconds. timeout -- Time in seconds to wait for a ping response. Defaults to 30 seconds. @@ -53,7 +53,7 @@ class XEP_0199(BasePlugin): stanza = stanza default_config = { 'keepalive': False, - 'frequency': 300, + 'interval': 300, 'timeout': 30 } @@ -61,6 +61,7 @@ class XEP_0199(BasePlugin): """ Start the XEP-0199 plugin. """ + register_stanza_plugin(Iq, Ping) self.xmpp.register_handler( @@ -70,88 +71,70 @@ class XEP_0199(BasePlugin): if self.keepalive: self.xmpp.add_event_handler('session_start', - self._handle_keepalive, + self.enable_keepalive, threaded=True) self.xmpp.add_event_handler('session_end', - self._handle_session_end) + self.disable_keepalive) def plugin_end(self): self.xmpp['xep_0030'].del_feature(feature=Ping.namespace) self.xmpp.remove_handler('Ping') if self.keepalive: self.xmpp.del_event_handler('session_start', - self._handle_keepalive) + self.enable_keepalive) self.xmpp.del_event_handler('session_end', - self._handle_session_end) + self.disable_keepalive) def session_bind(self, jid): self.xmpp['xep_0030'].add_feature(Ping.namespace) - def _handle_keepalive(self, event): - """ - Begin periodic pinging of the server. If a ping is not - answered, the connection will be restarted. - - The pinging interval can be adjused using self.frequency - before beginning processing. + def enable_keepalive(self, interval=None, timeout=None): + if interval: + self.interval = interval + if timeout: + self.timeout = timeout - Arguments: - event -- The session_start event. - """ - def scheduled_ping(): - """Send ping request to the server.""" - log.debug("Pinging...") - try: - self.send_ping(self.xmpp.boundjid.host, self.timeout) - except IqError: - log.debug("Ping response was an error." + \ - "Requesting Reconnect.") - self.xmpp.reconnect() - except IqTimeout: - log.debug("Did not recieve ping back in time." + \ - "Requesting Reconnect.") - self.xmpp.reconnect() - - self.xmpp.schedule('Ping Keep Alive', - self.frequency, - scheduled_ping, + self.keepalive = True + self.xmpp.schedule('Ping keepalive', + self.interval, + self._keepalive, repeat=True) - def _handle_session_end(self, event): - self.xmpp.scheduler.remove('Ping Keep Alive') + def disable_keepalive(self, event=None): + self.xmpp.scheduler.remove('Ping keepalive') - def _handle_ping(self, iq): - """ - Automatically reply to ping requests. + def _keepalive(self, event): + log.debug("Keepalive ping...") + try: + rtt = self.ping(self.xmpp.boundjid.host, self.timeout) + except IqTimeout: + log.debug("Did not recieve ping back in time." + \ + "Requesting Reconnect.") + self.xmpp.reconnect() + else: + log.debug('Keepalive RTT: %s' % rtt) - Arguments: - iq -- The ping request. - """ + def _handle_ping(self, iq): + """Automatically reply to ping requests.""" log.debug("Pinged by %s", iq['from']) iq.reply().send() - def send_ping(self, jid, timeout=None, errorfalse=False, - ifrom=None, block=True, callback=None): - """ - Send a ping request and calculate the response time. + def send_ping(self, jid, ifrom=None, block=True, timeout=None, callback=None): + """Send a ping request. Arguments: jid -- The JID that will receive the ping. - timeout -- Time in seconds to wait for a response. - Defaults to self.timeout. - errorfalse -- Indicates if False should be returned - if an error stanza is received. Defaults - to False. ifrom -- Specifiy the sender JID. block -- Indicate if execution should block until a pong response is received. Defaults to True. + timeout -- Time in seconds to wait for a response. + Defaults to self.timeout. callback -- Optional handler to execute when a pong is received. Useful in conjunction with the option block=False. """ - log.debug("Pinging %s", jid) - if timeout is None: + if not timeout: timeout = self.timeout iq = self.xmpp.Iq() @@ -160,21 +143,43 @@ class XEP_0199(BasePlugin): iq['from'] = ifrom iq.enable('ping') - start_time = time.clock() + return iq.send(block=block, timeout=timeout, callback=callback) - try: - resp = iq.send(block=block, - timeout=timeout, - callback=callback) - except IqError as err: - resp = err.iq + def ping(self, jid=None, ifrom=None, timeout=None): + """Send a ping request and calculate RTT. - end_time = time.clock() - - delay = end_time - start_time + Arguments: + jid -- The JID that will receive the ping. + ifrom -- Specifiy the sender JID. + timeout -- Time in seconds to wait for a response. + Defaults to self.timeout. + """ + if not jid: + if self.xmpp.is_component: + jid = self.xmpp.server + else: + jid = self.xmpp.boundjid.host + jid = JID(jid) + if jid == self.xmpp.boundjid.host or \ + self.xmpp.is_component and jid == self.xmpp.server: + own_host = True + + if not timeout: + timeout = self.timeout - if not block: - return None + start = time.time() - log.debug("Pong: %s %f", jid, delay) - return delay + log.debug('Pinging %s' % jid) + try: + self.send_ping(jid, ifrom=ifrom, timeout=timeout) + except IqError as e: + if own_host: + rtt = time.time() - start + log.debug('Pinged %s, RTT: %s', jid, rtt) + return rtt + else: + raise e + else: + rtt = time.time() - start + log.debug('Pinged %s, RTT: %s', jid, rtt) + return rtt diff --git a/sleekxmpp/plugins/xep_0231/bob.py b/sleekxmpp/plugins/xep_0231/bob.py index d86a5ddf..5e1f590b 100644 --- a/sleekxmpp/plugins/xep_0231/bob.py +++ b/sleekxmpp/plugins/xep_0231/bob.py @@ -10,7 +10,7 @@ import logging import hashlib -from sleekxmpp.stanza import Iq +from sleekxmpp.stanza import Iq, Message, Presence from sleekxmpp.exceptions import XMPPError from sleekxmpp.xmlstream.handler import Callback from sleekxmpp.xmlstream.matcher import StanzaPath @@ -36,6 +36,8 @@ class XEP_0231(BasePlugin): self._cids = {} register_stanza_plugin(Iq, BitsOfBinary) + register_stanza_plugin(Message, BitsOfBinary) + register_stanza_plugin(Presence, BitsOfBinary) self.xmpp.register_handler( Callback('Bits of Binary - Iq', |