diff --git a/setup.py b/setup.py index b2a6a858..f90639c1 100755 --- a/setup.py +++ b/setup.py @@ -67,6 +67,7 @@ packages = [ 'sleekxmpp', 'sleekxmpp/plugins/xep_0066', 'sleekxmpp/plugins/xep_0077', 'sleekxmpp/plugins/xep_0078', + 'sleekxmpp/plugins/xep_0080', 'sleekxmpp/plugins/xep_0085', 'sleekxmpp/plugins/xep_0086', 'sleekxmpp/plugins/xep_0092', diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py index 8c5d38f0..a970b7db 100644 --- a/sleekxmpp/plugins/__init__.py +++ b/sleekxmpp/plugins/__init__.py @@ -22,6 +22,7 @@ __all__ = [ 'xep_0060', # Pubsub (Client) 'xep_0066', # Out-of-band Transfer # 'xep_0078', # Non-SASL auth. Don't automatically load + 'xep_0080', # User Location 'xep_0082', # XMPP Date and Time Profiles 'xep_0085', # Chat State Notifications 'xep_0086', # Legacy Error Codes diff --git a/sleekxmpp/plugins/xep_0080/__init__.py b/sleekxmpp/plugins/xep_0080/__init__.py new file mode 100644 index 00000000..1e3fe4c8 --- /dev/null +++ b/sleekxmpp/plugins/xep_0080/__init__.py @@ -0,0 +1,10 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2010 Nathanael C. Fritz, Erik Reuterborg Larsson + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.plugins.xep_0080.stanza import Geoloc +from sleekxmpp.plugins.xep_0080.geoloc import xep_0080 diff --git a/sleekxmpp/plugins/xep_0080/geoloc.py b/sleekxmpp/plugins/xep_0080/geoloc.py new file mode 100644 index 00000000..735f6ac0 --- /dev/null +++ b/sleekxmpp/plugins/xep_0080/geoloc.py @@ -0,0 +1,134 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2010 Nathanael C. Fritz, Erik Reuterborg Larsson + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import logging + +import sleekxmpp +from sleekxmpp.plugins.base import base_plugin +from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.plugins.xep_0080 import stanza, Geoloc + + +log = logging.getLogger(__name__) + + +class xep_0080(base_plugin): + + """ + XEP-0080: User Location + """ + + def plugin_init(self): + """ + Start the XEP-0090 plugin. + """ + self.xep = '0080' + self.description = 'User Location' + self.stanza = stanza + + def post_init(self): + """Handle inter-plugin dependencies.""" + base_plugin.post_init(self) + + pubsub_stanza = self.xmpp['xep_0060'].stanza + register_stanza_plugin(pubsub_stanza.EventItem, Geoloc) + + self.xmpp['xep_0030'].add_feature(Geoloc.namespace) + self.xmpp['xep_0163'].add_interest(Geoloc.namespace) + self.xmpp['xep_0060'].map_node_event(Geoloc.namespace, 'user_location') + + def publish_location(self, **kwargs): + """ + Publish the user's current location. + + Arguments: + accuracy -- Horizontal GPS error in meters. + alt -- Altitude in meters above or below sea level. + area -- A named area such as a campus or neighborhood. + bearing -- GPS bearing (direction in which the entity is + heading to reach its next waypoint), measured in + decimal degrees relative to true north. + building -- A specific building on a street or in an area. + country -- The nation where the user is located. + countrycode -- The ISO 3166 two-letter country code. + datum -- GPS datum. + description -- A natural-language name for or description of + the location. + error -- Horizontal GPS error in arc minutes. Obsoleted by + the accuracy parameter. + floor -- A particular floor in a building. + lat -- Latitude in decimal degrees North. + locality -- A locality within the administrative region, such + as a town or city. + lon -- Longitude in decimal degrees East. + postalcode -- A code used for postal delivery. + region -- An administrative region of the nation, such + as a state or province. + room -- A particular room in a building. + speed -- The speed at which the entity is moving, + in meters per second. + street -- A thoroughfare within the locality, or a crossing + of two thoroughfares. + text -- A catch-all element that captures any other + information about the location. + timestamp -- UTC timestamp specifying the moment when the + reading was taken. + uri -- A URI or URL pointing to information about + the location. + + options -- Optional form of publish options. + 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. + """ + options = kwargs.get('options', None) + ifrom = kwargs.get('ifrom', None) + block = kwargs.get('block', None) + callback = kwargs.get('callback', None) + timeout = kwargs.get('timeout', None) + for param in ('ifrom', 'block', 'callback', 'timeout', 'options'): + if param in kwargs: + del kwargs[param] + + geoloc = Geoloc() + geoloc.values = kwargs + + self.xmpp['xep_0163'].publish(geoloc, + node=Geoloc.namespace, + options=options, + ifrom=ifrom, + block=block, + callback=callback, + timeout=timeout) + + def stop(self, ifrom=None, block=True, callback=None, timeout=None): + """ + Clear existing user location 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. + """ + geoloc = Geoloc() + self.xmpp['xep_0163'].publish(geoloc, + node=Geoloc.namespace, + ifrom=ifrom, + block=block, + callback=callback, + timeout=timeout) diff --git a/sleekxmpp/plugins/xep_0080/stanza.py b/sleekxmpp/plugins/xep_0080/stanza.py new file mode 100644 index 00000000..a83a8b1b --- /dev/null +++ b/sleekxmpp/plugins/xep_0080/stanza.py @@ -0,0 +1,266 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2010 Nathanael C. Fritz + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.xmlstream import ElementBase +from sleekxmpp.plugins import xep_0082 + + +class Geoloc(ElementBase): + + """ + XMPP's stanza allows entities to know the current + geographical or physical location of an entity. (XEP-0080: User Location) + + Example stanzas: + + + + 20 + Italy + 45.44 + Venice + 12.33 + + + Stanza Interface: + accuracy -- Horizontal GPS error in meters. + alt -- Altitude in meters above or below sea level. + area -- A named area such as a campus or neighborhood. + bearing -- GPS bearing (direction in which the entity is + heading to reach its next waypoint), measured in + decimal degrees relative to true north. + building -- A specific building on a street or in an area. + country -- The nation where the user is located. + countrycode -- The ISO 3166 two-letter country code. + datum -- GPS datum. + description -- A natural-language name for or description of + the location. + error -- Horizontal GPS error in arc minutes. Obsoleted by + the accuracy parameter. + floor -- A particular floor in a building. + lat -- Latitude in decimal degrees North. + locality -- A locality within the administrative region, such + as a town or city. + lon -- Longitude in decimal degrees East. + postalcode -- A code used for postal delivery. + region -- An administrative region of the nation, such + as a state or province. + room -- A particular room in a building. + speed -- The speed at which the entity is moving, + in meters per second. + street -- A thoroughfare within the locality, or a crossing + of two thoroughfares. + text -- A catch-all element that captures any other + information about the location. + timestamp -- UTC timestamp specifying the moment when the + reading was taken. + uri -- A URI or URL pointing to information about + the location. + """ + + namespace = 'http://jabber.org/protocol/geoloc' + name = 'geoloc' + interfaces = set(('accuracy', 'alt', 'area', 'bearing', 'building', + 'country', 'countrycode', 'datum', 'dscription', + 'error', 'floor', 'lat', 'locality', 'lon', + 'postalcode', 'region', 'room', 'speed', 'street', + 'text', 'timestamp', 'uri')) + sub_interfaces = interfaces + plugin_attrib = name + + def exception(self, e): + """ + Override exception passback for presence. + """ + pass + + def set_accuracy(self, accuracy): + """ + Set the value of the element. + + Arguments: + accuracy -- Horizontal GPS error in meters + """ + self._set_sub_text('accuracy', text=str(accuracy)) + return self + + def get_accuracy(self): + """ + Return the value of the element as an integer. + """ + p = self._get_sub_text('accuracy') + if not p: + return None + else: + try: + return int(p) + except ValueError: + return None + + def set_alt(self, alt): + """ + Set the value of the element. + + Arguments: + alt -- Altitude in meters above or below sea level + """ + self._set_sub_text('alt', text=str(alt)) + return self + + def get_alt(self): + """ + Return the value of the element as an integer. + """ + p = self._get_sub_text('alt') + if not p: + return None + else: + try: + return int(p) + except ValueError: + return None + + def set_bearing(self, bearing): + """ + Set the value of the element. + + Arguments: + bearing -- GPS bearing (direction in which the entity is heading + to reach its next waypoint), measured in decimal + degrees relative to true north + """ + self._set_sub_text('bearing', text=str(bearing)) + return self + + def get_bearing(self): + """ + Return the value of the element as a float. + """ + p = self._get_sub_text('bearing') + if not p: + return None + else: + try: + return float(p) + except ValueError: + return None + + def set_error(self, error): + """ + Set the value of the element. + + Arguments: + error -- Horizontal GPS error in arc minutes; this + element is deprecated in favor of + """ + self._set_sub_text('error', text=str(error)) + return self + + def get_error(self): + """ + Return the value of the element as a float. + """ + p = self._get_sub_text('error') + if not p: + return None + else: + try: + return float(p) + except ValueError: + return None + + def set_lat(self, lat): + """ + Set the value of the element. + + Arguments: + lat -- Latitude in decimal degrees North + """ + self._set_sub_text('lat', text=str(lat)) + return self + + def get_lat(self): + """ + Return the value of the element as a float. + """ + p = self._get_sub_text('lat') + if not p: + return None + else: + try: + return float(p) + except ValueError: + return None + + def set_lon(self, lon): + """ + Set the value of the element. + + Arguments: + lon -- Longitude in decimal degrees East + """ + self._set_sub_text('lon', text=str(lon)) + return self + + def get_lon(self): + """ + Return the value of the element as a float. + """ + p = self._get_sub_text('lon') + if not p: + return None + else: + try: + return float(p) + except ValueError: + return None + + def set_speed(self, speed): + """ + Set the value of the element. + + Arguments: + speed -- The speed at which the entity is moving, + in meters per second + """ + self._set_sub_text('speed', text=str(speed)) + return self + + def get_speed(self): + """ + Return the value of the element as a float. + """ + p = self._get_sub_text('speed') + if not p: + return None + else: + try: + return float(p) + except ValueError: + return None + + def set_timestamp(self, timestamp): + """ + Set the value of the element. + + Arguments: + timestamp -- UTC timestamp specifying the moment when + the reading was taken + """ + self._set_sub_text('timestamp', text=str(xep_0082.datetime(timestamp))) + return self + + def get_timestamp(self): + """ + Return the value of the element as a DateTime. + """ + p = self._get_sub_text('timestamp') + if not p: + return None + else: + return xep_0082.datetime(p)