Difference between revisions of "Telephone system:Number lookup"

From Hackerspace ACKspace
Jump to: navigation, search
(moving telephone scripts to separate pages)
 
m (Cleanup featured list)
 
(5 intermediate revisions by the same user not shown)
Line 1: Line 1:
We make use of the mod_cidlookup for ease of use, but not all features are functional in our implementation.
+
{{Project
 +
|Featured=No
 +
|State=Active
 +
|Members=Xopr
 +
|Description=Caller ID lookup
 +
|GitHub=cidlookup
 +
}}
 +
<onlyinclude>This script uses mod_cidlookup combined with a custom php page. It tests the number against a SQLite database, several reversed number lookup websites, the national telecommunications authority database and a coarse array of areas of the world, which are called in order of granularity. The script can be called both on outgoing and incoming calls
 +
 
 +
</onlyinclude>We make use of the mod_cidlookup for ease of use, but not all features are functional in our implementation.
 
Every request is done via HTTP requests to a php script that will check if the number:
 
Every request is done via HTTP requests to a php script that will check if the number:
 
* is an extension (and returns the name for that)
 
* is an extension (and returns the name for that)
* is stored in the local mySQL database, and return that
+
* is stored in the local SQLite database, and return that
 
* can be found online by using reversed number lookup websites for landlines
 
* can be found online by using reversed number lookup websites for landlines
* can be found online by using the national telecommunications authority database (opta.nl) for cell phones returning the associated cell provider
+
* can be found online by using the national telecommunications authority database (acm.nl) for cell phones returning the associated cell provider
 
* can be categorized by a more coarse lookup, like continent, country, region, town or number block owner, stored in a local array (~500 entries)
 
* can be categorized by a more coarse lookup, like continent, country, region, town or number block owner, stored in a local array (~500 entries)
  
 
The setting for mod_cidlookup is:
 
The setting for mod_cidlookup is:
  <param name="url" value="http://webserviceprovider/lookup.php?number=${caller_id_number}"/>
+
  <param name="url" value="https://domain.tld/cid.php?key=<your_desired_key>&amp;number=${caller_id_number}"/>
 
 
=== lookup.php ===
 
This script returns some information about the caller, preferrably the name.
 
It uses a local MySQL database and fetches info from some sites.
 
 
 
<pre>
 
<?php
 
/*
 
* Copyright (c) 2012, ACKspace foundation
 
* All rights reserved.
 
*
 
* Redistribution and use in source and binary forms, with or without
 
* modification, are permitted provided that the following conditions are met:
 
*
 
* 1. Redistributions of source code must retain the above copyright notice, this
 
*    list of conditions and the following disclaimer.
 
* 2. Redistributions in binary form must reproduce the above copyright notice,
 
*    this list of conditions and the following disclaimer in the documentation
 
*    and/or other materials provided with the distribution.
 
*
 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
*
 
* The views and conclusions contained in the software and documentation are those
 
* of the authors and should not be interpreted as representing official policies,
 
* either expressed or implied, of the FreeBSD Project.
 
*/
 
 
 
define( "COUNTRY", "31" );
 
define( "REGION", "45" );
 
define( "PLUS", "00" );
 
define( "MYSQL_DB", "freeswitch_cidlookup" );
 
 
 
// Number dial plan, ~500 entries, shortened for wiki
 
$arrNumbers[1]['info'] = "(continent) Verenigde Staten";
 
$arrNumbers[1][4][4][1]['info'] = "Bermuda";
 
$arrNumbers[3]['info'] = "(continent) Europa";
 
$arrNumbers[3][1]['info'] = "(land) Nederland";
 
$arrNumbers[3][1][1][4]['info'] = "Testnetnummer van KPN Telecom";
 
$arrNumbers[3][1][4]['info'] = "(provincies) Oostelijk Noord-Brabant, Limburg";
 
$arrNumbers[3][1][4][5]['info'] = "(regio) Heerlen";
 
$arrNumbers[3][1][6]['info'] = "Mobiele nummers en Semafoondiensten";
 
$arrNumbers[3][1][6][1]['info'] = "Mobiele telefoon";
 
$arrNumbers[3][1][6][1][0]['info'] = "(GSM) KPN";
 
$arrNumbers[3][1][8][5]['info'] = "(type) Plaatsonafhankelijk/VoIP";
 
$arrNumbers[3][1][8][5][8][7]['info'] = "(VoIP) XS4ALL";
 
 
 
// Normalize the number
 
$arrNumberInfo = normalizeNumber( getVar( "number", true ) );
 
 
 
// Extension? try and get from dialplan
 
if ( $arrNumberInfo['type'] == "extension" )
 
{
 
    echo getExtension( $arrNumberInfo['local'] );
 
    exit;
 
}
 
 
 
if ( !function_exists( "mysql_connect" ))
 
{
 
    echo "ERROR";
 
    exit;
 
}
 
 
 
// Fetch the number from the database
 
if ( $strName = dbLookup( $arrNumberInfo ))
 
{
 
    echo $strName;
 
    exit;
 
}
 
 
 
// Nothing in the database?
 
// national number starting with 0[1-578]?
 
// Fetch number from website (check last get timestamp to prevent DoS
 
// put result in DB
 
if ( preg_match( "/^0[1-578].*/", $arrNumberInfo['national'] ) && $strName = fetchWebsiteResult( $arrNumberInfo['national'] ))
 
{
 
    echo $strName;
 
 
 
    // Add the name to the DB
 
    $arrNumberInfo['name'] = $strName;
 
    dbInsert( $arrNumberInfo );
 
    exit;
 
}
 
else if ( preg_match( "/^0[6].*/", $arrNumberInfo['national'] ) && $strName = fetchOptaResult( $arrNumberInfo['national'] ))
 
{
 
    // Number porting
 
    echo $strName;
 
 
 
    // Add the name to the DB, so we don't have to look it up anymore
 
    $arrNumberInfo['name'] = $strName;
 
    dbInsert( $arrNumberInfo );
 
    exit;
 
}
 
 
 
// Nothing on the website? Try and find the number in the array
 
if ( isset( $arrNumberInfo['international'] ))
 
{
 
    $strName = _getInfo( str_split( $arrNumberInfo['international'] ));
 
    echo $strName;
 
    exit;
 
}
 
 
 
/////////////////////////////////////////////////////////////////////
 
function fetchWebsiteResult( $_strNumber )
 
{
 
 
 
    if ( $strName = fetch_delefoondetective_nl( $_strNumber ))
 
        return $strName;
 
 
 
    if ( $strName = fetch_gevonden_cc( $_strNumber ))
 
        return $strName;
 
 
 
    if ( $strName = fetch_zoekenbel_nl( $_strNumber ))
 
        return $strName;
 
 
 
    if ( $strName = fetch_nummerzoeker_com( $_strNumber ))
 
        return $strName;
 
 
 
    if ( $strName = fetch_nummerid_com( $_strNumber ))
 
        return $strName;
 
 
 
    if ( $strName = fetch_gebeld_nl( $_strNumber ))
 
        return $strName;
 
 
 
    return false;
 
}
 
 
 
function fetchOptaResult( $_strNumber )
 
{
 
    $strPage = file_get_contents( "http://www.opta.nl/nl/nummers/nummers-zoeken/resultaat/?query=".$_strNumber."&page=1&portering=1" );
 
 
 
    if ( !preg_match( "/<strong>Huidige aanbieder<\/strong>.*?<p>(.*?)<\/p>/si", $strPage, $matches ))
 
        return false;
 
 
 
    return "(GSM) ".$matches[1];
 
}
 
 
 
function fetch_delefoondetective_nl( $_strNumber )
 
{
 
    $strPage = file_get_contents( "http://www.telefoondetective.nl/telefoonnummer/".$_strNumber."/" );
 
 
 
    if ( !preg_match( "/<div\sid=\"name\"><h\d>(.*?)<\/h\d><\/div>/i", $strPage, $matches ))
 
        return false;
 
 
 
    return $matches[1];
 
}
 
 
 
function fetch_gevonden_cc( $_strNumber )
 
{
 
    return false;
 
}
 
 
 
function fetch_zoekenbel_nl( $_strNumber )
 
{
 
    return false;
 
}
 
 
 
function fetch_nummerzoeker_com( $_strNumber )
 
{
 
    return false;
 
}
 
 
 
 
 
function fetch_nummerid_com( $_strNumber )
 
{
 
    return false;
 
}
 
 
 
function fetch_gebeld_nl( $_strNumber )
 
{
 
    return false;
 
}
 
 
 
function dbLookup( $_arrNumberInfo )
 
{
 
    if (!$db = mysql_connect( NULL, "username", "password" ))
 
        return false;
 
 
 
    // TODO: close db
 
    if (!mysql_select_db( MYSQL_DB, $db ))
 
        return false;
 
 
 
    // Prevent SQL injection on variables
 
    $country = mysql_real_escape_string( $_arrNumberInfo['country'] );
 
    $international = mysql_real_escape_string( $_arrNumberInfo['international'] );
 
 
 
    // Full number partial listing (experimental)
 
    $query = "SELECT name FROM telephone_names WHERE country_code=".$country." AND INSTR( '".$international."', number ) = 1 ORDER BY LENGTH(number), sortorder LIMIT 1";
 
 
 
    if (!$result = mysql_query( $query, $db ))
 
        return false;
 
 
 
    $row = mysql_fetch_row( $result );
 
    mysql_close( $db );
 
    return $row[0];
 
}
 
 
 
 
 
function dbInsert( $_arrNumberInfo )
 
{
 
    if (!$db = mysql_connect( NULL, "username", "password" ))
 
        return false;
 
 
 
    // TODO: close db
 
    if (!mysql_select_db( "freeswitch_cidlookup", $db ))
 
        return false;
 
 
 
    // Prevent SQL injection on variables
 
    $country = mysql_real_escape_string( $_arrNumberInfo['country'] );
 
    $international = mysql_real_escape_string( $_arrNumberInfo['international'] );
 
    $name = mysql_real_escape_string( $_arrNumberInfo['name'] );
 
 
 
    $query = "INSERT INTO telephone_names (country_code,number,name) VALUES (".$country.",'".$international."','".$name."')";
 
 
 
    if (!$result = mysql_query( $query, $db ))
 
    {
 
        echo mysql_error( $db );
 
        return false;
 
    }
 
 
 
    mysql_close( $db );
 
 
 
    return true;
 
}
 
 
 
 
 
function getExtension( $_strExtension )
 
{
 
    return false;
 
    //return "Ext. ".$_strExtension;
 
}
 
 
 
function normalizeNumber( $_strNumber )
 
{
 
    $arrInfo = array();
 
 
 
    if ( preg_match( "/^([19]\d+)/", $_strNumber, $matches ))
 
    {
 
        $arrInfo['local'] = $matches[1];
 
        $arrInfo['type'] = 'extension';
 
        return $arrInfo;
 
    }
 
 
 
    $_strNumber = preg_replace( "/^([2345678])/", COUNTRY.REGION.'$1', $_strNumber );
 
 
 
    // Add country on national dials
 
    $_strNumber = preg_replace( "/^(0)([^0].*)/", COUNTRY.'$2', $_strNumber );
 
 
 
    // Replace + and 00 international symbols before parsing (include space for URI conversion
 
    $_strNumber = preg_replace( "/^( |\+|00)/", '', $_strNumber );
 
 
 
    $arrInfo['country'] = intval( substr( $_strNumber, 0, 2 ));
 
    $arrInfo['international'] = $_strNumber;
 
    $arrInfo['type'] = 'international';
 
 
 
    // National number?
 
    if ( $arrInfo['country'] == intval( COUNTRY ))
 
    {
 
        // only works with countries of 2 digits; replaces it with a 0
 
        $arrInfo['national'] = "0".substr( $_strNumber, 2 );
 
        $arrInfo['type'] = 'national';
 
    }
 
 
 
    return $arrInfo;
 
};
 
 
 
function GetInfo( $_strNumber )
 
{
 
    global $arrNumbers;
 
 
 
    $_strNumber = preg_replace( "/^([2345678])/", COUNTRY.REGION.'$1', $_strNumber );
 
 
 
    // Add country on national dials
 
    $_strNumber = preg_replace( "/^(0)([^0].*)/", COUNTRY.'$2', $_strNumber );
 
 
 
    // Replace + and 00 international symbols before parsing
 
    $_strNumber = preg_replace( "/^(\+|00)/", '', $_strNumber );
 
 
 
    return _getInfo( str_split( $_strNumber ));
 
};
 
 
 
function _getInfo( $_arrNumber )
 
{
 
    global $arrNumbers;
 
 
 
    $arrInfo = array();
 
 
 
    $arrNumberInfo = $arrNumbers;
 
    $nIndent = 0;
 
    $strDigits = "";
 
    $strDetailedInfo = "";
 
    foreach ( $_arrNumber as $digit )
 
    {
 
        if ( isset( $arrNumberInfo[$digit] ) )
 
        {
 
            $strDigits .= $digit;
 
            $arrNumberInfo = $arrNumberInfo[$digit];
 
            if ( isset( $arrNumberInfo['info'] ) )
 
            {
 
                $arrInfo[] = str_repeat( "-", $nIndent ) . $strDigits . " " . $arrNumberInfo['info'];
 
                $strDigits = "";
 
                $strDetailedInfo = $arrNumberInfo['info'];
 
            }
 
            $nIndent++;
 
        } else {
 
            break;
 
        }
 
    }
 
 
 
    return $strDetailedInfo;
 
}
 
 
 
////////////////////////////////////////////////////////////////////////////////
 
// Helpers
 
////////////////////////////////////////////////////////////////////////////////
 
function getVar( $_strVarName, $_bAllowGet = false )
 
{
 
    // If _POST var is set, return _POST var,
 
    // else, if _GET var is set and is allowed, return _GET var
 
    // else, requested var not found: return NULL
 
    if ( isset( $_POST[ $_strVarName ] ) )
 
        return $_POST[ $_strVarName ];
 
    else if ( isset( $_GET[ $_strVarName ] ) && ($_bAllowGet == true) )
 
        return $_GET[ $_strVarName ];
 
    else
 
        return NULL;
 
}
 
?>
 
</pre>
 
 
 
=== dialing out ===
 
This default dialplan snippet does a caller id lookup, and updates the callee name which will be visible on the local extension
 
 
 
<pre>
 
<extension name="National_numbers">
 
    <condition field="destination_number" expression="^0([1-578]\d{8})$">
 
        <action application="set" data="effective_caller_id_number=${outbound_caller_id}"/>
 
        <action application="export" data="callee_id_name=${cidlookup(0031$1)}" />
 
        <action application="bridge" data="sofia/gateway/myLandLineProvider/31$1"/>
 
    </condition>
 
</extension>
 
</pre>
 
 
 
=== incoming calls ===
 
This public dialplan snippet somewhat at the top sets the number (if any) first, checks if it has an international prefix, does a lookup for incoming calls and will set the name accordingly.
 
 
 
The second part will strip any leading + sign
 
 
 
<pre>
 
<extension name="fix_cidnam" continue="true">
 
    <!--make sure the module is loaded, or else loading it will kill our call!-->
 
    <!-- Simple case: name=number or name is empty -->
 
    <!-- and number is a 10digit (excluding optional leading 1), in nanpa nxx-nxx-xxxx form -->
 
    <!-- will skipurl lookup if not a 10digit # (don't lookup INTL), and instead just query the SQL -->
 
    <condition field="${module_exists(mod_cidlookup)}" expression="true"/>
 
    <condition field="caller_id_name" expression="^${caller_id_number}$|^$"/>
 
    <condition field="caller_id_number" expression="^(\+|00)(\d+)$">
 
        <action application="cidlookup" data="00$2"/>
 
        <anti-action application="cidlookup" data="${caller_id_number}"/>
 
    </condition>
 
</extension>
 
  
<extension name="fix_cidnam_plus" continue="true">
+
=== old implementation ===
    <!-- if the name starts with + followed by digits, strip the
+
The "inline" old script can be found here: https://ackspace.nl/w/index.php?title=Telephone_system:Number_lookup&oldid=2652
        + and then pass the number -->
 
    <condition field="caller_id_name" expression="^\+(1[2-9]\d\d[2-9]\d{6})$">
 
        <action application="cidlookup" data="$1"/>
 
    </condition>
 
</extension>
 
</pre>
 
  
 
=== todo ===
 
=== todo ===
 
items stored in the database will not be updated anymore. The only way to refresh the number's information is to remove the entry manually which will cause a new lookup the next time that number is requested.
 
items stored in the database will not be updated anymore. The only way to refresh the number's information is to remove the entry manually which will cause a new lookup the next time that number is requested.
 +
[[Category:Telephony]][[Category:Telephone snippet]][[Category:FreeSWITCH]]

Latest revision as of 14:25, 22 April 2023

Project: Telephone system:Number lookup
Featured: No
State Active
Members Xopr
GitHub cidlookup
Description Caller ID lookup
Picture
No project picture! Fill in form Picture or Upload a jpeg here

This script uses mod_cidlookup combined with a custom php page. It tests the number against a SQLite database, several reversed number lookup websites, the national telecommunications authority database and a coarse array of areas of the world, which are called in order of granularity. The script can be called both on outgoing and incoming calls

We make use of the mod_cidlookup for ease of use, but not all features are functional in our implementation. Every request is done via HTTP requests to a php script that will check if the number:

  • is an extension (and returns the name for that)
  • is stored in the local SQLite database, and return that
  • can be found online by using reversed number lookup websites for landlines
  • can be found online by using the national telecommunications authority database (acm.nl) for cell phones returning the associated cell provider
  • can be categorized by a more coarse lookup, like continent, country, region, town or number block owner, stored in a local array (~500 entries)

The setting for mod_cidlookup is:

<param name="url" value="https://domain.tld/cid.php?key=<your_desired_key>&number=${caller_id_number}"/>

old implementation

The "inline" old script can be found here: https://ackspace.nl/w/index.php?title=Telephone_system:Number_lookup&oldid=2652

todo

items stored in the database will not be updated anymore. The only way to refresh the number's information is to remove the entry manually which will cause a new lookup the next time that number is requested.