openbmap-logger-0.4.0/0000755000000000000000000000000011231127401013257 5ustar rootrootopenbmap-logger-0.4.0/openbmap/0000755000000000000000000000000011231127401015060 5ustar rootrootopenbmap-logger-0.4.0/openbmap/Upload.py0000644000000000000000000000565311215240504016671 0ustar rootroot# Taken from http://code.activestate.com/recipes/146306 #"Recipe 146306: Http client to POST using multipart/form-data " # Terms of Service (http://code.activestate.com/help/terms): # By submitting a recipe (or code in comments), you are agreeing to the following terms: # * All submitted material will be made freely available on the ActiveState site under the MIT license. # Authors: # Wade Leftwich (http://code.activestate.com/recipes/users/98656/) # Chris Green (http://code.activestate.com/recipes/users/1745761/) # chris hoke (http://code.activestate.com/recipes/users/2022253/) import httplib, mimetypes import urlparse def post_multipart(host, selector, fields, files): content_type, body = encode_multipart_formdata(fields, files) h = httplib.HTTPConnection(host) headers = { 'User-Agent': 'OBM_FSO_logger', 'Content-Type': content_type, 'content-length': str(len(body)) } h.request('POST', selector, body, headers) res = h.getresponse() return res.status, res.reason, res.read() def post_url(url, fields, files): urlparts = urlparse.urlsplit(url) return post_multipart(urlparts[1], urlparts[2], fields, files) def post_multipart_original(host, selector, fields, files): """ Post fields and files to an http host as multipart/form-data. fields is a sequence of (name, value) elements for regular form fields. files is a sequence of (name, filename, value) elements for data to be uploaded as files Return the server's response page. """ content_type, body = encode_multipart_formdata(fields, files) h = httplib.HTTP(host) h.putrequest('POST', selector) h.putheader('content-type', content_type) h.putheader('content-length', str(len(body))) h.endheaders() h.send(body) errcode, errmsg, headers = h.getreply() return h.file.read() def encode_multipart_formdata(fields, files): """ fields is a sequence of (name, value) elements for regular form fields. files is a sequence of (name, filename, value) elements for data to be uploaded as files Return (content_type, body) ready for httplib.HTTP instance """ BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$' CRLF = '\r\n' L = [] for (key, value) in fields: L.append('--' + BOUNDARY) L.append('Content-Disposition: form-data; name="%s"' % key) L.append('') L.append(value) for (key, filename, value) in files: L.append('--' + BOUNDARY) L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename)) L.append('Content-Type: %s' % get_content_type(filename)) L.append('') L.append(value) L.append('--' + BOUNDARY + '--') L.append('') body = CRLF.join(L) content_type = 'multipart/form-data; boundary=%s' % BOUNDARY return content_type, body def get_content_type(filename): return mimetypes.guess_type(filename)[0] or 'application/octet-stream' openbmap-logger-0.4.0/openbmap/__init__.py0000644000000000000000000000000011215240504017161 0ustar rootrootopenbmap-logger-0.4.0/openbmap/logger.py0000755000000000000000000020336311231122137016724 0ustar rootroot#!/usr/bin/python # Copyright 2008, 2009 Ronan DANIELLOU # Copyright 2008, 2009 Onen (onen.om@free.fr) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import gobject import dbus import sys import dbus.mainloop.glib import time from datetime import datetime import logging import ConfigParser import threading import os.path import urllib2 import math # HTTP multi part upload import Upload class Gsm: # This lock will be used when reading/updating *any* GSM related variable. # Thus MCC, MNC, lac, cellid and strength are consistent. lock = threading.Lock() def __init__(self, bus): # "MCC", "MNC", "lac", "cid" and "strength" are received asynchronuously, through signal handler # thus we need to store them for the time the logging loop runs self._lac = -1 self._cid = -1 self._strength = -1 self._networkAccessType = '' self._MCC = '' self._MNC = '' self._registrationGSM = '' #This will remember all the cells seen. The structure is: # {id}->{MCC}->{MNC}->( {LAC}->[cid], {LAC}->[cid] ) 0: servings, 1: neighbours self._remember_cells_structures = {} self._current_remember_cells_structure_id = None self.REMEMBER_CELLS_STRUCTURE_TOTAL_ID = 'Total number of cells since Launch' self.set_current_remember_cells_id(self.REMEMBER_CELLS_STRUCTURE_TOTAL_ID) self._nb_remember_servings_in_last_structure = 0 self._nb_remember_neighbours_in_last_structure = 0 self._nb_remember_servings_total = 0 self._nb_remember_neighbours_total = 0 self._manufacturer = 'N/A' self._model = 'N/A' self._revision = 'N/A' self.get_device_info() self._observers = [] self._call_ongoing = False if bus: bus.add_signal_receiver(self.network_status_handler, 'Status', 'org.freesmartphone.GSM.Network', 'org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device') bus.add_signal_receiver(self.signal_strength_handler, 'SignalStrength', 'org.freesmartphone.GSM.Network', 'org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device') bus.add_signal_receiver(self.call_status_handler, 'CallStatus', 'org.freesmartphone.GSM.Call', 'org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device') self._gsmMonitoringIface = dbus.Interface( bus.get_object('org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device'), "org.freesmartphone.GSM.Monitor" ) self._gsmNetworkIface = dbus.Interface( bus.get_object('org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device'), "org.freesmartphone.GSM.Network" ) self._gsmCallIface = dbus.Interface( bus.get_object('org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device'), "org.freesmartphone.GSM.Call" ) def call_status_handler(self, data, *args, **kwargs): """This maps to org.freesmartphone.GSM.Call.CallStatus. """ logging.debug('Call status change notified, gets the lock.') self.acquire_lock() # CallStatus ( isa{sv} ) #i: id #The index of the call that changed its status or properties. #s: status #The new status of the call. Expected values are: # * "incoming" = The call is incoming (but not yet accepted), # * "outgoing" = The call is outgoing (but not yet established), # * "active" = The call is the active call (you can talk), # * "held" = The call is being held, # * "release" = The call has been released. self._call_ongoing = False list = self._gsmCallIface.ListCalls() for call in list: index, status, properties = call if status != 'release': logging.info('Call ongoing: %i, %s.' % (index, status) ) self._call_ongoing = True if not self._call_ongoing: logging.info('No call ongoing left.') logging.debug('Call status updated, released the lock.') self.release_lock() def call_ongoing(self): """Returns True if a call is ongoing. False otherwise.""" logging.debug('call_ongoing() gets the lock.') self.acquire_lock() result = self._call_ongoing logging.debug('call_ongoing()? %s' % result) logging.debug('call_ongoing(), released the lock.') self.release_lock() return result def network_status_handler(self, data, *args, **kwargs): """Handler for org.freesmartphone.GSM.Network.Status signal. MCC, MNC, lac, cid and signal strengh are received asynchronuously through this signal/handler. Warning: we do not receive this signal when only the signal strength changes, see org.freesmartphone.GSM.Network.SignalStrength signal, and self.signal_strength_handler(). """ logging.debug("Wait for updating GSM data.") self.acquire_lock() logging.debug("Lock acquired, updating GSM data.") try: if data['registration'] == 'home' or data['registration'] == 'roaming': logging.info('Registration status is: %s.' % data['registration']) else: logging.info('Registration status is: %s. Skip.' % data['registration']) raise Exception, 'GSM data not available.' if "lac" and "cid" and "strength" and "code" and "act" in data: self._MCC = (str(data['code'])[:3]).lstrip('0') self._MNC = (str(data['code'])[3:]).lstrip('0') self._networkAccessType = data['act'] # lac and cid are hexadecimal strings self._lac = str(int(data["lac"], 16)) self._cid = str(int(data["cid"], 16)) # The signal strength in percent (0-100) is returned. # Mickey pointed out (see dev mailing list archive): # in module ogsmd.gsm.const: #def signalQualityToPercentage( signal ): #""" #Returns a percentage depending on a signal quality strength. #""" # #if signal == 0 or signal > 31: # return 0 #else: # return int( round( math.log( signal ) / math.log( 31 ) * 100 ) ) if data["strength"] == 0: raise Exception, 'GSM strength (0) not suitable.' else: self._strength = self.signal_percent_to_dbm( data["strength"] ) val_from_modem = (self._strength + 113 ) / 2 self._registrationGSM = data['registration'] logging.info("MCC %s MNC %s LAC %s, CID %s, strength %i/%i/%i (dBm, modem, percent 0-100)" % \ (self._MCC, self._MNC, self._lac, self._cid, self._strength, val_from_modem, data['strength'])) self.remember_serving_cell_as_seen(self._current_remember_cells_structure_id, [{'lac':self._lac, 'cid':self._cid}] ) else: raise Exception, 'One or more required GSM data (MCC, MNC, lac, cid or strength) is missing.' except Exception, e: logging.warning('Unable to get GSM data (%s).' % str(e)) self.empty_GSM_data() self.release_lock() logging.debug("GSM data updated, lock released.") self.notify_observers() def signal_strength_handler(self, data, *args, **kwargs): """Handler for org.freesmartphone.GSM.Network.SignalStrength signal. """ logging.debug("Wait for updating GSM signal strength.") self.acquire_lock() logging.debug("Lock acquired, updating GSM signal strength.") try: new_dbm = self.signal_percent_to_dbm(data) if self.check_GSM(): logging.info('GSM Signal strength updated from %i dBm to %i dBm (%i %%)' % (self._strength, new_dbm, data)) self._strength = new_dbm else: logging.info('GSM data invalid, no signal strength update to %i dBm (%i %%)' % (new_dbm, data)) except Exception, e: logging.warning('Unable to update GSM signal strength (%s).' % str(e)) self.release_lock() logging.debug("GSM signal strength update finished, lock released.") self.notify_observers() def empty_GSM_data(self): """Empty all the local GSM related variables.""" self._lac = '' self._cid = '' self._MCC = '' self._MNC = '' self._strength = 0 self._registrationGSM = '' self._networkAccessType = '' def get_device_info(self): """If available, returns the manufacturer, model and revision.""" #TODO call the dBus interface only if instance attributes are not set. obj = dbus.SystemBus().get_object('org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device') data = dbus.Interface(obj, 'org.freesmartphone.GSM.Device').GetInfo() if 'manufacturer' in data: # At the moment the returned string starts and ends with '"' for model and revision self._manufacturer = data['manufacturer'].strip('"') if 'model' in data: # At the moment the returned string starts and ends with '"' for model and revision self._model = data['model'].strip('"') if 'revision' in data: # At the moment the returned string starts and ends with '"' for model and revision self._revision = data['revision'].strip('"') logging.info('Hardware manufacturer=%s, model=%s, revision=%s.' % \ (self._manufacturer, self._model, self._revision)) return(self._manufacturer, self._model, self._revision) def check_GSM(self): """Returns True if valid GSM data is available.""" # if something went wrong with GSM data then strength will be set to 0 (see empty_GSM_data() ) # see 3GPP documentation TS 07.07 Chapter 8.5, GSM 07.07 command +CSQ return (self._strength >= -113 and self._strength <= -51) def signal_percent_to_dbm(self, val): """Translate the signal percent value to dbm.""" # The signal strength in percent (0-100) is returned. # Mickey pointed out (see dev mailing list archive): # in module ogsmd.gsm.const: #def signalQualityToPercentage( signal ): #""" #Returns a percentage depending on a signal quality strength. #""" # #if signal == 0 or signal > 31: # return 0 #else: # return int( round( math.log( signal ) / math.log( 31 ) * 100 ) ) val_from_modem = int( round(math.exp(val * math.log( 31 ) /100)) ) # translate to dBm (see 3GPP documentation TS 07.07 Chapter 8.5, GSM 07.07 command +CSQ) return val_from_modem * 2 - 113 def get_serving_cell_information(self): """Returns a dictionary with serving cell monitoring data. If available contains 'lac' and 'cid'. May contain 'rxlev' and 'tav'. Otherwise returns an empty dictionary. Maximal timeout is 0.8 second. """ result = {} try: data = self._gsmMonitoringIface.GetServingCellInformation(timeout = 0.8) # Debug # string hex #data['cid'] = '0' # string hex #data['lac'] = '0' # int #data['rxlev'] = 0 #del data['lac'] #del data['cid'] # end of debug logging.debug( 'Raw data serving cell: %s' % data) if 'cid' in data and int(data['cid'], 16) == 0: # I have seen cid of 0. This does not make sense? logging.info('Serving cell with cell id of 0 discarded.') elif 'lac' in data and int(data['lac'], 16) == 0: # Not sure if I have seen lac of 0. This does not make sense? In case of... logging.info('Serving cell with lac of 0 discarded.') elif ('rxlev' in data) and (data['rxlev'] == 0): logging.info('GSM rxlev (0) not suitable, this serving cell is discarded.') else: # wiki.openmoko.org/wiki/Neo_1973_and_Neo_FreeRunner_gsm_modem#Serving_Cell_Information_.282.2C1.29 # states: # rxlev Received Field Strength (rxlev/2)+2 gives the AT+CSQ response value # The best answer I could get was: no idea if this is correct. # Thus we keep the values as unmodified as possible. for key in ['rxlev', 'tav']: if key in data: result[key] = data[key] if "lac" in data and "cid" in data: # lac and cid are hexadecimal strings result['lac'] = str(int(data["lac"], 16)) result['cid'] = str(int(data["cid"], 16)) else: logging.warning('Either lac or cid is missing in serving cell information.') result.clear() except Exception, e: logging.error('get serving cell info: %s' % str(e)) result.clear() logging.debug( 'serving cell result: %s' % result) return result def get_neighbour_cell_info(self): """Returns a tuple of dictionaries, one for each cell. Each dictionary contains lac and cid fields. They may contain rxlev, c1, c2, and ctype. Maximal timeout is 0.8 second. """ results = [] try: data = self._gsmMonitoringIface.GetNeighbourCellInformation(timeout = 0.8) for cell in data: #logging.debug( 'Raw data neighbour cell: %s' % cell) if "lac" and "cid" in cell: # lac and cid are hexadecimal strings result = {} result['lac'] = str(int(cell["lac"], 16)) result['cid'] = str(int(cell["cid"], 16)) # The signal strength in percent (0-100) is returned. # The following comments were about the signal strength (see GetStatus): # Mickey pointed out (see dev mailing list archive): # in module ogsmd.gsm.const: #def signalQualityToPercentage( signal ): #""" #Returns a percentage depending on a signal quality strength. #""" # #if signal == 0 or signal > 31: # return 0 #else: # return int( round( math.log( signal ) / math.log( 31 ) * 100 ) ) # http://wiki.openmoko.org/wiki/Neo_1973_and_Neo_FreeRunner_gsm_modem#Serving_Cell_Information_.282.2C1.29 # states: # rxlev Received Field Strength (rxlev/2)+2 gives the AT+CSQ response value # The best answer I could get was: no idea if this is correct. # Thus we keep the values as unmodified as possible. if 'rxlev' in cell: result['rxlev'] = cell['rxlev'] if 'c1' in cell: result['c1'] = cell['c1'] if 'c2' in cell: result['c2'] = cell['c2'] #if 'ctype' in cell: # result['ctype'] = ('NA', 'GSM', 'GPRS')[cell['ctype']] #logging.debug( 'Neighbour cell result: %s' % result) if int(result['cid']) == 0: # I have seen cid of 0. This does not make sense? logging.info('Neighbour cell with cell id of 0 discarded.') elif int(result['lac']) == 0: # Not sure if I have seen lac of 0. This does not make sense? In case of... logging.info('Neighbour cell with lac of 0 discarded.') elif ('rxlev' in cell) and (cell['rxlev'] == 0): logging.info('GSM rxlev (0) not suitable, this neighbour cell is discarded.') else: results.append(result) except Exception, e: logging.error('get neighbour cells info: %s' % str(e)) return () return tuple(results) def get_gsm_data(self): """Return validity boolean, tuple serving cell data, tuple of neighbour cells dictionaries. Operation is atomic, values cannot be modified while reading it. The validity boolean is True when all fields are valid and consistent, False otherwise. Serving cell tuple contains: MCC, MNC, lac, cid, signal strength, access type, timing advance, rxlev. Timing advance and rxlev may be emtpy. Each neighbour cell dictionary contains lac and cid fields. They may contain rxlev, c1, c2, and ctype. """ logging.debug("Wait for reading GSM data.") self.acquire_lock() logging.debug("Lock acquired, reading GSM data.") (valid, mcc, mnc, lac, cid, strength, act) = (self.check_GSM(), self._MCC, self._MNC, self._lac, self._cid, self._strength, self._networkAccessType) neighbourCells = () tav = '' rxlev = '' # this is deactivated for release 0.2.0 # and re-activated for release 0.3.0 if valid: neighbourCells = self.get_neighbour_cell_info() servingInfo = self.get_serving_cell_information() # in case of a change in registration not already taken into account here # by processing D-Bus signal by network_status_handler(), we prefer using data # from get_serving_cell_information() if ('lac' in servingInfo) and ('cid' in servingInfo): lac = servingInfo['lac'] cid = servingInfo['cid'] # deactivated. Timing advance only works for the serving cell, and when a channel is actually open #if 'tav' in servingInfo: # tav = str(servingInfo['tav']) if 'rxlev' in servingInfo: rxlev = str(servingInfo['rxlev']) self.remember_neighbour_cells_as_seen(self._current_remember_cells_structure_id, neighbourCells) logging.info("valid=%s, MCC=%s, MNC=%s, lac=%s, cid=%s, strength=%s, act=%s, tav=%s, rxlev=%s" % (valid, mcc, mnc, lac, cid, strength, act, tav, rxlev)) self.release_lock() logging.debug("GSM data read, lock released.") return (valid, (mcc, mnc, lac, cid, strength, act, tav, rxlev), neighbourCells ) def get_status(self): """Get GSM status. Maps to org.freesmartphone.GSM.Network.GetStatus(). It uses network_status_handler() to parse the output. """ status = self._gsmNetworkIface.GetStatus() self.network_status_handler(status) def create_remember_cells_structure (self, id): """Tries to create a remember cells structure with given id. Throws exception if id already exists. Returns id on success.""" if id in self._remember_cells_structures: raise Exception, 'create_remember_cells_strucutre(): id already exists.' else: self._remember_cells_structures[id] = {} logging.info('id:%s added to remember cells structure.' % id) return id def remember_cells_as_seen(self, id, cells, type): """Parses cells dictionaries list and remembers having seen it. id: id of the remember cells structure to act upon cells: a list of dictionaries describing cells to remember type: 0 : servings, 1 : neighbours Cells already seen are ignored. If the id is not the one from the structure used to remember all the cells, and a new value is added, it calls the method on the "total" structure.""" if not type in (0, 1): raise Exception, 'remember_cells_as_seen() wrong type value (%s).' % type structure = self._remember_cells_structures if not id in structure: logging.warning('Remember_cells_as_seen(): id (%s) cannot be found.' % id) return else: structure = self._remember_cells_structures[id] if self._MCC == '': logging.debug('remember_cells_as_seen(): ignores empty MCC.') return elif not self._MCC in structure: logging.info('Adds MCC:%s to remember cell structure id (%s).' % (self._MCC, id)) structure[self._MCC] = {} structure = structure[self._MCC] if self._MNC == '': logging.debug('remember_cells_as_seen(): ignores empty MNC.') return elif not self._MNC in structure: logging.info('Adds MNC:%s to remember cell structure id (%s), MCC:%s.' % (self._MNC, id, self._MCC)) # servings and neighbours structure[self._MNC] = ({}, {}) structure = structure[self._MNC][type] logging.info('Update remember cells structure for %s.' % ['servings', 'neighbours'][type]) for cell in cells: if cell['lac'] in structure: if cell['cid'] in structure[ cell['lac'] ]: logging.debug('Cell %(lac)s / %(cid)s has already been seen' % cell) continue else: structure[ cell['lac'] ].append(cell['cid']) logging.info('Cell %(lac)s / %(cid)s adds a new cid to remember' % cell + ' to structure id: %s' % id) else: structure[ cell['lac'] ] = [ cell['cid'] ] logging.info('Cell %(lac)s / %(cid)s adds new lac and cid to remember' % cell + ' to structure id: %s' % id) self.increase_remember_cells_stats(id, type) if id != self.REMEMBER_CELLS_STRUCTURE_TOTAL_ID: # we are not in the structure which gathers *all* cells seen logging.debug('Try updating remember cells total structure.') self.remember_cells_as_seen(self.REMEMBER_CELLS_STRUCTURE_TOTAL_ID, [cell], type) def increase_remember_cells_stats(self, id, type): """Increments the number of cells for the id and type. id: id of the remember cells structure to act upon type: 0 : servings, 1 : neighbours """ if not type in (0, 1): raise Exception, 'increase_remember_cells_stats() wrong type value (%s).' % type if id == self.REMEMBER_CELLS_STRUCTURE_TOTAL_ID: if type == 0: self._nb_remember_servings_total += 1 else: self._nb_remember_neighbours_total += 1 logging.debug('Total numbers of cells seen are now: %i, %i.' % (self._nb_remember_servings_total, self._nb_remember_neighbours_total) ) else: if type == 0: self._nb_remember_servings_in_last_structure += 1 else: self._nb_remember_neighbours_in_last_structure += 1 logging.debug('Numbers of cells seen in last structure are now: %i, %i.' % (self._nb_remember_servings_in_last_structure, self._nb_remember_neighbours_in_last_structure) ) def remember_serving_cell_as_seen(self, id, serving): """Remembers having seen the serving cell. id: id of the remember cells structure to act upon serving: a list of dictionaries describing cells to remember """ self.remember_cells_as_seen(id, serving, 0) def remember_neighbour_cells_as_seen(self, id, neighbours): """Remembers having seen the neighbour cells. id: id of the remember cells structure to act upon neighbours: a list of dictionaries describing cells to remember """ self.remember_cells_as_seen(id, neighbours, 1) def set_current_remember_cells_id(self, id): """Sets the current remember cells structure id, creates it if necessary.""" if not id: logging.error('id:\'%s\' is not valid for a remember cells structure.' % id) return logging.debug("Wait for GSM Lock data.") self.acquire_lock() logging.debug("Lock acquired by set_current_remember_cells_id().") if id in self._remember_cells_structures: logging.info('id:\'%s\' already existed in remember cells structure.' % id) else: self.create_remember_cells_structure(id) self._current_remember_cells_structure_id = id #TODO: you can set an existing id. In that case, you should initialise # the values with the content of the existing structure self._nb_remember_servings_in_last_structure = 0 self._nb_remember_neighbours_in_last_structure = 0 logging.debug('Remember cells counters for current structure reset to 0.') logging.info('current remember cells structure id set to: %s' % id) self.release_lock() logging.debug("Lock released by set_current_remember_cells_id().") def get_seen_cells_stats(self): """Returns the number of cells which have been seen. Returns a tuple: number of serving cells seen in last remember structure, number of neighbour cells seen in last remember structure, number of serving cells seen since launch, number of neighbour cells seen since launch """ logging.debug("Wait for GSM Lock data.") self.acquire_lock() logging.debug("Lock acquired by get_seen_cells_stats(), reading.") res = (self._nb_remember_servings_in_last_structure, self._nb_remember_neighbours_in_last_structure, self._nb_remember_servings_total, self._nb_remember_neighbours_total) self.release_lock() logging.debug("Lock released by get_seen_cells_stats().") return res def acquire_lock(self): """Acquire the lock to prevent state of the GSM variables to be modified.""" self.lock.acquire() def release_lock(self): """Release the lock on the object""" self.lock.release() def notify_observers(self): for obs in self._observers: obs.notify() logging.debug('Gsm class notifies its observers.') def register(self, observer): self._observers.append(observer) class Config: LOG_FILENAME = 'General log file name' LOGGING_LEVEL = 'Logging level' APP_HOME_DIR = os.path.join(os.environ['HOME'], '.openBmap') TEMP_LOG_FILENAME = os.path.join(APP_HOME_DIR, 'openBmap.log') CONFIGURATION_FILENAME = os.path.join(APP_HOME_DIR, 'openBmap.conf') XML_LOG_VERSION = 'V2' # For ease of comparison in database, we use ##.##.## format for version: SOFTWARE_VERSION = '00.04.00' def __init__(self): # strings which will be used in the configuration file self.GENERAL = 'General' self.OBM_LOGS_DIR_NAME = 'OpenBmap logs directory name' self.OBM_PROCESSED_LOGS_DIR_NAME = 'OpenBmap uploaded logs directory name' self.OBM_UPLOAD_URL = 'OpenBmap upload URL' self.OBM_API_CHECK_URL = 'OpenBmap API check URL' self.OBM_API_VERSION = 'OpenBmap API version' self.SCAN_SPEED_DEFAULT = 'OpenBmap logger default scanning speed (in sec.)' self.MIN_SPEED_FOR_LOGGING = 'GPS minimal speed for logging (km/h)' self.MAX_SPEED_FOR_LOGGING = 'GPS maximal speed for logging (km/h)' # NB_OF_LOGS_PER_FILE is considered for writing of log to disk only if MAX_LOGS_FILE_SIZE <= 0 self.NB_OF_LOGS_PER_FILE = 'Number of logs per file' # puts sth <=0 to MAX_LOGS_FILE_SIZE to ignore it and let other conditions trigger # the write of the log to disk (e.g. NB_OF_LOGS_PER_FILE) self.MAX_LOGS_FILE_SIZE = 'Maximal size of log files to be uploaded (kbytes)' self.APP_LOGGING_LEVEL = 'Application logging level (debug, info, warning, error, critical)' self.CREDENTIALS = 'Credentials' self.OBM_LOGIN = 'OpenBmap login' self.OBM_PASSWORD = 'OpenBmap password' self._config = self.load_config() # TODO: it writes the config file every time! :-( self.save_config() def load_config(self): """Try loading the configuration file. Try to load the configuration file. If it does not exist, the default values are loaded, and the configuration file is saved with these default values. """ logging.debug('Loading configuration file: \'%s\'' % Config.CONFIGURATION_FILENAME) config = ConfigParser.RawConfigParser(); try: config.readfp(open(self.CONFIGURATION_FILENAME)) logging.debug('Configuration file loaded.') except Exception, e: logging.warning("No configuration file found: uses default values") config.add_section(self.GENERAL) #config.set(self.GENERAL, self.CONFIGURATION_FILENAME, 'OpenBmap.conf') #TODO config.set(self.GENERAL, self.LOGGING_LEVEL, 'logging.DEBUG') #TODO config.set(self.GENERAL, self.LOG_FILENAME, # os.path.join(self.APP_HOME_DIR, # 'OpenBmap.log')) config.set(self.GENERAL, self.OBM_LOGS_DIR_NAME, os.path.join(self.APP_HOME_DIR, 'Logs')) config.set(self.GENERAL, self.OBM_PROCESSED_LOGS_DIR_NAME, os.path.join(self.APP_HOME_DIR, 'Processed_logs')) config.set(self.GENERAL, self.OBM_UPLOAD_URL, 'http://realtimeblog.free.fr/upload/upl.php5') config.set(self.GENERAL, self.OBM_API_CHECK_URL, 'http://realtimeblog.free.fr/getInterfacesVersion.php') config.set(self.GENERAL, self.OBM_API_VERSION, '2') config.set(self.GENERAL, self.SCAN_SPEED_DEFAULT, 10) # in sec. config.set(self.GENERAL, self.MIN_SPEED_FOR_LOGGING, 0) config.set(self.GENERAL, self.MAX_SPEED_FOR_LOGGING, 150) config.set(self.GENERAL, self.NB_OF_LOGS_PER_FILE, 3) config.set(self.GENERAL, self.MAX_LOGS_FILE_SIZE, 20) config.set(self.GENERAL, self.APP_LOGGING_LEVEL, 'info') config.add_section(self.CREDENTIALS) config.set(self.CREDENTIALS, self.OBM_LOGIN, 'your_login') config.set(self.CREDENTIALS, self.OBM_PASSWORD, 'your_password') return config def get(self, section, option): try: if option in [self.SCAN_SPEED_DEFAULT, self.MIN_SPEED_FOR_LOGGING, self.MAX_SPEED_FOR_LOGGING, self.NB_OF_LOGS_PER_FILE, self.MAX_LOGS_FILE_SIZE]: return self._config.getint(section, option) elif option in [self.APP_LOGGING_LEVEL]: res = str.upper(self._config.get(section, option)) if not res in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']: errMsg = 'Application logging level should be one of'\ ' DEBUG, INFO, WARNING, ERROR, CRITICAL.'\ ' Found: %s' % res logging.error(errMsg) raise Exception, errMsg else: return res else: return self._config.get(section, option) except Exception, e: # we cannot find it. Maybe the current config file (old version) did not contain # this entry (newer version of the software) defaultValue = 0 if option in [self.MAX_LOGS_FILE_SIZE]: defaultValue = 20 elif option in [self.APP_LOGGING_LEVEL]: defaultValue = 'INFO' else: logging.critical("get_option() does not find (%s / %s). This is much probably a bug." % (section, option)) logging.critical(str(e)) #TODO: well in case this happens, this should be forwarded to Views (GUI) in order to inform the user sys.exit(-1) self._config.set(self.GENERAL, option, defaultValue) logging.info('Option \'%s\' cannot be found. Add it to the config file with default value: %s' % (option, defaultValue)) self.save_config() return defaultValue def set(self, section, option, value): self._config.set(section, option, value) def save_config(self): configFile = open(Config.CONFIGURATION_FILENAME, 'wb') logging.info('Save config file \'%s\'' % Config.CONFIGURATION_FILENAME) self._config.write(configFile) configFile.close() class Gps: GYPSY_DEVICE_FIX_STATUS_INVALID = 0 GYPSY_DEVICE_FIX_STATUS_NONE = 1 # A fix with latitude and longitude has been obtained GYPSY_DEVICE_FIX_STATUS_2D = 2 # A fix with latitude, longitude and altitude has been obtained GYPSY_DEVICE_FIX_STATUS_3D = 3 def __init__(self): self._dbusobj = dbus.SystemBus().get_object('org.freesmartphone.ogpsd', '/org/freedesktop/Gypsy') self._lat = -1 self._lng = -1 self._alt = -1 self._spe = -1 self._user_speed_kmh = -1 self._pdop = -1 self._hdop = -1 self._vdop = -1 self._tstamp = -1 def request(self): """Requests the GPS resource through /org/freesmartphone/Usage.""" obj = dbus.SystemBus().get_object('org.freesmartphone.ousaged', '/org/freesmartphone/Usage') request = dbus.Interface(obj, 'org.freesmartphone.Usage').RequestResource('GPS') if (request == None): logging.info("GPS ressource succesfully requested (%s)." % request) return True else: logging.critical("ERROR requesting the GPS (%s)" % request) return False def get_GPS_data(self): """Returns Validity boolean, time stamp, lat, lng, alt, pdop, hdop, vdop.""" logging.debug('Get GPS position') (fields, tstamp, lat, lng, alt) = dbus.Interface(self._dbusobj, 'org.freedesktop.Gypsy.Position').GetPosition() # From Python doc: The precision determines the number of digits after the decimal point and defaults to 6. # A difference of the sixth digit in lat/long leads to a difference of under a meter of precision. # Thus 6 is good enough. logging.debug('GPS position: fields (%d), lat (%f), lnt (%f), alt (%f)' % (fields, lat, lng, alt)) valid = True if fields != 7: valid = False (fields, pdop, hdop, vdop) = self._dbusobj.GetAccuracy(dbus_interface='org.freedesktop.Gypsy.Accuracy') logging.debug('GPS accuracy: fields (%d), pdop (%g), hdop (%g), vdop (%g)' % (fields, pdop, hdop, vdop)) if fields != 7: valid = False self._lat = lat self._lng = lng self._alt = alt self._pdop = pdop self._hdop = hdop self._vdop = vdop self._tstamp = tstamp return valid, tstamp, lat, lng, alt, pdop, hdop, vdop def get_course(self): """Return validity boolean, speed in knots, heading in decimal degree.""" (fields, tstamp, speed, heading, climb) = self._dbusobj.GetCourse(dbus_interface='org.freedesktop.Gypsy.Course') logging.debug('GPS course: fields (%d), speed (%f), heading (%f)' % (fields, speed, heading)) if (fields & (1 << 0)) and (fields & (1 << 1)): return True, speed, heading return False, speed, heading class ObmLogger(): # Lock to access the OBM logs files fileToSendLock = threading.Lock() def __init__(self): self._gps = Gps() self._observers = [] # is currently logging? Used to tell the thread to stop self._logging = False self._loggingThread = None self._bus = self.init_dbus() self._gsm = Gsm(self._bus) self._gsm.register(self) self._mcc = "" self._loggerLock = threading.Lock() # we will store every log in this list, until writing it to a file: self._logsInMemory = [] # _logsInMemory is a list of strings, which will be concatenated to write to disk self._logsInMemoryLengthInByte = 0 self._logFileHeader = "\n" + \ "\n" \ % ( self._gsm.get_device_info() + (config.SOFTWARE_VERSION,) ) self._logFileTail = '' logLvl = config.get(config.GENERAL, config.APP_LOGGING_LEVEL) logLvl = logging.__dict__[logLvl] logging.getLogger().setLevel(logLvl) logging.info('Application logging level set to %s' % logging.getLevelName(logLvl)) # DEBUG = True if you want to activate GPS/Web connection simulation self.DEBUG = False if self.DEBUG: self.get_gps_data = self.simulate_gps_data #self.get_gsm_data = self.simulate_gsm_data def request_ressource(self, resource): """Requests the given string resource through /org/freesmartphone/Usage.""" obj = self._bus.get_object('org.freesmartphone.ousaged', '/org/freesmartphone/Usage') request = dbus.Interface(obj, 'org.freesmartphone.Usage').RequestResource(resource) if (request == None): logging.info("'%s' resource succesfully requested (%s)." % (resource, request)) return True else: logging.critical("ERROR requesting the resource '%s' (%s)" % (resource, request)) return False def test_write_obm_log(self): self.write_obm_log(str(datetime.now()), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) def write_obm_log(self, date, tstamp, servingCell, lng, lat, alt, spe, heading, hdop, vdop, pdop, neighbourCells): """Format and stores in memory given data, possibly triggers writing in log file.""" # From Python doc: %f -> The precision determines the number of digits after the decimal point and defaults to 6. # A difference of the sixth digit in lat/long leads to a difference of under a meter of precision. # Maximum error by rounding is 5. GPS precision is at best 10m. 2 x (maxError x error) = 2 x (5 x 1) # introduces an error of 10m! Thus we settle to 9. latLonPrecision = 9 # http://gpsd.berlios.de/gpsd.html: # Altitude determination is more sensitive to variability to atmospheric signal lag than latitude/longitude, # and is also subject to errors in the estimation of local mean sea level; base error is 12 meters at 66% # confidence, 23 meters at 95% confidence. Again, this will be multiplied by a vertical dilution of # precision (VDOP). # Altitude is in meter. altitudePrecision = 1 # speed is in km/h. speedPrecision = 3 # Precision of 2 digits after the decimal point for h/p/v-dop is enough. hvpdopPrecision = 2 # heading in decimal degrees headingPrecision = 9 # log format, for release 0.2.0 # "" % servingCell[:5] logmsg = "" % date + \ "" #" ctype=\"%s\"" % cell['ctype'] + \ logmsg += "" + \ "\n" logging.info(logmsg) self.fileToSendLock.acquire() logging.info('OpenBmap log file lock acquired.') #debug #self._gsm._call_ongoing = True #end of debug if self._gsm.call_ongoing(): # see comments in log() about not logging in a call. logging.info('write_obm_log() canceled because a call is ongoing.') self.fileToSendLock.release() logging.info('OpenBmap log file lock released.') return maxLogsFileSize = config.get(config.GENERAL, config.MAX_LOGS_FILE_SIZE) * 1024 if ( maxLogsFileSize > 0 ): # we use the max log file size as criterium to trigger write of file # we write ascii file, that is to say, one byte per character fileLengthInByte = len(self._logFileHeader) + len(logmsg) \ + self._logsInMemoryLengthInByte + len(self._logFileTail) if (fileLengthInByte <= maxLogsFileSize): logging.debug('Current size of logs in memory %i bytes, max size of log files is %i bytes.' % (fileLengthInByte, maxLogsFileSize)) else: self.write_obm_log_to_disk_unprotected() self._logsInMemory.append(logmsg) self._logsInMemoryLengthInByte += len(logmsg) else: self._logsInMemory.append(logmsg) self._logsInMemoryLengthInByte += len(logmsg) if len(self._logsInMemory) < config.get(config.GENERAL, config.NB_OF_LOGS_PER_FILE): logging.debug('Max logs per file (%i/%i) not reached, wait to write to a file.' % (len(self._logsInMemory), config.get(config.GENERAL, config.NB_OF_LOGS_PER_FILE))) else: self.write_obm_log_to_disk_unprotected() self.fileToSendLock.release() logging.info('OpenBmap log file lock released.') def write_obm_log_to_disk(self): """Gets the Lock and then calls write_obm_log_to_disk_unprotected().""" self.fileToSendLock.acquire() logging.info('OpenBmap log file lock acquired by write_obm_log_to_disk().') self.write_obm_log_to_disk_unprotected() self.fileToSendLock.release() logging.info('OpenBmap log file lock released by write_obm_log_to_disk().') def write_obm_log_to_disk_unprotected(self): """Takes the logs already formatted in memory and write them to disk. Clears the log in memory. Warning: this method is not protected by a Lock! """ if len(self._logsInMemory) == 0: logging.info('No log to write to disk, returning.') return now = datetime.now() #"yyyyMMddHHmmss" date = now.strftime("%Y%m%d%H%M%S") logDir = config.get(config.GENERAL, config.OBM_LOGS_DIR_NAME) # at the moment: log files follow: logYYYYMMDDhhmmss.xml # log format, for release 0.2.0 # filename = os.path.join(logDir, 'log' + date + '.xml') # new filename format VX_MCC_logYYYYMMDDhhmmss.xml mcc = self._logsInMemory[0] # len('mcc="') = 5 mcc = mcc[mcc.find("mcc=") + 5 : ] mcc = mcc[ : mcc.find('"')] filename = os.path.join(logDir, config.XML_LOG_VERSION + '_' + mcc + '_log' + date + '.xml') logmsg = self._logFileHeader for log in self._logsInMemory: logmsg += log #TODO: escaped characters wich would lead to malformed XML document (e.g. '"') logmsg += self._logFileTail logging.debug('Write logs to file: %s' % logmsg) try: file = open(filename, 'w') file.write(logmsg) file.close() self._logsInMemory[:] = [] self._logsInMemoryLengthInByte = 0 except Exception, e: logging.error("Error while writing GSM/GPS log to file: %s" % str(e)) def send_logs(self): """Try uploading available log files to OBM database. Returns (b, i, i): True if nothing wrong happened. The total number of successfully uploaded files. The total number of files available for upload. """ totalFilesToUpload = 0 totalFilesUploaded = 0 result = True # to store the data once sent: dirProcessed = os.path.join(config.get(config.GENERAL, config.OBM_PROCESSED_LOGS_DIR_NAME)) logsDir = config.get(config.GENERAL, config.OBM_LOGS_DIR_NAME) self.fileToSendLock.acquire() logging.info('OpenBmap log file lock acquired.') try: if not self.check_obm_api_version(): logging.error('We do not support the server API version,' + \ 'do you have the latest version of the software?') return (False, -1, -1) os.chdir(logsDir) for f in os.listdir(logsDir): totalFilesToUpload += 1 logging.info('Try uploading \'%s\'' % f) fileRead = open(f, 'r') content = fileRead.read() fileRead.close() (status, reason, resRead) = Upload.post_url(config.get(config.GENERAL, config.OBM_UPLOAD_URL), [('openBmap_login', config.get(config.CREDENTIALS, config.OBM_LOGIN)), ('openBmap_passwd', config.get(config.CREDENTIALS, config.OBM_PASSWORD))], [('file', f, content)]) logging.debug('Upload response status:%s, reason:%s, body:%s' % (status, reason, resRead)) if resRead.startswith('Stored in'): newName = os.path.join(dirProcessed, f) os.rename(f, newName) logging.info('File \'%s\' successfully uploaded. Moved to \'%s\'. Thanks for contributing!' % (f, newName)) totalFilesUploaded += 1 elif resRead.strip(' ').endswith('already exists.'): # We assume the file has already been uploaded... newName = os.path.join(dirProcessed, f) os.rename(f, newName) logging.info('File \'%s\' probably already uploaded. Moved to \'%s\'. Thanks for contributing!' % (f, newName)) else: logging.error('Unable to upload file \'%s\'.' % f) result = False except Exception, e: logging.error("Error while sending GSM/GPS logged data: %s" % str(e)) return (False, totalFilesUploaded, totalFilesToUpload) finally: self.fileToSendLock.release() logging.info('OpenBmap log file lock released.') return (result, totalFilesUploaded, totalFilesToUpload) def delete_processed_logs(self): """Deletes all the files located in the 'processed' folder. Returns number deleted.""" # no Lock used here, I don't see this needed for Processed logs... dirProcessed = os.path.join(config.get(config.GENERAL, config.OBM_PROCESSED_LOGS_DIR_NAME)) deletedSoFar = 0 for f in os.listdir(dirProcessed): toBeDeleted = os.path.join(dirProcessed, f) os.remove(toBeDeleted) deletedSoFar += 1 logging.info('Processed log file \'%s\' has been deleted.' % toBeDeleted) return deletedSoFar def check_obm_api_version(self): """Get the current openBmap server API version, and return True if it corresponds.""" logging.debug('Checking the openBmap server interface Version...') if self.DEBUG: # simulation return True try: logging.info('We support API version: %s.' % config.get(config.GENERAL, config.OBM_API_VERSION)) response = urllib2.urlopen(config.get(config.GENERAL, config.OBM_API_CHECK_URL)) for line in response: if line.startswith('MappingManagerVersion='): version_string, val = line.split('=') val = val.strip(' \n') logging.info('Server API version: %s.' % val) if val == config.get(config.GENERAL, config.OBM_API_VERSION): return True except Exception, e: logging.error(str(e)) return False def init_dbus(self): """initialize dbus""" logging.debug("trying to get bus...") try: bus = dbus.SystemBus() except Exception, e: logging.error( "Can't connect to dbus: %s" % e ) logging.debug("ok") return bus def init_openBmap(self): self._gps.request() # this is intended to prevent the phone to go to suspend self.request_ressource('CPU') logDir = config.get(config.GENERAL, config.OBM_LOGS_DIR_NAME) if not os.path.exists(logDir): logging.info('Directory for storing cell logs does not exists, creating \'%s\'' % logDir) os.mkdir(logDir) # to store the data once sent: dirProcessed = os.path.join(config.get(config.GENERAL, config.OBM_PROCESSED_LOGS_DIR_NAME)) if not os.path.exists(dirProcessed): logging.info('Directory for storing processed cell logs does not exists, creating \'%s\'' % dirProcessed) os.mkdir(dirProcessed) # request the current status. If we are connected we get the data now. Otherwise # we would need to wait for a signal update. self._gsm.get_status() # check if we have no ongoing call... self._gsm.call_status_handler(None) def exit_openBmap(self): """Puts the logger in a nice state for exiting the application. * Saves logs in memory if any.""" self.write_obm_log_to_disk() def log(self): logging.info("OpenBmap logger runs.") self._loggerLock.acquire() logging.debug('OBM logger locked by log().') scanSpeed = config.get(config.GENERAL, config.SCAN_SPEED_DEFAULT) minSpeed = config.get(config.GENERAL, config.MIN_SPEED_FOR_LOGGING) maxSpeed = config.get(config.GENERAL, config.MAX_SPEED_FOR_LOGGING) startTime = datetime.now() now = datetime.now(); logging.info("Current date and time is: %s" % now) #("yyyy-MM-dd HH:mm:ss.000"); #adate = now.strftime("%Y-%m-%d %H-%M-%S.") # "%f" returns an empty result... so we compute ms by ourself. #adate += str(now.microsecond/1000)[:3] #logging.debug("LogGenerator - adate = " + adate) #"yyyyMMddHHmmss" adate2 = now.strftime("%Y%m%d%H%M%S") logging.debug("LogGenerator - adate2 = " + adate2) #ToString("dd MM yyyy") + " at " + dt.ToString("HH") + ":" + dt.ToString("mm"); #adate3 = now.strftime("%d %m %Y at %H:%M") #logging.debug("LogGenerator - adate3 = " + adate3) if self._gsm.call_ongoing(): # When a call is ongoing, the signal strength diminishes # (without a DBus signal to notify it), and neighbour cells data returned is garbage: # thus we do not log during a call. # I fear that when the framework notifies this program about call status change, some # time has passed since the modem has taken it into account. This could result in effects # described above (e.g. the neighbour cells data we have read is already garbage), but as # we still have # not received and taken into account the call, we don't know that the data is bad. To # prevent this, I check just before reading the data, and I will check again just before # writing it, hoping to have let enough time to never see the (possible?) situation # described above. logging.info('Log canceled because a call is ongoing.') else: (validGsm, servingCell, neighbourCells) = self.get_gsm_data() (validGps, tstamp, lat, lng, alt, pdop, hdop, vdop, spe, heading) = self.get_gps_data() duration = datetime.now() - startTime timeLimitToGetData = 2 if (duration.seconds > timeLimitToGetData): #to be sure to keep data consistent, we need to grab all the info in a reasonable amount # of time. At 50 km/h, you go about 15 m / second. # Thus you should spend only little time to grab everything you need. logging.warning('Log rejected because getting data took %i second(s), limit is %i second(s)' % (duration.seconds, timeLimitToGetData)) elif spe < minSpeed: # the test upon the speed, prevents from logging many times the same position with the same cell. # Nevertheless, it also prevents from logging the same position with the cell changing... logging.info('Log rejected because speed (%g) is under minimal speed (%g).' % (spe, minSpeed)) elif spe > maxSpeed: logging.info('Log rejected because speed (%g) is over maximal speed (%g).' % (spe, maxSpeed)) elif validGps and validGsm: self.write_obm_log(adate2, tstamp, servingCell, lng, lat, alt, spe, heading, hdop, vdop, pdop, neighbourCells) else: logging.info('Data were not valid for creating openBmap log.') logging.info("Validity=%s, MCC=%s, MNC=%s, lac=%s, cid=%s, strength=%i, act=%s, tav=%s, rxlev=%s" % ((validGsm,) + servingCell) ) logging.info("Validity=%s, lng=%f, lat=%f, alt=%f, spe=%f, hdop=%f, vdop=%f, pdop=%f" \ % (validGps, lng, lat, alt, spe, hdop, vdop, pdop)) self.notify_observers() duration = datetime.now() - startTime logging.info("Logging loop ended, total duration: %i sec." % duration.seconds) if not self._logging: logging.info('Logging loop is stopping.') self._loggingThread = None self.set_current_remember_cells_structure_id() else: logging.info('Next logging loop scheduled in %d seconds.' % scanSpeed) # storing in 'result' prevents modification of the return value between # the lock release() and the return statement. result = self._logging self._loggerLock.release() logging.debug('OBM logger lock released by log().') # together with timeout_add(). self._logging is True if it must keep looping. return result def start_logging(self): """Schedules a call to the logging method, using the scanning time.""" if not self._loggerLock.acquire(False): logging.debug('OBM logger is already locked. Probably already running. Returning...') return logging.debug('OBM logger locked by start_logging().') if self._logging: logging.debug('OBM logger is already running.') else: self._logging = True scanSpeed = config.get(config.GENERAL, config.SCAN_SPEED_DEFAULT) self.set_current_remember_cells_structure_id() self._loggingThread = gobject.timeout_add_seconds( scanSpeed, self.log ) logging.info('start_logging: OBM logger scheduled every %i second(s).' % scanSpeed) # be sure to notify as soon as possible the views, for better feedback self.notify_observers() self._loggerLock.release() logging.debug('OBM logger lock released by start_logging().') def stop_logging(self): """Stops the logging method to be regularly called.""" if not self._loggerLock.acquire(False): logging.debug('OBM logger is already locked. Probably already running.') gobject.idle_add(self.stop_logging, ) logging.info('OBM logger currently locked. Will retry stopping it later.') else: logging.debug('OBM logger locked by stop_logging().') self._logging = False logging.info('Requested logger to stop.') self._loggerLock.release() logging.debug('OBM logger lock released by stop_logging().') def set_current_remember_cells_structure_id(self, id = None): """Sets a new structure to remember cells seen. If id is not provided, then tries: YY-mm-DD_HH:MM:SS. """ if id == None: self._gsm.set_current_remember_cells_id(datetime.now().strftime("%Y-%m-%d_%H:%M:%S")) else: self._gsm.set_current_remember_cells_id(id) #===== observable interface ======= def register(self, observer): """Called by observers to be later notified of changes.""" self._observers.append(observer) def notify_observers(self): for obs in self._observers: gobject.idle_add(obs.notify, ) def get_gsm_data(self): """Returns Fields validity boolean, MCC, MNC, lac, cid, signal strength, tuple of neighbour cells dictionaries. Each neighbour cell dictionary contains lac and cid fields. They may contain rxlev, c1, c2, and ctype. If MCC has changed, triggers writing of log file. """ result = self._gsm.get_gsm_data() currentMcc = result[1][0] if currentMcc != self._mcc: # as soon as we have changed from MCC (thus from country), we save the logs because # for now the log files have the MCC in their name, to make easy to dispatch them. # Thus, a log file is supposed to contain only one MCC related data. logging.info("MCC has changed from '%s' to '%s'." % (self._mcc, currentMcc)) self.write_obm_log_to_disk() self._mcc = currentMcc else: logging.debug("MCC unchanged (was '%s', is '%s')" % (self._mcc, currentMcc)) return result def get_seen_cells_stats(self): """Returns the number of cells which have been seen. If the logger is on, the last remember structure contains the cells seen while logging, since last 'start'. Returns a tuple: number of serving cells seen in last remember structure, number of neighbour cells seen in last remember structure, number of serving cells seen since launch, number of neighbour cells seen since launch """ return self._gsm.get_seen_cells_stats() def get_gps_data(self): """Return validity boolean, time stamp, lat, lng, alt, pdop, hdop, vdop, speed in km/h, heading.""" (valPos, tstamp, lat, lng, alt, pdop, hdop, vdop) = self._gps.get_GPS_data() (valSpe, speed, heading) = self._gps.get_course() # knots * 1.852 = km/h return (valPos and valSpe, tstamp, lat, lng, alt, pdop, hdop, vdop, speed * 1.852, heading) def get_credentials(self): """Returns openBmap login, password.""" return (config.get(config.CREDENTIALS, config.OBM_LOGIN), config.get(config.CREDENTIALS, config.OBM_PASSWORD)) def set_credentials(self, login, password): """Sets the given login and password, saves the config file.""" config.set(config.CREDENTIALS, config.OBM_LOGIN, login) config.set(config.CREDENTIALS, config.OBM_PASSWORD, password) config.save_config() logging.info('Credentials set to \'%s\', \'%s\'' % (login, password) ) def is_logging(self): """Returns True if the logger is running, False otherwise.""" self._loggerLock.acquire() logging.debug('OBM logger locked by is_logging().') result = (self._loggingThread != None) logging.debug('Is the logger running? %s' % (result and 'Yes' or 'No') ) self._loggerLock.release() logging.debug('OBM logger lock released by is_logging().') return result #===== end of observable interface ======= #===== observer interface ======= def notify(self): """This method is used by observed objects to notify about changes.""" self.notify_observers() #===== end of observer interface ======= def simulate_gps_data(self): """Return simulated validity boolean, time stamp, lat, lng, alt, pdop, hdop, vdop, speed in km/h, heading.""" return (True, 345678, 2.989123456923999, 69.989123456123444, 2.896, 6.123, 2.468, 3.1, 3.456, 10) def simulate_gsm_data(self): """Return simulated Fields validity boolean, (MCC, MNC, lac, cid, signal strength, act), neighbour cells.""" return (True, ('208', '1', '123', '4', -123, 'GSM'), ( {'mcc':'123', 'mnc':'02', 'cid':'123', 'rxlev':456, 'c1':-123, 'c2':-234, 'ctype':'GSM'})) #----------------------------------------------------------------------------# # program starts here #----------------------------------------------------------------------------# dbus.mainloop.glib.DBusGMainLoop( set_as_default=True ) if not os.path.exists(Config.APP_HOME_DIR): print('Main directory does not exists, creating \'%s\'' % Config.APP_HOME_DIR) os.mkdir(Config.APP_HOME_DIR) logging.basicConfig(filename=Config.TEMP_LOG_FILENAME, level=logging.INFO, filemode='w',) config = Config() if __name__ == '__main__': #obmlogger = ObmLogger() #obmlogger.init_openBmap() mainloop = gobject.MainLoop() try: # start main loop, to receive DBus signals mainloop.run() except KeyboardInterrupt: logging.info("Keyboard interrupted, exiting...") mainloop.quit() else: logging.info("normal exit.") sys.exit( 0 )openbmap-logger-0.4.0/AUTHORS0000644000000000000000000000667711226601771014362 0ustar rootrootCopyright 2008, 2009 Ronan DANIELLOU Copyright 2008, 2009 Onen (onen.om@free.fr) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Excepted for: Upload.py taken from http://code.activestate.com/recipes/146306 "Recipe 146306: Http client to POST using multipart/form-data " Terms of Service (http://code.activestate.com/help/terms): By submitting a recipe (or code in comments), you are agreeing to the following terms: * All submitted material will be made freely available on the ActiveState site under the MIT license. Authors: Wade Leftwich (http://code.activestate.com/recipes/users/98656/) Chris Green (http://code.activestate.com/recipes/users/1745761/) chris hoke (http://code.activestate.com/recipes/users/2022253/) Icons are based upon: * Crystal kppp.png Source: http://commons.wikimedia.org/wiki/File:Crystal_kppp.png Author: http://www.everaldo.com License: GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version * Crystal Clear app linneighborhood.png Source: http://commons.wikimedia.org/wiki/File:Crystal_Clear_app_linneighborhood.png Authors: Everaldo Coelho and YellowIcon License: GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. * Crystal Clear action db add.png Source: http://commons.wikimedia.org/wiki/File:Crystal_Clear_action_db_add.png Authors: Everaldo Coelho (http://en.wikipedia.org/wiki/Everaldo_Coelho) and YellowIcon (http://www.yellowicon.com/) License: GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. * Crystal Clear action stop.png Source: http://commons.wikimedia.org/wiki/File:Crystal_Clear_action_stop.png Authors: Everaldo Coelho and YellowIcon License: GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. * Crystal Clear action exit.png Source: http://commons.wikimedia.org/wiki/File:Crystal_Clear_action_exit.png Authors: Everaldo Coelho and YellowIcon License: GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. * Source: http://commons.wikimedia.org/wiki/File:Go-jump.svg Authors: The people from the Tango! project (http://tango.freedesktop.org/The_People) License: http://tango.freedesktop.org/Frequently_Asked_Questions#Terms_of_Use.3F: " Terms of Use? The color palette is public domain. The icon theme is also available as public domain since the 0.8.90 release. While you are not obligated to, we would appreciate if you credit the project if you chose to use the icon theme or derivative artwork in your project by linking to our website. This will help to strengthen the awareness of the style guidelines. Thank you." openbmap-logger-0.4.0/CHANGELOG0000644000000000000000000000655111231121537014504 0ustar rootrootVersion 0.4.0 (20/07/2009) ========================== * Glade file path not hardcoded anymore. Now tries to look for the file in the script directory, and one above, possibly under share/openBmap. As the usual structure will be [path]/bin/script and [path]/share/openBmap/glade_file. This allows installing the application anywhere using distutils. * Application logging level now in config file. * New graphical interface. * Added new image file to distutils. * Added cells seen statistics. Now manages seen cells (servings / neighbours) counters: - total since launch - number of cells since last start (gets updated only when logging) * Improve final logging message schedule. When exiting, the last message to log should now be the last one. It was possible before to see the message be printed before the real end of the logging output. * GUI: GPS panel switches when fix status changes. * FIX: sometimes both windows were invisible. Version 0.3.3 ============= This version number has been used in logs uploaded to the server. It was meant as a testing number for version 0.4.0 only. Version 0.3.2 ============= * Logging level of some application messages have been changed. * Moved get GPS data after get GSM data, to ease debug. * In a loop, time is now limited to get all data necessary. * Set the timeout limit of dbus get neighbour cells info. * Set the timeout limit of dbus get serving cell info. * Expanders set to invisible. Version 0.3.1 (never officially released) ========================================= * distutils support. * Debian package. * get_serving_cell_information() added using FSO monitoring interface. * Duplicate key in desktop file removed. * New GUI first attempt. Hidden for now. * Button images do not embed any more text. The text is now a regular label under the image. * Button text is now "Start" instead of "Generate". * rxlev added to serving cell XML log, if available. * timing advance is available, but deactivated. It needs to be logged only on specific situation. * Application logging level set to INFO. Version 0.3.0 ============= * Now you can trigger writing logs to a file based on a maximal size specified in config file. * If logs in memory when exiting, they will be written to disk. * Log file name now starts with XML log version. * Added MCC in log file name. * Neighbour cells log re-activated. * Ignore neighbour cell if lac, cid or rxlev is 0. * GUI now says: GPS is active, and waiting for 3D fix. * Fix: GPS time in log is now based on GPS data. Was using the locale time of the phone. * When MCC changes, write logs to file. This means, a log file, only contains data related to a same MCC, that is to say, to one country. * Removed ambiguity about unit in config file. kB (byte) was turned into kb (bit), because turned low case. Now uses kbytes. Version 0.2.1 ============= Bug fix: when signal strength 100, GSM data incorrectly tagged as 'invalid' Version 0.2.0 ============= * Software id and version added in generated logs * do not log if in a call * GUI added before upload to enter login/password * requests CPU ressource to prevent from going into suspend (depends on the settings of the phone) * GUI added after upload, for deleting processed logs * Reads GSM data at startup, no need to wait for a Network update signal * code for logging neighbour cells added (but deactivated for this release) Version 0.1 =========== Initial version. openbmap-logger-0.4.0/ExitButton.png0000644000000000000000000002261611215240503016102 0ustar rootrootPNG  IHDR_YXsRGBbKGD pHYs  tIMEpЕ IDATx[ytO^]\w^@$EIH [R$+Nŗ8RJ*T\ʣ)\[TE"4i Bpbνo䡻g삲Se{CΥwNno|xr6aނ!]Q@kMÝadif1|<==?Zȏ¶5D#Ꚉ!"C ~^x$ORv&8Ǝ/%hM4WWͅ;/\J><=왛;9>5u455W "~Oq3Yf~63<@>^[fm}77_ۿp|q>#O=J%eu028B lpJ6'$m6vzם_~/l7W7 ?WϷ |>|矙{\a\(# P0iio4Ur 0"53yxq B)%: S_eGWΟuxjd+/<zgf|q&&h.:^r]TFZ€-H5,WDg1i|X0>NqjcǜT8199i/*~& #G~gyaڻ͕MFJum*+kR tf3RXmHhJ4(2q'}F¿/}t| JϛΡo}@uj7Fci2ZcE2~8}=0?RF+vt[[x *{pqeM߿-۵_׿쳿r _N\Fy^dzc K](dwr"Xh Ju<9߽>c<Ϯ(gJ|_|z -vy0,ߦ T1^KOw]VuA JuM6ƽ\ CfbrD޽;[`~B#G*F0OTh a l=X60Xg౉IPLh?7š!x^9AVbQ▊/-Ç9C[)~ {t 9n czeUgpjaxbd:#H2<&eϣ0=Mal KJ*T( 8²(E^ɗ0xDM"Th./}=8{pwAqp!Blp؀a̴A'l>T<c#142BЪؼ}֝;4u 6~ge&4I"M5'@hmaxbgRRf|nwk5lR:9Ƞ:+IL(3j\Z&H6aL^ǭ[-r 4Yf\:̓%tτ8p "Uaxea;Fe3Y69ܤqRʈ6x¶BCVïVqFG;0#nia2 4OLHف:AaP*L5 v޽ĺ/M,tj*":Aص.~##h4 4}`wZdK k̬5){5ZhIe8A;pa{C޶Dj}Z lzPa-t]F#2Rc)&3$-}$gbI RFd֌tQ\I;P zb֥q+yǞyVۓ!aLCs&MKcB)Z*˲iju);TVr25a996v"NpVT10KJHbq 0$}8MqZ{;$0San[FJNU)`HJ&EErCO6jQNiLb #ej|?Jup>ZvF֨|aFgkaadx8zvj|cZ8C>pXDn"MF,QD_Ԍ}P[[0Dҿe BϋS7af;[50irSSX<~JR!jwI"34mOfQ O}V/]~Uz mzzh2JҲЮKAdwk|S& jL-( ֶss>G},) ͠Kl$YdoZyMZK y}Oc^KK 1kJk5ݾUSds#8ͭ-dDN`Iz5 )[iADUpy(Ϝa'q`ykݹC76Ɍ. ץqBYaMN"3jON23MoyX\'dn\DH`kt  0'9z >:|ᗖ|M6^}hD4p1kkTO?e)<(2#ЧoǏ+ݹCpV"hUvGӅ@B--*@l'6v[-LWjZj~q=P,E KXϨ]H6ދv3]!P:kJ`e?=3389쳴}dmr9 ޽hl {0"vw%XYw Oztf{_ڏ~D 67KN.`T5#%z<| /`P Obw ѾR\D-/_6m'1N?z* )=8c>JPhklS*E0@n$Ĥ\aYׯh6Ecc}ivqr©SPܹ.\ fD9d<va; b"y7<,y@J>4>K[w+unO;vfeqo6OYJrǎ!Ş^Q(Q-؈BJٙ@l`60J%y{{4II 7!^.u!"H D M+W>``q9|Ө&n+,-`I%kE?"e༎OHZ)r;5{l.шh_^ǻs`cw}܏?FU*c&RKK ۿGX1GF1@X#Y`;ڬļcA>٬ƍQ{ɧjd/OMO3Xcc%aFp/^DαB7o67d4#4FDa!z/I!bBbxP6k#i3mQm>뗖h-,c9NP]uh+.D]aHMOGpW.xu꯼,d.sJ5EX= LL@w'qD&&cB_;Bz0>5@@ČfQmEN#6fnHvWc9v80kk:دMhvhl,ڜ^dzloHjUjerO#"GNLqE,g ?myOulvQqrU6kH5zkt&)@v$l$+6WL9'̧j5QKȑHx~g2$4$j:-/$ #74DnddG"ZW%i"IUDz jr );@ݻGx>4b@K&gP.cǏ;7J#mOI'ɊHx +EjF:=ZmΨ2%IYUћh$F."t􉴃l`avW[c%Yol6Я j~"ܔ.eJuJV8Vo3gfZ4nP͘&v߷*]T38AR*j hێ 󻶄f4*~1ߗLRfeV&!l h)ѣ#ވ *QH)ĨY&Gl3VsX]λ )dZF]"j5h"A8S\m¡CXG>V\6j=4#qj"/o6 \AbXߤ6=ԾN+揄u¥fD,"HBFc)RM?~R)J{{.]b*C=<˗[[0DhS |<cE+mLGt4eѭVD]i-΅6$$:$e&KZ㭭Q=ZOx^(0q#_*MܫW{9yG %ƥc +Tl!JpC_EΞo`IdO!cLOd o;IIh[w]|By™=Y{7kk8ɥ[G}˳JmK$R t5ÇwyU/V##Qpde[+hN׉&IV/3 m~L'?v\]0v&gZmOy!E)+h-_јo0_+-@kkxubk Gt߈5 8pkOk,iv(kX5~\OL0tX RLM1rJ"E]t} GfPDd$1zN>o6.2jY*sm7Pr8_k^u1#=vCtN? =ڿ@=<䗿 Zv[Ѽt cd8P@m7M(]hϿComFMvB=s%8 x2/ċ/b}8>R2} #'O|8G؞UWNSRw8}Μa[gwn\O} Q*!6#"ځXƗ5~tl"Oz>Bk}|~wG63_C9joEUDֆ б*pNf1z)?ݧ's6i#G o7ϻ -HdA0',@;A $yJ=+Hn4&: d56sCp 7X;؆In?9jo fŴ/2Js"ƭW_E!޽<,v:ܻwQZT;  pq5꽨 ɥT d_٘]N}H5Fwaw~]&u.$vawVQk4i?G,GiN#C6D+ƍS*3,>,'k"$Qz;{\a~cix*J~b=bwnD*yV*}c?5*ml0Sz){~~ /r.y 2݆Ѷ+?6|+U1W5']{͏>bϯgϒA EKJp֏~@p#D(cJ;Xiv}')Dt]c~$ q36_}Kl_0˿ٳNѦTe w~vWn[M쨼1 t<7KSA5 f5P*a'AD>o2{_{ɓN9t<n6 ~z%+ o@@GA5gG)1*e_ S@./ܨEp]YxE-zPi]H?f'(<'?==EQXtD-/||W?&q]o ,4:ųΡ 9P(deC" @onv]kqidY:7ޠX]*EwĞXIRV[P]"\YA^HK" yX:N+v2R[EMX" \?l`55oBַDeTZ.vbߺ6oVGy;wN\!-sUhqٲbh]hu"LX#jxw*('DAO bk~ vn;*xIDATqycr_dP4 Ra]4VklFZNaX 8Z( FjkRYR,A,)h6WZ?gOW%m<݇4^ەv>Iǎdȭ;F*:7/LU踁֚ݏz{EߨVo|ׁ2x;Kww?qBO<59y(L}zK6ZĴ=~,+tMO@kǰX|J#muJVe/ 33?5R*jV >e~L )ZArjtvw{ur\=BGw~{x \)c' }>rݸ9bod2ePEsWKܾ} U2_Rӯߗ>y'kѶL+⭸ز1=2~>zM8~ݶNQƚKqA¦osC~*+&N3EV}neɵҿ;i6穕xKKQ*>RT G4BwK R |V6iцeNʇq9и,Kd[:jFJ0GۇlWrs[M> p(XϞݿ?OPq#T[F%D6d?gtVV_3l7& v~CD Cdڧ~wo6@{ςr9qX'xèS^ kS9ؾ}F{g rdюٝaz^6yB=3hA>z1HI+;Mު-,k6?]h}~'pЬ PP'B"4$̖/#/ >]*?6R*JrD⾞dUg"2vk<QîN]aH6k(̀8 eTBkFzU7p*|B0򤀼`&azF2׶L챜eB&3\\T$@TB5R٤nڈau*j| ( 5n($IhFaq1^Lc@D@ոWYر(ŏc1OA %IH&m4 ~nՋxyp {IENDB`openbmap-logger-0.4.0/GenerateButton.png0000644000000000000000000003357411215240504016731 0ustar rootrootPNG  IHDR_YXsRGBbKGD pHYs  tIMEL|B IDATxiu&˷߭Ud["EHx^f"G&G26cO O HH$5cZM%M{wɏ_.Us%Y?T7k=9ysN$Ps J3R JU^'L(ApH glRƶ)%{,W[x)U(Uh} Kcĥh$ ZB* ǩBJBJ]hF( n[pcOſ?S[E&ϹCJ7"oy Q0p.|1>G E)Iqc:N^q=eazlm#Ry?EI=ռF >G}! \sM_yԎ^|qg瞻kQС4J! ԮS挂R B VBBJ e^!@(8/RF&^y}{;&?Y$//~7V-~/\t"_%A*BJihm<]x>@))\Ck 4V(K_ sc`2Q0F1emG_}|;߹BO8w~a?2˟{;[ /?|7 KO>EOW$JPBCHcX1mPM)QZiHMQя _Ri2 J=__= 2g c4L' 0kE)UwJ)4Lh*3Ɨ$X94L.!:p8V)L"n4UZ7\/s0~eWj|voI[_“oڧ٧#N d0 B=S6 T)(PY^"B@*葉rA:[†$?Wic|p/Ϊqf,h}\Zao0eq1[<+1>U?mփ'+HE)*q3F E)f%@V8lLxrQ!mL׺qZiȱHJ)XL) APF99RGkzX\,ܻw-~$?v/^נ1󟺶ۿ< aH8Z~l~R]mF)1;/&IRHxG`{> TIZX=6( YLN+i! E.B0@(Q/Z__kqJWp]˩IbRU/vhwUxp\!*DHl,/^LdRUHg^\}x 0c)}!2LZkH{BL7%q{W5>KAԯ1J92>c|$-li:QF'p.ZJj(-wv+BM2HpBѨ8}VJ2hm0I$iFS !% կ'j}"^zs^\rn^'?YQ{Wϑ'c ZA (*O&UW&B7A7;pqVpFquX둇QivfoJ݊.<1jMR#@jQ2F&qӯ~n3GxpVio9<:gƓHzX˖ @QM2'rq:})aӏ'HԆXb;4/1䠄"ahV !J$(44B( @)KS_<*|oq*x~tZwl?}e ]_rOP8BJ]Y `xcR(t1B43Is2]jG)8L*BJ-7qvzhh'9zôBCkazHrSuKK '4F2ۦU!z(ǃ>N!Q:?tA6.YKCBBPjWBk4/q؛7LLK /Jt T$W% T@(19QĕU )du#Ra0JMKIzinqQ4!S 3\ZkBH+opbpy} kK-,̇hp],q)ON֔8G z1T~&$)M̤6!j=A l {0RqPJlPV5`~F#f=p'I~n?P'u*R#$6w$|^e=[?S?9Bȿ^ \YJFrI ])U0πq8LoT%iaP)1I a`F *.,%8}l5BD $+&$YQU R[ ,5Do; |#KIs<_>B߅1@8Qjh+.DQpF_`8eeE)D \XB uB5|ceV7l*PJ nj)ЬX]h7'VO7?ol|Q絆Jc/K B`%%ҬZXYl Kg9mly/DYʙFA(k/ :\zh}Tc.|ρJ^uS<cb@w0aoP|FH`y 9!Iz!M3$ e9A`p4|ҬDfp2T(ִ1@V܄!$NtEAheR0\|CJ ץ2#RVEҀ&[$j B(p55.pk@yYԫ)賔(R3]pb}hݻ qRT$V; QZ"hVc-:R@^JRN=+(A ,{ihBBbyg:}X@Sj[JSܯ,+f%ȴ! s@1 0W#Oey_#zO~[}?'O9d`AzO^;Ct@Sh,G%y!l#\(-R*.Pd@~SC[!\`8ΐK u\_28~eq?Z$)!zǠ-#:}BHˠ*L&%X սR8'a̳͒[/ïZR@%=Vcrq +:(pbbu")\#@-$GXl[ȱ@QBNQ@b LH+ .ͣY0(K F` QKR`p.@)tՈv8!kZL7ȏe|#OLiies8&Iov8óqnug[FK ʅ%l޽}ܼ;g8:!mw{ۈ|IV?JMfۓ0i3BR@kZyBID*m:cʢsYy)ARfl5BLRHs5'4#oF|%Zk gpaq1w8)ڻ[9>Kh,4p|+ Nwnc8s $-P=,pН`hJ)+)R#B,:V<,&$LPpƐs0!dU"@já~ EM~1M&UߙQ!(P& W`@J]8D)$6xv6?-7J8HG M$2Uk";4CYx)VP8 K&7HtՠτaJE8ȲDoopk06Ԃ87QJ%X[??wL%۫?s;U-G]16p9qIB# P`ug! G @;pFK^ynL^ -%i{=\\kcu/ӕVd,SP*24:1UF'YѤsKukw&<ͽZEuca/9|^t'B5GQ ljo$Yfg硔Q )%nA3&2J_B !Cێ[7P<,kgZ)@ TtV$ٴZ-W2LϟR 8Q<`s$-MzOwaxvGu;]#jJinlߢ4L[$ҴD^(L:SBzqckF(扆,W\y?e)|Ďz J*m;'9Y1]+c(B\8;3M&BEQqa׃gWp"u#pF1 FcIs95\u#a'AQIWUe;wv>% 77ov>kQq1cm]n[МbjRDk3m*㢐(ʪ b\9cK `co4yRB໎i 8V@SWWPAu~$G~L W XR))Y2!' 1R:m 4c}TӶ ݍ.B*ӗV=@" \× 3@9jZe 4:!C(Q 5.pf6w 8B!J$aV<w6;5|:u$G^HG k:p!tP4j2Z55>l[#1ggW8ŐZE<֖Zy!y jey,P \y-m18w7{h5\A +&I1J+E PL{IafJi g1d_m{7s0J JVZPZL NJ58&IB)(TBe.9@=-8DoY01(J޾AaPO#*R{cs kyQ6"V"Zz䣴b"(Jw`X]jaq.#%TEMh\k6zx3sJ\攆iP/q:gN=YN=Rk<*.\1~)W/U:ZgZN)aTaJHBH@xhjE.lt0?aؑv+BpK0N j0.QS,P<䅀pv:N: A{*a/e*[U|!~zHZCVЋچ9 ($ꑏspԝ NB UأQ8-Ѭ{qWIˀZoWi𧻓N7Tк 5>Ҭk7vP ]B;acwRkT[ig\PTp;Ra<)=uiO_YAw Xw'sY?:j4 1gFfO]SAg'XA^VIV<} Hi3=> ̤TpǎvaK( |=[mY%޿E{ 03wH ց\+ 6 vv+0sɷoFwtqAAb" 4uf2JEl h.ԄBFQip{8E{.c니B8CgC(Jީȁ6hbRHx.JzRFyx!5pȬc%ӫ͹RJ cP4"KWh}|K8NpP`X :LATm8h5k9Pa!ҼQNҶo͛۸Ӂ).2dy8xY()i_mqBHe0)|ó@NUk7qVO_RI+OaʯcsT\1{@Em72 Ms? p9Ch|Q(u'H &I0q\\kyMR;OP^7hc7e:ؤA]P&A?Fk(\M*Zago YɫgPys stئg ;7W.ouq2?!ڨt| <2̭l畬DMg(~4/KBHwG Q"{[k=?l{Pّ,vɛr֧(ZGڻ<:~㗮0ԣ̞3 "Myx/fz@*z<0S( P NwAj(oߦ"C${=LRiLíC ?y#}*De 4 (tQ<8.Lȩ-Go7ǧ♫54k&q^:n~o^yc>@?$<#Rx `80=Fq4;y,4/*`dh5LOxjmwpzPncLC*nKHEvHdm}P*UZue!#9f3fH~yz<7iSͷ|CKP |\2]yЅ8xE[f&aRAIchbMPĎƹh<Ě 0UNoccM.BB*lĠu*D{Ei:F75!ӳD!oUPo|op~ߪZˋVjhχp8-~=y<M2Dסp1~'Y)9ZJMF R $Cc4 [PLO7qwc.삎 KoÍ;;SB+f RM`{=o )UPq&w"~0)J_3)X`QV>''cD3'B\dAaѬ{pma`uϿp6-)nfsjsq!gy$PAX(qR N BkN;]q8{sMg#/4 R 5b![` (d2 ׮R,2$Q&WSO9oCx t{ ά0?:\f10,̅&x>DS( UD从 keҼ9 a¨tYqB7Ko܅R8Co`gpF 1 %:c!Aٗ7T9|`ܘqhS}ϯ~~h8t_ 'n? $шj($:(NdJ\hsb^ cXZCQbjlw8B;k*#=u[u8;^ډsiQMSfe'>T =f=@i6~1!O?/GF36,gT㓙<@mp8m| 4Ζ| B|R4 qVͽNefgt?&܍l<QJ13wAHDpR` c7nZaQpW ;PxT,Ӷv8sPDk7B$?;.JF-wބ*abiP衏zb?6+7Ƀ ך %#ReXn\nZ]-\(R;N!5@ЎcLC!GJij0߈RR)iBH yQi的˭$1X5(E=qfyl rrFE-gOpO3]Kv`'bd0J(tt `8J䛒JgpBŽ^; VOU io8qBxLW*8@u(F,]'Di@e5CDih3jyk"[!#ًw7wL2nq;Bjt9)^?ktǜ <5T$m0, C9 k(Hl1gZyCϨ }rijLbԈ:L <2Irx.C{, S$)٥L[e&v29^Kp++RPC#/%Νm9w2>O𽯫hK[O5{gc=>pTl<ˤP Cw8b;=Q <u~\=#+Jt&Bq⯿!| 8l&]&IϱD^ 9BZ5Iǫ|IE9T'tÔFN`FbifL5,5'֠5𕯿Z h|w^SfA8|.Gb[2]x:+4 ^Vg<ϔgJ SYF@82;E ˱7@8PG k=ttQ](J4\7H1(E=ѝEfqәg /O]O1iC26"w\? jTRJ@+d6cIpj:!Lˮ=!TQD~LIW#%VY)lY'D^8ܸzýUe< ޞljB·߿sj֕TKQq FDPr/ܫœlNKjca``m3M4>V"96I* ]cm( x?H1I$ H3x{ۛ^~F3@cjd g0|aF| l;Rj.`ع}viqRJ)mts+E5]i`yV#b;B{.B+DP 6]h PJ3;1z &q4+xu=׳&P '3F? ?wpwp VńJ~kʹ]xzka}ua.0ps\fs3ը{=B8-N-΢0fݷ[ tbbsoNoٻykkPdRX kӒi |D1yLsfI&Zm///]\_X:l6Y|FA" B2 |n}0Tl%WDHsP(FH )z;?;<2KN&5>Ng`=ك3^-}s+ۭV~A๾wypdi:|@*QՖRUnBS1p8A{wp{pT(fY4Y\?Z(0r l qܠrqyeʥ3fkFfyq8ᜁQVQYD(Bi*dOF~{9?ܻsw{;wz֘S0M''ġRj3p 3ydwx6 la èYz Zuܐ;(ㄘc:+o$R )(HѰ?$x0MQZɸ 2>9a|y^=āZ>õ :IENDB`openbmap-logger-0.4.0/Go-jump.png0000644000000000000000000001145211226601771015321 0ustar rootrootPNG  IHDRYYU sRGBbKGD pHYs B(xtIME,**IDATxitTy]f_ cˀv;=n}6I}IĀ8uӞ&MBllEhX"b$aE4Fާ$" 39;Wwy/\"E.r\"hU[t/V#/#bx`cD|`] 8CLoi܍ni9c |L6Fxx3zc)w/؟C(fTUT nN& Q!2@QF0z{)+}Q"{ y.HZD~v1B_aGmrV ^k1W+qCK2Νkp4Ȉ!̆vJ 2rvםwع1}j?F # ǧ# fȂv \\ Ӊ7`[۷?,O}IOn[^uPZN\cYr9J,5p%:;Git|h q3ŏuO 6 m&r% +Ҍq?n'm]u3CW9εAjhm#yS;_Pf l ňBƔ9%NW>m*EVэѡqIA?W,D\(wmlY2a vmvSB u,(cIy E[ֳU7zY >j/ nS)r> `dC1"!Akйz5T< ٸ^WWb_MSGB9F3=7>t7 ndBrnDXߞĹgx^aZAzw 71@`,޽S&ю`b-o"Ҳr:,ɿ ]=8|5lܭ=vB&8gff@ߥapEslږ{EK&/Jغq;eA{6f߳[2("?=Omzg{ÙӈhQN<#ZŮxᵖm*@tH6(F:0!DwEx9/r럒׀-|yLW Rc[sq}k^:zS*C(+/ZuN1e0P8̒ EJ(ZcCŕtO#'(]:6n=ˆ+aA߳nBxk&B(u֠Zu%ȼߋ#0KW1B)9+kIn]!98C O4 0NqB 9j O[M'=ymNTW O2E7, gar }(_@.!ݝ&PͺϞ%+'j׏~]lo/v!סhN?ud>K_5ܖ1,2`b`2=cs28fX (5 ިU%Qtu*;Q̺h&RtS!u8ͮϋ==Z jL+=+J3l%..Qs_ʕdj'SL ^qbaLJ@q^lMl85S< |,AXP7&k-r#a:!dîS9A^uܾhJdh6/&AN.aJ+0xpPrS Km;(.' wp_&Z (iɟkn;nC.) \u53fkqxtB 8pK3AŒx \ 8v24S(Vx%G\,ٲfbKL.pvs~!)vt F/+ $ @LYcd@Mƍ%raq%zs IdaЕ0\M*E 8}I&1Hp7;;"*WIec3^\_1 W*D0&@`UDA0yxXR<+O?FFB'}{mz$$@U -uԅ?ǽUDL>ZU-D#0Ʈ OƄ)T,Hha /}UvmI*8K\)#OV5!t /}@b iϹߵFFj`#gM@_#wm u-R #83.T" 3&goA > 3q#cp-,_5@-hlƛG~Lgrۦdb~xF{x#ܧQ{*Ev``"HU}[پlkVyq~WgF~q&"qaP+2Ս|[9T@B[k~{DZd&oqa2t]x{ nvk`z.}w-hQ]uG?0/nOtq{A͈(c:I0au6TyjμV ^㻝3ZZI33HalG+{)G^^>\1p3n!x%8tU fYA^'s:TSuIj/^ʹ9K8a:g+EBB5_ +r,š`C^h$f3W _`4 *Z1Z*VrX58' vC`bj0C%0,-X%!0.FɣNqi*sD1.dWLi BFɉq*-G - _;ӗN?2.le3#OvCSAXen_ =]|+<C8x%tw^#6g|sn'OeuW*KRXH1ŧ-|PpE*]3lZNӤyyR,18ڍQE cNK3ܥ݁lΐ?'-yeYNXz& ؂m*Y)L7f/,QuCki#ttٳ- θN?>DWd)w&NCWN4MZH/5IV%ƃN8-PJ*ZZu Zg7])!@f|8tgj%ϴ1l,uY<%kFSa(Y2[p[ a͈%8s,#!/>GxkKpVx$Pw&V2[c,\<t8]N\{UFGKXAVT3ڇdWz(C qvr/ؖP *?0Ή 뻿0l}RZJM&r7bo76!E*83eWYy,y'xb/}Zt|s۬' S)9vdxiӬ2{3g}s܉XjʕZ[AsM{c.-L]e>}\]J yJ{͠hi]FA3OOl;[c,!C0i;Ҹ"i)> pa&# j"A3Ae\l=ӋM[ZJl3>@@F4Nj)ԙ,!b eh!tJq|ZE{Jb)B~:y) <[Ugg$lSe J # F3#eXL3/\Q022Ҁj<BR 9]Z[(9+B4mh!FB+x^Гylsr\"E.r\܄6 xIENDB`openbmap-logger-0.4.0/Main.glade0000644000000000000000000021673111230072643015161 0ustar rootroot True True 4 2 True N/A 1 2 1 2 True Altitude : 1 2 True N/A 1 2 2 3 True HPV-Dop : 2 3 True N/A 1 2 3 4 True Speed (km/h) : 3 4 True N/A 1 2 True GPS Lat/Lng : 0 True 2 0 in True 12 True True vertical True Cell id center 0 True N/A center 1 0 True 3 2 True LAC : True N/A 1 2 True Strength (dBm) : 1 2 True N/A 1 2 1 2 True Access Type : 2 3 True N/A 1 2 2 3 1 True <b>Serving cell</b> True label_item False False 1 2 2 True N/A end 1 2 1 2 True CID/Strength/Type : end 1 2 True N/A end 1 2 True GSM MCC/MNC/LAC : end 4 2 True True True True 5 11 True 10 11 4 5 True 10 11 2 3 True 10 11 True 9 10 4 5 True 9 10 3 4 True 9 10 2 3 True 9 10 1 2 True 9 10 True 3 4 4 5 True 5 6 4 5 True 7 8 4 5 True 3 4 True 7 8 3 4 True 5 6 3 4 True 3 4 3 4 True 1 2 4 5 True 1 2 3 4 True 6 7 True 4 5 True 6 7 2 3 True 2 3 True True 4 5 2 3 True 2 3 2 3 True 2 3 True 4 5 True 2 3 4 5 True 4 5 4 5 True 6 7 4 5 True 8 9 4 5 True 8 9 2 3 True 8 9 True 7 8 1 2 True 5 6 1 2 True 3 4 1 2 True 7 8 2 3 True 7 8 True 5 6 2 3 True 5 6 True 3 4 2 3 True N/A center 2 3 3 4 GTK_EXPAND True MNC center 2 3 1 2 GTK_EXPAND True 1 2 2 3 True N/A center 3 4 GTK_EXPAND True 1 2 1 2 True 1 2 True MCC center 1 2 GTK_EXPAND 1 True label_item 3 True 2 0 in True 12 True vertical vertical True 2 3 True 2 2 True Speed (km/h) center True N/A center end 1 2 True N/A center 2 3 True HPV Dops center 90 1 2 0 True True Lat : center 0 True N/A center end 1 True Lon : center 2 True N/A center end 3 True Alt : center 4 True N/A center 5 1 0 True 2 2 True GPS is ON True Waiting for a 3D fix. 1 2 1 True <b>GPS</b> True label_item 4 True 2 0 in True 12 True 3 4 True Cells seen since True Serving 1 2 True Neighbours 2 3 True Launch 3 4 True N/A 3 4 2 3 True Start 2 3 True Current 1 2 True N/A 2 3 1 2 True N/A 1 2 2 3 True N/A 3 4 1 2 True N/A 2 3 2 3 True <b>GSM statistics</b> True label_item 5 True 3 3 Menu True True True 2 3 True N/A 1 2 True Logging is 6 True 4 2 True True True True vertical True GenerateButton.png 0 True Start 1 GTK_FILL True False True True True vertical True StopButton.png 0 True Stop 1 1 2 GTK_FILL True True True True vertical True UploadButton.png 0 True Upload 1 1 2 GTK_FILL True True True True vertical True Go-jump.png 0 True Back 1 1 2 1 2 GTK_FILL True True True True vertical True ExitButton.png 0 True Exit 1 1 2 3 4 GTK_FILL True 1 2 2 3 True 2 3 openbmap-logger-0.4.0/README0000644000000000000000000001674411231121522014151 0ustar rootrootopenBmap logger version 0.4.0 (20/07/2009) SUMMARY: ======== OpenBmap is a free and open map of wireless communicating objects (e.g. cellular antenna, Wi-Fi, Bluetooth). It provides tools to mutualize data, create and access this map. The purpose of this software is to log GSM data, together with GPS coordinate. This data are sent to the website (www.openbmap.org), in order to build a free database. In order to keep a high quality of data, we store GPS quality, speed, GSM signal strength, etc... This is what makes us different from other similar projects: focus on quality. This free database will allow research and experimentation about location algorithms, security, location based services development, etc. Possible uses of this database: * get your location based on the current GSM cell you are connected to. (GPS needs extra power to function, GSM is always on. Less precise than GPS, but enough for a lot of usages. Instant location, GPS needs time to get a fix.) * speed up GPS first time to fix by providing the location based on GSM data * geolocate your photos when taken * get a map of GSM coverage * get a map of 2, 2.5, 3G coverage (not yet implemented) * ... WHAT'S NEW SINCE 0.3.3? ======================= * New graphical interface! * Glade file path not hardcoded anymore. * Application logging level now in config file. * Added cells seen statistics. * Details in CHANGELOG. WHAT'S NEW SINCE 0.3.2? ======================= The version number 0.3.3 has been used in logs uploaded to the server. It was meant as a testing number for version 0.4.0 only. WHAT'S NEW SINCE 0.3.0? ======================= (Version 0.3.1 has never been officially released.) * Debian package. * Button images do not embed any more text. The text is now a regular label under the image. * Button text is now "Start" instead of "Generate". * rxlev added to serving cell XML log, if available. * timing advance is available, but deactivated. It needs to be logged only on specific situation. * Application logging level set to INFO by default. * Logging level of some application messages have been changed. * In a loop, time is now limited to get all data necessary. * Details in CHANGELOG. WHAT'S NEW SINCE 0.2.1? ======================= * Neighbour cells log activated. * Log files are now much bigger, you should have less files to upload. * If logs in memory when exiting, they will be written to disk. * Ignore neighbour cell if lac, cid or rxlev is 0. * GUI now says: GPS is active, and waiting for 3D fix. * Fix: GPS time in log is now based on GPS data. Was using the locale time of the phone. * When MCC changes, write logs to file. This means, a log file, only contains data related to a same MCC, that is to say, to one country. * Details in CHANGELOG. WHAT'S NEW SINCE 0.1? ===================== * The complete process is now done through graphical interface! * Neighbour cells logging code is present, but deactivated. The reasons are: - we need to clarify the meaning of some fields - we need to clarify if there is no risk of mixing cells and MCC/MNC at the borders. * Now displays GSM data at startup. No need to wait for network update. * Before upload, login/password graphical interface added. * After upload, asks about deleting all processed log files. * Requests CPU ressource to prevent phone from going to suspend (this depends on the configuration of the phone...). * Do not log if a call is ongoing. The reasons are: - when in a call org.freesmartphone.GSM.Network.GetStatus() returns a lower signal strength. - org.freesmartphone.GSM.Monitor.GetNeighbourCellInformation() returns garbage when in a call. * Software id and version added in generated logs WHAT YOU SHOULD EXPECT: ======================= * The complete process is done through graphical interface. * Requests CPU ressource to prevent phone from going to suspend (this depends on the configuration of the phone...). * generation of logs (no log during a call). * logs serving and neighbour cells. * Graphical window to enter login/password before upload (possibility to cancel upload). * upload of logs. * Graphical window proposing to delete all logs already processed. * Seen cells (servings / neighbours) counters: - total since launch - number of cells since last start (gets updated only when logging) MANUAL: ======= Interface is straightforward. Note: The GPS is started as soon as the application is launched. And it keeps running if the application is logging or not. This is to prevent losing the GPS position if you pause your logging. You have to exit the application in order to stop the GPS. The main window displays data about: * GSM * GPS * GSM statistics Seen cells (servings / neighbours) counters: - total since launch - number of cells since last start (gets updated only when logging) and the status of the logger (running or not). You can find a menu button which brings a new window. This menu window is a grid of buttons: * A button to start generating logs. Values will be displayed when valid. Logs are stored under HOME/.openBmap/Logs by default. GPS data is considered valid only when we have a 3D fix. * A button to stop generating logs. * A button to upload. This pops a window up, which displays the current login/password. Please modify it before pressing 'ok' button if needed. You can cancel upload by pressing 'cancel'. If you press 'ok', this will block the interface until every log has been uploaded. This means that if you do not have Internet connection up and running, the GUI will be frozen until timeout of the upload part. After succesfull upload, the logs are moved to HOME/.openBmap/Processed_logs by default. When upload is finished, the result is first displayed (how many logs have been uploaded out of how many available). Then a popup window will propose you to delete all (this includes possible logs from previous upload) the processed logs (located in HOME/.openBmap/Processed_logs by default). Warning: you should create an account on realtimeblog.free.fr website, and fill a correct login/password in the popup window displayed before upload works. * A button to go back to main screen. * A button to exit (if logger is active, it will first stop it cleanly, and then exit). Config file and application log are located under HOME/.openBmap directory by default. You can modify values in the config files (by editing it). This way you can have a fine grained control of your logger: - change the locations of logs 'openbmap logs directory name', 'openbmap uploaded logs directory name' - change the rate of logging openbmap logger default scanning speed (in sec.) = 10 - set a minimal speed for logging gps minimal speed for logging (km/h) = 0 - set a maximal speed for logging gps maximal speed for logging (km/h) = 150 - 'openBmap.log' contains the application logs, sets the level of output application logging level (debug, info, warning, error or critical) - please do not modify other values, this could prevent the logger from working correctly. TROUBLESHOOTING: ================ If you break your configuration file, just exit the application. Delete the configuration file (by default: HOME/.openBmap/openBmap.conf). Launch the application. The configuration file, if not found is generated with default values. KNOWN BUGS: =========== * when you are generating logs, and you press 'Stop' button. A popup window let you know you should wait for the logger to finish stopping. Under FSO M5, if you press the power button, the phone suspends. You press it again it wakes up. Nevertheless the GUI is frozen. You will have to kill the process. openbmap-logger-0.4.0/StopButton.png0000644000000000000000000001633411215240504016117 0ustar rootrootPNG  IHDRYYU sRGBbKGD pHYs  tIME 2i\IDATxy\y.o߾/څ 18. vbV5a0N<3I9*W&+J2I`@`028a $!}{{q請ߦ\ܪ{V=o;߽ ll _CE!x-;A^H&BO0|4Я` 4fCp௠[-=l߫iEMP`xg4XC.x6j[]pKލaZ.l1c$$>u 9]w! !`r{W.8pJ}z%>S;I4 ? --hlڄ?8(B!n6< ~!Ga} yh<|Z5UvDK qBÚj " 7A^0>+[`hV<w;A"ѳYBa7A~+W o4p~}? 7рluuӃ({{?muSLNJ!5W7ϻ`s[$zăš5Mu(~?!៞[p=pa_SOAkI |V5W" GE=,<X&4>Sac``XWx6IQW#{`V<ӄ4כ& wWYnow}B6 qρlB@s3Ͳ;z T|N, #7_t]^?e < lV5 q!BAFL+䵔{_,V( !OZp{6"@=i']=w _ +]KZsZQ^^GSdR#6mB [| q16[{_Nho~A($'_=},Bu0~?ӐTvhl;6Fh|ܣXV}0C?jG{Y(_ dZ[%oTeGSr5])9;$tzֆ5X50X eV ?[/\$q#_~ٙ)zԱH~LLʸfe樐C!9؉DIOx6p* e!-xo{bݚnEwpJQXZNOM<".ImtwK뭢 {($;,dz5Dր-} .>[AO_5JwS/B{'De@, JH\>==Ru}qTez i~2= \T:|3lMM=!ްAaO`PJs%IZbL{{Tnu`r+y@mm& 0#pGVsuj뮓.r6XLvprrykk;ںT:t]tutigacŔ n?HG׾";@ !V$ifFdɁnl\L*, brP&/TU%/|a p00y#> ⁀<~Et2NdP~`pkkKq 6nWH$(v$`8}$KDBJ%~!>@R$d&!y3Z(2oygΐ>taE钕\i6-#@)Ɇ۳.pJe! |Goތ,hY3Yf!{tH? |z{᭷QVH 9i[; (:|cǘoقB6IG=|`6K hz8|XJ gKOJޢ|VKkKKmк-dn o[/, #f0N b+mKnjR),RqdjO^;A K2[nuTeYI:q8kjlDNŋ%R]2nsKfY  PLP=6.g0R{6%@׀!nB/\?={PkӋ祿{ |TS5!nZpp(\XzpaqYMC!oj,zYTN=y׋[vlcc2%;8sn(`X%ErRԇ(B௯O_6ݬ֮E̠ #ws93gk69) QZ, 9Mh]8$WS(K|{0jj7_'Z[e-pϞ~VS5NL3Y>'^-wTH;D޲E+/ћfD4gahHdruV UR 5 ;wX}[)6Ͳ8g+ /3e,oXj9'+^~<2r9] $E{ͥt&\n=Tn:a܄js ᶀ| l(4;2Uyo1kjK01QN&ˁuU傮 .Xbe!?>_)Tɹڀ7l[]6/R7`P3\[ULSNA)!|YFڅ}B!BK(f_*6m:8[lbʂ`~w=$8|jMCOŋXg9i?))X[*ÙhD-P NBYHj˝wE;WMMO>)_wwK^/ˁ|AYE뮓F;;jnlYEuzhZr^K#VWx4'bS|"߫ |;Rҗ+BrkI{6~4 {&p0ΩPN%%XUoII^[-<4\!6߸-w4\d5<A(T|3e4˝}5zKYHdanЎcaD-KJSO/)CᆆXy< 7Z" `%bU 0jkf cFK4D[Ҭ9} iyaÐvQa4:_A$svkuxedTFB$B$'ϝc&H]_?x_߂6\4#,hh)YY;2@kmEko_?.%AT4UX ^/b%ه0C?矧6"J׮(D8ϩӧIRHm; h7@ZÄZòMx=(-ݔdMCu<ӧI<Ԅٹ$eEds4:\S#Ә;wbXXmvYAi=r/455vq촰uΞ=KٳdY{x<>Uum[hM"!_(DE"rD-ɪ 0}J$vmeІ!}ҢKg4tnx]e땺<|-\q#nY#G~ի 2f(io>2 =~ӧ sE<}*x p'|A6Ruf*"NBjke'le06F r K'>SٖhM;v`l< ={~HڵkjK} a1Jq!{{1Ms@{^>* n4dYz0^s Xx"gvmIR)>\)wꄽD( B]QVB)fB]L<x#{ƺ(`㌍rv~y3łxs.¸ 0Fl2'<L!BhqIuX b.R(I F$ Q"qOwȟ;Յܶ;;Kף;Mƪ 55QFz{ݷy*Xn a9 [a6A( `󤦧Cz$Rʡ Z={kW2%4n\Ny4UEAO:DioDJY9cǸ{7yp9L?o0dl&? 3C0 hV%hae$&&rx0JzI:"FAĩSUk *TU﫤F$F"((G8@ͨ^量Ū% O޽dCZ@($<pyt~uPhf/켓e!H46J6hDkJ,hmEtt $ɕ*)j8Ux;;Q{N*`Lŝ;޷\*5Xl`ߗ*0M ND0Z@̰WdPA|4`*~D Pl5c\ٜ()n-ɑV]Ix0QRMxR!KD'!0 5q-B2IfrގRk夿Xgg0s"swi8:#xe !o4rU0z 4/mӤGFڊ"DWR%6JR_Mt5MŘ:vۙ=uj~ Cpej N"rŽ cB0L h+Т;X$ ax;;Qq9 Pn_{o%դ`a&CJXgY8"Tx@BC/IY VhHXQa fFʅ╦[zf*r90p֒7 |W^!m%Oݏ3/F]LIQ6a} ;肆 N4 F 0;G]]NJz\KyEƶop6fXdp^q ?oy@8Z$Hҫ! Q܆#;<wu!"-Zr+g{!VM >F};03yu0s0 ^p]Ʊudg >{^+lNVp}''~. qTOTӳnY,X1MVÓܿcv^,*JT5}oïWDуH-U1kA}HjJC7aNL&Qa,M+5UԄz\BfY%PqsF*[o1>|x;v pex1>NjDr)#1P7~QUo[V4)@ !b1f['5۠Yν˲yΑXV '`GVjDb@!VxrH>wOK@9+ub6TXKx`7[4pY > |.,kMUN6(0)+ 1 pMKc_] L{;$!0kT5t(eY`) @;˄\pS_|=).\_gy F0b*j?VjX ^ p7`$O_1MyY~ r\(7P( PBA\N,v%>Ltx A\)WصjIsc9uu[>O&F>/PQ{G ~]w˽v}>8SxӐ?K4\Jp0ڡpM~AU Y&.WدњȺP4jw |txlYz˰AăVmѢ(t3P9ל_cV>W|hV{R^8l6-r,cl"dOI0 o?}__w߭am/WտSVic YgJ)( BaF A(^7n}|/IΜ9s4WjW*+ 3MRPJ8[Ysa<AzEo}[3g4\eSq^tf6 }mi""yލ uyy+" ?ýJbYֿp]w81VDI(ד$kQ@p1ReY۶a§(4M}k/>-7D)?!@$XFQt3M?vȑx>._W80]R>W+a_HGQ3B\L%I80 SG e iB)u(M?8{ ۑd˲~w4}@ZR !x܆a`4M?~.<ɫW~?eYĶmBDqJM(koCfE.]oݺ)f<amm ieOHbaap8l̀A|H 8]V}Wf)~p8|”RB<4uX`0KokѶzzii>??_f 8mOMOO;w<zqqnLKK z !@)5<` ߸qh i~&}BU6>-ZBt:gjj `iA0 IYc Z Pٔ.oYrY7.˚&H_.Mӂ8z$MӇ l r$PJ!M",h<0<$/gz&C]\s9EOAn|])_S<9j|a@J)7he+e4a;"FӁyV ˲`f4\ܲ3M bŖ>Q!*}`۶wVL|`qKtPU!tԣ+O1<{n4 z=j5yO .Ss|n6y;DQЉ8BCؽ{7jڣvÇFC՚8ep˛q򸕖)sv.I6T*عs'l~4.ߏgbuueoS H~qF#>|V \,{(J{ǡC0$I G~kSfy+Gib8Va?KRƎgy X]]fa_ Y71nI,'I;w@Gb׮]t:#dڻw/N< ˲v + {;gEvލG²,(dەĒoݺLMMm_":}z=08ΧdLӜܯvdd():AUj+@ " aoWthE4Mض J)qq,//c4*W$(A%uqMJ 0$kwljlgs@`0okvX\\DVÁ ٲVa޽EmZ4!~^M2Ns( 8Vh y͚  h6S )K<8@tU0M{-,1F˲9/,8MSqAILJ7+?m&5 Z J(ϒ6lڳ́d`$tu Aǒwڥ水^#"۷oC*)hK) QQkܫ2_ iVK% ѧLGHQ'=$r ȻT~pE%h4p,,,CJǤ - CDQuh40==]vq0'Eek7Mdl.m$ FwMT LtZ& CۇvN(ٳgvqȑ#] kkk, Z FZ ISI4 VWWy0,5UTTAA@ k4;;cǎ֭[X[[41DeRd)|ǝ;wmۅST*T*p]˱vQ!ك]vmY=*xX[uq0Ɗ2/"4M1 "dS@D w2xK^V/۶133ӧObe%[0 qu C΢hsaNi ^a0 [l5okvv! tXf]tq9}mƍ69/lҢ4Px@REC4-ǹ9H>svz5%P6 TvWcl@&ú@ӟ3<ցp)4M IQ\;6o|Ք8)~ӈdEMPM9-h&(r[~+g5VH]6C j+&9=RN($"Aш3+W7xV\< CKBN'9eaN^0,7} ?s.gaX,U)PTi5:nݹiUq 2[J&H8N(~+w˯|+se@cEZyEQ u,<).y2r<߃ksk ')TRYrqkHM͆A (,dͩLQ"PJ5m)U ùTƸ-&]?ySH\ks;wxw}gMihַ{s[1c%0ZBv֟Jd^_\S{AJ$M!R @^=T 8c7/F?Cuޣ?V* aZ5MӴwɓ'cLEmvik-B1Bhd{CPy%!(BDw*>6byxWrr9Ud D)f2o=N8,MSvΏ~w=zo[sRE0QV] Ν;7|n>S>sO=SBR.oK)8=VVV~}VWW$RjB!lPAγd@uA2Yn5E%yzO)mXռpBoaaal~pBRgДRRU(I{FJ)UQEqz7nܸ~NA !"R $JPE =tL{wkw2H"4^&4҇rBh#nݮ'IHvܹs*Jmnnnzvv]۵Zmβ9 TsiJ9熎0r~apH)՗Rv F~[^^xJ)N)MR 4Rrmnˑ"fJ)YȜ.6bi|4(4M0 Cd 4@v=)0 !i5jҊm۶0LJ)@cibFEQ BHH3N$RR*ɁMR2B J)aTRclHPJۄR*us7 ?"_{HDz w~ U4]BHVYbBL~} B)^4RJER$MSaiRBq(U6l<"N!WPnTJQ0|L)aYB0˲&dAPV@3x0J)1 !eURUUƘk\.1# 9EjIENDB`openbmap-logger-0.4.0/gpl.txt0000644000000000000000000010451311215240503014607 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . openbmap-logger-0.4.0/lgpl.txt0000644000000000000000000001672711215240504014775 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. openbmap-logger-0.4.0/openBmap-desktop.png0000644000000000000000000004302311215240504017201 0ustar rootrootPNG  IHDR>asRGBbKGD pHYs  tIME -8AhE6tEXtCommentCreated with GIMPW IDATxYdy;5%ڗnu7"Q"(4hhh y?x^f`'?Y`A#KI $.MRԾefeV]ýUMq镬ӸQwzzzZ-pֿ7ZtI)2FDq {|Oa}\VR^eϡYNXt_tu۶,yFJ18n$i຅NE{9CZssӧT*qY=h'+Un;@- ᜨTj.=]SQ|(X.R.P*E1NZ()Q$mj rc~LXLR15]Zp]Id$ Tw%IlWظ&JF3/MLLBZV} ߷(,M$ a4K^S|<}c+'բS)(e0h! hN(B`88}" ~>W dJ jrZD Ǒnf]7\WWWnݽzvEƘ0TOp(*c~w\>Jxhʥ&劏;Xd0xVt|&Ϝi,c.OÓ*Z@`c[2 >V6rnww%O~TqR\>_Kzoc)fw]pY_ﱲqWWA.(y dqk7R6™3s\xfӧg)ض ۖ4-|ffbmmmltutu W766n\|_/jɅ?Vk͛,/-ݹY] PcbއZǺ/Tׯ<8SeybY?wn_Ο?FR Iߏc0%I R e25j5!4iI5|r!z}6B/pyJ?>;͉gggf$K%"rqZý{[|wz׮W_0} |-+l|3jzySԑB&ı&I &7ij Qpm7T\NaZ4zղssϽ~o޿*`JýKjuV+P,ؖq%45ll X^߹sݻi:Xzɏ/k-ZVۚo6˼ΞhpE@HOĐ$)q_ SSU&*J6*Ozd۶8;=}n~inm޻F HsjJxZ-R,~v<7#~++-mݽ{vfE }z-?yzw$|L<{qDa ] ZChȐ&m&&Ki6}|"S*ĩz}b6Lͭ7ϝΦO_ɉSz)J%~}xc\~|w z?I(<8m5=0%M3?d(S cCTQ(X U..d3cSg'?'~{G/]Z~^k\֊JqL~_ގ_ڸw޾f0k]?i\s4 S$ q1f_Ż2s3i aJil[ɓ,,4r6++{llW?h,\6__;}?krbѻhJՊOhc; Qx^VISjw7{n֍o\Kx;1X˿K{y /T*ř'9>?Ab$IfK&'O Z1 Zgov]Jض,ٗCvvzSJ/)v1Z|VTq@,%m,ba145aBMpZ@;h[7n~{-[c _˝6V*N^|N̟`W[7nZGY칭c'Zb;݇<2@c K),[!@HB>$ƠtB˒xd\)nVIJn\{睿^ɟa(>.RyYA\9qygn< q x?ʃ-=6u6[;\,rz /q~tV^torfϬ3˜;$id!-iJF!I4A,YX֓e)EZD!B.r67=D170MY.0iF1Q1q ZD&%ktm6 8iWv٤^8yayi?Nwn 1mq pTׇ"R5n ݺ̳^L,_lҜ+-4| wY| ¶mے+%/ml4u槦8uzmMZfX4~R'_cV`J8,;Wwy4'9N,25[\,;v<ɠ>(K93j13Mј*'KoݭoAlGÀ`x0Y^v;kkv;1FLZ}k0- ޥzvL;-kI,t Gャ~;B;s,,01iH "g kk}66:~uͷz=ͦ1Ig?ZY^Y]M6,.>E.6AcK%wƵw\G} DGQm23<1$ S>ŢY%H%SZݵ(6{>ۗlO**=3K@ͿG&{L8O_?23OO1ۘebB )ɋEZ~^zƽ< Ƅ!?t^8k3Ǧ)-ޱK Vj05^_*+5Sdέ]FN!I!1`%vw :Ƿ/qpI>eٛTh.~pZ^~[}|۝z=y<'NM3p;,9kn>HZdVF ="/=&ŘJRSH4phaIaaXl'~!>0acszNgo=9sA^܊I#p8qTT)>'99+${PBa!yVcHHL1]gȮEik"qjT.~²d KfBiD<ko]_}\2v}hT =- rIf6#2EU%U !11 R"3$ fH̀ $qCԘ,f0=7Nplp9&kN} T iÇ.-y'IXcLai 0w?ըs3ef{ $ =:f@HFbSC B BDHRv-{mfbඋ,_䴹b\R13V~Gom xC;$ o_K pC`h=A077g9srek.ȋݔrgݡ^+1װ )MEacc`P(D4!)C3AȮ!k k!g150B=Jin,8`Bk"{FwwgZgS^x1N35=əs'p>~Zwɣe:{OҜ*0[*$E.n_X` 4dAkLW Ztq|b)jeu4ՆWH71y_f۾wloK뛷i C \`r] &&hdc+֫Y,{}6csdNL`@ hRR"& pq钰B"@ Y=|c* Xɲ@w݋Xy3~ bѻzs­GvV@l"q0=bXdr{I&@qt8퍛D{x0VpJ.uۥDgT~e( Ɛ`3%Ç!3;9efzL6/HHAlFdC'HݭH &l,Ukͅ˕gT\{PiЫMA=GO?Onay%|nϜ=9CQ#BH 2QBNݻmmY^x%Ja5PXe`sd]}B\4}6;e9U>tMU$BIn]VW5$vEIiT K]餅>srI(\5ot`u_,4/)ˍF'Q,A7ThboQ4 Mz =LC2PD cf>>@#H,taMޟfQg~rdST즂agh4t"0 im eAU [!G(KT8Yu/g/pvQ(8v)W.,L3=5ւ0켤j IHEt$ s̶gy~%iɵok|omNJ2h rKdv`2 APk̬ea~B +%X54 EG0=![!l„%3 nv vR:=mdX qb<rUiU{y}_q,BxԩEqi1;7CAee5%G$3W:%HũQTe|SBIa=@*EQ*CD!C.WM*ؾŋ83е$n(NJ`(AV> KR(  B]e}[T)&M"jڪNy/Ɲkc'^P5u~00텟m뵗^z^?yAL'Xm+lK"xl?֙8edbǢTZMvuwao! Q%,4:dO(B7sNl??+ǰla <%( rT%^LzYVf t@Hprs IDATYQ-J*6rAezAtŽIao~2X$˗i6뤩& t,e)lKe?EmP±l|ף\t' 5n$wX(P.jƂ;C.ͷ^敉Wr $$X\L 7db'ɴ?6kNR!JjST3^瞏VA} 8sB؟/'矻 !quyH),cud %X)vɢVptyH5p'fʍ.+r l v(b#؏ qiƜ~/ĉK' %rq-}+JAł5 "m b}PN5D) %q\2FF =epju!/t|ɶΞ=.\84`gcLJe+ǶZ?i+-Tk+P'iЫ6v7.5Y*H![7 3?:;El[ }-V˲2;8 l{)!cZK@j _YU:J!H% CCSL ϶D { xϟ|X,O^~YN:y$ PJ8ck,?TKcyRd֞4{;{6['[ !Fili7xߡ0 B;Dƽ*SQfχ~ k/"JTQqBX<{?y/W)I8W׋/33qJY~~/biraaN]xJp$`@` ?G'xB-p=SjW2. bɰltiE-<=D2Z"#-PRU)͠s&4=@aFe/;;7s}wwӿNcY6atB56;c% =1.MS4H[OY嘵,K]vV\8_9f3ľw-(Y7iCMe[dDBqy=M`1N@*ejyrbo%x=W~u`~JJ{…;w/Ss(Rb)cp㉯=f%9$PJףR(Qp}&KSRǹ[ZXBX ]Y 8@4jB?z >hQ ɭP bm{Hq=x}t' 7*3 `} ']F#at}bNkX]wp+ L o6Xx aWXhKlCY+<u&}hx\S z4+J %7̵ߘ|TsEs}ԅ6z]JAhƂ~4,~e/l$poޛ#~1 녍SUXTjHH$IR"MM+KqkI(Jpl˕7␩凥(SkMJRD)7w ʱݬN0ÙZ9yύ9(&ӒE v[E IYZSt!N [[~XLad<ؼ#=MrpOspq0f " |v Z2L6$M?~e i i5'U&*Y#[=I0Ʌ[Dx'r0xT\R:{lqɩIIZqԀ4h"1om$f?܋ Mͭ)Ʋ[37uP6tf7#A@72X><|:[CQR_۹,GM>x 07"MB^h¶fg(qJG3 ژhw,&ȭeV fqy84 F@ hJ"li\+cSx:rD揮0}x b'hy&^@Y*Lم4BsZQ{fnܸ! L40>F I&?`؏ı&bsh)@5fB4IT73o tn8{S~X0#>`qm2 q$8 } ucL!hzQsZU~Z q!eF`r YF|Иkr،9= vh }C}4/6]!+y*~`=JƬF, RC$Ҥ$%$v4<#~೟}Tt<ϟk64MHSMXY5F@m`Ïgղx kmA E l =W5ډ> UE, $`W~pdaFp((z[ cC~)E)b[~XXn`A)YI4;N%3oLNfw 4v_+"aMܴ$_8Cߴ~ZhTXi4Q$hRnm)aJpu8cى `^FC*x!h#SÖ%YA^+ M ~&4IThGjR,@eS6IVϺxHs׌\Z& +BĆNa4:$ :){$9c 3~&4$TL<I4t}Fn`9=r.$){CzKg͖S&IAk=Ą)z^oyE("4"1%S=!>QÇP45 1Rd%yXP! M Q0L?&SlKX!4*HP `MY^ sΜ}֪,5\ۀ~eqz$Hra,KuF4 1i \08ML07,:pmP5j6iQFIQT2(!t qp!s^I3M5N>]̀/gU8$$3ĖN)Ɛ&,8V'"tܬvl@?I&J2phsNeu- 5~Ll&(Ul7rD(_ı{f0u 2J c }!g>G 82נY?fa^PmLoىN@Y>Fܤ "фA7Y_-7Bd;E>Hgg?q}(eEk QSiLԚ#с"wJRDŽ֤T8m)AʧǢ95^4vKg4+STX8?$F0Be)ġ T>(SJ¬P!<ԙ[Q6Pt2k0Sblf8 Qffg+ S -Mʔ[ \ /{JY(e穟cD\p |8DRñzNIt Nl$[SlA(Е*\sPckFU?1ւ$ zI?uGdž0l$a~+6vF:H Yc0Y. ="LE>;O2Fl9:5FPOEvȭ:;tD:"sҚ8NHS%"?) 52>GW+HK'Z0L6N,ʢuj%23X˘ӏnDҔjA)R )0>% ߷=P2;T0ijp }0)i)RZ9%?HI:F5GȂqR:8ٌwA4;K K,IvS~FHi*Ib J4}A]Hjʠ!2Rٰǎ}cD *Nްotv%7ʞ'(6Fĉ-,G8sdY!Y-! H׵FĆ' JD"-vJG!~$/M*%(T}Un$ ?4~/=ϲ" WnÁiP:Yx7 4ڨ$<ʭcqx lHOHASL9Cpxʂ>.ZL5N- *7`W٬ᝊ/9谴lsT0?i\TbbAYݘnP*Z Zզ׎Rj/[('>\%ZuoX~ʐGLM055$40c!Q F) qO>kDEI{h@V Y.]&}3ERP.Y\<_ba/H|Z%G{3oZ()OPYU IirBHgvv" *'|Sܸcye[LqluMD |(0O=w̅ !Vt4z{~nR5 c<Ѕ]È2?H+cJ 2?O- pPJEtFa\i~ҪmN 8֩$Ea$Ib[ؖBG=9 ƴ>-#s0fe$9 %)lJ%ܹݻ"-e*%;[ͺœK\GA_H}H,q00bd D^RJ`$k5خTAu؞E(aڼͿgF'-B~a (<ːw0j\_;7 kݡ(J;;;.~).s` o\&D96+@"k ڷ)QBF2fl `wo?GÕMd_|d7T;-urIK嚯acِ(+R>J =PlAdHSC`=o]{Ͼz.v?Reۻ} 9h$d[%@ }{-ZE$,ʼnmY9!g oCyg݇sE-W qZk.xǑŸF^> òD/B;HBxRe-yp)"Z%ϖ܁a…sZOw6͇)hlhY*ګQ(*0$q*hwzK>ip|$A)Ew 0zƤ3@zx^CB"")%#bLJkjV:޼2󜿚[:0gG ,(Ӄ=2 2Y\l+u4U*0;8W 7Rv5tnjf7mɠg>#HI[n|S tdjNWYNUT_Q2V\'8X~V:.ALX{!N[VA##MA"xn`v>Ϥ1\X(M0t]7=D%%iLF2{(K g8Ue(t\a6p13LO~_=}oq4E\ۖ++Ԝ)IqACMDu5saX U<˧~Z$*R9a0g 3wSw~[YhPyD}i* HJɅ@8^1a96"y@ C~)`Adr'l llP5v{>׵CםA_\Gw>Kw/~ jӄdˤs>E}:!ق"q3J `jXTݐa1Q4ڣvpiY~bR|}5H%shyy)\.'TU/:NP1Ly MWaYc$گ`g'BAmOP@`VIDATtvN簚 [?m jSNAz{x7c0sQ,i ^(1wKS2lB<b`N@ڭ77~?mC6aߛC% COaЛLnzűem!PTUZD%:QlasB>4a:CK>y[%QV谛xسq;%Q Kbؖo$[*~o/'Tz:^g@n KK2wM ′/v@gwON[fauWnR4G(@h!x~yGʊebRyw+.xRy;Dop)Y9SVK (mm _ȡR)榆`|z 74ΝlVɶ7J/N @7{m}}t\=8X>]/SRbwGSe  F|p9g#wyEzOWB|s$d, "XO&HJ3܀H;$2okhco4 Ԇ\…MyL laȃ0Ngg-)uuw:/̉'x&[ƞ' p><Ȭ1W`JKW~Kn~PF/CifYU`EabD;9m>s> y*O |?|饿  %E)\4/z>(NQRNF^Bb.IpA13Qi{Zp`!pRn ϫȤYH{ߖ(3a.?Y/Fe^ b9O>霓9w9=}x2[iWj"+nw@ br-Cu I^vIkZ% 9bq֘w|vUD@.|W1&d5\mɸk׮pk׋ŝ=ڨD n"DݞN۵ZA侧 3t2Ug"AOU>f”]?!)Z yh|XZ|3¨AzP25ʹSrq8zRX$$nysOᥚ}F{j+°JbpUX(e_*dSIiy5}f!2y Fk炆kkkkk, ]ZbiIENDB`openbmap-logger-0.4.0/openBmap.desktop0000644000000000000000000000036411231122121016410 0ustar rootroot[Desktop Entry] Name=OBM Comment=Logs GSM and GPS and uploads to openBmap. Encoding=UTF-8 Version=0.4.0 Type=Application Exec=openBmapGTK Icon=openBmap-desktop Terminal=true Categories=GTK;Application;PIM SingleInstance=true StartupNotify=true openbmap-logger-0.4.0/openBmapGTK0000755000000000000000000003665411230675201015337 0ustar rootroot#!/usr/bin/env python # Copyright 2008, 2009 Ronan DANIELLOU # Copyright 2008, 2009 Onen (onen.om@free.fr) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys try: import pygtk pygtk.require("2.0") except: pass try: import gtk import gtk.glade except: sys.exit(1) import logging import gobject import os.path import openbmap.logger class openBmapGTK: """This is a GTK frontend for the openBmap logger.""" def __init__(self): #Set the Glade file possibleGladeFile = None pathsTried = '' for path in [sys.path[0], os.path.split(sys.path[0])[0]]: for p in ['', os.path.join('share', 'openBmap')]: possibleGladeFile = os.path.join(path, p, 'Main.glade') pathsTried += '\n' + possibleGladeFile if os.path.exists(possibleGladeFile): print 'Try loading %s glade file.' % possibleGladeFile break else: possibleGladeFile = None if possibleGladeFile: break if not possibleGladeFile: print 'No graphical interface file found! Have tried: %s' % pathsTried sys.exit(-1) else: del pathsTried self.wTree = gtk.glade.XML(possibleGladeFile) #Get the Main Window, and connect the "destroy" event self.window = self.wTree.get_widget("windowMain") self._windowMenu = self.wTree.get_widget('windowMenu') if (self.window): self.window.connect("destroy", self.exit_obm) self._gsmLabel = self.wTree.get_widget('displayGsm') self._gsmLabel2 = self.wTree.get_widget('displayCidStrength') self._gpsPositionLabel = self.wTree.get_widget('displayGpsPosition') self._gpsAltitudeLabel = self.wTree.get_widget('displayGpsAlt') self._dops = self.wTree.get_widget('displayDops') self._speed = self.wTree.get_widget('displaySpeed') self._stopLogging = self.wTree.get_widget('buttonStopLogging') self._startLogging = self.wTree.get_widget('buttonGenerateLog') self._gpsViewWithFix = self.wTree.get_widget('vboxGPSWithFix') self._gpsViewNoFix = self.wTree.get_widget('tableGPSNoFix') self._mccLabel = self.wTree.get_widget('labelMCCValue') self._mncLabel = self.wTree.get_widget('labelMNCValue') self._lacLabel = self.wTree.get_widget('labelLACValue') self._cidLabel = self.wTree.get_widget('labelCIDValue') self._ssLabel = self.wTree.get_widget('labelCellSignalStrengthValue') self._actType = self.wTree.get_widget('labelAccessTypeValue') self._gsmServingLabelList = [self._mccLabel, self._mncLabel, self._lacLabel, self._cidLabel, self._ssLabel, self._actType] self._latitudeLabel = self.wTree.get_widget('labelLatitudeValue') self._longitudeLabel = self.wTree.get_widget('labelLongitudeValue') self._altitudeLabel = self.wTree.get_widget('labelAltitudeValue') self._speedLabel = self.wTree.get_widget('labelSpeedValue') self._hpvDopsLabel = self.wTree.get_widget('labelHPVDopsValue') self._gpsLabelList = [self._latitudeLabel, self._longitudeLabel, self._altitudeLabel, self._speedLabel, self._hpvDopsLabel] self._nbServSinceStartLabel = self.wTree.get_widget('labelNbServSinceStart') self._nbServSinceLaunchLabel = self.wTree.get_widget('labelNbServSinceLaunch') self._nbNeigSinceStartLabel = self.wTree.get_widget('labelNbNeigSinceStart') self._nbNeigSinceLaunchLabel = self.wTree.get_widget('labelNbNeigSinceLaunch') self._nbNeigCurrentLabel = self.wTree.get_widget('labelNbNeigCurrent') self._LoggingStatusLabel = self.wTree.get_widget('labelLoggingStatus') #Create our dictionary and connect it dic = { "NextWindow" : self.next_window, "StopLogging" : self.stop_logging, "StartLogging" : self.start_logging, "Upload" : self.upload, "ShowMenu" : self.show_menu_window, "ShowMainWindow" : self.show_main_window } self.wTree.signal_autoconnect(dic) self._plsWait = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, 'Stopping the logger. Please wait...') self._obmlogger = openbmap.logger.ObmLogger() self._obmlogger.register(self) self._obmlogger.init_openBmap() context = self._cidLabel.get_pango_context() font = context.get_font_description() self._biggerLabels = [self._cidLabel, self._speedLabel, self._hpvDopsLabel] self._biggerLabels2 = [self._hpvDopsLabel, self._nbServSinceStartLabel, self._nbServSinceLaunchLabel, self._nbNeigSinceStartLabel, self._nbNeigSinceLaunchLabel, self._nbNeigCurrentLabel, self._LoggingStatusLabel] font.set_size(int(font.get_size() * 3)) for l in self._biggerLabels: l.modify_font(font) font.set_size(int(font.get_size() *2/3)) for l in self._biggerLabels2: l.modify_font(font) def next_window(self, widget): """Cycle through the windows.""" #TODO: not yet implemented: Exit right now # timeout_add schedules the first call at the soonest in 'timeout' seconds self.exit_obm(widget) gobject.timeout_add_seconds(2, self.exit_obm, widget) def show_menu_window(self, widget): self._windowMenu.show() logging.debug('GUI: shows menu window.') self.window.hide() logging.debug('GUI: hides main window.') def show_main_window(self, widget): self.window.show() logging.debug('GUI: shows main window.') self._windowMenu.hide() logging.debug('GUI: hides the menu window.') def stop_logging(self, widget): self._plsWait.text = 'Stopping the logger. Please wait...' self._plsWait.show_all() while gtk.events_pending(): gtk.main_iteration(False) self._obmlogger.stop_logging() def exit_obm(self, widget): logging.info('Exiting on request of the user.') if self._obmlogger.is_logging(): self.stop_logging(widget) logging.debug('Still logging, wait...') # to keep being called by timeout_add return True else: self._obmlogger.exit_openBmap() gobject.idle_add( logging.info, 'Exiting...' ) gobject.idle_add(gtk.main_quit, ) def start_logging(self, widget): self._obmlogger.start_logging() self.show_main_window(widget) def notify(self): """This method will be called by the observable we are registered too upon change.""" logging.debug('View notified for changes.') (valid, servingCell, neighbourCells) = self._obmlogger.get_gsm_data() if valid: self._gsmLabel.set_text("%s / %s / %s" % servingCell[:3]) self._gsmLabel2.set_text("%s / %s / %s" % servingCell[3:6]) self._mccLabel.set_text('%s' % servingCell[0]) self._mncLabel.set_text('%s' % servingCell[1]) self._lacLabel.set_text('%s' % servingCell[2]) self._cidLabel.set_text('%s' % servingCell[3]) self._ssLabel.set_text('%s' % servingCell[4]) self._actType.set_text('%s' % servingCell[5]) self._nbNeigCurrentLabel.set_text('%s' % len(neighbourCells)) (nbServCurrent, nbNeighCurrent, nbServTotal, nbNeighTotal) = self._obmlogger.get_seen_cells_stats() # we update only if logging is on. This way, when we stop, # we still read meaningful information: the number of cells # seen during last start/stop. if self._obmlogger.is_logging(): self._nbServSinceStartLabel.set_text('%s' % nbServCurrent) self._nbNeigSinceStartLabel.set_text('%s' % nbNeighCurrent) self._nbServSinceLaunchLabel.set_text('%s' % nbServTotal) self._nbNeigSinceLaunchLabel.set_text('%s' % nbNeighTotal) else: for w in [self._gsmLabel, self._gsmLabel2]: w.set_text("N/A") for w in self._gsmServingLabelList: w.set_text('N/A') self._nbNeigCurrentLabel.set_text('N/A') (valid, tstamp, lat, lng, alt, pdop, hdop, vdop, speed, heading) = self._obmlogger.get_gps_data() if valid: self._gpsPositionLabel.set_text('%s / %s' % (lat, lng)) self._gpsAltitudeLabel.set_text('%s' % alt) self._dops.set_text('%s/%s/%s' % (pdop, hdop, vdop)) self._speed.set_text('%s' % speed) self._latitudeLabel.set_text('%s' % lat) self._longitudeLabel.set_text('%s' % lng) self._altitudeLabel.set_text('%i' % alt) self._speedLabel.set_text('%.2f' % speed) self._hpvDopsLabel.set_text('%s\n%s\n%s' % (pdop, hdop, vdop)) else: for w in [self._gpsPositionLabel, self._gpsAltitudeLabel, self._dops, self._speed]: w.set_text('N/A') for w in self._gpsLabelList: w.set_text('N/A') # quick improvement for notifying the user that: the GPS is active, and what it is waiting # for in order to display GPS data self._gpsPositionLabel.set_text('GPS is on') self._gpsAltitudeLabel.set_text('Waiting for a 3D fix') if self._gpsViewWithFix.get_property('visible') != valid: self._gpsViewWithFix.set_property('visible', valid) self._gpsViewNoFix.set_property('visible', not valid) self._gpsViewWithFix.parent.show() logging.debug('GUI: GPS view switched because fix status has changed.') else: logging.debug('GUI: No need to switch GPS graphical interface view.') isLogging = self._obmlogger.is_logging() self._startLogging.set_sensitive(not isLogging) self._stopLogging.set_sensitive(isLogging) if not isLogging: self._plsWait.hide() self._LoggingStatusLabel.set_text('OFF') else: self._LoggingStatusLabel.set_text('ON') # a sanity check if (not self.window.get_property('visible')) and (not self._windowMenu.get_property('visible')): logging.error('GUI: both windows are set to invisible! Shows main window.') self.show_main_window(None) def upload(self, widget): """Upload logs to OpenBmap database.""" if not self.check_credentials(): logging.debug('Upload aborted because credentials not validated.') return plsWait = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, 'Trying to upload logs. Please wait...') plsWait.show_all() while gtk.events_pending(): gtk.main_iteration(False) (uploaded, totalFilesUploaded, totalFilesToUpload) = self._obmlogger.send_logs() plsWait.destroy() if uploaded: plsWait = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, '%i out of %i log files uploaded.\nThanks for your contribution!' % (totalFilesUploaded, totalFilesToUpload)) else: plsWait = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, 'Upload failed.\nSee application log for details.') plsWait.run() plsWait.destroy() plsWait = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, 'Do you want to delete all logs located in the Processed folder?') if plsWait.run() == gtk.RESPONSE_YES: plsWait.destroy() plsWait = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, '%i processed log files deleted.' % self._obmlogger.delete_processed_logs()) plsWait.run() plsWait.destroy() def check_credentials(self): """Returns True if credentials are validated, False otherwise""" dialog = gtk.Dialog(title='Upload?', flags=gtk.DIALOG_MODAL, parent=self.window, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) result = False labelLogin = gtk.Label('Login:') entryLogin = gtk.Entry(0) login, password = self._obmlogger.get_credentials() entryLogin.set_text(login) labelPassword = gtk.Label('Password:') entryPassword = gtk.Entry(0) entryPassword.set_text(password) widgetsTuple = labelLogin, entryLogin, labelPassword, entryPassword for w in widgetsTuple: dialog.vbox.add(w) dialog.show_all() if dialog.run() == gtk.RESPONSE_ACCEPT: newLogin = entryLogin.get_text() newPassword = entryPassword.get_text() if (login != newLogin) or (password != newPassword): logging.debug('Credentials modified (\'%s\', \'%s\') -> (\'%s\', \'%s\').' % \ (login, password, newLogin, newPassword)) logging.info('Credentials changed, saving...') self._obmlogger.set_credentials(newLogin, newPassword) else: logging.debug('Credentials unchanged.') result = True dialog.destroy() return result if __name__ == "__main__": hwg = openBmapGTK() gtk.main() openbmap-logger-0.4.0/setup.py0000644000000000000000000000263111231122157014776 0ustar rootrootfrom distutils.core import setup import glob setup(name='openbmap-logger', version='0.4.0', description='GPS and GSM logger for openBmap.', author='Onen', author_email='onen.om@free.fr', url='http://www.openbmap.org', download_url='http://sourceforge.net/project/showfiles.php?group_id=218065&package_id=310952', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: X11 Applications :: GTK', 'Intended Audience :: End Users/Desktop', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Topic :: Scientific/Engineering :: GIS', ], package_dir= {'openbmap':'openbmap'}, packages=['openbmap'], data_files=[('share/applications', ['openBmap.desktop']), ('share/openBmap', ['AUTHORS', 'CHANGELOG', 'README', 'ExitButton.png', 'GenerateButton.png', 'StopButton.png', 'UploadButton.png', 'Go-jump.png', 'Main.glade', 'gpl.txt', 'lgpl.txt' ]), ('share/pixmaps', ['openBmap-desktop.png']) ], scripts = ['openBmapGTK'] ) openbmap-logger-0.4.0/PKG-INFO0000644000000000000000000000127311231127401014357 0ustar rootrootMetadata-Version: 1.0 Name: openbmap-logger Version: 0.4.0 Summary: GPS and GSM logger for openBmap. Home-page: http://www.openbmap.org Author: Onen Author-email: onen.om@free.fr License: UNKNOWN Download-URL: http://sourceforge.net/project/showfiles.php?group_id=218065&package_id=310952 Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: X11 Applications :: GTK Classifier: Intended Audience :: End Users/Desktop Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Topic :: Scientific/Engineering :: GIS