7777#include "../../str.h"
7878#include "../../locking.h"
7979#include "../../mod_fix.h"
80+ #include "../../pvar.h"
81+ #include "../../error.h"
8082#include "../../mi/mi.h"
8183
8284#define START 0
@@ -128,12 +130,15 @@ static void destroy(void);
128130 */
129131static int load_pcres (int );
130132static void free_shared_memory (void );
133+ static int fixup_check_pv_setf (void * * param );
134+ static int set_match_pvar (struct sip_msg * msg , pv_spec_t * match , str * value );
131135
132136
133137/*
134138 * Script functions
135139 */
136- static int w_pcre_match (struct sip_msg * _msg , str * string , str * _regex_s );
140+ static int w_pcre_match (struct sip_msg * _msg , str * string , str * _regex_s ,
141+ pv_spec_t * match );
137142static int w_pcre_match_group (struct sip_msg * _msg , str * string , int * _num_pcre );
138143
139144
@@ -152,7 +157,8 @@ static const cmd_export_t cmds[] =
152157{
153158 {"pcre_match" , (cmd_function )w_pcre_match , {
154159 {CMD_PARAM_STR ,0 ,0 },
155- {CMD_PARAM_STR ,0 ,0 }, {0 ,0 ,0 }},
160+ {CMD_PARAM_STR ,0 ,0 },
161+ {CMD_PARAM_VAR |CMD_PARAM_OPT , fixup_check_pv_setf , 0 }, {0 ,0 ,0 }},
156162 REQUEST_ROUTE |FAILURE_ROUTE |ONREPLY_ROUTE |BRANCH_ROUTE |LOCAL_ROUTE |
157163 STARTUP_ROUTE |TIMER_ROUTE |EVENT_ROUTE },
158164 {"pcre_match_group" , (cmd_function )w_pcre_match_group , {
@@ -584,8 +590,49 @@ static void free_shared_memory(void)
584590 * Script functions
585591 */
586592
593+ static int fixup_check_pv_setf (void * * param )
594+ {
595+ if (!pv_is_w (((pv_spec_t * )* param ))) {
596+ LM_ERR ("invalid output parameter: must be writable\n" );
597+ return E_SCRIPT ;
598+ }
599+
600+ return 0 ;
601+ }
602+
603+
604+ static int set_match_pvar (struct sip_msg * msg , pv_spec_t * match , str * value )
605+ {
606+ pv_value_t pv_val ;
607+
608+ if (!match )
609+ return 0 ;
610+
611+ if (!value ) {
612+ if (pv_set_value (msg , match , 0 , NULL ) != 0 ) {
613+ LM_ERR ("failed to clear match pvar\n" );
614+ return -1 ;
615+ }
616+
617+ return 0 ;
618+ }
619+
620+ memset (& pv_val , 0 , sizeof (pv_val ));
621+ pv_val .flags = PV_VAL_STR ;
622+ pv_val .rs = * value ;
623+
624+ if (pv_set_value (msg , match , 0 , & pv_val ) != 0 ) {
625+ LM_ERR ("failed to set match pvar\n" );
626+ return -1 ;
627+ }
628+
629+ return 0 ;
630+ }
631+
632+
587633/*! \brief Return true if the argument matches the regular expression parameter */
588- static int w_pcre_match (struct sip_msg * _msg , str * string , str * _regex_s )
634+ static int w_pcre_match (struct sip_msg * _msg , str * string , str * _regex_s ,
635+ pv_spec_t * match )
589636{
590637 pcre2_code * pcre_re = NULL ;
591638 int pcre_rc ;
@@ -594,8 +641,12 @@ static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
594641 PCRE2_SIZE pcre_erroffset ;
595642#ifdef PCRE2_LIB
596643 pcre2_match_data * match_data ;
644+ PCRE2_SIZE * ovector ;
645+ #else
646+ int ovector [3 ];
597647#endif
598648 str regex ;
649+ str match_str ;
599650
600651 if (pkg_nt_str_dup (& regex , _regex_s ) < 0 )
601652 return -1 ;
@@ -616,10 +667,19 @@ static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
616667 string -> len , /* the length of the subject */
617668 0 , /* start at offset 0 in the subject */
618669 0 , /* default options */
619- NULL , /* output vector for substring information */
620- 0 ); /* number of elements in the output vector */
670+ match ? ovector : NULL , /* output vector for substring information */
671+ match ? 3 : 0 ); /* number of elements in the output vector */
621672#else
622- match_data = pcre2_match_data_create (0 , NULL ); // no captures needed
673+ if (match )
674+ match_data = pcre2_match_data_create_from_pattern (pcre_re , NULL );
675+ else
676+ match_data = pcre2_match_data_create (0 , NULL );
677+ if (!match_data ) {
678+ LM_ERR ("failed to allocate match data\n" );
679+ pcre2_code_free (pcre_re );
680+ pkg_free (regex .s );
681+ return -1 ;
682+ }
623683
624684 pcre_rc = pcre2_match (
625685 pcre_re , /* the compiled pattern */
@@ -629,8 +689,6 @@ static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
629689 0 , /* default options */
630690 match_data , /* match data block */
631691 NULL ); /* match context */
632-
633- pcre2_match_data_free (match_data );
634692#endif
635693
636694 /* Matching failed: handle error cases */
@@ -643,14 +701,40 @@ static int w_pcre_match(struct sip_msg* _msg, str* string, str* _regex_s)
643701 LM_DBG ("matching error '%d'\n" , pcre_rc );
644702 break ;
645703 }
704+ #ifdef PCRE2_LIB
705+ pcre2_match_data_free (match_data );
706+ #endif
646707 pcre2_code_free (pcre_re );
647708 pkg_free (regex .s );
709+ if (set_match_pvar (_msg , match , NULL ) < 0 )
710+ return -1 ;
648711 return -1 ;
649712 }
650713
714+ LM_DBG ("'%s' matches '%s'\n" , string -> s , regex .s );
715+
716+ if (match ) {
717+ #ifdef PCRE2_LIB
718+ ovector = pcre2_get_ovector_pointer (match_data );
719+ #endif
720+ match_str .s = string -> s + ovector [0 ];
721+ match_str .len = (int )(ovector [1 ] - ovector [0 ]);
722+
723+ if (set_match_pvar (_msg , match , & match_str ) < 0 ) {
724+ #ifdef PCRE2_LIB
725+ pcre2_match_data_free (match_data );
726+ #endif
727+ pcre2_code_free (pcre_re );
728+ pkg_free (regex .s );
729+ return -1 ;
730+ }
731+ }
732+
733+ #ifdef PCRE2_LIB
734+ pcre2_match_data_free (match_data );
735+ #endif
651736 pcre2_code_free (pcre_re );
652737 pkg_free (regex .s );
653- LM_DBG ("'%s' matches '%s'\n" , string -> s , regex .s );
654738 return 1 ;
655739}
656740
@@ -769,7 +853,7 @@ mi_response_t *mi_pcres_match(const mi_params_t *params, struct mi_handler *asyn
769853 }
770854
771855 /* handle call back function result */
772- rc = w_pcre_match (NULL , & string , & pcre_regex );
856+ rc = w_pcre_match (NULL , & string , & pcre_regex , NULL );
773857 LM_DBG ("w_pcre_match: string<%s>, pcre_regex=<%s>, result:<%i>\n" , string .s , pcre_regex .s , rc );
774858
775859 switch (rc ) {
0 commit comments