Compare commits
	
		
			88 Commits
		
	
	
		
			slix-1.1
			...
			slix-1.2.4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 24f35e433f | ||
|   | 22664ee7b8 | ||
|   | 6476cfcde5 | ||
|   | 5bb347e884 | ||
|   | eb1251b919 | ||
|   | 820144c40c | ||
|   | 6034df0a78 | ||
|   | df4012e66d | ||
|   | c372f3071a | ||
|   | 829c8b27b6 | ||
|   | fb3ac78bf9 | ||
|   | ffd9436e5c | ||
|   | bbb1344d79 | ||
|   | 457785b286 | ||
|   | 4847f834bd | ||
|   | 53191ff1cf | ||
|   | ffdb6ffd69 | ||
|   | 7560db856b | ||
|   | 63d245ac48 | ||
|   | 7ddd37be29 | ||
|   | a4d3a4a25e | ||
|   | 58bd07628b | ||
|   | 3569038493 | ||
|   | 20c4ff823a | ||
|   | 8a7448a5a1 | ||
|   | d23d8f901e | ||
|   | 391f12eeab | ||
|   | d008988843 | ||
|   | dcacc7d7d5 | ||
|   | c4285961df | ||
|   | 1038f656eb | ||
|   | 3c7236fe73 | ||
|   | 36824379c3 | ||
|   | a0a37c19ff | ||
|   | 1b5fe57a5e | ||
|   | 5da31db0c7 | ||
|   | f8cea760b6 | ||
|   | 5ef01ecdd1 | ||
|   | 62aafe0ee7 | ||
|   | cf3f36ac52 | ||
|   | b88d2ecd77 | ||
|   | e691850a2b | ||
|   | d4bff8dee6 | ||
|   | 187c350805 | ||
|   | 96d1c26f90 | ||
|   | 46a90749f8 | ||
|   | 0c63a4bbda | ||
|   | e4696e0471 | ||
|   | 8217dc5239 | ||
|   | 2586abc0d3 | ||
|   | 28f84ab3d9 | ||
|   | 813b45aded | ||
|   | 3a9b45e4f2 | ||
|   | b8e091233e | ||
|   | 0edeefd977 | ||
|   | 6ba53cf1ff | ||
|   | d7758eb7f4 | ||
|   | 125336aeee | ||
|   | 7cd1cf32ae | ||
|   | d099e353a4 | ||
|   | 1e4a301c6e | ||
|   | f53b12d227 | ||
|   | e2562dcccf | ||
|   | 7b69ae3738 | ||
|   | ab6df235d7 | ||
|   | 52cd8f4b22 | ||
|   | e28318c271 | ||
|   | 39ee833c29 | ||
|   | 9019e2bc71 | ||
|   | 9208bf5bf1 | ||
|   | f0f1698e46 | ||
|   | eccd7f1c98 | ||
|   | 2587d82af8 | ||
|   | 7ea121b115 | ||
|   | bb81fbbdfc | ||
|   | 1a00a08b7d | ||
|   | 90ea2a3411 | ||
|   | 8fc6814b6d | ||
|   | ffced0ed9a | ||
|   | e7248d9af9 | ||
|   | 6b1a04f59d | ||
|   | 4905407092 | ||
|   | bd6ec10939 | ||
|   | e15e6735f1 | ||
|   | 67afd6a462 | ||
|   | 2e2b97c53b | ||
|   | a35df7fe1f | ||
|   | fbc8562779 | 
							
								
								
									
										8
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| test: | ||||
|   tags: | ||||
|     - docker | ||||
|   image: ubuntu:latest | ||||
|   script: | ||||
|     - apt update | ||||
|     - apt install -y python3 cython3 | ||||
|     - ./run_tests.py | ||||
							
								
								
									
										14
									
								
								CONTRIBUTING.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								CONTRIBUTING.rst
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| Contributing to the Slixmpp project | ||||
| =================================== | ||||
|  | ||||
| To contribute, the preferred way is to commit your changes on some | ||||
| publicly-available git repository (on a fork `on github | ||||
| <https://github.com/poezio/slixmpp>`_ or on your own repository) and to | ||||
| notify the developers with either: | ||||
|  - a ticket `on the bug tracker <https://dev.poez.io/new>`_ | ||||
|  - a pull request on github | ||||
|  - a simple message on `the XMPP MUC <xmpp:slixmpp@muc.poez.io>`_ | ||||
|  | ||||
| Even though Slixmpp’s github repository is just a read-only mirror, we can | ||||
| still be notified of the pull requests and fetch your mirror manually to | ||||
| integrate your changes. | ||||
							
								
								
									
										17
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								README.rst
									
									
									
									
									
								
							| @@ -12,8 +12,8 @@ Building | ||||
| -------- | ||||
|  | ||||
| Slixmpp can make use of cython to improve performance on critical modules. | ||||
| To do that, cython3 is necessary along with libidn headers. Otherwise, | ||||
| no compilation is needed. Building is done by running setup.py:: | ||||
| To do that, **cython3** is necessary along with **libidn** headers. | ||||
| Otherwise, no compilation is needed. Building is done by running setup.py:: | ||||
|  | ||||
|     python3 setup.py build_ext --inplace | ||||
|  | ||||
| @@ -102,8 +102,17 @@ Slixmpp projects:: | ||||
| Slixmpp Credits | ||||
| --------------- | ||||
|  | ||||
| **Maintainer of the slixmpp fork:** Florent Le Coz | ||||
|     `louiz@louiz.org <xmpp:louiz@louiz.org?message>`_, | ||||
| **Maintainers:** | ||||
|     - Florent Le Coz (`louiz@louiz.org <xmpp:louiz@louiz.org?message>`_), | ||||
|     - Mathieu Pasquet (`mathieui@mathieui.net <xmpp:mathieui@mathieui.net?message>`_), | ||||
|  | ||||
| **Contributors:** | ||||
|     - Emmanuel Gil Peyrot (`Link mauve <xmpp:linkmauve@linkmauve.fr?message>`_) | ||||
|     - Sam Whited (`Sam Whited <mailto:sam@samwhited.com>`_) | ||||
|     - Dan Sully (`Dan Sully <mailto:daniel@electricalrain.com>`_) | ||||
|     - Gasper Zejn (`Gasper Zejn <mailto:zejn@kiberpipa.org>`_) | ||||
|     - Krzysztof Kotlenga (`Krzysztof Kotlenga <mailto:pocek@users.sf.net>`_) | ||||
|     - Tsukasa Hiiragi (`Tsukasa Hiiragi <mailto:bakalolka@gmail.com>`_) | ||||
|  | ||||
| Credits (SleekXMPP) | ||||
| ------------------- | ||||
|   | ||||
| @@ -163,7 +163,7 @@ behaviour: | ||||
|         namespace = 'jabber:iq:register' | ||||
|         name = 'query' | ||||
|         plugin_attrib = 'register' | ||||
|         interfaces = set(('username', 'password', 'registered', 'remove')) | ||||
|         interfaces = {'username', 'password', 'registered', 'remove'} | ||||
|         sub_interfaces = interfaces | ||||
|  | ||||
|         def getRegistered(self): | ||||
| @@ -535,10 +535,10 @@ with some additional registration fields implemented. | ||||
|         namespace = 'jabber:iq:register' | ||||
|         name = 'query' | ||||
|         plugin_attrib = 'register' | ||||
|         interfaces = set(('username', 'password', 'email', 'nick', 'name', | ||||
|                           'first', 'last', 'address', 'city', 'state', 'zip', | ||||
|                           'phone', 'url', 'date', 'misc', 'text', 'key', | ||||
|                           'registered', 'remove', 'instructions')) | ||||
|         interfaces = {'username', 'password', 'email', 'nick', 'name', | ||||
|                       'first', 'last', 'address', 'city', 'state', 'zip', | ||||
|                       'phone', 'url', 'date', 'misc', 'text', 'key', | ||||
|                       'registered', 'remove', 'instructions'} | ||||
|         sub_interfaces = interfaces | ||||
|  | ||||
|         def getRegistered(self): | ||||
|   | ||||
| @@ -259,8 +259,8 @@ Event Index | ||||
|  | ||||
|         Signal that a connection to the XMPP server has been lost and the current | ||||
|         stream session has ended. Currently equivalent to :term:`disconnected`, but | ||||
|         future implementation of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_ | ||||
|         will distinguish the two events. | ||||
|         implementations of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_ | ||||
|         distinguish between the two events. | ||||
|  | ||||
|         Plugins that maintain session-based state should clear themselves when | ||||
|         this event is fired. | ||||
|   | ||||
| @@ -70,7 +70,7 @@ as well. | ||||
|     class EchoBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|         def __init__(self, jid, password): | ||||
|             super(EchoBot, self).__init__(jid, password) | ||||
|             super().__init__(jid, password) | ||||
|  | ||||
| Handling Session Start | ||||
| ~~~~~~~~~~~~~~~~~~~~~~ | ||||
| @@ -83,7 +83,7 @@ started. To do that, we will register an event handler for the :term:`session_st | ||||
| .. code-block:: python | ||||
|  | ||||
|      def __init__(self, jid, password): | ||||
|         super(EchoBot, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.add_event_handler('session_start', self.start) | ||||
|  | ||||
| @@ -153,7 +153,7 @@ whenever a messsage is received. | ||||
| .. code-block:: python | ||||
|  | ||||
|      def __init__(self, jid, password): | ||||
|         super(EchoBot, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.add_event_handler('session_start', self.start) | ||||
|         self.add_event_handler('message', self.message) | ||||
| @@ -329,7 +329,7 @@ The Final Product | ||||
| ----------------- | ||||
|  | ||||
| Here then is what the final result should look like after working through the guide above. The code | ||||
| can also be found in the Slixmpp `examples directory <http://github.com/fritzy/Slixmpp/tree/master/examples>`_. | ||||
| can also be found in the Slixmpp `examples directory <http://git.poez.io/slixmpp/tree/examples>`_. | ||||
|  | ||||
| .. compound:: | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| .. _mucbot: | ||||
|  | ||||
| ========================= | ||||
| Mulit-User Chat (MUC) Bot | ||||
| Multi-User Chat (MUC) Bot | ||||
| ========================= | ||||
|  | ||||
| .. note:: | ||||
| @@ -63,13 +63,13 @@ has been established: | ||||
|     def start(self, event): | ||||
|         self.get_roster() | ||||
|         self.send_presence() | ||||
|         self.plugin['xep_0045'].joinMUC(self.room, | ||||
|                                         self.nick, | ||||
|                                         wait=True) | ||||
|         self.plugin['xep_0045'].join_muc(self.room, | ||||
|                                          self.nick, | ||||
|                                          wait=True) | ||||
|  | ||||
| Note that as in :ref:`echobot`, we need to include send an initial presence and request | ||||
| the roster. Next, we want to join the group chat, so we call the | ||||
| ``joinMUC`` method of the MUC plugin. | ||||
| ``join_muc`` method of the MUC plugin. | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,7 @@ for the JID that will receive our message, and the string content of the message | ||||
|     class SendMsgBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|         def __init__(self, jid, password, recipient, msg): | ||||
|             super(SendMsgBot, self).__init__(jid, password) | ||||
|             super().__init__(jid, password) | ||||
|  | ||||
|             self.recipient = recipient | ||||
|             self.msg = msg | ||||
|   | ||||
| @@ -61,7 +61,7 @@ operation using these stanzas without doing any complex operations such as | ||||
| checking an ACL, etc. | ||||
|  | ||||
| You may find it necessary at some point to revert a particular node or JID to | ||||
| using the default, static handlers. To do so, use the method ``make_static()``. | ||||
| using the default, static handlers. To do so, use the method ``restore_defaults()``. | ||||
| You may also elect to only convert a given set of actions instead. | ||||
|  | ||||
| Creating a Node Handler | ||||
|   | ||||
| @@ -68,7 +68,7 @@ class CommandBot(slixmpp.ClientXMPP): | ||||
|                        session. Additional, custom data may be saved | ||||
|                        here to persist across handler callbacks. | ||||
|         """ | ||||
|         form = self['xep_0004'].makeForm('form', 'Greeting') | ||||
|         form = self['xep_0004'].make_form('form', 'Greeting') | ||||
|         form['instructions'] = 'Send a custom greeting to a JID' | ||||
|         form.addField(var='greeting', | ||||
|                       ftype='text-single', | ||||
|   | ||||
| @@ -94,7 +94,7 @@ class CommandUserBot(slixmpp.ClientXMPP): | ||||
|         #          label="Your greeting" /> | ||||
|         # </x> | ||||
|  | ||||
|         form = self['xep_0004'].makeForm(ftype='submit') | ||||
|         form = self['xep_0004'].make_form(ftype='submit') | ||||
|         form.addField(var='greeting', | ||||
|                       value=session['greeting']) | ||||
|  | ||||
|   | ||||
							
								
								
									
										100
									
								
								examples/confirm_answer.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										100
									
								
								examples/confirm_answer.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2015 Emmanuel Gil Peyrot | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import XMPPError | ||||
| from slixmpp import asyncio | ||||
|  | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class AnswerConfirm(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic client demonstrating how to confirm or deny an HTTP request. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, trusted): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.add_event_handler("http_confirm", self.confirm) | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     def start(self, *args): | ||||
|         self.make_presence().send() | ||||
|  | ||||
|     def prompt(self, stanza): | ||||
|         confirm = stanza['confirm'] | ||||
|         print('Received confirm request %s from %s to access %s using ' | ||||
|                  'method %s' % ( | ||||
|                      confirm['id'], stanza['from'], confirm['url'], | ||||
|                      confirm['method']) | ||||
|                 ) | ||||
|         result = input("Do you accept (y/N)? ") | ||||
|         return 'y' == result.lower() | ||||
|  | ||||
|     def confirm(self, stanza): | ||||
|         if self.prompt(stanza): | ||||
|             reply = stanza.reply() | ||||
|         else: | ||||
|             reply = stanza.reply() | ||||
|             reply.enable('error') | ||||
|             reply['error']['type'] = 'auth' | ||||
|             reply['error']['code'] = '401' | ||||
|             reply['error']['condition'] = 'not-authorized' | ||||
|         reply.append(stanza['confirm']) | ||||
|         reply.send() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.INFO) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     # Other options. | ||||
|     parser.add_argument("-t", "--trusted", nargs='*', | ||||
|                         help="List of trusted JIDs") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = AnswerConfirm(args.jid, args.password, args.trusted) | ||||
|     xmpp.register_plugin('xep_0070') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
							
								
								
									
										125
									
								
								examples/confirm_ask.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										125
									
								
								examples/confirm_ask.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,125 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2015 Emmanuel Gil Peyrot | ||||
|     This file is part of Slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import sys | ||||
|  | ||||
| import logging | ||||
| from getpass import getpass | ||||
| from argparse import ArgumentParser | ||||
|  | ||||
| import slixmpp | ||||
| from slixmpp.exceptions import XMPPError, IqError | ||||
| from slixmpp import asyncio | ||||
|  | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class AskConfirm(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic client asking an entity if they confirm the access to an HTTP URL. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, recipient, id, url, method): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         self.recipient = recipient | ||||
|         self.id = id | ||||
|         self.url = url | ||||
|         self.method = method | ||||
|  | ||||
|         # Will be used to set the proper exit code. | ||||
|         self.confirmed = asyncio.Future() | ||||
|  | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|         self.add_event_handler("message", self.start) | ||||
|         self.add_event_handler("http_confirm_message", self.confirm) | ||||
|  | ||||
|     def confirm(self, message): | ||||
|         print(message) | ||||
|         if message['confirm']['id'] == self.id: | ||||
|             if message['type'] == 'error': | ||||
|                 self.confirmed.set_result(False) | ||||
|             else: | ||||
|                 self.confirmed.set_result(True) | ||||
|  | ||||
|     @asyncio.coroutine | ||||
|     def start(self, event): | ||||
|         log.info('Sending confirm request %s to %s who wants to access %s using ' | ||||
|                  'method %s...' % (self.id, self.recipient, self.url, self.method)) | ||||
|         try: | ||||
|             confirmed = yield from self['xep_0070'].ask_confirm(self.recipient, | ||||
|                                                                 id=self.id, | ||||
|                                                                 url=self.url, | ||||
|                                                                 method=self.method, | ||||
|                                                                 message='Plz say yes or no for {method} {url} ({id}).') | ||||
|             if isinstance(confirmed, slixmpp.Message): | ||||
|                 confirmed = yield from self.confirmed | ||||
|             else: | ||||
|                 confirmed = True | ||||
|         except IqError: | ||||
|             confirmed = False | ||||
|         if confirmed: | ||||
|             print('Confirmed') | ||||
|         else: | ||||
|             print('Denied') | ||||
|         self.disconnect() | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser() | ||||
|     parser.add_argument("-q","--quiet", help="set logging to ERROR", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.ERROR, | ||||
|                         default=logging.INFO) | ||||
|     parser.add_argument("-d","--debug", help="set logging to DEBUG", | ||||
|                         action="store_const", | ||||
|                         dest="loglevel", | ||||
|                         const=logging.DEBUG, | ||||
|                         default=logging.INFO) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_argument("-j", "--jid", dest="jid", | ||||
|                         help="JID to use") | ||||
|     parser.add_argument("-p", "--password", dest="password", | ||||
|                         help="password to use") | ||||
|  | ||||
|     # Other options. | ||||
|     parser.add_argument("-r", "--recipient", required=True, | ||||
|                         help="Recipient JID") | ||||
|     parser.add_argument("-i", "--id", required=True, | ||||
|                         help="id TODO") | ||||
|     parser.add_argument("-u", "--url", required=True, | ||||
|                         help="URL the user tried to access") | ||||
|     parser.add_argument("-m", "--method", required=True, | ||||
|                         help="HTTP method used") | ||||
|  | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if args.jid is None: | ||||
|         args.jid = input("Username: ") | ||||
|     if args.password is None: | ||||
|         args.password = getpass("Password: ") | ||||
|  | ||||
|     xmpp = AskConfirm(args.jid, args.password, args.recipient, args.id, | ||||
|                       args.url, args.method) | ||||
|     xmpp.register_plugin('xep_0070') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
|     sys.exit(0 if xmpp.confirmed else 1) | ||||
| @@ -41,7 +41,7 @@ class Action(ElementBase): | ||||
|     #:     del action['status'] | ||||
|     #: | ||||
|     #: to set, get, or remove its values. | ||||
|     interfaces = set(('method', 'param', 'status')) | ||||
|     interfaces = {'method', 'param', 'status'} | ||||
|  | ||||
|     #: By default, values in the `interfaces` set are mapped to | ||||
|     #: attribute values. This can be changed such that an interface | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
|  | ||||
| from slixmpp import ClientXMPP | ||||
|  | ||||
| from optparse import OptionParser | ||||
| from argparse import ArgumentParser | ||||
| import logging | ||||
| import getpass | ||||
|  | ||||
| @@ -58,40 +58,40 @@ if __name__ == '__main__': | ||||
|     # ./http_over_xmpp.py -J <jid> -P <pwd> -i <ip> -p <port> [-v] | ||||
|     # | ||||
|  | ||||
|     parser = OptionParser() | ||||
|     parser = ArgumentParser() | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     parser.add_option( | ||||
|     parser.add_argument( | ||||
|         '-v', '--verbose', help='set logging to DEBUG', action='store_const', | ||||
|         dest='loglevel', const=logging.DEBUG, default=logging.ERROR | ||||
|     ) | ||||
|  | ||||
|     # JID and password options. | ||||
|     parser.add_option('-J', '--jid', dest='jid', help='JID') | ||||
|     parser.add_option('-P', '--password', dest='password', help='Password') | ||||
|     parser.add_argument('-J', '--jid', dest='jid', help='JID') | ||||
|     parser.add_argument('-P', '--password', dest='password', help='Password') | ||||
|  | ||||
|     # XMPP server ip and port options. | ||||
|     parser.add_option( | ||||
|     parser.add_argument( | ||||
|         '-i', '--ipaddr', dest='ipaddr', | ||||
|         help='IP Address of the XMPP server', default=None | ||||
|     ) | ||||
|     parser.add_option( | ||||
|     parser.add_argument( | ||||
|         '-p', '--port', dest='port', | ||||
|         help='Port of the XMPP server', default=None | ||||
|     ) | ||||
|  | ||||
|     opts, args = parser.parse_args() | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     # Setup logging. | ||||
|     logging.basicConfig(level=opts.loglevel, | ||||
|     logging.basicConfig(level=args.loglevel, | ||||
|                         format='%(levelname)-8s %(message)s') | ||||
|  | ||||
|     if opts.jid is None: | ||||
|         opts.jid = input('Username: ') | ||||
|     if opts.password is None: | ||||
|         opts.password = getpass.getpass('Password: ') | ||||
|     if args.jid is None: | ||||
|         args.jid = input('Username: ') | ||||
|     if args.password is None: | ||||
|         args.password = getpass.getpass('Password: ') | ||||
|  | ||||
|     xmpp = HTTPOverXMPPClient(opts.jid, opts.password) | ||||
|     xmpp = HTTPOverXMPPClient(args.jid, args.password) | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
|  | ||||
|   | ||||
| @@ -67,11 +67,11 @@ class MUCBot(slixmpp.ClientXMPP): | ||||
|         """ | ||||
|         self.get_roster() | ||||
|         self.send_presence() | ||||
|         self.plugin['xep_0045'].joinMUC(self.room, | ||||
|                                         self.nick, | ||||
|                                         # If a room password is needed, use: | ||||
|                                         # password=the_room_password, | ||||
|                                         wait=True) | ||||
|         self.plugin['xep_0045'].join_muc(self.room, | ||||
|                                          self.nick, | ||||
|                                          # If a room password is needed, use: | ||||
|                                          # password=the_room_password, | ||||
|                                          wait=True) | ||||
|  | ||||
|     def muc_message(self, msg): | ||||
|         """ | ||||
|   | ||||
| @@ -15,7 +15,7 @@ class PubsubClient(slixmpp.ClientXMPP): | ||||
|  | ||||
|     def __init__(self, jid, password, server, | ||||
|                        node=None, action='nodes', data=''): | ||||
|         super(PubsubClient, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.register_plugin('xep_0030') | ||||
|         self.register_plugin('xep_0059') | ||||
|   | ||||
| @@ -14,7 +14,7 @@ from slixmpp.xmlstream.handler import Callback | ||||
| class PubsubEvents(slixmpp.ClientXMPP): | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         super(PubsubEvents, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.register_plugin('xep_0030') | ||||
|         self.register_plugin('xep_0059') | ||||
|   | ||||
| @@ -22,7 +22,7 @@ from slixmpp import ClientXMPP | ||||
| class LocationBot(ClientXMPP): | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         super(LocationBot, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         self.add_event_handler('session_start', self.start) | ||||
|         self.add_event_handler('user_location_publish', | ||||
|   | ||||
| @@ -17,7 +17,7 @@ from slixmpp import ClientXMPP | ||||
| class TuneBot(ClientXMPP): | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         super(TuneBot, self).__init__(jid, password) | ||||
|         super().__init__(jid, password) | ||||
|  | ||||
|         # Check for the current song every 5 seconds. | ||||
|         self.schedule('Check Current Tune', 5, self._update_tune, repeat=True) | ||||
|   | ||||
							
								
								
									
										45
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								setup.py
									
									
									
									
									
								
							| @@ -7,20 +7,15 @@ | ||||
| # This software is licensed as described in the README.rst and LICENSE | ||||
| # file, which you should have received as part of this distribution. | ||||
|  | ||||
| import os | ||||
| from pathlib import Path | ||||
| from subprocess import call, DEVNULL, check_output, CalledProcessError | ||||
| from tempfile import TemporaryFile | ||||
| try: | ||||
|     from setuptools import setup | ||||
| except ImportError: | ||||
|     from distutils.core import setup | ||||
|  | ||||
| try: | ||||
|     from Cython.Build import cythonize | ||||
| except ImportError: | ||||
|     print('Cython not found, falling back to the slow stringprep module.') | ||||
|     ext_modules = None | ||||
| else: | ||||
|     ext_modules = cythonize('slixmpp/stringprep.pyx') | ||||
|  | ||||
| from run_tests import TestCommand | ||||
| from slixmpp.version import __version__ | ||||
|  | ||||
| @@ -40,6 +35,40 @@ CLASSIFIERS = [ | ||||
|  | ||||
| packages = [str(mod.parent) for mod in Path('slixmpp').rglob('__init__.py')] | ||||
|  | ||||
| def check_include(library_name, header): | ||||
|     command = [os.environ.get('PKG_CONFIG', 'pkg-config'), '--cflags', library_name] | ||||
|     try: | ||||
|         cflags = check_output(command).decode('utf-8').split() | ||||
|     except FileNotFoundError: | ||||
|         print('pkg-config not found.') | ||||
|         return False | ||||
|     except CalledProcessError: | ||||
|         # pkg-config already prints the missing libraries on stderr. | ||||
|         return False | ||||
|     command = [os.environ.get('CC', 'cc')] + cflags + ['-E', '-'] | ||||
|     with TemporaryFile('w+') as c_file: | ||||
|         c_file.write('#include <%s>' % header) | ||||
|         c_file.seek(0) | ||||
|         try: | ||||
|             return call(command, stdin=c_file, stdout=DEVNULL, stderr=DEVNULL) == 0 | ||||
|         except FileNotFoundError: | ||||
|             print('%s headers not found.' % library_name) | ||||
|             return False | ||||
|  | ||||
| HAS_PYTHON_HEADERS = check_include('python3', 'Python.h') | ||||
| HAS_STRINGPREP_HEADERS = check_include('libidn', 'stringprep.h') | ||||
|  | ||||
| ext_modules = None | ||||
| if HAS_PYTHON_HEADERS and HAS_STRINGPREP_HEADERS: | ||||
|     try: | ||||
|         from Cython.Build import cythonize | ||||
|     except ImportError: | ||||
|         print('Cython not found, falling back to the slow stringprep module.') | ||||
|     else: | ||||
|         ext_modules = cythonize('slixmpp/stringprep.pyx') | ||||
| else: | ||||
|     print('Falling back to the slow stringprep module.') | ||||
|  | ||||
| setup( | ||||
|     name="slixmpp", | ||||
|     version=VERSION, | ||||
|   | ||||
| @@ -12,8 +12,8 @@ | ||||
|     :license: MIT, see LICENSE for more details | ||||
| """ | ||||
|  | ||||
| import asyncio | ||||
| import logging | ||||
| import threading | ||||
|  | ||||
| from slixmpp import plugins, roster, stanza | ||||
| from slixmpp.api import APIRegistry | ||||
| @@ -21,7 +21,6 @@ from slixmpp.exceptions import IqError, IqTimeout | ||||
|  | ||||
| from slixmpp.stanza import Message, Presence, Iq, StreamError | ||||
| from slixmpp.stanza.roster import Roster | ||||
| from slixmpp.stanza.nick import Nick | ||||
|  | ||||
| from slixmpp.xmlstream import XMLStream, JID | ||||
| from slixmpp.xmlstream import ET, register_stanza_plugin | ||||
| @@ -70,7 +69,7 @@ class BaseXMPP(XMLStream): | ||||
|         #: redirections that will be followed before quitting. | ||||
|         self.max_redirects = 5 | ||||
|  | ||||
|         self.session_bind_event = threading.Event() | ||||
|         self.session_bind_event = asyncio.Event() | ||||
|  | ||||
|         #: A dictionary mapping plugin names to plugins. | ||||
|         self.plugin = PluginManager(self) | ||||
| @@ -194,7 +193,6 @@ class BaseXMPP(XMLStream): | ||||
|  | ||||
|         # Initialize a few default stanza plugins. | ||||
|         register_stanza_plugin(Iq, Roster) | ||||
|         register_stanza_plugin(Message, Nick) | ||||
|  | ||||
|     def start_stream_handler(self, xml): | ||||
|         """Save the stream ID once the streams have been established. | ||||
| @@ -687,7 +685,6 @@ class BaseXMPP(XMLStream): | ||||
|             self.address = (host, port) | ||||
|             self.default_domain = host | ||||
|             self.dns_records = None | ||||
|             self.reconnect_delay = None | ||||
|             self.reconnect() | ||||
|  | ||||
|     def _handle_message(self, msg): | ||||
| @@ -753,6 +750,9 @@ class BaseXMPP(XMLStream): | ||||
|  | ||||
|         Update the roster with presence information. | ||||
|         """ | ||||
|         if self.roster[presence['from']].ignore_updates: | ||||
|             return | ||||
|  | ||||
|         if not self.is_component and not presence['to'].bare: | ||||
|             presence['to'] = self.boundjid | ||||
|  | ||||
|   | ||||
| @@ -12,14 +12,16 @@ | ||||
|     :license: MIT, see LICENSE for more details | ||||
| """ | ||||
|  | ||||
| import asyncio | ||||
| import logging | ||||
|  | ||||
| from slixmpp.jid import JID | ||||
| from slixmpp.stanza import StreamFeatures | ||||
| from slixmpp.basexmpp import BaseXMPP | ||||
| from slixmpp.exceptions import XMPPError | ||||
| from slixmpp.xmlstream import XMLStream | ||||
| from slixmpp.xmlstream.matcher import StanzaPath, MatchXPath | ||||
| from slixmpp.xmlstream.handler import Callback | ||||
| from slixmpp.xmlstream.handler import Callback, CoroutineCallback | ||||
|  | ||||
| # Flag indicating if DNS SRV records are available for use. | ||||
| try: | ||||
| @@ -104,13 +106,24 @@ class ClientXMPP(BaseXMPP): | ||||
|         self.register_stanza(StreamFeatures) | ||||
|  | ||||
|         self.register_handler( | ||||
|                 Callback('Stream Features', | ||||
|                          MatchXPath('{%s}features' % self.stream_ns), | ||||
|                          self._handle_stream_features)) | ||||
|                 CoroutineCallback('Stream Features', | ||||
|                      MatchXPath('{%s}features' % self.stream_ns), | ||||
|                      self._handle_stream_features)) | ||||
|         def roster_push_filter(iq): | ||||
|             from_ = iq['from'] | ||||
|             if from_ and from_ != JID('') and from_ != self.boundjid.bare: | ||||
|                 reply = iq.reply() | ||||
|                 reply['type'] = 'error' | ||||
|                 reply['error']['type'] = 'cancel' | ||||
|                 reply['error']['code'] = 503 | ||||
|                 reply['error']['condition'] = 'service-unavailable' | ||||
|                 reply.send() | ||||
|                 return | ||||
|             self.event('roster_update', iq) | ||||
|         self.register_handler( | ||||
|                 Callback('Roster Update', | ||||
|                          StanzaPath('iq@type=set/roster'), | ||||
|                          lambda iq: self.event('roster_update', iq))) | ||||
|                          roster_push_filter)) | ||||
|  | ||||
|         # Setup default stream features | ||||
|         self.register_plugin('feature_starttls') | ||||
| @@ -140,8 +153,11 @@ class ClientXMPP(BaseXMPP): | ||||
|         will be used. | ||||
|  | ||||
|         :param address: A tuple containing the server's host and port. | ||||
|         :param use_tls: Indicates if TLS should be used for the | ||||
|                         connection. Defaults to ``True``. | ||||
|         :param force_starttls: Indicates that negotiation should be aborted | ||||
|                                if the server does not advertise support for | ||||
|                                STARTTLS. Defaults to ``True``. | ||||
|         :param disable_starttls: Disables TLS for the connection. | ||||
|                                  Defaults to ``False``. | ||||
|         :param use_ssl: Indicates if the older SSL connection method | ||||
|                         should be used. Defaults to ``False``. | ||||
|         """ | ||||
| @@ -249,6 +265,7 @@ class ClientXMPP(BaseXMPP): | ||||
|         self.bindfail = False | ||||
|         self.features = set() | ||||
|  | ||||
|     @asyncio.coroutine | ||||
|     def _handle_stream_features(self, features): | ||||
|         """Process the received stream features. | ||||
|  | ||||
| @@ -257,7 +274,11 @@ class ClientXMPP(BaseXMPP): | ||||
|         for order, name in self._stream_feature_order: | ||||
|             if name in features['features']: | ||||
|                 handler, restart = self._stream_feature_handlers[name] | ||||
|                 if handler(features) and restart: | ||||
|                 if asyncio.iscoroutinefunction(handler): | ||||
|                     result = yield from handler(features) | ||||
|                 else: | ||||
|                     result = handler(features) | ||||
|                 if result and restart: | ||||
|                     # Don't continue if the feature requires | ||||
|                     # restarting the XML stream. | ||||
|                     return True | ||||
|   | ||||
| @@ -77,7 +77,7 @@ class IqTimeout(XMPPError): | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, iq): | ||||
|         super(IqTimeout, self).__init__( | ||||
|         super().__init__( | ||||
|                 condition='remote-server-timeout', | ||||
|                 etype='cancel') | ||||
|  | ||||
| @@ -94,7 +94,7 @@ class IqError(XMPPError): | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, iq): | ||||
|         super(IqError, self).__init__( | ||||
|         super().__init__( | ||||
|                 condition=iq['error']['condition'], | ||||
|                 text=iq['error']['text'], | ||||
|                 etype=iq['error']['type']) | ||||
|   | ||||
| @@ -13,7 +13,3 @@ from slixmpp.features.feature_bind.stanza import Bind | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureBind) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_bind = FeatureBind | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import asyncio | ||||
| import logging | ||||
|  | ||||
| from slixmpp.jid import JID | ||||
| @@ -34,6 +35,7 @@ class FeatureBind(BasePlugin): | ||||
|         register_stanza_plugin(Iq, stanza.Bind) | ||||
|         register_stanza_plugin(StreamFeatures, stanza.Bind) | ||||
|  | ||||
|     @asyncio.coroutine | ||||
|     def _handle_bind_resource(self, features): | ||||
|         """ | ||||
|         Handle requesting a specific resource. | ||||
| @@ -49,7 +51,7 @@ class FeatureBind(BasePlugin): | ||||
|         if self.xmpp.requested_jid.resource: | ||||
|             iq['bind']['resource'] = self.xmpp.requested_jid.resource | ||||
|  | ||||
|         iq.send(callback=self._on_bind_response) | ||||
|         yield from iq.send(callback=self._on_bind_response) | ||||
|  | ||||
|     def _on_bind_response(self, response): | ||||
|         self.xmpp.boundjid = JID(response['bind']['jid']) | ||||
|   | ||||
| @@ -16,6 +16,6 @@ class Bind(ElementBase): | ||||
|  | ||||
|     name = 'bind' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-bind' | ||||
|     interfaces = set(('resource', 'jid')) | ||||
|     interfaces = {'resource', 'jid'} | ||||
|     sub_interfaces = interfaces | ||||
|     plugin_attrib = 'bind' | ||||
|   | ||||
| @@ -16,7 +16,3 @@ from slixmpp.features.feature_mechanisms.stanza import Failure | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureMechanisms) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_mechanisms = FeatureMechanisms | ||||
|   | ||||
| @@ -49,7 +49,7 @@ class FeatureMechanisms(BasePlugin): | ||||
|         if self.security_callback is None: | ||||
|             self.security_callback = self._default_security | ||||
|  | ||||
|         creds = self.sasl_callback(set(['username']), set()) | ||||
|         creds = self.sasl_callback({'username'}, set()) | ||||
|         if not self.use_mech and not creds['username']: | ||||
|             self.use_mech = 'ANONYMOUS' | ||||
|  | ||||
|   | ||||
| @@ -19,12 +19,12 @@ class Auth(StanzaBase): | ||||
|  | ||||
|     name = 'auth' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' | ||||
|     interfaces = set(('mechanism', 'value')) | ||||
|     interfaces = {'mechanism', 'value'} | ||||
|     plugin_attrib = name | ||||
|  | ||||
|     #: Some SASL mechs require sending values as is, | ||||
|     #: without converting base64. | ||||
|     plain_mechs = set(['X-MESSENGER-OAUTH2']) | ||||
|     plain_mechs = {'X-MESSENGER-OAUTH2'} | ||||
|  | ||||
|     def setup(self, xml): | ||||
|         StanzaBase.setup(self, xml) | ||||
|   | ||||
| @@ -19,7 +19,7 @@ class Challenge(StanzaBase): | ||||
|  | ||||
|     name = 'challenge' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' | ||||
|     interfaces = set(('value',)) | ||||
|     interfaces = {'value'} | ||||
|     plugin_attrib = name | ||||
|  | ||||
|     def setup(self, xml): | ||||
|   | ||||
| @@ -16,13 +16,14 @@ class Failure(StanzaBase): | ||||
|  | ||||
|     name = 'failure' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' | ||||
|     interfaces = set(('condition', 'text')) | ||||
|     interfaces = {'condition', 'text'} | ||||
|     plugin_attrib = name | ||||
|     sub_interfaces = set(('text',)) | ||||
|     conditions = set(('aborted', 'account-disabled', 'credentials-expired', | ||||
|         'encryption-required', 'incorrect-encoding', 'invalid-authzid', | ||||
|         'invalid-mechanism', 'malformed-request', 'mechansism-too-weak', | ||||
|         'not-authorized', 'temporary-auth-failure')) | ||||
|     sub_interfaces = {'text'} | ||||
|     conditions = {'aborted', 'account-disabled', 'credentials-expired', | ||||
|                   'encryption-required', 'incorrect-encoding', | ||||
|                   'invalid-authzid', 'invalid-mechanism', 'malformed-request', | ||||
|                   'mechansism-too-weak', 'not-authorized', | ||||
|                   'temporary-auth-failure'} | ||||
|  | ||||
|     def setup(self, xml=None): | ||||
|         """ | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class Mechanisms(ElementBase): | ||||
|  | ||||
|     name = 'mechanisms' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' | ||||
|     interfaces = set(('mechanisms', 'required')) | ||||
|     interfaces = {'mechanisms', 'required'} | ||||
|     plugin_attrib = name | ||||
|     is_extension = True | ||||
|  | ||||
| @@ -29,7 +29,7 @@ class Mechanisms(ElementBase): | ||||
|         """ | ||||
|         """ | ||||
|         results = [] | ||||
|         mechs = self.findall('{%s}mechanism' % self.namespace) | ||||
|         mechs = self.xml.findall('{%s}mechanism' % self.namespace) | ||||
|         if mechs: | ||||
|             for mech in mechs: | ||||
|                 results.append(mech.text) | ||||
| @@ -47,7 +47,7 @@ class Mechanisms(ElementBase): | ||||
|     def del_mechanisms(self): | ||||
|         """ | ||||
|         """ | ||||
|         mechs = self.findall('{%s}mechanism' % self.namespace) | ||||
|         mechs = self.xml.findall('{%s}mechanism' % self.namespace) | ||||
|         if mechs: | ||||
|             for mech in mechs: | ||||
|                 self.xml.remove(mech) | ||||
|   | ||||
| @@ -19,7 +19,7 @@ class Response(StanzaBase): | ||||
|  | ||||
|     name = 'response' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' | ||||
|     interfaces = set(('value',)) | ||||
|     interfaces = {'value'} | ||||
|     plugin_attrib = name | ||||
|  | ||||
|     def setup(self, xml): | ||||
|   | ||||
| @@ -18,7 +18,7 @@ class Success(StanzaBase): | ||||
|  | ||||
|     name = 'success' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' | ||||
|     interfaces = set(['value']) | ||||
|     interfaces = {'value'} | ||||
|     plugin_attrib = name | ||||
|  | ||||
|     def setup(self, xml): | ||||
|   | ||||
| @@ -13,7 +13,3 @@ from slixmpp.features.feature_rosterver.stanza import RosterVer | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureRosterVer) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_rosterver = FeatureRosterVer | ||||
|   | ||||
| @@ -13,7 +13,3 @@ from slixmpp.features.feature_session.stanza import Session | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureSession) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_session = FeatureSession | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| import asyncio | ||||
| import logging | ||||
|  | ||||
| from slixmpp.stanza import Iq, StreamFeatures | ||||
| @@ -34,6 +35,7 @@ class FeatureSession(BasePlugin): | ||||
|         register_stanza_plugin(Iq, stanza.Session) | ||||
|         register_stanza_plugin(StreamFeatures, stanza.Session) | ||||
|  | ||||
|     @asyncio.coroutine | ||||
|     def _handle_start_session(self, features): | ||||
|         """ | ||||
|         Handle the start of the session. | ||||
| @@ -44,7 +46,7 @@ class FeatureSession(BasePlugin): | ||||
|         iq = self.xmpp.Iq() | ||||
|         iq['type'] = 'set' | ||||
|         iq.enable('session') | ||||
|         iq.send(callback=self._on_start_session_response) | ||||
|         yield from iq.send(callback=self._on_start_session_response) | ||||
|  | ||||
|     def _on_start_session_response(self, response): | ||||
|         self.xmpp.features.add('session') | ||||
|   | ||||
| @@ -13,7 +13,3 @@ from slixmpp.features.feature_starttls.stanza import * | ||||
|  | ||||
|  | ||||
| register_plugin(FeatureSTARTTLS) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| feature_starttls = FeatureSTARTTLS | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class STARTTLS(ElementBase): | ||||
|  | ||||
|     name = 'starttls' | ||||
|     namespace = 'urn:ietf:params:xml:ns:xmpp-tls' | ||||
|     interfaces = set(('required',)) | ||||
|     interfaces = {'required'} | ||||
|     plugin_attrib = name | ||||
|  | ||||
|     def get_required(self): | ||||
|   | ||||
| @@ -79,7 +79,7 @@ def _validate_node(node): | ||||
|     :returns: The local portion of a JID, as validated by nodeprep. | ||||
|     """ | ||||
|     if node is None: | ||||
|         return None | ||||
|         return '' | ||||
|  | ||||
|     try: | ||||
|         node = nodeprep(node) | ||||
| @@ -160,7 +160,7 @@ def _validate_resource(resource): | ||||
|     :returns: The local portion of a JID, as validated by resourceprep. | ||||
|     """ | ||||
|     if resource is None: | ||||
|         return None | ||||
|         return '' | ||||
|  | ||||
|     try: | ||||
|         resource = resourceprep(resource) | ||||
| @@ -208,16 +208,15 @@ def _format_jid(local=None, domain=None, resource=None): | ||||
|  | ||||
|     :return: A full or bare JID string. | ||||
|     """ | ||||
|     result = [] | ||||
|     if domain is None: | ||||
|         return '' | ||||
|     if local is not None: | ||||
|         result.append(local) | ||||
|         result.append('@') | ||||
|     if domain is not None: | ||||
|         result.append(domain) | ||||
|         result = local + '@' + domain | ||||
|     else: | ||||
|         result = domain | ||||
|     if resource is not None: | ||||
|         result.append('/') | ||||
|         result.append(resource) | ||||
|     return ''.join(result) | ||||
|         result += '/' + resource | ||||
|     return result | ||||
|  | ||||
|  | ||||
| class InvalidJID(ValueError): | ||||
| @@ -300,19 +299,23 @@ class JID: | ||||
|     :raises InvalidJID: | ||||
|     """ | ||||
|  | ||||
|     __slots__ = ('_node', '_domain', '_resource') | ||||
|     __slots__ = ('_node', '_domain', '_resource', '_bare', '_full') | ||||
|  | ||||
|     def __init__(self, jid=None): | ||||
|         if not jid: | ||||
|             self._node = None | ||||
|             self._domain = None | ||||
|             self._resource = None | ||||
|             self._node = '' | ||||
|             self._domain = '' | ||||
|             self._resource = '' | ||||
|             self._bare = '' | ||||
|             self._full = '' | ||||
|             return | ||||
|         elif not isinstance(jid, JID): | ||||
|             self._node, self._domain, self._resource = _parse_jid(jid) | ||||
|         else: | ||||
|             self._node = jid._node | ||||
|             self._domain = jid._domain | ||||
|             self._resource = jid._resource | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     def unescape(self): | ||||
|         """Return an unescaped JID object. | ||||
| @@ -329,77 +332,94 @@ class JID: | ||||
|                             self._domain, | ||||
|                             self._resource) | ||||
|  | ||||
|     def _update_bare_full(self): | ||||
|         """Format the given JID into a bare and a full JID. | ||||
|         """ | ||||
|         self._bare = (self._node + '@' + self._domain | ||||
|                       if self._node | ||||
|                       else self._domain) | ||||
|         self._full = (self._bare + '/' + self._resource | ||||
|                       if self._resource | ||||
|                       else self._bare) | ||||
|  | ||||
|     @property | ||||
|     def node(self): | ||||
|         return self._node or '' | ||||
|         return self._node | ||||
|  | ||||
|     @property | ||||
|     def user(self): | ||||
|         return self._node or '' | ||||
|         return self._node | ||||
|  | ||||
|     @property | ||||
|     def local(self): | ||||
|         return self._node or '' | ||||
|         return self._node | ||||
|  | ||||
|     @property | ||||
|     def username(self): | ||||
|         return self._node or '' | ||||
|         return self._node | ||||
|  | ||||
|     @property | ||||
|     def domain(self): | ||||
|         return self._domain or '' | ||||
|         return self._domain | ||||
|  | ||||
|     @property | ||||
|     def server(self): | ||||
|         return self._domain or '' | ||||
|         return self._domain | ||||
|  | ||||
|     @property | ||||
|     def host(self): | ||||
|         return self._domain or '' | ||||
|         return self._domain | ||||
|  | ||||
|     @property | ||||
|     def resource(self): | ||||
|         return self._resource or '' | ||||
|         return self._resource | ||||
|  | ||||
|     @property | ||||
|     def bare(self): | ||||
|         return _format_jid(self._node, self._domain) | ||||
|         return self._bare | ||||
|  | ||||
|     @property | ||||
|     def full(self): | ||||
|         return _format_jid(self._node, self._domain, self._resource) | ||||
|         return self._full | ||||
|  | ||||
|     @property | ||||
|     def jid(self): | ||||
|         return _format_jid(self._node, self._domain, self._resource) | ||||
|         return self._full | ||||
|  | ||||
|     @node.setter | ||||
|     def node(self, value): | ||||
|         self._node = _validate_node(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @user.setter | ||||
|     def user(self, value): | ||||
|         self._node = _validate_node(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @local.setter | ||||
|     def local(self, value): | ||||
|         self._node = _validate_node(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @username.setter | ||||
|     def username(self, value): | ||||
|         self._node = _validate_node(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @domain.setter | ||||
|     def domain(self, value): | ||||
|         self._domain = _validate_domain(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @server.setter | ||||
|     def server(self, value): | ||||
|         self._domain = _validate_domain(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @host.setter | ||||
|     def host(self, value): | ||||
|         self._domain = _validate_domain(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @bare.setter | ||||
|     def bare(self, value): | ||||
| @@ -407,26 +427,30 @@ class JID: | ||||
|         assert not resource | ||||
|         self._node = node | ||||
|         self._domain = domain | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @resource.setter | ||||
|     def resource(self, value): | ||||
|         self._resource = _validate_resource(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @full.setter | ||||
|     def full(self, value): | ||||
|         self._node, self._domain, self._resource = _parse_jid(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     @jid.setter | ||||
|     def jid(self, value): | ||||
|         self._node, self._domain, self._resource = _parse_jid(value) | ||||
|         self._update_bare_full() | ||||
|  | ||||
|     def __str__(self): | ||||
|         """Use the full JID as the string value.""" | ||||
|         return _format_jid(self._node, self._domain, self._resource) | ||||
|         return self._full | ||||
|  | ||||
|     def __repr__(self): | ||||
|         """Use the full JID as the representation.""" | ||||
|         return _format_jid(self._node, self._domain, self._resource) | ||||
|         return self._full | ||||
|  | ||||
|     # pylint: disable=W0212 | ||||
|     def __eq__(self, other): | ||||
| @@ -446,4 +470,4 @@ class JID: | ||||
|  | ||||
|     def __hash__(self): | ||||
|         """Hash a JID based on the string version of its full JID.""" | ||||
|         return hash(_format_jid(self._node, self._domain, self._resource)) | ||||
|         return hash(self._full) | ||||
|   | ||||
| @@ -308,7 +308,7 @@ class BasePlugin(object): | ||||
|         if key in self.default_config: | ||||
|             self.config[key] = value | ||||
|         else: | ||||
|             super(BasePlugin, self).__setattr__(key, value) | ||||
|             super().__setattr__(key, value) | ||||
|  | ||||
|     def _init(self): | ||||
|         """Initialize plugin state, such as registering event handlers. | ||||
|   | ||||
| @@ -21,15 +21,15 @@ class GmailQuery(ElementBase): | ||||
|     namespace = 'google:mail:notify' | ||||
|     name = 'query' | ||||
|     plugin_attrib = 'gmail' | ||||
|     interfaces = set(('newer-than-time', 'newer-than-tid', 'q', 'search')) | ||||
|     interfaces = {'newer-than-time', 'newer-than-tid', 'q', 'search'} | ||||
|  | ||||
|     def getSearch(self): | ||||
|     def get_search(self): | ||||
|         return self['q'] | ||||
|  | ||||
|     def setSearch(self, search): | ||||
|     def set_search(self, search): | ||||
|         self['q'] = search | ||||
|  | ||||
|     def delSearch(self): | ||||
|     def del_search(self): | ||||
|         del self['q'] | ||||
|  | ||||
|  | ||||
| @@ -37,20 +37,20 @@ class MailBox(ElementBase): | ||||
|     namespace = 'google:mail:notify' | ||||
|     name = 'mailbox' | ||||
|     plugin_attrib = 'mailbox' | ||||
|     interfaces = set(('result-time', 'total-matched', 'total-estimate', | ||||
|                       'url', 'threads', 'matched', 'estimate')) | ||||
|     interfaces = {'result-time', 'total-matched', 'total-estimate', | ||||
|                   'url', 'threads', 'matched', 'estimate'} | ||||
|  | ||||
|     def getThreads(self): | ||||
|     def get_threads(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): | ||||
|     def get_matched(self): | ||||
|         return self['total-matched'] | ||||
|  | ||||
|     def getEstimate(self): | ||||
|     def get_estimate(self): | ||||
|         return self['total-estimate'] == '1' | ||||
|  | ||||
|  | ||||
| @@ -58,11 +58,11 @@ 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')) | ||||
|     interfaces = {'tid', 'participation', 'messages', 'date', | ||||
|                   'senders', 'url', 'labels', 'subject', 'snippet'} | ||||
|     sub_interfaces = {'labels', 'subject', 'snippet'} | ||||
|  | ||||
|     def getSenders(self): | ||||
|     def get_senders(self): | ||||
|         senders = [] | ||||
|         sendersXML = self.xml.find('{%s}senders' % self.namespace) | ||||
|         if sendersXML is not None: | ||||
| @@ -75,12 +75,12 @@ class MailSender(ElementBase): | ||||
|     namespace = 'google:mail:notify' | ||||
|     name = 'sender' | ||||
|     plugin_attrib = 'sender' | ||||
|     interfaces = set(('address', 'name', 'originator', 'unread')) | ||||
|     interfaces = {'address', 'name', 'originator', 'unread'} | ||||
|  | ||||
|     def getOriginator(self): | ||||
|     def get_originator(self): | ||||
|         return self.xml.attrib.get('originator', '0') == '1' | ||||
|  | ||||
|     def getUnread(self): | ||||
|     def get_unread(self): | ||||
|         return self.xml.attrib.get('unread', '0') == '1' | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										47
									
								
								slixmpp/plugins/google/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								slixmpp/plugins/google/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.plugins.base import register_plugin, BasePlugin | ||||
|  | ||||
| from slixmpp.plugins.google.gmail import Gmail | ||||
| from slixmpp.plugins.google.auth import GoogleAuth | ||||
| from slixmpp.plugins.google.settings import GoogleSettings | ||||
| from slixmpp.plugins.google.nosave import GoogleNoSave | ||||
|  | ||||
|  | ||||
| class Google(BasePlugin): | ||||
|  | ||||
|     """ | ||||
|     Google: Custom GTalk Features | ||||
|  | ||||
|     Also see: <https://developers.google.com/talk/jep_extensions/extensions> | ||||
|     """ | ||||
|  | ||||
|     name = 'google' | ||||
|     description = 'Google: Custom GTalk Features' | ||||
|     dependencies = set([ | ||||
|         'gmail', | ||||
|         'google_settings', | ||||
|         'google_nosave', | ||||
|         'google_auth' | ||||
|     ]) | ||||
|  | ||||
|     def __getitem__(self, attr): | ||||
|         if attr in ('settings', 'nosave', 'auth'): | ||||
|             return self.xmpp['google_%s' % attr] | ||||
|         elif attr == 'gmail': | ||||
|             return self.xmpp['gmail'] | ||||
|         else: | ||||
|             raise KeyError(attr) | ||||
|  | ||||
|  | ||||
| register_plugin(Gmail) | ||||
| register_plugin(GoogleAuth) | ||||
| register_plugin(GoogleSettings) | ||||
| register_plugin(GoogleNoSave) | ||||
| register_plugin(Google) | ||||
							
								
								
									
										10
									
								
								slixmpp/plugins/google/auth/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								slixmpp/plugins/google/auth/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.plugins.google.auth import stanza | ||||
| from slixmpp.plugins.google.auth.auth import GoogleAuth | ||||
							
								
								
									
										47
									
								
								slixmpp/plugins/google/auth/auth.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								slixmpp/plugins/google/auth/auth.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.xmlstream import register_stanza_plugin | ||||
| from slixmpp.plugins import BasePlugin | ||||
| from slixmpp.plugins.google.auth import stanza | ||||
|  | ||||
|  | ||||
| class GoogleAuth(BasePlugin): | ||||
|  | ||||
|     """ | ||||
|     Google: Auth Extensions (JID Domain Discovery, OAuth2) | ||||
|  | ||||
|     Also see: | ||||
|         <https://developers.google.com/talk/jep_extensions/jid_domain_change> | ||||
|         <https://developers.google.com/talk/jep_extensions/oauth> | ||||
|     """ | ||||
|  | ||||
|     name = 'google_auth' | ||||
|     description = 'Google: Auth Extensions (JID Domain Discovery, OAuth2)' | ||||
|     dependencies = set(['feature_mechanisms']) | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|         self.xmpp.namespace_map['http://www.google.com/talk/protocol/auth'] = 'ga' | ||||
|  | ||||
|         register_stanza_plugin(self.xmpp['feature_mechanisms'].stanza.Auth, | ||||
|                                stanza.GoogleAuth) | ||||
|  | ||||
|         self.xmpp.add_filter('out', self._auth) | ||||
|  | ||||
|     def plugin_end(self): | ||||
|         self.xmpp.del_filter('out', self._auth) | ||||
|  | ||||
|     def _auth(self, stanza): | ||||
|         if isinstance(stanza, self.xmpp['feature_mechanisms'].stanza.Auth): | ||||
|             stanza.stream = self.xmpp | ||||
|             stanza['google']['client_uses_full_bind_result'] = True | ||||
|             if stanza['mechanism'] == 'X-OAUTH2': | ||||
|                 stanza['google']['service'] = 'oauth2' | ||||
|             print(stanza) | ||||
|         return stanza | ||||
| @@ -13,7 +13,7 @@ class GoogleAuth(ElementBase): | ||||
|     name = 'auth' | ||||
|     namespace = 'http://www.google.com/talk/protocol/auth' | ||||
|     plugin_attrib = 'google' | ||||
|     interfaces = set(['client_uses_full_bind_result', 'service']) | ||||
|     interfaces = {'client_uses_full_bind_result', 'service'} | ||||
|  | ||||
|     discovery_attr= '{%s}client-uses-full-bind-result' % namespace | ||||
|     service_attr= '{%s}service' % namespace | ||||
|   | ||||
							
								
								
									
										10
									
								
								slixmpp/plugins/google/gmail/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								slixmpp/plugins/google/gmail/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.plugins.google.gmail import stanza | ||||
| from slixmpp.plugins.google.gmail.notifications import Gmail | ||||
							
								
								
									
										101
									
								
								slixmpp/plugins/google/gmail/stanza.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								slixmpp/plugins/google/gmail/stanza.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.xmlstream import ElementBase, 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) | ||||
							
								
								
									
										10
									
								
								slixmpp/plugins/google/nosave/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								slixmpp/plugins/google/nosave/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.plugins.google.nosave import stanza | ||||
| from slixmpp.plugins.google.nosave.nosave import GoogleNoSave | ||||
							
								
								
									
										78
									
								
								slixmpp/plugins/google/nosave/nosave.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								slixmpp/plugins/google/nosave/nosave.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.stanza import Iq, Message | ||||
| from slixmpp.xmlstream.handler import Callback | ||||
| from slixmpp.xmlstream.matcher import StanzaPath | ||||
| from slixmpp.xmlstream import register_stanza_plugin | ||||
| from slixmpp.plugins import BasePlugin | ||||
| from slixmpp.plugins.google.nosave import stanza | ||||
|  | ||||
|  | ||||
| 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, timeout=None, callback=None): | ||||
|         if jid is None: | ||||
|             self.xmpp['google_settings'].update({'archiving_enabled': False}, | ||||
|                     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(timeout=timeout, callback=callback) | ||||
|  | ||||
|     def disable(self, jid=None, timeout=None, callback=None): | ||||
|         if jid is None: | ||||
|             self.xmpp['google_settings'].update({'archiving_enabled': True}, | ||||
|                     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(timeout=timeout, callback=callback) | ||||
|  | ||||
|     def get(self, timeout=None, callback=None): | ||||
|         iq = self.xmpp.Iq() | ||||
|         iq['type'] = 'get' | ||||
|         iq.enable('google_nosave') | ||||
|         return iq.send(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) | ||||
| @@ -14,7 +14,7 @@ class NoSave(ElementBase): | ||||
|     name = 'x' | ||||
|     namespace = 'google:nosave' | ||||
|     plugin_attrib = 'google_nosave' | ||||
|     interfaces = set(['value']) | ||||
|     interfaces = {'value'} | ||||
|  | ||||
|     def get_value(self): | ||||
|         return self._get_attr('value', '') == 'enabled' | ||||
| @@ -35,7 +35,7 @@ class Item(ElementBase): | ||||
|     namespace = 'google:nosave' | ||||
|     plugin_attrib = 'item' | ||||
|     plugin_multi_attrib = 'items' | ||||
|     interfaces = set(['jid', 'source', 'value']) | ||||
|     interfaces = {'jid', 'source', 'value'} | ||||
|  | ||||
|     def get_value(self): | ||||
|         return self._get_attr('value', '') == 'enabled' | ||||
|   | ||||
							
								
								
									
										10
									
								
								slixmpp/plugins/google/settings/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								slixmpp/plugins/google/settings/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.plugins.google.settings import stanza | ||||
| from slixmpp.plugins.google.settings.settings import GoogleSettings | ||||
							
								
								
									
										110
									
								
								slixmpp/plugins/google/settings/stanza.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								slixmpp/plugins/google/settings/stanza.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout | ||||
|     This file is part of slixmpp. | ||||
|  | ||||
|     See the file LICENSE for copying permission. | ||||
| """ | ||||
|  | ||||
| from slixmpp.xmlstream import ET, ElementBase | ||||
|  | ||||
|  | ||||
| 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') | ||||
| @@ -14,9 +14,3 @@ from slixmpp.plugins.xep_0004.dataforms import XEP_0004 | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0004) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0004 = XEP_0004 | ||||
| xep_0004.makeForm = xep_0004.make_form | ||||
| xep_0004.buildForm = xep_0004.build_form | ||||
|   | ||||
| @@ -23,7 +23,7 @@ class XEP_0004(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0004' | ||||
|     description = 'XEP-0004: Data Forms' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -14,21 +14,21 @@ class FormField(ElementBase): | ||||
|     name = 'field' | ||||
|     plugin_attrib = 'field' | ||||
|     plugin_multi_attrib = 'fields' | ||||
|     interfaces = set(('answer', 'desc', 'required', 'value', | ||||
|                       'label', 'type', 'var')) | ||||
|     sub_interfaces = set(('desc',)) | ||||
|     interfaces = {'answer', 'desc', 'required', 'value', | ||||
|                   'label', 'type', 'var'} | ||||
|     sub_interfaces = {'desc'} | ||||
|     plugin_tag_map = {} | ||||
|     plugin_attrib_map = {} | ||||
|  | ||||
|     field_types = set(('boolean', 'fixed', 'hidden', 'jid-multi', | ||||
|                        'jid-single', 'list-multi', 'list-single', | ||||
|                        'text-multi', 'text-private', 'text-single')) | ||||
|     field_types = {'boolean', 'fixed', 'hidden', 'jid-multi', | ||||
|                    'jid-single', 'list-multi', 'list-single', | ||||
|                    'text-multi', 'text-private', 'text-single'} | ||||
|  | ||||
|     true_values = set((True, '1', 'true')) | ||||
|     option_types = set(('list-multi', 'list-single')) | ||||
|     multi_line_types = set(('hidden', 'text-multi')) | ||||
|     multi_value_types = set(('hidden', 'jid-multi', | ||||
|                              'list-multi', 'text-multi')) | ||||
|     true_values = {True, '1', 'true'} | ||||
|     option_types = {'list-multi', 'list-single'} | ||||
|     multi_line_types = {'hidden', 'text-multi'} | ||||
|     multi_value_types = {'hidden', 'jid-multi', | ||||
|                          'list-multi', 'text-multi'} | ||||
|  | ||||
|     def setup(self, xml=None): | ||||
|         if ElementBase.setup(self, xml): | ||||
| @@ -164,8 +164,8 @@ class FieldOption(ElementBase): | ||||
|     namespace = 'jabber:x:data' | ||||
|     name = 'option' | ||||
|     plugin_attrib = 'option' | ||||
|     interfaces = set(('label', 'value')) | ||||
|     sub_interfaces = set(('value',)) | ||||
|     interfaces = {'label', 'value'} | ||||
|     sub_interfaces = {'value'} | ||||
|     plugin_multi_attrib = 'options' | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -24,8 +24,8 @@ class Form(ElementBase): | ||||
|     name = 'x' | ||||
|     plugin_attrib = 'form' | ||||
|     interfaces = OrderedSet(('instructions', 'reported', 'title', 'type', 'items', )) | ||||
|     sub_interfaces = set(('title',)) | ||||
|     form_types = set(('cancel', 'form', 'result', 'submit')) | ||||
|     sub_interfaces = {'title'} | ||||
|     form_types = {'cancel', 'form', 'result', 'submit'} | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         title = None | ||||
| @@ -81,18 +81,6 @@ class Form(ElementBase): | ||||
|         self.append(field) | ||||
|         return field | ||||
|  | ||||
|     def getXML(self, type='submit'): | ||||
|         self['type'] = type | ||||
|         log.warning("Form.getXML() is deprecated API compatibility " + \ | ||||
|                     "with plugins/old_0004.py") | ||||
|         return self.xml | ||||
|  | ||||
|     def fromXML(self, xml): | ||||
|         log.warning("Form.fromXML() is deprecated API compatibility " + \ | ||||
|                     "with plugins/old_0004.py") | ||||
|         n = Form(xml=xml) | ||||
|         return n | ||||
|  | ||||
|     def add_item(self, values): | ||||
|         itemXML = ET.Element('{%s}item' % self.namespace) | ||||
|         self.xml.append(itemXML) | ||||
|   | ||||
| @@ -14,7 +14,3 @@ from slixmpp.plugins.xep_0009.stanza import RPCQuery, MethodCall, MethodResponse | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0009) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0009 = XEP_0009 | ||||
|   | ||||
| @@ -25,7 +25,7 @@ def fault2xml(fault): | ||||
|  | ||||
| def xml2fault(params): | ||||
|     vals = [] | ||||
|     for value in params.findall('{%s}value' % _namespace): | ||||
|     for value in params.xml.findall('{%s}value' % _namespace): | ||||
|         vals.append(_xml2py(value)) | ||||
|     fault = dict() | ||||
|     fault['code'] = vals[0]['faultCode'] | ||||
| @@ -98,33 +98,34 @@ def xml2py(params): | ||||
|  | ||||
| def _xml2py(value): | ||||
|     namespace = 'jabber:iq:rpc' | ||||
|     if value.find('{%s}nil' % namespace) is not None: | ||||
|     find_value = value.find | ||||
|     if find_value('{%s}nil' % namespace) is not None: | ||||
|         return None | ||||
|     if value.find('{%s}i4' % namespace) is not None: | ||||
|         return int(value.find('{%s}i4' % namespace).text) | ||||
|     if value.find('{%s}int' % namespace) is not None: | ||||
|         return int(value.find('{%s}int' % namespace).text) | ||||
|     if value.find('{%s}boolean' % namespace) is not None: | ||||
|         return bool(int(value.find('{%s}boolean' % namespace).text)) | ||||
|     if value.find('{%s}string' % namespace) is not None: | ||||
|         return value.find('{%s}string' % namespace).text | ||||
|     if value.find('{%s}double' % namespace) is not None: | ||||
|         return float(value.find('{%s}double' % namespace).text) | ||||
|     if value.find('{%s}base64' % namespace) is not None: | ||||
|         return rpcbase64(value.find('{%s}base64' % namespace).text.encode()) | ||||
|     if value.find('{%s}Base64' % namespace) is not None: | ||||
|     if find_value('{%s}i4' % namespace) is not None: | ||||
|         return int(find_value('{%s}i4' % namespace).text) | ||||
|     if find_value('{%s}int' % namespace) is not None: | ||||
|         return int(find_value('{%s}int' % namespace).text) | ||||
|     if find_value('{%s}boolean' % namespace) is not None: | ||||
|         return bool(int(find_value('{%s}boolean' % namespace).text)) | ||||
|     if find_value('{%s}string' % namespace) is not None: | ||||
|         return find_value('{%s}string' % namespace).text | ||||
|     if find_value('{%s}double' % namespace) is not None: | ||||
|         return float(find_value('{%s}double' % namespace).text) | ||||
|     if find_value('{%s}base64' % namespace) is not None: | ||||
|         return rpcbase64(find_value('{%s}base64' % namespace).text.encode()) | ||||
|     if find_value('{%s}Base64' % namespace) is not None: | ||||
|         # Older versions of XEP-0009 used Base64 | ||||
|         return rpcbase64(value.find('{%s}Base64' % namespace).text.encode()) | ||||
|     if value.find('{%s}dateTime.iso8601' % namespace) is not None: | ||||
|         return rpctime(value.find('{%s}dateTime.iso8601' % namespace).text) | ||||
|     if value.find('{%s}struct' % namespace) is not None: | ||||
|         return rpcbase64(find_value('{%s}Base64' % namespace).text.encode()) | ||||
|     if find_value('{%s}dateTime.iso8601' % namespace) is not None: | ||||
|         return rpctime(find_value('{%s}dateTime.iso8601' % namespace).text) | ||||
|     if find_value('{%s}struct' % namespace) is not None: | ||||
|         struct = {} | ||||
|         for member in value.find('{%s}struct' % namespace).findall('{%s}member' % namespace): | ||||
|         for member in find_value('{%s}struct' % namespace).findall('{%s}member' % namespace): | ||||
|             struct[member.find('{%s}name' % namespace).text] = _xml2py(member.find('{%s}value' % namespace)) | ||||
|         return struct | ||||
|     if value.find('{%s}array' % namespace) is not None: | ||||
|     if find_value('{%s}array' % namespace) is not None: | ||||
|         array = [] | ||||
|         for val in value.find('{%s}array' % namespace).find('{%s}data' % namespace).findall('{%s}value' % namespace): | ||||
|         for val in find_value('{%s}array' % namespace).find('{%s}data' % namespace).findall('{%s}value' % namespace): | ||||
|             array.append(_xml2py(val)) | ||||
|         return array | ||||
|     raise ValueError() | ||||
|   | ||||
| @@ -163,7 +163,7 @@ class ACL: | ||||
|  | ||||
|     @classmethod | ||||
|     def _next_token(cls, expression, index): | ||||
|         new_index = expression.find('*', index) | ||||
|         new_index = expression.xml.find('*', index) | ||||
|         if new_index == 0: | ||||
|             return '' | ||||
|         else: | ||||
| @@ -182,7 +182,7 @@ class ACL: | ||||
|             #! print "[TOKEN] '%s'" % token | ||||
|             size = len(token) | ||||
|             if size > 0: | ||||
|                 token_index = value.find(token, position) | ||||
|                 token_index = value.xml.find(token, position) | ||||
|                 if token_index == -1: | ||||
|                     return False | ||||
|                 else: | ||||
|   | ||||
| @@ -24,7 +24,7 @@ class XEP_0009(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0009' | ||||
|     description = 'XEP-0009: Jabber-RPC' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
| @@ -121,7 +121,7 @@ class XEP_0009(BasePlugin): | ||||
|     def _recipient_unvailable(self, iq): | ||||
|         payload = iq.get_payload() | ||||
|         iq = iq.reply() | ||||
|         error().set_payload(payload) | ||||
|         iq.error().set_payload(payload) | ||||
|         iq['error']['code'] = '404' | ||||
|         iq['error']['type'] = 'wait' | ||||
|         iq['error']['condition'] = 'recipient-unavailable' | ||||
|   | ||||
| @@ -14,8 +14,8 @@ class RPCQuery(ElementBase): | ||||
|     name = 'query' | ||||
|     namespace = 'jabber:iq:rpc' | ||||
|     plugin_attrib = 'rpc_query' | ||||
|     interfaces = set(()) | ||||
|     subinterfaces = set(()) | ||||
|     interfaces = {} | ||||
|     subinterfaces = {} | ||||
|     plugin_attrib_map = {} | ||||
|     plugin_tag_map = {} | ||||
|  | ||||
| @@ -24,8 +24,8 @@ class MethodCall(ElementBase): | ||||
|     name = 'methodCall' | ||||
|     namespace = 'jabber:iq:rpc' | ||||
|     plugin_attrib = 'method_call' | ||||
|     interfaces = set(('method_name', 'params')) | ||||
|     subinterfaces = set(()) | ||||
|     interfaces = {'method_name', 'params'} | ||||
|     subinterfaces = {} | ||||
|     plugin_attrib_map = {} | ||||
|     plugin_tag_map = {} | ||||
|  | ||||
| @@ -46,8 +46,8 @@ class MethodResponse(ElementBase): | ||||
|     name = 'methodResponse' | ||||
|     namespace = 'jabber:iq:rpc' | ||||
|     plugin_attrib = 'method_response' | ||||
|     interfaces = set(('params', 'fault')) | ||||
|     subinterfaces = set(()) | ||||
|     interfaces = {'params', 'fault'} | ||||
|     subinterfaces = {} | ||||
|     plugin_attrib_map = {} | ||||
|     plugin_tag_map = {} | ||||
|  | ||||
|   | ||||
| @@ -13,7 +13,3 @@ from slixmpp.plugins.xep_0012.last_activity import XEP_0012 | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0012) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0004 = XEP_0012 | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class XEP_0012(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0012' | ||||
|     description = 'XEP-0012: Last Activity' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
| @@ -66,7 +66,7 @@ class XEP_0012(BasePlugin): | ||||
|         self.del_last_activity(jid) | ||||
|  | ||||
|     def start_uptime(self, status=None): | ||||
|         self.set_last_activity(jid, 0, status) | ||||
|         self.set_last_activity(None, 0, status) | ||||
|  | ||||
|     def set_last_activity(self, jid=None, seconds=None, status=None): | ||||
|         self.api['set_last_activity'](jid, args={ | ||||
|   | ||||
| @@ -14,7 +14,7 @@ class LastActivity(ElementBase): | ||||
|     name = 'query' | ||||
|     namespace = 'jabber:iq:last' | ||||
|     plugin_attrib = 'last_activity' | ||||
|     interfaces = set(('seconds', 'status')) | ||||
|     interfaces = {'seconds', 'status'} | ||||
|  | ||||
|     def get_seconds(self): | ||||
|         return int(self._get_attr('seconds')) | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class XEP_0013(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0013' | ||||
|     description = 'XEP-0013: Flexible Offline Message Retrieval' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -14,7 +14,7 @@ class Offline(ElementBase): | ||||
|     name = 'offline' | ||||
|     namespace = 'http://jabber.org/protocol/offline' | ||||
|     plugin_attrib = 'offline' | ||||
|     interfaces = set(['fetch', 'purge', 'results']) | ||||
|     interfaces = {'fetch', 'purge', 'results'} | ||||
|     bool_interfaces = interfaces | ||||
|  | ||||
|     def setup(self, xml=None): | ||||
| @@ -39,9 +39,9 @@ class Item(ElementBase): | ||||
|     name = 'item' | ||||
|     namespace = 'http://jabber.org/protocol/offline' | ||||
|     plugin_attrib = 'item' | ||||
|     interfaces = set(['action', 'node', 'jid']) | ||||
|     interfaces = {'action', 'node', 'jid'} | ||||
|  | ||||
|     actions = set(['view', 'remove']) | ||||
|     actions = {'view', 'remove'} | ||||
|  | ||||
|     def get_jid(self): | ||||
|         return JID(self._get_attr('jid')) | ||||
|   | ||||
| @@ -17,7 +17,7 @@ class XEP_0016(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0016' | ||||
|     description = 'XEP-0016: Privacy Lists' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -18,14 +18,14 @@ class Active(ElementBase): | ||||
|     name = 'active' | ||||
|     namespace = 'jabber:iq:privacy' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(['name']) | ||||
|     interfaces = {'name'} | ||||
|  | ||||
|  | ||||
| class Default(ElementBase): | ||||
|     name = 'default' | ||||
|     namespace = 'jabber:iq:privacy' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(['name']) | ||||
|     interfaces = {'name'} | ||||
|  | ||||
|  | ||||
| class List(ElementBase): | ||||
| @@ -33,7 +33,7 @@ class List(ElementBase): | ||||
|     namespace = 'jabber:iq:privacy' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'lists' | ||||
|     interfaces = set(['name']) | ||||
|     interfaces = {'name'} | ||||
|  | ||||
|     def add_item(self, value, action, order, itype=None, iq=False, | ||||
|                  message=False, presence_in=False, presence_out=False): | ||||
| @@ -55,9 +55,9 @@ class Item(ElementBase): | ||||
|     namespace = 'jabber:iq:privacy' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'items' | ||||
|     interfaces = set(['type', 'value', 'action', 'order', 'iq', | ||||
|                       'message', 'presence_in', 'presence_out']) | ||||
|     bool_interfaces = set(['message', 'iq', 'presence_in', 'presence_out']) | ||||
|     interfaces = {'type', 'value', 'action', 'order', 'iq', | ||||
|                   'message', 'presence_in', 'presence_out'} | ||||
|     bool_interfaces = {'message', 'iq', 'presence_in', 'presence_out'} | ||||
|  | ||||
|     type_values = ('', 'jid', 'group', 'subscription') | ||||
|     action_values = ('allow', 'deny') | ||||
|   | ||||
| @@ -24,7 +24,7 @@ class XEP_0020(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0020' | ||||
|     description = 'XEP-0020: Feature Negotiation' | ||||
|     dependencies = set(['xep_0004', 'xep_0030']) | ||||
|     dependencies = {'xep_0004', 'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -13,7 +13,7 @@ class Signed(ElementBase): | ||||
|     name = 'x' | ||||
|     namespace = 'jabber:x:signed' | ||||
|     plugin_attrib = 'signed' | ||||
|     interfaces = set(['signed']) | ||||
|     interfaces = {'signed'} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_signed(self, value): | ||||
| @@ -33,7 +33,7 @@ class Encrypted(ElementBase): | ||||
|     name = 'x' | ||||
|     namespace = 'jabber:x:encrypted' | ||||
|     plugin_attrib = 'encrypted' | ||||
|     interfaces = set(['encrypted']) | ||||
|     interfaces = {'encrypted'} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_encrypted(self, value): | ||||
|   | ||||
| @@ -15,8 +15,3 @@ from slixmpp.plugins.xep_0030.disco import XEP_0030 | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0030) | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0030 = XEP_0030 | ||||
| XEP_0030.getInfo = XEP_0030.get_info | ||||
| XEP_0030.make_static = XEP_0030.restore_defaults | ||||
|   | ||||
| @@ -71,8 +71,8 @@ class DiscoInfo(ElementBase): | ||||
|     name = 'query' | ||||
|     namespace = 'http://jabber.org/protocol/disco#info' | ||||
|     plugin_attrib = 'disco_info' | ||||
|     interfaces = set(('node', 'features', 'identities')) | ||||
|     lang_interfaces = set(('identities',)) | ||||
|     interfaces = {'node', 'features', 'identities'} | ||||
|     lang_interfaces = {'identities'} | ||||
|  | ||||
|     # Cache identities and features | ||||
|     _identities = set() | ||||
| @@ -91,7 +91,7 @@ class DiscoInfo(ElementBase): | ||||
|         """ | ||||
|         ElementBase.setup(self, xml) | ||||
|  | ||||
|         self._identities = set([id[0:3] for id in self['identities']]) | ||||
|         self._identities = {id[0:3] for id in self['identities']} | ||||
|         self._features = self['features'] | ||||
|  | ||||
|     def add_identity(self, category, itype, name=None, lang=None): | ||||
| @@ -137,7 +137,7 @@ class DiscoInfo(ElementBase): | ||||
|         identity = (category, itype, lang) | ||||
|         if identity in self._identities: | ||||
|             self._identities.remove(identity) | ||||
|             for id_xml in self.findall('{%s}identity' % self.namespace): | ||||
|             for id_xml in self.xml.findall('{%s}identity' % self.namespace): | ||||
|                 id = (id_xml.attrib['category'], | ||||
|                       id_xml.attrib['type'], | ||||
|                       id_xml.attrib.get('{%s}lang' % self.xml_ns, None)) | ||||
| @@ -163,7 +163,7 @@ class DiscoInfo(ElementBase): | ||||
|             identities = set() | ||||
|         else: | ||||
|             identities = [] | ||||
|         for id_xml in self.findall('{%s}identity' % self.namespace): | ||||
|         for id_xml in self.xml.findall('{%s}identity' % self.namespace): | ||||
|             xml_lang = id_xml.attrib.get('{%s}lang' % self.xml_ns, None) | ||||
|             if lang is None or xml_lang == lang: | ||||
|                 id = (id_xml.attrib['category'], | ||||
| @@ -205,7 +205,7 @@ class DiscoInfo(ElementBase): | ||||
|         Arguments: | ||||
|             lang -- Optional, standard xml:lang value. | ||||
|         """ | ||||
|         for id_xml in self.findall('{%s}identity' % self.namespace): | ||||
|         for id_xml in self.xml.findall('{%s}identity' % self.namespace): | ||||
|             if lang is None: | ||||
|                 self.xml.remove(id_xml) | ||||
|             elif id_xml.attrib.get('{%s}lang' % self.xml_ns, None) == lang: | ||||
| @@ -239,7 +239,7 @@ class DiscoInfo(ElementBase): | ||||
|         """ | ||||
|         if feature in self._features: | ||||
|             self._features.remove(feature) | ||||
|             for feature_xml in self.findall('{%s}feature' % self.namespace): | ||||
|             for feature_xml in self.xml.findall('{%s}feature' % self.namespace): | ||||
|                 if feature_xml.attrib['var'] == feature: | ||||
|                     self.xml.remove(feature_xml) | ||||
|                     return True | ||||
| @@ -251,7 +251,7 @@ class DiscoInfo(ElementBase): | ||||
|             features = set() | ||||
|         else: | ||||
|             features = [] | ||||
|         for feature_xml in self.findall('{%s}feature' % self.namespace): | ||||
|         for feature_xml in self.xml.findall('{%s}feature' % self.namespace): | ||||
|             if dedupe: | ||||
|                 features.add(feature_xml.attrib['var']) | ||||
|             else: | ||||
| @@ -272,5 +272,5 @@ class DiscoInfo(ElementBase): | ||||
|     def del_features(self): | ||||
|         """Remove all features.""" | ||||
|         self._features = set() | ||||
|         for feature_xml in self.findall('{%s}feature' % self.namespace): | ||||
|         for feature_xml in self.xml.findall('{%s}feature' % self.namespace): | ||||
|             self.xml.remove(feature_xml) | ||||
|   | ||||
| @@ -45,7 +45,7 @@ class DiscoItems(ElementBase): | ||||
|     name = 'query' | ||||
|     namespace = 'http://jabber.org/protocol/disco#items' | ||||
|     plugin_attrib = 'disco_items' | ||||
|     interfaces = set(('node', 'items')) | ||||
|     interfaces = {'node', 'items'} | ||||
|  | ||||
|     # Cache items | ||||
|     _items = set() | ||||
| @@ -62,7 +62,7 @@ class DiscoItems(ElementBase): | ||||
|             xml -- Use an existing XML object for the stanza's values. | ||||
|         """ | ||||
|         ElementBase.setup(self, xml) | ||||
|         self._items = set([item[0:2] for item in self['items']]) | ||||
|         self._items = {item[0:2] for item in self['items']} | ||||
|  | ||||
|     def add_item(self, jid, node=None, name=None): | ||||
|         """ | ||||
| @@ -95,7 +95,7 @@ class DiscoItems(ElementBase): | ||||
|             node -- Optional extra identifying information. | ||||
|         """ | ||||
|         if (jid, node) in self._items: | ||||
|             for item_xml in self.findall('{%s}item' % self.namespace): | ||||
|             for item_xml in self.xml.findall('{%s}item' % self.namespace): | ||||
|                 item = (item_xml.attrib['jid'], | ||||
|                         item_xml.attrib.get('node', None)) | ||||
|                 if item == (jid, node): | ||||
| @@ -138,7 +138,7 @@ class DiscoItem(ElementBase): | ||||
|     name = 'item' | ||||
|     namespace = 'http://jabber.org/protocol/disco#items' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('jid', 'node', 'name')) | ||||
|     interfaces = {'jid', 'node', 'name'} | ||||
|  | ||||
|     def get_node(self): | ||||
|         """Return the item's node name or ``None``.""" | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| """ | ||||
|  | ||||
| import logging | ||||
| import threading | ||||
|  | ||||
| from slixmpp import Iq | ||||
| from slixmpp.exceptions import XMPPError, IqError, IqTimeout | ||||
| @@ -48,7 +47,6 @@ class StaticDisco(object): | ||||
|         self.nodes = {} | ||||
|         self.xmpp = xmpp | ||||
|         self.disco = disco | ||||
|         self.lock = threading.RLock() | ||||
|  | ||||
|     def add_node(self, jid=None, node=None, ifrom=None): | ||||
|         """ | ||||
| @@ -59,48 +57,45 @@ class StaticDisco(object): | ||||
|             jid  -- The JID that will own the new stanzas. | ||||
|             node -- The node that will own the new stanzas. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if jid is None: | ||||
|                 jid = self.xmpp.boundjid.full | ||||
|             if node is None: | ||||
|                 node = '' | ||||
|             if ifrom is None: | ||||
|                 ifrom = '' | ||||
|             if isinstance(ifrom, JID): | ||||
|                 ifrom = ifrom.full | ||||
|             if (jid, node, ifrom) not in self.nodes: | ||||
|                 self.nodes[(jid, node, ifrom)] = {'info': DiscoInfo(), | ||||
|                                            'items': DiscoItems()} | ||||
|                 self.nodes[(jid, node, ifrom)]['info']['node'] = node | ||||
|                 self.nodes[(jid, node, ifrom)]['items']['node'] = node | ||||
|         if jid is None: | ||||
|             jid = self.xmpp.boundjid.full | ||||
|         if node is None: | ||||
|             node = '' | ||||
|         if ifrom is None: | ||||
|             ifrom = '' | ||||
|         if isinstance(ifrom, JID): | ||||
|             ifrom = ifrom.full | ||||
|         if (jid, node, ifrom) not in self.nodes: | ||||
|             self.nodes[(jid, node, ifrom)] = {'info': DiscoInfo(), | ||||
|                                        'items': DiscoItems()} | ||||
|             self.nodes[(jid, node, ifrom)]['info']['node'] = node | ||||
|             self.nodes[(jid, node, ifrom)]['items']['node'] = node | ||||
|  | ||||
|     def get_node(self, jid=None, node=None, ifrom=None): | ||||
|         with self.lock: | ||||
|             if jid is None: | ||||
|                 jid = self.xmpp.boundjid.full | ||||
|             if node is None: | ||||
|                 node = '' | ||||
|             if ifrom is None: | ||||
|                 ifrom = '' | ||||
|             if isinstance(ifrom, JID): | ||||
|                 ifrom = ifrom.full | ||||
|             if (jid, node, ifrom) not in self.nodes: | ||||
|                 self.add_node(jid, node, ifrom) | ||||
|             return self.nodes[(jid, node, ifrom)] | ||||
|         if jid is None: | ||||
|             jid = self.xmpp.boundjid.full | ||||
|         if node is None: | ||||
|             node = '' | ||||
|         if ifrom is None: | ||||
|             ifrom = '' | ||||
|         if isinstance(ifrom, JID): | ||||
|             ifrom = ifrom.full | ||||
|         if (jid, node, ifrom) not in self.nodes: | ||||
|             self.add_node(jid, node, ifrom) | ||||
|         return self.nodes[(jid, node, ifrom)] | ||||
|  | ||||
|     def node_exists(self, jid=None, node=None, ifrom=None): | ||||
|         with self.lock: | ||||
|             if jid is None: | ||||
|                 jid = self.xmpp.boundjid.full | ||||
|             if node is None: | ||||
|                 node = '' | ||||
|             if ifrom is None: | ||||
|                 ifrom = '' | ||||
|             if isinstance(ifrom, JID): | ||||
|                 ifrom = ifrom.full | ||||
|             if (jid, node, ifrom) not in self.nodes: | ||||
|                 return False | ||||
|             return True | ||||
|         if jid is None: | ||||
|             jid = self.xmpp.boundjid.full | ||||
|         if node is None: | ||||
|             node = '' | ||||
|         if ifrom is None: | ||||
|             ifrom = '' | ||||
|         if isinstance(ifrom, JID): | ||||
|             ifrom = ifrom.full | ||||
|         if (jid, node, ifrom) not in self.nodes: | ||||
|             return False | ||||
|         return True | ||||
|  | ||||
|     # ================================================================= | ||||
|     # Node Handlers | ||||
| @@ -199,14 +194,13 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is not used. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if not self.node_exists(jid, node): | ||||
|                 if not node: | ||||
|                     return DiscoInfo() | ||||
|                 else: | ||||
|                     raise XMPPError(condition='item-not-found') | ||||
|         if not self.node_exists(jid, node): | ||||
|             if not node: | ||||
|                 return DiscoInfo() | ||||
|             else: | ||||
|                 return self.get_node(jid, node)['info'] | ||||
|                 raise XMPPError(condition='item-not-found') | ||||
|         else: | ||||
|             return self.get_node(jid, node)['info'] | ||||
|  | ||||
|     def set_info(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -214,9 +208,8 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is a disco#info substanza. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             self.add_node(jid, node) | ||||
|             self.get_node(jid, node)['info'] = data | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info'] = data | ||||
|  | ||||
|     def del_info(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -224,9 +217,8 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is not used. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if self.node_exists(jid, node): | ||||
|                 self.get_node(jid, node)['info'] = DiscoInfo() | ||||
|         if self.node_exists(jid, node): | ||||
|             self.get_node(jid, node)['info'] = DiscoInfo() | ||||
|  | ||||
|     def get_items(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -234,14 +226,13 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is not used. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if not self.node_exists(jid, node): | ||||
|                 if not node: | ||||
|                     return DiscoItems() | ||||
|                 else: | ||||
|                     raise XMPPError(condition='item-not-found') | ||||
|         if not self.node_exists(jid, node): | ||||
|             if not node: | ||||
|                 return DiscoItems() | ||||
|             else: | ||||
|                 return self.get_node(jid, node)['items'] | ||||
|                 raise XMPPError(condition='item-not-found') | ||||
|         else: | ||||
|             return self.get_node(jid, node)['items'] | ||||
|  | ||||
|     def set_items(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -250,10 +241,9 @@ class StaticDisco(object): | ||||
|         The data parameter may provide: | ||||
|             items -- A set of items in tuple format. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             items = data.get('items', set()) | ||||
|             self.add_node(jid, node) | ||||
|             self.get_node(jid, node)['items']['items'] = items | ||||
|         items = data.get('items', set()) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['items']['items'] = items | ||||
|  | ||||
|     def del_items(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -261,9 +251,8 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is not used. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if self.node_exists(jid, node): | ||||
|                 self.get_node(jid, node)['items'] = DiscoItems() | ||||
|         if self.node_exists(jid, node): | ||||
|             self.get_node(jid, node)['items'] = DiscoItems() | ||||
|  | ||||
|     def add_identity(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -275,13 +264,12 @@ class StaticDisco(object): | ||||
|             name     -- Optional human readable name for this identity. | ||||
|             lang     -- Optional standard xml:lang value. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             self.add_node(jid, node) | ||||
|             self.get_node(jid, node)['info'].add_identity( | ||||
|                     data.get('category', ''), | ||||
|                     data.get('itype', ''), | ||||
|                     data.get('name', None), | ||||
|                     data.get('lang', None)) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info'].add_identity( | ||||
|                 data.get('category', ''), | ||||
|                 data.get('itype', ''), | ||||
|                 data.get('name', None), | ||||
|                 data.get('lang', None)) | ||||
|  | ||||
|     def set_identities(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -291,10 +279,9 @@ class StaticDisco(object): | ||||
|             identities -- A list of identities in tuple form: | ||||
|                             (category, type, name, lang) | ||||
|         """ | ||||
|         with self.lock: | ||||
|             identities = data.get('identities', set()) | ||||
|             self.add_node(jid, node) | ||||
|             self.get_node(jid, node)['info']['identities'] = identities | ||||
|         identities = data.get('identities', set()) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info']['identities'] = identities | ||||
|  | ||||
|     def del_identity(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -306,13 +293,12 @@ class StaticDisco(object): | ||||
|             name     -- Optional human readable name for this identity. | ||||
|             lang     -- Optional, standard xml:lang value. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if self.node_exists(jid, node): | ||||
|                 self.get_node(jid, node)['info'].del_identity( | ||||
|                         data.get('category', ''), | ||||
|                         data.get('itype', ''), | ||||
|                         data.get('name', None), | ||||
|                         data.get('lang', None)) | ||||
|         if self.node_exists(jid, node): | ||||
|             self.get_node(jid, node)['info'].del_identity( | ||||
|                     data.get('category', ''), | ||||
|                     data.get('itype', ''), | ||||
|                     data.get('name', None), | ||||
|                     data.get('lang', None)) | ||||
|  | ||||
|     def del_identities(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -320,9 +306,8 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is not used. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if self.node_exists(jid, node): | ||||
|                 del self.get_node(jid, node)['info']['identities'] | ||||
|         if self.node_exists(jid, node): | ||||
|             del self.get_node(jid, node)['info']['identities'] | ||||
|  | ||||
|     def add_feature(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -331,10 +316,9 @@ class StaticDisco(object): | ||||
|         The data parameter should include: | ||||
|             feature -- The namespace of the supported feature. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             self.add_node(jid, node) | ||||
|             self.get_node(jid, node)['info'].add_feature( | ||||
|                     data.get('feature', '')) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info'].add_feature( | ||||
|                 data.get('feature', '')) | ||||
|  | ||||
|     def set_features(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -343,10 +327,9 @@ class StaticDisco(object): | ||||
|         The data parameter should include: | ||||
|             features -- The new set of supported features. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             features = data.get('features', set()) | ||||
|             self.add_node(jid, node) | ||||
|             self.get_node(jid, node)['info']['features'] = features | ||||
|         features = data.get('features', set()) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info']['features'] = features | ||||
|  | ||||
|     def del_feature(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -355,10 +338,9 @@ class StaticDisco(object): | ||||
|         The data parameter should include: | ||||
|             feature -- The namespace of the removed feature. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if self.node_exists(jid, node): | ||||
|                 self.get_node(jid, node)['info'].del_feature( | ||||
|                         data.get('feature', '')) | ||||
|         if self.node_exists(jid, node): | ||||
|             self.get_node(jid, node)['info'].del_feature( | ||||
|                     data.get('feature', '')) | ||||
|  | ||||
|     def del_features(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -366,10 +348,9 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is not used. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if not self.node_exists(jid, node): | ||||
|                 return | ||||
|             del self.get_node(jid, node)['info']['features'] | ||||
|         if not self.node_exists(jid, node): | ||||
|             return | ||||
|         del self.get_node(jid, node)['info']['features'] | ||||
|  | ||||
|     def add_item(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -381,12 +362,11 @@ class StaticDisco(object): | ||||
|                      non-addressable items. | ||||
|             name  -- Optional human readable name for the item. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             self.add_node(jid, node) | ||||
|             self.get_node(jid, node)['items'].add_item( | ||||
|                     data.get('ijid', ''), | ||||
|                     node=data.get('inode', ''), | ||||
|                     name=data.get('name', '')) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['items'].add_item( | ||||
|                 data.get('ijid', ''), | ||||
|                 node=data.get('inode', ''), | ||||
|                 name=data.get('name', '')) | ||||
|  | ||||
|     def del_item(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -396,11 +376,10 @@ class StaticDisco(object): | ||||
|             ijid  -- JID of the item to remove. | ||||
|             inode -- Optional extra identifying information. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if self.node_exists(jid, node): | ||||
|                 self.get_node(jid, node)['items'].del_item( | ||||
|                         data.get('ijid', ''), | ||||
|                         node=data.get('inode', None)) | ||||
|         if self.node_exists(jid, node): | ||||
|             self.get_node(jid, node)['items'].del_item( | ||||
|                     data.get('ijid', ''), | ||||
|                     node=data.get('inode', None)) | ||||
|  | ||||
|     def cache_info(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -410,12 +389,11 @@ class StaticDisco(object): | ||||
|         containing the disco info to cache, or | ||||
|         the disco#info substanza itself. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if isinstance(data, Iq): | ||||
|                 data = data['disco_info'] | ||||
|         if isinstance(data, Iq): | ||||
|             data = data['disco_info'] | ||||
|  | ||||
|             self.add_node(jid, node, ifrom) | ||||
|             self.get_node(jid, node, ifrom)['info'] = data | ||||
|         self.add_node(jid, node, ifrom) | ||||
|         self.get_node(jid, node, ifrom)['info'] = data | ||||
|  | ||||
|     def get_cached_info(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -423,8 +401,7 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is not used. | ||||
|         """ | ||||
|         with self.lock: | ||||
|             if not self.node_exists(jid, node, ifrom): | ||||
|                 return None | ||||
|             else: | ||||
|                 return self.get_node(jid, node, ifrom)['info'] | ||||
|         if not self.node_exists(jid, node, ifrom): | ||||
|             return None | ||||
|         else: | ||||
|             return self.get_node(jid, node, ifrom)['info'] | ||||
|   | ||||
| @@ -14,7 +14,3 @@ from slixmpp.plugins.xep_0033.addresses import XEP_0033 | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0033) | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0033 = XEP_0033 | ||||
| Addresses.addAddress = Addresses.add_address | ||||
|   | ||||
| @@ -22,7 +22,7 @@ class XEP_0033(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0033' | ||||
|     description = 'XEP-0033: Extended Stanza Addressing' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -37,9 +37,9 @@ class Address(ElementBase): | ||||
|     name = 'address' | ||||
|     namespace = 'http://jabber.org/protocol/address' | ||||
|     plugin_attrib = 'address' | ||||
|     interfaces = set(['type', 'jid', 'node', 'uri', 'desc', 'delivered']) | ||||
|     interfaces = {'type', 'jid', 'node', 'uri', 'desc', 'delivered'} | ||||
|  | ||||
|     address_types = set(('bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to')) | ||||
|     address_types = {'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'} | ||||
|  | ||||
|     def get_jid(self): | ||||
|         return JID(self._get_attr('jid')) | ||||
| @@ -117,15 +117,12 @@ for atype in ('all', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'): | ||||
|     setattr(Addresses, "set_%s" % atype, set_multi) | ||||
|     setattr(Addresses, "del_%s" % atype, del_multi) | ||||
|  | ||||
|     # To retain backwards compatibility: | ||||
|     setattr(Addresses, "get%s" % atype.title(), get_multi) | ||||
|     setattr(Addresses, "set%s" % atype.title(), set_multi) | ||||
|     setattr(Addresses, "del%s" % atype.title(), del_multi) | ||||
|     if atype == 'all': | ||||
|         Addresses.interfaces.add('addresses') | ||||
|         setattr(Addresses, "getAddresses", get_multi) | ||||
|         setattr(Addresses, "setAddresses", set_multi) | ||||
|         setattr(Addresses, "delAddresses", del_multi) | ||||
|         setattr(Addresses, "get_addresses", get_multi) | ||||
|         setattr(Addresses, "set_addresses", set_multi) | ||||
|         setattr(Addresses, "del_addresses", del_multi) | ||||
|  | ||||
|  | ||||
|  | ||||
| register_stanza_plugin(Addresses, Address, iterable=True) | ||||
|   | ||||
| @@ -25,86 +25,86 @@ class MUCPresence(ElementBase): | ||||
|     name = 'x' | ||||
|     namespace = 'http://jabber.org/protocol/muc#user' | ||||
|     plugin_attrib = 'muc' | ||||
|     interfaces = set(('affiliation', 'role', 'jid', 'nick', 'room')) | ||||
|     affiliations = set(('', )) | ||||
|     roles = set(('', )) | ||||
|     interfaces = {'affiliation', 'role', 'jid', 'nick', 'room'} | ||||
|     affiliations = {'', } | ||||
|     roles = {'', } | ||||
|  | ||||
|     def getXMLItem(self): | ||||
|     def get_xml_item(self): | ||||
|         item = self.xml.find('{http://jabber.org/protocol/muc#user}item') | ||||
|         if item is None: | ||||
|             item = ET.Element('{http://jabber.org/protocol/muc#user}item') | ||||
|             self.xml.append(item) | ||||
|         return item | ||||
|  | ||||
|     def getAffiliation(self): | ||||
|     def get_affiliation(self): | ||||
|         #TODO if no affilation, set it to the default and return default | ||||
|         item = self.getXMLItem() | ||||
|         item = self.get_xml_item() | ||||
|         return item.get('affiliation', '') | ||||
|  | ||||
|     def setAffiliation(self, value): | ||||
|         item = self.getXMLItem() | ||||
|     def set_affiliation(self, value): | ||||
|         item = self.get_xml_item() | ||||
|         #TODO check for valid affiliation | ||||
|         item.attrib['affiliation'] = value | ||||
|         return self | ||||
|  | ||||
|     def delAffiliation(self): | ||||
|         item = self.getXMLItem() | ||||
|     def del_affiliation(self): | ||||
|         item = self.get_xml_item() | ||||
|         #TODO set default affiliation | ||||
|         if 'affiliation' in item.attrib: del item.attrib['affiliation'] | ||||
|         return self | ||||
|  | ||||
|     def getJid(self): | ||||
|         item = self.getXMLItem() | ||||
|     def get_jid(self): | ||||
|         item = self.get_xml_item() | ||||
|         return JID(item.get('jid', '')) | ||||
|  | ||||
|     def setJid(self, value): | ||||
|         item = self.getXMLItem() | ||||
|     def set_jid(self, value): | ||||
|         item = self.get_xml_item() | ||||
|         if not isinstance(value, str): | ||||
|             value = str(value) | ||||
|         item.attrib['jid'] = value | ||||
|         return self | ||||
|  | ||||
|     def delJid(self): | ||||
|         item = self.getXMLItem() | ||||
|     def del_jid(self): | ||||
|         item = self.get_xml_item() | ||||
|         if 'jid' in item.attrib: del item.attrib['jid'] | ||||
|         return self | ||||
|  | ||||
|     def getRole(self): | ||||
|         item = self.getXMLItem() | ||||
|     def get_role(self): | ||||
|         item = self.get_xml_item() | ||||
|         #TODO get default role, set default role if none | ||||
|         return item.get('role', '') | ||||
|  | ||||
|     def setRole(self, value): | ||||
|         item = self.getXMLItem() | ||||
|     def set_role(self, value): | ||||
|         item = self.get_xml_item() | ||||
|         #TODO check for valid role | ||||
|         item.attrib['role'] = value | ||||
|         return self | ||||
|  | ||||
|     def delRole(self): | ||||
|         item = self.getXMLItem() | ||||
|     def del_role(self): | ||||
|         item = self.get_xml_item() | ||||
|         #TODO set default role | ||||
|         if 'role' in item.attrib: del item.attrib['role'] | ||||
|         return self | ||||
|  | ||||
|     def getNick(self): | ||||
|     def get_nick(self): | ||||
|         return self.parent()['from'].resource | ||||
|  | ||||
|     def getRoom(self): | ||||
|     def get_room(self): | ||||
|         return self.parent()['from'].bare | ||||
|  | ||||
|     def setNick(self, value): | ||||
|     def set_nick(self, value): | ||||
|         log.warning("Cannot set nick through mucpresence plugin.") | ||||
|         return self | ||||
|  | ||||
|     def setRoom(self, value): | ||||
|     def set_room(self, value): | ||||
|         log.warning("Cannot set room through mucpresence plugin.") | ||||
|         return self | ||||
|  | ||||
|     def delNick(self): | ||||
|     def del_nick(self): | ||||
|         log.warning("Cannot delete nick through mucpresence plugin.") | ||||
|         return self | ||||
|  | ||||
|     def delRoom(self): | ||||
|     def del_room(self): | ||||
|         log.warning("Cannot delete room through mucpresence plugin.") | ||||
|         return self | ||||
|  | ||||
| @@ -117,11 +117,11 @@ class XEP_0045(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0045' | ||||
|     description = 'XEP-0045: Multi-User Chat' | ||||
|     dependencies = set(['xep_0030', 'xep_0004']) | ||||
|     dependencies = {'xep_0030', 'xep_0004'} | ||||
|  | ||||
|     def plugin_init(self): | ||||
|         self.rooms = {} | ||||
|         self.ourNicks = {} | ||||
|         self.our_nicks = {} | ||||
|         self.xep = '0045' | ||||
|         # load MUC support in presence stanzas | ||||
|         register_stanza_plugin(Presence, MUCPresence) | ||||
| @@ -160,6 +160,7 @@ class XEP_0045(BasePlugin): | ||||
|         got_online = False | ||||
|         if pr['muc']['room'] not in self.rooms.keys(): | ||||
|             return | ||||
|         self.xmpp.roster[pr['from']].ignore_updates = True | ||||
|         entry = pr['muc'].get_stanza_values() | ||||
|         entry['show'] = pr['show'] | ||||
|         entry['status'] = pr['status'] | ||||
| @@ -200,28 +201,28 @@ class XEP_0045(BasePlugin): | ||||
|         """ | ||||
|         self.xmpp.event('groupchat_subject', msg) | ||||
|  | ||||
|     def jidInRoom(self, room, jid): | ||||
|     def jid_in_room(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): | ||||
|     def get_nick(self, room, jid): | ||||
|         for nick in self.rooms[room]: | ||||
|             entry = self.rooms[room][nick] | ||||
|             if entry is not None and entry['jid'].full == jid: | ||||
|                 return nick | ||||
|  | ||||
|     def configureRoom(self, room, form=None, ifrom=None): | ||||
|     def configure_room(self, room, form=None, ifrom=None): | ||||
|         if form is None: | ||||
|             form = self.getRoomConfig(room, ifrom=ifrom) | ||||
|             form = self.get_room_config(room, ifrom=ifrom) | ||||
|         iq = self.xmpp.make_iq_set() | ||||
|         iq['to'] = room | ||||
|         if ifrom is not None: | ||||
|             iq['from'] = ifrom | ||||
|         query = ET.Element('{http://jabber.org/protocol/muc#owner}query') | ||||
|         form = form.getXML('submit') | ||||
|         form['type'] = 'submit' | ||||
|         query.append(form) | ||||
|         iq.append(query) | ||||
|         # For now, swallow errors to preserve existing API | ||||
| @@ -233,7 +234,7 @@ class XEP_0045(BasePlugin): | ||||
|             return False | ||||
|         return True | ||||
|  | ||||
|     def joinMUC(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None, pfrom=None): | ||||
|     def join_muc(self, room, nick, maxhistory="0", password='', wait=False, pstatus=None, pshow=None, pfrom=None): | ||||
|         """ Join the specified room, requesting 'maxhistory' lines of history. | ||||
|         """ | ||||
|         stanza = self.xmpp.make_presence(pto="%s/%s" % (room, nick), pstatus=pstatus, pshow=pshow, pfrom=pfrom) | ||||
| @@ -257,7 +258,7 @@ class XEP_0045(BasePlugin): | ||||
|             expect = ET.Element("{%s}presence" % self.xmpp.default_ns, {'from':"%s/%s" % (room, nick)}) | ||||
|             self.xmpp.send(stanza, expect) | ||||
|         self.rooms[room] = {} | ||||
|         self.ourNicks[room] = nick | ||||
|         self.our_nicks[room] = nick | ||||
|  | ||||
|     def destroy(self, room, reason='', altroom = '', ifrom=None): | ||||
|         iq = self.xmpp.make_iq_set() | ||||
| @@ -282,7 +283,7 @@ class XEP_0045(BasePlugin): | ||||
|             return False | ||||
|         return True | ||||
|  | ||||
|     def setAffiliation(self, room, jid=None, nick=None, affiliation='member', ifrom=None): | ||||
|     def set_affiliation(self, room, jid=None, nick=None, affiliation='member', ifrom=None): | ||||
|         """ Change room affiliation.""" | ||||
|         if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'): | ||||
|             raise TypeError | ||||
| @@ -304,7 +305,7 @@ class XEP_0045(BasePlugin): | ||||
|             return False | ||||
|         return True | ||||
|  | ||||
|     def setRole(self, room, nick, role): | ||||
|     def set_role(self, room, nick, role): | ||||
|         """ Change role property of a nick in a room. | ||||
|             Typically, roles are temporary (they last only as long as you are in the | ||||
|             room), whereas affiliations are permanent (they last across groupchat | ||||
| @@ -336,7 +337,7 @@ class XEP_0045(BasePlugin): | ||||
|         msg.append(x) | ||||
|         self.xmpp.send(msg) | ||||
|  | ||||
|     def leaveMUC(self, room, nick, msg='', pfrom=None): | ||||
|     def leave_muc(self, room, nick, msg='', pfrom=None): | ||||
|         """ Leave the specified room. | ||||
|         """ | ||||
|         if msg: | ||||
| @@ -345,7 +346,7 @@ class XEP_0045(BasePlugin): | ||||
|             self.xmpp.send_presence(pshow='unavailable', pto="%s/%s" % (room, nick), pfrom=pfrom) | ||||
|         del self.rooms[room] | ||||
|  | ||||
|     def getRoomConfig(self, room, ifrom=''): | ||||
|     def get_room_config(self, room, ifrom=''): | ||||
|         iq = self.xmpp.make_iq_get('http://jabber.org/protocol/muc#owner') | ||||
|         iq['to'] = room | ||||
|         iq['from'] = ifrom | ||||
| @@ -359,9 +360,9 @@ class XEP_0045(BasePlugin): | ||||
|         form = result.xml.find('{http://jabber.org/protocol/muc#owner}query/{jabber:x:data}x') | ||||
|         if form is None: | ||||
|             raise ValueError | ||||
|         return self.xmpp.plugin['xep_0004'].buildForm(form) | ||||
|         return self.xmpp.plugin['xep_0004'].build_form(form) | ||||
|  | ||||
|     def cancelConfig(self, room, ifrom=None): | ||||
|     def cancel_config(self, room, ifrom=None): | ||||
|         query = ET.Element('{http://jabber.org/protocol/muc#owner}query') | ||||
|         x = ET.Element('{jabber:x:data}x', type='cancel') | ||||
|         query.append(x) | ||||
| @@ -370,40 +371,40 @@ class XEP_0045(BasePlugin): | ||||
|         iq['from'] = ifrom | ||||
|         iq.send() | ||||
|  | ||||
|     def setRoomConfig(self, room, config, ifrom=''): | ||||
|     def set_room_config(self, room, config, ifrom=''): | ||||
|         query = ET.Element('{http://jabber.org/protocol/muc#owner}query') | ||||
|         x = config.getXML('submit') | ||||
|         query.append(x) | ||||
|         config['type'] = 'submit' | ||||
|         query.append(config) | ||||
|         iq = self.xmpp.make_iq_set(query) | ||||
|         iq['to'] = room | ||||
|         iq['from'] = ifrom | ||||
|         iq.send() | ||||
|  | ||||
|     def getJoinedRooms(self): | ||||
|     def get_joined_rooms(self): | ||||
|         return self.rooms.keys() | ||||
|  | ||||
|     def getOurJidInRoom(self, roomJid): | ||||
|     def get_our_jid_in_room(self, room_jid): | ||||
|         """ Return the jid we're using in a room. | ||||
|         """ | ||||
|         return "%s/%s" % (roomJid, self.ourNicks[roomJid]) | ||||
|         return "%s/%s" % (room_jid, self.our_nicks[room_jid]) | ||||
|  | ||||
|     def getJidProperty(self, room, nick, jidProperty): | ||||
|     def get_jid_property(self, room, nick, jid_property): | ||||
|         """ Get the property of a nick in a room, such as its 'jid' or 'affiliation' | ||||
|             If not found, return None. | ||||
|         """ | ||||
|         if room in self.rooms and nick in self.rooms[room] and jidProperty in self.rooms[room][nick]: | ||||
|             return self.rooms[room][nick][jidProperty] | ||||
|         if room in self.rooms and nick in self.rooms[room] and jid_property in self.rooms[room][nick]: | ||||
|             return self.rooms[room][nick][jid_property] | ||||
|         else: | ||||
|             return None | ||||
|  | ||||
|     def getRoster(self, room): | ||||
|     def get_roster(self, room): | ||||
|         """ Get the list of nicks in a room. | ||||
|         """ | ||||
|         if room not in self.rooms.keys(): | ||||
|             return None | ||||
|         return self.rooms[room].keys() | ||||
|  | ||||
|     def getUsersByAffiliation(cls, room, affiliation='member', ifrom=None): | ||||
|     def get_users_by_affiliation(cls, room, affiliation='member', ifrom=None): | ||||
|         if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'): | ||||
|             raise TypeError | ||||
|         query = ET.Element('{http://jabber.org/protocol/muc#admin}query') | ||||
| @@ -414,5 +415,4 @@ class XEP_0045(BasePlugin): | ||||
|         return iq.send() | ||||
|  | ||||
|  | ||||
| xep_0045 = XEP_0045 | ||||
| register_plugin(XEP_0045) | ||||
|   | ||||
| @@ -15,7 +15,3 @@ from slixmpp.plugins.xep_0047.ibb import XEP_0047 | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0047) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0047 = XEP_0047 | ||||
|   | ||||
| @@ -18,7 +18,7 @@ class XEP_0047(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0047' | ||||
|     description = 'XEP-0047: In-band Bytestreams' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|     default_config = { | ||||
|         'block_size': 4096, | ||||
|   | ||||
| @@ -21,7 +21,7 @@ class Open(ElementBase): | ||||
|     name = 'open' | ||||
|     namespace = 'http://jabber.org/protocol/ibb' | ||||
|     plugin_attrib = 'ibb_open' | ||||
|     interfaces = set(('block_size', 'sid', 'stanza')) | ||||
|     interfaces = {'block_size', 'sid', 'stanza'} | ||||
|  | ||||
|     def get_block_size(self): | ||||
|         return int(self._get_attr('block-size', '0')) | ||||
| @@ -37,8 +37,8 @@ class Data(ElementBase): | ||||
|     name = 'data' | ||||
|     namespace = 'http://jabber.org/protocol/ibb' | ||||
|     plugin_attrib = 'ibb_data' | ||||
|     interfaces = set(('seq', 'sid', 'data')) | ||||
|     sub_interfaces = set(['data']) | ||||
|     interfaces = {'seq', 'sid', 'data'} | ||||
|     sub_interfaces = {'data'} | ||||
|  | ||||
|     def get_seq(self): | ||||
|         return int(self._get_attr('seq', '0')) | ||||
| @@ -67,4 +67,4 @@ class Close(ElementBase): | ||||
|     name = 'close' | ||||
|     namespace = 'http://jabber.org/protocol/ibb' | ||||
|     plugin_attrib = 'ibb_close' | ||||
|     interfaces = set(['sid']) | ||||
|     interfaces = {'sid'} | ||||
|   | ||||
| @@ -24,7 +24,7 @@ class XEP_0048(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0048' | ||||
|     description = 'XEP-0048: Bookmarks' | ||||
|     dependencies = set(['xep_0045', 'xep_0049', 'xep_0060', 'xep_0163', 'xep_0223']) | ||||
|     dependencies = {'xep_0045', 'xep_0049', 'xep_0060', 'xep_0163', 'xep_0223'} | ||||
|     stanza = stanza | ||||
|     default_config = { | ||||
|         'auto_join': False, | ||||
| @@ -59,7 +59,7 @@ class XEP_0048(BasePlugin): | ||||
|         for conf in bookmarks['conferences']: | ||||
|             if conf['autojoin']: | ||||
|                 log.debug('Auto joining %s as %s', conf['jid'], conf['nick']) | ||||
|                 self.xmpp['xep_0045'].joinMUC(conf['jid'], conf['nick'], | ||||
|                 self.xmpp['xep_0045'].join_muc(conf['jid'], conf['nick'], | ||||
|                         password=conf['password']) | ||||
|  | ||||
|     def set_bookmarks(self, bookmarks, method=None, **iqargs): | ||||
|   | ||||
| @@ -40,8 +40,8 @@ class Conference(ElementBase): | ||||
|     namespace = 'storage:bookmarks' | ||||
|     plugin_attrib = 'conference' | ||||
|     plugin_multi_attrib = 'conferences' | ||||
|     interfaces = set(['nick', 'password', 'autojoin', 'jid', 'name']) | ||||
|     sub_interfaces = set(['nick', 'password']) | ||||
|     interfaces = {'nick', 'password', 'autojoin', 'jid', 'name'} | ||||
|     sub_interfaces = {'nick', 'password'} | ||||
|  | ||||
|     def get_autojoin(self): | ||||
|         value = self._get_attr('autojoin') | ||||
| @@ -58,7 +58,7 @@ class URL(ElementBase): | ||||
|     namespace = 'storage:bookmarks' | ||||
|     plugin_attrib = 'url' | ||||
|     plugin_multi_attrib = 'urls' | ||||
|     interfaces = set(['url', 'name']) | ||||
|     interfaces = {'url', 'name'} | ||||
|  | ||||
|  | ||||
| register_stanza_plugin(Bookmarks, Conference, iterable=True) | ||||
|   | ||||
| @@ -23,7 +23,7 @@ class XEP_0049(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0049' | ||||
|     description = 'XEP-0049: Private XML Storage' | ||||
|     dependencies = set([]) | ||||
|     dependencies = {} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -13,7 +13,3 @@ from slixmpp.plugins.xep_0050.adhoc import XEP_0050 | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0050) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0050 = XEP_0050 | ||||
|   | ||||
| @@ -74,7 +74,7 @@ class XEP_0050(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0050' | ||||
|     description = 'XEP-0050: Ad-Hoc Commands' | ||||
|     dependencies = set(['xep_0030', 'xep_0004']) | ||||
|     dependencies = {'xep_0030', 'xep_0004'} | ||||
|     stanza = stanza | ||||
|     default_config = { | ||||
|         'session_db': None | ||||
| @@ -225,8 +225,8 @@ class XEP_0050(BasePlugin): | ||||
|         if len(payload) == 1: | ||||
|             payload = payload[0] | ||||
|  | ||||
|         interfaces = set([item.plugin_attrib for item in payload]) | ||||
|         payload_classes = set([item.__class__ for item in payload]) | ||||
|         interfaces = {item.plugin_attrib for item in payload} | ||||
|         payload_classes = {item.__class__ for item in payload} | ||||
|  | ||||
|         initial_session = {'id': sessionid, | ||||
|                            'from': iq['from'], | ||||
| @@ -322,8 +322,8 @@ class XEP_0050(BasePlugin): | ||||
|         interfaces = session.get('interfaces', set()) | ||||
|         payload_classes = session.get('payload_classes', set()) | ||||
|  | ||||
|         interfaces.update(set([item.plugin_attrib for item in payload])) | ||||
|         payload_classes.update(set([item.__class__ for item in payload])) | ||||
|         interfaces.update({item.plugin_attrib for item in payload}) | ||||
|         payload_classes.update({item.__class__ for item in payload}) | ||||
|  | ||||
|         session['interfaces'] = interfaces | ||||
|         session['payload_classes'] = payload_classes | ||||
|   | ||||
| @@ -72,11 +72,11 @@ class Command(ElementBase): | ||||
|     name = 'command' | ||||
|     namespace = 'http://jabber.org/protocol/commands' | ||||
|     plugin_attrib = 'command' | ||||
|     interfaces = set(('action', 'sessionid', 'node', | ||||
|                       'status', 'actions', 'notes')) | ||||
|     actions = set(('cancel', 'complete', 'execute', 'next', 'prev')) | ||||
|     statuses = set(('canceled', 'completed', 'executing')) | ||||
|     next_actions = set(('prev', 'next', 'complete')) | ||||
|     interfaces = {'action', 'sessionid', 'node', | ||||
|                   'status', 'actions', 'notes'} | ||||
|     actions = {'cancel', 'complete', 'execute', 'next', 'prev'} | ||||
|     statuses = {'canceled', 'completed', 'executing'} | ||||
|     next_actions = {'prev', 'next', 'complete'} | ||||
|  | ||||
|     def get_action(self): | ||||
|         """ | ||||
| @@ -100,7 +100,7 @@ class Command(ElementBase): | ||||
|         self.del_actions() | ||||
|         if values: | ||||
|             self._set_sub_text('{%s}actions' % self.namespace, '', True) | ||||
|             actions = self.find('{%s}actions' % self.namespace) | ||||
|             actions = self.xml.find('{%s}actions' % self.namespace) | ||||
|             for val in values: | ||||
|                 if val in self.next_actions: | ||||
|                     action = ET.Element('{%s}%s' % (self.namespace, val)) | ||||
| @@ -111,7 +111,7 @@ class Command(ElementBase): | ||||
|         Return the set of allowable next actions. | ||||
|         """ | ||||
|         actions = set() | ||||
|         actions_xml = self.find('{%s}actions' % self.namespace) | ||||
|         actions_xml = self.xml.find('{%s}actions' % self.namespace) | ||||
|         if actions_xml is not None: | ||||
|             for action in self.next_actions: | ||||
|                 action_xml = actions_xml.find('{%s}%s' % (self.namespace, | ||||
| @@ -136,7 +136,7 @@ class Command(ElementBase): | ||||
|              ('error', 'The command ran, but had errors')] | ||||
|         """ | ||||
|         notes = [] | ||||
|         notes_xml = self.findall('{%s}note' % self.namespace) | ||||
|         notes_xml = self.xml.findall('{%s}note' % self.namespace) | ||||
|         for note in notes_xml: | ||||
|             notes.append((note.attrib.get('type', 'info'), | ||||
|                           note.text)) | ||||
| @@ -167,7 +167,7 @@ class Command(ElementBase): | ||||
|         """ | ||||
|         Remove all notes associated with the command result. | ||||
|         """ | ||||
|         notes_xml = self.findall('{%s}note' % self.namespace) | ||||
|         notes_xml = self.xml.findall('{%s}note' % self.namespace) | ||||
|         for note in notes_xml: | ||||
|             self.xml.remove(note) | ||||
|  | ||||
|   | ||||
| @@ -10,15 +10,15 @@ class VCardTemp(ElementBase): | ||||
|     name = 'vCard' | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = 'vcard_temp' | ||||
|     interfaces = set(['FN', 'VERSION']) | ||||
|     sub_interfaces = set(['FN', 'VERSION']) | ||||
|     interfaces = {'FN', 'VERSION'} | ||||
|     sub_interfaces = {'FN', 'VERSION'} | ||||
|  | ||||
|  | ||||
| class Name(ElementBase): | ||||
|     name = 'N' | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(['FAMILY', 'GIVEN', 'MIDDLE', 'PREFIX', 'SUFFIX']) | ||||
|     interfaces = {'FAMILY', 'GIVEN', 'MIDDLE', 'PREFIX', 'SUFFIX'} | ||||
|     sub_interfaces = interfaces | ||||
|  | ||||
|     def _set_component(self, name, value): | ||||
| @@ -72,7 +72,7 @@ class Nickname(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'nicknames' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_nickname(self, value): | ||||
| @@ -95,9 +95,9 @@ class Email(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'emails' | ||||
|     interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400', 'USERID']) | ||||
|     sub_interfaces = set(['USERID']) | ||||
|     bool_interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400']) | ||||
|     interfaces = {'HOME', 'WORK', 'INTERNET', 'PREF', 'X400', 'USERID'} | ||||
|     sub_interfaces = {'USERID'} | ||||
|     bool_interfaces = {'HOME', 'WORK', 'INTERNET', 'PREF', 'X400'} | ||||
|  | ||||
|  | ||||
| class Address(ElementBase): | ||||
| @@ -105,12 +105,12 @@ class Address(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'addresses' | ||||
|     interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL', | ||||
|                       'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY', | ||||
|                       'REGION', 'PCODE', 'CTRY']) | ||||
|     sub_interfaces = set(['POBOX', 'EXTADD', 'STREET', 'LOCALITY', | ||||
|                           'REGION', 'PCODE', 'CTRY']) | ||||
|     bool_interfaces = set(['HOME', 'WORK', 'DOM', 'INTL', 'PREF']) | ||||
|     interfaces = {'HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL', | ||||
|                   'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY', | ||||
|                   'REGION', 'PCODE', 'CTRY'} | ||||
|     sub_interfaces = {'POBOX', 'EXTADD', 'STREET', 'LOCALITY', | ||||
|                       'REGION', 'PCODE', 'CTRY'} | ||||
|     bool_interfaces = {'HOME', 'WORK', 'DOM', 'INTL', 'PREF'} | ||||
|  | ||||
|  | ||||
| class Telephone(ElementBase): | ||||
| @@ -118,16 +118,16 @@ class Telephone(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'telephone_numbers' | ||||
|     interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', 'MSG', | ||||
|                       'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS', | ||||
|                       'PREF', 'NUMBER']) | ||||
|     sub_interfaces = set(['NUMBER']) | ||||
|     bool_interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', | ||||
|                            'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM', | ||||
|                            'ISDN', 'PCS', 'PREF']) | ||||
|     interfaces = {'HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', 'MSG', | ||||
|                   'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS', | ||||
|                   'PREF', 'NUMBER'} | ||||
|     sub_interfaces = {'NUMBER'} | ||||
|     bool_interfaces = {'HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', | ||||
|                        'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM', | ||||
|                        'ISDN', 'PCS', 'PREF'} | ||||
|  | ||||
|     def setup(self, xml=None): | ||||
|         super(Telephone, self).setup(xml=xml) | ||||
|         super().setup(xml=xml) | ||||
|         ## this blanks out numbers received from server | ||||
|         ##self._set_sub_text('NUMBER', '', keep=True) | ||||
|  | ||||
| @@ -143,10 +143,10 @@ class Label(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'labels' | ||||
|     interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT', | ||||
|                       'PREF', 'lines']) | ||||
|     bool_interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', | ||||
|                            'INT', 'PREF']) | ||||
|     interfaces = {'HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT', | ||||
|                   'PREF', 'lines'} | ||||
|     bool_interfaces = {'HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', | ||||
|                        'INT', 'PREF'} | ||||
|  | ||||
|     def add_line(self, value): | ||||
|         line = ET.Element('{%s}LINE' % self.namespace) | ||||
| @@ -177,7 +177,7 @@ class Geo(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'geolocations' | ||||
|     interfaces = set(['LAT', 'LON']) | ||||
|     interfaces = {'LAT', 'LON'} | ||||
|     sub_interfaces = interfaces | ||||
|  | ||||
|  | ||||
| @@ -186,8 +186,8 @@ class Org(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'organizations' | ||||
|     interfaces = set(['ORGNAME', 'ORGUNIT', 'orgunits']) | ||||
|     sub_interfaces = set(['ORGNAME', 'ORGUNIT']) | ||||
|     interfaces = {'ORGNAME', 'ORGUNIT', 'orgunits'} | ||||
|     sub_interfaces = {'ORGNAME', 'ORGUNIT'} | ||||
|  | ||||
|     def add_orgunit(self, value): | ||||
|         orgunit = ET.Element('{%s}ORGUNIT' % self.namespace) | ||||
| @@ -218,7 +218,7 @@ class Photo(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'photos' | ||||
|     interfaces = set(['TYPE', 'EXTVAL']) | ||||
|     interfaces = {'TYPE', 'EXTVAL'} | ||||
|     sub_interfaces = interfaces | ||||
|  | ||||
|  | ||||
| @@ -227,7 +227,7 @@ class Logo(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'logos' | ||||
|     interfaces = set(['TYPE', 'EXTVAL']) | ||||
|     interfaces = {'TYPE', 'EXTVAL'} | ||||
|     sub_interfaces = interfaces | ||||
|  | ||||
|  | ||||
| @@ -236,7 +236,7 @@ class Sound(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'sounds' | ||||
|     interfaces = set(['PHONETC', 'EXTVAL']) | ||||
|     interfaces = {'PHONETC', 'EXTVAL'} | ||||
|     sub_interfaces = interfaces | ||||
|  | ||||
|  | ||||
| @@ -244,7 +244,7 @@ class BinVal(ElementBase): | ||||
|     name = 'BINVAL' | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(['BINVAL']) | ||||
|     interfaces = {'BINVAL'} | ||||
|     is_extension = True | ||||
|  | ||||
|     def setup(self, xml=None): | ||||
| @@ -275,7 +275,7 @@ class Classification(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'classifications' | ||||
|     interfaces = set(['PUBLIC', 'PRIVATE', 'CONFIDENTIAL']) | ||||
|     interfaces = {'PUBLIC', 'PRIVATE', 'CONFIDENTIAL'} | ||||
|     bool_interfaces = interfaces | ||||
|  | ||||
|  | ||||
| @@ -284,7 +284,7 @@ class Categories(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'categories' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_categories(self, values): | ||||
| @@ -314,7 +314,7 @@ class Birthday(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'birthdays' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_bday(self, value): | ||||
| @@ -336,7 +336,7 @@ class Rev(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'revision_dates' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_rev(self, value): | ||||
| @@ -358,7 +358,7 @@ class Title(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'titles' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_title(self, value): | ||||
| @@ -373,7 +373,7 @@ class Role(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'roles' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_role(self, value): | ||||
| @@ -388,7 +388,7 @@ class Note(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'notes' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_note(self, value): | ||||
| @@ -403,7 +403,7 @@ class Desc(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'descriptions' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_desc(self, value): | ||||
| @@ -418,7 +418,7 @@ class URL(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'urls' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_url(self, value): | ||||
| @@ -433,7 +433,7 @@ class UID(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'uids' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_uid(self, value): | ||||
| @@ -448,7 +448,7 @@ class ProdID(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'product_ids' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_prodid(self, value): | ||||
| @@ -463,7 +463,7 @@ class Mailer(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'mailers' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_mailer(self, value): | ||||
| @@ -478,7 +478,7 @@ class SortString(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = 'SORT_STRING' | ||||
|     plugin_multi_attrib = 'sort_strings' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_sort_string(self, value): | ||||
| @@ -493,7 +493,7 @@ class Agent(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'agents' | ||||
|     interfaces = set(['EXTVAL']) | ||||
|     interfaces = {'EXTVAL'} | ||||
|     sub_interfaces = interfaces | ||||
|  | ||||
|  | ||||
| @@ -502,7 +502,7 @@ class JabberID(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'jids' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_jabberid(self, value): | ||||
| @@ -517,7 +517,7 @@ class TimeZone(ElementBase): | ||||
|     namespace = 'vcard-temp' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'timezones' | ||||
|     interfaces = set([name]) | ||||
|     interfaces = {name} | ||||
|     is_extension = True | ||||
|  | ||||
|     def set_tz(self, value): | ||||
|   | ||||
| @@ -29,7 +29,7 @@ class XEP_0054(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0054' | ||||
|     description = 'XEP-0054: vcard-temp' | ||||
|     dependencies = set(['xep_0030', 'xep_0082']) | ||||
|     dependencies = {'xep_0030', 'xep_0082'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -13,6 +13,3 @@ from slixmpp.plugins.xep_0059.rsm import ResultIterator, XEP_0059 | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0059) | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0059 = XEP_0059 | ||||
|   | ||||
| @@ -111,7 +111,7 @@ class XEP_0059(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0059' | ||||
|     description = 'XEP-0059: Result Set Management' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -64,13 +64,13 @@ class Set(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/rsm' | ||||
|     name = 'set' | ||||
|     plugin_attrib = 'rsm' | ||||
|     sub_interfaces = set(('first', 'after', 'before', 'count', | ||||
|                           'index', 'last', 'max')) | ||||
|     interfaces = set(('first_index', 'first', 'after', 'before', | ||||
|                       'count', 'index', 'last', 'max')) | ||||
|     sub_interfaces = {'first', 'after', 'before', 'count', | ||||
|                       'index', 'last', 'max'} | ||||
|     interfaces = {'first_index', 'first', 'after', 'before', | ||||
|                   'count', 'index', 'last', 'max'} | ||||
|  | ||||
|     def set_first_index(self, val): | ||||
|         fi = self.find("{%s}first" % (self.namespace)) | ||||
|         fi = self.xml.find("{%s}first" % (self.namespace)) | ||||
|         if fi is not None: | ||||
|             if val: | ||||
|                 fi.attrib['index'] = val | ||||
| @@ -82,7 +82,7 @@ class Set(ElementBase): | ||||
|             self.xml.append(fi) | ||||
|  | ||||
|     def get_first_index(self): | ||||
|         fi = self.find("{%s}first" % (self.namespace)) | ||||
|         fi = self.xml.find("{%s}first" % (self.namespace)) | ||||
|         if fi is not None: | ||||
|             return fi.attrib.get('index', '') | ||||
|  | ||||
|   | ||||
| @@ -13,7 +13,3 @@ from slixmpp.plugins.xep_0060 import stanza | ||||
|  | ||||
|  | ||||
| register_plugin(XEP_0060) | ||||
|  | ||||
|  | ||||
| # Retain some backwards compatibility | ||||
| xep_0060 = XEP_0060 | ||||
|   | ||||
| @@ -26,7 +26,7 @@ class XEP_0060(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0060' | ||||
|     description = 'XEP-0060: Publish-Subscribe' | ||||
|     dependencies = set(['xep_0030', 'xep_0004', 'xep_0082', 'xep_0131']) | ||||
|     dependencies = {'xep_0030', 'xep_0004', 'xep_0082', 'xep_0131'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -11,7 +11,7 @@ from slixmpp.xmlstream import ET | ||||
|  | ||||
| class OptionalSetting(object): | ||||
|  | ||||
|     interfaces = set(('required',)) | ||||
|     interfaces = {'required'} | ||||
|  | ||||
|     def set_required(self, value): | ||||
|         if value in (True, 'true', 'True', '1'): | ||||
|   | ||||
| @@ -23,14 +23,14 @@ class Affiliations(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'affiliations' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class Affiliation(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'affiliation' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'affiliation', 'jid')) | ||||
|     interfaces = {'node', 'affiliation', 'jid'} | ||||
|  | ||||
|     def set_jid(self, value): | ||||
|         self._set_attr('jid', str(value)) | ||||
| @@ -43,7 +43,7 @@ class Subscription(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'subscription' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('jid', 'node', 'subscription', 'subid')) | ||||
|     interfaces = {'jid', 'node', 'subscription', 'subid'} | ||||
|  | ||||
|     def set_jid(self, value): | ||||
|         self._set_attr('jid', str(value)) | ||||
| @@ -56,21 +56,21 @@ class Subscriptions(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'subscriptions' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class SubscribeOptions(ElementBase, OptionalSetting): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'subscribe-options' | ||||
|     plugin_attrib = 'suboptions' | ||||
|     interfaces = set(('required',)) | ||||
|     interfaces = {'required'} | ||||
|  | ||||
|  | ||||
| class Item(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'item' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('id', 'payload')) | ||||
|     interfaces = {'id', 'payload'} | ||||
|  | ||||
|     def set_payload(self, value): | ||||
|         del self['payload'] | ||||
| @@ -95,7 +95,7 @@ class Items(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'items' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'max_items')) | ||||
|     interfaces = {'node', 'max_items'} | ||||
|  | ||||
|     def set_max_items(self, value): | ||||
|         self._set_attr('max_items', str(value)) | ||||
| @@ -105,14 +105,14 @@ class Create(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'create' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class Default(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'default' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'type')) | ||||
|     interfaces = {'node', 'type'} | ||||
|  | ||||
|     def get_type(self): | ||||
|         t = self._get_attr('type') | ||||
| @@ -125,14 +125,14 @@ class Publish(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'publish' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class Retract(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'retract' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'notify')) | ||||
|     interfaces = {'node', 'notify'} | ||||
|  | ||||
|     def get_notify(self): | ||||
|         notify = self._get_attr('notify') | ||||
| @@ -156,7 +156,7 @@ class Unsubscribe(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'unsubscribe' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'jid', 'subid')) | ||||
|     interfaces = {'node', 'jid', 'subid'} | ||||
|  | ||||
|     def set_jid(self, value): | ||||
|         self._set_attr('jid', str(value)) | ||||
| @@ -169,7 +169,7 @@ class Subscribe(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'subscribe' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'jid')) | ||||
|     interfaces = {'node', 'jid'} | ||||
|  | ||||
|     def set_jid(self, value): | ||||
|         self._set_attr('jid', str(value)) | ||||
| @@ -182,7 +182,7 @@ class Configure(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'configure' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'type')) | ||||
|     interfaces = {'node', 'type'} | ||||
|  | ||||
|     def getType(self): | ||||
|         t = self._get_attr('type') | ||||
| @@ -195,7 +195,7 @@ class Options(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'options' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('jid', 'node', 'options')) | ||||
|     interfaces = {'jid', 'node', 'options'} | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         ElementBase.__init__(self, *args, **kwargs) | ||||
| @@ -206,7 +206,10 @@ class Options(ElementBase): | ||||
|         return form | ||||
|  | ||||
|     def set_options(self, value): | ||||
|         self.xml.append(value.getXML()) | ||||
|         if isinstance(value, ElementBase): | ||||
|             self.xml.append(value.xml) | ||||
|         else: | ||||
|             self.xml.append(value) | ||||
|         return self | ||||
|  | ||||
|     def del_options(self): | ||||
| @@ -224,7 +227,7 @@ class PublishOptions(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub' | ||||
|     name = 'publish-options' | ||||
|     plugin_attrib = 'publish_options' | ||||
|     interfaces = set(('publish_options',)) | ||||
|     interfaces = {'publish_options'} | ||||
|     is_extension = True | ||||
|  | ||||
|     def get_publish_options(self): | ||||
| @@ -238,7 +241,10 @@ class PublishOptions(ElementBase): | ||||
|         if value is None: | ||||
|             self.del_publish_options() | ||||
|         else: | ||||
|             self.xml.append(value.getXML()) | ||||
|             if isinstance(value, ElementBase): | ||||
|                 self.xml.append(value.xml) | ||||
|             else: | ||||
|                 self.xml.append(value) | ||||
|         return self | ||||
|  | ||||
|     def del_publish_options(self): | ||||
|   | ||||
| @@ -13,18 +13,18 @@ from slixmpp.xmlstream import ElementBase, ET, register_stanza_plugin | ||||
| class PubsubErrorCondition(ElementBase): | ||||
|  | ||||
|     plugin_attrib = 'pubsub' | ||||
|     interfaces = set(('condition', 'unsupported')) | ||||
|     interfaces = {'condition', 'unsupported'} | ||||
|     plugin_attrib_map = {} | ||||
|     plugin_tag_map = {} | ||||
|     conditions = set(('closed-node', 'configuration-required', 'invalid-jid', | ||||
|                       'invalid-options', 'invalid-payload', 'invalid-subid', | ||||
|                       'item-forbidden', 'item-required', 'jid-required', | ||||
|                       'max-items-exceeded', 'max-nodes-exceeded', | ||||
|                       'nodeid-required', 'not-in-roster-group', | ||||
|                       'not-subscribed', 'payload-too-big', | ||||
|                       'payload-required', 'pending-subscription', | ||||
|                       'presence-subscription-required', 'subid-required', | ||||
|                       'too-many-subscriptions', 'unsupported')) | ||||
|     conditions = {'closed-node', 'configuration-required', 'invalid-jid', | ||||
|                   'invalid-options', 'invalid-payload', 'invalid-subid', | ||||
|                   'item-forbidden', 'item-required', 'jid-required', | ||||
|                   'max-items-exceeded', 'max-nodes-exceeded', | ||||
|                   'nodeid-required', 'not-in-roster-group', | ||||
|                   'not-subscribed', 'payload-too-big', | ||||
|                   'payload-required', 'pending-subscription', | ||||
|                   'presence-subscription-required', 'subid-required', | ||||
|                   'too-many-subscriptions', 'unsupported'} | ||||
|     condition_ns = 'http://jabber.org/protocol/pubsub#errors' | ||||
|  | ||||
|     def setup(self, xml): | ||||
|   | ||||
| @@ -25,7 +25,7 @@ class EventItem(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'item' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('id', 'payload', 'node', 'publisher')) | ||||
|     interfaces = {'id', 'payload', 'node', 'publisher'} | ||||
|  | ||||
|     def set_payload(self, value): | ||||
|         self.xml.append(value) | ||||
| @@ -44,56 +44,56 @@ class EventRetract(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'retract' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('id',)) | ||||
|     interfaces = {'id'} | ||||
|  | ||||
|  | ||||
| class EventItems(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'items' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class EventCollection(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'collection' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class EventAssociate(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'associate' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class EventDisassociate(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'disassociate' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class EventConfiguration(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'configuration' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class EventPurge(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'purge' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class EventDelete(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'delete' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'redirect')) | ||||
|     interfaces = {'node', 'redirect'} | ||||
|  | ||||
|     def set_redirect(self, uri): | ||||
|         del self['redirect'] | ||||
| @@ -117,7 +117,7 @@ class EventSubscription(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#event' | ||||
|     name = 'subscription' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'expiry', 'jid', 'subid', 'subscription')) | ||||
|     interfaces = {'node', 'expiry', 'jid', 'subid', 'subscription'} | ||||
|  | ||||
|     def get_expiry(self): | ||||
|         expiry = self._get_attr('expiry') | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user