Compare commits
	
		
			28 Commits
		
	
	
		
			1.1.4
			...
			sleek-1.1.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					7a112f2523 | ||
| 
						 | 
					e86444e5fb | ||
| 
						 | 
					36c11ad9de | ||
| 
						 | 
					019a4b20ae | ||
| 
						 | 
					433ee08687 | ||
| 
						 | 
					7858d969d8 | ||
| 
						 | 
					8119551049 | ||
| 
						 | 
					061489f03a | ||
| 
						 | 
					d92aa05b5c | ||
| 
						 | 
					f7a74d960e | ||
| 
						 | 
					95a0e51b41 | ||
| 
						 | 
					110e45e187 | ||
| 
						 | 
					534aaf2b2a | ||
| 
						 | 
					4cc20fdd05 | ||
| 
						 | 
					f3fae192a8 | ||
| 
						 | 
					7d59a8a0ad | ||
| 
						 | 
					8da387a38a | ||
| 
						 | 
					ff6fc44215 | ||
| 
						 | 
					62391a895a | ||
| 
						 | 
					9bcdd7d18f | ||
| 
						 | 
					5c4f7bfe8b | ||
| 
						 | 
					0b7f134021 | ||
| 
						 | 
					378a42889f | ||
| 
						 | 
					f824950552 | ||
| 
						 | 
					3d2d11f169 | ||
| 
						 | 
					181aea737d | ||
| 
						 | 
					ee702f4071 | ||
| 
						 | 
					a08c2161a7 | 
@@ -45,7 +45,7 @@ The latest source code for SleekXMPP may be found on `Github
 | 
				
			|||||||
``develop`` branch.
 | 
					``develop`` branch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Latest Release**
 | 
					**Latest Release**
 | 
				
			||||||
    - `1.1.4 <http://github.com/fritzy/SleekXMPP/zipball/1.1.4>`_
 | 
					    - `1.1.6 <http://github.com/fritzy/SleekXMPP/zipball/1.1.6>`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Develop Releases**
 | 
					**Develop Releases**
 | 
				
			||||||
    - `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
 | 
					    - `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										165
									
								
								examples/gtalk_custom_domain.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										165
									
								
								examples/gtalk_custom_domain.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2010  Nathanael C. Fritz
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import getpass
 | 
				
			||||||
 | 
					from optparse import OptionParser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sleekxmpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import ssl
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import cert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Python versions before 3.0 do not use UTF-8 encoding
 | 
				
			||||||
 | 
					# by default. To ensure that Unicode is handled properly
 | 
				
			||||||
 | 
					# throughout SleekXMPP, we will set the default encoding
 | 
				
			||||||
 | 
					# ourselves to UTF-8.
 | 
				
			||||||
 | 
					if sys.version_info < (3, 0):
 | 
				
			||||||
 | 
					    reload(sys)
 | 
				
			||||||
 | 
					    sys.setdefaultencoding('utf8')
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					    raw_input = input
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GTalkBot(sleekxmpp.ClientXMPP):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    A demonstration of using SleekXMPP with accounts from a Google Apps
 | 
				
			||||||
 | 
					    account with a custom domain, because it requires custom certificate
 | 
				
			||||||
 | 
					    validation.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, jid, password):
 | 
				
			||||||
 | 
					        sleekxmpp.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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Using a Google Apps custom domain, the certificate
 | 
				
			||||||
 | 
					        # does not contain the custom domain, just the GTalk
 | 
				
			||||||
 | 
					        # server name. So we will need to process invalid
 | 
				
			||||||
 | 
					        # certifcates ourselves and check that it really
 | 
				
			||||||
 | 
					        # is from Google.
 | 
				
			||||||
 | 
					        self.add_event_handler("ssl_invalid_cert", self.invalid_cert)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def invalid_cert(self, pem_cert):
 | 
				
			||||||
 | 
					        der_cert = ssl.PEM_cert_to_DER_cert(pem_cert)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if msg['type'] in ('chat', 'normal'):
 | 
				
			||||||
 | 
					            msg.reply("Thanks for sending\n%(body)s" % msg).send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    # Setup the command line arguments.
 | 
				
			||||||
 | 
					    optp = OptionParser()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Output verbosity options.
 | 
				
			||||||
 | 
					    optp.add_option('-q', '--quiet', help='set logging to ERROR',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=logging.ERROR, default=logging.INFO)
 | 
				
			||||||
 | 
					    optp.add_option('-d', '--debug', help='set logging to DEBUG',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=logging.DEBUG, default=logging.INFO)
 | 
				
			||||||
 | 
					    optp.add_option('-v', '--verbose', help='set logging to COMM',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=5, default=logging.INFO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # JID and password options.
 | 
				
			||||||
 | 
					    optp.add_option("-j", "--jid", dest="jid",
 | 
				
			||||||
 | 
					                    help="JID to use")
 | 
				
			||||||
 | 
					    optp.add_option("-p", "--password", dest="password",
 | 
				
			||||||
 | 
					                    help="password to use")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    opts, args = optp.parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Setup logging.
 | 
				
			||||||
 | 
					    logging.basicConfig(level=opts.loglevel,
 | 
				
			||||||
 | 
					                        format='%(levelname)-8s %(message)s')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if opts.jid is None:
 | 
				
			||||||
 | 
					        opts.jid = raw_input("Username: ")
 | 
				
			||||||
 | 
					    if opts.password is None:
 | 
				
			||||||
 | 
					        opts.password = getpass.getpass("Password: ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Setup the GTalkBot and register plugins. Note that while plugins may
 | 
				
			||||||
 | 
					    # have interdependencies, the order in which you register them does
 | 
				
			||||||
 | 
					    # not matter.
 | 
				
			||||||
 | 
					    xmpp = GTalkBot(opts.jid, opts.password)
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0030') # Service Discovery
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0004') # Data Forms
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0060') # PubSub
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0199') # XMPP Ping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If you are working with an OpenFire server, you may need
 | 
				
			||||||
 | 
					    # to adjust the SSL version used:
 | 
				
			||||||
 | 
					    # xmpp.ssl_version = ssl.PROTOCOL_SSLv3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If you want to verify the SSL certificates offered by a server:
 | 
				
			||||||
 | 
					    # xmpp.ca_certs = "path/to/ca/cert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Connect to the XMPP server and start processing XMPP stanzas.
 | 
				
			||||||
 | 
					    if xmpp.connect():
 | 
				
			||||||
 | 
					        # If you do not have the dnspython library installed, you will need
 | 
				
			||||||
 | 
					        # to manually specify the name of the server if it does not match
 | 
				
			||||||
 | 
					        # the one in the JID. For example, to use Google Talk you would
 | 
				
			||||||
 | 
					        # need to use:
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        # if xmpp.connect(('talk.google.com', 5222)):
 | 
				
			||||||
 | 
					        #     ...
 | 
				
			||||||
 | 
					        xmpp.process(block=True)
 | 
				
			||||||
 | 
					        print("Done")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print("Unable to connect.")
 | 
				
			||||||
							
								
								
									
										149
									
								
								examples/ibb_transfer/ibb_receiver.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										149
									
								
								examples/ibb_transfer/ibb_receiver.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2010  Nathanael C. Fritz
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import getpass
 | 
				
			||||||
 | 
					from optparse import OptionParser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sleekxmpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Python versions before 3.0 do not use UTF-8 encoding
 | 
				
			||||||
 | 
					# by default. To ensure that Unicode is handled properly
 | 
				
			||||||
 | 
					# throughout SleekXMPP, we will set the default encoding
 | 
				
			||||||
 | 
					# ourselves to UTF-8.
 | 
				
			||||||
 | 
					if sys.version_info < (3, 0):
 | 
				
			||||||
 | 
					    reload(sys)
 | 
				
			||||||
 | 
					    sys.setdefaultencoding('utf8')
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					    raw_input = input
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IBBReceiver(sleekxmpp.ClientXMPP):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    A basic example of creating and using an in-band bytestream.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, jid, password):
 | 
				
			||||||
 | 
					        sleekxmpp.ClientXMPP.__init__(self, jid, password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.register_plugin('xep_0030') # Service Discovery
 | 
				
			||||||
 | 
					        self.register_plugin('xep_0047', {
 | 
				
			||||||
 | 
					            'accept_stream': self.accept_stream
 | 
				
			||||||
 | 
					        }) # In-band Bytestreams
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.add_event_handler("ibb_stream_start", self.stream_opened)
 | 
				
			||||||
 | 
					        self.add_event_handler("ibb_stream_data", self.stream_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 accept_stream(self, iq):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Check that it is ok to accept a stream request. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Controlling stream acceptance can be done via either:
 | 
				
			||||||
 | 
					            - setting 'auto_accept' to False in the plugin
 | 
				
			||||||
 | 
					              configuration. The default is True.
 | 
				
			||||||
 | 
					            - setting 'accept_stream' to a function which accepts
 | 
				
			||||||
 | 
					              an Iq stanza as its argument, like this one.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The accept_stream function will be used if it exists, and the
 | 
				
			||||||
 | 
					        auto_accept value will be used otherwise.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stream_opened(self, stream):
 | 
				
			||||||
 | 
					        # NOTE: IBB streams are bi-directional, so the original sender is
 | 
				
			||||||
 | 
					        # now the opened stream's receiver.
 | 
				
			||||||
 | 
					        print('Stream opened: %s from ' % (stream.sid, stream.receiver))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # You could run a loop reading from the stream using stream.recv(),
 | 
				
			||||||
 | 
					        # or use the ibb_stream_data event.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stream_data(self, event):
 | 
				
			||||||
 | 
					        print(event['data'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    # Setup the command line arguments.
 | 
				
			||||||
 | 
					    optp = OptionParser()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Output verbosity options.
 | 
				
			||||||
 | 
					    optp.add_option('-q', '--quiet', help='set logging to ERROR',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=logging.ERROR, default=logging.INFO)
 | 
				
			||||||
 | 
					    optp.add_option('-d', '--debug', help='set logging to DEBUG',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=logging.DEBUG, default=logging.INFO)
 | 
				
			||||||
 | 
					    optp.add_option('-v', '--verbose', help='set logging to COMM',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=5, default=logging.INFO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # JID and password options.
 | 
				
			||||||
 | 
					    optp.add_option("-j", "--jid", dest="jid",
 | 
				
			||||||
 | 
					                    help="JID to use")
 | 
				
			||||||
 | 
					    optp.add_option("-p", "--password", dest="password",
 | 
				
			||||||
 | 
					                    help="password to use")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    opts, args = optp.parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Setup logging.
 | 
				
			||||||
 | 
					    logging.basicConfig(level=opts.loglevel,
 | 
				
			||||||
 | 
					                        format='%(levelname)-8s %(message)s')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if opts.jid is None:
 | 
				
			||||||
 | 
					        opts.jid = raw_input("Username: ")
 | 
				
			||||||
 | 
					    if opts.password is None:
 | 
				
			||||||
 | 
					        opts.password = getpass.getpass("Password: ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    xmpp = IBBReceiver(opts.jid, opts.password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If you are working with an OpenFire server, you may need
 | 
				
			||||||
 | 
					    # to adjust the SSL version used:
 | 
				
			||||||
 | 
					    # xmpp.ssl_version = ssl.PROTOCOL_SSLv3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If you want to verify the SSL certificates offered by a server:
 | 
				
			||||||
 | 
					    # xmpp.ca_certs = "path/to/ca/cert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Connect to the XMPP server and start processing XMPP stanzas.
 | 
				
			||||||
 | 
					    if xmpp.connect():
 | 
				
			||||||
 | 
					        # If you do not have the dnspython library installed, you will need
 | 
				
			||||||
 | 
					        # to manually specify the name of the server if it does not match
 | 
				
			||||||
 | 
					        # the one in the JID. For example, to use Google Talk you would
 | 
				
			||||||
 | 
					        # need to use:
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        # if xmpp.connect(('talk.google.com', 5222)):
 | 
				
			||||||
 | 
					        #     ...
 | 
				
			||||||
 | 
					        xmpp.process(block=True)
 | 
				
			||||||
 | 
					        print("Done")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print("Unable to connect.")
 | 
				
			||||||
							
								
								
									
										145
									
								
								examples/ibb_transfer/ibb_sender.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										145
									
								
								examples/ibb_transfer/ibb_sender.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2010  Nathanael C. Fritz
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import getpass
 | 
				
			||||||
 | 
					from optparse import OptionParser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sleekxmpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Python versions before 3.0 do not use UTF-8 encoding
 | 
				
			||||||
 | 
					# by default. To ensure that Unicode is handled properly
 | 
				
			||||||
 | 
					# throughout SleekXMPP, we will set the default encoding
 | 
				
			||||||
 | 
					# ourselves to UTF-8.
 | 
				
			||||||
 | 
					if sys.version_info < (3, 0):
 | 
				
			||||||
 | 
					    reload(sys)
 | 
				
			||||||
 | 
					    sys.setdefaultencoding('utf8')
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					    raw_input = input
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IBBSender(sleekxmpp.ClientXMPP):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    A basic example of creating and using an in-band bytestream.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, jid, password, receiver, filename):
 | 
				
			||||||
 | 
					        sleekxmpp.ClientXMPP.__init__(self, jid, password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.receiver = receiver
 | 
				
			||||||
 | 
					        self.filename = filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # For the purpose of demonstration, we'll set a very small block
 | 
				
			||||||
 | 
					        # size. The default block size is 4096. We'll also use a window
 | 
				
			||||||
 | 
					        # allowing sending multiple blocks at a time; in this case, three
 | 
				
			||||||
 | 
					        # block transfers may be in progress at any time.
 | 
				
			||||||
 | 
					        stream = self['xep_0047'].open_stream(self.receiver)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with open(self.filename) as f:
 | 
				
			||||||
 | 
					            data = f.read()
 | 
				
			||||||
 | 
					            stream.sendall(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    # Setup the command line arguments.
 | 
				
			||||||
 | 
					    optp = OptionParser()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Output verbosity options.
 | 
				
			||||||
 | 
					    optp.add_option('-q', '--quiet', help='set logging to ERROR',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=logging.ERROR, default=logging.INFO)
 | 
				
			||||||
 | 
					    optp.add_option('-d', '--debug', help='set logging to DEBUG',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=logging.DEBUG, default=logging.INFO)
 | 
				
			||||||
 | 
					    optp.add_option('-v', '--verbose', help='set logging to COMM',
 | 
				
			||||||
 | 
					                    action='store_const', dest='loglevel',
 | 
				
			||||||
 | 
					                    const=5, default=logging.INFO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # JID and password options.
 | 
				
			||||||
 | 
					    optp.add_option("-j", "--jid", dest="jid",
 | 
				
			||||||
 | 
					                    help="JID to use")
 | 
				
			||||||
 | 
					    optp.add_option("-p", "--password", dest="password",
 | 
				
			||||||
 | 
					                    help="password to use")
 | 
				
			||||||
 | 
					    optp.add_option("-r", "--receiver", dest="receiver",
 | 
				
			||||||
 | 
					                    help="JID to use")
 | 
				
			||||||
 | 
					    optp.add_option("-f", "--file", dest="filename",
 | 
				
			||||||
 | 
					                    help="JID to use")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    opts, args = optp.parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Setup logging.
 | 
				
			||||||
 | 
					    logging.basicConfig(level=opts.loglevel,
 | 
				
			||||||
 | 
					                        format='%(levelname)-8s %(message)s')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if opts.jid is None:
 | 
				
			||||||
 | 
					        opts.jid = raw_input("Username: ")
 | 
				
			||||||
 | 
					    if opts.password is None:
 | 
				
			||||||
 | 
					        opts.password = getpass.getpass("Password: ")
 | 
				
			||||||
 | 
					    if opts.receiver is None:
 | 
				
			||||||
 | 
					        opts.receiver = raw_input("Receiver: ")
 | 
				
			||||||
 | 
					    if opts.filename is None:
 | 
				
			||||||
 | 
					        opts.filename = raw_input("File path: ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Setup the EchoBot and register plugins. Note that while plugins may
 | 
				
			||||||
 | 
					    # have interdependencies, the order in which you register them does
 | 
				
			||||||
 | 
					    # not matter.
 | 
				
			||||||
 | 
					    xmpp = IBBSender(opts.jid, opts.password, opts.receiver, opts.filename)
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0030') # Service Discovery
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0004') # Data Forms
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0047') # In-band Bytestreams
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0060') # PubSub
 | 
				
			||||||
 | 
					    xmpp.register_plugin('xep_0199') # XMPP Ping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If you are working with an OpenFire server, you may need
 | 
				
			||||||
 | 
					    # to adjust the SSL version used:
 | 
				
			||||||
 | 
					    # xmpp.ssl_version = ssl.PROTOCOL_SSLv3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If you want to verify the SSL certificates offered by a server:
 | 
				
			||||||
 | 
					    # xmpp.ca_certs = "path/to/ca/cert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Connect to the XMPP server and start processing XMPP stanzas.
 | 
				
			||||||
 | 
					    if xmpp.connect():
 | 
				
			||||||
 | 
					        # If you do not have the dnspython library installed, you will need
 | 
				
			||||||
 | 
					        # to manually specify the name of the server if it does not match
 | 
				
			||||||
 | 
					        # the one in the JID. For example, to use Google Talk you would
 | 
				
			||||||
 | 
					        # need to use:
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        # if xmpp.connect(('talk.google.com', 5222)):
 | 
				
			||||||
 | 
					        #     ...
 | 
				
			||||||
 | 
					        xmpp.process(block=True)
 | 
				
			||||||
 | 
					        print("Done")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print("Unable to connect.")
 | 
				
			||||||
							
								
								
									
										3
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								setup.py
									
									
									
									
									
								
							@@ -61,6 +61,7 @@ packages     = [ 'sleekxmpp',
 | 
				
			|||||||
                 'sleekxmpp/plugins/xep_0027',
 | 
					                 'sleekxmpp/plugins/xep_0027',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0030',
 | 
					                 'sleekxmpp/plugins/xep_0030',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0030/stanza',
 | 
					                 'sleekxmpp/plugins/xep_0030/stanza',
 | 
				
			||||||
 | 
					                 'sleekxmpp/plugins/xep_0033',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0047',
 | 
					                 'sleekxmpp/plugins/xep_0047',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0050',
 | 
					                 'sleekxmpp/plugins/xep_0050',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0054',
 | 
					                 'sleekxmpp/plugins/xep_0054',
 | 
				
			||||||
@@ -71,6 +72,7 @@ packages     = [ 'sleekxmpp',
 | 
				
			|||||||
                 'sleekxmpp/plugins/xep_0077',
 | 
					                 'sleekxmpp/plugins/xep_0077',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0078',
 | 
					                 'sleekxmpp/plugins/xep_0078',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0080',
 | 
					                 'sleekxmpp/plugins/xep_0080',
 | 
				
			||||||
 | 
					                 'sleekxmpp/plugins/xep_0084',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0085',
 | 
					                 'sleekxmpp/plugins/xep_0085',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0086',
 | 
					                 'sleekxmpp/plugins/xep_0086',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0092',
 | 
					                 'sleekxmpp/plugins/xep_0092',
 | 
				
			||||||
@@ -89,6 +91,7 @@ packages     = [ 'sleekxmpp',
 | 
				
			|||||||
                 'sleekxmpp/plugins/xep_0224',
 | 
					                 'sleekxmpp/plugins/xep_0224',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0231',
 | 
					                 'sleekxmpp/plugins/xep_0231',
 | 
				
			||||||
                 'sleekxmpp/plugins/xep_0249',
 | 
					                 'sleekxmpp/plugins/xep_0249',
 | 
				
			||||||
 | 
					                 'sleekxmpp/plugins/xep_0258',
 | 
				
			||||||
                 'sleekxmpp/features',
 | 
					                 'sleekxmpp/features',
 | 
				
			||||||
                 'sleekxmpp/features/feature_mechanisms',
 | 
					                 'sleekxmpp/features/feature_mechanisms',
 | 
				
			||||||
                 'sleekxmpp/features/feature_mechanisms/stanza',
 | 
					                 'sleekxmpp/features/feature_mechanisms/stanza',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,24 +16,24 @@ class APIWrapper(object):
 | 
				
			|||||||
        elif attr == 'settings':
 | 
					        elif attr == 'settings':
 | 
				
			||||||
            return self.api.settings[self.name]
 | 
					            return self.api.settings[self.name]
 | 
				
			||||||
        elif attr == 'register':
 | 
					        elif attr == 'register':
 | 
				
			||||||
            def curried_handler(handler, op, jid=None, node=None, default=False):
 | 
					            def partial(handler, op, jid=None, node=None, default=False):
 | 
				
			||||||
                register = getattr(self.api, attr)
 | 
					                register = getattr(self.api, attr)
 | 
				
			||||||
                return register(handler, self.name, op, jid, node, default)
 | 
					                return register(handler, self.name, op, jid, node, default)
 | 
				
			||||||
            return curried_handler
 | 
					            return partial
 | 
				
			||||||
        elif attr == 'register_default':
 | 
					        elif attr == 'register_default':
 | 
				
			||||||
            def curried_handler(handler, op, jid=None, node=None):
 | 
					            def partial(handler, op, jid=None, node=None):
 | 
				
			||||||
                return getattr(self.api, attr)(handler, self.name, op)
 | 
					                return getattr(self.api, attr)(handler, self.name, op)
 | 
				
			||||||
            return curried_handler
 | 
					            return partial
 | 
				
			||||||
        elif attr in ('run', 'restore_default', 'unregister'):
 | 
					        elif attr in ('run', 'restore_default', 'unregister'):
 | 
				
			||||||
            def curried_handler(*args, **kwargs):
 | 
					            def partial(*args, **kwargs):
 | 
				
			||||||
                return getattr(self.api, attr)(self.name, *args, **kwargs)
 | 
					                return getattr(self.api, attr)(self.name, *args, **kwargs)
 | 
				
			||||||
            return curried_handler
 | 
					            return partial
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getitem__(self, attr):
 | 
					    def __getitem__(self, attr):
 | 
				
			||||||
        def curried_handler(jid=None, node=None, ifrom=None, args=None):
 | 
					        def partial(jid=None, node=None, ifrom=None, args=None):
 | 
				
			||||||
            return self.api.run(self.name, attr, jid, node, ifrom, args)
 | 
					            return self.api.run(self.name, attr, jid, node, ifrom, args)
 | 
				
			||||||
        return curried_handler
 | 
					        return partial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class APIRegistry(object):
 | 
					class APIRegistry(object):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,7 @@ from sleekxmpp.xmlstream import XMLStream, JID
 | 
				
			|||||||
from sleekxmpp.xmlstream import ET, register_stanza_plugin
 | 
					from sleekxmpp.xmlstream import ET, register_stanza_plugin
 | 
				
			||||||
from sleekxmpp.xmlstream.matcher import MatchXPath
 | 
					from sleekxmpp.xmlstream.matcher import MatchXPath
 | 
				
			||||||
from sleekxmpp.xmlstream.handler import Callback
 | 
					from sleekxmpp.xmlstream.handler import Callback
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream.stanzabase import XML_NS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from sleekxmpp.features import *
 | 
					from sleekxmpp.features import *
 | 
				
			||||||
from sleekxmpp.plugins import PluginManager, register_plugin, load_plugin
 | 
					from sleekxmpp.plugins import PluginManager, register_plugin, load_plugin
 | 
				
			||||||
@@ -180,6 +181,8 @@ class BaseXMPP(XMLStream):
 | 
				
			|||||||
        :param xml: The incoming stream's root element.
 | 
					        :param xml: The incoming stream's root element.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.stream_id = xml.get('id', '')
 | 
					        self.stream_id = xml.get('id', '')
 | 
				
			||||||
 | 
					        self.stream_version = xml.get('version', '')
 | 
				
			||||||
 | 
					        self.peer_default_lang = xml.get('{%s}lang' % XML_NS, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def process(self, *args, **kwargs):
 | 
					    def process(self, *args, **kwargs):
 | 
				
			||||||
        """Initialize plugins and begin processing the XML stream.
 | 
					        """Initialize plugins and begin processing the XML stream.
 | 
				
			||||||
@@ -272,7 +275,9 @@ class BaseXMPP(XMLStream):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def Message(self, *args, **kwargs):
 | 
					    def Message(self, *args, **kwargs):
 | 
				
			||||||
        """Create a Message stanza associated with this stream."""
 | 
					        """Create a Message stanza associated with this stream."""
 | 
				
			||||||
        return Message(self, *args, **kwargs)
 | 
					        msg = Message(self, *args, **kwargs)
 | 
				
			||||||
 | 
					        msg['lang'] = self.default_lang
 | 
				
			||||||
 | 
					        return msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def Iq(self, *args, **kwargs):
 | 
					    def Iq(self, *args, **kwargs):
 | 
				
			||||||
        """Create an Iq stanza associated with this stream."""
 | 
					        """Create an Iq stanza associated with this stream."""
 | 
				
			||||||
@@ -280,7 +285,9 @@ class BaseXMPP(XMLStream):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def Presence(self, *args, **kwargs):
 | 
					    def Presence(self, *args, **kwargs):
 | 
				
			||||||
        """Create a Presence stanza associated with this stream."""
 | 
					        """Create a Presence stanza associated with this stream."""
 | 
				
			||||||
        return Presence(self, *args, **kwargs)
 | 
					        pres = Presence(self, *args, **kwargs)
 | 
				
			||||||
 | 
					        pres['lang'] = self.default_lang
 | 
				
			||||||
 | 
					        return pres
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def make_iq(self, id=0, ifrom=None, ito=None, itype=None, iquery=None):
 | 
					    def make_iq(self, id=0, ifrom=None, ito=None, itype=None, iquery=None):
 | 
				
			||||||
        """Create a new Iq stanza with a given Id and from JID.
 | 
					        """Create a new Iq stanza with a given Id and from JID.
 | 
				
			||||||
@@ -529,18 +536,8 @@ class BaseXMPP(XMLStream):
 | 
				
			|||||||
        :param pfrom: The sender of the presence.
 | 
					        :param pfrom: The sender of the presence.
 | 
				
			||||||
        :param pnick: Optional nickname of the presence's sender.
 | 
					        :param pnick: Optional nickname of the presence's sender.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        # Python2.6 chokes on Unicode strings for dict keys.
 | 
					        self.make_presence(pshow, pstatus, ppriority, pto,
 | 
				
			||||||
        args = {str('pto'): pto,
 | 
					                           ptype, pfrom, pnick).send()
 | 
				
			||||||
                str('ptype'): ptype,
 | 
					 | 
				
			||||||
                str('pshow'): pshow,
 | 
					 | 
				
			||||||
                str('pstatus'): pstatus,
 | 
					 | 
				
			||||||
                str('ppriority'): ppriority,
 | 
					 | 
				
			||||||
                str('pnick'): pnick}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if self.is_component:
 | 
					 | 
				
			||||||
            self.roster[pfrom].send_presence(**args)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            self.client_roster.send_presence(**args)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def send_presence_subscription(self, pto, pfrom=None,
 | 
					    def send_presence_subscription(self, pto, pfrom=None,
 | 
				
			||||||
                                   ptype='subscribe', pnick=None):
 | 
					                                   ptype='subscribe', pnick=None):
 | 
				
			||||||
@@ -554,14 +551,10 @@ class BaseXMPP(XMLStream):
 | 
				
			|||||||
        :param ptype: The type of presence, such as ``'subscribe'``.
 | 
					        :param ptype: The type of presence, such as ``'subscribe'``.
 | 
				
			||||||
        :param pnick: Optional nickname of the presence's sender.
 | 
					        :param pnick: Optional nickname of the presence's sender.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        presence = self.makePresence(ptype=ptype,
 | 
					        self.make_presence(ptype=ptype,
 | 
				
			||||||
                                     pfrom=pfrom,
 | 
					                           pfrom=pfrom,
 | 
				
			||||||
                                     pto=self.getjidbare(pto))
 | 
					                           pto=JID(pto).bare,
 | 
				
			||||||
        if pnick:
 | 
					                           pnick=pnick).send()
 | 
				
			||||||
            nick = ET.Element('{http://jabber.org/protocol/nick}nick')
 | 
					 | 
				
			||||||
            nick.text = pnick
 | 
					 | 
				
			||||||
            presence.append(nick)
 | 
					 | 
				
			||||||
        presence.send()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def jid(self):
 | 
					    def jid(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,8 +60,8 @@ class ClientXMPP(BaseXMPP):
 | 
				
			|||||||
    :param escape_quotes: **Deprecated.**
 | 
					    :param escape_quotes: **Deprecated.**
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, jid, password, ssl=False, plugin_config={},
 | 
					    def __init__(self, jid, password, plugin_config={}, plugin_whitelist=[],
 | 
				
			||||||
                 plugin_whitelist=[], escape_quotes=True, sasl_mech=None):
 | 
					                 escape_quotes=True, sasl_mech=None, lang='en'):
 | 
				
			||||||
        BaseXMPP.__init__(self, jid, 'jabber:client')
 | 
					        BaseXMPP.__init__(self, jid, 'jabber:client')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.set_jid(jid)
 | 
					        self.set_jid(jid)
 | 
				
			||||||
@@ -69,15 +69,18 @@ class ClientXMPP(BaseXMPP):
 | 
				
			|||||||
        self.plugin_config = plugin_config
 | 
					        self.plugin_config = plugin_config
 | 
				
			||||||
        self.plugin_whitelist = plugin_whitelist
 | 
					        self.plugin_whitelist = plugin_whitelist
 | 
				
			||||||
        self.default_port = 5222
 | 
					        self.default_port = 5222
 | 
				
			||||||
 | 
					        self.default_lang = lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.credentials = {}
 | 
					        self.credentials = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.password = password
 | 
					        self.password = password
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.stream_header = "<stream:stream to='%s' %s %s version='1.0'>" % (
 | 
					        self.stream_header = "<stream:stream to='%s' %s %s %s %s>" % (
 | 
				
			||||||
                self.boundjid.host,
 | 
					                self.boundjid.host,
 | 
				
			||||||
                "xmlns:stream='%s'" % self.stream_ns,
 | 
					                "xmlns:stream='%s'" % self.stream_ns,
 | 
				
			||||||
                "xmlns='%s'" % self.default_ns)
 | 
					                "xmlns='%s'" % self.default_ns,
 | 
				
			||||||
 | 
					                "xml:lang='%s'" % self.default_lang,
 | 
				
			||||||
 | 
					                "version='1.0'")
 | 
				
			||||||
        self.stream_footer = "</stream:stream>"
 | 
					        self.stream_footer = "</stream:stream>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.features = set()
 | 
					        self.features = set()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,6 +73,7 @@ class IqTimeout(XMPPError):
 | 
				
			|||||||
        #: did not arrive before the timeout expired.
 | 
					        #: did not arrive before the timeout expired.
 | 
				
			||||||
        self.iq = iq
 | 
					        self.iq = iq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class IqError(XMPPError):
 | 
					class IqError(XMPPError):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ class Failure(StanzaBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_condition(self):
 | 
					    def get_condition(self):
 | 
				
			||||||
        """Return the condition element's name."""
 | 
					        """Return the condition element's name."""
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            if "{%s}" % self.namespace in child.tag:
 | 
					            if "{%s}" % self.namespace in child.tag:
 | 
				
			||||||
                cond = child.tag.split('}', 1)[-1]
 | 
					                cond = child.tag.split('}', 1)[-1]
 | 
				
			||||||
                if cond in self.conditions:
 | 
					                if cond in self.conditions:
 | 
				
			||||||
@@ -68,7 +68,7 @@ class Failure(StanzaBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def del_condition(self):
 | 
					    def del_condition(self):
 | 
				
			||||||
        """Remove the condition element."""
 | 
					        """Remove the condition element."""
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            if "{%s}" % self.condition_ns in child.tag:
 | 
					            if "{%s}" % self.condition_ns in child.tag:
 | 
				
			||||||
                tag = child.tag.split('}', 1)[-1]
 | 
					                tag = child.tag.split('}', 1)[-1]
 | 
				
			||||||
                if tag in self.conditions:
 | 
					                if tag in self.conditions:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,7 @@ __all__ = [
 | 
				
			|||||||
#   'xep_0078',  # Non-SASL auth. Don't automatically load
 | 
					#   'xep_0078',  # Non-SASL auth. Don't automatically load
 | 
				
			||||||
    'xep_0080',  # User Location
 | 
					    'xep_0080',  # User Location
 | 
				
			||||||
    'xep_0082',  # XMPP Date and Time Profiles
 | 
					    'xep_0082',  # XMPP Date and Time Profiles
 | 
				
			||||||
 | 
					    'xep_0084',  # User Avatar
 | 
				
			||||||
    'xep_0085',  # Chat State Notifications
 | 
					    'xep_0085',  # Chat State Notifications
 | 
				
			||||||
    'xep_0086',  # Legacy Error Codes
 | 
					    'xep_0086',  # Legacy Error Codes
 | 
				
			||||||
    'xep_0092',  # Software Version
 | 
					    'xep_0092',  # Software Version
 | 
				
			||||||
@@ -48,7 +49,10 @@ __all__ = [
 | 
				
			|||||||
    'xep_0199',  # Ping
 | 
					    'xep_0199',  # Ping
 | 
				
			||||||
    'xep_0202',  # Entity Time
 | 
					    'xep_0202',  # Entity Time
 | 
				
			||||||
    'xep_0203',  # Delayed Delivery
 | 
					    'xep_0203',  # Delayed Delivery
 | 
				
			||||||
 | 
					    'xep_0222',  # Persistent Storage of Public Data via Pubsub
 | 
				
			||||||
 | 
					    'xep_0223',  # Persistent Storage of Private Data via Pubsub
 | 
				
			||||||
    'xep_0224',  # Attention
 | 
					    'xep_0224',  # Attention
 | 
				
			||||||
    'xep_0231',  # Bits of Binary
 | 
					    'xep_0231',  # Bits of Binary
 | 
				
			||||||
    'xep_0249',  # Direct MUC Invitations
 | 
					    'xep_0249',  # Direct MUC Invitations
 | 
				
			||||||
 | 
					    'xep_0258',  # Security Labels in XMPP
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,7 +84,7 @@ def load_plugin(name, module=None):
 | 
				
			|||||||
                module = 'sleekxmpp.plugins.%s' % name
 | 
					                module = 'sleekxmpp.plugins.%s' % name
 | 
				
			||||||
                __import__(module)
 | 
					                __import__(module)
 | 
				
			||||||
                mod = sys.modules[module]
 | 
					                mod = sys.modules[module]
 | 
				
			||||||
            except:
 | 
					            except ImportError:
 | 
				
			||||||
                module = 'sleekxmpp.features.%s' % name
 | 
					                module = 'sleekxmpp.features.%s' % name
 | 
				
			||||||
                __import__(module)
 | 
					                __import__(module)
 | 
				
			||||||
                mod = sys.modules[module]
 | 
					                mod = sys.modules[module]
 | 
				
			||||||
@@ -103,7 +103,7 @@ def load_plugin(name, module=None):
 | 
				
			|||||||
                # we can work around dependency issues.
 | 
					                # we can work around dependency issues.
 | 
				
			||||||
                plugin.old_style = True
 | 
					                plugin.old_style = True
 | 
				
			||||||
            register_plugin(plugin, name)
 | 
					            register_plugin(plugin, name)
 | 
				
			||||||
    except:
 | 
					    except ImportError:
 | 
				
			||||||
        log.exception("Unable to load plugin: %s", name)
 | 
					        log.exception("Unable to load plugin: %s", name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,7 +81,8 @@ class XEP_0027(BasePlugin):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def _sign_presence(self, stanza):
 | 
					    def _sign_presence(self, stanza):
 | 
				
			||||||
        if isinstance(stanza, Presence):
 | 
					        if isinstance(stanza, Presence):
 | 
				
			||||||
            if stanza['type'] == 'available' or stanza['type'] in Presence.showtypes:
 | 
					            if stanza['type'] == 'available' or \
 | 
				
			||||||
 | 
					                    stanza['type'] in Presence.showtypes:
 | 
				
			||||||
                stanza['signed'] = stanza['status']
 | 
					                stanza['signed'] = stanza['status']
 | 
				
			||||||
        return stanza
 | 
					        return stanza
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,6 +51,3 @@ class Encrypted(ElementBase):
 | 
				
			|||||||
        if self.xml.text:
 | 
					        if self.xml.text:
 | 
				
			||||||
            return xmpp['xep_0027'].decrypt(self.xml.text, parent['to'])
 | 
					            return xmpp['xep_0027'].decrypt(self.xml.text, parent['to'])
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,167 +0,0 @@
 | 
				
			|||||||
"""
 | 
					 | 
				
			||||||
    SleekXMPP: The Sleek XMPP Library
 | 
					 | 
				
			||||||
    Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
 | 
					 | 
				
			||||||
    This file is part of SleekXMPP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    See the file LICENSE for copying permission.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
from sleekxmpp import Message
 | 
					 | 
				
			||||||
from sleekxmpp.xmlstream.handler.callback import Callback
 | 
					 | 
				
			||||||
from sleekxmpp.xmlstream.matcher.xpath import MatchXPath
 | 
					 | 
				
			||||||
from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase, ET, JID
 | 
					 | 
				
			||||||
from sleekxmpp.plugins import BasePlugin, register_plugin
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Addresses(ElementBase):
 | 
					 | 
				
			||||||
    namespace = 'http://jabber.org/protocol/address'
 | 
					 | 
				
			||||||
    name = 'addresses'
 | 
					 | 
				
			||||||
    plugin_attrib = 'addresses'
 | 
					 | 
				
			||||||
    interfaces = set(('addresses', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def addAddress(self, atype='to', jid='', node='', uri='', desc='', delivered=False):
 | 
					 | 
				
			||||||
        address = Address(parent=self)
 | 
					 | 
				
			||||||
        address['type'] = atype
 | 
					 | 
				
			||||||
        address['jid'] = jid
 | 
					 | 
				
			||||||
        address['node'] = node
 | 
					 | 
				
			||||||
        address['uri'] = uri
 | 
					 | 
				
			||||||
        address['desc'] = desc
 | 
					 | 
				
			||||||
        address['delivered'] = delivered
 | 
					 | 
				
			||||||
        return address
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getAddresses(self, atype=None):
 | 
					 | 
				
			||||||
        addresses = []
 | 
					 | 
				
			||||||
        for addrXML in self.xml.findall('{%s}address' % Address.namespace):
 | 
					 | 
				
			||||||
            # ElementTree 1.2.6 does not support [@attr='value'] in findall
 | 
					 | 
				
			||||||
            if atype is None or addrXML.attrib.get('type') == atype:
 | 
					 | 
				
			||||||
                addresses.append(Address(xml=addrXML, parent=None))
 | 
					 | 
				
			||||||
        return addresses
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setAddresses(self, addresses, set_type=None):
 | 
					 | 
				
			||||||
        self.delAddresses(set_type)
 | 
					 | 
				
			||||||
        for addr in addresses:
 | 
					 | 
				
			||||||
            addr = dict(addr)
 | 
					 | 
				
			||||||
            # Remap 'type' to 'atype' to match the add method
 | 
					 | 
				
			||||||
            if set_type is not None:
 | 
					 | 
				
			||||||
                addr['type'] = set_type
 | 
					 | 
				
			||||||
            curr_type = addr.get('type', None)
 | 
					 | 
				
			||||||
            if curr_type is not None:
 | 
					 | 
				
			||||||
                del addr['type']
 | 
					 | 
				
			||||||
                addr['atype'] = curr_type
 | 
					 | 
				
			||||||
            self.addAddress(**addr)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delAddresses(self, atype=None):
 | 
					 | 
				
			||||||
        if atype is None:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        for addrXML in self.xml.findall('{%s}address' % Address.namespace):
 | 
					 | 
				
			||||||
            # ElementTree 1.2.6 does not support [@attr='value'] in findall
 | 
					 | 
				
			||||||
            if addrXML.attrib.get('type') == atype:
 | 
					 | 
				
			||||||
                self.xml.remove(addrXML)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # --------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delBcc(self):
 | 
					 | 
				
			||||||
        self.delAddresses('bcc')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delCc(self):
 | 
					 | 
				
			||||||
        self.delAddresses('cc')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delNoreply(self):
 | 
					 | 
				
			||||||
        self.delAddresses('noreply')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delReplyroom(self):
 | 
					 | 
				
			||||||
        self.delAddresses('replyroom')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delReplyto(self):
 | 
					 | 
				
			||||||
        self.delAddresses('replyto')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delTo(self):
 | 
					 | 
				
			||||||
        self.delAddresses('to')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # --------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getBcc(self):
 | 
					 | 
				
			||||||
        return self.getAddresses('bcc')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getCc(self):
 | 
					 | 
				
			||||||
        return self.getAddresses('cc')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getNoreply(self):
 | 
					 | 
				
			||||||
        return self.getAddresses('noreply')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getReplyroom(self):
 | 
					 | 
				
			||||||
        return self.getAddresses('replyroom')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getReplyto(self):
 | 
					 | 
				
			||||||
        return self.getAddresses('replyto')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getTo(self):
 | 
					 | 
				
			||||||
        return self.getAddresses('to')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # --------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setBcc(self, addresses):
 | 
					 | 
				
			||||||
        self.setAddresses(addresses, 'bcc')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setCc(self, addresses):
 | 
					 | 
				
			||||||
        self.setAddresses(addresses, 'cc')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setNoreply(self, addresses):
 | 
					 | 
				
			||||||
        self.setAddresses(addresses, 'noreply')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setReplyroom(self, addresses):
 | 
					 | 
				
			||||||
        self.setAddresses(addresses, 'replyroom')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setReplyto(self, addresses):
 | 
					 | 
				
			||||||
        self.setAddresses(addresses, 'replyto')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setTo(self, addresses):
 | 
					 | 
				
			||||||
        self.setAddresses(addresses, 'to')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Address(ElementBase):
 | 
					 | 
				
			||||||
    namespace = 'http://jabber.org/protocol/address'
 | 
					 | 
				
			||||||
    name = 'address'
 | 
					 | 
				
			||||||
    plugin_attrib = 'address'
 | 
					 | 
				
			||||||
    interfaces = set(('delivered', 'desc', 'jid', 'node', 'type', 'uri'))
 | 
					 | 
				
			||||||
    address_types = set(('bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getDelivered(self):
 | 
					 | 
				
			||||||
        return self.xml.attrib.get('delivered', False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setDelivered(self, delivered):
 | 
					 | 
				
			||||||
        if delivered:
 | 
					 | 
				
			||||||
            self.xml.attrib['delivered'] = "true"
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            del self['delivered']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setUri(self, uri):
 | 
					 | 
				
			||||||
        if uri:
 | 
					 | 
				
			||||||
            del self['jid']
 | 
					 | 
				
			||||||
            del self['node']
 | 
					 | 
				
			||||||
            self.xml.attrib['uri'] = uri
 | 
					 | 
				
			||||||
        elif 'uri' in self.xml.attrib:
 | 
					 | 
				
			||||||
            del self.xml.attrib['uri']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class XEP_0033(BasePlugin):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    XEP-0033: Extended Stanza Addressing
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    name = 'xep_0033'
 | 
					 | 
				
			||||||
    description = 'XEP-0033: Extended Stanza Addressing'
 | 
					 | 
				
			||||||
    dependencies = set(['xep_0033'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def plugin_init(self):
 | 
					 | 
				
			||||||
        self.xep = '0033'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        register_stanza_plugin(Message, Addresses)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.xmpp.plugin['xep_0030'].add_feature(Addresses.namespace)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
xep_0033 = XEP_0033
 | 
					 | 
				
			||||||
register_plugin(XEP_0033)
 | 
					 | 
				
			||||||
							
								
								
									
										20
									
								
								sleekxmpp/plugins/xep_0033/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								sleekxmpp/plugins/xep_0033/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.base import register_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0033 import stanza
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0033.stanza import Addresses, Address
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0033.addresses import XEP_0033
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register_plugin(XEP_0033)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Retain some backwards compatibility
 | 
				
			||||||
 | 
					xep_0033 = XEP_0033
 | 
				
			||||||
 | 
					Addresses.addAddress = Addresses.add_address
 | 
				
			||||||
							
								
								
									
										32
									
								
								sleekxmpp/plugins/xep_0033/addresses.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								sleekxmpp/plugins/xep_0033/addresses.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp import Message, Presence
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import register_stanza_plugin
 | 
				
			||||||
 | 
					from sleekxmpp.plugins import BasePlugin
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0033 import stanza, Addresses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class XEP_0033(BasePlugin):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    XEP-0033: Extended Stanza Addressing
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'xep_0033'
 | 
				
			||||||
 | 
					    description = 'XEP-0033: Extended Stanza Addressing'
 | 
				
			||||||
 | 
					    dependencies = set(['xep_0030'])
 | 
				
			||||||
 | 
					    stanza = stanza
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def plugin_init(self):
 | 
				
			||||||
 | 
					        self.xmpp['xep_0030'].add_feature(Addresses.namespace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        register_stanza_plugin(Message, Addresses)
 | 
				
			||||||
 | 
					        register_stanza_plugin(Presence, Addresses)
 | 
				
			||||||
							
								
								
									
										131
									
								
								sleekxmpp/plugins/xep_0033/stanza.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								sleekxmpp/plugins/xep_0033/stanza.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import JID, ElementBase, ET, register_stanza_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Addresses(ElementBase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'addresses'
 | 
				
			||||||
 | 
					    namespace = 'http://jabber.org/protocol/address'
 | 
				
			||||||
 | 
					    plugin_attrib = 'addresses'
 | 
				
			||||||
 | 
					    interfaces = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_address(self, atype='to', jid='', node='', uri='',
 | 
				
			||||||
 | 
					                          desc='', delivered=False):
 | 
				
			||||||
 | 
					        addr = Address(parent=self)
 | 
				
			||||||
 | 
					        addr['type'] = atype
 | 
				
			||||||
 | 
					        addr['jid'] = jid
 | 
				
			||||||
 | 
					        addr['node'] = node
 | 
				
			||||||
 | 
					        addr['uri'] = uri
 | 
				
			||||||
 | 
					        addr['desc'] = desc
 | 
				
			||||||
 | 
					        addr['delivered'] = delivered
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Additional methods for manipulating sets of addresses
 | 
				
			||||||
 | 
					    # based on type are generated below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Address(ElementBase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'address'
 | 
				
			||||||
 | 
					    namespace = 'http://jabber.org/protocol/address'
 | 
				
			||||||
 | 
					    plugin_attrib = 'address'
 | 
				
			||||||
 | 
					    interfaces = set(['type', 'jid', 'node', 'uri', 'desc', 'delivered'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    address_types = set(('bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_jid(self):
 | 
				
			||||||
 | 
					        return JID(self._get_attr('jid'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_jid(self, value):
 | 
				
			||||||
 | 
					        self._set_attr('jid', str(value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_delivered(self):
 | 
				
			||||||
 | 
					        value = self._get_attr('delivered', False)
 | 
				
			||||||
 | 
					        return value and value.lower() in ('true', '1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_delivered(self, delivered):
 | 
				
			||||||
 | 
					        if delivered:
 | 
				
			||||||
 | 
					            self._set_attr('delivered', 'true')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            del self['delivered']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_uri(self, uri):
 | 
				
			||||||
 | 
					        if uri:
 | 
				
			||||||
 | 
					            del self['jid']
 | 
				
			||||||
 | 
					            del self['node']
 | 
				
			||||||
 | 
					            self._set_attr('uri', uri)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self._del_attr('uri')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# =====================================================================
 | 
				
			||||||
 | 
					# Auto-generate address type filters for the Addresses class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _addr_filter(atype):
 | 
				
			||||||
 | 
					    def _type_filter(addr):
 | 
				
			||||||
 | 
					        if isinstance(addr, Address):
 | 
				
			||||||
 | 
					            if atype == 'all' or addr['type'] == atype:
 | 
				
			||||||
 | 
					                return True
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					    return _type_filter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _build_methods(atype):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_multi(self):
 | 
				
			||||||
 | 
					        return list(filter(_addr_filter(atype), self))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_multi(self, value):
 | 
				
			||||||
 | 
					        del self[atype]
 | 
				
			||||||
 | 
					        for addr in value:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Support assigning dictionary versions of addresses
 | 
				
			||||||
 | 
					            # instead of full Address objects.
 | 
				
			||||||
 | 
					            if not isinstance(addr, Address):
 | 
				
			||||||
 | 
					                if atype != 'all':
 | 
				
			||||||
 | 
					                    addr['type'] = atype
 | 
				
			||||||
 | 
					                elif 'atype' in addr and 'type' not in addr:
 | 
				
			||||||
 | 
					                    addr['type'] = addr['atype']
 | 
				
			||||||
 | 
					                addrObj = Address()
 | 
				
			||||||
 | 
					                addrObj.values = addr
 | 
				
			||||||
 | 
					                addr = addrObj
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.append(addr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def del_multi(self):
 | 
				
			||||||
 | 
					        res = list(filter(_addr_filter(atype), self))
 | 
				
			||||||
 | 
					        for addr in res:
 | 
				
			||||||
 | 
					            self.iterables.remove(addr)
 | 
				
			||||||
 | 
					            self.xml.remove(addr.xml)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return get_multi, set_multi, del_multi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for atype in ('all', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'):
 | 
				
			||||||
 | 
					    get_multi, set_multi, del_multi = _build_methods(atype)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Addresses.interfaces.add(atype)
 | 
				
			||||||
 | 
					    setattr(Addresses, "get_%s" % atype, get_multi)
 | 
				
			||||||
 | 
					    setattr(Addresses, "set_%s" % atype, set_multi)
 | 
				
			||||||
 | 
					    setattr(Addresses, "del_%s" % atype, del_multi)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # To retain backwards compatibility:
 | 
				
			||||||
 | 
					    setattr(Addresses, "get%s" % atype.title(), get_multi)
 | 
				
			||||||
 | 
					    setattr(Addresses, "set%s" % atype.title(), set_multi)
 | 
				
			||||||
 | 
					    setattr(Addresses, "del%s" % atype.title(), del_multi)
 | 
				
			||||||
 | 
					    if atype == 'all':
 | 
				
			||||||
 | 
					        Addresses.interfaces.add('addresses')
 | 
				
			||||||
 | 
					        setattr(Addresses, "getAddresses", get_multi)
 | 
				
			||||||
 | 
					        setattr(Addresses, "setAddresses", set_multi)
 | 
				
			||||||
 | 
					        setattr(Addresses, "delAddresses", del_multi)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register_stanza_plugin(Addresses, Address, iterable=True)
 | 
				
			||||||
@@ -110,14 +110,14 @@ class Command(ElementBase):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        Return the set of allowable next actions.
 | 
					        Return the set of allowable next actions.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        actions = []
 | 
					        actions = set()
 | 
				
			||||||
        actions_xml = self.find('{%s}actions' % self.namespace)
 | 
					        actions_xml = self.find('{%s}actions' % self.namespace)
 | 
				
			||||||
        if actions_xml is not None:
 | 
					        if actions_xml is not None:
 | 
				
			||||||
            for action in self.next_actions:
 | 
					            for action in self.next_actions:
 | 
				
			||||||
                action_xml = actions_xml.find('{%s}%s' % (self.namespace,
 | 
					                action_xml = actions_xml.find('{%s}%s' % (self.namespace,
 | 
				
			||||||
                                                          action))
 | 
					                                                          action))
 | 
				
			||||||
                if action_xml is not None:
 | 
					                if action_xml is not None:
 | 
				
			||||||
                    actions.append(action)
 | 
					                    actions.add(action)
 | 
				
			||||||
        return actions
 | 
					        return actions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def del_actions(self):
 | 
					    def del_actions(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,6 +72,7 @@ class Nickname(ElementBase):
 | 
				
			|||||||
    name = 'NICKNAME'
 | 
					    name = 'NICKNAME'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'nicknames'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,6 +95,7 @@ class Email(ElementBase):
 | 
				
			|||||||
    name = 'EMAIL'
 | 
					    name = 'EMAIL'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'emails'
 | 
				
			||||||
    interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400', 'USERID'])
 | 
					    interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400', 'USERID'])
 | 
				
			||||||
    sub_interfaces = set(['USERID'])
 | 
					    sub_interfaces = set(['USERID'])
 | 
				
			||||||
    bool_interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400'])
 | 
					    bool_interfaces = set(['HOME', 'WORK', 'INTERNET', 'PREF', 'X400'])
 | 
				
			||||||
@@ -103,6 +105,7 @@ class Address(ElementBase):
 | 
				
			|||||||
    name = 'ADR'
 | 
					    name = 'ADR'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'addresses'
 | 
				
			||||||
    interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL',
 | 
					    interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL',
 | 
				
			||||||
                      'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY',
 | 
					                      'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY',
 | 
				
			||||||
                      'REGION', 'PCODE', 'CTRY'])
 | 
					                      'REGION', 'PCODE', 'CTRY'])
 | 
				
			||||||
@@ -115,6 +118,7 @@ class Telephone(ElementBase):
 | 
				
			|||||||
    name = 'TEL'
 | 
					    name = 'TEL'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'telephone_numbers'
 | 
				
			||||||
    interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', 'MSG',
 | 
					    interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', 'MSG',
 | 
				
			||||||
                      'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS',
 | 
					                      'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS',
 | 
				
			||||||
                      'PREF', 'NUMBER'])
 | 
					                      'PREF', 'NUMBER'])
 | 
				
			||||||
@@ -138,6 +142,7 @@ class Label(ElementBase):
 | 
				
			|||||||
    name = 'LABEL'
 | 
					    name = 'LABEL'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'labels'
 | 
				
			||||||
    interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT',
 | 
					    interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT',
 | 
				
			||||||
                      'PREF', 'lines'])
 | 
					                      'PREF', 'lines'])
 | 
				
			||||||
    bool_interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM',
 | 
					    bool_interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM',
 | 
				
			||||||
@@ -171,6 +176,7 @@ class Geo(ElementBase):
 | 
				
			|||||||
    name = 'GEO'
 | 
					    name = 'GEO'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'geolocations'
 | 
				
			||||||
    interfaces = set(['LAT', 'LON'])
 | 
					    interfaces = set(['LAT', 'LON'])
 | 
				
			||||||
    sub_interfaces = interfaces
 | 
					    sub_interfaces = interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -179,6 +185,7 @@ class Org(ElementBase):
 | 
				
			|||||||
    name = 'ORG'
 | 
					    name = 'ORG'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'organizations'
 | 
				
			||||||
    interfaces = set(['ORGNAME', 'ORGUNIT', 'orgunits'])
 | 
					    interfaces = set(['ORGNAME', 'ORGUNIT', 'orgunits'])
 | 
				
			||||||
    sub_interfaces = set(['ORGNAME', 'ORGUNIT'])
 | 
					    sub_interfaces = set(['ORGNAME', 'ORGUNIT'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -210,6 +217,7 @@ class Photo(ElementBase):
 | 
				
			|||||||
    name = 'PHOTO'
 | 
					    name = 'PHOTO'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'photos'
 | 
				
			||||||
    interfaces = set(['TYPE', 'EXTVAL'])
 | 
					    interfaces = set(['TYPE', 'EXTVAL'])
 | 
				
			||||||
    sub_interfaces = interfaces
 | 
					    sub_interfaces = interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -218,14 +226,16 @@ class Logo(ElementBase):
 | 
				
			|||||||
    name = 'LOGO'
 | 
					    name = 'LOGO'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'logos'
 | 
				
			||||||
    interfaces = set(['TYPE', 'EXTVAL'])
 | 
					    interfaces = set(['TYPE', 'EXTVAL'])
 | 
				
			||||||
    sub_interfaces = interfaces
 | 
					    sub_interfaces = interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Sound(ElementBase):
 | 
					class Sound(ElementBase):
 | 
				
			||||||
    name = 'LOGO'
 | 
					    name = 'SOUND'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'sounds'
 | 
				
			||||||
    interfaces = set(['PHONETC', 'EXTVAL'])
 | 
					    interfaces = set(['PHONETC', 'EXTVAL'])
 | 
				
			||||||
    sub_interfaces = interfaces
 | 
					    sub_interfaces = interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -264,6 +274,7 @@ class Classification(ElementBase):
 | 
				
			|||||||
    name = 'CLASS'
 | 
					    name = 'CLASS'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'classifications'
 | 
				
			||||||
    interfaces = set(['PUBLIC', 'PRIVATE', 'CONFIDENTIAL'])
 | 
					    interfaces = set(['PUBLIC', 'PRIVATE', 'CONFIDENTIAL'])
 | 
				
			||||||
    bool_interfaces = interfaces
 | 
					    bool_interfaces = interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -272,6 +283,7 @@ class Categories(ElementBase):
 | 
				
			|||||||
    name = 'CATEGORIES'
 | 
					    name = 'CATEGORIES'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'categories'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -301,6 +313,7 @@ class Birthday(ElementBase):
 | 
				
			|||||||
    name = 'BDAY'
 | 
					    name = 'BDAY'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'birthdays'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -319,6 +332,7 @@ class Rev(ElementBase):
 | 
				
			|||||||
    name = 'REV'
 | 
					    name = 'REV'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'revision_dates'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -337,6 +351,7 @@ class Title(ElementBase):
 | 
				
			|||||||
    name = 'TITLE'
 | 
					    name = 'TITLE'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'titles'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -351,6 +366,7 @@ class Role(ElementBase):
 | 
				
			|||||||
    name = 'ROLE'
 | 
					    name = 'ROLE'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'roles'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -365,6 +381,7 @@ class Note(ElementBase):
 | 
				
			|||||||
    name = 'NOTE'
 | 
					    name = 'NOTE'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'notes'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -379,6 +396,7 @@ class Desc(ElementBase):
 | 
				
			|||||||
    name = 'DESC'
 | 
					    name = 'DESC'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'descriptions'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -393,6 +411,7 @@ class URL(ElementBase):
 | 
				
			|||||||
    name = 'URL'
 | 
					    name = 'URL'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'urls'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -407,6 +426,7 @@ class UID(ElementBase):
 | 
				
			|||||||
    name = 'UID'
 | 
					    name = 'UID'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'uids'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -421,6 +441,7 @@ class ProdID(ElementBase):
 | 
				
			|||||||
    name = 'PRODID'
 | 
					    name = 'PRODID'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'product_ids'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -435,6 +456,7 @@ class Mailer(ElementBase):
 | 
				
			|||||||
    name = 'MAILER'
 | 
					    name = 'MAILER'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'mailers'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -449,6 +471,7 @@ class SortString(ElementBase):
 | 
				
			|||||||
    name = 'SORT-STRING'
 | 
					    name = 'SORT-STRING'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = 'SORT_STRING'
 | 
					    plugin_attrib = 'SORT_STRING'
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'sort_strings'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -463,6 +486,7 @@ class Agent(ElementBase):
 | 
				
			|||||||
    name = 'AGENT'
 | 
					    name = 'AGENT'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'agents'
 | 
				
			||||||
    interfaces = set(['EXTVAL'])
 | 
					    interfaces = set(['EXTVAL'])
 | 
				
			||||||
    sub_interfaces = interfaces
 | 
					    sub_interfaces = interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -471,6 +495,7 @@ class JabberID(ElementBase):
 | 
				
			|||||||
    name = 'JABBERID'
 | 
					    name = 'JABBERID'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'jids'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -485,6 +510,7 @@ class TimeZone(ElementBase):
 | 
				
			|||||||
    name = 'TZ'
 | 
					    name = 'TZ'
 | 
				
			||||||
    namespace = 'vcard-temp'
 | 
					    namespace = 'vcard-temp'
 | 
				
			||||||
    plugin_attrib = name
 | 
					    plugin_attrib = name
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'timezones'
 | 
				
			||||||
    interfaces = set([name])
 | 
					    interfaces = set([name])
 | 
				
			||||||
    is_extension = True
 | 
					    is_extension = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,7 +107,7 @@ class XEP_0054(BasePlugin):
 | 
				
			|||||||
            self.api['set_vcard'](jid=iq['from'], args=iq['vcard_temp'])
 | 
					            self.api['set_vcard'](jid=iq['from'], args=iq['vcard_temp'])
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        elif iq['type'] == 'get':
 | 
					        elif iq['type'] == 'get':
 | 
				
			||||||
            vcard = self.api['get_vard'](iq['from'].bare)
 | 
					            vcard = self.api['get_vcard'](iq['from'].bare)
 | 
				
			||||||
            if isinstance(vcard, Iq):
 | 
					            if isinstance(vcard, Iq):
 | 
				
			||||||
                vcard.send()
 | 
					                vcard.send()
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,7 +74,7 @@ class Set(ElementBase):
 | 
				
			|||||||
        if fi is not None:
 | 
					        if fi is not None:
 | 
				
			||||||
            if val:
 | 
					            if val:
 | 
				
			||||||
                fi.attrib['index'] = val
 | 
					                fi.attrib['index'] = val
 | 
				
			||||||
            else:
 | 
					            elif 'index' in fi.attrib:
 | 
				
			||||||
                del fi.attrib['index']
 | 
					                del fi.attrib['index']
 | 
				
			||||||
        elif val:
 | 
					        elif val:
 | 
				
			||||||
            fi = ET.Element("{%s}first" % (self.namespace))
 | 
					            fi = ET.Element("{%s}first" % (self.namespace))
 | 
				
			||||||
@@ -93,7 +93,7 @@ class Set(ElementBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def set_before(self, val):
 | 
					    def set_before(self, val):
 | 
				
			||||||
        b = self.xml.find("{%s}before" % (self.namespace))
 | 
					        b = self.xml.find("{%s}before" % (self.namespace))
 | 
				
			||||||
        if b is None and val == True:
 | 
					        if b is None and val is True:
 | 
				
			||||||
            self._set_sub_text('{%s}before' % self.namespace, '', True)
 | 
					            self._set_sub_text('{%s}before' % self.namespace, '', True)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self._set_sub_text('{%s}before' % self.namespace, val)
 | 
					            self._set_sub_text('{%s}before' % self.namespace, val)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,12 +77,12 @@ class Item(ElementBase):
 | 
				
			|||||||
        self.append(value)
 | 
					        self.append(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_payload(self):
 | 
					    def get_payload(self):
 | 
				
			||||||
        childs = self.xml.getchildren()
 | 
					        childs = list(self.xml)
 | 
				
			||||||
        if len(childs) > 0:
 | 
					        if len(childs) > 0:
 | 
				
			||||||
            return childs[0]
 | 
					            return childs[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def del_payload(self):
 | 
					    def del_payload(self):
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            self.xml.remove(child)
 | 
					            self.xml.remove(child)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -254,12 +254,12 @@ class PubsubState(ElementBase):
 | 
				
			|||||||
        self.xml.append(value)
 | 
					        self.xml.append(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_payload(self):
 | 
					    def get_payload(self):
 | 
				
			||||||
        childs = self.xml.getchildren()
 | 
					        childs = list(self.xml)
 | 
				
			||||||
        if len(childs) > 0:
 | 
					        if len(childs) > 0:
 | 
				
			||||||
            return childs[0]
 | 
					            return childs[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def del_payload(self):
 | 
					    def del_payload(self):
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            self.xml.remove(child)
 | 
					            self.xml.remove(child)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ class PubsubErrorCondition(ElementBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_condition(self):
 | 
					    def get_condition(self):
 | 
				
			||||||
        """Return the condition element's name."""
 | 
					        """Return the condition element's name."""
 | 
				
			||||||
        for child in self.parent().xml.getchildren():
 | 
					        for child in self.parent().xml:
 | 
				
			||||||
            if "{%s}" % self.condition_ns in child.tag:
 | 
					            if "{%s}" % self.condition_ns in child.tag:
 | 
				
			||||||
                cond = child.tag.split('}', 1)[-1]
 | 
					                cond = child.tag.split('}', 1)[-1]
 | 
				
			||||||
                if cond in self.conditions:
 | 
					                if cond in self.conditions:
 | 
				
			||||||
@@ -55,7 +55,7 @@ class PubsubErrorCondition(ElementBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def del_condition(self):
 | 
					    def del_condition(self):
 | 
				
			||||||
        """Remove the condition element."""
 | 
					        """Remove the condition element."""
 | 
				
			||||||
        for child in self.parent().xml.getchildren():
 | 
					        for child in self.parent().xml:
 | 
				
			||||||
            if "{%s}" % self.condition_ns in child.tag:
 | 
					            if "{%s}" % self.condition_ns in child.tag:
 | 
				
			||||||
                tag = child.tag.split('}', 1)[-1]
 | 
					                tag = child.tag.split('}', 1)[-1]
 | 
				
			||||||
                if tag in self.conditions:
 | 
					                if tag in self.conditions:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,12 +31,12 @@ class EventItem(ElementBase):
 | 
				
			|||||||
        self.xml.append(value)
 | 
					        self.xml.append(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_payload(self):
 | 
					    def get_payload(self):
 | 
				
			||||||
        childs = self.xml.getchildren()
 | 
					        childs = list(self.xml)
 | 
				
			||||||
        if len(childs) > 0:
 | 
					        if len(childs) > 0:
 | 
				
			||||||
            return childs[0]
 | 
					            return childs[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def del_payload(self):
 | 
					    def del_payload(self):
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            self.xml.remove(child)
 | 
					            self.xml.remove(child)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,5 +39,3 @@ class AuthFeature(ElementBase):
 | 
				
			|||||||
    interfaces = set()
 | 
					    interfaces = set()
 | 
				
			||||||
    plugin_tag_map = {}
 | 
					    plugin_tag_map = {}
 | 
				
			||||||
    plugin_attrib_map = {}
 | 
					    plugin_attrib_map = {}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ def format_date(time_obj):
 | 
				
			|||||||
        time_obj = time_obj.date()
 | 
					        time_obj = time_obj.date()
 | 
				
			||||||
    return time_obj.isoformat()
 | 
					    return time_obj.isoformat()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def format_time(time_obj):
 | 
					def format_time(time_obj):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Return a formatted string version of a time object.
 | 
					    Return a formatted string version of a time object.
 | 
				
			||||||
@@ -60,6 +61,7 @@ def format_time(time_obj):
 | 
				
			|||||||
        return '%sZ' % timestamp
 | 
					        return '%sZ' % timestamp
 | 
				
			||||||
    return timestamp
 | 
					    return timestamp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def format_datetime(time_obj):
 | 
					def format_datetime(time_obj):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Return a formatted string version of a datetime object.
 | 
					    Return a formatted string version of a datetime object.
 | 
				
			||||||
@@ -76,6 +78,7 @@ def format_datetime(time_obj):
 | 
				
			|||||||
        return '%sZ' % timestamp
 | 
					        return '%sZ' % timestamp
 | 
				
			||||||
    return timestamp
 | 
					    return timestamp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def date(year=None, month=None, day=None, obj=False):
 | 
					def date(year=None, month=None, day=None, obj=False):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create a date only timestamp for the given instant.
 | 
					    Create a date only timestamp for the given instant.
 | 
				
			||||||
@@ -101,6 +104,7 @@ def date(year=None, month=None, day=None, obj=False):
 | 
				
			|||||||
        return value
 | 
					        return value
 | 
				
			||||||
    return format_date(value)
 | 
					    return format_date(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def time(hour=None, min=None, sec=None, micro=None, offset=None, obj=False):
 | 
					def time(hour=None, min=None, sec=None, micro=None, offset=None, obj=False):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create a time only timestamp for the given instant.
 | 
					    Create a time only timestamp for the given instant.
 | 
				
			||||||
@@ -136,6 +140,7 @@ def time(hour=None, min=None, sec=None, micro=None, offset=None, obj=False):
 | 
				
			|||||||
        return value
 | 
					        return value
 | 
				
			||||||
    return format_time(value)
 | 
					    return format_time(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def datetime(year=None, month=None, day=None, hour=None,
 | 
					def datetime(year=None, month=None, day=None, hour=None,
 | 
				
			||||||
             min=None, sec=None, micro=None, offset=None,
 | 
					             min=None, sec=None, micro=None, offset=None,
 | 
				
			||||||
             separators=True, obj=False):
 | 
					             separators=True, obj=False):
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								sleekxmpp/plugins/xep_0084/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								sleekxmpp/plugins/xep_0084/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.base import register_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0084 import stanza
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0084.stanza import Data, MetaData
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0084.avatar import XEP_0084
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register_plugin(XEP_0084)
 | 
				
			||||||
							
								
								
									
										101
									
								
								sleekxmpp/plugins/xep_0084/avatar.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								sleekxmpp/plugins/xep_0084/avatar.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import hashlib
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp import Iq
 | 
				
			||||||
 | 
					from sleekxmpp.plugins import BasePlugin
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream.handler import Callback
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream.matcher import StanzaPath
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import register_stanza_plugin, JID
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0084 import stanza, Data, MetaData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class XEP_0084(BasePlugin):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'xep_0084'
 | 
				
			||||||
 | 
					    description = 'XEP-0084: User Avatar'
 | 
				
			||||||
 | 
					    dependencies = set(['xep_0163', 'xep_0060'])
 | 
				
			||||||
 | 
					    stanza = stanza
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def plugin_init(self):
 | 
				
			||||||
 | 
					        self.xmpp['xep_0163'].register_pep('avatar_metadata', MetaData)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pubsub_stanza = self.xmpp['xep_0060'].stanza
 | 
				
			||||||
 | 
					        register_stanza_plugin(pubsub_stanza.Item, Data)
 | 
				
			||||||
 | 
					        register_stanza_plugin(pubsub_stanza.EventItem, Data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.xmpp['xep_0060'].map_node_event(Data.namespace, 'avatar_data')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retrieve_avatar(self, jid, id, url=None, ifrom=None, block=True,
 | 
				
			||||||
 | 
					                              callback=None, timeout=None):
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0060'].get_item(jid, Data.namespace, id,
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def publish_avatar(self, data, ifrom=None, block=True, callback=None,
 | 
				
			||||||
 | 
					                             timeout=None):
 | 
				
			||||||
 | 
					        payload = Data()
 | 
				
			||||||
 | 
					        payload['value'] = data
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0163'].publish(payload,
 | 
				
			||||||
 | 
					                node=Data.namespace,
 | 
				
			||||||
 | 
					                id=hashlib.sha1(data).hexdigest(),
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def publish_avatar_metadata(self, items=None, pointers=None,
 | 
				
			||||||
 | 
					                                      ifrom=None, block=True,
 | 
				
			||||||
 | 
					                                      callback=None, timeout=None):
 | 
				
			||||||
 | 
					        metadata = MetaData()
 | 
				
			||||||
 | 
					        if items is None:
 | 
				
			||||||
 | 
					            items = []
 | 
				
			||||||
 | 
					        for info in items:
 | 
				
			||||||
 | 
					            metadata.add_info(info['id'], info['type'], info['bytes'],
 | 
				
			||||||
 | 
					                    height=info.get('height', ''),
 | 
				
			||||||
 | 
					                    width=info.get('width', ''),
 | 
				
			||||||
 | 
					                    url=info.get('url', ''))
 | 
				
			||||||
 | 
					        for pointer in pointers:
 | 
				
			||||||
 | 
					            metadata.add_pointer(pointer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0163'].publish(payload,
 | 
				
			||||||
 | 
					                node=Data.namespace,
 | 
				
			||||||
 | 
					                id=hashlib.sha1(data).hexdigest(),
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stop(self, ifrom=None, block=True, callback=None, timeout=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Clear existing avatar metadata information to stop notifications.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Arguments:
 | 
				
			||||||
 | 
					            ifrom    -- Specify the sender's JID.
 | 
				
			||||||
 | 
					            block    -- Specify if the send call will block until a response
 | 
				
			||||||
 | 
					                        is received, or a timeout occurs. Defaults to True.
 | 
				
			||||||
 | 
					            timeout  -- The length of time (in seconds) to wait for a response
 | 
				
			||||||
 | 
					                        before exiting the send call if blocking is used.
 | 
				
			||||||
 | 
					                        Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT
 | 
				
			||||||
 | 
					            callback -- Optional reference to a stream handler function. Will
 | 
				
			||||||
 | 
					                        be executed when a reply stanza is received.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        metadata = MetaData()
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0163'].publish(metadata,
 | 
				
			||||||
 | 
					                node=MetaData.namespace,
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
							
								
								
									
										78
									
								
								sleekxmpp/plugins/xep_0084/stanza.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								sleekxmpp/plugins/xep_0084/stanza.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from base64 import b64encode, b64decode
 | 
				
			||||||
 | 
					from sleekxmpp.thirdparty.suelta.util import bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Data(ElementBase):
 | 
				
			||||||
 | 
					    name = 'data'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:avatar:data'
 | 
				
			||||||
 | 
					    plugin_attrib = 'avatar_data'
 | 
				
			||||||
 | 
					    interfaces = set(['value'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_value(self):
 | 
				
			||||||
 | 
					        if self.xml.text:
 | 
				
			||||||
 | 
					            return b64decode(bytes(self.xml.text))
 | 
				
			||||||
 | 
					        return ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_value(self, value):
 | 
				
			||||||
 | 
					        if value:
 | 
				
			||||||
 | 
					            self.xml.text = b64encode(bytes(value))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.xml.text = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def del_value(self):
 | 
				
			||||||
 | 
					        self.xml.text = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MetaData(ElementBase):
 | 
				
			||||||
 | 
					    name = 'metadata'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:avatar:metadata'
 | 
				
			||||||
 | 
					    plugin_attrib = 'avatar_metadata'
 | 
				
			||||||
 | 
					    interfaces = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_info(self, id, itype, ibytes, height=None, width=None, url=None):
 | 
				
			||||||
 | 
					        info = Info()
 | 
				
			||||||
 | 
					        info.values = {'id': id,
 | 
				
			||||||
 | 
					                       'type': itype,
 | 
				
			||||||
 | 
					                       'bytes': ibytes,
 | 
				
			||||||
 | 
					                       'height': height,
 | 
				
			||||||
 | 
					                       'width': width,
 | 
				
			||||||
 | 
					                       'url': url}
 | 
				
			||||||
 | 
					        self.append(info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_pointer(self, xml):
 | 
				
			||||||
 | 
					        if not isinstance(xml, Pointer):
 | 
				
			||||||
 | 
					            pointer = Pointer()
 | 
				
			||||||
 | 
					            pointer.append(xml)
 | 
				
			||||||
 | 
					            self.append(pointer)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.append(xml)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Info(ElementBase):
 | 
				
			||||||
 | 
					    name = 'info'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:avatar:metadata'
 | 
				
			||||||
 | 
					    plugin_attrib = 'info'
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'items'
 | 
				
			||||||
 | 
					    interfaces = set(['bytes', 'height', 'id', 'type', 'url', 'width'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Pointer(ElementBase):
 | 
				
			||||||
 | 
					    name = 'pointer'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:avatar:metadata'
 | 
				
			||||||
 | 
					    plugin_attrib = 'pointer'
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'pointers'
 | 
				
			||||||
 | 
					    interfaces = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register_stanza_plugin(MetaData, Info, iterable=True)
 | 
				
			||||||
 | 
					register_stanza_plugin(MetaData, Pointer, iterable=True)
 | 
				
			||||||
@@ -47,28 +47,28 @@ class LegacyError(ElementBase):
 | 
				
			|||||||
    interfaces = set(('condition',))
 | 
					    interfaces = set(('condition',))
 | 
				
			||||||
    overrides = ['set_condition']
 | 
					    overrides = ['set_condition']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    error_map = {'bad-request': ('modify','400'),
 | 
					    error_map = {'bad-request': ('modify', '400'),
 | 
				
			||||||
                 'conflict': ('cancel','409'),
 | 
					                 'conflict': ('cancel', '409'),
 | 
				
			||||||
                 'feature-not-implemented': ('cancel','501'),
 | 
					                 'feature-not-implemented': ('cancel', '501'),
 | 
				
			||||||
                 'forbidden': ('auth','403'),
 | 
					                 'forbidden': ('auth', '403'),
 | 
				
			||||||
                 'gone': ('modify','302'),
 | 
					                 'gone': ('modify', '302'),
 | 
				
			||||||
                 'internal-server-error': ('wait','500'),
 | 
					                 'internal-server-error': ('wait', '500'),
 | 
				
			||||||
                 'item-not-found': ('cancel','404'),
 | 
					                 'item-not-found': ('cancel', '404'),
 | 
				
			||||||
                 'jid-malformed': ('modify','400'),
 | 
					                 'jid-malformed': ('modify', '400'),
 | 
				
			||||||
                 'not-acceptable': ('modify','406'),
 | 
					                 'not-acceptable': ('modify', '406'),
 | 
				
			||||||
                 'not-allowed': ('cancel','405'),
 | 
					                 'not-allowed': ('cancel', '405'),
 | 
				
			||||||
                 'not-authorized': ('auth','401'),
 | 
					                 'not-authorized': ('auth', '401'),
 | 
				
			||||||
                 'payment-required': ('auth','402'),
 | 
					                 'payment-required': ('auth', '402'),
 | 
				
			||||||
                 'recipient-unavailable': ('wait','404'),
 | 
					                 'recipient-unavailable': ('wait', '404'),
 | 
				
			||||||
                 'redirect': ('modify','302'),
 | 
					                 'redirect': ('modify', '302'),
 | 
				
			||||||
                 'registration-required': ('auth','407'),
 | 
					                 'registration-required': ('auth', '407'),
 | 
				
			||||||
                 'remote-server-not-found': ('cancel','404'),
 | 
					                 'remote-server-not-found': ('cancel', '404'),
 | 
				
			||||||
                 'remote-server-timeout': ('wait','504'),
 | 
					                 'remote-server-timeout': ('wait', '504'),
 | 
				
			||||||
                 'resource-constraint': ('wait','500'),
 | 
					                 'resource-constraint': ('wait', '500'),
 | 
				
			||||||
                 'service-unavailable': ('cancel','503'),
 | 
					                 'service-unavailable': ('cancel', '503'),
 | 
				
			||||||
                 'subscription-required': ('auth','407'),
 | 
					                 'subscription-required': ('auth', '407'),
 | 
				
			||||||
                 'undefined-condition': (None,'500'),
 | 
					                 'undefined-condition': (None, '500'),
 | 
				
			||||||
                 'unexpected-request': ('wait','400')}
 | 
					                 'unexpected-request': ('wait', '400')}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setup(self, xml):
 | 
					    def setup(self, xml):
 | 
				
			||||||
        """Don't create XML for the plugin."""
 | 
					        """Don't create XML for the plugin."""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -79,5 +79,7 @@ class XEP_0092(BasePlugin):
 | 
				
			|||||||
        result = iq.send()
 | 
					        result = iq.send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if result and result['type'] != 'error':
 | 
					        if result and result['type'] != 'error':
 | 
				
			||||||
            return result['software_version'].values
 | 
					            values = result['software_version'].values
 | 
				
			||||||
 | 
					            del values['lang']
 | 
				
			||||||
 | 
					            return values
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -173,7 +173,8 @@ class XEP_0115(BasePlugin):
 | 
				
			|||||||
                    form_types.append(f_type)
 | 
					                    form_types.append(f_type)
 | 
				
			||||||
                    deduped_form_types.add(f_type)
 | 
					                    deduped_form_types.add(f_type)
 | 
				
			||||||
                    if len(form_types) != len(deduped_form_types):
 | 
					                    if len(form_types) != len(deduped_form_types):
 | 
				
			||||||
                        log.debug("Duplicated FORM_TYPE values, invalid for caps")
 | 
					                        log.debug("Duplicated FORM_TYPE values, " + \
 | 
				
			||||||
 | 
					                                  "invalid for caps")
 | 
				
			||||||
                        return False
 | 
					                        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if len(f_type) > 1:
 | 
					                    if len(f_type) > 1:
 | 
				
			||||||
@@ -183,7 +184,8 @@ class XEP_0115(BasePlugin):
 | 
				
			|||||||
                            return False
 | 
					                            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if stanza['fields']['FORM_TYPE']['type'] != 'hidden':
 | 
					                    if stanza['fields']['FORM_TYPE']['type'] != 'hidden':
 | 
				
			||||||
                        log.debug("Field FORM_TYPE type not 'hidden', ignoring form for caps")
 | 
					                        log.debug("Field FORM_TYPE type not 'hidden', " + \
 | 
				
			||||||
 | 
					                                  "ignoring form for caps")
 | 
				
			||||||
                        caps.xml.remove(stanza.xml)
 | 
					                        caps.xml.remove(stanza.xml)
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    log.debug("No FORM_TYPE found, ignoring form for caps")
 | 
					                    log.debug("No FORM_TYPE found, ignoring form for caps")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,7 +56,7 @@ class XEP_0163(BasePlugin):
 | 
				
			|||||||
            jid       -- Optionally specify the JID.
 | 
					            jid       -- Optionally specify the JID.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if not isinstance(namespace, set) and not isinstance(namespace, list):
 | 
					        if not isinstance(namespace, set) and not isinstance(namespace, list):
 | 
				
			||||||
           namespace = [namespace]
 | 
					            namespace = [namespace]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for ns in namespace:
 | 
					        for ns in namespace:
 | 
				
			||||||
            self.xmpp['xep_0030'].add_feature('%s+notify' % ns,
 | 
					            self.xmpp['xep_0030'].add_feature('%s+notify' % ns,
 | 
				
			||||||
@@ -75,7 +75,7 @@ class XEP_0163(BasePlugin):
 | 
				
			|||||||
            jid       -- Optionally specify the JID.
 | 
					            jid       -- Optionally specify the JID.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if not isinstance(namespace, set) and not isinstance(namespace, list):
 | 
					        if not isinstance(namespace, set) and not isinstance(namespace, list):
 | 
				
			||||||
           namespace = [namespace]
 | 
					            namespace = [namespace]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for ns in namespace:
 | 
					        for ns in namespace:
 | 
				
			||||||
            self.xmpp['xep_0030'].del_feature(jid=jid,
 | 
					            self.xmpp['xep_0030'].del_feature(jid=jid,
 | 
				
			||||||
@@ -109,6 +109,7 @@ class XEP_0163(BasePlugin):
 | 
				
			|||||||
            node = stanza.namespace
 | 
					            node = stanza.namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self.xmpp['xep_0060'].publish(ifrom, node,
 | 
					        return self.xmpp['xep_0060'].publish(ifrom, node,
 | 
				
			||||||
 | 
					                id=id,
 | 
				
			||||||
                payload=stanza.xml,
 | 
					                payload=stanza.xml,
 | 
				
			||||||
                options=options,
 | 
					                options=options,
 | 
				
			||||||
                ifrom=ifrom,
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,7 +82,6 @@ class Resumed(StanzaBase):
 | 
				
			|||||||
        self._set_attr('h', str(val))
 | 
					        self._set_attr('h', str(val))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class Failed(StanzaBase, Error):
 | 
					class Failed(StanzaBase, Error):
 | 
				
			||||||
    name = 'failed'
 | 
					    name = 'failed'
 | 
				
			||||||
    namespace = 'urn:xmpp:sm:3'
 | 
					    namespace = 'urn:xmpp:sm:3'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ from sleekxmpp.plugins.xep_0198 import stanza
 | 
				
			|||||||
log = logging.getLogger(__name__)
 | 
					log = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MAX_SEQ = 2**32
 | 
					MAX_SEQ = 2 ** 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class XEP_0198(BasePlugin):
 | 
					class XEP_0198(BasePlugin):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,8 +40,12 @@ class XEP_0202(BasePlugin):
 | 
				
			|||||||
        # custom function can be supplied which accepts
 | 
					        # custom function can be supplied which accepts
 | 
				
			||||||
        # the JID of the entity to query for the time.
 | 
					        # the JID of the entity to query for the time.
 | 
				
			||||||
        self.local_time = self.config.get('local_time', None)
 | 
					        self.local_time = self.config.get('local_time', None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def default_local_time(jid):
 | 
				
			||||||
 | 
					            return xep_0082.datetime(offset=self.tz_offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not self.local_time:
 | 
					        if not self.local_time:
 | 
				
			||||||
            self.local_time = lambda x: xep_0082.datetime(offset=self.tz_offset)
 | 
					            self.local_time = default_local_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.xmpp.registerHandler(
 | 
					        self.xmpp.registerHandler(
 | 
				
			||||||
            Callback('Entity Time',
 | 
					            Callback('Entity Time',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,9 +13,7 @@ from sleekxmpp.plugins.xep_0203.stanza import Delay
 | 
				
			|||||||
from sleekxmpp.plugins.xep_0203.delay import XEP_0203
 | 
					from sleekxmpp.plugins.xep_0203.delay import XEP_0203
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
register_plugin(XEP_0203)
 | 
					register_plugin(XEP_0203)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
# Retain some backwards compatibility
 | 
					# Retain some backwards compatibility
 | 
				
			||||||
xep_0203 = XEP_0203
 | 
					xep_0203 = XEP_0203
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										126
									
								
								sleekxmpp/plugins/xep_0222.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								sleekxmpp/plugins/xep_0222.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import register_stanza_plugin
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.base import BasePlugin, register_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class XEP_0222(BasePlugin):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    XEP-0222: Persistent Storage of Public Data via PubSub
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'xep_0222'
 | 
				
			||||||
 | 
					    description = 'XEP-0222: Persistent Storage of Private Data via PubSub'
 | 
				
			||||||
 | 
					    dependencies = set(['xep_0163', 'xep_0060', 'xep_0004'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    profile = {'pubsub#persist_items': True,
 | 
				
			||||||
 | 
					               'pubsub#send_last_published_item': 'never'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def configure(self, node):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Update a node's configuration to match the public storage profile.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        config = self.xmpp['xep_0004'].Form()
 | 
				
			||||||
 | 
					        config['type'] = 'submit'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for field, value in self.profile.items():
 | 
				
			||||||
 | 
					            config.add_field(var=field, value=value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0060'].set_node_config(None, node, config,
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def store(self, stanza, node=None, id=None, ifrom=None, options=None,
 | 
				
			||||||
 | 
					              block=True, callback=None, timeout=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Store public data via PEP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This is just a (very) thin wrapper around the XEP-0060 publish()
 | 
				
			||||||
 | 
					        method to set the defaults expected by PEP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Arguments:
 | 
				
			||||||
 | 
					            stanza   -- The private content to store.
 | 
				
			||||||
 | 
					            node     -- The node to publish the content to. If not specified,
 | 
				
			||||||
 | 
					                        the stanza's namespace will be used.
 | 
				
			||||||
 | 
					            id       -- Optionally specify the ID of the item.
 | 
				
			||||||
 | 
					            options  -- Publish options to use, which will be modified to
 | 
				
			||||||
 | 
					                        fit the persistent storage option profile.
 | 
				
			||||||
 | 
					            ifrom    -- Specify the sender's JID.
 | 
				
			||||||
 | 
					            block    -- Specify if the send call will block until a response
 | 
				
			||||||
 | 
					                        is received, or a timeout occurs. Defaults to True.
 | 
				
			||||||
 | 
					            timeout  -- The length of time (in seconds) to wait for a response
 | 
				
			||||||
 | 
					                        before exiting the send call if blocking is used.
 | 
				
			||||||
 | 
					                        Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT
 | 
				
			||||||
 | 
					            callback -- Optional reference to a stream handler function. Will
 | 
				
			||||||
 | 
					                        be executed when a reply stanza is received.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if not options:
 | 
				
			||||||
 | 
					            options = self.xmpp['xep_0004'].stanza.Form()
 | 
				
			||||||
 | 
					            options['type'] = 'submit'
 | 
				
			||||||
 | 
					            options.add_field(
 | 
				
			||||||
 | 
					                var='FORM_TYPE',
 | 
				
			||||||
 | 
					                ftype='hidden',
 | 
				
			||||||
 | 
					                value='http://jabber.org/protocol/pubsub#publish-options')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for field, value in self.profile.items():
 | 
				
			||||||
 | 
					            if field not in options.fields:
 | 
				
			||||||
 | 
					                options.add_field(var=field)
 | 
				
			||||||
 | 
					            options.fields[field]['value'] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0163'].publish(stanza, node,
 | 
				
			||||||
 | 
					                options=options,
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retrieve(self, node, id=None, item_ids=None, ifrom=None,
 | 
				
			||||||
 | 
					                 block=True, callback=None, timeout=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Retrieve public data via PEP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This is just a (very) thin wrapper around the XEP-0060 publish()
 | 
				
			||||||
 | 
					        method to set the defaults expected by PEP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Arguments:
 | 
				
			||||||
 | 
					            node     -- The node to retrieve content from.
 | 
				
			||||||
 | 
					            id       -- Optionally specify the ID of the item.
 | 
				
			||||||
 | 
					            item_ids -- Specify a group of IDs. If id is also specified, it
 | 
				
			||||||
 | 
					                        will be included in item_ids.
 | 
				
			||||||
 | 
					            ifrom    -- Specify the sender's JID.
 | 
				
			||||||
 | 
					            block    -- Specify if the send call will block until a response
 | 
				
			||||||
 | 
					                        is received, or a timeout occurs. Defaults to True.
 | 
				
			||||||
 | 
					            timeout  -- The length of time (in seconds) to wait for a response
 | 
				
			||||||
 | 
					                        before exiting the send call if blocking is used.
 | 
				
			||||||
 | 
					                        Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT
 | 
				
			||||||
 | 
					            callback -- Optional reference to a stream handler function. Will
 | 
				
			||||||
 | 
					                        be executed when a reply stanza is received.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if item_ids is None:
 | 
				
			||||||
 | 
					            item_ids = []
 | 
				
			||||||
 | 
					        if id is not None:
 | 
				
			||||||
 | 
					            item_ids.append(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0060'].get_items(None, node,
 | 
				
			||||||
 | 
					                item_ids=item_ids,
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register_plugin(XEP_0222)
 | 
				
			||||||
							
								
								
									
										126
									
								
								sleekxmpp/plugins/xep_0223.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								sleekxmpp/plugins/xep_0223.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import register_stanza_plugin
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.base import BasePlugin, register_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class XEP_0223(BasePlugin):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    XEP-0223: Persistent Storage of Private Data via PubSub
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'xep_0223'
 | 
				
			||||||
 | 
					    description = 'XEP-0223: Persistent Storage of Private Data via PubSub'
 | 
				
			||||||
 | 
					    dependencies = set(['xep_0163', 'xep_0060', 'xep_0004'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    profile = {'pubsub#persist_items': True,
 | 
				
			||||||
 | 
					               'pubsub#send_last_published_item': 'never'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def configure(self, node):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Update a node's configuration to match the public storage profile.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        config = self.xmpp['xep_0004'].Form()
 | 
				
			||||||
 | 
					        config['type'] = 'submit'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for field, value in self.profile.items():
 | 
				
			||||||
 | 
					            config.add_field(var=field, value=value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0060'].set_node_config(None, node, config,
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def store(self, stanza, node=None, id=None, ifrom=None, options=None,
 | 
				
			||||||
 | 
					              block=True, callback=None, timeout=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Store private data via PEP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This is just a (very) thin wrapper around the XEP-0060 publish()
 | 
				
			||||||
 | 
					        method to set the defaults expected by PEP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Arguments:
 | 
				
			||||||
 | 
					            stanza   -- The private content to store.
 | 
				
			||||||
 | 
					            node     -- The node to publish the content to. If not specified,
 | 
				
			||||||
 | 
					                        the stanza's namespace will be used.
 | 
				
			||||||
 | 
					            id       -- Optionally specify the ID of the item.
 | 
				
			||||||
 | 
					            options  -- Publish options to use, which will be modified to
 | 
				
			||||||
 | 
					                        fit the persistent storage option profile.
 | 
				
			||||||
 | 
					            ifrom    -- Specify the sender's JID.
 | 
				
			||||||
 | 
					            block    -- Specify if the send call will block until a response
 | 
				
			||||||
 | 
					                        is received, or a timeout occurs. Defaults to True.
 | 
				
			||||||
 | 
					            timeout  -- The length of time (in seconds) to wait for a response
 | 
				
			||||||
 | 
					                        before exiting the send call if blocking is used.
 | 
				
			||||||
 | 
					                        Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT
 | 
				
			||||||
 | 
					            callback -- Optional reference to a stream handler function. Will
 | 
				
			||||||
 | 
					                        be executed when a reply stanza is received.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if not options:
 | 
				
			||||||
 | 
					            options = self.xmpp['xep_0004'].stanza.Form()
 | 
				
			||||||
 | 
					            options['type'] = 'submit'
 | 
				
			||||||
 | 
					            options.add_field(
 | 
				
			||||||
 | 
					                var='FORM_TYPE',
 | 
				
			||||||
 | 
					                ftype='hidden',
 | 
				
			||||||
 | 
					                value='http://jabber.org/protocol/pubsub#publish-options')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for field, value in self.profile.items():
 | 
				
			||||||
 | 
					            if field not in options.fields:
 | 
				
			||||||
 | 
					                options.add_field(var=field)
 | 
				
			||||||
 | 
					            options.fields[field]['value'] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0163'].publish(stanza, node,
 | 
				
			||||||
 | 
					                options=options,
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retrieve(self, node, id=None, item_ids=None, ifrom=None,
 | 
				
			||||||
 | 
					                 block=True, callback=None, timeout=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Retrieve private data via PEP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This is just a (very) thin wrapper around the XEP-0060 publish()
 | 
				
			||||||
 | 
					        method to set the defaults expected by PEP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Arguments:
 | 
				
			||||||
 | 
					            node     -- The node to retrieve content from.
 | 
				
			||||||
 | 
					            id       -- Optionally specify the ID of the item.
 | 
				
			||||||
 | 
					            item_ids -- Specify a group of IDs. If id is also specified, it
 | 
				
			||||||
 | 
					                        will be included in item_ids.
 | 
				
			||||||
 | 
					            ifrom    -- Specify the sender's JID.
 | 
				
			||||||
 | 
					            block    -- Specify if the send call will block until a response
 | 
				
			||||||
 | 
					                        is received, or a timeout occurs. Defaults to True.
 | 
				
			||||||
 | 
					            timeout  -- The length of time (in seconds) to wait for a response
 | 
				
			||||||
 | 
					                        before exiting the send call if blocking is used.
 | 
				
			||||||
 | 
					                        Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT
 | 
				
			||||||
 | 
					            callback -- Optional reference to a stream handler function. Will
 | 
				
			||||||
 | 
					                        be executed when a reply stanza is received.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if item_ids is None:
 | 
				
			||||||
 | 
					            item_ids = []
 | 
				
			||||||
 | 
					        if id is not None:
 | 
				
			||||||
 | 
					            item_ids.append(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.xmpp['xep_0060'].get_items(None, node,
 | 
				
			||||||
 | 
					                item_ids=item_ids,
 | 
				
			||||||
 | 
					                ifrom=ifrom,
 | 
				
			||||||
 | 
					                block=block,
 | 
				
			||||||
 | 
					                callback=callback,
 | 
				
			||||||
 | 
					                timeout=timeout)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register_plugin(XEP_0223)
 | 
				
			||||||
@@ -58,7 +58,6 @@ class XEP_0231(BasePlugin):
 | 
				
			|||||||
        self.api.register(self._set_bob, 'set_bob', default=True)
 | 
					        self.api.register(self._set_bob, 'set_bob', default=True)
 | 
				
			||||||
        self.api.register(self._del_bob, 'del_bob', default=True)
 | 
					        self.api.register(self._del_bob, 'del_bob', default=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def set_bob(self, data, mtype, cid=None, max_age=None):
 | 
					    def set_bob(self, data, mtype, cid=None, max_age=None):
 | 
				
			||||||
        if cid is None:
 | 
					        if cid is None:
 | 
				
			||||||
            cid = 'sha1+%s@bob.xmpp.org' % hashlib.sha1(data).hexdigest()
 | 
					            cid = 'sha1+%s@bob.xmpp.org' % hashlib.sha1(data).hexdigest()
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								sleekxmpp/plugins/xep_0258/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								sleekxmpp/plugins/xep_0258/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.base import register_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0258 import stanza
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0258.stanza import SecurityLabel, Label
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0258.stanza import DisplayMarking, EquivalentLabel
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0258.stanza import ESSLabel, Catalog, CatalogItem
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0258.security_labels import XEP_0258
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register_plugin(XEP_0258)
 | 
				
			||||||
							
								
								
									
										40
									
								
								sleekxmpp/plugins/xep_0258/security_labels.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								sleekxmpp/plugins/xep_0258/security_labels.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp import Iq, Message
 | 
				
			||||||
 | 
					from sleekxmpp.plugins import BasePlugin
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import register_stanza_plugin
 | 
				
			||||||
 | 
					from sleekxmpp.plugins.xep_0258 import stanza, SecurityLabel, Catalog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class XEP_0258(BasePlugin):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'xep_0258'
 | 
				
			||||||
 | 
					    description = 'XEP-0258: Security Labels in XMPP'
 | 
				
			||||||
 | 
					    dependencies = set(['xep_0030'])
 | 
				
			||||||
 | 
					    stanza = stanza
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def plugin_init(self):
 | 
				
			||||||
 | 
					        self.xmpp['xep_0030'].add_feature(SecurityLabel.namespace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        register_stanza_plugin(Message, SecurityLabel)
 | 
				
			||||||
 | 
					        register_stanza_plugin(Iq, Catalog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_catalog(self, jid, ifrom=None, block=True,
 | 
				
			||||||
 | 
					                          callback=None, timeout=None):
 | 
				
			||||||
 | 
					        iq = self.xmpp.Iq()
 | 
				
			||||||
 | 
					        iq['to'] = jid
 | 
				
			||||||
 | 
					        iq['from'] = ifrom
 | 
				
			||||||
 | 
					        iq['type'] = 'get'
 | 
				
			||||||
 | 
					        iq.enable('security_label_catalog')
 | 
				
			||||||
 | 
					        return iq.send(block=block, callback=callback, timeout=timeout)
 | 
				
			||||||
							
								
								
									
										142
									
								
								sleekxmpp/plugins/xep_0258/stanza.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								sleekxmpp/plugins/xep_0258/stanza.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,142 @@
 | 
				
			|||||||
 | 
					"""
 | 
				
			||||||
 | 
					    SleekXMPP: The Sleek XMPP Library
 | 
				
			||||||
 | 
					    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
				
			||||||
 | 
					    This file is part of SleekXMPP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from base64 import b64encode, b64decode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.thirdparty.suelta.util import bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SecurityLabel(ElementBase):
 | 
				
			||||||
 | 
					    name = 'securitylabel'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:sec-label:0'
 | 
				
			||||||
 | 
					    plugin_attrib = 'security_label'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_equivalent(self, label):
 | 
				
			||||||
 | 
					        equiv = EquivalentLabel(parent=self)
 | 
				
			||||||
 | 
					        equiv.append(label)
 | 
				
			||||||
 | 
					        return equiv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Label(ElementBase):
 | 
				
			||||||
 | 
					    name = 'label'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:sec-label:0'
 | 
				
			||||||
 | 
					    plugin_attrib = 'label'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DisplayMarking(ElementBase):
 | 
				
			||||||
 | 
					    name = 'displaymarking'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:sec-label:0'
 | 
				
			||||||
 | 
					    plugin_attrib = 'display_marking'
 | 
				
			||||||
 | 
					    interfaces = set(['fgcolor', 'bgcolor', 'value'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_fgcolor(self):
 | 
				
			||||||
 | 
					        return self._get_attr('fgcolor', 'black')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_bgcolor(self):
 | 
				
			||||||
 | 
					        return self._get_attr('fgcolor', 'white')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_value(self):
 | 
				
			||||||
 | 
					        return self.xml.text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_value(self, value):
 | 
				
			||||||
 | 
					        self.xml.text = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def del_value(self):
 | 
				
			||||||
 | 
					        self.xml.text = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EquivalentLabel(ElementBase):
 | 
				
			||||||
 | 
					    name = 'equivalentlabel'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:sec-label:0'
 | 
				
			||||||
 | 
					    plugin_attrib = 'equivalent_label'
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'equivalent_labels'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Catalog(ElementBase):
 | 
				
			||||||
 | 
					    name = 'catalog'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:sec-label:catalog:2'
 | 
				
			||||||
 | 
					    plugin_attrib = 'security_label_catalog'
 | 
				
			||||||
 | 
					    interfaces = set(['to', 'from', 'name', 'desc', 'id', 'size', 'restrict'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_to(self):
 | 
				
			||||||
 | 
					        return JID(self._get_attr('to'))
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_to(self, value):
 | 
				
			||||||
 | 
					        return self._set_attr('to', str(value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_from(self):
 | 
				
			||||||
 | 
					        return JID(self._get_attr('from'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_from(self, value):
 | 
				
			||||||
 | 
					        return self._set_attr('from', str(value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_restrict(self):
 | 
				
			||||||
 | 
					        value = self._get_attr('restrict', '')
 | 
				
			||||||
 | 
					        if value and value.lower() in ('true', '1'):
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_restrict(self, value):
 | 
				
			||||||
 | 
					        self._del_attr('restrict')
 | 
				
			||||||
 | 
					        if value:
 | 
				
			||||||
 | 
					            self._set_attr('restrict', 'true')
 | 
				
			||||||
 | 
					        elif value is False:
 | 
				
			||||||
 | 
					            self._set_attr('restrict', 'false')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CatalogItem(ElementBase):
 | 
				
			||||||
 | 
					    name = 'catalog'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:sec-label:catalog:2'
 | 
				
			||||||
 | 
					    plugin_attrib = 'item'
 | 
				
			||||||
 | 
					    plugin_multi_attrib = 'items'
 | 
				
			||||||
 | 
					    interfaces = set(['selector', 'default'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_default(self):
 | 
				
			||||||
 | 
					        value = self._get_attr('default', '')
 | 
				
			||||||
 | 
					        if value.lower() in ('true', '1'):
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_default(self, value):
 | 
				
			||||||
 | 
					        self._del_attr('default')
 | 
				
			||||||
 | 
					        if value:
 | 
				
			||||||
 | 
					            self._set_attr('default', 'true')
 | 
				
			||||||
 | 
					        elif value is False:
 | 
				
			||||||
 | 
					            self._set_attr('default', 'false')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ESSLabel(ElementBase):
 | 
				
			||||||
 | 
					    name = 'esssecuritylabel'
 | 
				
			||||||
 | 
					    namespace = 'urn:xmpp:sec-label:ess:0'
 | 
				
			||||||
 | 
					    plugin_attrib = 'ess'
 | 
				
			||||||
 | 
					    interfaces = set(['value'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_value(self):
 | 
				
			||||||
 | 
					        if self.xml.text:
 | 
				
			||||||
 | 
					            return b64decode(bytes(self.xml.text))
 | 
				
			||||||
 | 
					        return ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_value(self, value):
 | 
				
			||||||
 | 
					        self.xml.text = ''
 | 
				
			||||||
 | 
					        if value:
 | 
				
			||||||
 | 
					            self.xml.text = b64encode(bytes(value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def del_value(self):
 | 
				
			||||||
 | 
					        self.xml.text = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register_stanza_plugin(Catalog, CatalogItem, iterable=True)
 | 
				
			||||||
 | 
					register_stanza_plugin(CatalogItem, SecurityLabel)
 | 
				
			||||||
 | 
					register_stanza_plugin(EquivalentLabel, ESSLabel)
 | 
				
			||||||
 | 
					register_stanza_plugin(Label, ESSLabel)
 | 
				
			||||||
 | 
					register_stanza_plugin(SecurityLabel, DisplayMarking)
 | 
				
			||||||
 | 
					register_stanza_plugin(SecurityLabel, EquivalentLabel, iterable=True)
 | 
				
			||||||
 | 
					register_stanza_plugin(SecurityLabel, Label)
 | 
				
			||||||
@@ -307,34 +307,29 @@ class RosterItem(object):
 | 
				
			|||||||
            p['from'] = self.owner
 | 
					            p['from'] = self.owner
 | 
				
			||||||
        p.send()
 | 
					        p.send()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def send_presence(self, ptype=None, pshow=None, pstatus=None,
 | 
					    def send_presence(self, **kwargs):
 | 
				
			||||||
                            ppriority=None, pnick=None):
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Create, initialize, and send a Presence stanza.
 | 
					        Create, initialize, and send a Presence stanza.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If no recipient is specified, send the presence immediately.
 | 
				
			||||||
 | 
					        Otherwise, forward the send request to the recipient's roster
 | 
				
			||||||
 | 
					        entry for processing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Arguments:
 | 
					        Arguments:
 | 
				
			||||||
            pshow     -- The presence's show value.
 | 
					            pshow     -- The presence's show value.
 | 
				
			||||||
            pstatus   -- The presence's status message.
 | 
					            pstatus   -- The presence's status message.
 | 
				
			||||||
            ppriority -- This connections' priority.
 | 
					            ppriority -- This connections' priority.
 | 
				
			||||||
 | 
					            pto       -- The recipient of a directed presence.
 | 
				
			||||||
 | 
					            pfrom     -- The sender of a directed presence, which should
 | 
				
			||||||
 | 
					                         be the owner JID plus resource.
 | 
				
			||||||
            ptype     -- The type of presence, such as 'subscribe'.
 | 
					            ptype     -- The type of presence, such as 'subscribe'.
 | 
				
			||||||
            pnick     -- Optional nickname of the presence's sender.
 | 
					            pnick     -- Optional nickname of the presence's sender.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        p = self.xmpp.make_presence(pshow=pshow,
 | 
					        if self.xmpp.is_component and not kwargs.get('pfrom', ''):
 | 
				
			||||||
                                    pstatus=pstatus,
 | 
					            kwargs['pfrom'] = self.owner
 | 
				
			||||||
                                    ppriority=ppriority,
 | 
					        if not kwargs.get('pto', ''):
 | 
				
			||||||
                                    ptype=ptype,
 | 
					            kwargs['pto'] = self.jid
 | 
				
			||||||
                                    pnick=pnick,
 | 
					        self.xmpp.send_presence(**kwargs)
 | 
				
			||||||
                                    pto=self.jid)
 | 
					 | 
				
			||||||
        if self.xmpp.is_component:
 | 
					 | 
				
			||||||
            p['from'] = self.owner
 | 
					 | 
				
			||||||
        if p['type'] in p.showtypes or \
 | 
					 | 
				
			||||||
           p['type'] in ['available', 'unavailable']:
 | 
					 | 
				
			||||||
            self.last_status = p
 | 
					 | 
				
			||||||
        p.send()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if not self.xmpp.sentpresence:
 | 
					 | 
				
			||||||
            self.xmpp.event('sent_presence')
 | 
					 | 
				
			||||||
            self.xmpp.sentpresence = True
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def send_last_presence(self):
 | 
					    def send_last_presence(self):
 | 
				
			||||||
        if self.last_status is None:
 | 
					        if self.last_status is None:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,11 @@
 | 
				
			|||||||
    See the file LICENSE for copying permission.
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.stanza import Presence
 | 
				
			||||||
from sleekxmpp.xmlstream import JID
 | 
					from sleekxmpp.xmlstream import JID
 | 
				
			||||||
from sleekxmpp.roster import RosterNode
 | 
					from sleekxmpp.roster import RosterNode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Roster(object):
 | 
					class Roster(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -55,6 +57,33 @@ class Roster(object):
 | 
				
			|||||||
            for node in self.db.entries(None, {}):
 | 
					            for node in self.db.entries(None, {}):
 | 
				
			||||||
                self.add(node)
 | 
					                self.add(node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.xmpp.add_filter('out', self._save_last_status)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _save_last_status(self, stanza):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if isinstance(stanza, Presence):
 | 
				
			||||||
 | 
					            sfrom = stanza['from'].full
 | 
				
			||||||
 | 
					            sto = stanza['to'].full
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if not sfrom:
 | 
				
			||||||
 | 
					                sfrom = self.xmpp.boundjid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if stanza['type'] in stanza.showtypes or \
 | 
				
			||||||
 | 
					               stanza['type'] in ('available', 'unavailable'):
 | 
				
			||||||
 | 
					                if sto:
 | 
				
			||||||
 | 
					                    self[sfrom][sto].last_status = stanza
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    self[sfrom].last_status = stanza
 | 
				
			||||||
 | 
					                    with self[sfrom]._last_status_lock:
 | 
				
			||||||
 | 
					                        for jid in self[sfrom]:
 | 
				
			||||||
 | 
					                            self[sfrom][jid].last_status = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if not self.xmpp.sentpresence:
 | 
				
			||||||
 | 
					                    self.xmpp.event('sent_presence')
 | 
				
			||||||
 | 
					                    self.xmpp.sentpresence = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return stanza
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getitem__(self, key):
 | 
					    def __getitem__(self, key):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return the roster node for a JID.
 | 
					        Return the roster node for a JID.
 | 
				
			||||||
@@ -121,29 +150,27 @@ class Roster(object):
 | 
				
			|||||||
        for node in self:
 | 
					        for node in self:
 | 
				
			||||||
            self[node].reset()
 | 
					            self[node].reset()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def send_presence(self, pshow=None, pstatus=None, ppriority=None,
 | 
					    def send_presence(self, **kwargs):
 | 
				
			||||||
                      pto=None, pfrom=None, ptype=None, pnick=None):
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Create, initialize, and send a Presence stanza.
 | 
					        Create, initialize, and send a Presence stanza.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Forwards the send request to the appropriate roster to
 | 
					        If no recipient is specified, send the presence immediately.
 | 
				
			||||||
        perform the actual sending.
 | 
					        Otherwise, forward the send request to the recipient's roster
 | 
				
			||||||
 | 
					        entry for processing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Arguments:
 | 
					        Arguments:
 | 
				
			||||||
            pshow     -- The presence's show value.
 | 
					            pshow     -- The presence's show value.
 | 
				
			||||||
            pstatus   -- The presence's status message.
 | 
					            pstatus   -- The presence's status message.
 | 
				
			||||||
            ppriority -- This connections' priority.
 | 
					            ppriority -- This connections' priority.
 | 
				
			||||||
            pto       -- The recipient of a directed presence.
 | 
					            pto       -- The recipient of a directed presence.
 | 
				
			||||||
 | 
					            pfrom     -- The sender of a directed presence, which should
 | 
				
			||||||
 | 
					                         be the owner JID plus resource.
 | 
				
			||||||
            ptype     -- The type of presence, such as 'subscribe'.
 | 
					            ptype     -- The type of presence, such as 'subscribe'.
 | 
				
			||||||
            pfrom     -- The sender of the presence.
 | 
					 | 
				
			||||||
            pnick     -- Optional nickname of the presence's sender.
 | 
					            pnick     -- Optional nickname of the presence's sender.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self[pfrom].send_presence(ptype=ptype,
 | 
					        if self.xmpp.is_component and not kwargs.get('pfrom', ''):
 | 
				
			||||||
                                  pshow=pshow,
 | 
					            kwargs['pfrom'] = self.jid
 | 
				
			||||||
                                  pstatus=pstatus,
 | 
					        self.xmpp.send_presence(**kwargs)
 | 
				
			||||||
                                  ppriority=ppriority,
 | 
					 | 
				
			||||||
                                  pnick=pnick,
 | 
					 | 
				
			||||||
                                  pto=pto)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def auto_authorize(self):
 | 
					    def auto_authorize(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@
 | 
				
			|||||||
    See the file LICENSE for copying permission.
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import threading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from sleekxmpp.xmlstream import JID
 | 
					from sleekxmpp.xmlstream import JID
 | 
				
			||||||
from sleekxmpp.roster import RosterItem
 | 
					from sleekxmpp.roster import RosterItem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,6 +61,7 @@ class RosterNode(object):
 | 
				
			|||||||
        self.last_status = None
 | 
					        self.last_status = None
 | 
				
			||||||
        self._version = ''
 | 
					        self._version = ''
 | 
				
			||||||
        self._jids = {}
 | 
					        self._jids = {}
 | 
				
			||||||
 | 
					        self._last_status_lock = threading.Lock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.db:
 | 
					        if self.db:
 | 
				
			||||||
            if hasattr(self.db, 'version'):
 | 
					            if hasattr(self.db, 'version'):
 | 
				
			||||||
@@ -291,8 +294,7 @@ class RosterNode(object):
 | 
				
			|||||||
        for jid in self:
 | 
					        for jid in self:
 | 
				
			||||||
            self[jid].reset()
 | 
					            self[jid].reset()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def send_presence(self, ptype=None, pshow=None, pstatus=None,
 | 
					    def send_presence(self, **kwargs):
 | 
				
			||||||
                            ppriority=None, pnick=None, pto=None):
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Create, initialize, and send a Presence stanza.
 | 
					        Create, initialize, and send a Presence stanza.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -305,27 +307,14 @@ class RosterNode(object):
 | 
				
			|||||||
            pstatus   -- The presence's status message.
 | 
					            pstatus   -- The presence's status message.
 | 
				
			||||||
            ppriority -- This connections' priority.
 | 
					            ppriority -- This connections' priority.
 | 
				
			||||||
            pto       -- The recipient of a directed presence.
 | 
					            pto       -- The recipient of a directed presence.
 | 
				
			||||||
 | 
					            pfrom     -- The sender of a directed presence, which should
 | 
				
			||||||
 | 
					                         be the owner JID plus resource.
 | 
				
			||||||
            ptype     -- The type of presence, such as 'subscribe'.
 | 
					            ptype     -- The type of presence, such as 'subscribe'.
 | 
				
			||||||
 | 
					            pnick     -- Optional nickname of the presence's sender.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if pto:
 | 
					        if self.xmpp.is_component and not kwargs.get('pfrom', ''):
 | 
				
			||||||
            self[pto].send_presence(ptype, pshow, pstatus,
 | 
					            kwargs['pfrom'] = self.jid
 | 
				
			||||||
                                    ppriority, pnick)
 | 
					        self.xmpp.send_presence(**kwargs)
 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            p = self.xmpp.make_presence(pshow=pshow,
 | 
					 | 
				
			||||||
                                        pstatus=pstatus,
 | 
					 | 
				
			||||||
                                        ppriority=ppriority,
 | 
					 | 
				
			||||||
                                        ptype=ptype,
 | 
					 | 
				
			||||||
                                        pnick=pnick)
 | 
					 | 
				
			||||||
            if self.xmpp.is_component:
 | 
					 | 
				
			||||||
                p['from'] = self.jid
 | 
					 | 
				
			||||||
            if p['type'] in p.showtypes or \
 | 
					 | 
				
			||||||
               p['type'] in ['available', 'unavailable']:
 | 
					 | 
				
			||||||
                self.last_status = p
 | 
					 | 
				
			||||||
            p.send()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not self.xmpp.sentpresence:
 | 
					 | 
				
			||||||
                self.xmpp.event('sent_presence')
 | 
					 | 
				
			||||||
                self.xmpp.sentpresence = True
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def send_last_presence(self):
 | 
					    def send_last_presence(self):
 | 
				
			||||||
        if self.last_status is None:
 | 
					        if self.last_status is None:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,7 +51,8 @@ class Error(ElementBase):
 | 
				
			|||||||
    namespace = 'jabber:client'
 | 
					    namespace = 'jabber:client'
 | 
				
			||||||
    name = 'error'
 | 
					    name = 'error'
 | 
				
			||||||
    plugin_attrib = 'error'
 | 
					    plugin_attrib = 'error'
 | 
				
			||||||
    interfaces = set(('code', 'condition', 'text', 'type'))
 | 
					    interfaces = set(('code', 'condition', 'text', 'type',
 | 
				
			||||||
 | 
					                      'gone', 'redirect'))
 | 
				
			||||||
    sub_interfaces = set(('text',))
 | 
					    sub_interfaces = set(('text',))
 | 
				
			||||||
    plugin_attrib_map = {}
 | 
					    plugin_attrib_map = {}
 | 
				
			||||||
    plugin_tag_map = {}
 | 
					    plugin_tag_map = {}
 | 
				
			||||||
@@ -88,7 +89,7 @@ class Error(ElementBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_condition(self):
 | 
					    def get_condition(self):
 | 
				
			||||||
        """Return the condition element's name."""
 | 
					        """Return the condition element's name."""
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            if "{%s}" % self.condition_ns in child.tag:
 | 
					            if "{%s}" % self.condition_ns in child.tag:
 | 
				
			||||||
                cond = child.tag.split('}', 1)[-1]
 | 
					                cond = child.tag.split('}', 1)[-1]
 | 
				
			||||||
                if cond in self.conditions:
 | 
					                if cond in self.conditions:
 | 
				
			||||||
@@ -109,7 +110,7 @@ class Error(ElementBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def del_condition(self):
 | 
					    def del_condition(self):
 | 
				
			||||||
        """Remove the condition element."""
 | 
					        """Remove the condition element."""
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            if "{%s}" % self.condition_ns in child.tag:
 | 
					            if "{%s}" % self.condition_ns in child.tag:
 | 
				
			||||||
                tag = child.tag.split('}', 1)[-1]
 | 
					                tag = child.tag.split('}', 1)[-1]
 | 
				
			||||||
                if tag in self.conditions:
 | 
					                if tag in self.conditions:
 | 
				
			||||||
@@ -135,6 +136,33 @@ class Error(ElementBase):
 | 
				
			|||||||
        self._del_sub('{%s}text' % self.condition_ns)
 | 
					        self._del_sub('{%s}text' % self.condition_ns)
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_gone(self):
 | 
				
			||||||
 | 
					        return self._get_sub_text('{%s}gone' % self.condition_ns, '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_redirect(self):
 | 
				
			||||||
 | 
					        return self._get_sub_text('{%s}redirect' % self.condition_ns, '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_gone(self, value):
 | 
				
			||||||
 | 
					        if value:
 | 
				
			||||||
 | 
					            del self['condition']
 | 
				
			||||||
 | 
					            return self._set_sub_text('{%s}gone' % self.condition_ns, value)
 | 
				
			||||||
 | 
					        elif self['condition'] == 'gone':
 | 
				
			||||||
 | 
					            del self['condition']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_redirect(self, value):
 | 
				
			||||||
 | 
					        if value:
 | 
				
			||||||
 | 
					            del self['condition']
 | 
				
			||||||
 | 
					            ns = self.condition_ns
 | 
				
			||||||
 | 
					            return self._set_sub_text('{%s}redirect' % ns, value)
 | 
				
			||||||
 | 
					        elif self['condition'] == 'redirect':
 | 
				
			||||||
 | 
					            del self['condition']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def del_gone(self):
 | 
				
			||||||
 | 
					        self._del_sub('{%s}gone' % self.condition_ns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def del_redirect(self):
 | 
				
			||||||
 | 
					        self._del_sub('{%s}redirect' % self.condition_ns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# To comply with PEP8, method names now use underscores.
 | 
					# To comply with PEP8, method names now use underscores.
 | 
				
			||||||
# Deprecated method names are re-mapped for backwards compatibility.
 | 
					# Deprecated method names are re-mapped for backwards compatibility.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -122,7 +122,7 @@ class Iq(RootStanza):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_query(self):
 | 
					    def get_query(self):
 | 
				
			||||||
        """Return the namespace of the <query> element."""
 | 
					        """Return the namespace of the <query> element."""
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            if child.tag.endswith('query'):
 | 
					            if child.tag.endswith('query'):
 | 
				
			||||||
                ns = child.tag.split('}')[0]
 | 
					                ns = child.tag.split('}')[0]
 | 
				
			||||||
                if '{' in ns:
 | 
					                if '{' in ns:
 | 
				
			||||||
@@ -132,7 +132,7 @@ class Iq(RootStanza):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def del_query(self):
 | 
					    def del_query(self):
 | 
				
			||||||
        """Remove the <query> element."""
 | 
					        """Remove the <query> element."""
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            if child.tag.endswith('query'):
 | 
					            if child.tag.endswith('query'):
 | 
				
			||||||
                self.xml.remove(child)
 | 
					                self.xml.remove(child)
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,8 @@ class RootStanza(StanzaBase):
 | 
				
			|||||||
            self['error']['type'] = 'cancel'
 | 
					            self['error']['type'] = 'cancel'
 | 
				
			||||||
            self.send()
 | 
					            self.send()
 | 
				
			||||||
            # log the error
 | 
					            # log the error
 | 
				
			||||||
            log.exception('Error handling {%s}%s stanza' ,  self.namespace, self.name)
 | 
					            log.exception('Error handling {%s}%s stanza',
 | 
				
			||||||
 | 
					                          self.namespace, self.name)
 | 
				
			||||||
            # Finally raise the exception to a global exception handler
 | 
					            # Finally raise the exception to a global exception handler
 | 
				
			||||||
            self.stream.exception(e)
 | 
					            self.stream.exception(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,6 +102,7 @@ class Roster(ElementBase):
 | 
				
			|||||||
                # Remove extra JID reference to keep everything
 | 
					                # Remove extra JID reference to keep everything
 | 
				
			||||||
                # backward compatible
 | 
					                # backward compatible
 | 
				
			||||||
                del items[item['jid']]['jid']
 | 
					                del items[item['jid']]['jid']
 | 
				
			||||||
 | 
					                del items[item['jid']]['lang']
 | 
				
			||||||
        return items
 | 
					        return items
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def del_items(self):
 | 
					    def del_items(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ class StreamError(Error, StanzaBase):
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    namespace = 'http://etherx.jabber.org/streams'
 | 
					    namespace = 'http://etherx.jabber.org/streams'
 | 
				
			||||||
    interfaces = set(('condition', 'text'))
 | 
					    interfaces = set(('condition', 'text', 'see_other_host'))
 | 
				
			||||||
    conditions = set((
 | 
					    conditions = set((
 | 
				
			||||||
        'bad-format', 'bad-namespace-prefix', 'conflict',
 | 
					        'bad-format', 'bad-namespace-prefix', 'conflict',
 | 
				
			||||||
        'connection-timeout', 'host-gone', 'host-unknown',
 | 
					        'connection-timeout', 'host-gone', 'host-unknown',
 | 
				
			||||||
@@ -66,3 +66,18 @@ class StreamError(Error, StanzaBase):
 | 
				
			|||||||
        'unsupported-feature', 'unsupported-stanza-type',
 | 
					        'unsupported-feature', 'unsupported-stanza-type',
 | 
				
			||||||
        'unsupported-version'))
 | 
					        'unsupported-version'))
 | 
				
			||||||
    condition_ns = 'urn:ietf:params:xml:ns:xmpp-streams'
 | 
					    condition_ns = 'urn:ietf:params:xml:ns:xmpp-streams'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_see_other_host(self):
 | 
				
			||||||
 | 
					        ns = self.condition_ns
 | 
				
			||||||
 | 
					        return self._get_sub_text('{%s}see-other-host' % ns, '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_see_other_host(self, value):
 | 
				
			||||||
 | 
					        if value:
 | 
				
			||||||
 | 
					            del self['condition']
 | 
				
			||||||
 | 
					            ns = self.condition_ns
 | 
				
			||||||
 | 
					            return self._set_sub_text('{%s}see-other-host' % ns, value)
 | 
				
			||||||
 | 
					        elif self['condition'] == 'see-other-host':
 | 
				
			||||||
 | 
					            del self['condition']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def del_see_other_host(self):
 | 
				
			||||||
 | 
					        self._del_sub('{%s}see-other-host' % self.condition_ns)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
    See the file LICENSE for copying permission.
 | 
					    See the file LICENSE for copying permission.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from sleekxmpp.thirdparty import OrderedDict
 | 
				
			||||||
from sleekxmpp.xmlstream import StanzaBase
 | 
					from sleekxmpp.xmlstream import StanzaBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,7 +29,10 @@ class StreamFeatures(StanzaBase):
 | 
				
			|||||||
    def get_features(self):
 | 
					    def get_features(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return self.plugins
 | 
					        features = OrderedDict()
 | 
				
			||||||
 | 
					        for (name, lang), plugin in self.plugins.items():
 | 
				
			||||||
 | 
					            features[name] = plugin
 | 
				
			||||||
 | 
					        return features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_features(self, value):
 | 
					    def set_features(self, value):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,7 +76,7 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
                            known_prefixes[prefix],
 | 
					                            known_prefixes[prefix],
 | 
				
			||||||
                            xml_string)
 | 
					                            xml_string)
 | 
				
			||||||
                xml = self.parse_xml(xml_string)
 | 
					                xml = self.parse_xml(xml_string)
 | 
				
			||||||
                xml = xml.getchildren()[0]
 | 
					                xml = list(xml)[0]
 | 
				
			||||||
                return xml
 | 
					                return xml
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                self.fail("XML data was mal-formed:\n%s" % xml_string)
 | 
					                self.fail("XML data was mal-formed:\n%s" % xml_string)
 | 
				
			||||||
@@ -333,6 +333,8 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
        # Remove unique ID prefix to make it easier to test
 | 
					        # Remove unique ID prefix to make it easier to test
 | 
				
			||||||
        self.xmpp._id_prefix = ''
 | 
					        self.xmpp._id_prefix = ''
 | 
				
			||||||
        self.xmpp._disconnect_wait_for_threads = False
 | 
					        self.xmpp._disconnect_wait_for_threads = False
 | 
				
			||||||
 | 
					        self.xmpp.default_lang = None
 | 
				
			||||||
 | 
					        self.xmpp.peer_default_lang = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # We will use this to wait for the session_start event
 | 
					        # We will use this to wait for the session_start event
 | 
				
			||||||
        # for live connections.
 | 
					        # for live connections.
 | 
				
			||||||
@@ -386,6 +388,7 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
                          sid='',
 | 
					                          sid='',
 | 
				
			||||||
                          stream_ns="http://etherx.jabber.org/streams",
 | 
					                          stream_ns="http://etherx.jabber.org/streams",
 | 
				
			||||||
                          default_ns="jabber:client",
 | 
					                          default_ns="jabber:client",
 | 
				
			||||||
 | 
					                          default_lang="en",
 | 
				
			||||||
                          version="1.0",
 | 
					                          version="1.0",
 | 
				
			||||||
                          xml_header=True):
 | 
					                          xml_header=True):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -413,6 +416,8 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
            parts.append('from="%s"' % sfrom)
 | 
					            parts.append('from="%s"' % sfrom)
 | 
				
			||||||
        if sid:
 | 
					        if sid:
 | 
				
			||||||
            parts.append('id="%s"' % sid)
 | 
					            parts.append('id="%s"' % sid)
 | 
				
			||||||
 | 
					        if default_lang:
 | 
				
			||||||
 | 
					            parts.append('xml:lang="%s"' % default_lang)
 | 
				
			||||||
        parts.append('version="%s"' % version)
 | 
					        parts.append('version="%s"' % version)
 | 
				
			||||||
        parts.append('xmlns:stream="%s"' % stream_ns)
 | 
					        parts.append('xmlns:stream="%s"' % stream_ns)
 | 
				
			||||||
        parts.append('xmlns="%s"' % default_ns)
 | 
					        parts.append('xmlns="%s"' % default_ns)
 | 
				
			||||||
@@ -512,9 +517,9 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
        if '{%s}lang' % xml_ns in recv_xml.attrib:
 | 
					        if '{%s}lang' % xml_ns in recv_xml.attrib:
 | 
				
			||||||
            del recv_xml.attrib['{%s}lang' % xml_ns]
 | 
					            del recv_xml.attrib['{%s}lang' % xml_ns]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if recv_xml.getchildren:
 | 
					        if list(recv_xml):
 | 
				
			||||||
            # We received more than just the header
 | 
					            # We received more than just the header
 | 
				
			||||||
            for xml in recv_xml.getchildren():
 | 
					            for xml in recv_xml:
 | 
				
			||||||
                self.xmpp.socket.recv_data(tostring(xml))
 | 
					                self.xmpp.socket.recv_data(tostring(xml))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            attrib = recv_xml.attrib
 | 
					            attrib = recv_xml.attrib
 | 
				
			||||||
@@ -564,6 +569,7 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
                          sid='',
 | 
					                          sid='',
 | 
				
			||||||
                          stream_ns="http://etherx.jabber.org/streams",
 | 
					                          stream_ns="http://etherx.jabber.org/streams",
 | 
				
			||||||
                          default_ns="jabber:client",
 | 
					                          default_ns="jabber:client",
 | 
				
			||||||
 | 
					                          default_lang="en",
 | 
				
			||||||
                          version="1.0",
 | 
					                          version="1.0",
 | 
				
			||||||
                          xml_header=False,
 | 
					                          xml_header=False,
 | 
				
			||||||
                          timeout=1):
 | 
					                          timeout=1):
 | 
				
			||||||
@@ -585,6 +591,7 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
        header = self.make_header(sto, sfrom, sid,
 | 
					        header = self.make_header(sto, sfrom, sid,
 | 
				
			||||||
                                  stream_ns=stream_ns,
 | 
					                                  stream_ns=stream_ns,
 | 
				
			||||||
                                  default_ns=default_ns,
 | 
					                                  default_ns=default_ns,
 | 
				
			||||||
 | 
					                                  default_lang=default_lang,
 | 
				
			||||||
                                  version=version,
 | 
					                                  version=version,
 | 
				
			||||||
                                  xml_header=xml_header)
 | 
					                                  xml_header=xml_header)
 | 
				
			||||||
        sent_header = self.xmpp.socket.next_sent(timeout)
 | 
					        sent_header = self.xmpp.socket.next_sent(timeout)
 | 
				
			||||||
@@ -691,7 +698,7 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
        if xml.tag.startswith('{'):
 | 
					        if xml.tag.startswith('{'):
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        xml.tag = '{%s}%s' % (ns, xml.tag)
 | 
					        xml.tag = '{%s}%s' % (ns, xml.tag)
 | 
				
			||||||
        for child in xml.getchildren():
 | 
					        for child in xml:
 | 
				
			||||||
            self.fix_namespaces(child, ns)
 | 
					            self.fix_namespaces(child, ns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def compare(self, xml, *other):
 | 
					    def compare(self, xml, *other):
 | 
				
			||||||
@@ -734,7 +741,7 @@ class SleekTest(unittest.TestCase):
 | 
				
			|||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Step 4: Check children count
 | 
					        # Step 4: Check children count
 | 
				
			||||||
        if len(xml.getchildren()) != len(other.getchildren()):
 | 
					        if len(list(xml)) != len(list(other)):
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Step 5: Recursively check children
 | 
					        # Step 5: Recursively check children
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,5 +9,5 @@
 | 
				
			|||||||
# We don't want to have to import the entire library
 | 
					# We don't want to have to import the entire library
 | 
				
			||||||
# just to get the version info for setup.py
 | 
					# just to get the version info for setup.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__version__ = '1.1.4'
 | 
					__version__ = '1.1.6'
 | 
				
			||||||
__version_info__ = (1, 1, 4, '', 0)
 | 
					__version_info__ = (1, 1, 6, '', 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,11 +7,12 @@ try:
 | 
				
			|||||||
    from pyasn1.type.univ import Any, ObjectIdentifier, OctetString
 | 
					    from pyasn1.type.univ import Any, ObjectIdentifier, OctetString
 | 
				
			||||||
    from pyasn1.type.char import BMPString, IA5String, UTF8String
 | 
					    from pyasn1.type.char import BMPString, IA5String, UTF8String
 | 
				
			||||||
    from pyasn1.type.useful import GeneralizedTime
 | 
					    from pyasn1.type.useful import GeneralizedTime
 | 
				
			||||||
    from pyasn1_modules.rfc2459 import Certificate, DirectoryString, SubjectAltName, GeneralNames, GeneralName
 | 
					    from pyasn1_modules.rfc2459 import (Certificate, DirectoryString,
 | 
				
			||||||
 | 
					                                        SubjectAltName, GeneralNames,
 | 
				
			||||||
 | 
					                                        GeneralName)
 | 
				
			||||||
    from pyasn1_modules.rfc2459 import id_ce_subjectAltName as SUBJECT_ALT_NAME
 | 
					    from pyasn1_modules.rfc2459 import id_ce_subjectAltName as SUBJECT_ALT_NAME
 | 
				
			||||||
    from pyasn1_modules.rfc2459 import id_at_commonName as COMMON_NAME
 | 
					    from pyasn1_modules.rfc2459 import id_at_commonName as COMMON_NAME
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    XMPP_ADDR = ObjectIdentifier('1.3.6.1.5.5.7.8.5')
 | 
					    XMPP_ADDR = ObjectIdentifier('1.3.6.1.5.5.7.8.5')
 | 
				
			||||||
    SRV_NAME = ObjectIdentifier('1.3.6.1.5.5.7.8.7')
 | 
					    SRV_NAME = ObjectIdentifier('1.3.6.1.5.5.7.8.7')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,7 +43,7 @@ def extract_names(raw_cert):
 | 
				
			|||||||
    cert = decoder.decode(raw_cert, asn1Spec=Certificate())[0]
 | 
					    cert = decoder.decode(raw_cert, asn1Spec=Certificate())[0]
 | 
				
			||||||
    tbs = cert.getComponentByName('tbsCertificate')
 | 
					    tbs = cert.getComponentByName('tbsCertificate')
 | 
				
			||||||
    subject = tbs.getComponentByName('subject')
 | 
					    subject = tbs.getComponentByName('subject')
 | 
				
			||||||
    extensions = tbs.getComponentByName('extensions')
 | 
					    extensions = tbs.getComponentByName('extensions') or []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Extract the CommonName(s) from the cert.
 | 
					    # Extract the CommonName(s) from the cert.
 | 
				
			||||||
    for rdnss in subject:
 | 
					    for rdnss in subject:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,8 +151,8 @@ class MatchXMLMask(MatcherBase):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        tag = tag.split('}')[-1]
 | 
					        tag = tag.split('}')[-1]
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            children = [c.tag.split('}')[-1] for c in xml.getchildren()]
 | 
					            children = [c.tag.split('}')[-1] for c in xml]
 | 
				
			||||||
            index = children.index(tag)
 | 
					            index = children.index(tag)
 | 
				
			||||||
        except ValueError:
 | 
					        except ValueError:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
        return xml.getchildren()[index]
 | 
					        return list(xml)[index]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,10 +77,10 @@ class MatchXPath(MatcherBase):
 | 
				
			|||||||
                    # Skip empty tag name artifacts from the cleanup phase.
 | 
					                    # Skip empty tag name artifacts from the cleanup phase.
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                children = [c.tag.split('}')[-1] for c in xml.getchildren()]
 | 
					                children = [c.tag.split('}')[-1] for c in xml]
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    index = children.index(tag)
 | 
					                    index = children.index(tag)
 | 
				
			||||||
                except ValueError:
 | 
					                except ValueError:
 | 
				
			||||||
                    return False
 | 
					                    return False
 | 
				
			||||||
                xml = xml.getchildren()[index]
 | 
					                xml = list(xml)[index]
 | 
				
			||||||
            return True
 | 
					            return True
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,8 @@ def default_resolver():
 | 
				
			|||||||
    return None
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def resolve(host, port=None, service=None, proto='tcp', resolver=None):
 | 
					def resolve(host, port=None, service=None, proto='tcp',
 | 
				
			||||||
 | 
					            resolver=None, use_ipv6=True):
 | 
				
			||||||
    """Peform DNS resolution for a given hostname.
 | 
					    """Peform DNS resolution for a given hostname.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Resolution may perform SRV record lookups if a service and protocol
 | 
					    Resolution may perform SRV record lookups if a service and protocol
 | 
				
			||||||
@@ -73,16 +74,23 @@ def resolve(host, port=None, service=None, proto='tcp', resolver=None):
 | 
				
			|||||||
    :param    proto: Optional SRV protocol name without leading underscore.
 | 
					    :param    proto: Optional SRV protocol name without leading underscore.
 | 
				
			||||||
    :param resolver: Optionally provide a DNS resolver object that has
 | 
					    :param resolver: Optionally provide a DNS resolver object that has
 | 
				
			||||||
                     been custom configured.
 | 
					                     been custom configured.
 | 
				
			||||||
 | 
					    :param use_ipv6: Optionally control the use of IPv6 in situations
 | 
				
			||||||
 | 
					                     where it is either not available, or performance
 | 
				
			||||||
 | 
					                     is degraded. Defaults to ``True``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    :type     host: string
 | 
					    :type     host: string
 | 
				
			||||||
    :type     port: int
 | 
					    :type     port: int
 | 
				
			||||||
    :type  service: string
 | 
					    :type  service: string
 | 
				
			||||||
    :type    proto: string
 | 
					    :type    proto: string
 | 
				
			||||||
    :type resolver: :class:`dns.resolver.Resolver`
 | 
					    :type resolver: :class:`dns.resolver.Resolver`
 | 
				
			||||||
 | 
					    :type use_ipv6: bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    :return: An iterable of IP address, port pairs in the order
 | 
					    :return: An iterable of IP address, port pairs in the order
 | 
				
			||||||
             dictated by SRV priorities and weights, if applicable.
 | 
					             dictated by SRV priorities and weights, if applicable.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					    if not use_ipv6:
 | 
				
			||||||
 | 
					        log.debug("DNS: Use of IPv6 has been disabled.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if resolver is None and USE_DNSPYTHON:
 | 
					    if resolver is None and USE_DNSPYTHON:
 | 
				
			||||||
        resolver = dns.resolver.get_default_resolver()
 | 
					        resolver = dns.resolver.get_default_resolver()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -98,13 +106,15 @@ def resolve(host, port=None, service=None, proto='tcp', resolver=None):
 | 
				
			|||||||
    except socket.error:
 | 
					    except socket.error:
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    if use_ipv6:
 | 
				
			||||||
        # Likewise, If `host` is an IPv6 literal, we can return it immediately.
 | 
					        try:
 | 
				
			||||||
        if hasattr(socket, 'inet_pton'):
 | 
					            # Likewise, If `host` is an IPv6 literal, we can return
 | 
				
			||||||
            ipv6 = socket.inet_pton(socket.AF_INET6, host)
 | 
					            # it immediately.
 | 
				
			||||||
            yield (host, port)
 | 
					            if hasattr(socket, 'inet_pton'):
 | 
				
			||||||
    except socket.error:
 | 
					                ipv6 = socket.inet_pton(socket.AF_INET6, host)
 | 
				
			||||||
        pass
 | 
					                yield (host, port)
 | 
				
			||||||
 | 
					        except socket.error:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # If no service was provided, then we can just do A/AAAA lookups on the
 | 
					    # If no service was provided, then we can just do A/AAAA lookups on the
 | 
				
			||||||
    # provided host. Otherwise we need to get an ordered list of hosts to
 | 
					    # provided host. Otherwise we need to get an ordered list of hosts to
 | 
				
			||||||
@@ -117,10 +127,12 @@ def resolve(host, port=None, service=None, proto='tcp', resolver=None):
 | 
				
			|||||||
    for host, port in hosts:
 | 
					    for host, port in hosts:
 | 
				
			||||||
        results = []
 | 
					        results = []
 | 
				
			||||||
        if host == 'localhost':
 | 
					        if host == 'localhost':
 | 
				
			||||||
            results.append(('::1', port))
 | 
					            if use_ipv6:
 | 
				
			||||||
 | 
					                results.append(('::1', port))
 | 
				
			||||||
            results.append(('127.0.0.1', port))
 | 
					            results.append(('127.0.0.1', port))
 | 
				
			||||||
        for address in get_AAAA(host, resolver=resolver):
 | 
					        if use_ipv6:
 | 
				
			||||||
            results.append((address, port))
 | 
					            for address in get_AAAA(host, resolver=resolver):
 | 
				
			||||||
 | 
					                results.append((address, port))
 | 
				
			||||||
        for address in get_A(host, resolver=resolver):
 | 
					        for address in get_A(host, resolver=resolver):
 | 
				
			||||||
            results.append((address, port))
 | 
					            results.append((address, port))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,13 +172,13 @@ def get_A(host, resolver=None):
 | 
				
			|||||||
        recs = resolver.query(host, dns.rdatatype.A)
 | 
					        recs = resolver.query(host, dns.rdatatype.A)
 | 
				
			||||||
        return [rec.to_text() for rec in recs]
 | 
					        return [rec.to_text() for rec in recs]
 | 
				
			||||||
    except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
 | 
					    except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
 | 
				
			||||||
        log.debug("DNS: No A records for %s." % host)
 | 
					        log.debug("DNS: No A records for %s" % host)
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
    except dns.exception.Timeout:
 | 
					    except dns.exception.Timeout:
 | 
				
			||||||
        log.debug("DNS: A record resolution timed out for %s." % host)
 | 
					        log.debug("DNS: A record resolution timed out for %s" % host)
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
    except dns.exception.DNSException as e:
 | 
					    except dns.exception.DNSException as e:
 | 
				
			||||||
        log.debug("DNS: Error querying A records for %s." % host)
 | 
					        log.debug("DNS: Error querying A records for %s" % host)
 | 
				
			||||||
        log.exception(e)
 | 
					        log.exception(e)
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -204,13 +216,13 @@ def get_AAAA(host, resolver=None):
 | 
				
			|||||||
        recs = resolver.query(host, dns.rdatatype.AAAA)
 | 
					        recs = resolver.query(host, dns.rdatatype.AAAA)
 | 
				
			||||||
        return [rec.to_text() for rec in recs]
 | 
					        return [rec.to_text() for rec in recs]
 | 
				
			||||||
    except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
 | 
					    except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
 | 
				
			||||||
        log.debug("DNS: No AAAA records for %s." % host)
 | 
					        log.debug("DNS: No AAAA records for %s" % host)
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
    except dns.exception.Timeout:
 | 
					    except dns.exception.Timeout:
 | 
				
			||||||
        log.debug("DNS: AAAA record resolution timed out for %s." % host)
 | 
					        log.debug("DNS: AAAA record resolution timed out for %s" % host)
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
    except dns.exception.DNSException as e:
 | 
					    except dns.exception.DNSException as e:
 | 
				
			||||||
        log.debug("DNS: Error querying AAAA records for %s." % host)
 | 
					        log.debug("DNS: Error querying AAAA records for %s" % host)
 | 
				
			||||||
        log.exception(e)
 | 
					        log.exception(e)
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -244,7 +256,7 @@ def get_SRV(host, port, service, proto='tcp', resolver=None):
 | 
				
			|||||||
    if resolver is None:
 | 
					    if resolver is None:
 | 
				
			||||||
        return [(host, port)]
 | 
					        return [(host, port)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    log.debug("Querying SRV records for %s" % host)
 | 
					    log.debug("DNS: Querying SRV records for %s" % host)
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        recs = resolver.query('_%s._%s.%s' % (service, proto, host),
 | 
					        recs = resolver.query('_%s._%s.%s' % (service, proto, host),
 | 
				
			||||||
                              dns.rdatatype.SRV)
 | 
					                              dns.rdatatype.SRV)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,8 @@
 | 
				
			|||||||
    :license: MIT, see LICENSE for more details
 | 
					    :license: MIT, see LICENSE for more details
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from __future__ import with_statement, unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import copy
 | 
					import copy
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import weakref
 | 
					import weakref
 | 
				
			||||||
@@ -29,6 +31,9 @@ log = logging.getLogger(__name__)
 | 
				
			|||||||
XML_TYPE = type(ET.Element('xml'))
 | 
					XML_TYPE = type(ET.Element('xml'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					XML_NS = 'http://www.w3.org/XML/1998/namespace'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def register_stanza_plugin(stanza, plugin, iterable=False, overrides=False):
 | 
					def register_stanza_plugin(stanza, plugin, iterable=False, overrides=False):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Associate a stanza object as a plugin for another stanza.
 | 
					    Associate a stanza object as a plugin for another stanza.
 | 
				
			||||||
@@ -94,6 +99,14 @@ def multifactory(stanza, plugin_attrib):
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    Returns a ElementBase class for handling reoccuring child stanzas
 | 
					    Returns a ElementBase class for handling reoccuring child stanzas
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def plugin_filter(self):
 | 
				
			||||||
 | 
					        return lambda x: isinstance(x, self._multistanza)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def plugin_lang_filter(self, lang):
 | 
				
			||||||
 | 
					        return lambda x: isinstance(x, self._multistanza) and \
 | 
				
			||||||
 | 
					                         x['lang'] == lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Multi(ElementBase):
 | 
					    class Multi(ElementBase):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Template class for multifactory
 | 
					        Template class for multifactory
 | 
				
			||||||
@@ -101,28 +114,45 @@ def multifactory(stanza, plugin_attrib):
 | 
				
			|||||||
        def setup(self, xml=None):
 | 
					        def setup(self, xml=None):
 | 
				
			||||||
            self.xml = ET.Element('')
 | 
					            self.xml = ET.Element('')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_multi(self):
 | 
					    def get_multi(self, lang=None):
 | 
				
			||||||
        parent = self.parent()
 | 
					        parent = self.parent()
 | 
				
			||||||
        res = filter(lambda sub: isinstance(sub, self._multistanza), parent)
 | 
					        if not lang or lang == '*':
 | 
				
			||||||
 | 
					            res = filter(plugin_filter(self), parent)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            res = filter(plugin_filter(self, lang), parent)
 | 
				
			||||||
        return list(res)
 | 
					        return list(res)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_multi(self, val):
 | 
					    def set_multi(self, val, lang=None):
 | 
				
			||||||
        parent = self.parent()
 | 
					        parent = self.parent()
 | 
				
			||||||
        del parent[self.plugin_attrib]
 | 
					        del_multi = getattr(self, 'del_%s' % plugin_attrib)
 | 
				
			||||||
 | 
					        del_multi(lang)
 | 
				
			||||||
        for sub in val:
 | 
					        for sub in val:
 | 
				
			||||||
            parent.append(sub)
 | 
					            parent.append(sub)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def del_multi(self):
 | 
					    def del_multi(self, lang=None):
 | 
				
			||||||
        parent = self.parent()
 | 
					        parent = self.parent()
 | 
				
			||||||
        res = filter(lambda sub: isinstance(sub, self._multistanza), parent)
 | 
					        if not lang or lang == '*':
 | 
				
			||||||
        for stanza in list(res):
 | 
					            res = filter(plugin_filter(self), parent)
 | 
				
			||||||
            parent.iterables.remove(stanza)
 | 
					        else:
 | 
				
			||||||
            parent.xml.remove(stanza.xml)
 | 
					            res = filter(plugin_filter(self, lang), parent)
 | 
				
			||||||
 | 
					        res = list(res)
 | 
				
			||||||
 | 
					        if not res:
 | 
				
			||||||
 | 
					            del parent.plugins[(plugin_attrib, None)]
 | 
				
			||||||
 | 
					            parent.loaded_plugins.remove(plugin_attrib)
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                parent.xml.remove(self.xml)
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            for stanza in list(res):
 | 
				
			||||||
 | 
					                parent.iterables.remove(stanza)
 | 
				
			||||||
 | 
					                parent.xml.remove(stanza.xml)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Multi.is_extension = True
 | 
					    Multi.is_extension = True
 | 
				
			||||||
    Multi.plugin_attrib = plugin_attrib
 | 
					    Multi.plugin_attrib = plugin_attrib
 | 
				
			||||||
    Multi._multistanza = stanza
 | 
					    Multi._multistanza = stanza
 | 
				
			||||||
    Multi.interfaces = (plugin_attrib,)
 | 
					    Multi.interfaces = set([plugin_attrib])
 | 
				
			||||||
 | 
					    Multi.lang_interfaces = set([plugin_attrib])
 | 
				
			||||||
    setattr(Multi, "get_%s" % plugin_attrib, get_multi)
 | 
					    setattr(Multi, "get_%s" % plugin_attrib, get_multi)
 | 
				
			||||||
    setattr(Multi, "set_%s" % plugin_attrib, set_multi)
 | 
					    setattr(Multi, "set_%s" % plugin_attrib, set_multi)
 | 
				
			||||||
    setattr(Multi, "del_%s" % plugin_attrib, del_multi)
 | 
					    setattr(Multi, "del_%s" % plugin_attrib, del_multi)
 | 
				
			||||||
@@ -231,8 +261,10 @@ class ElementBase(object):
 | 
				
			|||||||
    directly from the parent stanza, as shown below, but retrieving
 | 
					    directly from the parent stanza, as shown below, but retrieving
 | 
				
			||||||
    information will require all interfaces to be used, as so::
 | 
					    information will require all interfaces to be used, as so::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        >>> message['custom'] = 'bar' # Same as using message['custom']['custom']
 | 
					        >>> # Same as using message['custom']['custom']
 | 
				
			||||||
        >>> message['custom']['custom'] # Must use all interfaces
 | 
					        >>> message['custom'] = 'bar'
 | 
				
			||||||
 | 
					        >>> # Must use all interfaces
 | 
				
			||||||
 | 
					        >>> message['custom']['custom']
 | 
				
			||||||
        'bar'
 | 
					        'bar'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    If the plugin sets :attr:`is_extension` to ``True``, then both setting
 | 
					    If the plugin sets :attr:`is_extension` to ``True``, then both setting
 | 
				
			||||||
@@ -245,13 +277,13 @@ class ElementBase(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    :param xml: Initialize the stanza object with an existing XML object.
 | 
					    :param xml: Initialize the stanza object with an existing XML object.
 | 
				
			||||||
    :param parent: Optionally specify a parent stanza object will will
 | 
					    :param parent: Optionally specify a parent stanza object will
 | 
				
			||||||
                   contain this substanza.
 | 
					                   contain this substanza.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #: The XML tag name of the element, not including any namespace
 | 
					    #: The XML tag name of the element, not including any namespace
 | 
				
			||||||
    #: prefixes. For example, an :class:`ElementBase` object for ``<message />``
 | 
					    #: prefixes. For example, an :class:`ElementBase` object for
 | 
				
			||||||
    #: would use ``name = 'message'``.
 | 
					    #: ``<message />`` would use ``name = 'message'``.
 | 
				
			||||||
    name = 'stanza'
 | 
					    name = 'stanza'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #: The XML namespace for the element. Given ``<foo xmlns="bar" />``,
 | 
					    #: The XML namespace for the element. Given ``<foo xmlns="bar" />``,
 | 
				
			||||||
@@ -289,14 +321,17 @@ class ElementBase(object):
 | 
				
			|||||||
    #: subelements of the underlying XML object. Using this set, the text
 | 
					    #: subelements of the underlying XML object. Using this set, the text
 | 
				
			||||||
    #: of these subelements may be set, retrieved, or removed without
 | 
					    #: of these subelements may be set, retrieved, or removed without
 | 
				
			||||||
    #: needing to define custom methods.
 | 
					    #: needing to define custom methods.
 | 
				
			||||||
    sub_interfaces = tuple()
 | 
					    sub_interfaces = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #: A subset of :attr:`interfaces` which maps the presence of
 | 
					    #: A subset of :attr:`interfaces` which maps the presence of
 | 
				
			||||||
    #: subelements to boolean values. Using this set allows for quickly
 | 
					    #: subelements to boolean values. Using this set allows for quickly
 | 
				
			||||||
    #: checking for the existence of empty subelements like ``<required />``.
 | 
					    #: checking for the existence of empty subelements like ``<required />``.
 | 
				
			||||||
    #:
 | 
					    #:
 | 
				
			||||||
    #: .. versionadded:: 1.1
 | 
					    #: .. versionadded:: 1.1
 | 
				
			||||||
    bool_interfaces = tuple()
 | 
					    bool_interfaces = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #: .. versionadded:: 1.1.2
 | 
				
			||||||
 | 
					    lang_interfaces = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #: In some cases you may wish to override the behaviour of one of the
 | 
					    #: In some cases you may wish to override the behaviour of one of the
 | 
				
			||||||
    #: parent stanza's interfaces. The ``overrides`` list specifies the
 | 
					    #: parent stanza's interfaces. The ``overrides`` list specifies the
 | 
				
			||||||
@@ -363,7 +398,7 @@ class ElementBase(object):
 | 
				
			|||||||
    subitem = set()
 | 
					    subitem = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #: The default XML namespace: ``http://www.w3.org/XML/1998/namespace``.
 | 
					    #: The default XML namespace: ``http://www.w3.org/XML/1998/namespace``.
 | 
				
			||||||
    xml_ns = 'http://www.w3.org/XML/1998/namespace'
 | 
					    xml_ns = XML_NS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, xml=None, parent=None):
 | 
					    def __init__(self, xml=None, parent=None):
 | 
				
			||||||
        self._index = 0
 | 
					        self._index = 0
 | 
				
			||||||
@@ -375,6 +410,7 @@ class ElementBase(object):
 | 
				
			|||||||
        #: An ordered dictionary of plugin stanzas, mapped by their
 | 
					        #: An ordered dictionary of plugin stanzas, mapped by their
 | 
				
			||||||
        #: :attr:`plugin_attrib` value.
 | 
					        #: :attr:`plugin_attrib` value.
 | 
				
			||||||
        self.plugins = OrderedDict()
 | 
					        self.plugins = OrderedDict()
 | 
				
			||||||
 | 
					        self.loaded_plugins = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #: A list of child stanzas whose class is included in
 | 
					        #: A list of child stanzas whose class is included in
 | 
				
			||||||
        #: :attr:`plugin_iterables`.
 | 
					        #: :attr:`plugin_iterables`.
 | 
				
			||||||
@@ -385,6 +421,12 @@ class ElementBase(object):
 | 
				
			|||||||
        #: ``'{namespace}elementname'``.
 | 
					        #: ``'{namespace}elementname'``.
 | 
				
			||||||
        self.tag = self.tag_name()
 | 
					        self.tag = self.tag_name()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if 'lang' not in self.interfaces:
 | 
				
			||||||
 | 
					            if isinstance(self.interfaces, tuple):
 | 
				
			||||||
 | 
					                self.interfaces += ('lang',)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.interfaces.add('lang')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #: A :class:`weakref.weakref` to the parent stanza, if there is one.
 | 
					        #: A :class:`weakref.weakref` to the parent stanza, if there is one.
 | 
				
			||||||
        #: If not, then :attr:`parent` is ``None``.
 | 
					        #: If not, then :attr:`parent` is ``None``.
 | 
				
			||||||
        self.parent = None
 | 
					        self.parent = None
 | 
				
			||||||
@@ -403,13 +445,12 @@ class ElementBase(object):
 | 
				
			|||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Initialize values using provided XML
 | 
					        # Initialize values using provided XML
 | 
				
			||||||
        for child in self.xml.getchildren():
 | 
					        for child in self.xml:
 | 
				
			||||||
            if child.tag in self.plugin_tag_map:
 | 
					            if child.tag in self.plugin_tag_map:
 | 
				
			||||||
                plugin_class = self.plugin_tag_map[child.tag]
 | 
					                plugin_class = self.plugin_tag_map[child.tag]
 | 
				
			||||||
                plugin = plugin_class(child, self)
 | 
					                self.init_plugin(plugin_class.plugin_attrib,
 | 
				
			||||||
                self.plugins[plugin.plugin_attrib] = plugin
 | 
					                                 existing_xml=child,
 | 
				
			||||||
                if plugin_class in self.plugin_iterables:
 | 
					                                 reuse=False)
 | 
				
			||||||
                    self.iterables.append(plugin)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setup(self, xml=None):
 | 
					    def setup(self, xml=None):
 | 
				
			||||||
        """Initialize the stanza's XML contents.
 | 
					        """Initialize the stanza's XML contents.
 | 
				
			||||||
@@ -443,7 +484,7 @@ class ElementBase(object):
 | 
				
			|||||||
            # We did not generate XML
 | 
					            # We did not generate XML
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def enable(self, attrib):
 | 
					    def enable(self, attrib, lang=None):
 | 
				
			||||||
        """Enable and initialize a stanza plugin.
 | 
					        """Enable and initialize a stanza plugin.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Alias for :meth:`init_plugin`.
 | 
					        Alias for :meth:`init_plugin`.
 | 
				
			||||||
@@ -451,24 +492,67 @@ class ElementBase(object):
 | 
				
			|||||||
        :param string attrib: The :attr:`plugin_attrib` value of the
 | 
					        :param string attrib: The :attr:`plugin_attrib` value of the
 | 
				
			||||||
                              plugin to enable.
 | 
					                              plugin to enable.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return self.init_plugin(attrib)
 | 
					        return self.init_plugin(attrib, lang)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def init_plugin(self, attrib):
 | 
					    def _get_plugin(self, name, lang=None):
 | 
				
			||||||
 | 
					        if lang is None:
 | 
				
			||||||
 | 
					            lang = self.get_lang()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if name not in self.plugin_attrib_map:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        plugin_class = self.plugin_attrib_map[name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if plugin_class.is_extension:
 | 
				
			||||||
 | 
					            if (name, None) in self.plugins:
 | 
				
			||||||
 | 
					                return self.plugins[(name, None)]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return self.init_plugin(name, lang)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if (name, lang) in self.plugins:
 | 
				
			||||||
 | 
					                return self.plugins[(name, lang)]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return self.init_plugin(name, lang)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def init_plugin(self, attrib, lang=None, existing_xml=None, reuse=True):
 | 
				
			||||||
        """Enable and initialize a stanza plugin.
 | 
					        """Enable and initialize a stanza plugin.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :param string attrib: The :attr:`plugin_attrib` value of the
 | 
					        :param string attrib: The :attr:`plugin_attrib` value of the
 | 
				
			||||||
                              plugin to enable.
 | 
					                              plugin to enable.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if attrib not in self.plugins:
 | 
					        if lang is None:
 | 
				
			||||||
            plugin_class = self.plugin_attrib_map[attrib]
 | 
					            lang = self.get_lang()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        plugin_class = self.plugin_attrib_map[attrib]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if plugin_class.is_extension and (attrib, None) in self.plugins:
 | 
				
			||||||
 | 
					            return self.plugins[(attrib, None)]
 | 
				
			||||||
 | 
					        if reuse and (attrib, lang) in self.plugins:
 | 
				
			||||||
 | 
					            return self.plugins[(attrib, lang)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if existing_xml is None:
 | 
				
			||||||
            existing_xml = self.xml.find(plugin_class.tag_name())
 | 
					            existing_xml = self.xml.find(plugin_class.tag_name())
 | 
				
			||||||
            plugin = plugin_class(parent=self, xml=existing_xml)
 | 
					
 | 
				
			||||||
            self.plugins[attrib] = plugin
 | 
					        if existing_xml is not None:
 | 
				
			||||||
            if plugin_class in self.plugin_iterables:
 | 
					            if existing_xml.attrib.get('{%s}lang' % XML_NS, '') != lang:
 | 
				
			||||||
                self.iterables.append(plugin)
 | 
					                existing_xml = None
 | 
				
			||||||
                if plugin_class.plugin_multi_attrib:
 | 
					
 | 
				
			||||||
                    self.init_plugin(plugin_class.plugin_multi_attrib)
 | 
					        plugin = plugin_class(parent=self, xml=existing_xml)
 | 
				
			||||||
        return self
 | 
					
 | 
				
			||||||
 | 
					        if plugin.is_extension:
 | 
				
			||||||
 | 
					            self.plugins[(attrib, None)] = plugin
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            plugin['lang'] = lang
 | 
				
			||||||
 | 
					            self.plugins[(attrib, lang)] = plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if plugin_class in self.plugin_iterables:
 | 
				
			||||||
 | 
					            self.iterables.append(plugin)
 | 
				
			||||||
 | 
					            if plugin_class.plugin_multi_attrib:
 | 
				
			||||||
 | 
					                self.init_plugin(plugin_class.plugin_multi_attrib)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.loaded_plugins.add(attrib)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return plugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _get_stanza_values(self):
 | 
					    def _get_stanza_values(self):
 | 
				
			||||||
        """Return A JSON/dictionary version of the XML content
 | 
					        """Return A JSON/dictionary version of the XML content
 | 
				
			||||||
@@ -492,8 +576,14 @@ class ElementBase(object):
 | 
				
			|||||||
        values = {}
 | 
					        values = {}
 | 
				
			||||||
        for interface in self.interfaces:
 | 
					        for interface in self.interfaces:
 | 
				
			||||||
            values[interface] = self[interface]
 | 
					            values[interface] = self[interface]
 | 
				
			||||||
 | 
					            if interface in self.lang_interfaces:
 | 
				
			||||||
 | 
					                values['%s|*' % interface] = self['%s|*' % interface]
 | 
				
			||||||
        for plugin, stanza in self.plugins.items():
 | 
					        for plugin, stanza in self.plugins.items():
 | 
				
			||||||
            values[plugin] = stanza.values
 | 
					            lang = stanza['lang']
 | 
				
			||||||
 | 
					            if lang:
 | 
				
			||||||
 | 
					                values['%s|%s' % (plugin, lang)] = stanza.values
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                values[plugin[0]] = stanza.values
 | 
				
			||||||
        if self.iterables:
 | 
					        if self.iterables:
 | 
				
			||||||
            iterables = []
 | 
					            iterables = []
 | 
				
			||||||
            for stanza in self.iterables:
 | 
					            for stanza in self.iterables:
 | 
				
			||||||
@@ -517,6 +607,11 @@ class ElementBase(object):
 | 
				
			|||||||
                                    p in self.plugin_iterables]
 | 
					                                    p in self.plugin_iterables]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for interface, value in values.items():
 | 
					        for interface, value in values.items():
 | 
				
			||||||
 | 
					            full_interface = interface
 | 
				
			||||||
 | 
					            interface_lang = ('%s|' % interface).split('|')
 | 
				
			||||||
 | 
					            interface = interface_lang[0]
 | 
				
			||||||
 | 
					            lang = interface_lang[1] or self.get_lang()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if interface == 'substanzas':
 | 
					            if interface == 'substanzas':
 | 
				
			||||||
                # Remove existing substanzas
 | 
					                # Remove existing substanzas
 | 
				
			||||||
                for stanza in self.iterables:
 | 
					                for stanza in self.iterables:
 | 
				
			||||||
@@ -535,12 +630,12 @@ class ElementBase(object):
 | 
				
			|||||||
                                self.iterables.append(sub)
 | 
					                                self.iterables.append(sub)
 | 
				
			||||||
                                break
 | 
					                                break
 | 
				
			||||||
            elif interface in self.interfaces:
 | 
					            elif interface in self.interfaces:
 | 
				
			||||||
                self[interface] = value
 | 
					                self[full_interface] = value
 | 
				
			||||||
            elif interface in self.plugin_attrib_map:
 | 
					            elif interface in self.plugin_attrib_map:
 | 
				
			||||||
                if interface not in iterable_interfaces:
 | 
					                if interface not in iterable_interfaces:
 | 
				
			||||||
                    if interface not in self.plugins:
 | 
					                    plugin = self._get_plugin(interface, lang)
 | 
				
			||||||
                        self.init_plugin(interface)
 | 
					                    if plugin:
 | 
				
			||||||
                    self.plugins[interface].values = value
 | 
					                        plugin.values = value
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getitem__(self, attrib):
 | 
					    def __getitem__(self, attrib):
 | 
				
			||||||
@@ -572,6 +667,15 @@ class ElementBase(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        :param string attrib: The name of the requested stanza interface.
 | 
					        :param string attrib: The name of the requested stanza interface.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        full_attrib = attrib
 | 
				
			||||||
 | 
					        attrib_lang = ('%s|' % attrib).split('|')
 | 
				
			||||||
 | 
					        attrib = attrib_lang[0]
 | 
				
			||||||
 | 
					        lang = attrib_lang[1] or ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        kwargs = {}
 | 
				
			||||||
 | 
					        if lang and attrib in self.lang_interfaces:
 | 
				
			||||||
 | 
					            kwargs['lang'] = lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if attrib == 'substanzas':
 | 
					        if attrib == 'substanzas':
 | 
				
			||||||
            return self.iterables
 | 
					            return self.iterables
 | 
				
			||||||
        elif attrib in self.interfaces:
 | 
					        elif attrib in self.interfaces:
 | 
				
			||||||
@@ -579,32 +683,31 @@ class ElementBase(object):
 | 
				
			|||||||
            get_method2 = "get%s" % attrib.title()
 | 
					            get_method2 = "get%s" % attrib.title()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if self.plugin_overrides:
 | 
					            if self.plugin_overrides:
 | 
				
			||||||
                plugin = self.plugin_overrides.get(get_method, None)
 | 
					                name = self.plugin_overrides.get(get_method, None)
 | 
				
			||||||
                if plugin:
 | 
					                if name:
 | 
				
			||||||
                    if plugin not in self.plugins:
 | 
					                    plugin = self._get_plugin(name, lang)
 | 
				
			||||||
                        self.init_plugin(plugin)
 | 
					                    if plugin:
 | 
				
			||||||
                    handler = getattr(self.plugins[plugin], get_method, None)
 | 
					                        handler = getattr(plugin, get_method, None)
 | 
				
			||||||
                    if handler:
 | 
					                        if handler:
 | 
				
			||||||
                        return handler()
 | 
					                            return handler(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if hasattr(self, get_method):
 | 
					            if hasattr(self, get_method):
 | 
				
			||||||
                return getattr(self, get_method)()
 | 
					                return getattr(self, get_method)(**kwargs)
 | 
				
			||||||
            elif hasattr(self, get_method2):
 | 
					            elif hasattr(self, get_method2):
 | 
				
			||||||
                return getattr(self, get_method2)()
 | 
					                return getattr(self, get_method2)(**kwargs)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                if attrib in self.sub_interfaces:
 | 
					                if attrib in self.sub_interfaces:
 | 
				
			||||||
                    return self._get_sub_text(attrib)
 | 
					                    return self._get_sub_text(attrib, lang=lang)
 | 
				
			||||||
                elif attrib in self.bool_interfaces:
 | 
					                elif attrib in self.bool_interfaces:
 | 
				
			||||||
                    elem = self.xml.find('{%s}%s' % (self.namespace, attrib))
 | 
					                    elem = self.xml.find('{%s}%s' % (self.namespace, attrib))
 | 
				
			||||||
                    return elem is not None
 | 
					                    return elem is not None
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    return self._get_attr(attrib)
 | 
					                    return self._get_attr(attrib)
 | 
				
			||||||
        elif attrib in self.plugin_attrib_map:
 | 
					        elif attrib in self.plugin_attrib_map:
 | 
				
			||||||
            if attrib not in self.plugins:
 | 
					            plugin = self._get_plugin(attrib, lang)
 | 
				
			||||||
                self.init_plugin(attrib)
 | 
					            if plugin and plugin.is_extension:
 | 
				
			||||||
            if self.plugins[attrib].is_extension:
 | 
					                return plugin[full_attrib]
 | 
				
			||||||
                return self.plugins[attrib][attrib]
 | 
					            return plugin
 | 
				
			||||||
            return self.plugins[attrib]
 | 
					 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return ''
 | 
					            return ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -640,41 +743,58 @@ class ElementBase(object):
 | 
				
			|||||||
        :param string attrib: The name of the stanza interface to modify.
 | 
					        :param string attrib: The name of the stanza interface to modify.
 | 
				
			||||||
        :param value: The new value of the stanza interface.
 | 
					        :param value: The new value of the stanza interface.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        full_attrib = attrib
 | 
				
			||||||
 | 
					        attrib_lang = ('%s|' % attrib).split('|')
 | 
				
			||||||
 | 
					        attrib = attrib_lang[0]
 | 
				
			||||||
 | 
					        lang = attrib_lang[1] or ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        kwargs = {}
 | 
				
			||||||
 | 
					        if lang and attrib in self.lang_interfaces:
 | 
				
			||||||
 | 
					            kwargs['lang'] = lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if attrib in self.interfaces:
 | 
					        if attrib in self.interfaces:
 | 
				
			||||||
            if value is not None:
 | 
					            if value is not None:
 | 
				
			||||||
                set_method = "set_%s" % attrib.lower()
 | 
					                set_method = "set_%s" % attrib.lower()
 | 
				
			||||||
                set_method2 = "set%s" % attrib.title()
 | 
					                set_method2 = "set%s" % attrib.title()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if self.plugin_overrides:
 | 
					                if self.plugin_overrides:
 | 
				
			||||||
                    plugin = self.plugin_overrides.get(set_method, None)
 | 
					                    name = self.plugin_overrides.get(set_method, None)
 | 
				
			||||||
                    if plugin:
 | 
					                    if name:
 | 
				
			||||||
                        if plugin not in self.plugins:
 | 
					                        plugin = self._get_plugin(name, lang)
 | 
				
			||||||
                            self.init_plugin(plugin)
 | 
					                        if plugin:
 | 
				
			||||||
                        handler = getattr(self.plugins[plugin],
 | 
					                            handler = getattr(plugin, set_method, None)
 | 
				
			||||||
                                          set_method, None)
 | 
					                            if handler:
 | 
				
			||||||
                        if handler:
 | 
					                                return handler(value, **kwargs)
 | 
				
			||||||
                            return handler(value)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if hasattr(self, set_method):
 | 
					                if hasattr(self, set_method):
 | 
				
			||||||
                    getattr(self, set_method)(value,)
 | 
					                    getattr(self, set_method)(value, **kwargs)
 | 
				
			||||||
                elif hasattr(self, set_method2):
 | 
					                elif hasattr(self, set_method2):
 | 
				
			||||||
                    getattr(self, set_method2)(value,)
 | 
					                    getattr(self, set_method2)(value, **kwargs)
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    if attrib in self.sub_interfaces:
 | 
					                    if attrib in self.sub_interfaces:
 | 
				
			||||||
                        return self._set_sub_text(attrib, text=value)
 | 
					                        if lang == '*':
 | 
				
			||||||
 | 
					                            return self._set_all_sub_text(attrib,
 | 
				
			||||||
 | 
					                                                          value,
 | 
				
			||||||
 | 
					                                                          lang='*')
 | 
				
			||||||
 | 
					                        return self._set_sub_text(attrib, text=value,
 | 
				
			||||||
 | 
					                                                          lang=lang)
 | 
				
			||||||
                    elif attrib in self.bool_interfaces:
 | 
					                    elif attrib in self.bool_interfaces:
 | 
				
			||||||
                        if value:
 | 
					                        if value:
 | 
				
			||||||
                            return self._set_sub_text(attrib, '', keep=True)
 | 
					                            return self._set_sub_text(attrib, '',
 | 
				
			||||||
 | 
					                                    keep=True,
 | 
				
			||||||
 | 
					                                    lang=lang)
 | 
				
			||||||
                        else:
 | 
					                        else:
 | 
				
			||||||
                            return self._set_sub_text(attrib, '', keep=False)
 | 
					                            return self._set_sub_text(attrib, '',
 | 
				
			||||||
 | 
					                                    keep=False,
 | 
				
			||||||
 | 
					                                    lang=lang)
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        self._set_attr(attrib, value)
 | 
					                        self._set_attr(attrib, value)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                self.__delitem__(attrib)
 | 
					                self.__delitem__(attrib)
 | 
				
			||||||
        elif attrib in self.plugin_attrib_map:
 | 
					        elif attrib in self.plugin_attrib_map:
 | 
				
			||||||
            if attrib not in self.plugins:
 | 
					            plugin = self._get_plugin(attrib, lang)
 | 
				
			||||||
                self.init_plugin(attrib)
 | 
					            if plugin:
 | 
				
			||||||
            self.plugins[attrib][attrib] = value
 | 
					                plugin[full_attrib] = value
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __delitem__(self, attrib):
 | 
					    def __delitem__(self, attrib):
 | 
				
			||||||
@@ -709,40 +829,53 @@ class ElementBase(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        :param attrib: The name of the affected stanza interface.
 | 
					        :param attrib: The name of the affected stanza interface.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        full_attrib = attrib
 | 
				
			||||||
 | 
					        attrib_lang = ('%s|' % attrib).split('|')
 | 
				
			||||||
 | 
					        attrib = attrib_lang[0]
 | 
				
			||||||
 | 
					        lang = attrib_lang[1] or ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        kwargs = {}
 | 
				
			||||||
 | 
					        if lang and attrib in self.lang_interfaces:
 | 
				
			||||||
 | 
					            kwargs['lang'] = lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if attrib in self.interfaces:
 | 
					        if attrib in self.interfaces:
 | 
				
			||||||
            del_method = "del_%s" % attrib.lower()
 | 
					            del_method = "del_%s" % attrib.lower()
 | 
				
			||||||
            del_method2 = "del%s" % attrib.title()
 | 
					            del_method2 = "del%s" % attrib.title()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if self.plugin_overrides:
 | 
					            if self.plugin_overrides:
 | 
				
			||||||
                plugin = self.plugin_overrides.get(del_method, None)
 | 
					                name = self.plugin_overrides.get(del_method, None)
 | 
				
			||||||
                if plugin:
 | 
					                if name:
 | 
				
			||||||
                    if plugin not in self.plugins:
 | 
					                    plugin = self._get_plugin(attrib, lang)
 | 
				
			||||||
                        self.init_plugin(plugin)
 | 
					                    if plugin:
 | 
				
			||||||
                    handler = getattr(self.plugins[plugin], del_method, None)
 | 
					                        handler = getattr(plugin, del_method, None)
 | 
				
			||||||
                    if handler:
 | 
					                        if handler:
 | 
				
			||||||
                        return handler()
 | 
					                            return handler(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if hasattr(self, del_method):
 | 
					            if hasattr(self, del_method):
 | 
				
			||||||
                getattr(self, del_method)()
 | 
					                getattr(self, del_method)(**kwargs)
 | 
				
			||||||
            elif hasattr(self, del_method2):
 | 
					            elif hasattr(self, del_method2):
 | 
				
			||||||
                getattr(self, del_method2)()
 | 
					                getattr(self, del_method2)(**kwargs)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                if attrib in self.sub_interfaces:
 | 
					                if attrib in self.sub_interfaces:
 | 
				
			||||||
                    return self._del_sub(attrib)
 | 
					                    return self._del_sub(attrib, lang=lang)
 | 
				
			||||||
                elif attrib in self.bool_interfaces:
 | 
					                elif attrib in self.bool_interfaces:
 | 
				
			||||||
                    return self._del_sub(attrib)
 | 
					                    return self._del_sub(attrib, lang=lang)
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    self._del_attr(attrib)
 | 
					                    self._del_attr(attrib)
 | 
				
			||||||
        elif attrib in self.plugin_attrib_map:
 | 
					        elif attrib in self.plugin_attrib_map:
 | 
				
			||||||
            if attrib in self.plugins:
 | 
					            plugin = self._get_plugin(attrib, lang)
 | 
				
			||||||
                xml = self.plugins[attrib].xml
 | 
					            if not plugin:
 | 
				
			||||||
                if self.plugins[attrib].is_extension:
 | 
					                return self
 | 
				
			||||||
                    del self.plugins[attrib][attrib]
 | 
					            if plugin.is_extension:
 | 
				
			||||||
                del self.plugins[attrib]
 | 
					                del plugin[full_attrib]
 | 
				
			||||||
                try:
 | 
					                del self.plugins[(attrib, None)]
 | 
				
			||||||
                    self.xml.remove(xml)
 | 
					            else:
 | 
				
			||||||
                except:
 | 
					                del self.plugins[(attrib, lang)]
 | 
				
			||||||
                    pass
 | 
					            self.loaded_plugins.remove(attrib)
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                self.xml.remove(plugin.xml)
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _set_attr(self, name, value):
 | 
					    def _set_attr(self, name, value):
 | 
				
			||||||
@@ -781,7 +914,7 @@ class ElementBase(object):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        return self.xml.attrib.get(name, default)
 | 
					        return self.xml.attrib.get(name, default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _get_sub_text(self, name, default=''):
 | 
					    def _get_sub_text(self, name, default='', lang=None):
 | 
				
			||||||
        """Return the text contents of a sub element.
 | 
					        """Return the text contents of a sub element.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        In case the element does not exist, or it has no textual content,
 | 
					        In case the element does not exist, or it has no textual content,
 | 
				
			||||||
@@ -793,13 +926,38 @@ class ElementBase(object):
 | 
				
			|||||||
                        not exists. An empty string is returned otherwise.
 | 
					                        not exists. An empty string is returned otherwise.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        name = self._fix_ns(name)
 | 
					        name = self._fix_ns(name)
 | 
				
			||||||
        stanza = self.xml.find(name)
 | 
					        if lang == '*':
 | 
				
			||||||
        if stanza is None or stanza.text is None:
 | 
					            return self._get_all_sub_text(name, default, None)
 | 
				
			||||||
            return default
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return stanza.text
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _set_sub_text(self, name, text=None, keep=False):
 | 
					        default_lang = self.get_lang()
 | 
				
			||||||
 | 
					        if not lang:
 | 
				
			||||||
 | 
					            lang = default_lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stanzas = self.xml.findall(name)
 | 
				
			||||||
 | 
					        if not stanzas:
 | 
				
			||||||
 | 
					            return default
 | 
				
			||||||
 | 
					        for stanza in stanzas:
 | 
				
			||||||
 | 
					            if stanza.attrib.get('{%s}lang' % XML_NS, default_lang) == lang:
 | 
				
			||||||
 | 
					                if stanza.text is None:
 | 
				
			||||||
 | 
					                    return default
 | 
				
			||||||
 | 
					                return stanza.text
 | 
				
			||||||
 | 
					        return default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_all_sub_text(self, name, default='', lang=None):
 | 
				
			||||||
 | 
					        name = self._fix_ns(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default_lang = self.get_lang()
 | 
				
			||||||
 | 
					        results = OrderedDict()
 | 
				
			||||||
 | 
					        stanzas = self.xml.findall(name)
 | 
				
			||||||
 | 
					        if stanzas:
 | 
				
			||||||
 | 
					            for stanza in stanzas:
 | 
				
			||||||
 | 
					                stanza_lang = stanza.attrib.get('{%s}lang' % XML_NS,
 | 
				
			||||||
 | 
					                                                default_lang)
 | 
				
			||||||
 | 
					                if not lang or lang == '*' or stanza_lang == lang:
 | 
				
			||||||
 | 
					                    results[stanza_lang] = stanza.text
 | 
				
			||||||
 | 
					        return results
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _set_sub_text(self, name, text=None, keep=False, lang=None):
 | 
				
			||||||
        """Set the text contents of a sub element.
 | 
					        """Set the text contents of a sub element.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        In case the element does not exist, a element will be created,
 | 
					        In case the element does not exist, a element will be created,
 | 
				
			||||||
@@ -817,9 +975,14 @@ class ElementBase(object):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        path = self._fix_ns(name, split=True)
 | 
					        path = self._fix_ns(name, split=True)
 | 
				
			||||||
        element = self.xml.find(name)
 | 
					        element = self.xml.find(name)
 | 
				
			||||||
 | 
					        parent = self.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default_lang = self.get_lang()
 | 
				
			||||||
 | 
					        if lang is None:
 | 
				
			||||||
 | 
					            lang = default_lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not text and not keep:
 | 
					        if not text and not keep:
 | 
				
			||||||
            return self._del_sub(name)
 | 
					            return self._del_sub(name, lang=lang)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if element is None:
 | 
					        if element is None:
 | 
				
			||||||
            # We need to add the element. If the provided name was
 | 
					            # We need to add the element. If the provided name was
 | 
				
			||||||
@@ -833,14 +996,31 @@ class ElementBase(object):
 | 
				
			|||||||
                element = self.xml.find("/".join(walked))
 | 
					                element = self.xml.find("/".join(walked))
 | 
				
			||||||
                if element is None:
 | 
					                if element is None:
 | 
				
			||||||
                    element = ET.Element(ename)
 | 
					                    element = ET.Element(ename)
 | 
				
			||||||
 | 
					                    if lang:
 | 
				
			||||||
 | 
					                        element.attrib['{%s}lang' % XML_NS] = lang
 | 
				
			||||||
                    last_xml.append(element)
 | 
					                    last_xml.append(element)
 | 
				
			||||||
 | 
					                parent = last_xml
 | 
				
			||||||
                last_xml = element
 | 
					                last_xml = element
 | 
				
			||||||
            element = last_xml
 | 
					            element = last_xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if element.attrib.get('{%s}lang' % XML_NS, default_lang) != lang:
 | 
				
			||||||
 | 
					            element = ET.Element(ename)
 | 
				
			||||||
 | 
					            if lang:
 | 
				
			||||||
 | 
					                element.attrib['{%s}lang' % XML_NS] = lang
 | 
				
			||||||
 | 
					            parent.append(element)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        element.text = text
 | 
					        element.text = text
 | 
				
			||||||
        return element
 | 
					        return element
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _del_sub(self, name, all=False):
 | 
					    def _set_all_sub_text(self, name, values, keep=False, lang=None):
 | 
				
			||||||
 | 
					        self._del_sub(name, lang)
 | 
				
			||||||
 | 
					        for value_lang, value in values.items():
 | 
				
			||||||
 | 
					            if not lang or lang == '*' or value_lang == lang:
 | 
				
			||||||
 | 
					                self._set_sub_text(name, text=value,
 | 
				
			||||||
 | 
					                                         keep=keep,
 | 
				
			||||||
 | 
					                                         lang=value_lang)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _del_sub(self, name, all=False, lang=None):
 | 
				
			||||||
        """Remove sub elements that match the given name or XPath.
 | 
					        """Remove sub elements that match the given name or XPath.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        If the element is in a path, then any parent elements that become
 | 
					        If the element is in a path, then any parent elements that become
 | 
				
			||||||
@@ -854,6 +1034,10 @@ class ElementBase(object):
 | 
				
			|||||||
        path = self._fix_ns(name, split=True)
 | 
					        path = self._fix_ns(name, split=True)
 | 
				
			||||||
        original_target = path[-1]
 | 
					        original_target = path[-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default_lang = self.get_lang()
 | 
				
			||||||
 | 
					        if not lang:
 | 
				
			||||||
 | 
					            lang = default_lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for level, _ in enumerate(path):
 | 
					        for level, _ in enumerate(path):
 | 
				
			||||||
            # Generate the paths to the target elements and their parent.
 | 
					            # Generate the paths to the target elements and their parent.
 | 
				
			||||||
            element_path = "/".join(path[:len(path) - level])
 | 
					            element_path = "/".join(path[:len(path) - level])
 | 
				
			||||||
@@ -866,11 +1050,13 @@ class ElementBase(object):
 | 
				
			|||||||
                if parent is None:
 | 
					                if parent is None:
 | 
				
			||||||
                    parent = self.xml
 | 
					                    parent = self.xml
 | 
				
			||||||
                for element in elements:
 | 
					                for element in elements:
 | 
				
			||||||
                    if element.tag == original_target or \
 | 
					                    if element.tag == original_target or not list(element):
 | 
				
			||||||
                        not element.getchildren():
 | 
					 | 
				
			||||||
                        # Only delete the originally requested elements, and
 | 
					                        # Only delete the originally requested elements, and
 | 
				
			||||||
                        # any parent elements that have become empty.
 | 
					                        # any parent elements that have become empty.
 | 
				
			||||||
                        parent.remove(element)
 | 
					                        elem_lang = element.attrib.get('{%s}lang' % XML_NS,
 | 
				
			||||||
 | 
					                                                       default_lang)
 | 
				
			||||||
 | 
					                        if lang == '*' or elem_lang == lang:
 | 
				
			||||||
 | 
					                            parent.remove(element)
 | 
				
			||||||
            if not all:
 | 
					            if not all:
 | 
				
			||||||
                # If we don't want to delete elements up the tree, stop
 | 
					                # If we don't want to delete elements up the tree, stop
 | 
				
			||||||
                # after deleting the first level of elements.
 | 
					                # after deleting the first level of elements.
 | 
				
			||||||
@@ -903,7 +1089,7 @@ class ElementBase(object):
 | 
				
			|||||||
        attributes = components[1:]
 | 
					        attributes = components[1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if tag not in (self.name, "{%s}%s" % (self.namespace, self.name)) and \
 | 
					        if tag not in (self.name, "{%s}%s" % (self.namespace, self.name)) and \
 | 
				
			||||||
            tag not in self.plugins and tag not in self.plugin_attrib:
 | 
					            tag not in self.loaded_plugins and tag not in self.plugin_attrib:
 | 
				
			||||||
            # The requested tag is not in this stanza, so no match.
 | 
					            # The requested tag is not in this stanza, so no match.
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -932,10 +1118,12 @@ class ElementBase(object):
 | 
				
			|||||||
        if not matched_substanzas and len(xpath) > 1:
 | 
					        if not matched_substanzas and len(xpath) > 1:
 | 
				
			||||||
            # Convert {namespace}tag@attribs to just tag
 | 
					            # Convert {namespace}tag@attribs to just tag
 | 
				
			||||||
            next_tag = xpath[1].split('@')[0].split('}')[-1]
 | 
					            next_tag = xpath[1].split('@')[0].split('}')[-1]
 | 
				
			||||||
            if next_tag in self.plugins:
 | 
					            langs = [name[1] for name in self.plugins if name[0] == next_tag]
 | 
				
			||||||
                return self.plugins[next_tag].match(xpath[1:])
 | 
					            for lang in langs:
 | 
				
			||||||
            else:
 | 
					                plugin = self._get_plugin(next_tag, lang)
 | 
				
			||||||
                return False
 | 
					                if plugin and plugin.match(xpath[1:]):
 | 
				
			||||||
 | 
					                    return True
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Everything matched.
 | 
					        # Everything matched.
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
@@ -995,7 +1183,7 @@ class ElementBase(object):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        out = []
 | 
					        out = []
 | 
				
			||||||
        out += [x for x in self.interfaces]
 | 
					        out += [x for x in self.interfaces]
 | 
				
			||||||
        out += [x for x in self.plugins]
 | 
					        out += [x for x in self.loaded_plugins]
 | 
				
			||||||
        if self.iterables:
 | 
					        if self.iterables:
 | 
				
			||||||
            out.append('substanzas')
 | 
					            out.append('substanzas')
 | 
				
			||||||
        return out
 | 
					        return out
 | 
				
			||||||
@@ -1075,6 +1263,23 @@ class ElementBase(object):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        return "{%s}%s" % (cls.namespace, cls.name)
 | 
					        return "{%s}%s" % (cls.namespace, cls.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_lang(self):
 | 
				
			||||||
 | 
					        result = self.xml.attrib.get('{%s}lang' % XML_NS, '')
 | 
				
			||||||
 | 
					        if not result and self.parent and self.parent():
 | 
				
			||||||
 | 
					            return self.parent()['lang']
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_lang(self, lang):
 | 
				
			||||||
 | 
					        self.del_lang()
 | 
				
			||||||
 | 
					        attr = '{%s}lang' % XML_NS
 | 
				
			||||||
 | 
					        if lang:
 | 
				
			||||||
 | 
					            self.xml.attrib[attr] = lang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def del_lang(self):
 | 
				
			||||||
 | 
					        attr = '{%s}lang' % XML_NS
 | 
				
			||||||
 | 
					        if attr in self.xml.attrib:
 | 
				
			||||||
 | 
					            del self.xml.attrib[attr]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def attrib(self):
 | 
					    def attrib(self):
 | 
				
			||||||
        """Return the stanza object itself.
 | 
					        """Return the stanza object itself.
 | 
				
			||||||
@@ -1219,6 +1424,8 @@ class StanzaBase(ElementBase):
 | 
				
			|||||||
    :param sfrom: Optional string or :class:`sleekxmpp.xmlstream.JID`
 | 
					    :param sfrom: Optional string or :class:`sleekxmpp.xmlstream.JID`
 | 
				
			||||||
                  object of the sender's JID.
 | 
					                  object of the sender's JID.
 | 
				
			||||||
    :param string sid: Optional ID value for the stanza.
 | 
					    :param string sid: Optional ID value for the stanza.
 | 
				
			||||||
 | 
					    :param parent: Optionally specify a parent stanza object will
 | 
				
			||||||
 | 
					                   contain this substanza.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #: The default XMPP client namespace
 | 
					    #: The default XMPP client namespace
 | 
				
			||||||
@@ -1233,11 +1440,11 @@ class StanzaBase(ElementBase):
 | 
				
			|||||||
    types = set(('get', 'set', 'error', None, 'unavailable', 'normal', 'chat'))
 | 
					    types = set(('get', 'set', 'error', None, 'unavailable', 'normal', 'chat'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, stream=None, xml=None, stype=None,
 | 
					    def __init__(self, stream=None, xml=None, stype=None,
 | 
				
			||||||
                 sto=None, sfrom=None, sid=None):
 | 
					                 sto=None, sfrom=None, sid=None, parent=None):
 | 
				
			||||||
        self.stream = stream
 | 
					        self.stream = stream
 | 
				
			||||||
        if stream is not None:
 | 
					        if stream is not None:
 | 
				
			||||||
            self.namespace = stream.default_ns
 | 
					            self.namespace = stream.default_ns
 | 
				
			||||||
        ElementBase.__init__(self, xml)
 | 
					        ElementBase.__init__(self, xml, parent)
 | 
				
			||||||
        if stype is not None:
 | 
					        if stype is not None:
 | 
				
			||||||
            self['type'] = stype
 | 
					            self['type'] = stype
 | 
				
			||||||
        if sto is not None:
 | 
					        if sto is not None:
 | 
				
			||||||
@@ -1285,7 +1492,7 @@ class StanzaBase(ElementBase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_payload(self):
 | 
					    def get_payload(self):
 | 
				
			||||||
        """Return a list of XML objects contained in the stanza."""
 | 
					        """Return a list of XML objects contained in the stanza."""
 | 
				
			||||||
        return self.xml.getchildren()
 | 
					        return list(self.xml)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_payload(self, value):
 | 
					    def set_payload(self, value):
 | 
				
			||||||
        """Add XML content to the stanza.
 | 
					        """Add XML content to the stanza.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,14 +13,19 @@
 | 
				
			|||||||
    :license: MIT, see LICENSE for more details
 | 
					    :license: MIT, see LICENSE for more details
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if sys.version_info < (3, 0):
 | 
					if sys.version_info < (3, 0):
 | 
				
			||||||
    import types
 | 
					    import types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					XML_NS = 'http://www.w3.org/XML/1998/namespace'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def tostring(xml=None, xmlns='', stanza_ns='', stream=None,
 | 
					def tostring(xml=None, xmlns='', stanza_ns='', stream=None,
 | 
				
			||||||
             outbuffer='', top_level=False):
 | 
					             outbuffer='', top_level=False, open_only=False):
 | 
				
			||||||
    """Serialize an XML object to a Unicode string.
 | 
					    """Serialize an XML object to a Unicode string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    If namespaces are provided using ``xmlns`` or ``stanza_ns``, then
 | 
					    If namespaces are provided using ``xmlns`` or ``stanza_ns``, then
 | 
				
			||||||
@@ -88,6 +93,13 @@ def tostring(xml=None, xmlns='', stanza_ns='', stream=None,
 | 
				
			|||||||
                    output.append(' %s:%s="%s"' % (mapped_ns,
 | 
					                    output.append(' %s:%s="%s"' % (mapped_ns,
 | 
				
			||||||
                                                   attrib,
 | 
					                                                   attrib,
 | 
				
			||||||
                                                   value))
 | 
					                                                   value))
 | 
				
			||||||
 | 
					            elif attrib_ns == XML_NS:
 | 
				
			||||||
 | 
					                output.append(' xml:%s="%s"' % (attrib, value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if open_only:
 | 
				
			||||||
 | 
					        # Only output the opening tag, regardless of content.
 | 
				
			||||||
 | 
					        output.append(">")
 | 
				
			||||||
 | 
					        return ''.join(output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if len(xml) or xml.text:
 | 
					    if len(xml) or xml.text:
 | 
				
			||||||
        # If there are additional child elements to serialize.
 | 
					        # If there are additional child elements to serialize.
 | 
				
			||||||
@@ -95,7 +107,7 @@ def tostring(xml=None, xmlns='', stanza_ns='', stream=None,
 | 
				
			|||||||
        if xml.text:
 | 
					        if xml.text:
 | 
				
			||||||
            output.append(xml_escape(xml.text))
 | 
					            output.append(xml_escape(xml.text))
 | 
				
			||||||
        if len(xml):
 | 
					        if len(xml):
 | 
				
			||||||
            for child in xml.getchildren():
 | 
					            for child in xml:
 | 
				
			||||||
                output.append(tostring(child, tag_xmlns, stanza_ns, stream))
 | 
					                output.append(tostring(child, tag_xmlns, stanza_ns, stream))
 | 
				
			||||||
        output.append("</%s>" % tag_name)
 | 
					        output.append("</%s>" % tag_name)
 | 
				
			||||||
    elif xml.text:
 | 
					    elif xml.text:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -223,6 +223,9 @@ class XMLStream(object):
 | 
				
			|||||||
        #: stream wrapper itself.
 | 
					        #: stream wrapper itself.
 | 
				
			||||||
        self.default_ns = ''
 | 
					        self.default_ns = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.default_lang = None
 | 
				
			||||||
 | 
					        self.peer_default_lang = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #: The namespace of the enveloping stream element.
 | 
					        #: The namespace of the enveloping stream element.
 | 
				
			||||||
        self.stream_ns = ''
 | 
					        self.stream_ns = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -414,12 +417,12 @@ class XMLStream(object):
 | 
				
			|||||||
        if use_tls is not None:
 | 
					        if use_tls is not None:
 | 
				
			||||||
            self.use_tls = use_tls
 | 
					            self.use_tls = use_tls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Repeatedly attempt to connect until a successful connection
 | 
					        # Repeatedly attempt to connect until a successful connection
 | 
				
			||||||
        # is established.
 | 
					        # is established.
 | 
				
			||||||
        attempts = self.reconnect_max_attempts
 | 
					        attempts = self.reconnect_max_attempts
 | 
				
			||||||
        connected = self.state.transition('disconnected', 'connected',
 | 
					        connected = self.state.transition('disconnected', 'connected',
 | 
				
			||||||
                                          func=self._connect, args=(reattempt,))
 | 
					                                          func=self._connect,
 | 
				
			||||||
 | 
					                                          args=(reattempt,))
 | 
				
			||||||
        while reattempt and not connected and not self.stop.is_set():
 | 
					        while reattempt and not connected and not self.stop.is_set():
 | 
				
			||||||
            connected = self.state.transition('disconnected', 'connected',
 | 
					            connected = self.state.transition('disconnected', 'connected',
 | 
				
			||||||
                                              func=self._connect)
 | 
					                                              func=self._connect)
 | 
				
			||||||
@@ -517,7 +520,8 @@ class XMLStream(object):
 | 
				
			|||||||
                    except (Socket.error, ssl.SSLError):
 | 
					                    except (Socket.error, ssl.SSLError):
 | 
				
			||||||
                        log.error('CERT: Invalid certificate trust chain.')
 | 
					                        log.error('CERT: Invalid certificate trust chain.')
 | 
				
			||||||
                        if not self.event_handled('ssl_invalid_chain'):
 | 
					                        if not self.event_handled('ssl_invalid_chain'):
 | 
				
			||||||
                            self.disconnect(self.auto_reconnect, send_close=False)
 | 
					                            self.disconnect(self.auto_reconnect,
 | 
				
			||||||
 | 
					                                            send_close=False)
 | 
				
			||||||
                        else:
 | 
					                        else:
 | 
				
			||||||
                            self.event('ssl_invalid_chain', direct=True)
 | 
					                            self.event('ssl_invalid_chain', direct=True)
 | 
				
			||||||
                        return False
 | 
					                        return False
 | 
				
			||||||
@@ -534,7 +538,9 @@ class XMLStream(object):
 | 
				
			|||||||
                        if not self.event_handled('ssl_invalid_cert'):
 | 
					                        if not self.event_handled('ssl_invalid_cert'):
 | 
				
			||||||
                            self.disconnect(send_close=False)
 | 
					                            self.disconnect(send_close=False)
 | 
				
			||||||
                        else:
 | 
					                        else:
 | 
				
			||||||
                            self.event('ssl_invalid_cert', cert, direct=True)
 | 
					                            self.event('ssl_invalid_cert',
 | 
				
			||||||
 | 
					                                       pem_cert,
 | 
				
			||||||
 | 
					                                       direct=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.set_socket(self.socket, ignore=True)
 | 
					            self.set_socket(self.socket, ignore=True)
 | 
				
			||||||
            #this event is where you should set your application state
 | 
					            #this event is where you should set your application state
 | 
				
			||||||
@@ -711,7 +717,9 @@ class XMLStream(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        log.debug("connecting...")
 | 
					        log.debug("connecting...")
 | 
				
			||||||
        connected = self.state.transition('disconnected', 'connected',
 | 
					        connected = self.state.transition('disconnected', 'connected',
 | 
				
			||||||
                                          wait=2.0, func=self._connect, args=(reattempt,))
 | 
					                                          wait=2.0,
 | 
				
			||||||
 | 
					                                          func=self._connect,
 | 
				
			||||||
 | 
					                                          args=(reattempt,))
 | 
				
			||||||
        while reattempt and not connected and not self.stop.is_set():
 | 
					        while reattempt and not connected and not self.stop.is_set():
 | 
				
			||||||
            connected = self.state.transition('disconnected', 'connected',
 | 
					            connected = self.state.transition('disconnected', 'connected',
 | 
				
			||||||
                                              wait=2.0, func=self._connect)
 | 
					                                              wait=2.0, func=self._connect)
 | 
				
			||||||
@@ -821,7 +829,7 @@ class XMLStream(object):
 | 
				
			|||||||
                if not self.event_handled('ssl_invalid_cert'):
 | 
					                if not self.event_handled('ssl_invalid_cert'):
 | 
				
			||||||
                    self.disconnect(self.auto_reconnect, send_close=False)
 | 
					                    self.disconnect(self.auto_reconnect, send_close=False)
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    self.event('ssl_invalid_cert', cert, direct=True)
 | 
					                    self.event('ssl_invalid_cert', pem_cert, direct=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.set_socket(self.socket)
 | 
					            self.set_socket(self.socket)
 | 
				
			||||||
            return True
 | 
					            return True
 | 
				
			||||||
@@ -874,8 +882,8 @@ class XMLStream(object):
 | 
				
			|||||||
        self.schedule('Whitespace Keepalive',
 | 
					        self.schedule('Whitespace Keepalive',
 | 
				
			||||||
                      self.whitespace_keepalive_interval,
 | 
					                      self.whitespace_keepalive_interval,
 | 
				
			||||||
                      self.send_raw,
 | 
					                      self.send_raw,
 | 
				
			||||||
                      args = (' ',),
 | 
					                      args=(' ',),
 | 
				
			||||||
                      kwargs = {'now': True},
 | 
					                      kwargs={'now': True},
 | 
				
			||||||
                      repeat=True)
 | 
					                      repeat=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _remove_schedules(self, event):
 | 
					    def _remove_schedules(self, event):
 | 
				
			||||||
@@ -976,8 +984,9 @@ class XMLStream(object):
 | 
				
			|||||||
        """Add a stream event handler that will be executed when a matching
 | 
					        """Add a stream event handler that will be executed when a matching
 | 
				
			||||||
        stanza is received.
 | 
					        stanza is received.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :param handler: The :class:`~sleekxmpp.xmlstream.handler.base.BaseHandler`
 | 
					        :param handler:
 | 
				
			||||||
                        derived object to execute.
 | 
					                The :class:`~sleekxmpp.xmlstream.handler.base.BaseHandler`
 | 
				
			||||||
 | 
					                derived object to execute.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if handler.stream is None:
 | 
					        if handler.stream is None:
 | 
				
			||||||
            self.__handlers.append(handler)
 | 
					            self.__handlers.append(handler)
 | 
				
			||||||
@@ -1008,7 +1017,9 @@ class XMLStream(object):
 | 
				
			|||||||
        resolver = default_resolver()
 | 
					        resolver = default_resolver()
 | 
				
			||||||
        self.configure_dns(resolver, domain=domain, port=port)
 | 
					        self.configure_dns(resolver, domain=domain, port=port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return resolve(domain, port, service=self.dns_service, resolver=resolver)
 | 
					        return resolve(domain, port, service=self.dns_service,
 | 
				
			||||||
 | 
					                                     resolver=resolver,
 | 
				
			||||||
 | 
					                                     use_ipv6=self.use_ipv6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def pick_dns_answer(self, domain, port=None):
 | 
					    def pick_dns_answer(self, domain, port=None):
 | 
				
			||||||
        """Pick a server and port from DNS answers.
 | 
					        """Pick a server and port from DNS answers.
 | 
				
			||||||
@@ -1237,14 +1248,15 @@ class XMLStream(object):
 | 
				
			|||||||
                            count += 1
 | 
					                            count += 1
 | 
				
			||||||
                        except ssl.SSLError as serr:
 | 
					                        except ssl.SSLError as serr:
 | 
				
			||||||
                            if tries >= self.ssl_retry_max:
 | 
					                            if tries >= self.ssl_retry_max:
 | 
				
			||||||
                                log.debug('SSL error - max retries reached')
 | 
					                                log.debug('SSL error: max retries reached')
 | 
				
			||||||
                                self.exception(serr)
 | 
					                                self.exception(serr)
 | 
				
			||||||
                                log.warning("Failed to send %s", data)
 | 
					                                log.warning("Failed to send %s", data)
 | 
				
			||||||
                                if reconnect is None:
 | 
					                                if reconnect is None:
 | 
				
			||||||
                                    reconnect = self.auto_reconnect
 | 
					                                    reconnect = self.auto_reconnect
 | 
				
			||||||
                                if not self.stop.is_set():
 | 
					                                if not self.stop.is_set():
 | 
				
			||||||
                                    self.disconnect(reconnect, send_close=False)
 | 
					                                    self.disconnect(reconnect,
 | 
				
			||||||
                            log.warning('SSL write error - reattempting')
 | 
					                                                    send_close=False)
 | 
				
			||||||
 | 
					                                log.warning('SSL write error: retrying')
 | 
				
			||||||
                            if not self.stop.is_set():
 | 
					                            if not self.stop.is_set():
 | 
				
			||||||
                                time.sleep(self.ssl_retry_delay)
 | 
					                                time.sleep(self.ssl_retry_delay)
 | 
				
			||||||
                            tries += 1
 | 
					                            tries += 1
 | 
				
			||||||
@@ -1431,6 +1443,10 @@ class XMLStream(object):
 | 
				
			|||||||
                if depth == 0:
 | 
					                if depth == 0:
 | 
				
			||||||
                    # We have received the start of the root element.
 | 
					                    # We have received the start of the root element.
 | 
				
			||||||
                    root = xml
 | 
					                    root = xml
 | 
				
			||||||
 | 
					                    log.debug('RECV: %s', tostring(root, xmlns=self.default_ns,
 | 
				
			||||||
 | 
					                                                         stream=self,
 | 
				
			||||||
 | 
					                                                         top_level=True,
 | 
				
			||||||
 | 
					                                                         open_only=True))
 | 
				
			||||||
                    # Perform any stream initialization actions, such
 | 
					                    # Perform any stream initialization actions, such
 | 
				
			||||||
                    # as handshakes.
 | 
					                    # as handshakes.
 | 
				
			||||||
                    self.stream_end_event.clear()
 | 
					                    self.stream_end_event.clear()
 | 
				
			||||||
@@ -1478,6 +1494,8 @@ class XMLStream(object):
 | 
				
			|||||||
                stanza_type = stanza_class
 | 
					                stanza_type = stanza_class
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
        stanza = stanza_type(self, xml)
 | 
					        stanza = stanza_type(self, xml)
 | 
				
			||||||
 | 
					        if stanza['lang'] is None and self.peer_default_lang:
 | 
				
			||||||
 | 
					            stanza['lang'] = self.peer_default_lang
 | 
				
			||||||
        return stanza
 | 
					        return stanza
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __spawn_event(self, xml):
 | 
					    def __spawn_event(self, xml):
 | 
				
			||||||
@@ -1647,12 +1665,13 @@ class XMLStream(object):
 | 
				
			|||||||
                                count += 1
 | 
					                                count += 1
 | 
				
			||||||
                            except ssl.SSLError as serr:
 | 
					                            except ssl.SSLError as serr:
 | 
				
			||||||
                                if tries >= self.ssl_retry_max:
 | 
					                                if tries >= self.ssl_retry_max:
 | 
				
			||||||
                                    log.debug('SSL error - max retries reached')
 | 
					                                    log.debug('SSL error: max retries reached')
 | 
				
			||||||
                                    self.exception(serr)
 | 
					                                    self.exception(serr)
 | 
				
			||||||
                                    log.warning("Failed to send %s", data)
 | 
					                                    log.warning("Failed to send %s", data)
 | 
				
			||||||
                                    if not self.stop.is_set():
 | 
					                                    if not self.stop.is_set():
 | 
				
			||||||
                                        self.disconnect(self.auto_reconnect, send_close=False)
 | 
					                                        self.disconnect(self.auto_reconnect,
 | 
				
			||||||
                                log.warning('SSL write error - reattempting')
 | 
					                                                        send_close=False)
 | 
				
			||||||
 | 
					                                    log.warning('SSL write error: retrying')
 | 
				
			||||||
                                if not self.stop.is_set():
 | 
					                                if not self.stop.is_set():
 | 
				
			||||||
                                    time.sleep(self.ssl_retry_delay)
 | 
					                                    time.sleep(self.ssl_retry_delay)
 | 
				
			||||||
                                tries += 1
 | 
					                                tries += 1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,14 +64,18 @@ class TestElementBase(SleekTest):
 | 
				
			|||||||
        stanza.append(substanza)
 | 
					        stanza.append(substanza)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        values = stanza.getStanzaValues()
 | 
					        values = stanza.getStanzaValues()
 | 
				
			||||||
        expected = {'bar': 'a',
 | 
					        expected = {'lang': '',
 | 
				
			||||||
 | 
					                    'bar': 'a',
 | 
				
			||||||
                    'baz': '',
 | 
					                    'baz': '',
 | 
				
			||||||
                    'foo2': {'bar': '',
 | 
					                    'foo2': {'lang': '',
 | 
				
			||||||
 | 
					                             'bar': '',
 | 
				
			||||||
                             'baz': 'b'},
 | 
					                             'baz': 'b'},
 | 
				
			||||||
                    'substanzas': [{'__childtag__': '{foo}foo2',
 | 
					                    'substanzas': [{'__childtag__': '{foo}foo2',
 | 
				
			||||||
 | 
					                                    'lang': '',
 | 
				
			||||||
                                    'bar': '',
 | 
					                                    'bar': '',
 | 
				
			||||||
                                    'baz': 'b'},
 | 
					                                    'baz': 'b'},
 | 
				
			||||||
                                   {'__childtag__': '{foo}subfoo',
 | 
					                                   {'__childtag__': '{foo}subfoo',
 | 
				
			||||||
 | 
					                                    'lang': '',
 | 
				
			||||||
                                    'bar': 'c',
 | 
					                                    'bar': 'c',
 | 
				
			||||||
                                    'baz': ''}]}
 | 
					                                    'baz': ''}]}
 | 
				
			||||||
        self.failUnless(values == expected,
 | 
					        self.failUnless(values == expected,
 | 
				
			||||||
@@ -555,12 +559,12 @@ class TestElementBase(SleekTest):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        stanza = TestStanza()
 | 
					        stanza = TestStanza()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.failUnless(set(stanza.keys()) == set(('bar', 'baz')),
 | 
					        self.failUnless(set(stanza.keys()) == set(('lang', 'bar', 'baz')),
 | 
				
			||||||
            "Returned set of interface keys does not match expected.")
 | 
					            "Returned set of interface keys does not match expected.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        stanza.enable('qux')
 | 
					        stanza.enable('qux')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.failUnless(set(stanza.keys()) == set(('bar', 'baz', 'qux')),
 | 
					        self.failUnless(set(stanza.keys()) == set(('lang', 'bar', 'baz', 'qux')),
 | 
				
			||||||
            "Incorrect set of interface and plugin keys.")
 | 
					            "Incorrect set of interface and plugin keys.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def testGet(self):
 | 
					    def testGet(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,7 @@ class TestAdHocCommandStanzas(SleekTest):
 | 
				
			|||||||
        iq['command']['actions'] = ['prev', 'next']
 | 
					        iq['command']['actions'] = ['prev', 'next']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        results = iq['command']['actions']
 | 
					        results = iq['command']['actions']
 | 
				
			||||||
        expected = ['prev', 'next']
 | 
					        expected = set(['prev', 'next'])
 | 
				
			||||||
        self.assertEqual(results, expected,
 | 
					        self.assertEqual(results, expected,
 | 
				
			||||||
                         "Incorrect next actions: %s" % results)
 | 
					                         "Incorrect next actions: %s" % results)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user