1# Copyright (C) 2009-2014 Yann Leboulanger <asterix AT lagaule.org> 2# 3# This file is part of Gajim. 4# 5# Gajim is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published 7# by the Free Software Foundation; version 3 only. 8# 9# Gajim is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with Gajim. If not, see <http://www.gnu.org/licenses/>. 16 17import logging 18from datetime import datetime 19 20from gi.repository import GLib 21from nbxmpp.structs import LocationData 22 23from gajim.common import app 24 25if app.is_installed('GEOCLUE'): 26 from gi.repository import Geoclue # pylint: disable=ungrouped-imports,no-name-in-module 27 28log = logging.getLogger('gajim.c.dbus.location') 29 30 31class LocationListener: 32 _instance = None 33 34 @classmethod 35 def get(cls): 36 if cls._instance is None: 37 cls._instance = cls() 38 return cls._instance 39 40 def __init__(self): 41 self._data = {} 42 self.location_info = {} 43 self.simple = None 44 45 # Note: do not remove third parameter `param` 46 # because notify signal expects three parameters 47 def _on_location_update(self, simple, _param=None): 48 location = simple.get_location() 49 timestamp = location.get_property("timestamp")[0] 50 lat = location.get_property("latitude") 51 lon = location.get_property("longitude") 52 alt = location.get_property("altitude") 53 # in XEP-0080 it's horizontal accuracy 54 acc = location.get_property("accuracy") 55 56 # update data with info we just received 57 self._data = {'lat': lat, 'lon': lon, 'alt': alt, 'accuracy': acc} 58 self._data['timestamp'] = self._timestamp_to_utc(timestamp) 59 self._send_location() 60 61 def _on_simple_ready(self, _obj, result): 62 try: 63 self.simple = Geoclue.Simple.new_finish(result) 64 except GLib.Error as error: 65 log.warning("Could not enable geolocation: %s", error.message) 66 else: 67 self.simple.connect('notify::location', self._on_location_update) 68 self._on_location_update(self.simple) 69 70 def get_data(self): 71 Geoclue.Simple.new("org.gajim.Gajim", 72 Geoclue.AccuracyLevel.EXACT, 73 None, 74 self._on_simple_ready) 75 76 def start(self): 77 self.location_info = {} 78 self.get_data() 79 80 def _send_location(self): 81 accounts = app.connections.keys() 82 for acct in accounts: 83 if not app.account_is_available(acct): 84 continue 85 if not app.settings.get_account_setting(acct, 'publish_location'): 86 continue 87 if self.location_info == self._data: 88 continue 89 if 'timestamp' in self.location_info and 'timestamp' in self._data: 90 last_data = self.location_info.copy() 91 del last_data['timestamp'] 92 new_data = self._data.copy() 93 del new_data['timestamp'] 94 if last_data == new_data: 95 continue 96 app.connections[acct].get_module('UserLocation').set_location( 97 LocationData(**self._data)) 98 self.location_info = self._data.copy() 99 100 @staticmethod 101 def _timestamp_to_utc(timestamp): 102 time = datetime.utcfromtimestamp(timestamp) 103 return time.strftime('%Y-%m-%dT%H:%MZ') 104 105 106def enable(): 107 if not app.is_installed('GEOCLUE'): 108 log.warning('GeoClue not installed') 109 return 110 111 listener = LocationListener.get() 112 listener.start() 113