From d907ba2e725d34e035231274a4de7f8faa1fd736 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sun, 23 Sep 2012 00:08:08 +0200 Subject: [PATCH] Add support for geolocalisation via the phonenumbers lib in the get_cid_name.py script. If you add --geoloc, the numbers that are not found in OpenERP will be geolocalized. Thanks to Ludovic Gasc for making me discover this great "phonenumbers" lib. --- asterisk_click2dial/scripts/get_cid_name.py | 84 +++++++++++++------ .../scripts/get_cid_name_timeout.sh | 11 ++- 2 files changed, 69 insertions(+), 26 deletions(-) diff --git a/asterisk_click2dial/scripts/get_cid_name.py b/asterisk_click2dial/scripts/get_cid_name.py index e9fbd57..bd3cd5c 100755 --- a/asterisk_click2dial/scripts/get_cid_name.py +++ b/asterisk_click2dial/scripts/get_cid_name.py @@ -7,15 +7,16 @@ OpenERP's partner addresses, and, if it finds the phone number, it will get the corresponding name of the person and use this name as CallerID name for the incoming call. - Requires the "asterisk_click2dial" module (available in the extra-addons) - on OpenERP version >= 5 + Requires the "asterisk_click2dial" module + available from https://code.launchpad.net/openerp-asterisk-connector + for OpenERP version >= 5.0 This script is designed to be used as an AGI on an Asterisk IPBX... BUT I advise you to use a wrapper around this script to control the execution time. Why ? Because if the script takes too much time to execute or get stucks (in the XML-RPC request for example), then the incoming phone call will also get stucks and you will miss a call ! - The most simple solution I found is to use the "timeout" shell command to + The simplest solution I found is to use the "timeout" shell command to call this script, for example : # timeout 1s get_cid_name.py @@ -34,11 +35,14 @@ It's probably a good idea to create a user in OpenERP dedicated to this task. This user only needs to be part of the group "Asterisk CallerID", which has read access on the 'res.partner.address' object, nothing more. + + Note that this script can be used without OpenERP, with just the geolocalisation + feature : for that, don't use option --server ; only use --geoloc """ __author__ = "Alexis de Lattre " __date__ = "December 2010" -__version__ = "0.1" +__version__ = "0.2" # Copyright (C) 2010-2012 Alexis de Lattre # @@ -61,18 +65,23 @@ from optparse import OptionParser # CID Name that will be displayed if there is no match in res.partner.address +# and no geolocalisation default_cid_name = "Not in OpenERP" # Define command line options -option_server = {'names': ('-s', '--server'), 'dest': 'server', 'type': 'string', 'help': 'DNS or IP address of the OpenERP server. Default = localhost', 'action': 'store', 'default':'localhost'} +option_server = {'names': ('-s', '--server'), 'dest': 'server', 'type': 'string', 'help': 'DNS or IP address of the OpenERP server. Default = none (will not try to connect to OpenERP)', 'action': 'store', 'default': False} option_port = {'names': ('-p', '--port'), 'dest': 'port', 'type': 'int', 'help': "Port of OpenERP's XML-RPC interface. Default = 8069", 'action': 'store', 'default': 8069} -option_ssl = {'names': ('-e', '--ssl'), 'dest': 'ssl', 'help': "Use XML-RPC secure i.e. with SSL instead of clear XML-RPC. Default = no, use clear XML-RPC.", 'action': 'store_true', 'default': False} -option_database = {'names': ('-d', '--database'), 'dest': 'database', 'type': 'string', 'help': "OpenERP database name. Default = openerp", 'action': 'store', 'default': 'openerp'} +option_ssl = {'names': ('-e', '--ssl'), 'dest': 'ssl', 'help': "Use XML-RPC secure i.e. with SSL instead of clear XML-RPC. Default = no, use clear XML-RPC", 'action': 'store_true', 'default': False} +option_database = {'names': ('-d', '--database'), 'dest': 'database', 'type': 'string', 'help': "OpenERP database name. Default = 'openerp'", 'action': 'store', 'default': 'openerp'} option_user = {'names': ('-u', '--user-id'), 'dest': 'user', 'type': 'int', 'help': "OpenERP user ID to use when connecting to OpenERP. Default = 2", 'action': 'store', 'default': 2} -option_password = {'names': ('-w', '--password'), 'dest': 'password', 'type': 'string', 'help': "Password of the OpenERP user. Default = demo", 'action': 'store', 'default': 'demo'} +option_password = {'names': ('-w', '--password'), 'dest': 'password', 'type': 'string', 'help': "Password of the OpenERP user. Default = 'demo'", 'action': 'store', 'default': 'demo'} option_ascii = {'names': ('-a', '--ascii'), 'dest': 'ascii', 'help': "Convert name from UTF-8 to ASCII. Default = no, keep UTF-8", 'action': 'store_true', 'default': False} +option_geoloc = {'names': ('-g', '--geoloc'), 'dest': 'geoloc', 'help': "Try to geolocate phone numbers unknown to OpenERP. This features requires the 'phonenumbers' Python lib. To install it, run 'sudo pip install phonenumbers' Default = no", 'action': 'store_true', 'default': False} +option_geoloc_lang = {'names': ('-l', '--geoloc-lang'), 'dest': 'lang', 'help': "Language in which the name of the country and city name will be displayed by the geolocalisation database. Use the 2 letters ISO code of the language. Default = 'en'", 'action': 'store', 'default': "en"} +option_geoloc_country = {'names': ('-c', '--geoloc-country'), 'dest': 'country', 'help': "2 letters ISO code for your country e.g. 'FR' for France. This will be used by the geolocalisation system to parse the phone number of the calling party. Default = 'FR'", 'action': 'store', 'default': "FR"} +option_geoloc_cityonly = {'names': ('-t', '--geoloc-city-only'), 'dest': 'cityonly', 'help': "Only display the city name, instead of displaying both the country and the city. Default = no", 'action': 'store_true', 'default': False} -options = [option_server, option_port, option_ssl, option_database, option_user, option_password, option_ascii] +options = [option_server, option_port, option_ssl, option_database, option_user, option_password, option_ascii, option_geoloc, option_geoloc_lang, option_geoloc_country, option_geoloc_cityonly] def stdout_write(string): '''Wrapper on sys.stdout.write''' @@ -90,6 +99,21 @@ def stderr_write(string): sys.stdout.flush() return True +def geolocate_phone_number(number, country_code, lang): + import phonenumbers + import phonenumbers.geocoder + res = '' + phonenum = phonenumbers.parse(number, country_code.upper()) + city = phonenumbers.area_description_for_number(phonenum, lang.lower()) + if not options.cityonly: + country = phonenumbers.country_name_for_number(phonenum, lang.lower()) + if country and city: + res = country + ' ' + city + elif country and not city: + res = country + elif city: + res = city + return res def reformat_phone_number_before_query_openerp(number): '''We match only on the end of the phone number''' @@ -150,30 +174,42 @@ def main(options, arguments): exit(0) stdout_write('VERBOSE "CallerID number = %s"\n' % input_cid_number) - query_number = reformat_phone_number_before_query_openerp(input_cid_number) - stderr_write("phone number sent to OpenERP = %s\n" % query_number) - if options.ssl: - stdout_write('VERBOSE "Starting XML-RPC secure request on OpenERP %s:%s"\n' % (options.server, str(options.port))) - protocol = 'https' - else: - stdout_write('VERBOSE "Starting clear XML-RPC request on OpenERP %s:%s"\n' % (options.server, str(options.port))) - protocol = 'http' - sock = xmlrpclib.ServerProxy('%s://%s:%s/xmlrpc/object' % (protocol, options.server, str(options.port))) + res = False + if options.server: # Yes, this script can be used without "-s openerp_server" ! + query_number = reformat_phone_number_before_query_openerp(input_cid_number) + stderr_write("phone number sent to OpenERP = %s\n" % query_number) + if options.ssl: + stdout_write('VERBOSE "Starting XML-RPC secure request on OpenERP %s:%s"\n' % (options.server, str(options.port))) + protocol = 'https' + else: + stdout_write('VERBOSE "Starting clear XML-RPC request on OpenERP %s:%s"\n' % (options.server, str(options.port))) + protocol = 'http' - res = sock.execute(options.database, options.user, options.password, 'res.partner.address', 'get_name_from_phone_number', query_number) - # To simulate a long execution of the XML-RPC request - #import time - #time.sleep(5) + sock = xmlrpclib.ServerProxy('%s://%s:%s/xmlrpc/object' % (protocol, options.server, str(options.port))) - stdout_write('VERBOSE "End of XML-RPC request on OpenERP"\n') + try: + res = sock.execute(options.database, options.user, options.password, 'res.partner.address', 'get_name_from_phone_number', query_number) + stdout_write('VERBOSE "End of XML-RPC request on OpenERP"\n') + if not res: + stdout_write('VERBOSE "Phone number not found in OpenERP"\n') + except: + stdout_write('VERBOSE "Could not connect to OpenERP"\n') + res = False + # To simulate a long execution of the XML-RPC request + #import time + #time.sleep(5) # Function to limit the size of the CID name to 40 chars if res: if len(res) > 40: res = res[0:40] + elif options.geoloc: + # if the number is not found in OpenERP, we try to geolocate + stdout_write('VERBOSE "Trying to geolocate with country %s and lang %s"\n' % (options.country, options.lang)) + res = geolocate_phone_number(input_cid_number, options.country, options.lang) else: - # if the number is not found in OpenERP, we put 'default_cid_name' as CID Name + # if the number is not found in OpenERP and geoloc is off, we put 'default_cid_name' as CID Name res = default_cid_name # All SIP phones should support UTF-8... but in case you have analog phones over TDM diff --git a/asterisk_click2dial/scripts/get_cid_name_timeout.sh b/asterisk_click2dial/scripts/get_cid_name_timeout.sh index d9d3edc..b1e9bf8 100755 --- a/asterisk_click2dial/scripts/get_cid_name_timeout.sh +++ b/asterisk_click2dial/scripts/get_cid_name_timeout.sh @@ -14,5 +14,12 @@ # in the "coreutils" package # The first argument of the "timeout" command is the maximum execution time -# In this example, we chose 1 second -timeout 1s /usr/local/bin/get_cid_name.py -s openerp.mycompany.com -d erp_prod -u 12 -w "mypasswd" +# In this example, we chose 2 seconds. Note that geolocalisation takes about +# 1 second on an small machine ; so if you enable the --geoloc option, +# don't put a 1 sec timeout ! + +# To test this script manually (i.e. outside of Asterisk), run : +# echo "agi_callerid:0141981242"|get_cid_name_timeout.sh +# where 0141981242 is a phone number that could be presented by the calling party + +timeout 2s /usr/local/bin/get_cid_name.py --server openerp.mycompany.com --database erp_prod --user-id 12 --password "thepasswd" --geoloc --geoloc-country "FR" --geoloc-lang "fr"