diff options
Diffstat (limited to 'examples')
-rwxr-xr-x | examples/muc.py | 4 | ||||
-rw-r--r-- | examples/pubsub_client.py | 198 | ||||
-rw-r--r-- | examples/pubsub_events.py | 151 | ||||
-rw-r--r-- | examples/register_account.py | 175 | ||||
-rw-r--r-- | examples/thirdpary_auth.py | 247 | ||||
-rw-r--r-- | examples/user_location.py | 125 | ||||
-rw-r--r-- | examples/user_tune.py | 137 |
7 files changed, 1035 insertions, 2 deletions
diff --git a/examples/muc.py b/examples/muc.py index 8fe2eb49..7b93da16 100755 --- a/examples/muc.py +++ b/examples/muc.py @@ -76,8 +76,8 @@ class MUCBot(sleekxmpp.ClientXMPP): event does not provide any additional data. """ - self.getRoster() - self.sendPresence() + self.get_roster() + self.send_presence() self.plugin['xep_0045'].joinMUC(self.room, self.nick, # If a room password is needed, use: diff --git a/examples/pubsub_client.py b/examples/pubsub_client.py new file mode 100644 index 00000000..b0459c84 --- /dev/null +++ b/examples/pubsub_client.py @@ -0,0 +1,198 @@ +import sys +import logging +import getpass +from optparse import OptionParser + +import sleekxmpp +from sleekxmpp.xmlstream import ET, tostring + + +# 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 PubsubClient(sleekxmpp.ClientXMPP): + + def __init__(self, jid, password, server, + node=None, action='list', data=''): + super(PubsubClient, self).__init__(jid, password) + + self.register_plugin('xep_0030') + self.register_plugin('xep_0059') + self.register_plugin('xep_0060') + + self.actions = ['nodes', 'create', 'delete', + 'publish', 'get', 'retract', + 'purge', 'subscribe', 'unsubscribe'] + + self.action = action + self.node = node + self.data = data + self.pubsub_server = server + + self.add_event_handler('session_start', self.start) + + def start(self, event): + self.get_roster() + self.send_presence() + + try: + getattr(self, self.action)() + except: + logging.error('Could not execute: %s' % self.action) + self.disconnect() + + def nodes(self): + try: + result = self['xep_0060'].get_nodes(self.pubsub_server, self.node) + for item in result['disco_items']['items']: + print(' - %s' % str(item)) + except: + logging.error('Could not retrieve node list.') + + def create(self): + try: + self['xep_0060'].create_node(self.pubsub_server, self.node) + except: + logging.error('Could not create node: %s' % self.node) + + def delete(self): + try: + self['xep_0060'].delete_node(self.pubsub_server, self.node) + print('Deleted node: %s' % self.node) + except: + logging.error('Could not delete node: %s' % self.node) + + def publish(self): + payload = ET.fromstring("<test xmlns='test'>%s</test>" % self.data) + try: + result = self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload) + id = result['pubsub']['publish']['item']['id'] + print('Published at item id: %s' % id) + except: + logging.error('Could not publish to: %s' % self.node) + + def get(self): + try: + result = self['xep_0060'].get_item(self.pubsub_server, self.node, self.data) + for item in result['pubsub']['items']['substanzas']: + print('Retrieved item %s: %s' % (item['id'], tostring(item['payload']))) + except: + logging.error('Could not retrieve item %s from node %s' % (self.data, self.node)) + + def retract(self): + try: + result = self['xep_0060'].retract(self.pubsub_server, self.node, self.data) + print('Retracted item %s from node %s' % (self.data, self.node)) + except: + logging.error('Could not retract item %s from node %s' % (self.data, self.node)) + + def purge(self): + try: + result = self['xep_0060'].purge(self.pubsub_server, self.node) + print('Purged all items from node %s' % self.node) + except: + logging.error('Could not purge items from node %s' % self.node) + + def subscribe(self): + try: + result = self['xep_0060'].subscribe(self.pubsub_server, self.node) + print('Subscribed %s to node %s' % (self.boundjid.bare, self.node)) + except: + logging.error('Could not subscribe %s to node %s' % (self.boundjid.bare, self.node)) + + def unsubscribe(self): + try: + result = self['xep_0060'].unsubscribe(self.pubsub_server, self.node) + print('Unsubscribed %s from node %s' % (self.boundjid.bare, self.node)) + except: + logging.error('Could not unsubscribe %s from node %s' % (self.boundjid.bare, self.node)) + + + + +if __name__ == '__main__': + # Setup the command line arguments. + optp = OptionParser() + optp.version = '%%prog 0.1' + optp.usage = "Usage: %%prog [options] <jid> " + \ + 'nodes|create|delete|purge|subscribe|unsubscribe|publish|retract|get' + \ + ' [<node> <data>]' + + optp.add_option('-q','--quiet', help='set logging to ERROR', + action='store_const', + dest='loglevel', + const=logging.ERROR, + default=logging.ERROR) + optp.add_option('-d','--debug', help='set logging to DEBUG', + action='store_const', + dest='loglevel', + const=logging.DEBUG, + default=logging.ERROR) + optp.add_option('-v','--verbose', help='set logging to COMM', + action='store_const', + dest='loglevel', + const=5, + default=logging.ERROR) + + # 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 len(args) < 2: + optp.print_help() + exit() + + if opts.jid is None: + opts.jid = raw_input("Username: ") + if opts.password is None: + opts.password = getpass.getpass("Password: ") + + if len(args) == 2: + args = (args[0], args[1], '', '', '') + elif len(args) == 3: + args = (args[0], args[1], args[2], '', '') + elif len(args) == 4: + args = (args[0], args[1], args[2], args[3], '') + + + # Setup the Pubsub client + xmpp = PubsubClient(opts.jid, opts.password, + server=args[0], + node=args[2], + action=args[1], + data=args[3]) + + # 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) + else: + print("Unable to connect.") diff --git a/examples/pubsub_events.py b/examples/pubsub_events.py new file mode 100644 index 00000000..6fe7159b --- /dev/null +++ b/examples/pubsub_events.py @@ -0,0 +1,151 @@ +import sys +import logging +import getpass +from optparse import OptionParser + +import sleekxmpp +from sleekxmpp.xmlstream import ET, tostring +from sleekxmpp.xmlstream.matcher import StanzaPath +from sleekxmpp.xmlstream.handler import Callback + + +# 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 PubsubEvents(sleekxmpp.ClientXMPP): + + def __init__(self, jid, password): + super(PubsubEvents, self).__init__(jid, password) + + self.register_plugin('xep_0030') + self.register_plugin('xep_0059') + self.register_plugin('xep_0060') + + self.add_event_handler('session_start', self.start) + + # Some services may require configuration to allow + # sending delete, configuration, or subscription events. + self.add_event_handler('pubsub_publish', self._publish) + self.add_event_handler('pubsub_retract', self._retract) + self.add_event_handler('pubsub_purge', self._purge) + self.add_event_handler('pubsub_delete', self._delete) + self.add_event_handler('pubsub_config', self._config) + self.add_event_handler('pubsub_subscription', self._subscription) + + # Want to use nicer, more specific pubsub event names? + # self['xep_0060'].map_node_event('node_name', 'event_prefix') + # self.add_event_handler('event_prefix_publish', handler) + # self.add_event_handler('event_prefix_retract', handler) + # self.add_event_handler('event_prefix_purge', handler) + # self.add_event_handler('event_prefix_delete', handler) + + def start(self, event): + self.get_roster() + self.send_presence() + + def _publish(self, msg): + """Handle receiving a publish item event.""" + print('Published item %s to %s:' % ( + msg['pubsub_event']['items']['item']['id'], + msg['pubsub_event']['items']['node'])) + data = msg['pubsub_event']['items']['item']['payload'] + if data is not None: + print(tostring(data)) + else: + print('No item content') + + def _retract(self, msg): + """Handle receiving a retract item event.""" + print('Retracted item %s from %s' % ( + msg['pubsub_event']['items']['retract']['id'], + msg['pubsub_event']['items']['node'])) + + def _purge(self, msg): + """Handle receiving a node purge event.""" + print('Purged all items from %s' % ( + msg['pubsub_event']['purge']['node'])) + + def _delete(self, msg): + """Handle receiving a node deletion event.""" + print('Deleted node %s' % ( + msg['pubsub_event']['delete']['node'])) + + def _config(self, msg): + """Handle receiving a node configuration event.""" + print('Configured node %s:' % ( + msg['pubsub_event']['configuration']['node'])) + print(msg['pubsub_event']['configuration']['form']) + + def _subscription(self, msg): + """Handle receiving a node subscription event.""" + print('Subscription change for node %s:' % ( + msg['pubsub_event']['subscription']['node'])) + print(msg['pubsub_event']['subscription']) + + +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: ") + + logging.info("Run this in conjunction with the pubsub_client.py " + \ + "example to watch events happen as you give commands.") + + # Setup the PubsubEvents listener + xmpp = PubsubEvents(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.") diff --git a/examples/register_account.py b/examples/register_account.py new file mode 100644 index 00000000..17f075ab --- /dev/null +++ b/examples/register_account.py @@ -0,0 +1,175 @@ +#!/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 +from sleekxmpp.exceptions import IqError, IqTimeout + +# 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 RegisterBot(sleekxmpp.ClientXMPP): + + """ + A basic bot that will attempt to register an account + with an XMPP server. + + NOTE: This follows the very basic registration workflow + from XEP-0077. More advanced server registration + workflows will need to check for data forms, etc. + """ + + 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 register event provides an Iq result stanza with + # a registration form from the server. This may include + # the basic registration fields, a data form, an + # out-of-band URL, or any combination. For more advanced + # cases, you will need to examine the fields provided + # and respond accordingly. SleekXMPP provides plugins + # for data forms and OOB links that will make that easier. + self.add_event_handler("register", self.register) + + 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() + + # We're only concerned about registering, so nothing more to do here. + self.disconnect() + + def register(self, iq): + """ + Fill out and submit a registration form. + + The form may be composed of basic registration fields, a data form, + an out-of-band link, or any combination thereof. Data forms and OOB + links can be checked for as so: + + if iq.match('iq/register/form'): + # do stuff with data form + # iq['register']['form']['fields'] + if iq.match('iq/register/oob'): + # do stuff with OOB URL + # iq['register']['oob']['url'] + + To get the list of basic registration fields, you can use: + iq['register']['fields'] + """ + resp = self.Iq() + resp['type'] = 'set' + resp['register']['username'] = self.boundjid.user + resp['register']['password'] = self.password + + try: + resp.send(now=True) + logging.info("Account created for %s!" % self.boundjid) + except IqError as e: + logging.error("Could not register account: %s" % + e.iq['error']['text']) + self.disconnect() + except IqTimeout: + logging.error("No response from server.") + self.disconnect() + + +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 RegisterBot and register plugins. Note that while plugins may + # have interdependencies, the order in which you register them does + # not matter. + xmpp = RegisterBot(opts.jid, opts.password) + xmpp.register_plugin('xep_0030') # Service Discovery + xmpp.register_plugin('xep_0004') # Data forms + xmpp.register_plugin('xep_0066') # Out-of-band Data + xmpp.register_plugin('xep_0077') # In-band Registration + + # 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.") diff --git a/examples/thirdpary_auth.py b/examples/thirdpary_auth.py new file mode 100644 index 00000000..727311ae --- /dev/null +++ b/examples/thirdpary_auth.py @@ -0,0 +1,247 @@ +#!/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 + +try: + from httplib import HTTPSConnection + from urllib import urlencode +except ImportError: + from urllib.parse import urlencode + from http.client import HTTPSConnection + +import sleekxmpp +from sleekxmpp.xmlstream import JID + +# 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 ThirdPartyAuthBot(sleekxmpp.ClientXMPP): + + """ + A simple SleekXMPP bot that will echo messages it + receives, along with a short thank you message. + + This version uses a thirdpary service for authentication, + such as Facebook or Google. + """ + + def __init__(self, jid, password): + sleekxmpp.ClientXMPP.__init__(self, jid, password) + + # The X-GOOGLE-TOKEN mech is ranked lower than PLAIN + # due to Google only allowing a single SASL attempt per + # connection. So PLAIN will be used for TLS connections, + # and X-GOOGLE-TOKEN for non-TLS connections. To use + # X-GOOGLE-TOKEN with a TLS connection, explicitly select + # it using: + # + # sleekxmpp.ClientXMPP.__init__(self, jid, password, + # sasl_mech="X-GOOGLE-TOKEN") + + # The session_start event will be triggered when + # the bot establishes its connection with the server + # and the XML streams are ready for use. We want to + # listen for this event so that we we can initialize + # our roster. + self.add_event_handler("session_start", self.start) + + # The message event is triggered whenever a message + # stanza is received. Be aware that that includes + # MUC messages and error messages. + self.add_event_handler("message", self.message) + + def start(self, event): + """ + Process the session_start event. + + Typical actions for the session_start event are + requesting the roster and broadcasting an initial + presence stanza. + + Arguments: + event -- An empty dictionary. The session_start + event does not provide any additional + data. + """ + self.send_presence() + self.get_roster() + + def message(self, msg): + """ + Process incoming message stanzas. Be aware that this also + includes MUC messages and error messages. It is usually + a good idea to check the messages's type before processing + or sending replies. + + Arguments: + msg -- The received message stanza. See the documentation + for stanza objects and the Message stanza to see + how it may be used. + """ + 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: ") + + + access_token = None + + # Since documentation on how to work with Google tokens + # can be difficult to find, we'll demo a basic version + # here. Note that responses could refer to a Captcha + # URL that would require a browser. + + # Using Facebook or MSN's custom authentication requires + # a browser, but the process is the same once a token + # has been retrieved. + + # Request an access token from Google: + try: + conn = HTTPSConnection('www.google.com') + except: + print('Could not connect to Google') + sys.exit() + + params = urlencode({ + 'accountType': 'GOOGLE', + 'service': 'mail', + 'Email': JID(opts.jid).bare, + 'Passwd': opts.password + }) + headers = { + 'Content-Type': 'application/x-www-form-urlencoded' + } + try: + conn.request('POST', '/accounts/ClientLogin', params, headers) + resp = conn.getresponse().read() + data = {} + for line in resp.split(): + k, v = line.split(b'=', 1) + data[k] = v + except Exception as e: + print('Could not retrieve login data') + sys.exit() + + if b'SID' not in data: + print('Required data not found') + sys.exit() + + + params = urlencode({ + 'SID': data[b'SID'], + 'LSID': data[b'LSID'], + 'service': 'mail' + }) + try: + conn.request('POST', '/accounts/IssueAuthToken', params, headers) + resp = conn.getresponse() + data = resp.read().split() + except: + print('Could not retrieve auth data') + sys.exit() + + if not data: + print('Could not retrieve token') + sys.exit() + + access_token = data[0] + + + # Setup the ThirdPartyAuthBot and register plugins. Note that while plugins + # may have interdependencies, the order in which you register them does not + # matter. + + # If using MSN, the JID should be "user@messenger.live.com", which will + # be overridden on session bind. + + # We're using an access token instead of a password, so we'll use `''` as + # a password argument filler. + + xmpp = ThirdPartyAuthBot(opts.jid, '') + xmpp.credentials['access_token'] = access_token + + # The credentials dictionary is used to provide additional authentication + # information beyond just a password. + + xmpp.register_plugin('xep_0030') # Service Discovery + xmpp.register_plugin('xep_0004') # Data Forms + xmpp.register_plugin('xep_0060') # PubSub + + # MSN will kill connections that have been inactive for even + # short periods of time. So use pings to keep the session alive; + # whitespace keepalives do not work. + xmpp.register_plugin('xep_0199', {'keepalive': True, 'frequency': 60}) + + # 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. + # Google only allows one SASL attempt per connection, so in order to + # enable the X-GOOGLE-TOKEN mechanism, we'll disable TLS. + if xmpp.connect(use_tls=False): + # 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.") diff --git a/examples/user_location.py b/examples/user_location.py new file mode 100644 index 00000000..2877f7bd --- /dev/null +++ b/examples/user_location.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python + +import sys +import logging +import getpass +from optparse import OptionParser + +try: + import json +except ImportError: + import simplejson as json + +try: + import requests +except ImportError: + print('This demo requires the requests package for using HTTP.') + sys.exit() + +from sleekxmpp import ClientXMPP + + +class LocationBot(ClientXMPP): + + def __init__(self, jid, password): + super(LocationBot, self).__init__(jid, password) + + self.add_event_handler('session_start', self.start) + self.add_event_handler('user_location_publish', + self.user_location_publish) + + self.register_plugin('xep_0004') + self.register_plugin('xep_0030') + self.register_plugin('xep_0060') + self.register_plugin('xep_0115') + self.register_plugin('xep_0128') + self.register_plugin('xep_0163') + self.register_plugin('xep_0080') + + self.current_tune = None + + def start(self, event): + self.send_presence() + self.get_roster() + self['xep_0115'].update_caps() + + print("Using freegeoip.net to get geolocation.") + r = requests.get('http://freegeoip.net/json/') + try: + data = json.loads(r.text) + except: + print("Could not retrieve user location.") + self.disconnect() + return + + self['xep_0080'].publish_location( + lat=data['latitude'], + lon=data['longitude'], + locality=data['city'], + region=data['region_name'], + country=data['country_name'], + countrycode=data['country_code'], + postalcode=data['zipcode']) + + def user_location_publish(self, msg): + geo = msg['pubsub_event']['items']['item']['geoloc'] + print("%s is at:" % msg['from']) + for key, val in geo.values.items(): + if val: + print(" %s: %s" % (key, val)) + + +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 = LocationBot(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.") diff --git a/examples/user_tune.py b/examples/user_tune.py new file mode 100644 index 00000000..09e050f0 --- /dev/null +++ b/examples/user_tune.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +import sys +import logging +import getpass +from optparse import OptionParser + +try: + from appscript import * +except ImportError: + print('This demo requires the appscript package to interact with iTunes.') + sys.exit() + +from sleekxmpp import ClientXMPP + + +class TuneBot(ClientXMPP): + + def __init__(self, jid, password): + super(TuneBot, self).__init__(jid, password) + + # Check for the current song every 5 seconds. + self.schedule('Check Current Tune', 5, self._update_tune, repeat=True) + + self.add_event_handler('session_start', self.start) + self.add_event_handler('user_tune_publish', self.user_tune_publish) + + self.register_plugin('xep_0004') + self.register_plugin('xep_0030') + self.register_plugin('xep_0060') + self.register_plugin('xep_0115') + self.register_plugin('xep_0118') + self.register_plugin('xep_0128') + self.register_plugin('xep_0163') + + self.current_tune = None + + def start(self, event): + self.send_presence() + self.get_roster() + self['xep_0115'].update_caps() + + def _update_tune(self): + itunes_count = app('System Events').processes[its.name == 'iTunes'].count() + if itunes_count > 0: + iTunes = app('iTunes') + if iTunes.player_state.get() == k.playing: + track = iTunes.current_track.get() + length = track.time.get() + if ':' in length: + minutes, secs = map(int, length.split(':')) + secs += minutes * 60 + else: + secs = int(length) + + artist = track.artist.get() + title = track.name.get() + source = track.album.get() + rating = track.rating.get() / 10 + + tune = (artist, secs, rating, source, title) + if tune != self.current_tune: + self.current_tune = tune + + # We have a new song playing, so publish it. + self['xep_0118'].publish_tune( + artist=artist, + length=secs, + title=title, + rating=rating, + source=source) + else: + # No song is playing, clear the user tune. + tune = None + if tune != self.current_tune: + self.current_tune = tune + self['xep_0118'].stop() + + def user_tune_publish(self, msg): + tune = msg['pubsub_event']['items']['item']['tune'] + print("%s is listening to: %s" % (msg['from'], tune['title'])) + + +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 = TuneBot(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.") |