ソースを参照

textops(k): two functions to search and subst inside header fields

- search_hf(hf, re, flags) - search inside header fields body
- subst_hf(hf, subst, flags) - perl-like substitution inside header
  field body
Daniel-Constantin Mierla 13 年 前
コミット
5fc6a215d5
3 ファイル変更573 行追加222 行削除
  1. 269 222
      modules_k/textops/README
  2. 79 0
      modules_k/textops/doc/textops_admin.xml
  3. 225 0
      modules_k/textops/textops.c

+ 269 - 222
modules_k/textops/README

@@ -23,7 +23,7 @@ Juha Heinanen
 
 
    <[email protected]>
    <[email protected]>
 
 
-   Copyright © 2003 FhG FOKUS
+   Copyright © 2003 FhG FOKUS
      __________________________________________________________________
      __________________________________________________________________
 
 
    Table of Contents
    Table of Contents
@@ -43,40 +43,42 @@ Juha Heinanen
 
 
               3.1. search(re)
               3.1. search(re)
               3.2. search_body(re)
               3.2. search_body(re)
-              3.3. search_append(re, txt)
-              3.4. search_append_body(re, txt)
-              3.5. replace(re, txt)
-              3.6. replace_body(re, txt)
-              3.7. replace_all(re, txt)
-              3.8. replace_body_all(re, txt)
-              3.9. replace_body_atonce(re, txt)
-              3.10. subst('/re/repl/flags')
-              3.11. subst_uri('/re/repl/flags')
-              3.12. subst_user('/re/repl/flags')
-              3.13. subst_body('/re/repl/flags')
-              3.14. set_body(txt,content_type)
-              3.15. set_reply_body(txt,content_type)
-              3.16. filter_body(content_type)
-              3.17. append_to_reply(txt)
-              3.18. append_hf(txt)
-              3.19. append_hf(txt, hdr)
-              3.20. insert_hf(txt)
-              3.21. insert_hf(txt, hdr)
-              3.22. append_urihf(prefix, suffix)
-              3.23. is_present_hf(hf_name)
-              3.24. is_present_hf_re(hf_name_re)
-              3.25. append_time()
-              3.26. append_time_to_request()
-              3.27. is_method(name)
-              3.28. remove_hf(hname)
-              3.29. remove_hf_re(re)
-              3.30. has_body(), has_body(mime)
-              3.31. is_audio_on_hold()
-              3.32. is_privacy(privacy_type)
-              3.33. in_list(subject, list, separator)
-              3.34. cmp_str(str1, str2)
-              3.35. cmp_istr(str1, str2)
-              3.36. starts_with(str1, str2)
+              3.3. search_hf(hf, re, flags)
+              3.4. search_append(re, txt)
+              3.5. search_append_body(re, txt)
+              3.6. replace(re, txt)
+              3.7. replace_body(re, txt)
+              3.8. replace_all(re, txt)
+              3.9. replace_body_all(re, txt)
+              3.10. replace_body_atonce(re, txt)
+              3.11. subst('/re/repl/flags')
+              3.12. subst_uri('/re/repl/flags')
+              3.13. subst_user('/re/repl/flags')
+              3.14. subst_body('/re/repl/flags')
+              3.15. subst_hf(hf, subexp, flags)
+              3.16. set_body(txt,content_type)
+              3.17. set_reply_body(txt,content_type)
+              3.18. filter_body(content_type)
+              3.19. append_to_reply(txt)
+              3.20. append_hf(txt)
+              3.21. append_hf(txt, hdr)
+              3.22. insert_hf(txt)
+              3.23. insert_hf(txt, hdr)
+              3.24. append_urihf(prefix, suffix)
+              3.25. is_present_hf(hf_name)
+              3.26. is_present_hf_re(hf_name_re)
+              3.27. append_time()
+              3.28. append_time_to_request()
+              3.29. is_method(name)
+              3.30. remove_hf(hname)
+              3.31. remove_hf_re(re)
+              3.32. has_body(), has_body(mime)
+              3.33. is_audio_on_hold()
+              3.34. is_privacy(privacy_type)
+              3.35. in_list(subject, list, separator)
+              3.36. cmp_str(str1, str2)
+              3.37. cmp_istr(str1, str2)
+              3.38. starts_with(str1, str2)
 
 
         4. Known Limitations
         4. Known Limitations
 
 
@@ -90,40 +92,42 @@ Juha Heinanen
 
 
    1.1. search usage
    1.1. search usage
    1.2. search_body usage
    1.2. search_body usage
-   1.3. search_append usage
-   1.4. search_append_body usage
-   1.5. replace usage
-   1.6. replace_body usage
-   1.7. replace_all usage
-   1.8. replace_body_all usage
-   1.9. replace_body_atonce usage
-   1.10. subst usage
-   1.11. subst_uri usage
-   1.12. subst usage
-   1.13. subst_body usage
-   1.14. set_body usage
-   1.15. set_reply_body usage
-   1.16. filter_body usage
-   1.17. append_to_reply usage
-   1.18. append_hf usage
-   1.19. append_hf usage
-   1.20. insert_hf usage
-   1.21. insert_hf usage
-   1.22. append_urihf usage
-   1.23. is_present_hf usage
-   1.24. is_present_hf_re usage
-   1.25. append_time usage
-   1.26. append_time_to_request usage
-   1.27. is_method usage
-   1.28. remove_hf usage
-   1.29. remove_hf_re usage
-   1.30. has_body usage
-   1.31. is_audio_on_hold usage
-   1.32. is_privacy usage
-   1.33. in_list() usage
-   1.34. cmp_str usage
-   1.35. cmp_str usage
-   1.36. starts_with usage
+   1.3. search_body usage
+   1.4. search_append usage
+   1.5. search_append_body usage
+   1.6. replace usage
+   1.7. replace_body usage
+   1.8. replace_all usage
+   1.9. replace_body_all usage
+   1.10. replace_body_atonce usage
+   1.11. subst usage
+   1.12. subst_uri usage
+   1.13. subst usage
+   1.14. subst_body usage
+   1.15. search_body usage
+   1.16. set_body usage
+   1.17. set_reply_body usage
+   1.18. filter_body usage
+   1.19. append_to_reply usage
+   1.20. append_hf usage
+   1.21. append_hf usage
+   1.22. insert_hf usage
+   1.23. insert_hf usage
+   1.24. append_urihf usage
+   1.25. is_present_hf usage
+   1.26. is_present_hf_re usage
+   1.27. append_time usage
+   1.28. append_time_to_request usage
+   1.29. is_method usage
+   1.30. remove_hf usage
+   1.31. remove_hf_re usage
+   1.32. has_body usage
+   1.33. is_audio_on_hold usage
+   1.34. is_privacy usage
+   1.35. in_list() usage
+   1.36. cmp_str usage
+   1.37. cmp_str usage
+   1.38. starts_with usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -142,40 +146,42 @@ Chapter 1. Admin Guide
 
 
         3.1. search(re)
         3.1. search(re)
         3.2. search_body(re)
         3.2. search_body(re)
-        3.3. search_append(re, txt)
-        3.4. search_append_body(re, txt)
-        3.5. replace(re, txt)
-        3.6. replace_body(re, txt)
-        3.7. replace_all(re, txt)
-        3.8. replace_body_all(re, txt)
-        3.9. replace_body_atonce(re, txt)
-        3.10. subst('/re/repl/flags')
-        3.11. subst_uri('/re/repl/flags')
-        3.12. subst_user('/re/repl/flags')
-        3.13. subst_body('/re/repl/flags')
-        3.14. set_body(txt,content_type)
-        3.15. set_reply_body(txt,content_type)
-        3.16. filter_body(content_type)
-        3.17. append_to_reply(txt)
-        3.18. append_hf(txt)
-        3.19. append_hf(txt, hdr)
-        3.20. insert_hf(txt)
-        3.21. insert_hf(txt, hdr)
-        3.22. append_urihf(prefix, suffix)
-        3.23. is_present_hf(hf_name)
-        3.24. is_present_hf_re(hf_name_re)
-        3.25. append_time()
-        3.26. append_time_to_request()
-        3.27. is_method(name)
-        3.28. remove_hf(hname)
-        3.29. remove_hf_re(re)
-        3.30. has_body(), has_body(mime)
-        3.31. is_audio_on_hold()
-        3.32. is_privacy(privacy_type)
-        3.33. in_list(subject, list, separator)
-        3.34. cmp_str(str1, str2)
-        3.35. cmp_istr(str1, str2)
-        3.36. starts_with(str1, str2)
+        3.3. search_hf(hf, re, flags)
+        3.4. search_append(re, txt)
+        3.5. search_append_body(re, txt)
+        3.6. replace(re, txt)
+        3.7. replace_body(re, txt)
+        3.8. replace_all(re, txt)
+        3.9. replace_body_all(re, txt)
+        3.10. replace_body_atonce(re, txt)
+        3.11. subst('/re/repl/flags')
+        3.12. subst_uri('/re/repl/flags')
+        3.13. subst_user('/re/repl/flags')
+        3.14. subst_body('/re/repl/flags')
+        3.15. subst_hf(hf, subexp, flags)
+        3.16. set_body(txt,content_type)
+        3.17. set_reply_body(txt,content_type)
+        3.18. filter_body(content_type)
+        3.19. append_to_reply(txt)
+        3.20. append_hf(txt)
+        3.21. append_hf(txt, hdr)
+        3.22. insert_hf(txt)
+        3.23. insert_hf(txt, hdr)
+        3.24. append_urihf(prefix, suffix)
+        3.25. is_present_hf(hf_name)
+        3.26. is_present_hf_re(hf_name_re)
+        3.27. append_time()
+        3.28. append_time_to_request()
+        3.29. is_method(name)
+        3.30. remove_hf(hname)
+        3.31. remove_hf_re(re)
+        3.32. has_body(), has_body(mime)
+        3.33. is_audio_on_hold()
+        3.34. is_privacy(privacy_type)
+        3.35. in_list(subject, list, separator)
+        3.36. cmp_str(str1, str2)
+        3.37. cmp_istr(str1, str2)
+        3.38. starts_with(str1, str2)
 
 
    4. Known Limitations
    4. Known Limitations
 
 
@@ -192,7 +198,7 @@ Chapter 1. Admin Guide
 
 
 1.1. Known Limitations
 1.1. Known Limitations
 
 
-   search ignores folded lines. For example, search(“(From|f):.*@foo.bar�)
+   search ignores folded lines. For example, search("(From|f):.*@foo.bar")
    doesn't match the following From header field:
    doesn't match the following From header field:
 From: medabeda
 From: medabeda
  <sip:[email protected]>;tag=1234
  <sip:[email protected]>;tag=1234
@@ -217,42 +223,44 @@ From: medabeda
 
 
    3.1. search(re)
    3.1. search(re)
    3.2. search_body(re)
    3.2. search_body(re)
-   3.3. search_append(re, txt)
-   3.4. search_append_body(re, txt)
-   3.5. replace(re, txt)
-   3.6. replace_body(re, txt)
-   3.7. replace_all(re, txt)
-   3.8. replace_body_all(re, txt)
-   3.9. replace_body_atonce(re, txt)
-   3.10. subst('/re/repl/flags')
-   3.11. subst_uri('/re/repl/flags')
-   3.12. subst_user('/re/repl/flags')
-   3.13. subst_body('/re/repl/flags')
-   3.14. set_body(txt,content_type)
-   3.15. set_reply_body(txt,content_type)
-   3.16. filter_body(content_type)
-   3.17. append_to_reply(txt)
-   3.18. append_hf(txt)
-   3.19. append_hf(txt, hdr)
-   3.20. insert_hf(txt)
-   3.21. insert_hf(txt, hdr)
-   3.22. append_urihf(prefix, suffix)
-   3.23. is_present_hf(hf_name)
-   3.24. is_present_hf_re(hf_name_re)
-   3.25. append_time()
-   3.26. append_time_to_request()
-   3.27. is_method(name)
-   3.28. remove_hf(hname)
-   3.29. remove_hf_re(re)
-   3.30. has_body(), has_body(mime)
-   3.31. is_audio_on_hold()
-   3.32. is_privacy(privacy_type)
-   3.33. in_list(subject, list, separator)
-   3.34. cmp_str(str1, str2)
-   3.35. cmp_istr(str1, str2)
-   3.36. starts_with(str1, str2)
-
-3.1.  search(re)
+   3.3. search_hf(hf, re, flags)
+   3.4. search_append(re, txt)
+   3.5. search_append_body(re, txt)
+   3.6. replace(re, txt)
+   3.7. replace_body(re, txt)
+   3.8. replace_all(re, txt)
+   3.9. replace_body_all(re, txt)
+   3.10. replace_body_atonce(re, txt)
+   3.11. subst('/re/repl/flags')
+   3.12. subst_uri('/re/repl/flags')
+   3.13. subst_user('/re/repl/flags')
+   3.14. subst_body('/re/repl/flags')
+   3.15. subst_hf(hf, subexp, flags)
+   3.16. set_body(txt,content_type)
+   3.17. set_reply_body(txt,content_type)
+   3.18. filter_body(content_type)
+   3.19. append_to_reply(txt)
+   3.20. append_hf(txt)
+   3.21. append_hf(txt, hdr)
+   3.22. insert_hf(txt)
+   3.23. insert_hf(txt, hdr)
+   3.24. append_urihf(prefix, suffix)
+   3.25. is_present_hf(hf_name)
+   3.26. is_present_hf_re(hf_name_re)
+   3.27. append_time()
+   3.28. append_time_to_request()
+   3.29. is_method(name)
+   3.30. remove_hf(hname)
+   3.31. remove_hf_re(re)
+   3.32. has_body(), has_body(mime)
+   3.33. is_audio_on_hold()
+   3.34. is_privacy(privacy_type)
+   3.35. in_list(subject, list, separator)
+   3.36. cmp_str(str1, str2)
+   3.37. cmp_istr(str1, str2)
+   3.38. starts_with(str1, str2)
+
+3.1. search(re)
 
 
    Searches for the re in the message.
    Searches for the re in the message.
 
 
@@ -267,7 +275,7 @@ From: medabeda
 if ( search("[Ss][Ii][Pp]") ) { /*....*/ };
 if ( search("[Ss][Ii][Pp]") ) { /*....*/ };
 ...
 ...
 
 
-3.2.  search_body(re)
+3.2. search_body(re)
 
 
    Searches for the re in the body of the message.
    Searches for the re in the body of the message.
 
 
@@ -282,7 +290,26 @@ if ( search("[Ss][Ii][Pp]") ) { /*....*/ };
 if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ };
 if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ };
 ...
 ...
 
 
-3.3.  search_append(re, txt)
+3.3. search_hf(hf, re, flags)
+
+   Searches for the re in the body of a header field.
+
+   Meaning of the parameters is as follows:
+     * hf - header field name.
+     * re - regular expression.
+     * flags - control flags - it has to be one of: a - all headers
+       matching the name; f - only first header matching the name; l -
+       only the last header matching the name.
+
+   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   FAILURE_ROUTE, BRANCH_ROUTE.
+
+   Example 1.3. search_body usage
+...
+if ( search_hf("From", ":test@", "a") ) { /*....*/ };
+...
+
+3.4. search_append(re, txt)
 
 
    Searches for the first match of re and appends txt after it.
    Searches for the first match of re and appends txt after it.
 
 
@@ -293,12 +320,12 @@ if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ };
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.3. search_append usage
+   Example 1.4. search_append usage
 ...
 ...
 search_append("[Oo]pen[Ss]er", " SIP Proxy");
 search_append("[Oo]pen[Ss]er", " SIP Proxy");
 ...
 ...
 
 
-3.4.  search_append_body(re, txt)
+3.5. search_append_body(re, txt)
 
 
    Searches for the first match of re in the body of the message and
    Searches for the first match of re in the body of the message and
    appends txt after it.
    appends txt after it.
@@ -310,12 +337,12 @@ search_append("[Oo]pen[Ss]er", " SIP Proxy");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.4. search_append_body usage
+   Example 1.5. search_append_body usage
 ...
 ...
 search_append_body("[Oo]pen[Ss]er", " SIP Proxy");
 search_append_body("[Oo]pen[Ss]er", " SIP Proxy");
 ...
 ...
 
 
-3.5.  replace(re, txt)
+3.6. replace(re, txt)
 
 
    Replaces the first occurrence of re with txt.
    Replaces the first occurrence of re with txt.
 
 
@@ -326,12 +353,12 @@ search_append_body("[Oo]pen[Ss]er", " SIP Proxy");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.5. replace usage
+   Example 1.6. replace usage
 ...
 ...
 replace("openser", "Kamailio SIP Proxy");
 replace("openser", "Kamailio SIP Proxy");
 ...
 ...
 
 
-3.6.  replace_body(re, txt)
+3.7. replace_body(re, txt)
 
 
    Replaces the first occurrence of re in the body of the message with
    Replaces the first occurrence of re in the body of the message with
    txt.
    txt.
@@ -343,12 +370,12 @@ replace("openser", "Kamailio SIP Proxy");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.6. replace_body usage
+   Example 1.7. replace_body usage
 ...
 ...
 replace_body("openser", "Kamailio SIP Proxy");
 replace_body("openser", "Kamailio SIP Proxy");
 ...
 ...
 
 
-3.7.  replace_all(re, txt)
+3.8. replace_all(re, txt)
 
 
    Replaces all occurrence of re with txt.
    Replaces all occurrence of re with txt.
 
 
@@ -359,12 +386,12 @@ replace_body("openser", "Kamailio SIP Proxy");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.7. replace_all usage
+   Example 1.8. replace_all usage
 ...
 ...
 replace_all("openser", "Kamailio SIP Proxy");
 replace_all("openser", "Kamailio SIP Proxy");
 ...
 ...
 
 
-3.8.  replace_body_all(re, txt)
+3.9. replace_body_all(re, txt)
 
 
    Replaces all occurrence of re in the body of the message with txt.
    Replaces all occurrence of re in the body of the message with txt.
    Matching is done on a per-line basis.
    Matching is done on a per-line basis.
@@ -376,12 +403,12 @@ replace_all("openser", "Kamailio SIP Proxy");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.8. replace_body_all usage
+   Example 1.9. replace_body_all usage
 ...
 ...
 replace_body_all("openser", "Kamailio SIP Proxy");
 replace_body_all("openser", "Kamailio SIP Proxy");
 ...
 ...
 
 
-3.9.  replace_body_atonce(re, txt)
+3.10. replace_body_atonce(re, txt)
 
 
    Replaces all occurrence of re in the body of the message with txt.
    Replaces all occurrence of re in the body of the message with txt.
    Matching is done over the whole body.
    Matching is done over the whole body.
@@ -393,14 +420,14 @@ replace_body_all("openser", "Kamailio SIP Proxy");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.9. replace_body_atonce usage
+   Example 1.10. replace_body_atonce usage
 ...
 ...
 # strip the whole body from the message:
 # strip the whole body from the message:
 if(has_body() && replace_body_atonce("^.+$", ""))
 if(has_body() && replace_body_atonce("^.+$", ""))
         remove_hf("Content-Type");
         remove_hf("Content-Type");
 ...
 ...
 
 
-3.10.  subst('/re/repl/flags')
+3.11. subst('/re/repl/flags')
 
 
    Replaces re with repl (sed or perl like).
    Replaces re with repl (sed or perl like).
 
 
@@ -415,7 +442,7 @@ if(has_body() && replace_body_atonce("^.+$", ""))
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.10. subst usage
+   Example 1.11. subst usage
 ...
 ...
 # replace the uri in to: with the message uri (just an example)
 # replace the uri in to: with the message uri (just an example)
 if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1\u\2/ig') ) {};
 if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1\u\2/ig') ) {};
@@ -426,7 +453,7 @@ if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1$avp(sip_address)\2/ig') )
 
 
 ...
 ...
 
 
-3.11.  subst_uri('/re/repl/flags')
+3.12. subst_uri('/re/repl/flags')
 
 
    Runs the re substitution on the message uri (like subst but works only
    Runs the re substitution on the message uri (like subst but works only
    on the uri)
    on the uri)
@@ -442,7 +469,7 @@ if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1$avp(sip_address)\2/ig') )
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.11. subst_uri usage
+   Example 1.12. subst_uri usage
 ...
 ...
 # adds 3463 prefix to numeric uris, and save the original uri (\0 match)
 # adds 3463 prefix to numeric uris, and save the original uri (\0 match)
 # as a parameter: orig_uri (just an example)
 # as a parameter: orig_uri (just an example)
@@ -454,7 +481,7 @@ if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:$avp(uri_prefix)\1@\2;orig_uri=\0/i')){$
 
 
 ...
 ...
 
 
-3.12.  subst_user('/re/repl/flags')
+3.13. subst_user('/re/repl/flags')
 
 
    Runs the re substitution on the message uri (like subst_uri but works
    Runs the re substitution on the message uri (like subst_uri but works
    only on the user portion of the uri)
    only on the user portion of the uri)
@@ -470,7 +497,7 @@ if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:$avp(uri_prefix)\1@\2;orig_uri=\0/i')){$
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.12. subst usage
+   Example 1.13. subst usage
 ...
 ...
 # adds 3463 prefix to uris ending with 3642 (just an example)
 # adds 3463 prefix to uris ending with 3642 (just an example)
 if (subst_user('/3642$/36423463/')){$
 if (subst_user('/3642$/36423463/')){$
@@ -481,7 +508,7 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$
 
 
 ...
 ...
 
 
-3.13.  subst_body('/re/repl/flags')
+3.14. subst_body('/re/repl/flags')
 
 
    Replaces re with repl (sed or perl like) in the body of the message.
    Replaces re with repl (sed or perl like) in the body of the message.
 
 
@@ -496,13 +523,33 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.13. subst_body usage
+   Example 1.14. subst_body usage
 ...
 ...
 if ( subst_body('/^o=(.*) /o=$fU /') ) {};
 if ( subst_body('/^o=(.*) /o=$fU /') ) {};
 
 
 ...
 ...
 
 
-3.14.  set_body(txt,content_type)
+3.15. subst_hf(hf, subexp, flags)
+
+   Perl-like substitutions in the body of a header field.
+
+   Meaning of the parameters is as follows:
+     * hf - header field name.
+     * subexp - substitution expression in the same format as of the
+       'subst' function parameter.
+     * flags - control flags - it has to be one of: a - all headers
+       matching the name; f - only first header matching the name; l -
+       only the last header matching the name.
+
+   This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
+   FAILURE_ROUTE, BRANCH_ROUTE.
+
+   Example 1.15. search_body usage
+...
+if ( subst_hf("From", "/:test@/:best@/", "a") ) { /*....*/ };
+...
+
+3.16. set_body(txt,content_type)
 
 
    Set body to a SIP message.
    Set body to a SIP message.
 
 
@@ -514,12 +561,12 @@ if ( subst_body('/^o=(.*) /o=$fU /') ) {};
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.14. set_body usage
+   Example 1.16. set_body usage
 ...
 ...
 set_body("test", "text/plain");
 set_body("test", "text/plain");
 ...
 ...
 
 
-3.15.  set_reply_body(txt,content_type)
+3.17. set_reply_body(txt,content_type)
 
 
    Set body to a SIP reply to be generated by Kamailio.
    Set body to a SIP reply to be generated by Kamailio.
 
 
@@ -531,12 +578,12 @@ set_body("test", "text/plain");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
    BRANCH_ROUTE.
 
 
-   Example 1.15. set_reply_body usage
+   Example 1.17. set_reply_body usage
 ...
 ...
 set_reply_body("test", "text/plain");
 set_reply_body("test", "text/plain");
 ...
 ...
 
 
-3.16.  filter_body(content_type)
+3.18. filter_body(content_type)
 
 
    Filters multipart/mixed body by leaving out all other body parts except
    Filters multipart/mixed body by leaving out all other body parts except
    the first body part of given type.
    the first body part of given type.
@@ -547,7 +594,7 @@ set_reply_body("test", "text/plain");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.16. filter_body usage
+   Example 1.18. filter_body usage
 ...
 ...
 if (has_body("multipart/mixed")) {
 if (has_body("multipart/mixed")) {
     if (filter_body("application/sdp") {
     if (filter_body("application/sdp") {
@@ -559,7 +606,7 @@ if (has_body("multipart/mixed")) {
 }
 }
 ...
 ...
 
 
-3.17.  append_to_reply(txt)
+3.19. append_to_reply(txt)
 
 
    Append txt as header to the reply.
    Append txt as header to the reply.
 
 
@@ -569,13 +616,13 @@ if (has_body("multipart/mixed")) {
    This function can be used from REQUEST_ROUTE, BRANCH_ROUTE,
    This function can be used from REQUEST_ROUTE, BRANCH_ROUTE,
    FAILURE_ROUTE, ERROR_ROUTE.
    FAILURE_ROUTE, ERROR_ROUTE.
 
 
-   Example 1.17. append_to_reply usage
+   Example 1.19. append_to_reply usage
 ...
 ...
 append_to_reply("Foo: bar\r\n");
 append_to_reply("Foo: bar\r\n");
 append_to_reply("Foo: $rm at $Ts\r\n");
 append_to_reply("Foo: $rm at $Ts\r\n");
 ...
 ...
 
 
-3.18.  append_hf(txt)
+3.20. append_hf(txt)
 
 
    Appends 'txt' as header after the last header field.
    Appends 'txt' as header after the last header field.
 
 
@@ -592,13 +639,13 @@ append_to_reply("Foo: $rm at $Ts\r\n");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.18. append_hf usage
+   Example 1.20. append_hf usage
 ...
 ...
 append_hf("P-hint: VOICEMAIL\r\n");
 append_hf("P-hint: VOICEMAIL\r\n");
 append_hf("From-username: $fU\r\n");
 append_hf("From-username: $fU\r\n");
 ...
 ...
 
 
-3.19.  append_hf(txt, hdr)
+3.21. append_hf(txt, hdr)
 
 
    Appends 'txt' as header after first 'hdr' header field.
    Appends 'txt' as header after first 'hdr' header field.
 
 
@@ -610,13 +657,13 @@ append_hf("From-username: $fU\r\n");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.19. append_hf usage
+   Example 1.21. append_hf usage
 ...
 ...
 append_hf("P-hint: VOICEMAIL\r\n", "Call-ID");
 append_hf("P-hint: VOICEMAIL\r\n", "Call-ID");
 append_hf("From-username: $fU\r\n", "Call-ID");
 append_hf("From-username: $fU\r\n", "Call-ID");
 ...
 ...
 
 
-3.20.  insert_hf(txt)
+3.22. insert_hf(txt)
 
 
    Inserts 'txt' as header before the first header field.
    Inserts 'txt' as header before the first header field.
 
 
@@ -627,13 +674,13 @@ append_hf("From-username: $fU\r\n", "Call-ID");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.20. insert_hf usage
+   Example 1.22. insert_hf usage
 ...
 ...
 insert_hf("P-hint: VOICEMAIL\r\n");
 insert_hf("P-hint: VOICEMAIL\r\n");
 insert_hf("To-username: $tU\r\n");
 insert_hf("To-username: $tU\r\n");
 ...
 ...
 
 
-3.21.  insert_hf(txt, hdr)
+3.23. insert_hf(txt, hdr)
 
 
    Inserts 'txt' as header before first 'hdr' header field.
    Inserts 'txt' as header before first 'hdr' header field.
 
 
@@ -645,13 +692,13 @@ insert_hf("To-username: $tU\r\n");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.21. insert_hf usage
+   Example 1.23. insert_hf usage
 ...
 ...
 insert_hf("P-hint: VOICEMAIL\r\n", "Call-ID");
 insert_hf("P-hint: VOICEMAIL\r\n", "Call-ID");
 insert_hf("To-username: $tU\r\n", "Call-ID");
 insert_hf("To-username: $tU\r\n", "Call-ID");
 ...
 ...
 
 
-3.22.  append_urihf(prefix, suffix)
+3.24. append_urihf(prefix, suffix)
 
 
    Append header field name with original Request-URI in middle.
    Append header field name with original Request-URI in middle.
 
 
@@ -662,19 +709,19 @@ insert_hf("To-username: $tU\r\n", "Call-ID");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
    BRANCH_ROUTE.
 
 
-   Example 1.22. append_urihf usage
+   Example 1.24. append_urihf usage
 ...
 ...
 append_urihf("CC-Diversion: ", "\r\n");
 append_urihf("CC-Diversion: ", "\r\n");
 ...
 ...
 
 
-3.23.  is_present_hf(hf_name)
+3.25. is_present_hf(hf_name)
 
 
    Return true if a header field is present in message.
    Return true if a header field is present in message.
 
 
 Note
 Note
 
 
    The function is also able to distinguish the compact names. For exmaple
    The function is also able to distinguish the compact names. For exmaple
-   “From� will match with “f�
+   "From" will match with "f"
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
      * hf_name - Header field name.(long or compact form)
      * hf_name - Header field name.(long or compact form)
@@ -682,12 +729,12 @@ Note
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.23. is_present_hf usage
+   Example 1.25. is_present_hf usage
 ...
 ...
 if (is_present_hf("From")) log(1, "From HF Present");
 if (is_present_hf("From")) log(1, "From HF Present");
 ...
 ...
 
 
-3.24.  is_present_hf_re(hf_name_re)
+3.26. is_present_hf_re(hf_name_re)
 
 
    Return true if a header field whose name matches regular expression
    Return true if a header field whose name matches regular expression
    'hf_name_re' is present in message.
    'hf_name_re' is present in message.
@@ -698,17 +745,17 @@ if (is_present_hf("From")) log(1, "From HF Present");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.24. is_present_hf_re usage
+   Example 1.26. is_present_hf_re usage
 ...
 ...
 if (is_present_hf_re("^P-")) log(1, "There are headers starting with P-\n");
 if (is_present_hf_re("^P-")) log(1, "There are headers starting with P-\n");
 ...
 ...
 
 
-3.25.  append_time()
+3.27. append_time()
 
 
    Adds a time header to the reply of the request. You must use it before
    Adds a time header to the reply of the request. You must use it before
    functions that are likely to send a reply, e.g., save() from
    functions that are likely to send a reply, e.g., save() from
-   'registrar' module. Header format is: “Date: %a, %d %b %Y %H:%M:%S
-   GMT�, with the legend:
+   'registrar' module. Header format is: "Date: %a, %d %b %Y %H:%M:%S
+   GMT", with the legend:
      * %a abbreviated week of day name (locale)
      * %a abbreviated week of day name (locale)
      * %d day of month as decimal number
      * %d day of month as decimal number
      * %b abbreviated month name (locale)
      * %b abbreviated month name (locale)
@@ -722,15 +769,15 @@ if (is_present_hf_re("^P-")) log(1, "There are headers starting with P-\n");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
    BRANCH_ROUTE.
 
 
-   Example 1.25. append_time usage
+   Example 1.27. append_time usage
 ...
 ...
 append_time();
 append_time();
 ...
 ...
 
 
-3.26.  append_time_to_request()
+3.28. append_time_to_request()
 
 
-   Adds a time header to the request. Header format is: “Date: %a, %d %b
-   %Y %H:%M:%S GMT�, with the legend:
+   Adds a time header to the request. Header format is: "Date: %a, %d %b
+   %Y %H:%M:%S GMT", with the legend:
      * %a abbreviated week of day name (locale)
      * %a abbreviated week of day name (locale)
      * %d day of month as decimal number
      * %d day of month as decimal number
      * %b abbreviated month name (locale)
      * %b abbreviated month name (locale)
@@ -744,13 +791,13 @@ append_time();
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
    FAILURE_ROUTE, BRANCH_ROUTE.
 
 
-   Example 1.26. append_time_to_request usage
+   Example 1.28. append_time_to_request usage
 ...
 ...
 if(!is_present_hf("Date"))
 if(!is_present_hf("Date"))
     append_time_to_request();
     append_time_to_request();
 ...
 ...
 
 
-3.27.  is_method(name)
+3.29. is_method(name)
 
 
    Check if the method of the message matches the name. If name is a known
    Check if the method of the message matches the name. If name is a known
    method (invite, cancel, ack, bye, options, info, update, register,
    method (invite, cancel, ack, bye, options, info, update, register,
@@ -775,7 +822,7 @@ if(!is_present_hf("Date"))
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, and BRANCH_ROUTE.
    FAILURE_ROUTE, and BRANCH_ROUTE.
 
 
-   Example 1.27. is_method usage
+   Example 1.29. is_method usage
 ...
 ...
 if(is_method("INVITE"))
 if(is_method("INVITE"))
 {
 {
@@ -787,9 +834,9 @@ if(is_method("OPTION|UPDATE"))
 }
 }
 ...
 ...
 
 
-3.28.  remove_hf(hname)
+3.30. remove_hf(hname)
 
 
-   Remove from message all headers with name “hname�. Header matching is
+   Remove from message all headers with name "hname". Header matching is
    case-insensitive. Matches and removes also the compact header forms.
    case-insensitive. Matches and removes also the compact header forms.
 
 
    Returns true if at least one header is found and removed.
    Returns true if at least one header is found and removed.
@@ -800,7 +847,7 @@ if(is_method("OPTION|UPDATE"))
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
    FAILURE_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.28. remove_hf usage
+   Example 1.30. remove_hf usage
 ...
 ...
 if(remove_hf("User-Agent"))
 if(remove_hf("User-Agent"))
 {
 {
@@ -812,10 +859,10 @@ remove_hf("Contact")
 remove_hf("m")
 remove_hf("m")
 ...
 ...
 
 
-3.29.  remove_hf_re(re)
+3.31. remove_hf_re(re)
 
 
    Remove from message all headers with name matching regular expression
    Remove from message all headers with name matching regular expression
-   “re�
+   "re"
 
 
    Returns true if at least one header is found and removed.
    Returns true if at least one header is found and removed.
 
 
@@ -825,7 +872,7 @@ remove_hf("m")
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
    FAILURE_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.29. remove_hf_re usage
+   Example 1.31. remove_hf_re usage
 ...
 ...
 if(remove_hf_re("^P-"))
 if(remove_hf_re("^P-"))
 {
 {
@@ -833,22 +880,22 @@ if(remove_hf_re("^P-"))
 }
 }
 ...
 ...
 
 
-3.30.  has_body(), has_body(mime)
+3.32. has_body(), has_body(mime)
 
 
    The function returns true if the SIP message has a body attached. The
    The function returns true if the SIP message has a body attached. The
-   checked includes also the “Content-Lenght� header presence and value.
+   checked includes also the "Content-Lenght" header presence and value.
 
 
    If a parameter is given, the mime described will be also checked
    If a parameter is given, the mime described will be also checked
-   against the “Content-Type� header.
+   against the "Content-Type" header.
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
-     * mime - mime to be checked against the “Content-Type� header. If not
+     * mime - mime to be checked against the "Content-Type" header. If not
        present or 0, this check will be disabled.
        present or 0, this check will be disabled.
 
 
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
    FAILURE_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.30. has_body usage
+   Example 1.32. has_body usage
 ...
 ...
 if(has_body("application/sdp"))
 if(has_body("application/sdp"))
 {
 {
@@ -856,7 +903,7 @@ if(has_body("application/sdp"))
 }
 }
 ...
 ...
 
 
-3.31.  is_audio_on_hold()
+3.33. is_audio_on_hold()
 
 
    The function returns true if the SIP message has a body attached and at
    The function returns true if the SIP message has a body attached and at
    least one audio stream in on hold.
    least one audio stream in on hold.
@@ -864,7 +911,7 @@ if(has_body("application/sdp"))
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
    FAILURE_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.31. is_audio_on_hold usage
+   Example 1.33. is_audio_on_hold usage
 ...
 ...
 if(is_audio_on_hold())
 if(is_audio_on_hold())
 {
 {
@@ -872,7 +919,7 @@ if(is_audio_on_hold())
 }
 }
 ...
 ...
 
 
-3.32.  is_privacy(privacy_type)
+3.34. is_privacy(privacy_type)
 
 
    The function returns true if the SIP message has a Privacy header field
    The function returns true if the SIP message has a Privacy header field
    that includes the given privacy_type among its privacy values. See
    that includes the given privacy_type among its privacy values. See
@@ -882,7 +929,7 @@ if(is_audio_on_hold())
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
    FAILURE_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.32. is_privacy usage
+   Example 1.34. is_privacy usage
 ...
 ...
 if(is_privacy("id"))
 if(is_privacy("id"))
 {
 {
@@ -890,7 +937,7 @@ if(is_privacy("id"))
 }
 }
 ...
 ...
 
 
-3.33.  in_list(subject, list, separator)
+3.35. in_list(subject, list, separator)
 
 
    Function checks if subject string is found in list string where list
    Function checks if subject string is found in list string where list
    items are separated by separator string. Subject and list strings may
    items are separated by separator string. Subject and list strings may
@@ -899,7 +946,7 @@ if(is_privacy("id"))
 
 
    Function can be used from all kinds of routes.
    Function can be used from all kinds of routes.
 
 
-   Example 1.33. in_list() usage
+   Example 1.35. in_list() usage
 ...
 ...
 $var(subject) = "fi";
 $var(subject) = "fi";
 $var(list) = "dk,fi,no,se";
 $var(list) = "dk,fi,no,se";
@@ -908,7 +955,7 @@ if (in_list("$var(subject)", "$var(list)", ",") {
 }
 }
 ...
 ...
 
 
-3.34.  cmp_str(str1, str2)
+3.36. cmp_str(str1, str2)
 
 
    The function returns true if the two parameters matches as string case
    The function returns true if the two parameters matches as string case
    sensitive comparison.
    sensitive comparison.
@@ -916,7 +963,7 @@ if (in_list("$var(subject)", "$var(list)", ",") {
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
    FAILURE_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.34. cmp_str usage
+   Example 1.36. cmp_str usage
 ...
 ...
 if(cmp_str("$rU", "kamailio"))
 if(cmp_str("$rU", "kamailio"))
 {
 {
@@ -924,7 +971,7 @@ if(cmp_str("$rU", "kamailio"))
 }
 }
 ...
 ...
 
 
-3.35.  cmp_istr(str1, str2)
+3.37. cmp_istr(str1, str2)
 
 
    The function returns true if the two parameters matches as string case
    The function returns true if the two parameters matches as string case
    insensitive comparison.
    insensitive comparison.
@@ -932,7 +979,7 @@ if(cmp_str("$rU", "kamailio"))
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
    FAILURE_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.35. cmp_str usage
+   Example 1.37. cmp_str usage
 ...
 ...
 if(cmp_istr("$rU@you", "kamailio@YOU"))
 if(cmp_istr("$rU@you", "kamailio@YOU"))
 {
 {
@@ -940,7 +987,7 @@ if(cmp_istr("$rU@you", "kamailio@YOU"))
 }
 }
 ...
 ...
 
 
-3.36.  starts_with(str1, str2)
+3.38. starts_with(str1, str2)
 
 
    The function returns true if the first string starts with the second
    The function returns true if the first string starts with the second
    string.
    string.
@@ -948,7 +995,7 @@ if(cmp_istr("$rU@you", "kamailio@YOU"))
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
    FAILURE_ROUTE and BRANCH_ROUTE.
 
 
-   Example 1.36. starts_with usage
+   Example 1.38. starts_with usage
 ...
 ...
 if (starts_with("$rU", "+358"))
 if (starts_with("$rU", "+358"))
 {
 {
@@ -973,10 +1020,10 @@ Chapter 2. Developer Guide
 
 
    1.1. load_textops(*import_structure)
    1.1. load_textops(*import_structure)
 
 
-1.1.  load_textops(*import_structure)
+1.1. load_textops(*import_structure)
 
 
    For programmatic use only--import the Textops API.
    For programmatic use only--import the Textops API.
 
 
    Meaning of the parameters is as follows:
    Meaning of the parameters is as follows:
-     * import_structure - Pointer to the import structure - see “struct
-       textops_binds� in modules/textops/api.h
+     * import_structure - Pointer to the import structure - see "struct
+       textops_binds" in modules/textops/api.h

+ 79 - 0
modules_k/textops/doc/textops_admin.xml

@@ -123,6 +123,45 @@ if ( search("[Ss][Ii][Pp]") ) { /*....*/ };
 ...
 ...
 if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ };
 if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ };
 ...
 ...
+</programlisting>
+		</example>
+	</section>
+
+		<section>
+		<title>
+		<function moreinfo="none">search_hf(hf, re, flags)</function>
+		</title>
+		<para>
+		Searches for the re in the body of a header field.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>hf</emphasis> - header field name.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>re</emphasis> - regular expression.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>flags</emphasis> - control flags - it
+				has to be one of: a - all headers matching the
+				name; f - only first header matching the name;
+				l - only the last header matching the name.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, 
+		FAILURE_ROUTE, BRANCH_ROUTE.
+		</para>
+		<example>
+		<title><function>search_body</function> usage</title>
+		<programlisting format="linespecific">
+...
+if ( search_hf("From", ":test@", "a") ) { /*....*/ };
+...
 </programlisting>
 </programlisting>
 		</example>
 		</example>
 	</section>
 	</section>
@@ -529,6 +568,46 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$
 ...
 ...
 if ( subst_body('/^o=(.*) /o=$fU /') ) {};
 if ( subst_body('/^o=(.*) /o=$fU /') ) {};
 
 
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title>
+		<function moreinfo="none">subst_hf(hf, subexp, flags)</function>
+		</title>
+		<para>
+		Perl-like substitutions in the body of a header field.
+		</para>
+		<para>Meaning of the parameters is as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>hf</emphasis> - header field name.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>subexp</emphasis> - substitution expression
+				in the same format as of the 'subst' function parameter.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>flags</emphasis> - control flags - it
+				has to be one of: a - all headers matching the
+				name; f - only first header matching the name;
+				l - only the last header matching the name.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, 
+		FAILURE_ROUTE, BRANCH_ROUTE.
+		</para>
+		<example>
+		<title><function>search_body</function> usage</title>
+		<programlisting format="linespecific">
+...
+if ( subst_hf("From", "/:test@/:best@/", "a") ) { /*....*/ };
 ...
 ...
 </programlisting>
 </programlisting>
 		</example>
 		</example>

+ 225 - 0
modules_k/textops/textops.c

@@ -99,6 +99,7 @@ MODULE_VERSION
 
 
 
 
 static int search_body_f(struct sip_msg*, char*, char*);
 static int search_body_f(struct sip_msg*, char*, char*);
+static int search_hf_f(struct sip_msg*, char*, char*, char*);
 static int replace_f(struct sip_msg*, char*, char*);
 static int replace_f(struct sip_msg*, char*, char*);
 static int replace_body_f(struct sip_msg*, char*, char*);
 static int replace_body_f(struct sip_msg*, char*, char*);
 static int replace_all_f(struct sip_msg*, char*, char*);
 static int replace_all_f(struct sip_msg*, char*, char*);
@@ -108,6 +109,7 @@ static int subst_f(struct sip_msg*, char*, char*);
 static int subst_uri_f(struct sip_msg*, char*, char*);
 static int subst_uri_f(struct sip_msg*, char*, char*);
 static int subst_user_f(struct sip_msg*, char*, char*);
 static int subst_user_f(struct sip_msg*, char*, char*);
 static int subst_body_f(struct sip_msg*, char*, char*);
 static int subst_body_f(struct sip_msg*, char*, char*);
+static int subst_hf_f(struct sip_msg*, char*, char*, char*);
 static int filter_body_f(struct sip_msg*, char*, char*);
 static int filter_body_f(struct sip_msg*, char*, char*);
 static int is_present_hf_f(struct sip_msg* msg, char* str_hf, char* foo);
 static int is_present_hf_f(struct sip_msg* msg, char* str_hf, char* foo);
 static int search_append_body_f(struct sip_msg*, char*, char*);
 static int search_append_body_f(struct sip_msg*, char*, char*);
@@ -140,6 +142,8 @@ 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(void** param, int param_no);
 static int fixup_free_in_list(void** param, int param_no);
 static int fixup_free_in_list(void** param, int param_no);
 int fixup_regexpNL_none(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);
 
 
 static int mod_init(void);
 static int mod_init(void);
 
 
@@ -157,6 +161,9 @@ static cmd_export_t cmds[]={
 	{"search_body",      (cmd_function)search_body_f,     1,
 	{"search_body",      (cmd_function)search_body_f,     1,
 		fixup_regexp_null, fixup_free_regexp_null,
 		fixup_regexp_null, fixup_free_regexp_null,
 		ANY_ROUTE},
 		ANY_ROUTE},
+	{"search_hf",      (cmd_function)search_hf_f,         3,
+		fixup_search_hf, 0,
+		ANY_ROUTE},
 	{"search_append",    (cmd_function)search_append_f,   2,
 	{"search_append",    (cmd_function)search_append_f,   2,
 		fixup_regexp_none,fixup_free_regexp_none,
 		fixup_regexp_none,fixup_free_regexp_none,
 		ANY_ROUTE},
 		ANY_ROUTE},
@@ -220,6 +227,9 @@ static cmd_export_t cmds[]={
 	{"subst_body",       (cmd_function)subst_body_f,      1,
 	{"subst_body",       (cmd_function)subst_body_f,      1,
 		fixup_substre, 0,
 		fixup_substre, 0,
 		ANY_ROUTE},
 		ANY_ROUTE},
+	{"subst_hf",         (cmd_function)subst_hf_f,        3,
+		fixup_subst_hf, 0,
+		ANY_ROUTE},
 	{"filter_body",      (cmd_function)filter_body_f,     1,
 	{"filter_body",      (cmd_function)filter_body_f,     1,
 		fixup_str_null, 0,
 		fixup_str_null, 0,
 		ANY_ROUTE},
 		ANY_ROUTE},
@@ -2142,3 +2152,218 @@ int fixup_free_regexp_none(void** param, int param_no)
 }
 }
 
 
 
 
+/**
+ *
+ */
+static int search_hf_f(struct sip_msg* msg, char* str_hf, char* re, char *flags)
+{
+	hdr_field_t *hf;
+	hdr_field_t *hfl;
+	str body;
+	gparam_t *gp;
+	regmatch_t pmatch;
+	char c;
+	int ret;
+
+	gp = (gparam_t*)str_hf;
+
+	/* we need to be sure we have seen all HFs */
+	parse_headers(msg, HDR_EOH_F, 0);
+	for (hf=msg->headers; hf; hf=hf->next) {
+		if(gp->type==GPARAM_TYPE_INT)
+		{
+			if (gp->v.i!=hf->type)
+				continue;
+		} else {
+			if (hf->name.len!=gp->v.str.len)
+				continue;
+			if (cmp_hdrname_str(&hf->name,&gp->v.str)!=0)
+				continue;
+		}
+
+		if(flags==NULL || *flags!='l')
+		{
+			body = hf->body;
+			c = body.s[body.len];
+			body.s[body.len] = '\0';
+			ret = regexec((regex_t*) re, body.s, 1, &pmatch, 0);
+			body.s[body.len] = c;
+			if(ret==0)
+			{
+				/* match */
+				if(flags==NULL || *flags!='l')
+					return 1;
+			} else {
+				if(flags!=NULL && *flags=='f')
+					return 1;
+			}
+		} else {
+			hfl = hf;
+		}
+	}
+	if(hfl!=NULL)
+	{
+		hf = hfl;
+		body = hf->body;
+		c = body.s[body.len];
+		body.s[body.len] = '\0';
+		ret = regexec((regex_t*) re, body.s, 1, &pmatch, 0);
+		body.s[body.len] = c;
+		if(ret==0)
+			return 1;
+	}
+	return -1;
+}
+
+/*
+ * Convert header name, regexp and flags
+ */
+static int fixup_search_hf(void** param, int param_no)
+{
+	if(param_no==1)
+		return hname_fixup(param, param_no);
+	if(param_no==2)
+		return fixup_regexp_null(param, 1);
+	return 0;
+}
+
+/* sed-perl style re: s/regular expression/replacement/flags */
+static int subst_hf_f(struct sip_msg *msg, char *str_hf, char *subst, char *flags)
+{
+	struct lump* l;
+	struct replace_lst* lst = NULL;
+	struct replace_lst* rpl = NULL;
+	char* begin;
+	struct subst_expr* se;
+	int off;
+	int nmatches;
+	str body;
+	hdr_field_t *hf;
+	hdr_field_t *hfl;
+	gparam_t *gp;
+	char c;
+	int ret;
+
+	ret = -1;
+	gp = (gparam_t*)str_hf;
+	se=(struct subst_expr*)subst;
+
+	/* we need to be sure we have seen all HFs */
+	parse_headers(msg, HDR_EOH_F, 0);
+	for (hf=msg->headers; hf; hf=hf->next) {
+		if(gp->type==GPARAM_TYPE_INT)
+		{
+			if (gp->v.i!=hf->type)
+				continue;
+		} else {
+			if (hf->name.len!=gp->v.str.len)
+				continue;
+			if (cmp_hdrname_str(&hf->name,&gp->v.str)!=0)
+				continue;
+		}
+
+		if(flags==NULL || *flags!='l')
+		{
+			body = hf->body;
+			c = body.s[body.len];
+			body.s[body.len] = '\0';
+
+			begin=body.s;
+
+			off=begin-msg->buf;
+			lst=subst_run(se, begin, msg, &nmatches);
+			body.s[body.len] = c;
+			if(lst==0 && flags!=NULL && *flags=='f')
+				goto error; /* not found */
+			if(lst!=0)
+				ret=1;
+			for (rpl=lst; rpl; rpl=rpl->next)
+			{
+				LM_DBG("%s replacing at offset %d [%.*s] with [%.*s]\n",
+						exports.name, rpl->offset+off,
+						rpl->size, rpl->offset+off+msg->buf,
+						rpl->rpl.len, rpl->rpl.s);
+				if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0)
+				{
+					ret=-1;
+					goto error;
+				}
+				/* hack to avoid re-copying rpl, possible because both 
+				 * replace_lst & lumps use pkg_malloc */
+				if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0)
+				{
+					LM_ERR("%s could not insert new lump\n",
+						exports.name);
+					ret=-1;
+					goto error;
+				}
+				/* hack continued: set rpl.s to 0 so that replace_lst_free will
+				 * not free it */
+				rpl->rpl.s=0;
+				rpl->rpl.len=0;
+			}
+		} else {
+			hfl = hf;
+		}
+	}
+	if(hfl!=NULL)
+	{
+		hf= hfl;
+		body = hf->body;
+		c = body.s[body.len];
+		body.s[body.len] = '\0';
+
+		begin=body.s;
+
+		off=begin-msg->buf;
+		lst=subst_run(se, begin, msg, &nmatches);
+		body.s[body.len] = c;
+		if(lst==0)
+			goto error; /* not found */
+		ret=1;
+		for (rpl=lst; rpl; rpl=rpl->next)
+		{
+			LM_DBG("%s replacing at offset %d [%.*s] with [%.*s]\n",
+					exports.name, rpl->offset+off,
+					rpl->size, rpl->offset+off+msg->buf,
+					rpl->rpl.len, rpl->rpl.s);
+			if ((l=del_lump(msg, rpl->offset+off, rpl->size, 0))==0)
+			{
+				ret=-1;
+				goto error;
+			}
+			/* hack to avoid re-copying rpl, possible because both 
+			 * replace_lst & lumps use pkg_malloc */
+			if (insert_new_lump_after(l, rpl->rpl.s, rpl->rpl.len, 0)==0)
+			{
+				LM_ERR("%s could not insert new lump\n",
+					exports.name);
+				ret=-1;
+				goto error;
+			}
+			/* hack continued: set rpl.s to 0 so that replace_lst_free will
+			 * not free it */
+			rpl->rpl.s=0;
+			rpl->rpl.len=0;
+		}
+	}
+error:
+	LM_DBG("lst was %p\n", lst);
+	if (lst) replace_lst_free(lst);
+	if (nmatches<0)
+		LM_ERR("%s subst_run failed\n", exports.name);
+	return ret;
+}
+
+/*
+ * Convert header name, substexp and flags
+ */
+static int fixup_subst_hf(void** param, int param_no)
+{
+	if(param_no==1)
+		return hname_fixup(param, param_no);
+	if(param_no==2)
+		return fixup_substre(param, 1);
+	return 0;
+}
+