소스 검색

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]>
 
-   Copyright © 2003 FhG FOKUS
+   Copyright © 2003 FhG FOKUS
      __________________________________________________________________
 
    Table of Contents
@@ -43,40 +43,42 @@ Juha Heinanen
 
               3.1. search(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
 
@@ -90,40 +92,42 @@ Juha Heinanen
 
    1.1. search 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
 
@@ -142,40 +146,42 @@ Chapter 1. Admin Guide
 
         3.1. search(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
 
@@ -192,7 +198,7 @@ Chapter 1. Admin Guide
 
 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:
 From: medabeda
  <sip:[email protected]>;tag=1234
@@ -217,42 +223,44 @@ From: medabeda
 
    3.1. search(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.
 
@@ -267,7 +275,7 @@ From: medabeda
 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.
 
@@ -282,7 +290,26 @@ if ( search("[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.
 
@@ -293,12 +320,12 @@ if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ };
    This function can be used from REQUEST_ROUTE, ONREPLY_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");
 ...
 
-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
    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,
    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");
 ...
 
-3.5.  replace(re, txt)
+3.6. replace(re, 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,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.5. replace usage
+   Example 1.6. replace usage
 ...
 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
    txt.
@@ -343,12 +370,12 @@ replace("openser", "Kamailio SIP Proxy");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.6. replace_body usage
+   Example 1.7. replace_body usage
 ...
 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.
 
@@ -359,12 +386,12 @@ replace_body("openser", "Kamailio SIP Proxy");
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.7. replace_all usage
+   Example 1.8. replace_all usage
 ...
 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.
    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,
    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");
 ...
 
-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.
    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,
    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:
 if(has_body() && replace_body_atonce("^.+$", ""))
         remove_hf("Content-Type");
 ...
 
-3.10.  subst('/re/repl/flags')
+3.11. subst('/re/repl/flags')
 
    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,
    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)
 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
    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,
    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)
 # 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
    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,
    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)
 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.
 
@@ -496,13 +523,33 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.13. subst_body usage
+   Example 1.14. subst_body usage
 ...
 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.
 
@@ -514,12 +561,12 @@ if ( subst_body('/^o=(.*) /o=$fU /') ) {};
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.14. set_body usage
+   Example 1.16. set_body usage
 ...
 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.
 
@@ -531,12 +578,12 @@ set_body("test", "text/plain");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
 
-   Example 1.15. set_reply_body usage
+   Example 1.17. set_reply_body usage
 ...
 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
    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,
    FAILURE_ROUTE, BRANCH_ROUTE.
 
-   Example 1.16. filter_body usage
+   Example 1.18. filter_body usage
 ...
 if (has_body("multipart/mixed")) {
     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.
 
@@ -569,13 +616,13 @@ if (has_body("multipart/mixed")) {
    This function can be used from REQUEST_ROUTE, BRANCH_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: $rm at $Ts\r\n");
 ...
 
-3.18.  append_hf(txt)
+3.20. append_hf(txt)
 
    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,
    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("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.
 
@@ -610,13 +657,13 @@ append_hf("From-username: $fU\r\n");
    This function can be used from REQUEST_ROUTE, ONREPLY_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("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.
 
@@ -627,13 +674,13 @@ append_hf("From-username: $fU\r\n", "Call-ID");
    This function can be used from REQUEST_ROUTE, ONREPLY_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("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.
 
@@ -645,13 +692,13 @@ insert_hf("To-username: $tU\r\n");
    This function can be used from REQUEST_ROUTE, ONREPLY_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("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.
 
@@ -662,19 +709,19 @@ insert_hf("To-username: $tU\r\n", "Call-ID");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE.
 
-   Example 1.22. append_urihf usage
+   Example 1.24. append_urihf usage
 ...
 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.
 
 Note
 
    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:
      * hf_name - Header field name.(long or compact form)
@@ -682,12 +729,12 @@ Note
    This function can be used from REQUEST_ROUTE, ONREPLY_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");
 ...
 
-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
    '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,
    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");
 ...
 
-3.25.  append_time()
+3.27. append_time()
 
    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
-   '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)
      * %d day of month as decimal number
      * %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,
    BRANCH_ROUTE.
 
-   Example 1.25. append_time usage
+   Example 1.27. append_time usage
 ...
 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)
      * %d day of month as decimal number
      * %b abbreviated month name (locale)
@@ -744,13 +791,13 @@ append_time();
    This function can be used from REQUEST_ROUTE, ONREPLY_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"))
     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
    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,
    FAILURE_ROUTE, and BRANCH_ROUTE.
 
-   Example 1.27. is_method usage
+   Example 1.29. is_method usage
 ...
 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.
 
    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,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
-   Example 1.28. remove_hf usage
+   Example 1.30. remove_hf usage
 ...
 if(remove_hf("User-Agent"))
 {
@@ -812,10 +859,10 @@ remove_hf("Contact")
 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
-   “re�
+   "re"
 
    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,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
-   Example 1.29. remove_hf_re usage
+   Example 1.31. remove_hf_re usage
 ...
 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
-   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
-   against the “Content-Type� header.
+   against the "Content-Type" header.
 
    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.
 
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
-   Example 1.30. has_body usage
+   Example 1.32. has_body usage
 ...
 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
    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,
    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())
 {
@@ -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
    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,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
-   Example 1.32. is_privacy usage
+   Example 1.34. is_privacy usage
 ...
 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
    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.
 
-   Example 1.33. in_list() usage
+   Example 1.35. in_list() usage
 ...
 $var(subject) = "fi";
 $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
    sensitive comparison.
@@ -916,7 +963,7 @@ if (in_list("$var(subject)", "$var(list)", ",") {
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
-   Example 1.34. cmp_str usage
+   Example 1.36. cmp_str usage
 ...
 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
    insensitive comparison.
@@ -932,7 +979,7 @@ if(cmp_str("$rU", "kamailio"))
    This function can be used from REQUEST_ROUTE, ONREPLY_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"))
 {
@@ -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
    string.
@@ -948,7 +995,7 @@ if(cmp_istr("$rU@you", "kamailio@YOU"))
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE and BRANCH_ROUTE.
 
-   Example 1.36. starts_with usage
+   Example 1.38. starts_with usage
 ...
 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)
 
    For programmatic use only--import the Textops API.
 
    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]") ) { /*....*/ };
 ...
+</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>
 		</example>
 	</section>
@@ -529,6 +568,46 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$
 ...
 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>
 		</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_hf_f(struct sip_msg*, char*, char*, char*);
 static int replace_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*);
@@ -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_user_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 is_present_hf_f(struct sip_msg* msg, char* str_hf, char* foo);
 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_free_in_list(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);
 
@@ -157,6 +161,9 @@ static cmd_export_t cmds[]={
 	{"search_body",      (cmd_function)search_body_f,     1,
 		fixup_regexp_null, fixup_free_regexp_null,
 		ANY_ROUTE},
+	{"search_hf",      (cmd_function)search_hf_f,         3,
+		fixup_search_hf, 0,
+		ANY_ROUTE},
 	{"search_append",    (cmd_function)search_append_f,   2,
 		fixup_regexp_none,fixup_free_regexp_none,
 		ANY_ROUTE},
@@ -220,6 +227,9 @@ static cmd_export_t cmds[]={
 	{"subst_body",       (cmd_function)subst_body_f,      1,
 		fixup_substre, 0,
 		ANY_ROUTE},
+	{"subst_hf",         (cmd_function)subst_hf_f,        3,
+		fixup_subst_hf, 0,
+		ANY_ROUTE},
 	{"filter_body",      (cmd_function)filter_body_f,     1,
 		fixup_str_null, 0,
 		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;
+}
+