src/modules/phonenum/phonenum_pv.c
12b2a249
 /**
  *
  * 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"
 
103173e6
 /* clang-format off */
12b2a249
 typedef struct _sr_phonenum_record {
 	telnum_t *record;
 	char tomatch[256];
103173e6
 	long flags;
12b2a249
 } 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;
103173e6
 /* clang-format on */
12b2a249
 
 
 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;
 
103173e6
 	hashid = get_hash1_raw(name->s, name->len);
12b2a249
 
 	it = _sr_phonenum_list;
103173e6
 	while(it != NULL) {
 		if(it->hashid == hashid && it->pvclass.len == name->len
 				&& strncmp(it->pvclass.s, name->s, name->len) == 0)
12b2a249
 			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;
 
103173e6
 	hashid = get_hash1_raw(name->s, name->len);
12b2a249
 
 	it = _sr_phonenum_list;
103173e6
 	while(it != NULL) {
 		if(it->hashid == hashid && it->pvclass.len == name->len
 				&& strncmp(it->pvclass.s, name->s, name->len) == 0)
12b2a249
 			return it;
 		it = it->next;
 	}
 	/* add new */
103173e6
 	it = (sr_phonenum_item_t *)pkg_malloc(sizeof(sr_phonenum_item_t));
 	if(it == NULL) {
12b2a249
 		LM_ERR("no more pkg\n");
 		return NULL;
 	}
 	memset(it, 0, sizeof(sr_phonenum_item_t));
103173e6
 	it->pvclass.s = (char *)pkg_malloc(name->len + 1);
 	if(it->pvclass.s == NULL) {
12b2a249
 		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;
 }
 
67412b4b
 int sr_phonenum_add_resid(str *rname)
 {
 	if(sr_phonenum_add_item(rname)==NULL) {
 		return -1;
 	}
 	return 0;
 }
12b2a249
 
 int pv_parse_phonenum_name(pv_spec_p sp, str *in)
 {
103173e6
 	phonenum_pv_t *gpv = NULL;
12b2a249
 	char *p;
 	str pvc;
 	str pvs;
103173e6
 	if(sp == NULL || in == NULL || in->len <= 0)
12b2a249
 		return -1;
 
103173e6
 	gpv = (phonenum_pv_t *)pkg_malloc(sizeof(phonenum_pv_t));
 	if(gpv == NULL)
12b2a249
 		return -1;
 
 	memset(gpv, 0, sizeof(phonenum_pv_t));
 
 	p = in->s;
 
103173e6
 	while(p < in->s + in->len
 			&& (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'))
12b2a249
 		p++;
103173e6
 	if(p > in->s + in->len || *p == '\0')
12b2a249
 		goto error;
 	pvc.s = p;
103173e6
 	while(p < in->s + in->len) {
 		if(*p == '=' || *p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
12b2a249
 			break;
 		p++;
 	}
103173e6
 	if(p > in->s + in->len || *p == '\0')
12b2a249
 		goto error;
 	pvc.len = p - pvc.s;
103173e6
 	if(*p != '=') {
 		while(p < in->s + in->len
 				&& (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'))
12b2a249
 			p++;
103173e6
 		if(p > in->s + in->len || *p == '\0' || *p != '=')
12b2a249
 			goto error;
 	}
 	p++;
103173e6
 	if(*p != '>')
12b2a249
 		goto error;
 	p++;
 
 	pvs.len = in->len - (int)(p - in->s);
 	pvs.s = p;
103173e6
 	LM_DBG("phonenum [%.*s] - key [%.*s]\n", pvc.len, pvc.s, pvs.len, pvs.s);
12b2a249
 
 	gpv->item = sr_phonenum_add_item(&pvc);
103173e6
 	if(gpv->item == NULL)
12b2a249
 		goto error;
 
103173e6
 	switch(pvs.len) {
 		case 5:
2196c677
 			if(strncmp(pvs.s, "ltype", 5) == 0)
103173e6
 				gpv->type = 2;
2196c677
 			else if(strncmp(pvs.s, "ndesc", 5) == 0)
103173e6
 				gpv->type = 3;
2196c677
 			else if(strncmp(pvs.s, "error", 5) == 0)
103173e6
 				gpv->type = 4;
2196c677
 			else if(strncmp(pvs.s, "cctel", 5) == 0)
103173e6
 				gpv->type = 5;
2196c677
 			else if(strncmp(pvs.s, "valid", 5) == 0)
103173e6
 				gpv->type = 6;
 			else
 				goto error;
2196c677
 			break;
12b2a249
 		case 6:
103173e6
 			if(strncmp(pvs.s, "number", 6) == 0)
12b2a249
 				gpv->type = 0;
675f2d6e
 			else if(strncmp(pvs.s, "ccname", 6) == 0)
 				gpv->type = 7;
103173e6
 			else
 				goto error;
 			break;
 		case 10:
 			if(strncmp(pvs.s, "normalized", 10) == 0)
12b2a249
 				gpv->type = 1;
103173e6
 			else
 				goto error;
 			break;
12b2a249
 		default:
 			goto error;
 	}
103173e6
 	sp->pvp.pvn.u.dname = (void *)gpv;
12b2a249
 	sp->pvp.pvn.type = PV_NAME_OTHER;
 
 	return 0;
 
 error:
103173e6
 	if(gpv != NULL)
12b2a249
 		pkg_free(gpv);
 
 	LM_ERR("error at PV phonenum name: %.*s\n", in->len, in->s);
 	return -1;
 }
 
103173e6
 int pv_phonenum_get_strzval(
 		struct sip_msg *msg, pv_param_t *param, pv_value_t *res, char *sval)
12b2a249
 {
 	str s;
103173e6
 	if(sval == NULL)
12b2a249
 		return pv_get_null(msg, param, res);
 
 	s.s = sval;
 	s.len = strlen(s.s);
 	return pv_get_strval(msg, param, res, &s);
 }
 
103173e6
 int pv_get_phonenum(struct sip_msg *msg, pv_param_t *param, pv_value_t *res)
12b2a249
 {
 	phonenum_pv_t *gpv;
 
103173e6
 	if(msg == NULL || param == NULL)
12b2a249
 		return -1;
 
103173e6
 	gpv = (phonenum_pv_t *)param->pvn.u.dname;
 	if(gpv == NULL)
12b2a249
 		return -1;
103173e6
 	if(gpv->item == NULL)
 		return pv_get_null(msg, param, res);
 	if(gpv->item->r.record==NULL)
12b2a249
 		return pv_get_null(msg, param, res);
 
103173e6
 	switch(gpv->type) {
 		case 1: /* normalized */
 			if(gpv->item->r.record->normalized==NULL)
 				return pv_get_null(msg, param, res);
 			return pv_get_strzval(msg, param, res,
 						gpv->item->r.record->normalized);
 		case 2: /* ltype */
 			if(gpv->item->r.record->ltype==NULL)
 				return pv_get_null(msg, param, res);
 			return pv_get_strzval(msg, param, res, gpv->item->r.record->ltype);
 		case 3: /* ndesc */
 			if(gpv->item->r.record->ndesc==NULL)
 				return pv_get_null(msg, param, res);
 			return pv_get_strzval(msg, param, res, gpv->item->r.record->ndesc);
 		case 4: /* error */
 			if(gpv->item->r.record->error==NULL)
 				return pv_get_null(msg, param, res);
 			return pv_get_strzval(msg, param, res, gpv->item->r.record->error);
 		case 5: /* cctel */
 			return pv_get_sintval(msg, param, res, gpv->item->r.record->cctel);
 		case 6: /* valid */
 			return pv_get_sintval(msg, param, res, gpv->item->r.record->valid);
675f2d6e
 		case 7: /* ccname */
 			if(gpv->item->r.record->ccname==NULL)
 				return pv_get_null(msg, param, res);
 			return pv_get_strzval(msg, param, res, gpv->item->r.record->ccname);
12b2a249
 		default: /* number */
103173e6
 			if(gpv->item->r.record->number==NULL)
 				return pv_get_null(msg, param, res);
 			return pv_get_strzval(msg, param, res, gpv->item->r.record->number);
12b2a249
 	}
 }
 
 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);
 
103173e6
 	if(gr == NULL)
12b2a249
 		return;
103173e6
 	if(gr->record != NULL) {
 		telnum_free(gr->record);
 	}
12b2a249
 	memset(gr, 0, sizeof(sr_phonenum_record_t));
 }
 
431e9821
 int phonenum_update_pv(str *tomatch, str *cncode, str *name)
12b2a249
 {
 	sr_phonenum_record_t *gr = NULL;
 
103173e6
 	if(tomatch->len > 255) {
12b2a249
 		LM_DBG("target too long (max 255): %s\n", tomatch->s);
 		return -3;
 	}
 
 	gr = sr_phonenum_get_record(name);
103173e6
 	if(gr == NULL) {
12b2a249
 		LM_DBG("container not found: %s\n", tomatch->s);
103173e6
 		return -4;
 	}
 	if(gr->record != NULL) {
 		telnum_free(gr->record);
12b2a249
 	}
 
 	strncpy(gr->tomatch, tomatch->s, tomatch->len);
 	gr->tomatch[tomatch->len] = '\0';
 	LM_DBG("attempt to match: %s\n", gr->tomatch);
cc7c066d
 	gr->record = telnum_parse(gr->tomatch,
 			(cncode && cncode->len>0)?cncode->s:"ZZ");
103173e6
 	if(gr->record == NULL) {
12b2a249
 		LM_DBG("no match for: %s\n", gr->tomatch);
 		return -2;
 	}
2196c677
 	LM_DBG("phonenum PV updated for: %s (%d/%s/%s)\n", gr->tomatch,
 			gr->record->valid,
 			(gr->record->normalized)?gr->record->normalized:"none",
 			(gr->record->error)?gr->record->error:"none");
12b2a249
 
 	return 1;
 }