Strip, prefix, rewriteuser, ... all the SET_* actions preserve the
[sip-router] / action.c
index f825626..b35a543 100644 (file)
--- a/action.c
+++ b/action.c
@@ -110,6 +110,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
        unsigned short flags;
        int_str name, value;
        str* dst_host;
+       int orig_p2t;
 
        /* reset the value of error to E_UNSPEC so avoid unknowledgable
           functions to return with error (status<0) and not setting it
@@ -483,18 +484,22 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                case PREFIX_T:
                case STRIP_T:
                case STRIP_TAIL_T:
+               case SET_USERPHONE_T:
                                user=0;
                                if (a->type==STRIP_T || a->type==STRIP_TAIL_T) {
                                        if (a->val[0].type!=NUMBER_ST) {
                                                LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
                                                        a->val[0].type);
+                                               ret=E_BUG;
                                                break;
                                        }
-                               } else if (a->val[0].type!=STRING_ST){
-                                       LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
+                               } else if (a->type!=SET_USERPHONE_T) {
+                                       if (a->val[0].type!=STRING_ST) {
+                                               LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
                                                        a->val[0].type);
-                                       ret=E_BUG;
-                                       break;
+                                               ret=E_BUG;
+                                               break;
+                                       }
                                }
                                if (a->type==SET_URI_T){
                                        if (msg->new_uri.s) {
@@ -517,7 +522,7 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                        ret=1;
                                        break;
                                }
-                               if (msg->parsed_uri_ok==0) {
+                               if ((msg->parsed_uri_ok==0) || ((uri.flags & URI_SIP_USER_PHONE)!=0)) {
                                        if (msg->new_uri.s) {
                                                tmp=msg->new_uri.s;
                                                len=msg->new_uri.len;
@@ -525,16 +530,41 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                                tmp=msg->first_line.u.request.uri.s;
                                                len=msg->first_line.u.request.uri.len;
                                        }
+                                       /* don't convert sip:user=phone to tel, otherwise we loose parameters */
+                                       orig_p2t=phone2tel;
+                                       phone2tel=0;
+                                       msg->parsed_uri_ok=0;
                                        if (parse_uri(tmp, len, &uri)<0){
+                                               phone2tel=orig_p2t;
                                                LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping"
                                                                        " packet\n", tmp);
                                                ret=E_UNSPEC;
                                                break;
                                        }
+                                       phone2tel=orig_p2t;
                                } else {
                                        uri=msg->parsed_uri;
                                }
 
+                               /* skip SET_USERPHONE_T action if the URI is already
+                                * a tel: or tels: URI, or contains the user=phone param */
+                               if ((a->type==SET_USERPHONE_T) 
+                                       && ((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T)
+                                               || ((uri.user_param_val.len==5) && (memcmp(uri.user_param_val.s, "phone", 5)==0)))
+                               ) {
+                                       ret=1;
+                                       break;
+                               }
+                               /* SET_PORT_T does not work with tel: URIs */
+                               if ((a->type==SET_PORT_T)
+                                       && ((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T))
+                                       && ((uri.flags & URI_SIP_USER_PHONE)==0)
+                               ) {
+                                       LOG(L_ERR, "ERROR: do_action: port number of a tel: URI cannot be set\n");
+                                       ret=E_UNSPEC;
+                                       break;
+                               }
+
                                new_uri=pkg_malloc(MAX_URI_SIZE);
                                if (new_uri==0){
                                        LOG(L_ERR, "ERROR: do_action: memory allocation "
@@ -545,8 +575,57 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                end=new_uri+MAX_URI_SIZE;
                                crt=new_uri;
                                /* begin copying */
-                               len=strlen("sip:"); if(crt+len>end) goto error_uri;
-                               memcpy(crt,"sip:",len);crt+=len;
+                               /* Preserve the URI scheme unless the host part needs
+                                * to be rewritten, and the shceme is tel: or tels: */
+                               switch (uri.type) {
+                               case SIP_URI_T:
+                                       len=s_sip.len;
+                                       tmp=s_sip.s;
+                                       break;
+
+                               case SIPS_URI_T:
+                                       len=s_sips.len;
+                                       tmp=s_sips.s;
+                                       break;
+
+                               case TEL_URI_T:
+                                       if ((uri.flags & URI_SIP_USER_PHONE)
+                                               || (a->type==SET_HOST_T)
+                                               || (a->type==SET_HOSTPORT_T)
+                                               || (a->type==SET_HOSTPORTTRANS_T)
+                                       ) {
+                                               len=s_sip.len;
+                                               tmp=s_sip.s;
+                                               break;
+                                       }
+                                       len=s_tel.len;
+                                       tmp=s_tel.s;
+                                       break;
+
+                               case TELS_URI_T:
+                                       if ((uri.flags & URI_SIP_USER_PHONE)
+                                               || (a->type==SET_HOST_T)
+                                               || (a->type==SET_HOSTPORT_T)
+                                               || (a->type==SET_HOSTPORTTRANS_T)
+                                       ) {
+                                               len=s_sips.len;
+                                               tmp=s_sips.s;
+                                               break;
+                                       }
+                                       len=s_tels.len;
+                                       tmp=s_tels.s;
+                                       break;
+
+                               default:
+                                       LOG(L_ERR, "ERROR: Unsupported URI scheme (%d), "
+                                               "reverted to sip:\n",
+                                               uri.type);
+                                       len=s_sip.len;
+                                       tmp=s_sip.s;
+                               }
+                               if(crt+len+1 /* colon */ >end) goto error_uri;
+                               memcpy(crt,tmp,len);crt+=len;
+                               *crt=':'; crt++;
 
                                /* user */
 
@@ -607,21 +686,27 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                        memcpy(crt,tmp,len);crt+=len;
                                }
                                /* host */
-                               if (user || tmp){ /* add @ */
-                                       if(crt+1>end) goto error_uri;
-                                       *crt='@'; crt++;
-                               }
                                if ((a->type==SET_HOST_T)
                                                || (a->type==SET_HOSTPORT_T)
-                                               || (a->type==SET_HOSTPORTTRANS_T)) {
+                                               || (a->type==SET_HOSTPORTTRANS_T)
+                               ) {
                                        tmp=a->val[0].u.string;
                                        if (tmp) len = strlen(tmp);
                                        else len=0;
-                               } else {
+                               } else if ((uri.type==SIP_URI_T)
+                                       || (uri.type==SIPS_URI_T)
+                                       || (uri.flags & URI_SIP_USER_PHONE)
+                               ) {
                                        tmp=uri.host.s;
-                                       len = uri.host.len;
+                                       len=uri.host.len;
+                               } else {
+                                       tmp=0;
                                }
                                if (tmp){
+                                       if (user) { /* add @ */
+                                               if(crt+1>end) goto error_uri;
+                                               *crt='@'; crt++;
+                                       }
                                        if(crt+len>end) goto error_uri;
                                        memcpy(crt,tmp,len);crt+=len;
                                }
@@ -669,6 +754,22 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                                                memcpy(crt,tmp,len);crt+=len;
                                        }
                                }
+                               /* Add the user=phone param if a tel: or tels:
+                                * URI was converted to sip: or sips:.
+                                * (host part of a tel/tels URI was set.)
+                                * Or in case of sip: URI and SET_USERPHONE_T action */
+                               if (((((uri.type==TEL_URI_T) || (uri.type==TELS_URI_T))
+                                       && ((uri.flags & URI_SIP_USER_PHONE)==0))
+                                       && ((a->type==SET_HOST_T)
+                                               || (a->type==SET_HOSTPORT_T)
+                                               || (a->type==SET_HOSTPORTTRANS_T)))
+                                       || (a->type==SET_USERPHONE_T)
+                               ) {
+                                       tmp=";user=phone";
+                                       len=strlen(tmp);
+                                       if(crt+len>end) goto error_uri;
+                                       memcpy(crt,tmp,len);crt+=len;
+                               }
                                /* headers */
                                tmp=uri.headers.s;
                                if (tmp){