diff --git a/src/modules/textops/doc/textops_admin.xml b/src/modules/textops/doc/textops_admin.xml index f94183dabfa..f480ae2183c 100644 --- a/src/modules/textops/doc/textops_admin.xml +++ b/src/modules/textops/doc/textops_admin.xml @@ -1323,7 +1323,7 @@ if(is_privacy("id")) ... $var(subject) = "fi"; $var(list) = "dk,fi,no,se"; -if (in_list("$var(subject)", "$var(list)", ",") { +if (in_list("$var(subject)", "$var(list)", ",")) { xlog("L_INFO", "subject is found in list\n"); } ... @@ -1331,6 +1331,30 @@ if (in_list("$var(subject)", "$var(list)", ",") { +
+ + <function moreinfo="none">in_list_prefix(subject, list, separator)</function> + + + Function checks if any element in list string is a prefix for subject string where list items are separated by separator string. Subject and list strings may contain pseudo variables. Separator string needs to be one character long. Returns 1 if subject is found and -1 otherwise. + + + Function can be used from all kinds of routes. + + + <function>in_list()</function> usage + +... +$var(subject) = "final"; +$var(list) = "dk,fi,no,se"; +if (in_list_prefix("$var(subject)", "$var(list)", ",")) { + xlog("L_INFO", "prefix for subject is found in list\n"); +} +... + + +
+
<function moreinfo="none">cmp_str(str1, str2)</function> diff --git a/src/modules/textops/textops.c b/src/modules/textops/textops.c index 97f1ecff127..8f493fdf39c 100644 --- a/src/modules/textops/textops.c +++ b/src/modules/textops/textops.c @@ -125,6 +125,8 @@ static int is_method_f(struct sip_msg* msg, char* , char *); static int has_body_f(struct sip_msg *msg, char *type, char *str2 ); static int in_list_f(struct sip_msg* _msg, char* _subject, char* _list, char* _sep); +static int in_list_prefix_f(struct sip_msg* _msg, char* _subject, char* _list, + char* _sep); static int cmp_str_f(struct sip_msg *msg, char *str1, char *str2 ); static int cmp_istr_f(struct sip_msg *msg, char *str1, char *str2 ); static int starts_with_f(struct sip_msg *msg, char *str1, char *str2 ); @@ -139,7 +141,9 @@ static int fixup_method(void** param, int param_no); static int add_header_fixup(void** param, int param_no); static int fixup_body_type(void** param, int param_no); static int fixup_in_list(void** param, int param_no); +static int fixup_in_list_prefix(void** param, int param_no); static int fixup_free_in_list(void** param, int param_no); +static int fixup_free_in_list_prefix(void** param, int param_no); int fixup_regexpNL_none(void** param, int param_no); static int fixup_search_hf(void** param, int param_no); static int fixup_subst_hf(void** param, int param_no); @@ -259,6 +263,9 @@ static cmd_export_t cmds[]={ {"in_list", (cmd_function)in_list_f, 3, fixup_in_list, fixup_free_in_list, ANY_ROUTE}, + {"in_list_prefix", (cmd_function)in_list_prefix_f, 3, + fixup_in_list_prefix, fixup_free_in_list_prefix, + ANY_ROUTE}, {"cmp_str", (cmd_function)cmp_str_f, 2, fixup_spve_spve, 0, ANY_ROUTE}, @@ -3007,6 +3014,41 @@ static int fixup_free_in_list(void** param, int param_no) return -1; } +/* + * Fix in_list_prefix params: subject and list (strings that may contain pvars), + * separator (string) + */ +static int fixup_in_list_prefix(void** param, int param_no) +{ + if ((param_no == 1) || (param_no == 2)) return fixup_spve_null(param, 1); + + if (param_no == 3) { + if ((strlen((char *)*param) != 1) || (*((char *)(*param)) == 0)) { + LM_ERR("invalid separator parameter\n"); + return -1; + } + return 0; + } + + LM_ERR("invalid parameter number <%d>\n", param_no); + return -1; +} + +/* + * Free in_list_prefix params + */ +static int fixup_free_in_list_prefix(void** param, int param_no) +{ + if ((param_no == 1) || (param_no == 2)) { + return fixup_free_spve_null(param, 1); + } + + if (param_no == 3) return 0; + + LM_ERR("invalid parameter number <%d>\n", param_no); + return -1; +} + static int add_header_fixup(void** param, int param_no) { if(param_no==1) @@ -3242,6 +3284,112 @@ int in_list_f(struct sip_msg* _m, char* _subject, char* _list, char* _sep) return ki_in_list(_m, &subject, &list, &sep); } +/* + * Checks if an element in list is a prefix for subject + */ +int ki_in_list_prefix(sip_msg_t* _m, str* subject, str* list, str* vsep) +{ + int sep; + char *at, *past, *next_sep, *s; + + if(subject==NULL || subject->len<=0 || list==NULL || list->len<=0 + || vsep==NULL || vsep->len<=0) + return -1; + + sep = vsep->s[0]; + + at = list->s; + past = list->s + list->len; + + /* Eat leading white space */ + while ((at < past) && + ((*at == ' ') || (*at == '\t') || (*at == '\r') || (*at == '\n') )) { + at++; + } + + while (at < past) { + next_sep = index(at, sep); + s = next_sep; + int list_element_len; + + if (s == NULL) { + /* Eat trailing white space */ + while ((at < past) && + ((*(past-1) == ' ') || (*(past-1) == '\t') + || (*(past-1) == '\r') || (*(past-1) == '\n') )) { + past--; + } + list_element_len = past - at; + if (list_element_len == 0) { + /* There is no list element */ + return -1; + } + if (list_element_len > subject->len) { + /* Length of list element is greater than subject length */ + return -1; + } + if (strncmp(at, subject->s, list_element_len) != 0) { + return -1; + } + /* Prefix match found */ + return 1; + + } else { + /* Eat trailing white space */ + while ((at < s) && + ((*(s-1) == ' ') || (*(s-1) == '\t') || (*(s-1) == '\r') + || (*(s-1) == '\n') )) { + s--; + } + list_element_len = s - at; + if (list_element_len == 0 || list_element_len > subject->len || + strncmp(at, subject->s, list_element_len) != 0) { + /* Prefix match not found */ + at = next_sep + 1; + /* Eat leading white space */ + while ((at < past) && + ((*at == ' ') || (*at == '\t') || (*at == '\r') + || (*at == '\n') )) { + at++; + } + } else { + /* Prefix match found */ + return 1; + } + } + } + + return -1; +} + +/* + * Checks if an element in list is a prefix for subject + */ +int in_list_prefix_f(struct sip_msg* _m, char* _subject, char* _list, char* _sep) +{ + str subject, list, sep; + if (fixup_get_svalue(_m, (gparam_p)_subject, &subject) != 0) { + LM_ERR("cannot get subject value\n"); + return -1; + } else { + if (subject.len == 0) { + LM_ERR("subject cannot be empty string\n"); + return -1; + } + } + + if (fixup_get_svalue(_m, (gparam_p)_list, &list) != 0) { + LM_ERR("cannot get list value\n"); + return -1; + } else { + if (list.len == 0) return -1; + } + sep.s = _sep; + sep.len = 1; + + return ki_in_list_prefix(_m, &subject, &list, &sep); +} + static int cmp_str_f(struct sip_msg *msg, char *str1, char *str2 ) { str s1; @@ -4049,6 +4197,11 @@ static sr_kemi_t sr_kemi_textops_exports[] = { { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } }, + { str_init("textops"), str_init("in_list_prefix"), + SR_KEMIP_INT, ki_in_list_prefix, + { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR, + SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } + }, { str_init("textops"), str_init("cmp_str"), SR_KEMIP_INT, ki_cmp_str, { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,