Procházet zdrojové kódy

phonenum: new module to do lookup on phone numbers

- relies on libphonenumber to get the attributes associated with the
  phone number
Daniel-Constantin Mierla před 8 roky
rodič
revize
12b2a24957

+ 25 - 0
src/modules/phonenum/Makefile

@@ -0,0 +1,25 @@
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=phonenum.so
+
+CXX=g++
+LD=g++
+LIB_DIR = /opt/local/lib
+
+LIBS= -L${LIB_DIR} cphonenumber.o -lphonenumber
+
+DEFS+= -I/opt/local/include -DKAMAILIO_MOD_INTERFACE
+
+CXXFLAGS=$(CFLAGS:-Wno-deprecated option=)
+CXXFLAGS+=-Wno-write-strings -Wno-deprecated -Wno-unused-function -Wno-sign-compare -Wno-strict-aliasing
+
+include ../../Makefile.modules
+
+cphonenumber.o: cphonenumber.cpp cphonenumber.h
+	@echo "Compiling $<"
+	$(CXX) $(CXXFLAGS) $(CFLAGS) $(C_DEFS) $(DEFS) -c $< -o $@
+
+phonenum.so: cphonenumber.o

+ 138 - 0
src/modules/phonenum/README

@@ -0,0 +1,138 @@
+PHONENUM Module
+
+Daniel-Constantin Mierla
+
+   asipto.com
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+   Copyright © 2017 Daniel-Constantin Mierla (asipto.com)
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. smode (int)
+
+        4. Functions
+
+              4.1. phonenum_match(num, pvc)
+
+        5. Pseudo Variables
+
+   List of Examples
+
+   1.1. Set smode parameter
+   1.2. phonenum_match usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. smode (int)
+
+   4. Functions
+
+        4.1. phonenum_match(num, pvc)
+
+   5. Pseudo Variables
+
+1. Overview
+
+   This module allows real-time queries against the libphonenumber to be
+   performed from the config script. With that it is possible to get
+   normalize and get details about a phone number.
+
+   More details about libphonenumber can be found at
+   https://github.com/googlei18n/libphonenumber.
+
+   This module exports a new class of pseudo-variables - $phn(pvc=>key) -
+   to enable access to the results of a query to the database.
+
+   Many queries can be done and store results in different containers to
+   be able to use in parallel.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * libphonenumber - the phone number library.
+
+3. Parameters
+
+   3.1. smode (int)
+
+3.1. smode (int)
+
+   Phone number search mode.
+
+   Default value is "0".
+
+   Example 1.1. Set smode parameter
+...
+modparam("phonenum", "smode", 0)
+...
+
+4. Functions
+
+   4.1. phonenum_match(num, pvc)
+
+4.1. phonenum_match(num, pvc)
+
+   Match num against the libphonenumber and set the attributes inside the
+   pvc container. The function has to be called before accessing a key
+   via: $phn(pvc=>key).
+
+   The parameters can be static strings or strings with variables.
+
+   It can be used from ANY_ROUTE.
+
+   Example 1.2. phonenum_match usage
+...
+if(phonenum_match("1-484-555-8888", "src"))
+    xlog("number normalized to: $phn(src=>num)\n");
+...
+
+5. Pseudo Variables
+
+     * $phn(pvc=>key) - pvc is an identifier for this query result; it is
+       designated by the second parameter of phonenum_match(). The key can
+       be one of the following:
+          + number - normalized phone number
+          + country - country for phone number
+          + region - region for phone number
+          + operator - operator for phone number
+
+   Exported pseudo-variables are documented at
+   https://www.kamailio.org/wiki/.

+ 179 - 0
src/modules/phonenum/cphonenumber.cpp

@@ -0,0 +1,179 @@
+/**
+ *
+ * Copyright (C) 2017 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <phonenumbers/geocoding/phonenumber_offline_geocoder.h>
+#include <phonenumbers/phonenumberutil.h>
+#include <unicode/locid.h>
+#include <string.h>
+#include <cstring>
+#include <string>
+#include "cphonenumber.h"
+
+using namespace i18n::phonenumbers;
+using icu::Locale;
+using std::string;
+
+const PhoneNumberUtil& _phoneUtil(*PhoneNumberUtil::GetInstance());
+static PhoneNumberOfflineGeocoder *_phoneGeoCoder = new PhoneNumberOfflineGeocoder();
+
+const char* telnum_linetype(PhoneNumberUtil::PhoneNumberType ltype)
+{
+	switch(ltype) {
+      case PhoneNumberUtil::FIXED_LINE:
+	  	return "fixed-line";
+      case PhoneNumberUtil::MOBILE:
+	  	return "mobile";
+      // In some regions (e.g. the USA), it is impossible to distinguish between
+      // fixed-line and mobile numbers by looking at the phone number itself.
+      case PhoneNumberUtil::FIXED_LINE_OR_MOBILE:
+	  	return "fixed-line-or-mobile";
+      // Freephone lines
+      case PhoneNumberUtil::TOLL_FREE:
+	  	return "toll-free";
+      case PhoneNumberUtil::PREMIUM_RATE:
+	  	return "premium-rate";
+      // The cost of this call is shared between the caller and the recipient, and
+      // is hence typically less than PREMIUM_RATE calls. See
+      // http://en.wikipedia.org/wiki/Shared_Cost_Service for more information.
+      case PhoneNumberUtil::SHARED_COST:
+	  	return "shared-cost";
+      // Voice over IP numbers. This includes TSoIP (Telephony Service over IP).
+      case PhoneNumberUtil::VOIP:
+	  	return "voip";
+      // A personal number is associated with a particular person, and may be
+      // routed to either a MOBILE or FIXED_LINE number. Some more information can
+      // be found here: http://en.wikipedia.org/wiki/Personal_Numbers
+      case PhoneNumberUtil::PERSONAL_NUMBER:
+	  	return "personal-number";
+      case PhoneNumberUtil::PAGER:
+	  	return "pager";
+      // Used for "Universal Access Numbers" or "Company Numbers". They may be
+      // further routed to specific offices, but allow one number to be used for a
+      // company.
+      case PhoneNumberUtil::UAN:
+	  	return "uan";
+      // Used for "Voice Mail Access Numbers".
+      case PhoneNumberUtil::VOICEMAIL:
+	  	return "voicemail";
+      // A phone number is of type UNKNOWN when it does not fit any of the known
+      // patterns for a specific region.
+      case PhoneNumberUtil::UNKNOWN:
+	  	return "unknown";
+    }
+	return "unknown";
+}
+int telnum_possible(char* number, char* region)
+{
+	string numStr(number);
+	string regionStr(region);
+
+	bool isPossible = _phoneUtil.IsPossibleNumberForString(numStr, regionStr);
+	return (isPossible ? 1 : 0);
+}
+
+char* telnum_cc(char* number)
+{
+	string numStr(number);
+	string defaultRegion("ZZ");
+	PhoneNumber parsedNumber;
+
+	PhoneNumberUtil::ErrorType error = _phoneUtil.Parse(numStr, defaultRegion, &parsedNumber);
+	if (error != PhoneNumberUtil::NO_PARSING_ERROR) {
+		return NULL;
+	}
+	string regionCode;
+	_phoneUtil.GetRegionCodeForNumber(parsedNumber, &regionCode);
+	return strdup(regionCode.c_str());
+}
+
+telnum_t* telnum_parse(char* number, char* region)
+{
+	string numStr(number);
+	string regionStr(region);
+
+	PhoneNumber parsedNumber;
+	PhoneNumberUtil::ErrorType error = _phoneUtil.Parse(numStr, regionStr, &parsedNumber);
+	telnum_t* res = telnum_new(number);
+	if(res==NULL) {
+		return NULL;
+	}
+	if (error != PhoneNumberUtil::NO_PARSING_ERROR) {
+		string error = "Parsing number failed";
+		res->error = strdup(error.c_str());
+		return res;
+	}
+	if (!_phoneUtil.IsValidNumber(parsedNumber)) {
+		string error = "Invalid number";
+		res->error = strdup(error.c_str());
+		return res;
+	}
+	res->valid = 1;
+	string formattedNumber;
+	_phoneUtil.Format(parsedNumber, PhoneNumberUtil::E164, &formattedNumber);
+	res->normalized = strdup(formattedNumber.c_str());
+	string descNumber = _phoneGeoCoder->GetDescriptionForNumber(parsedNumber, Locale("en"));
+	res->ndesc = strdup(descNumber.c_str());
+	res->ltype = strdup(telnum_linetype(_phoneUtil.GetNumberType(parsedNumber)));
+	res->cctel = _phoneUtil.GetCountryCodeForRegion(regionStr);
+
+	return res;
+}
+
+telnum_t* telnum_new(char* number)
+{
+	telnum_t* tn = (telnum_t*)malloc(sizeof(telnum_t));
+	if(tn==NULL) {
+		return NULL;
+	}
+	tn->valid = 0;
+	tn->cctel = 0;
+	tn->number = strdup(number);
+	tn->normalized = NULL;
+	tn->ltype = NULL;
+	tn->ndesc = NULL;
+	tn->error = NULL;
+	return tn;
+}
+
+void telnum_free(telnum_t* tn)
+{
+	if(tn==NULL) {
+		return;
+	}
+	if (tn->number) {
+		free(tn->number);
+	}
+	if (tn->normalized) {
+		free(tn->normalized);
+	}
+	if (tn->error) {
+		free(tn->error);
+	}
+	if (tn->ltype) {
+		free(tn->ltype);
+	}
+	if (tn->ndesc) {
+		free(tn->ndesc);
+	}
+	free(tn);
+}

+ 56 - 0
src/modules/phonenum/cphonenumber.h

@@ -0,0 +1,56 @@
+/**
+ *
+ * Copyright (C) 2017 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _CPHONENUMBER_H_
+#define _CPHONENUMBER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Phone number details
+typedef struct telnum {
+  char* number;
+  char* normalized;
+  char* ltype;
+  char* ndesc;
+  char* error;
+  int cctel;
+  int valid;
+} telnum_t;
+
+telnum_t* telnum_new(char*);
+void telnum_free(telnum_t*);
+
+// test if number is possible
+int telnum_possible(char* number, char* region);
+// parse a number
+telnum_t* telnum_parse(char* number, char* region);
+// get country code for number
+char* telnum_cc(char* number);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 4 - 0
src/modules/phonenum/doc/Makefile

@@ -0,0 +1,4 @@
+docs = phonenum.xml
+
+docbook_dir = ../../../../doc/docbook
+include $(docbook_dir)/Makefile.module

+ 36 - 0
src/modules/phonenum/doc/phonenum.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>PHONENUM Module</title>
+	<productname class="trade">&kamailioname;</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<affiliation><orgname>asipto.com</orgname></affiliation>
+	    </author>
+	    <editor>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		    <email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2017</year>
+	    <holder>Daniel-Constantin Mierla (asipto.com)</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+
+	<xi:include href="phonenum_admin.xml"/>
+
+</book>

+ 154 - 0
src/modules/phonenum/doc/phonenum_admin.xml

@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Module User's Guide -->
+
+<chapter>
+
+    <title>&adminguide;</title>
+
+    <section>
+	<title>Overview</title>
+	<para>
+		This module allows real-time queries against the libphonenumber
+		to be performed from the config script. With that it is possible
+		to get normalize and get details about a phone number.
+	</para>
+	<para>
+		More details about libphonenumber can be found at
+		<ulink url="https://github.com/googlei18n/libphonenumber">
+			https://github.com/googlei18n/libphonenumber</ulink>.
+	</para>
+	<para>
+		This module exports a new class of pseudo-variables -
+		$phn(pvc=&gt;key) - to enable access to the results of a query to the
+		database.
+	</para>
+	<para>
+		Many queries can be done and store results in different containers to
+		be able to use in parallel.
+	</para>
+    </section>
+    <section>
+	<title>Dependencies</title>
+	<section>
+	    <title>&kamailio; Modules</title>
+	    <para>
+		The following modules must be loaded before this module:
+	    	<itemizedlist>
+		    <listitem>
+			<para>
+			    <emphasis>none</emphasis>.
+			</para>
+		    </listitem>
+	    	</itemizedlist>
+	    </para>
+	</section>
+	<section>
+	    <title>External Libraries or Applications</title>
+	    <para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+	    	<itemizedlist>
+		    <listitem>
+			<para>
+			    <emphasis>libphonenumber</emphasis> - the phone number library.
+			</para>
+		    </listitem>
+	    	</itemizedlist>
+	    </para>
+	</section>
+    </section>
+    <section>
+	<title>Parameters</title>
+	<section>
+	    <title><varname>smode</varname> (int)</title>
+	    <para>
+		Phone number search mode.
+	    </para>
+	    <para>
+		<emphasis>
+		    Default value is <quote>0</quote>.
+		</emphasis>
+	    </para>
+	    <example>
+		<title>Set <varname>smode</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("phonenum", "smode", 0)
+...
+</programlisting>
+	    </example>
+	</section>
+
+	</section>
+
+    <section>
+	<title>Functions</title>
+ 	<section>
+	    <title>
+		<function moreinfo="none">phonenum_match(num, pvc)</function>
+	    </title>
+	    <para>
+			Match num against the libphonenumber and set the attributes inside
+			the pvc container. The function has to be called before accessing
+			a key via: $phn(pvc=&gt;key).
+	    </para>
+	    <para>
+	    	The parameters can be static strings or strings with variables.
+	    </para>
+	    <para>
+	    	It can be used from ANY_ROUTE.
+	    </para>
+		<example>
+		<title><function>phonenum_match</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(phonenum_match("1-484-555-8888", "src"))
+    xlog("number normalized to: $phn(src=&gt;num)\n");
+...
+</programlisting>
+	    </example>
+	</section>
+
+    </section>
+
+	<section>
+		<title>Pseudo Variables</title>
+		<itemizedlist>
+			<listitem><para>
+				<emphasis>$phn(pvc=&gt;key)</emphasis> - <emphasis>pvc</emphasis>
+				is an identifier for this query result; it is designated by
+				the second parameter of phonenum_match().
+				The <emphasis>key</emphasis> can be one of the following:
+				</para>
+			<itemizedlist>
+				<listitem><para>
+					<emphasis>number</emphasis> - normalized phone number
+				</para></listitem>
+				<listitem><para>
+					<emphasis>country</emphasis> - country for phone number
+				</para></listitem>
+				<listitem><para>
+					<emphasis>region</emphasis> - region for phone number
+				</para></listitem>
+				<listitem><para>
+					<emphasis>operator</emphasis> - operator for phone number
+				</para></listitem>
+			</itemizedlist>
+			</listitem>
+		</itemizedlist>
+		<para>
+		Exported pseudo-variables are documented at &kamwikilink;.
+		</para>
+	</section>
+
+</chapter>
+

+ 150 - 0
src/modules/phonenum/phonenum_mod.c

@@ -0,0 +1,150 @@
+/**
+ *
+ * Copyright (C) 2017 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../core/sr_module.h"
+#include "../../core/dprint.h"
+#include "../../core/ut.h"
+#include "../../core/pvar.h"
+#include "../../core/kemi.h"
+#include "../../core/mod_fix.h"
+
+#include "phonenum_pv.h"
+
+MODULE_VERSION
+
+static int phonenum_smode = 0;
+
+static int  mod_init(void);
+static void mod_destroy(void);
+
+static int w_phonenum_match(struct sip_msg* msg, char* str1, char* str2);
+static int phonenum_match(sip_msg_t *msg, str *tomatch, str *pvclass);
+
+static pv_export_t mod_pvs[] = {
+	{ {"phn", sizeof("phn")-1}, PVT_OTHER, pv_get_phonenum, 0,
+		pv_parse_phonenum_name, 0, 0, 0 },
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+
+static cmd_export_t cmds[]={
+	{"phonenum_match", (cmd_function)w_phonenum_match, 2, fixup_spve_spve,
+		0, ANY_ROUTE},
+	{0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[]={
+	{"smode", PARAM_INT, &phonenum_smode},
+	{0, 0, 0}
+};
+
+struct module_exports exports = {
+	"phonenum",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,
+	0,
+	0,              /* exported MI functions */
+	mod_pvs,        /* exported pseudo-variables */
+	0,              /* extra processes */
+	mod_init,       /* module initialization function */
+	0,              /* response function */
+	mod_destroy,    /* destroy function */
+	0               /* per child init function */
+};
+
+
+/**
+ * init module function
+ */
+static int mod_init(void)
+{
+
+	if(phonenum_init_pv(phonenum_smode)!=0)
+	{
+		LM_ERR("cannot do init\n");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * destroy module function
+ */
+static void mod_destroy(void)
+{
+	phonenum_destroy_pv();
+}
+
+
+static int phonenum_match(sip_msg_t *msg, str *tomatch, str *pvclass)
+{
+	phonenum_pv_reset(pvclass);
+
+	return phonenum_update_pv(tomatch, pvclass);
+}
+
+static int w_phonenum_match(sip_msg_t* msg, char* target, char* pvname)
+{
+	str tomatch = STR_NULL;
+	str pvclass = STR_NULL;
+
+	if(msg==NULL) {
+		LM_ERR("received null msg\n");
+		return -1;
+	}
+
+	if(fixup_get_svalue(msg, (gparam_t*)target, &tomatch)<0) {
+		LM_ERR("cannot get the address\n");
+		return -1;
+	}
+	if(fixup_get_svalue(msg, (gparam_t*)pvname, &pvclass)<0) {
+		LM_ERR("cannot get the pv class\n");
+		return -1;
+	}
+
+	return phonenum_match(msg, &tomatch, &pvclass);
+}
+
+/**
+ *
+ */
+static sr_kemi_t sr_kemi_phonenum_exports[] = {
+    { str_init("phonenum"), str_init("match"),
+        SR_KEMIP_INT, phonenum_match,
+        { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
+            SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
+    },
+
+    { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
+};
+
+int mod_register(char *path, int *dlflags, void *p1, void *p2) {
+    sr_kemi_modules_add(sr_kemi_phonenum_exports);
+    return 0;
+}

+ 299 - 0
src/modules/phonenum/phonenum_pv.c

@@ -0,0 +1,299 @@
+/**
+ *
+ * Copyright (C) 2017 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "../../core/dprint.h"
+#include "../../core/hashes.h"
+#include "../../core/pvar.h"
+
+#include "cphonenumber.h"
+#include "phonenum_pv.h"
+
+typedef struct _sr_phonenum_record {
+	telnum_t *record;
+	char *number;
+	char *country;
+	char *region;
+	char *operator;
+	char tomatch[256];
+	int flags;
+} sr_phonenum_record_t;
+
+typedef struct _sr_phonenum_item {
+	str pvclass;
+	unsigned int hashid;
+	sr_phonenum_record_t r;
+	struct _sr_phonenum_item *next;
+} sr_phonenum_item_t;
+
+typedef struct _phonenum_pv {
+	sr_phonenum_item_t *item;
+	int type;
+} phonenum_pv_t;
+
+
+static sr_phonenum_item_t *_sr_phonenum_list = NULL;
+
+sr_phonenum_record_t *sr_phonenum_get_record(str *name)
+{
+	sr_phonenum_item_t *it = NULL;
+	unsigned int hashid = 0;
+
+	hashid =  get_hash1_raw(name->s, name->len);
+
+	it = _sr_phonenum_list;
+	while(it!=NULL)
+	{
+		if(it->hashid==hashid && it->pvclass.len == name->len
+				&& strncmp(it->pvclass.s, name->s, name->len)==0)
+			return &it->r;
+		it = it->next;
+	}
+	return NULL;
+}
+
+sr_phonenum_item_t *sr_phonenum_add_item(str *name)
+{
+	sr_phonenum_item_t *it = NULL;
+	unsigned int hashid = 0;
+
+	hashid =  get_hash1_raw(name->s, name->len);
+
+	it = _sr_phonenum_list;
+	while(it!=NULL)
+	{
+		if(it->hashid==hashid && it->pvclass.len == name->len
+				&& strncmp(it->pvclass.s, name->s, name->len)==0)
+			return it;
+		it = it->next;
+	}
+	/* add new */
+	it = (sr_phonenum_item_t*)pkg_malloc(sizeof(sr_phonenum_item_t));
+	if(it==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		return NULL;
+	}
+	memset(it, 0, sizeof(sr_phonenum_item_t));
+	it->pvclass.s = (char*)pkg_malloc(name->len+1);
+	if(it->pvclass.s==NULL)
+	{
+		LM_ERR("no more pkg.\n");
+		pkg_free(it);
+		return NULL;
+	}
+	memcpy(it->pvclass.s, name->s, name->len);
+	it->pvclass.s[name->len] = '\0';
+	it->pvclass.len = name->len;
+	it->hashid = hashid;
+	it->next = _sr_phonenum_list;
+	_sr_phonenum_list = it;
+	return it;
+}
+
+
+int pv_parse_phonenum_name(pv_spec_p sp, str *in)
+{
+	phonenum_pv_t *gpv=NULL;
+	char *p;
+	str pvc;
+	str pvs;
+	if(sp==NULL || in==NULL || in->len<=0)
+		return -1;
+
+	gpv = (phonenum_pv_t*)pkg_malloc(sizeof(phonenum_pv_t));
+	if(gpv==NULL)
+		return -1;
+
+	memset(gpv, 0, sizeof(phonenum_pv_t));
+
+	p = in->s;
+
+	while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+		p++;
+	if(p>in->s+in->len || *p=='\0')
+		goto error;
+	pvc.s = p;
+	while(p < in->s + in->len)
+	{
+		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r')
+			break;
+		p++;
+	}
+	if(p>in->s+in->len || *p=='\0')
+		goto error;
+	pvc.len = p - pvc.s;
+	if(*p!='=')
+	{
+		while(p<in->s+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r'))
+			p++;
+		if(p>in->s+in->len || *p=='\0' || *p!='=')
+			goto error;
+	}
+	p++;
+	if(*p!='>')
+		goto error;
+	p++;
+
+	pvs.len = in->len - (int)(p - in->s);
+	pvs.s = p;
+	LM_DBG("phonenum [%.*s] - key [%.*s]\n", pvc.len, pvc.s,
+			pvs.len, pvs.s);
+
+	gpv->item = sr_phonenum_add_item(&pvc);
+	if(gpv->item==NULL)
+		goto error;
+
+	switch(pvs.len)
+	{
+		case 6:
+			if(strncmp(pvs.s, "number", 6)==0)
+				gpv->type = 0;
+			else if(strncmp(pvs.s, "region", 6)==0)
+				gpv->type = 2;
+			else goto error;
+		break;
+		case 7:
+			if(strncmp(pvs.s, "country", 7)==0)
+				gpv->type = 1;
+			else goto error;
+		break;
+		case 8:
+			if(strncmp(pvs.s, "operator", 8)==0)
+				gpv->type = 3;
+			else goto error;
+		break;
+		default:
+			goto error;
+	}
+	sp->pvp.pvn.u.dname = (void*)gpv;
+	sp->pvp.pvn.type = PV_NAME_OTHER;
+
+	return 0;
+
+error:
+	if(gpv!=NULL)
+		pkg_free(gpv);
+
+	LM_ERR("error at PV phonenum name: %.*s\n", in->len, in->s);
+	return -1;
+}
+
+int pv_phonenum_get_strzval(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res, char *sval)
+{
+	str s;
+	if(sval==NULL)
+		return pv_get_null(msg, param, res);
+
+	s.s = sval;
+	s.len = strlen(s.s);
+	return pv_get_strval(msg, param, res, &s);
+}
+
+int pv_get_phonenum(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res)
+{
+	phonenum_pv_t *gpv;
+
+	if(msg==NULL || param==NULL)
+		return -1;
+
+	gpv = (phonenum_pv_t*)param->pvn.u.dname;
+	if(gpv==NULL)
+		return -1;
+	if(gpv->item==NULL)
+		return pv_get_null(msg, param, res);
+
+	switch(gpv->type)
+	{
+		case 1: /* country */
+			return pv_get_null(msg, param, res);
+		case 2: /* region */
+			return pv_get_null(msg, param, res);
+		case 3: /* operator */
+			return pv_get_null(msg, param, res);
+		default: /* number */
+			return pv_get_null(msg, param, res);
+	}
+}
+
+int phonenum_init_pv(int smode)
+{
+	return 0;
+}
+
+void phonenum_destroy_list(void)
+{
+}
+
+void phonenum_destroy_pv(void)
+{
+}
+
+void phonenum_pv_reset(str *name)
+{
+	sr_phonenum_record_t *gr = NULL;
+
+	gr = sr_phonenum_get_record(name);
+
+	if(gr==NULL)
+		return;
+	memset(gr, 0, sizeof(sr_phonenum_record_t));
+}
+
+int phonenum_update_pv(str *tomatch, str *name)
+{
+	sr_phonenum_record_t *gr = NULL;
+
+	if(tomatch->len>255)
+	{
+		LM_DBG("target too long (max 255): %s\n", tomatch->s);
+		return -3;
+	}
+
+	gr = sr_phonenum_get_record(name);
+	if(gr==NULL)
+	{
+		LM_DBG("container not found: %s\n", tomatch->s);
+		return - 4;
+	}
+
+	strncpy(gr->tomatch, tomatch->s, tomatch->len);
+	gr->tomatch[tomatch->len] = '\0';
+	LM_DBG("attempt to match: %s\n", gr->tomatch);
+	if (gr->record == NULL)
+	{
+		LM_DBG("no match for: %s\n", gr->tomatch);
+		return -2;
+	}
+	LM_DBG("phonenum PV updated for: %s\n", gr->tomatch);
+
+	return 1;
+}

+ 39 - 0
src/modules/phonenum/phonenum_pv.h

@@ -0,0 +1,39 @@
+/**
+ *
+ * Copyright (C) 2017 Daniel-Constantin Mierla (asipto.com)
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file 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 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _PHONENUM_PV_H_
+#define _PHONENUM_PV_H_
+
+#include "../../core/pvar.h"
+
+int pv_parse_phonenum_name(pv_spec_p sp, str *in);
+int pv_get_phonenum(struct sip_msg *msg, pv_param_t *param,
+		pv_value_t *res);
+
+int phonenum_init_pv(int smode);
+void phonenum_destroy_pv(void);
+void phonenum_pv_reset(str *pvclass);
+int phonenum_update_pv(str *tomatch, str *pvclass);
+
+#endif
+