Compare commits
	
		
			80 Commits
		
	
	
		
			disco
			...
			slix-1.3.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d73f56a7af | ||
|   | 7c7f4308c5 | ||
|   | eab8c265f4 | ||
|   | 80b9cd43b1 | ||
|   | af1f9e08ad | ||
|   | e3fd0af9c8 | ||
|   | 27e23672c1 | ||
|   | b38e229359 | ||
|   | 9a563f1425 | ||
|   | 8b6f5953a7 | ||
|   | 2d2a80c73d | ||
|   | 4dfdd5d8e3 | ||
|   | 1994ed3025 | ||
|   | aaa45846d3 | ||
|   | d7ffcb54eb | ||
|   | c33749e57a | ||
|   | e4107d8b4d | ||
|   | da5cb72d3a | ||
|   | c372bd5168 | ||
|   | cabf623131 | ||
|   | ffc240d5b6 | ||
|   | cc4522d9cd | ||
|   | 5bf69dca76 | ||
|   | 59dad12820 | ||
|   | 007c836296 | ||
|   | 3721bf9f6b | ||
|   | 802949eba8 | ||
|   | 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 | ||
|   | 8b06aa1146 | ||
|   | 3c7236fe73 | ||
|   | 36824379c3 | ||
|   | a0a37c19ff | ||
|   | 1b5fe57a5e | ||
|   | 5da31db0c7 | ||
|   | f8cea760b6 | ||
|   | 5ef01ecdd1 | ||
|   | 62aafe0ee7 | ||
|   | cf3f36ac52 | ||
|   | b88d2ecd77 | ||
|   | e691850a2b | ||
|   | d4bff8dee6 | ||
|   | 187c350805 | ||
|   | 96d1c26f90 | ||
|   | 46a90749f8 | ||
|   | 0c63a4bbda | ||
|   | e4696e0471 | ||
|   | 8217dc5239 | ||
|   | 2586abc0d3 | ||
|   | 28f84ab3d9 | ||
|   | 813b45aded | 
							
								
								
									
										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 | ||||
							
								
								
									
										11
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								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 | ||||
|  | ||||
| @@ -36,7 +36,7 @@ The Slixmpp Boilerplate | ||||
| ------------------------- | ||||
| Projects using Slixmpp tend to follow a basic pattern for setting up client/component | ||||
| connections and configuration. Here is the gist of the boilerplate needed for a Slixmpp | ||||
| based project. See the documetation or examples directory for more detailed archetypes for | ||||
| based project. See the documentation or examples directory for more detailed archetypes for | ||||
| Slixmpp projects:: | ||||
|  | ||||
|     import logging | ||||
| @@ -108,6 +108,11 @@ Slixmpp Credits | ||||
|  | ||||
| **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', | ||||
|         interfaces = {'username', 'password', 'email', 'nick', 'name', | ||||
|                       'first', 'last', 'address', 'city', 'state', 'zip', | ||||
|                       'phone', 'url', 'date', 'misc', 'text', 'key', | ||||
|                           'registered', 'remove', 'instructions')) | ||||
|                       'registered', 'remove', 'instructions'} | ||||
|         sub_interfaces = interfaces | ||||
|  | ||||
|         def getRegistered(self): | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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.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 | ||||
|   | ||||
| @@ -50,7 +50,7 @@ class ActionBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|         register_stanza_plugin(Iq, Action) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -73,7 +73,7 @@ class ActionBot(slixmpp.ClientXMPP): | ||||
|         """ | ||||
|         self.event('custom_action', iq) | ||||
|  | ||||
|     def _handle_action_event(self, iq): | ||||
|     async def _handle_action_event(self, iq): | ||||
|         """ | ||||
|         Respond to the custom action event. | ||||
|         """ | ||||
| @@ -82,17 +82,20 @@ class ActionBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|         if method == 'is_prime' and param == '2': | ||||
|             print("got message: %s" % iq) | ||||
|             iq.reply() | ||||
|             iq['action']['status'] = 'done' | ||||
|             iq.send() | ||||
|             rep = iq.reply() | ||||
|             rep['action']['status'] = 'done' | ||||
|             await rep.send() | ||||
|         elif method == 'bye': | ||||
|             print("got message: %s" % iq) | ||||
|             rep = iq.reply() | ||||
|             rep['action']['status'] = 'done' | ||||
|             await rep.send() | ||||
|             self.disconnect() | ||||
|         else: | ||||
|             print("got message: %s" % iq) | ||||
|             iq.reply() | ||||
|             iq['action']['status'] = 'error' | ||||
|             iq.send() | ||||
|             rep = iq.reply() | ||||
|             rep['action']['status'] = 'error' | ||||
|             await rep.send() | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|   | ||||
| @@ -43,7 +43,7 @@ class ActionUserBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|         register_stanza_plugin(Iq, Action) | ||||
|  | ||||
|     def start(self, event): | ||||
|     async def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
| @@ -57,11 +57,11 @@ class ActionUserBot(slixmpp.ClientXMPP): | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|         await self.get_roster() | ||||
|  | ||||
|         self.send_custom_iq() | ||||
|         await self.send_custom_iq() | ||||
|  | ||||
|     def send_custom_iq(self): | ||||
|     async def send_custom_iq(self): | ||||
|         """Create and send two custom actions. | ||||
|  | ||||
|         If the first action was successful, then send | ||||
| @@ -74,14 +74,14 @@ class ActionUserBot(slixmpp.ClientXMPP): | ||||
|         iq['action']['param'] = '2' | ||||
|  | ||||
|         try: | ||||
|             resp = iq.send() | ||||
|             resp = await iq.send() | ||||
|             if resp['action']['status'] == 'done': | ||||
|                 #sending bye | ||||
|                 iq2 = self.Iq() | ||||
|                 iq2['to'] = self.action_provider | ||||
|                 iq2['type'] = 'set' | ||||
|                 iq2['action']['method'] = 'bye' | ||||
|                 iq2.send(block=False) | ||||
|                 await iq2.send() | ||||
|  | ||||
|                 self.disconnect() | ||||
|         except XMPPError: | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -55,8 +55,8 @@ class GTalkBot(slixmpp.ClientXMPP): | ||||
|             cert.verify('talk.google.com', der_cert) | ||||
|             logging.debug("CERT: Found GTalk certificate") | ||||
|         except cert.CertificateError as err: | ||||
|             log.error(err.message) | ||||
|             self.disconnect(send_close=False) | ||||
|             logging.error(err.message) | ||||
|             self.disconnect() | ||||
|  | ||||
|     def start(self, event): | ||||
|         """ | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
|  | ||||
| from slixmpp import ClientXMPP | ||||
|  | ||||
| from optparse import OptionParser | ||||
| from argparse import ArgumentParser | ||||
| import logging | ||||
| import getpass | ||||
|  | ||||
| @@ -23,7 +23,7 @@ class HTTPOverXMPPClient(ClientXMPP): | ||||
|         ClientXMPP.__init__(self, jid, password) | ||||
|         self.register_plugin('xep_0332')    # HTTP over XMPP Transport | ||||
|         self.add_event_handler( | ||||
|             'session_start', self.session_start, threaded=True | ||||
|             'session_start', self.session_start | ||||
|         ) | ||||
|         self.add_event_handler('http_request', self.http_request_received) | ||||
|         self.add_event_handler('http_response', self.http_response_received) | ||||
| @@ -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() | ||||
|  | ||||
|   | ||||
							
								
								
									
										98
									
								
								examples/mam.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										98
									
								
								examples/mam.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2017 Mathieu Pasquet | ||||
|     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 MAM(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A basic client fetching mam archive messages | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password, remote_jid, start): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|         self.remote_jid = remote_jid | ||||
|         self.start_date = start | ||||
|  | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|     async def start(self, *args): | ||||
|         """ | ||||
|         Fetch mam results for the specified JID. | ||||
|         Use RSM to paginate the results. | ||||
|         """ | ||||
|         results = self.plugin['xep_0313'].retrieve(jid=self.remote_jid, iterator=True, rsm={'max': 10}, start=self.start_date) | ||||
|         page = 1 | ||||
|         async for rsm in results: | ||||
|             print('Page %d' % page) | ||||
|             for msg in rsm['mam']['results']: | ||||
|                 forwarded = msg['mam_result']['forwarded'] | ||||
|                 timestamp = forwarded['delay']['stamp'] | ||||
|                 message = forwarded['stanza'] | ||||
|                 print('[%s] %s: %s' % (timestamp, message['from'], message['body'])) | ||||
|             page += 1 | ||||
|         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", "--remote-jid", dest="remote_jid", | ||||
|                         help="Remote JID") | ||||
|     parser.add_argument("--start", help="Start date", default='2017-09-20T12:00:00Z') | ||||
|  | ||||
|     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: ") | ||||
|     if args.remote_jid is None: | ||||
|         args.remote_jid = input("Remote JID: ") | ||||
|     if args.start is None: | ||||
|         args.start = input("Start time: ") | ||||
|  | ||||
|     xmpp = MAM(args.jid, args.password, args.remote_jid, args.start) | ||||
|     xmpp.register_plugin('xep_0313') | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process(forever=False) | ||||
							
								
								
									
										120
									
								
								examples/markup.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										120
									
								
								examples/markup.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| """ | ||||
|     Slixmpp: The Slick XMPP Library | ||||
|     Copyright (C) 2010  Nathanael C. Fritz | ||||
|     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.plugins.xep_0394 import stanza as markup_stanza | ||||
|  | ||||
|  | ||||
| class EchoBot(slixmpp.ClientXMPP): | ||||
|  | ||||
|     """ | ||||
|     A simple Slixmpp bot that will echo messages it | ||||
|     receives, along with a short thank you message. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, jid, password): | ||||
|         slixmpp.ClientXMPP.__init__(self, jid, password) | ||||
|  | ||||
|         # The session_start event will be triggered when | ||||
|         # the bot establishes its connection with the server | ||||
|         # and the XML streams are ready for use. We want to | ||||
|         # listen for this event so that we we can initialize | ||||
|         # our roster. | ||||
|         self.add_event_handler("session_start", self.start) | ||||
|  | ||||
|         # The message event is triggered whenever a message | ||||
|         # stanza is received. Be aware that that includes | ||||
|         # MUC messages and error messages. | ||||
|         self.add_event_handler("message", self.message) | ||||
|  | ||||
|     def start(self, event): | ||||
|         """ | ||||
|         Process the session_start event. | ||||
|  | ||||
|         Typical actions for the session_start event are | ||||
|         requesting the roster and broadcasting an initial | ||||
|         presence stanza. | ||||
|  | ||||
|         Arguments: | ||||
|             event -- An empty dictionary. The session_start | ||||
|                      event does not provide any additional | ||||
|                      data. | ||||
|         """ | ||||
|         self.send_presence() | ||||
|         self.get_roster() | ||||
|  | ||||
|     def message(self, msg): | ||||
|         """ | ||||
|         Process incoming message stanzas. Be aware that this also | ||||
|         includes MUC messages and error messages. It is usually | ||||
|         a good idea to check the messages's type before processing | ||||
|         or sending replies. | ||||
|  | ||||
|         Arguments: | ||||
|             msg -- The received message stanza. See the documentation | ||||
|                    for stanza objects and the Message stanza to see | ||||
|                    how it may be used. | ||||
|         """ | ||||
|         body = msg['body'] | ||||
|         new_body = self['xep_0394'].to_plain_text(body, msg['markup']) | ||||
|         xhtml = self['xep_0394'].to_xhtml_im(body, msg['markup']) | ||||
|         print('Plain text:', new_body) | ||||
|         print('XHTML-IM:', xhtml['body']) | ||||
|         message = msg.reply() | ||||
|         message['body'] = new_body | ||||
|         message['html']['body'] = xhtml['body'] | ||||
|         self.send(message) | ||||
|  | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     # Setup the command line arguments. | ||||
|     parser = ArgumentParser(description=EchoBot.__doc__) | ||||
|  | ||||
|     # Output verbosity options. | ||||
|     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") | ||||
|  | ||||
|     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: ") | ||||
|  | ||||
|     # Setup the EchoBot and register plugins. Note that while plugins may | ||||
|     # have interdependencies, the order in which you register them does | ||||
|     # not matter. | ||||
|     xmpp = EchoBot(args.jid, args.password) | ||||
|     xmpp.register_plugin('xep_0030') # Service Discovery | ||||
|     xmpp.register_plugin('xep_0199') # XMPP Ping | ||||
|     xmpp.register_plugin('xep_0394') # Message Markup | ||||
|  | ||||
|     # Connect to the XMPP server and start processing XMPP stanzas. | ||||
|     xmpp.connect() | ||||
|     xmpp.process() | ||||
| @@ -67,7 +67,7 @@ class MUCBot(slixmpp.ClientXMPP): | ||||
|         """ | ||||
|         self.get_roster() | ||||
|         self.send_presence() | ||||
|         self.plugin['xep_0045'].joinMUC(self.room, | ||||
|         self.plugin['xep_0045'].join_muc(self.room, | ||||
|                                          self.nick, | ||||
|                                          # If a room password is needed, use: | ||||
|                                          # password=the_room_password, | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
							
								
								
									
										48
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								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__ | ||||
|  | ||||
| @@ -35,11 +30,48 @@ CLASSIFIERS = [ | ||||
|     'License :: OSI Approved :: MIT License', | ||||
|     'Programming Language :: Python', | ||||
|     'Programming Language :: Python :: 3.4', | ||||
|     'Programming Language :: Python :: 3.5', | ||||
|     'Programming Language :: Python :: 3.6', | ||||
|     'Topic :: Internet :: XMPP', | ||||
|     'Topic :: Software Development :: Libraries :: Python Modules', | ||||
| ] | ||||
|  | ||||
| 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, | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| import asyncio | ||||
| import logging | ||||
|  | ||||
| from slixmpp.jid import JID | ||||
| from slixmpp.stanza import StreamFeatures | ||||
| from slixmpp.basexmpp import BaseXMPP | ||||
| from slixmpp.exceptions import XMPPError | ||||
| @@ -108,10 +109,21 @@ class ClientXMPP(BaseXMPP): | ||||
|                 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') | ||||
| @@ -141,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``. | ||||
|         """ | ||||
| @@ -240,7 +255,7 @@ class ClientXMPP(BaseXMPP): | ||||
|                 orig_cb(resp) | ||||
|             callback = wrapped | ||||
|  | ||||
|         iq.send(callback, timeout, timeout_callback) | ||||
|         return iq.send(callback, timeout, timeout_callback) | ||||
|  | ||||
|     def _reset_connection_state(self, event=None): | ||||
|         #TODO: Use stream state here | ||||
|   | ||||
| @@ -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']) | ||||
|   | ||||
| @@ -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' | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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') | ||||
| @@ -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', | ||||
|     field_types = {'boolean', 'fixed', 'hidden', 'jid-multi', | ||||
|                    'jid-single', 'list-multi', 'list-single', | ||||
|                        'text-multi', 'text-private', 'text-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 | ||||
|   | ||||
| @@ -92,13 +92,13 @@ def _py2xml(*args): | ||||
| def xml2py(params): | ||||
|     namespace = 'jabber:iq:rpc' | ||||
|     vals = [] | ||||
|     for param in params.xml.findall('{%s}param' % namespace): | ||||
|     for param in params.findall('{%s}param' % namespace): | ||||
|         vals.append(_xml2py(param.find('{%s}value' % namespace))) | ||||
|     return vals | ||||
|  | ||||
| def _xml2py(value): | ||||
|     namespace = 'jabber:iq:rpc' | ||||
|     find_value = value.xml.find | ||||
|     find_value = value.find | ||||
|     if find_value('{%s}nil' % namespace) is not None: | ||||
|         return None | ||||
|     if find_value('{%s}i4' % namespace) is not None: | ||||
|   | ||||
| @@ -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 = {} | ||||
|  | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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): | ||||
|         """ | ||||
| @@ -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``.""" | ||||
|   | ||||
| @@ -66,10 +66,11 @@ class StaticDisco(object): | ||||
|         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 | ||||
|             new_node = {'info': DiscoInfo(), 'items': DiscoItems()} | ||||
|             new_node['info']['node'] = node | ||||
|             new_node['items']['node'] = node | ||||
|             self.nodes[(jid, node, ifrom)] = new_node | ||||
|         return self.nodes[(jid, node, ifrom)] | ||||
|  | ||||
|     def get_node(self, jid=None, node=None, ifrom=None): | ||||
|         if jid is None: | ||||
| @@ -208,8 +209,8 @@ class StaticDisco(object): | ||||
|  | ||||
|         The data parameter is a disco#info substanza. | ||||
|         """ | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info'] = data | ||||
|         new_node = self.add_node(jid, node) | ||||
|         new_node['info'] = data | ||||
|  | ||||
|     def del_info(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -242,8 +243,8 @@ class StaticDisco(object): | ||||
|             items -- A set of items in tuple format. | ||||
|         """ | ||||
|         items = data.get('items', set()) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['items']['items'] = items | ||||
|         new_node = self.add_node(jid, node) | ||||
|         new_node['items']['items'] = items | ||||
|  | ||||
|     def del_items(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -264,8 +265,8 @@ class StaticDisco(object): | ||||
|             name     -- Optional human readable name for this identity. | ||||
|             lang     -- Optional standard xml:lang value. | ||||
|         """ | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info'].add_identity( | ||||
|         new_node = self.add_node(jid, node) | ||||
|         new_node['info'].add_identity( | ||||
|                 data.get('category', ''), | ||||
|                 data.get('itype', ''), | ||||
|                 data.get('name', None), | ||||
| @@ -280,8 +281,8 @@ class StaticDisco(object): | ||||
|                             (category, type, name, lang) | ||||
|         """ | ||||
|         identities = data.get('identities', set()) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info']['identities'] = identities | ||||
|         new_node = self.add_node(jid, node) | ||||
|         new_node['info']['identities'] = identities | ||||
|  | ||||
|     def del_identity(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -316,8 +317,8 @@ class StaticDisco(object): | ||||
|         The data parameter should include: | ||||
|             feature -- The namespace of the supported feature. | ||||
|         """ | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info'].add_feature( | ||||
|         new_node = self.add_node(jid, node) | ||||
|         new_node['info'].add_feature( | ||||
|                 data.get('feature', '')) | ||||
|  | ||||
|     def set_features(self, jid, node, ifrom, data): | ||||
| @@ -328,8 +329,8 @@ class StaticDisco(object): | ||||
|             features -- The new set of supported features. | ||||
|         """ | ||||
|         features = data.get('features', set()) | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['info']['features'] = features | ||||
|         new_node = self.add_node(jid, node) | ||||
|         new_node['info']['features'] = features | ||||
|  | ||||
|     def del_feature(self, jid, node, ifrom, data): | ||||
|         """ | ||||
| @@ -362,8 +363,8 @@ class StaticDisco(object): | ||||
|                      non-addressable items. | ||||
|             name  -- Optional human readable name for the item. | ||||
|         """ | ||||
|         self.add_node(jid, node) | ||||
|         self.get_node(jid, node)['items'].add_item( | ||||
|         new_node = self.add_node(jid, node) | ||||
|         new_node['items'].add_item( | ||||
|                 data.get('ijid', ''), | ||||
|                 node=data.get('inode', ''), | ||||
|                 name=data.get('name', '')) | ||||
| @@ -392,8 +393,8 @@ class StaticDisco(object): | ||||
|         if isinstance(data, Iq): | ||||
|             data = data['disco_info'] | ||||
|  | ||||
|         self.add_node(jid, node, ifrom) | ||||
|         self.get_node(jid, node, ifrom)['info'] = data | ||||
|         new_node = self.add_node(jid, node, ifrom) | ||||
|         new_node['info'] = data | ||||
|  | ||||
|     def get_cached_info(self, jid, node, ifrom, data): | ||||
|         """ | ||||
|   | ||||
| @@ -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,9 +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: | ||||
|     if atype == 'all': | ||||
|         Addresses.interfaces.add('addresses') | ||||
|         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) | ||||
| @@ -201,22 +201,22 @@ 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: | ||||
| @@ -234,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) | ||||
| @@ -258,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() | ||||
| @@ -283,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 | ||||
| @@ -305,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 | ||||
| @@ -337,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: | ||||
| @@ -346,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 | ||||
| @@ -362,7 +362,7 @@ class XEP_0045(BasePlugin): | ||||
|             raise ValueError | ||||
|         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) | ||||
| @@ -371,7 +371,7 @@ 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') | ||||
|         config['type'] = 'submit' | ||||
|         query.append(config) | ||||
| @@ -380,31 +380,31 @@ class XEP_0045(BasePlugin): | ||||
|         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') | ||||
| @@ -415,5 +415,4 @@ class XEP_0045(BasePlugin): | ||||
|         return iq.send() | ||||
|  | ||||
|  | ||||
| xep_0045 = XEP_0045 | ||||
| register_plugin(XEP_0045) | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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): | ||||
|         """ | ||||
| @@ -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', | ||||
|     interfaces = {'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']) | ||||
|                   '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', | ||||
|     interfaces = {'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', | ||||
|                   'PREF', 'NUMBER'} | ||||
|     sub_interfaces = {'NUMBER'} | ||||
|     bool_interfaces = {'HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', | ||||
|                        'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM', | ||||
|                            'ISDN', 'PCS', 'PREF']) | ||||
|                        '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): | ||||
| @@ -261,7 +261,7 @@ class BinVal(ElementBase): | ||||
|  | ||||
|     def get_binval(self): | ||||
|         parent = self.parent() | ||||
|         xml = parent.find('{%s}BINVAL' % self.namespace) | ||||
|         xml = parent.xml.find('{%s}BINVAL' % self.namespace) | ||||
|         if xml is not None: | ||||
|             return base64.b64decode(bytes(xml.text)) | ||||
|         return b'' | ||||
| @@ -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): | ||||
|   | ||||
| @@ -19,23 +19,27 @@ from slixmpp.exceptions import XMPPError | ||||
| log = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| class ResultIterator(): | ||||
| class ResultIterator: | ||||
|  | ||||
|     """ | ||||
|     An iterator for Result Set Managment | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, query, interface, results='substanzas', amount=10, | ||||
|                        start=None, reverse=False): | ||||
|                        start=None, reverse=False, recv_interface=None, | ||||
|                        pre_cb=None, post_cb=None): | ||||
|         """ | ||||
|         Arguments: | ||||
|            query     -- The template query | ||||
|            interface -- The substanza of the query, for example disco_items | ||||
|            interface -- The substanza of the query to send, for example disco_items | ||||
|            recv_interface -- The substanza of the query to receive, for example disco_items | ||||
|            results   -- The query stanza's interface which provides a | ||||
|                         countable list of query results. | ||||
|            amount    -- The max amounts of items to request per iteration | ||||
|            start     -- From which item id to start | ||||
|            reverse   -- If True, page backwards through the results | ||||
|            pre_cb    -- Callback to run before sending the stanza | ||||
|            post_cb   -- Callback to run after receiving the reply | ||||
|  | ||||
|         Example: | ||||
|            q = Iq() | ||||
| @@ -49,17 +53,23 @@ class ResultIterator(): | ||||
|         self.amount = amount | ||||
|         self.start = start | ||||
|         self.interface = interface | ||||
|         if recv_interface: | ||||
|             self.recv_interface = recv_interface | ||||
|         else: | ||||
|             self.recv_interface = interface | ||||
|         self.pre_cb = pre_cb | ||||
|         self.post_cb = post_cb | ||||
|         self.results = results | ||||
|         self.reverse = reverse | ||||
|         self._stop = False | ||||
|  | ||||
|     def __iter__(self): | ||||
|     def __aiter__(self): | ||||
|         return self | ||||
|  | ||||
|     def __next__(self): | ||||
|         return self.next() | ||||
|     async def __anext__(self): | ||||
|         return await self.next() | ||||
|  | ||||
|     def next(self): | ||||
|     async def next(self): | ||||
|         """ | ||||
|         Return the next page of results from a query. | ||||
|  | ||||
| @@ -68,7 +78,7 @@ class ResultIterator(): | ||||
|               of items. | ||||
|         """ | ||||
|         if self._stop: | ||||
|             raise StopIteration | ||||
|             raise StopAsyncIteration | ||||
|         self.query[self.interface]['rsm']['before'] = self.reverse | ||||
|         self.query['id'] = self.query.stream.new_id() | ||||
|         self.query[self.interface]['rsm']['max'] = str(self.amount) | ||||
| @@ -79,28 +89,32 @@ class ResultIterator(): | ||||
|             self.query[self.interface]['rsm']['after'] = self.start | ||||
|  | ||||
|         try: | ||||
|             r = self.query.send(block=True) | ||||
|             if self.pre_cb: | ||||
|                 self.pre_cb(self.query) | ||||
|             r = await self.query.send() | ||||
|  | ||||
|             if not r[self.interface]['rsm']['first'] and \ | ||||
|                not r[self.interface]['rsm']['last']: | ||||
|                 raise StopIteration | ||||
|             if not r[self.recv_interface]['rsm']['first'] and \ | ||||
|                not r[self.recv_interface]['rsm']['last']: | ||||
|                 raise StopAsyncIteration | ||||
|  | ||||
|             if r[self.interface]['rsm']['count'] and \ | ||||
|                r[self.interface]['rsm']['first_index']: | ||||
|                 count = int(r[self.interface]['rsm']['count']) | ||||
|                 first = int(r[self.interface]['rsm']['first_index']) | ||||
|                 num_items = len(r[self.interface][self.results]) | ||||
|             if r[self.recv_interface]['rsm']['count'] and \ | ||||
|                r[self.recv_interface]['rsm']['first_index']: | ||||
|                 count = int(r[self.recv_interface]['rsm']['count']) | ||||
|                 first = int(r[self.recv_interface]['rsm']['first_index']) | ||||
|                 num_items = len(r[self.recv_interface][self.results]) | ||||
|                 if first + num_items == count: | ||||
|                     self._stop = True | ||||
|  | ||||
|             if self.reverse: | ||||
|                 self.start = r[self.interface]['rsm']['first'] | ||||
|                 self.start = r[self.recv_interface]['rsm']['first'] | ||||
|             else: | ||||
|                 self.start = r[self.interface]['rsm']['last'] | ||||
|                 self.start = r[self.recv_interface]['rsm']['last'] | ||||
|  | ||||
|             if self.post_cb: | ||||
|                 self.post_cb(r) | ||||
|             return r | ||||
|         except XMPPError: | ||||
|             raise StopIteration | ||||
|             raise StopAsyncIteration | ||||
|  | ||||
|  | ||||
| class XEP_0059(BasePlugin): | ||||
| @@ -111,7 +125,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): | ||||
| @@ -127,7 +141,8 @@ class XEP_0059(BasePlugin): | ||||
|     def session_bind(self, jid): | ||||
|         self.xmpp['xep_0030'].add_feature(Set.namespace) | ||||
|  | ||||
|     def iterate(self, stanza, interface, results='substanzas'): | ||||
|     def iterate(self, stanza, interface, results='substanzas', | ||||
|                 recv_interface=None, pre_cb=None, post_cb=None): | ||||
|         """ | ||||
|         Create a new result set iterator for a given stanza query. | ||||
|  | ||||
| @@ -137,9 +152,23 @@ class XEP_0059(BasePlugin): | ||||
|                          basic disco#items query. | ||||
|             interface -- The name of the substanza to which the | ||||
|                          result set management stanza should be | ||||
|                          appended. For example, for disco#items queries | ||||
|                          the interface 'disco_items' should be used. | ||||
|                          appended in the query stanza. For example, | ||||
|                          for disco#items queries the interface | ||||
|                          'disco_items' should be used. | ||||
|             recv_interface -- The name of the substanza from which the | ||||
|                               result set management stanza should be | ||||
|                               read in the result stanza. If unspecified, | ||||
|                               it will be set to the same value as the | ||||
|                               ``interface`` parameter. | ||||
|             pre_cb    -- Callback to run before sending each stanza e.g. | ||||
|                          setting the MAM queryid and starting a stanza | ||||
|                          collector. | ||||
|             post_cb   -- Callback to run after receiving each stanza e.g. | ||||
|                          stopping a MAM stanza collector in order to | ||||
|                          gather results. | ||||
|             results   -- The name of the interface containing the | ||||
|                          query results (typically just 'substanzas'). | ||||
|         """ | ||||
|         return ResultIterator(stanza, interface, results) | ||||
|         return ResultIterator(stanza, interface, results, | ||||
|                               recv_interface=recv_interface, pre_cb=pre_cb, | ||||
|                               post_cb=post_cb) | ||||
|   | ||||
| @@ -64,10 +64,10 @@ 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.xml.find("{%s}first" % (self.namespace)) | ||||
|   | ||||
| @@ -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,6 +206,9 @@ class Options(ElementBase): | ||||
|         return form | ||||
|  | ||||
|     def set_options(self, value): | ||||
|         if isinstance(value, ElementBase): | ||||
|             self.xml.append(value.xml) | ||||
|         else: | ||||
|             self.xml.append(value) | ||||
|         return 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): | ||||
| @@ -237,6 +240,9 @@ class PublishOptions(ElementBase): | ||||
|     def set_publish_options(self, value): | ||||
|         if value is None: | ||||
|             self.del_publish_options() | ||||
|         else: | ||||
|             if isinstance(value, ElementBase): | ||||
|                 self.xml.append(value.xml) | ||||
|             else: | ||||
|                 self.xml.append(value) | ||||
|         return self | ||||
|   | ||||
| @@ -13,10 +13,10 @@ 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', | ||||
|     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', | ||||
| @@ -24,7 +24,7 @@ class PubsubErrorCondition(ElementBase): | ||||
|                   'not-subscribed', 'payload-too-big', | ||||
|                   'payload-required', 'pending-subscription', | ||||
|                   'presence-subscription-required', 'subid-required', | ||||
|                       'too-many-subscriptions', 'unsupported')) | ||||
|                   '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') | ||||
|   | ||||
| @@ -25,7 +25,7 @@ class DefaultConfig(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     name = 'default' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'config')) | ||||
|     interfaces = {'node', 'config'} | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         ElementBase.__init__(self, *args, **kwargs) | ||||
| @@ -41,7 +41,7 @@ class DefaultConfig(ElementBase): | ||||
|  | ||||
| class OwnerAffiliations(Affiliations): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|     def append(self, affiliation): | ||||
|         if not isinstance(affiliation, OwnerAffiliation): | ||||
| @@ -51,40 +51,40 @@ class OwnerAffiliations(Affiliations): | ||||
|  | ||||
| class OwnerAffiliation(Affiliation): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     interfaces = set(('affiliation', 'jid')) | ||||
|     interfaces = {'affiliation', 'jid'} | ||||
|  | ||||
|  | ||||
| class OwnerConfigure(Configure): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     name = 'configure' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class OwnerDefault(OwnerConfigure): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class OwnerDelete(ElementBase, OptionalSetting): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     name = 'delete' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class OwnerPurge(ElementBase, OptionalSetting): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     name = 'purge' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|  | ||||
| class OwnerRedirect(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     name = 'redirect' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node', 'jid')) | ||||
|     interfaces = {'node', 'jid'} | ||||
|  | ||||
|     def set_jid(self, value): | ||||
|         self._set_attr('jid', str(value)) | ||||
| @@ -97,7 +97,7 @@ class OwnerSubscriptions(Subscriptions): | ||||
|     name = 'subscriptions' | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('node',)) | ||||
|     interfaces = {'node'} | ||||
|  | ||||
|     def append(self, subscription): | ||||
|         if not isinstance(subscription, OwnerSubscription): | ||||
| @@ -109,7 +109,7 @@ class OwnerSubscription(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/pubsub#owner' | ||||
|     name = 'subscription' | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('jid', 'subscription')) | ||||
|     interfaces = {'jid', 'subscription'} | ||||
|  | ||||
|     def set_jid(self, value): | ||||
|         self._set_attr('jid', str(value)) | ||||
|   | ||||
| @@ -22,7 +22,7 @@ class XEP_0065(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0065' | ||||
|     description = "XEP-0065: SOCKS5 Bytestreams" | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     default_config = { | ||||
|         'auto_accept': False | ||||
|     } | ||||
| @@ -55,6 +55,7 @@ class XEP_0065(BasePlugin): | ||||
|         """Returns the socket associated to the SID.""" | ||||
|         return self._sessions.get(sid, None) | ||||
|  | ||||
|     @asyncio.coroutine | ||||
|     def handshake(self, to, ifrom=None, sid=None, timeout=None): | ||||
|         """ Starts the handshake to establish the socks5 bytestreams | ||||
|         connection. | ||||
| @@ -104,6 +105,7 @@ class XEP_0065(BasePlugin): | ||||
|             iq['socks'].add_streamhost(proxy, host, port) | ||||
|         return iq.send(timeout=timeout, callback=callback) | ||||
|  | ||||
|     @asyncio.coroutine | ||||
|     def discover_proxies(self, jid=None, ifrom=None, timeout=None): | ||||
|         """Auto-discover the JIDs of SOCKS5 proxies on an XMPP server.""" | ||||
|         if jid is None: | ||||
|   | ||||
| @@ -6,8 +6,8 @@ class Socks5(ElementBase): | ||||
|     name = 'query' | ||||
|     namespace = 'http://jabber.org/protocol/bytestreams' | ||||
|     plugin_attrib = 'socks' | ||||
|     interfaces = set(['sid', 'activate']) | ||||
|     sub_interfaces = set(['activate']) | ||||
|     interfaces = {'sid', 'activate'} | ||||
|     sub_interfaces = {'activate'} | ||||
|  | ||||
|     def add_streamhost(self, jid, host, port): | ||||
|         sh = StreamHost(parent=self) | ||||
| @@ -21,7 +21,7 @@ class StreamHost(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/bytestreams' | ||||
|     plugin_attrib = 'streamhost' | ||||
|     plugin_multi_attrib = 'streamhosts' | ||||
|     interfaces = set(['host', 'jid', 'port']) | ||||
|     interfaces = {'host', 'jid', 'port'} | ||||
|  | ||||
|     def set_jid(self, value): | ||||
|         return self._set_attr('jid', str(value)) | ||||
| @@ -34,7 +34,7 @@ class StreamHostUsed(ElementBase): | ||||
|     name = 'streamhost-used' | ||||
|     namespace = 'http://jabber.org/protocol/bytestreams' | ||||
|     plugin_attrib = 'streamhost_used' | ||||
|     interfaces = set(['jid']) | ||||
|     interfaces = {'jid'} | ||||
|  | ||||
|     def set_jid(self, value): | ||||
|         return self._set_attr('jid', str(value)) | ||||
|   | ||||
| @@ -44,7 +44,7 @@ class XEP_0066(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0066' | ||||
|     description = 'XEP-0066: Out of Band Data' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -17,8 +17,8 @@ class OOBTransfer(ElementBase): | ||||
|     name = 'query' | ||||
|     namespace = 'jabber:iq:oob' | ||||
|     plugin_attrib = 'oob_transfer' | ||||
|     interfaces = set(('url', 'desc', 'sid')) | ||||
|     sub_interfaces = set(('url', 'desc')) | ||||
|     interfaces = {'url', 'desc', 'sid'} | ||||
|     sub_interfaces = {'url', 'desc'} | ||||
|  | ||||
|  | ||||
| class OOB(ElementBase): | ||||
| @@ -29,5 +29,5 @@ class OOB(ElementBase): | ||||
|     name = 'x' | ||||
|     namespace = 'jabber:x:oob' | ||||
|     plugin_attrib = 'oob' | ||||
|     interfaces = set(('url', 'desc')) | ||||
|     interfaces = {'url', 'desc'} | ||||
|     sub_interfaces = interfaces | ||||
|   | ||||
| @@ -19,8 +19,8 @@ class XHTML_IM(ElementBase): | ||||
|  | ||||
|     namespace = 'http://jabber.org/protocol/xhtml-im' | ||||
|     name = 'html' | ||||
|     interfaces = set(['body']) | ||||
|     lang_interfaces = set(['body']) | ||||
|     interfaces = {'body'} | ||||
|     lang_interfaces = {'body'} | ||||
|     plugin_attrib = name | ||||
|  | ||||
|     def set_body(self, content, lang=None): | ||||
|   | ||||
| @@ -17,7 +17,7 @@ class XEP_0071(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0071' | ||||
|     description = 'XEP-0071: XHTML-IM' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -26,7 +26,7 @@ class XEP_0077(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0077' | ||||
|     description = 'XEP-0077: In-Band Registration' | ||||
|     dependencies = set(['xep_0004', 'xep_0066']) | ||||
|     dependencies = {'xep_0004', 'xep_0066'} | ||||
|     stanza = stanza | ||||
|     default_config = { | ||||
|         'create_account': True, | ||||
|   | ||||
| @@ -16,14 +16,14 @@ class Register(ElementBase): | ||||
|     namespace = 'jabber:iq:register' | ||||
|     name = 'query' | ||||
|     plugin_attrib = 'register' | ||||
|     interfaces = set(('username', 'password', 'email', 'nick', 'name', | ||||
|     interfaces = {'username', 'password', 'email', 'nick', 'name', | ||||
|                   'first', 'last', 'address', 'city', 'state', 'zip', | ||||
|                   'phone', 'url', 'date', 'misc', 'text', 'key', | ||||
|                       'registered', 'remove', 'instructions', 'fields')) | ||||
|                   'registered', 'remove', 'instructions', 'fields'} | ||||
|     sub_interfaces = interfaces | ||||
|     form_fields = set(('username', 'password', 'email', 'nick', 'name', | ||||
|     form_fields = {'username', 'password', 'email', 'nick', 'name', | ||||
|                    'first', 'last', 'address', 'city', 'state', 'zip', | ||||
|                        'phone', 'url', 'date', 'misc', 'text', 'key')) | ||||
|                    'phone', 'url', 'date', 'misc', 'text', 'key'} | ||||
|  | ||||
|     def get_registered(self): | ||||
|         present = self.xml.find('{%s}registered' % self.namespace) | ||||
|   | ||||
| @@ -13,8 +13,8 @@ class IqAuth(ElementBase): | ||||
|     namespace = 'jabber:iq:auth' | ||||
|     name = 'query' | ||||
|     plugin_attrib = 'auth' | ||||
|     interfaces = set(('fields', 'username', 'password', 'resource', 'digest')) | ||||
|     sub_interfaces = set(('username', 'password', 'resource', 'digest')) | ||||
|     interfaces = {'fields', 'username', 'password', 'resource', 'digest'} | ||||
|     sub_interfaces = {'username', 'password', 'resource', 'digest'} | ||||
|     plugin_tag_map = {} | ||||
|     plugin_attrib_map = {} | ||||
|  | ||||
|   | ||||
| @@ -27,7 +27,7 @@ class XEP_0079(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0079' | ||||
|     description = 'XEP-0079: Advanced Message Processing' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
|  | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| from slixmpp import JID | ||||
| from slixmpp.xmlstream import ElementBase, register_stanza_plugin | ||||
|  | ||||
|  | ||||
| @@ -15,7 +16,7 @@ class AMP(ElementBase): | ||||
|     namespace = 'http://jabber.org/protocol/amp' | ||||
|     name = 'amp' | ||||
|     plugin_attrib = 'amp' | ||||
|     interfaces = set(['from', 'to', 'status', 'per_hop']) | ||||
|     interfaces = {'from', 'to', 'status', 'per_hop'} | ||||
|  | ||||
|     def get_from(self): | ||||
|         return JID(self._get_attr('from')) | ||||
| @@ -53,7 +54,7 @@ class Rule(ElementBase): | ||||
|     name = 'rule' | ||||
|     plugin_attrib = name | ||||
|     plugin_multi_attrib = 'rules' | ||||
|     interfaces = set(['action', 'condition', 'value']) | ||||
|     interfaces = {'action', 'condition', 'value'} | ||||
|  | ||||
|  | ||||
| class InvalidRules(ElementBase): | ||||
|   | ||||
| @@ -25,7 +25,7 @@ class XEP_0080(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0080' | ||||
|     description = 'XEP-0080: User Location' | ||||
|     dependencies = set(['xep_0163']) | ||||
|     dependencies = {'xep_0163'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_end(self): | ||||
|   | ||||
| @@ -65,11 +65,11 @@ class Geoloc(ElementBase): | ||||
|  | ||||
|     namespace = 'http://jabber.org/protocol/geoloc' | ||||
|     name = 'geoloc' | ||||
|     interfaces = set(('accuracy', 'alt', 'area', 'bearing', 'building', | ||||
|     interfaces = {'accuracy', 'alt', 'area', 'bearing', 'building', | ||||
|                   'country', 'countrycode', 'datum', 'dscription', | ||||
|                   'error', 'floor', 'lat', 'locality', 'lon', | ||||
|                   'postalcode', 'region', 'room', 'speed', 'street', | ||||
|                       'text', 'timestamp', 'uri')) | ||||
|                   'text', 'timestamp', 'uri'} | ||||
|     sub_interfaces = interfaces | ||||
|     plugin_attrib = name | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,7 @@ class XEP_0084(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0084' | ||||
|     description = 'XEP-0084: User Avatar' | ||||
|     dependencies = set(['xep_0163', 'xep_0060']) | ||||
|     dependencies = {'xep_0163', 'xep_0060'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class Data(ElementBase): | ||||
|     name = 'data' | ||||
|     namespace = 'urn:xmpp:avatar:data' | ||||
|     plugin_attrib = 'avatar_data' | ||||
|     interfaces = set(['value']) | ||||
|     interfaces = {'value'} | ||||
|  | ||||
|     def get_value(self): | ||||
|         if self.xml.text: | ||||
| @@ -63,7 +63,7 @@ class Info(ElementBase): | ||||
|     namespace = 'urn:xmpp:avatar:metadata' | ||||
|     plugin_attrib = 'info' | ||||
|     plugin_multi_attrib = 'items' | ||||
|     interfaces = set(['bytes', 'height', 'id', 'type', 'url', 'width']) | ||||
|     interfaces = {'bytes', 'height', 'id', 'type', 'url', 'width'} | ||||
|  | ||||
|  | ||||
| class Pointer(ElementBase): | ||||
|   | ||||
| @@ -28,7 +28,7 @@ class XEP_0085(BasePlugin): | ||||
|  | ||||
|     name = 'xep_0085' | ||||
|     description = 'XEP-0085: Chat State Notifications' | ||||
|     dependencies = set(['xep_0030']) | ||||
|     dependencies = {'xep_0030'} | ||||
|     stanza = stanza | ||||
|  | ||||
|     def plugin_init(self): | ||||
|   | ||||
| @@ -37,11 +37,11 @@ class ChatState(ElementBase): | ||||
|     name = '' | ||||
|     namespace = 'http://jabber.org/protocol/chatstates' | ||||
|     plugin_attrib = 'chat_state' | ||||
|     interfaces = set(('chat_state',)) | ||||
|     interfaces = {'chat_state'} | ||||
|     sub_interfaces = interfaces | ||||
|     is_extension = True | ||||
|  | ||||
|     states = set(('active', 'composing', 'gone', 'inactive', 'paused')) | ||||
|     states = {'active', 'composing', 'gone', 'inactive', 'paused'} | ||||
|  | ||||
|     def setup(self, xml=None): | ||||
|         self.xml = ET.Element('') | ||||
|   | ||||
| @@ -44,7 +44,7 @@ class LegacyError(ElementBase): | ||||
|     name = 'legacy' | ||||
|     namespace = Error.namespace | ||||
|     plugin_attrib = name | ||||
|     interfaces = set(('condition',)) | ||||
|     interfaces = {'condition'} | ||||
|     overrides = ['set_condition'] | ||||
|  | ||||
|     error_map = {'bad-request': ('modify', '400'), | ||||
|   | ||||
| @@ -18,7 +18,7 @@ class LegacyDelay(ElementBase): | ||||
|     name = 'x' | ||||
|     namespace = 'jabber:x:delay' | ||||
|     plugin_attrib = 'legacy_delay' | ||||
|     interfaces = set(('from', 'stamp', 'text')) | ||||
|     interfaces = {'from', 'stamp', 'text'} | ||||
|  | ||||
|     def get_from(self): | ||||
|         from_ = self._get_attr('from') | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user