<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(&params[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>