diff --git a/modules/dialplan/dialplan.c b/modules/dialplan/dialplan.c index 2c59fe04c3e..9719053afe5 100644 --- a/modules/dialplan/dialplan.c +++ b/modules/dialplan/dialplan.c @@ -65,18 +65,19 @@ str default_param_s = str_init(DEFAULT_PARAM); dp_param_p default_par2 = NULL; static param_export_t mod_params[]={ - { "db_url", STR_PARAM, &dp_db_url.s }, + { "db_url", STR_PARAM, &dp_db_url.s }, { "table_name", STR_PARAM, &dp_table_name.s }, { "dpid_col", STR_PARAM, &dpid_column.s }, - { "pr_col", STR_PARAM, &pr_column.s }, + { "pr_col", STR_PARAM, &pr_column.s }, { "match_op_col", STR_PARAM, &match_op_column.s }, { "match_exp_col", STR_PARAM, &match_exp_column.s }, - { "match_flags_col",STR_PARAM, &match_flags_column.s }, + { "match_flags_col", STR_PARAM, &match_flags_column.s }, { "subst_exp_col", STR_PARAM, &subst_exp_column.s }, { "repl_exp_col", STR_PARAM, &repl_exp_column.s }, { "attrs_col", STR_PARAM, &attrs_column.s }, + { "timerec_col", STR_PARAM, &timerec_column.s }, { "disabled_col", STR_PARAM, &disabled_column.s}, - { "attrs_pvar", STR_PARAM, &attr_pvar_s.s}, + { "attrs_pvar", STR_PARAM, &attr_pvar_s.s}, { "attribute_pvar", STR_PARAM, &attr_pvar_s.s}, {0,0,0} }; @@ -120,7 +121,7 @@ static int mod_init(void) init_db_url( dp_db_url , 0 /*cannot be null*/); dp_table_name.len = strlen(dp_table_name.s); - dpid_column.len = strlen( dpid_column.s); + dpid_column.len = strlen(dpid_column.s); pr_column.len = strlen(pr_column.s); match_op_column.len = strlen(match_op_column.s); match_exp_column.len = strlen(match_exp_column.s); @@ -128,6 +129,7 @@ static int mod_init(void) subst_exp_column.len = strlen(subst_exp_column.s); repl_exp_column.len = strlen(repl_exp_column.s); attrs_column.len = strlen(attrs_column.s); + timerec_column.len = strlen(timerec_column.s); disabled_column.len = strlen(disabled_column.s); if(attr_pvar_s.s) { @@ -273,7 +275,6 @@ static int dp_update(struct sip_msg * msg, pv_spec_t * src, pv_spec_t * dest, return 0; } - static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2) { int dpid; @@ -292,7 +293,6 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2) LM_ERR("no dpid value\n"); return -1; } - LM_DBG("dpid is %i\n", dpid); repl_par = (str2!=NULL)? ((dp_param_p)str2):default_par2; if (dp_get_svalue(msg, repl_par->v.sp[0], &input)!=0){ @@ -311,12 +311,16 @@ static int dp_translate_f(struct sip_msg* msg, char* str1, char* str2) goto error; } + LM_DBG("Checking %.*s with dpid %i => output %.*s\n", + input.len, input.s, idp->dp_id, output.len, output.s); + attrs_par = (!attr_pvar)?NULL:&attrs; if (translate(msg, input, &output, idp, attrs_par)!=0){ LM_DBG("could not translate %.*s " "with dpid %i\n", input.len, input.s, idp->dp_id); goto error; } + LM_DBG("input %.*s with dpid %i => output %.*s\n", input.len, input.s, idp->dp_id, output.len, output.s); diff --git a/modules/dialplan/dialplan.h b/modules/dialplan/dialplan.h index 7142bf767a8..bb398fb89d3 100644 --- a/modules/dialplan/dialplan.h +++ b/modules/dialplan/dialplan.h @@ -29,6 +29,7 @@ #include "../../parser/msg_parser.h" #include "../../rw_locking.h" +#include "../../time_rec.h" #include "../../re.h" #include @@ -49,6 +50,8 @@ typedef struct dpl_node{ pcre * match_comp, * subst_comp; /*compiled patterns*/ struct subst_expr * repl_comp; str attrs; + str timerec; + tmrec_t *parsed_timerec; struct dpl_node * next; /*next rule*/ }dpl_node_t, *dpl_node_p; diff --git a/modules/dialplan/dp_db.c b/modules/dialplan/dp_db.c index c254b72a10f..8c3d0046958 100644 --- a/modules/dialplan/dp_db.c +++ b/modules/dialplan/dp_db.c @@ -30,6 +30,7 @@ #include "../../dprint.h" #include "../../ut.h" #include "../../db/db.h" +#include "../../time_rec.h" #include "dp_db.h" #include "dialplan.h" @@ -44,6 +45,7 @@ str subst_exp_column = str_init(SUBST_EXP_COL); str repl_exp_column = str_init(REPL_EXP_COL); str disabled_column = str_init(DISABLED_COL); str attrs_column = str_init(ATTRS_COL); +str timerec_column = str_init(TIMEREC_COL); static db_con_t* dp_db_handle = 0; /* database connection handle */ static db_func_t dp_dbf; @@ -67,7 +69,6 @@ int add_rule2hash(dpl_node_t * rule, dp_table_list_t *table, int index); void list_rule(dpl_node_t * ); void list_hash(dpl_id_t * , rw_lock_t *); - dp_table_list_p dp_tables = NULL; dp_table_list_p dp_default_table = NULL; @@ -187,7 +188,7 @@ int dp_load_db(dp_table_list_p dp_table) db_key_t query_cols[DP_TABLE_COL_NO] = { &dpid_column, &pr_column, &match_op_column, &match_exp_column, &match_flags_column, - &subst_exp_column, &repl_exp_column, &attrs_column }; + &subst_exp_column, &repl_exp_column, &attrs_column, &timerec_column }; db_key_t order = &pr_column; /* disabled condition */ db_key_t cond_cols[1] = { &disabled_column }; @@ -320,14 +321,55 @@ int str_to_shm(str src, str * dest) return 0; } +static inline tmrec_t* parse_time_def(char *time_str) { + + tmrec_p time_rec; + char *p,*s; + + p = time_str; + time_rec = 0; + + time_rec = tmrec_new(SHM_ALLOC); + if (time_rec==0) { + LM_ERR("no more shm mem\n"); + goto error; + } + + /* empty definition? */ + if ( time_str==0 || *time_str==0 ) + goto done; + + load_TR_value( p, s, time_rec, tr_parse_dtstart, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_duration, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_freq, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_until, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_interval, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_byday, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_bymday, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_byyday, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_byweekno, parse_error, done); + load_TR_value( p, s, time_rec, tr_parse_bymonth, parse_error, done); + + /* success */ +done: + return time_rec; +parse_error: + LM_ERR("parse error in <%s> around position %i\n", + time_str, (int)(long)(p-time_str)); +error: + if (time_rec) + tmrec_free( time_rec ); + return 0; +} /*compile the expressions, and if ok, build the rule */ dpl_node_t * build_rule(db_val_t * values) { + tmrec_t *parsed_timerec; pcre * match_comp, *subst_comp; struct subst_expr * repl_comp; dpl_node_t * new_rule; - str match_exp, subst_exp, repl_exp, attrs; + str match_exp, subst_exp, repl_exp, attrs, timerec; int matchop; int namecount; @@ -338,7 +380,8 @@ dpl_node_t * build_rule(db_val_t * values) return NULL; } - match_comp = subst_comp =0; + parsed_timerec = 0; + match_comp = subst_comp = 0; repl_comp = 0; new_rule = 0; @@ -416,6 +459,7 @@ dpl_node_t * build_rule(db_val_t * values) new_rule->pr = VAL_INT(values+1); new_rule->match_flags = VAL_INT(values+4); new_rule->matchop = matchop; + GET_STR_VALUE(attrs, values, 7); if(str_to_shm(attrs, &new_rule->attrs)!=0) goto err; @@ -423,6 +467,25 @@ dpl_node_t * build_rule(db_val_t * values) LM_DBG("attrs are %.*s\n", new_rule->attrs.len, new_rule->attrs.s); + /* Retrieve and Parse Timerec Matching Pattern */ + GET_STR_VALUE(timerec, values, 8); + if(timerec.len && timerec.s) { + parsed_timerec = parse_time_def(timerec.s); + if(!parsed_timerec) { + LM_ERR("failed to parse timerec pattern %.*s\n", + timerec.len, timerec.s); + goto err; + } + + if(str_to_shm(timerec, &new_rule->timerec) != 0) + goto err; + + new_rule->parsed_timerec = parsed_timerec; + + LM_DBG("timerecs are %.*s\n", + new_rule->timerec.len, new_rule->timerec.s); + } + if (match_comp) new_rule->match_comp = match_comp; @@ -459,14 +522,12 @@ int add_rule2hash(dpl_node_t * rule, dp_table_list_t *table, int index) /*didn't find a dpl_id*/ if(!crt_idp){ - crt_idp = shm_malloc(sizeof(dpl_id_t) + - (DP_INDEX_HASH_SIZE+1) * sizeof(dpl_index_t)); + crt_idp = shm_malloc(sizeof(dpl_id_t) + (DP_INDEX_HASH_SIZE+1) * sizeof(dpl_index_t)); if(!crt_idp){ LM_ERR("out of shm memory (crt_idp)\n"); return -1; } - memset(crt_idp, 0, sizeof(dpl_id_t) + - (DP_INDEX_HASH_SIZE+1) * sizeof(dpl_index_t)); + memset(crt_idp, 0, sizeof(dpl_id_t) + (DP_INDEX_HASH_SIZE+1) * sizeof(dpl_index_t)); crt_idp->dp_id = rule->dpid; crt_idp->rule_hash = (dpl_index_t*)(crt_idp + 1); new_id = 1; @@ -502,13 +563,12 @@ int add_rule2hash(dpl_node_t * rule, dp_table_list_t *table, int index) indexp->last_rule = rule; if(new_id){ - crt_idp->next = table->hash[table->next_index]; - table->hash[table->next_index] = crt_idp; + crt_idp->next = table->hash[table->next_index]; + table->hash[table->next_index] = crt_idp; } + LM_DBG("added the rule id %i pr %i next %p to the " - " %i bucket\n", rule->dpid, - rule->pr, rule->next, rule->matchop == REGEX_OP? - DP_INDEX_HASH_SIZE : bucket); + " %i bucket\n", rule->dpid, rule->pr, rule->next, rule->matchop == REGEX_OP ? DP_INDEX_HASH_SIZE : bucket); return 0; @@ -583,6 +643,9 @@ void destroy_rule(dpl_node_t * rule){ if(rule->attrs.s) shm_free(rule->attrs.s); + + if(rule->timerec.s) + shm_free(rule->timerec.s); } @@ -636,13 +699,14 @@ void list_hash(dpl_id_t * hash, rw_lock_t * ref_lock) void list_rule(dpl_node_t * rule) { LM_DBG("RULE %p: pr %i next %p match_exp %.*s match_flags %d, " - "subst_exp %.*s, repl_exp %.*s and attrs %.*s\n", rule, + "subst_exp %.*s, repl_exp %.*s, attrs %.*s and timerec %.*s\n", rule, rule->pr, rule->next, - rule->match_exp.len, rule->match_exp.s, + rule->match_exp.len, rule->match_exp.s, rule->match_flags, - rule->subst_exp.len, rule->subst_exp.s, - rule->repl_exp.len, rule->repl_exp.s, - rule->attrs.len, rule->attrs.s); + rule->subst_exp.len, rule->subst_exp.s, + rule->repl_exp.len, rule->repl_exp.s, + rule->attrs.len, rule->attrs.s, + rule->timerec.len, rule->timerec.s); } /* Retrieves the corresponding entry of the given table name */ diff --git a/modules/dialplan/dp_db.h b/modules/dialplan/dp_db.h index 85163454560..d55bbf29714 100644 --- a/modules/dialplan/dp_db.h +++ b/modules/dialplan/dp_db.h @@ -31,18 +31,19 @@ #include "../../db/db.h" #define DP_TABLE_NAME "dialplan" -#define DPID_COL "dpid" -#define PR_COL "pr" +#define DPID_COL "dpid" +#define PR_COL "pr" #define MATCH_OP_COL "match_op" #define MATCH_EXP_COL "match_exp" #define MATCH_FLAGS_COL "match_flags" #define SUBST_EXP_COL "subst_exp" #define REPL_EXP_COL "repl_exp" #define DISABLED_COL "disabled" -#define ATTRS_COL "attrs" +#define ATTRS_COL "attrs" +#define TIMEREC_COL "timerec" #define DP_TABLE_VERSION 4 -#define DP_TABLE_COL_NO 8 +#define DP_TABLE_COL_NO 9 extern str dp_db_url; extern str dp_table_name; @@ -54,6 +55,7 @@ extern str match_flags_column; extern str subst_exp_column; extern str repl_exp_column; extern str attrs_column; +extern str timerec_column; extern str disabled_column; struct dp_param_list; diff --git a/modules/dialplan/dp_repl.c b/modules/dialplan/dp_repl.c index 9bf99f2398d..7e1e9a49c36 100644 --- a/modules/dialplan/dp_repl.c +++ b/modules/dialplan/dp_repl.c @@ -25,6 +25,7 @@ */ #include "../../re.h" +#include "../../time_rec.h" #include "dialplan.h" #define MAX_REPLACE_WITH 10 @@ -275,11 +276,95 @@ int rule_translate(struct sip_msg *msg, str string, dpl_node_t * rule, return -1; } +int timerec_print(tmrec_p _trp) +{ + static char *_wdays[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; + int i; + + if(!_trp) + { + LM_DBG("\n(null)\n"); + return -1; + } + LM_DBG("Recurrence definition\n-- start time ---\n"); + LM_DBG("Sys time: %d\n", (int)_trp->dtstart); + LM_DBG("Time: %02d:%02d:%02d\n", _trp->ts.tm_hour, + _trp->ts.tm_min, _trp->ts.tm_sec); + LM_DBG("Date: %s, %04d-%02d-%02d\n", _wdays[_trp->ts.tm_wday], + _trp->ts.tm_year+1900, _trp->ts.tm_mon+1, _trp->ts.tm_mday); + LM_DBG("---\n"); + LM_DBG("End time: %d\n", (int)_trp->dtend); + LM_DBG("Duration: %d\n", (int)_trp->duration); + LM_DBG("Until: %d\n", (int)_trp->until); + LM_DBG("Freq: %d\n", (int)_trp->freq); + LM_DBG("Interval: %d\n", (int)_trp->interval); + if(_trp->byday) + { + LM_DBG("Byday: "); + for(i=0; i<_trp->byday->nr; i++) + LM_DBG(" %d%s", _trp->byday->req[i], _wdays[_trp->byday->xxx[i]]); + LM_DBG("\n"); + } + if(_trp->bymday) + { + LM_DBG("Bymday: %d:", _trp->bymday->nr); + for(i=0; i<_trp->bymday->nr; i++) + LM_DBG(" %d", _trp->bymday->xxx[i]*_trp->bymday->req[i]); + LM_DBG("\n"); + } + if(_trp->byyday) + { + LM_DBG("Byyday:"); + for(i=0; i<_trp->byyday->nr; i++) + LM_DBG(" %d", _trp->byyday->xxx[i]*_trp->byyday->req[i]); + LM_DBG("\n"); + } + if(_trp->bymonth) + { + LM_DBG("Bymonth: %d:", _trp->bymonth->nr); + for(i=0; i< _trp->bymonth->nr; i++) + LM_DBG(" %d", _trp->bymonth->xxx[i]*_trp->bymonth->req[i]); + LM_DBG("\n"); + } + if(_trp->byweekno) + { + LM_DBG("Byweekno: "); + for(i=0; i<_trp->byweekno->nr; i++) + LM_DBG(" %d", _trp->byweekno->xxx[i]*_trp->byweekno->req[i]); + LM_DBG("\n"); + } + LM_DBG("Weekstart: %d\n", _trp->wkst); + return 0; +} + +// Validate Passed Time Recurrence Instance +static inline int check_time(tmrec_t *time_rec) { + ac_tm_t att; + + // No TimeRec: Rule is Valid + if(time_rec->dtstart == 0) + return 1; + + // Uncomment to enable Debug + // timerec_print(time_rec); + + // Set Current Time + memset(&att, 0, sizeof(att)); + if(ac_tm_set_time(&att, time(0))) + return -1; + + // Check_Tmrec will return 0 on successfully time recurrence match + if(check_tmrec(time_rec, &att, 0) != 0) + return 0; + + // Recurrence Matched -- Validating Rule + return 1; +} + #define DP_MAX_ATTRS_LEN 32 static char dp_attrs_buf[DP_MAX_ATTRS_LEN+1]; -int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, - str * attrs) -{ +int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, str * attrs) { + dpl_node_p rulep, rrulep; int string_res = -1, regexp_res = -1, bucket; @@ -298,9 +383,19 @@ int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, if(rulep->match_exp.len != input.len) continue; - LM_DBG("Comparing (input %.*s) with (rule %.*s) [%d]\n", + LM_DBG("Comparing (input %.*s) with (rule %.*s) [%d] and timerec %.*s\n", input.len, input.s, rulep->match_exp.len, rulep->match_exp.s, - rulep->match_flags); + rulep->match_flags, rulep->timerec.len, rulep->timerec.s); + + // Check for Time Period if Set + if(rulep->parsed_timerec) { + LM_DBG("Timerec exists for rule checking: %.*s\n", rulep->timerec.len, rulep->timerec.s); + // Doesn't matches time period continue with next rule + if(!check_time(rulep->parsed_timerec)) { + LM_DBG("Time rule doesn't match: skip next!\n"); + continue; + } + } if (rulep->match_flags & DP_CASE_INSENSITIVE) { string_res = strncasecmp(rulep->match_exp.s,input.s,input.len); @@ -314,9 +409,18 @@ int translate(struct sip_msg *msg, str input, str * output, dpl_id_p idp, } /* try to match the input in the regexp bucket */ - for (rrulep = idp->rule_hash[DP_INDEX_HASH_SIZE].first_rule; - rrulep; rrulep=rrulep->next) { - + for (rrulep = idp->rule_hash[DP_INDEX_HASH_SIZE].first_rule; rrulep; rrulep=rrulep->next) { + + // Check for Time Period if Set + if(rrulep->parsed_timerec) { + LM_DBG("Timerec exists for rule checking: %.*s\n", rrulep->timerec.len, rrulep->timerec.s); + // Doesn't matches time period continue with next rule + if(!check_time(rrulep->parsed_timerec)) { + LM_DBG("Time rule doesn't match: skip next!\n"); + continue; + } + } + regexp_res = (test_match(input, rrulep->match_comp, matches, MAX_MATCHES) >= 0 ? 0 : -1);