<p><a href="https://github.com/miconda" class="user-mention">@miconda</a>, thanks, that is exactly what I have now, so, will submit it when I can. Below is the code that I wrote with a new function named "std_tel2sip()", as a preview I used most of the old procedure where possible, and tried to keep the same style.</p>
<p>I have been given a task with a short deadline, so, will not be able to work on this anymore right now. I will get back to it as soon as possible.</p>
<p>Don.</p>
<pre><code>/*
* Compare function to sort tel: uri options acording to standard
* before inserting into sip: uri
*
* See "RFC 3261 SIP: Session Initiation Protocol June 2002"
* 19.1.6 Relating SIP URIs and tel URLs
*/
typedef struct
{
char *name;
char *value;
} tel_param_t;
#define MAX_TEL_PARAMS (10)
int compare_tel_options(const void *v1, const void *v2)
{
tel_param_t *p1 = (tel_param_t *) v1;
tel_param_t *p2 = (tel_param_t *) v2;
if (0 == strcasecmp(p1->name, "isdn-subaddress"))
{
return -1;
}
else if (0 == strcasecmp(p2->name, "isdn-subaddress"))
{
return 1;
}
else if (0 == strcasecmp(p1->name, "post-dial"))
{
return -1;
}
else if (0 == strcasecmp(p2->name, "post-dial"))
{
return 1;
}
else
{
return strcasecmp(p1->name, p2->name);
}
}
/*
* Remove visual separators from the phone number
* Assume it has been validated as a number containing
* ONLY leading '+', digits, and visual separators.
*/
static void remove_visual_separators_from_phone(char *p)
{
char *p2;
p2 = p;
while (*p != '\0')
{
/* Skip all visual separators */
while ((*p != '\0') && ((*p == '.') || (*p == '-') || (*p == '(') || (*p == ')')))
{
p++;
}
*p2 = *p; /* Until the first visual separator, these both point to the same place. */
/* but, more efficient to just do it than an if statement each time. */
/* If we arrived at a terminator in the inner loop, time to exit */
if (*p == '\0') return;
/* Now we increment both pointers. */
p++;
p2++;
}
*p2 = '\0'; /* Make sure that the string is terminated after the last valid digit. */
}
/*
* Check if this is a phone number.
* Assume possible leading '+'
* Assume separators '.', '-', '(', or ')' could be present.
*/
static int is_number(const char *p)
{
if (*p == '+') p++;
while (*p != '\0')
{
if ((!isdigit(*p)) && (*p != '.') && (*p != '-') && (*p != '(') && (*p != ')')) return 0;
p++;
}
return 1;
}
/*
* Converts URI, if it is tel URI, to SIP URI. Returns 1, if
* conversion succeeded or if no conversion was needed, i.e., URI was not
* tel URI. Returns -1, if conversion failed. Takes SIP URI hostpart from
* second parameter and (if needed) writes the result to third parameter.
* This one attempts to be standards compliant and sort tel: uri parameters
* copied to the sip: uri in the manner defined in the standard. It also
* deletes the "phone-context" parameter if it is a domain, and, takes visual
* separators from the "phone-context" parameter if it is a telephone number.
*/
int std_tel2sip(struct sip_msg* _msg, char* _uri, char* _hostpart, char* _res)
{
str uri, hostpart, tel_uri, sip_uri;
char *at;
int i, j, in_tel_parameters = 0;
pv_spec_t *res;
pv_value_t res_val;
/* get parameters */
if (get_str_fparam(&uri, _msg, (fparam_t*)_uri) < 0) {
LM_ERR("failed to get uri value\n");
}
if (get_str_fparam(&hostpart, _msg, (fparam_t*)_hostpart) < 0) {
LM_ERR("failed to get hostpart value\n");
}
res = (pv_spec_t *)_res;
/* check if anything needs to be done */
if (uri.len < 4) return 1;
if (strncasecmp(uri.s, "tel:", 4) != 0) return 1;
/* reserve memory for clean tel uri */
tel_uri.s = pkg_malloc(uri.len+1);
if (tel_uri.s == 0) {
LM_ERR("no more pkg memory\n");
return -1;
}
/* Remove visual separators before converting to SIP URI. Don't remove
* visual separators in TEL URI parameters (after the first ";") */
for (i=0, j=0; i < uri.len; i++) {
if (in_tel_parameters == 0) {
if (uri.s[i] == ';')
in_tel_parameters = 1;
}
if (in_tel_parameters == 0) {
if ((uri.s[i] != '-') && (uri.s[i] != '.') &&
(uri.s[i] != '(') && (uri.s[i] != ')'))
tel_uri.s[j++] = tolower(uri.s[i]);
} else {
tel_uri.s[j++] = tolower(uri.s[i]);
}
}
tel_uri.s[j] = '\0';
tel_uri.len = strlen(tel_uri.s);
/*** Start Code to sort tel: params *******/
tel_param_t params[MAX_TEL_PARAMS];
char *tmp_ptr = tel_uri.s + 4; // skip tel:
int n_tel_params = 0;
for (int i=0; i < MAX_TEL_PARAMS; i++)
{
tmp_ptr = strchr(tmp_ptr, ';');
if (tmp_ptr == NULL)
{
break;
}
*tmp_ptr = '\0';
tmp_ptr++;
n_tel_params++;
params[i].name = tmp_ptr;
}
for (int i=0; i < n_tel_params; i++)
{
tmp_ptr = strchr(params[i].name, '=');
if (tmp_ptr == NULL)
{
params[i].value = "";
}
else
{
*tmp_ptr = '\0';
tmp_ptr++;
params[i].value = tmp_ptr;
}
if ((0 == strcasecmp(params[i].name, "phone-context")) && (is_number(params[i].value)))
{
remove_visual_separators_from_phone(params[i].value);
}
}
if (n_tel_params > 1)
{
qsort(¶ms[0], n_tel_params, sizeof(tel_param_t), compare_tel_options);
}
/*** End Code to sort tel: params ******/
/* reserve memory for resulting sip uri */
sip_uri.len = 4 + tel_uri.len - 4 + 1 + hostpart.len + 1 + 10;
sip_uri.s = pkg_malloc(sip_uri.len+1);
if (sip_uri.s == 0) {
LM_ERR("no more pkg memory\n");
pkg_free(tel_uri.s);
return -1;
}
/* create resulting sip uri */
at = sip_uri.s;
append_str(at, "sip:", 4);
/** Original code tel: parameters NOT sorted
append_str(at, tel_uri.s + 4, tel_uri.len - 4);
*****/
/***** Start Changed Code for sorted tel: parameters ****/
append_str(at, tel_uri.s + 4, strlen(tel_uri.s + 4)); /* This string was terminated after the number */
/** Now we need to insert sorted tel: parameters **/
for (int i=0; i < n_tel_params; i++)
{
/* If the phone context is a domain, it has already been extracted and is in the "host part" */
if ((0 != strcasecmp(params[i].name, "phone-context")) || (is_number(params[i].value)))
{
append_chr(at, ';');
append_str(at, params[i].name, strlen(params[i].name));
append_chr(at, '=');
append_str(at, params[i].value, strlen(params[i].value));
}
}
/***** End Changed Code for sort tel: parameters ****/
append_chr(at, '@');
append_str(at, hostpart.s, hostpart.len);
append_chr(at, ';');
append_str(at, "user=phone", 10);
/* tel_uri is not needed anymore */
pkg_free(tel_uri.s);
/* set result pv value and write sip uri to result pv */
res_val.rs = sip_uri;
res_val.flags = PV_VAL_STR;
if (res->setf(_msg, &res->pvp, (int)EQ_T, &res_val) != 0) {
LM_ERR("failed to set result pvar\n");
pkg_free(sip_uri.s);
return -1;
}
/* free allocated pkg memory and return */
pkg_free(sip_uri.s);
return 1;
}
</code></pre>
<p style="font-size:small;-webkit-text-size-adjust:none;color:#666;">—<br />You are receiving this because you were mentioned.<br />Reply to this email directly, <a href="https://github.com/kamailio/kamailio/issues/1173#issuecomment-315198949">view it on GitHub</a>, or <a href="https://github.com/notifications/unsubscribe-auth/AF36ZRm_FjjKAqPfqRZAv95E7WRvM0CEks5sNoO5gaJpZM4OJzVh">mute the thread</a>.<img alt="" height="1" src="https://github.com/notifications/beacon/AF36ZWp2zH9qdDWZs8Oj1PyQuGuHWFC8ks5sNoO5gaJpZM4OJzVh.gif" width="1" /></p>
<div itemscope itemtype="http://schema.org/EmailMessage">
<div itemprop="action" itemscope itemtype="http://schema.org/ViewAction">
<link itemprop="url" href="https://github.com/kamailio/kamailio/issues/1173#issuecomment-315198949"></link>
<meta itemprop="name" content="View Issue"></meta>
</div>
<meta itemprop="description" content="View this Issue on GitHub"></meta>
</div>
<script type="application/json" data-scope="inboxmarkup">{"api_version":"1.0","publisher":{"api_key":"05dde50f1d1a384dd78767c55493e4bb","name":"GitHub"},"entity":{"external_key":"github/kamailio/kamailio","title":"kamailio/kamailio","subtitle":"GitHub repository","main_image_url":"https://cloud.githubusercontent.com/assets/143418/17495839/a5054eac-5d88-11e6-95fc-7290892c7bb5.png","avatar_image_url":"https://cloud.githubusercontent.com/assets/143418/15842166/7c72db34-2c0b-11e6-9aed-b52498112777.png","action":{"name":"Open in GitHub","url":"https://github.com/kamailio/kamailio"}},"updates":{"snippets":[{"icon":"PERSON","message":"@doncarr in #1173: @miconda, thanks, that is exactly what I have now, so, will submit it when I can. Below is the code that I wrote with a new function named \"std_tel2sip()\", as a preview I used most of the old procedure where possible, and tried to keep the same style.\r\n\r\nI have been given a task with a short deadline, so, will not be able to work on this anymore right now. I will get back to it as soon as possible.\r\n\r\nDon.\r\n\r\n```\r\n/*\r\n * Compare function to sort tel: uri options acording to standard\r\n * before inserting into sip: uri\r\n *\r\n * See \"RFC 3261 SIP: Session Initiation Protocol June 2002\" \r\n * 19.1.6 Relating SIP URIs and tel URLs\r\n */\r\ntypedef struct\r\n{\r\n char *name;\r\n char *value;\r\n} tel_param_t;\r\n#define MAX_TEL_PARAMS (10)\r\n\r\nint compare_tel_options(const void *v1, const void *v2)\r\n{\r\n tel_param_t *p1 = (tel_param_t *) v1;\r\n tel_param_t *p2 = (tel_param_t *) v2;\r\n\r\n if (0 == strcasecmp(p1-\u003ename, \"isdn-subaddress\"))\r\n {\r\n return -1;\r\n }\r\n else if (0 == strcasecmp(p2-\u003ename, \"isdn-subaddress\"))\r\n {\r\n return 1;\r\n }\r\n else if (0 == strcasecmp(p1-\u003ename, \"post-dial\"))\r\n {\r\n return -1;\r\n }\r\n else if (0 == strcasecmp(p2-\u003ename, \"post-dial\"))\r\n {\r\n return 1;\r\n }\r\n else\r\n {\r\n return strcasecmp(p1-\u003ename, p2-\u003ename);\r\n }\r\n}\r\n\r\n/*\r\n * Remove visual separators from the phone number \r\n * Assume it has been validated as a number containing \r\n * ONLY leading '+', digits, and visual separators.\r\n */\r\nstatic void remove_visual_separators_from_phone(char *p)\r\n{\r\n char *p2;\r\n p2 = p;\r\n while (*p != '\\0')\r\n {\r\n /* Skip all visual separators */\r\n while ((*p != '\\0') \u0026\u0026 ((*p == '.') || (*p == '-') || (*p == '(') || (*p == ')')))\r\n {\r\n p++; \r\n }\r\n *p2 = *p; /* Until the first visual separator, these both point to the same place. */\r\n /* but, more efficient to just do it than an if statement each time. */\r\n /* If we arrived at a terminator in the inner loop, time to exit */\r\n if (*p == '\\0') return;\r\n /* Now we increment both pointers. */\r\n p++;\r\n p2++;\r\n }\r\n *p2 = '\\0'; /* Make sure that the string is terminated after the last valid digit. */\r\n}\r\n\r\n/*\r\n * Check if this is a phone number.\r\n * Assume possible leading '+'\r\n * Assume separators '.', '-', '(', or ')' could be present.\r\n */\r\nstatic int is_number(const char *p)\r\n{\r\n if (*p == '+') p++;\r\n while (*p != '\\0')\r\n {\r\n if ((!isdigit(*p)) \u0026\u0026 (*p != '.') \u0026\u0026 (*p != '-') \u0026\u0026 (*p != '(') \u0026\u0026 (*p != ')')) return 0;\r\n p++;\r\n }\r\n return 1;\r\n}\r\n\r\n/*\r\n * Converts URI, if it is tel URI, to SIP URI. Returns 1, if\r\n * conversion succeeded or if no conversion was needed, i.e., URI was not\r\n * tel URI. Returns -1, if conversion failed. Takes SIP URI hostpart from\r\n * second parameter and (if needed) writes the result to third parameter.\r\n * This one attempts to be standards compliant and sort tel: uri parameters\r\n * copied to the sip: uri in the manner defined in the standard. It also \r\n * deletes the \"phone-context\" parameter if it is a domain, and, takes visual\r\n * separators from the \"phone-context\" parameter if it is a telephone number.\r\n */\r\nint std_tel2sip(struct sip_msg* _msg, char* _uri, char* _hostpart, char* _res)\r\n{\r\n str uri, hostpart, tel_uri, sip_uri;\r\n char *at;\r\n int i, j, in_tel_parameters = 0;\r\n pv_spec_t *res;\r\n pv_value_t res_val;\r\n\r\n /* get parameters */\r\n if (get_str_fparam(\u0026uri, _msg, (fparam_t*)_uri) \u003c 0) {\r\n LM_ERR(\"failed to get uri value\\n\");\r\n }\r\n if (get_str_fparam(\u0026hostpart, _msg, (fparam_t*)_hostpart) \u003c 0) {\r\n LM_ERR(\"failed to get hostpart value\\n\");\r\n }\r\n res = (pv_spec_t *)_res;\r\n\r\n /* check if anything needs to be done */\r\n if (uri.len \u003c 4) return 1;\r\n if (strncasecmp(uri.s, \"tel:\", 4) != 0) return 1;\r\n\r\n /* reserve memory for clean tel uri */\r\n tel_uri.s = pkg_malloc(uri.len+1);\r\n if (tel_uri.s == 0) {\r\n LM_ERR(\"no more pkg memory\\n\");\r\n return -1;\r\n }\r\n\r\n /* Remove visual separators before converting to SIP URI. Don't remove\r\n * visual separators in TEL URI parameters (after the first \";\") */\r\n for (i=0, j=0; i \u003c uri.len; i++) {\r\n if (in_tel_parameters == 0) {\r\n if (uri.s[i] == ';')\r\n in_tel_parameters = 1;\r\n }\r\n if (in_tel_parameters == 0) {\r\n if ((uri.s[i] != '-') \u0026\u0026 (uri.s[i] != '.') \u0026\u0026\r\n (uri.s[i] != '(') \u0026\u0026 (uri.s[i] != ')'))\r\n tel_uri.s[j++] = tolower(uri.s[i]);\r\n } else {\r\n tel_uri.s[j++] = tolower(uri.s[i]);\r\n }\r\n }\r\n tel_uri.s[j] = '\\0';\r\n tel_uri.len = strlen(tel_uri.s);\r\n\r\n /*** Start Code to sort tel: params *******/\r\n tel_param_t params[MAX_TEL_PARAMS];\r\n char *tmp_ptr = tel_uri.s + 4; // skip tel:\r\n\r\n int n_tel_params = 0;\r\n for (int i=0; i \u003c MAX_TEL_PARAMS; i++)\r\n {\r\n tmp_ptr = strchr(tmp_ptr, ';');\r\n if (tmp_ptr == NULL)\r\n {\r\n break;\r\n }\r\n *tmp_ptr = '\\0';\r\n tmp_ptr++;\r\n n_tel_params++;\r\n params[i].name = tmp_ptr;\r\n }\r\n for (int i=0; i \u003c n_tel_params; i++)\r\n {\r\n tmp_ptr = strchr(params[i].name, '=');\r\n if (tmp_ptr == NULL)\r\n {\r\n params[i].value = \"\";\r\n }\r\n else\r\n {\r\n *tmp_ptr = '\\0';\r\n tmp_ptr++;\r\n params[i].value = tmp_ptr;\r\n }\r\n if ((0 == strcasecmp(params[i].name, \"phone-context\")) \u0026\u0026 (is_number(params[i].value)))\r\n {\r\n remove_visual_separators_from_phone(params[i].value);\r\n }\r\n \r\n }\r\n if (n_tel_params \u003e 1)\r\n {\r\n qsort(\u0026params[0], n_tel_params, sizeof(tel_param_t), compare_tel_options);\r\n }\r\n /*** End Code to sort tel: params ******/\r\n\r\n /* reserve memory for resulting sip uri */\r\n sip_uri.len = 4 + tel_uri.len - 4 + 1 + hostpart.len + 1 + 10;\r\n sip_uri.s = pkg_malloc(sip_uri.len+1);\r\n if (sip_uri.s == 0) {\r\n LM_ERR(\"no more pkg memory\\n\");\r\n pkg_free(tel_uri.s);\r\n return -1;\r\n }\r\n\r\n /* create resulting sip uri */\r\n at = sip_uri.s;\r\n append_str(at, \"sip:\", 4);\r\n /** Original code tel: parameters NOT sorted \r\n append_str(at, tel_uri.s + 4, tel_uri.len - 4);\r\n *****/\r\n /***** Start Changed Code for sorted tel: parameters ****/\r\n append_str(at, tel_uri.s + 4, strlen(tel_uri.s + 4)); /* This string was terminated after the number */\r\n /** Now we need to insert sorted tel: parameters **/\r\n for (int i=0; i \u003c n_tel_params; i++)\r\n {\r\n /* If the phone context is a domain, it has already been extracted and is in the \"host part\" */\r\n if ((0 != strcasecmp(params[i].name, \"phone-context\")) || (is_number(params[i].value)))\r\n {\r\n append_chr(at, ';');\r\n append_str(at, params[i].name, strlen(params[i].name));\r\n append_chr(at, '=');\r\n append_str(at, params[i].value, strlen(params[i].value));\r\n }\r\n }\r\n /***** End Changed Code for sort tel: parameters ****/\r\n append_chr(at, '@');\r\n append_str(at, hostpart.s, hostpart.len);\r\n append_chr(at, ';');\r\n append_str(at, \"user=phone\", 10);\r\n\r\n /* tel_uri is not needed anymore */\r\n pkg_free(tel_uri.s);\r\n\r\n /* set result pv value and write sip uri to result pv */\r\n res_val.rs = sip_uri;\r\n res_val.flags = PV_VAL_STR;\r\n if (res-\u003esetf(_msg, \u0026res-\u003epvp, (int)EQ_T, \u0026res_val) != 0) {\r\n LM_ERR(\"failed to set result pvar\\n\");\r\n pkg_free(sip_uri.s);\r\n return -1;\r\n }\r\n\r\n /* free allocated pkg memory and return */\r\n pkg_free(sip_uri.s);\r\n return 1;\r\n}\r\n```\r\n"}],"action":{"name":"View Issue","url":"https://github.com/kamailio/kamailio/issues/1173#issuecomment-315198949"}}}</script>