From 9b7b46dbca9c4c458121dc80c3eeedf8e5ec9643 Mon Sep 17 00:00:00 2001 From: Anthony Minessale <anthm@freeswitch.org> Date: Fri, 14 Dec 2012 00:29:15 -0600 Subject: [PATCH] FS-4935 add nested condition support to XML dialplan --- .../mod_dialplan_xml/mod_dialplan_xml.c | 107 ++++++++++++++---- 1 file changed, 83 insertions(+), 24 deletions(-) diff --git a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c index ac1500c4f5..c0fe707fd0 100644 --- a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c +++ b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c @@ -79,6 +79,9 @@ static switch_status_t exec_app(switch_core_session_t *session, const char *app, return status; } +#define MAX_RECUR 100 +#define RECUR_SPACE 4 +#define MAX_RECUR_SPACE 100 * RECUR_SPACE #define check_tz() tzoff = switch_channel_get_variable(channel, "tod_tz_offset"); \ tzname = switch_channel_get_variable(channel, "timezone"); \ @@ -91,24 +94,70 @@ static switch_status_t exec_app(switch_core_session_t *session, const char *app, break; \ } while(tzoff) -static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *caller_profile, switch_xml_t xexten, switch_caller_extension_t **extension) +static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *caller_profile, switch_xml_t xexten, + switch_caller_extension_t **extension, const char *exten_name, int recur) { switch_xml_t xcond, xaction, xexpression, xregex; switch_channel_t *channel = switch_core_session_get_channel(session); - char *exten_name = (char *) switch_xml_attr(xexten, "name"); int proceed = 0, save_proceed = 0; char *expression_expanded = NULL, *field_expanded = NULL; switch_regex_t *re = NULL, *save_re = NULL; int offset = 0; - const char *tzoff = NULL, *tzname = NULL; + const char *tmp, *tzoff = NULL, *tzname = NULL, *req_nesta = NULL; + char nbuf[128] = ""; + int req_nest = 1; + char space[MAX_RECUR_SPACE] = ""; + const char *orig_exten_name = exten_name; check_tz(); - if (!exten_name) { exten_name = "_anon_"; } + if (!orig_exten_name) { + orig_exten_name = "_anon_"; + } + + + if (recur) { + int i, j = 0, k = 0; + + if (recur > MAX_RECUR) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Recursion LIMIT!\n"); + return 0; + } + + switch_snprintf(nbuf, sizeof(nbuf), "%s_recur_%d", exten_name, recur); + exten_name = nbuf; + + space[j++] = '|'; + + for (i = 0; i < recur; i++) { + for (k = 0; k < RECUR_SPACE; k++) { + if (i == recur-1 && k == RECUR_SPACE-1) { + space[j++] = ' '; + } else { + space[j++] = '-'; + } + } + } + + if ((req_nesta = switch_xml_attr(xexten, "require-nested"))) { + req_nest = switch_true(req_nesta); + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, + "%sDialplan: Processing recursive conditions level:%d [%s] require-nested=%s\n", space, + recur, exten_name, req_nest ? "TRUE" : "FALSE"); + + } else { + if ((tmp = switch_xml_attr(xexten, "name"))) { + exten_name = tmp; + } + } + + for (xcond = switch_xml_child(xexten, "condition"); xcond; xcond = xcond->next) { char *field = NULL; char *do_break_a = NULL; @@ -123,16 +172,9 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * check_tz(); time_match = switch_xml_std_datetime_check(xcond, tzoff ? &offset : NULL, tzname); - switch_safe_free(field_expanded); switch_safe_free(expression_expanded); - if (switch_xml_child(xcond, "condition")) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Nested conditions are not allowed!\n"); - proceed = 1; - goto done; - } - field = (char *) switch_xml_attr(xcond, "field"); @@ -150,15 +192,25 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } } + + if (switch_xml_child(xcond, "condition")) { + if (!(proceed = parse_exten(session, caller_profile, xcond, extension, orig_exten_name, recur + 1))) { + if (do_break_i == BREAK_NEVER) { + continue; + } + goto done; + } + } + if (time_match == 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Date/Time Match (PASS) [%s] break=%s\n", + "%sDialplan: %s Date/Time Match (PASS) [%s] break=%s\n", space, switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); anti_action = SWITCH_FALSE; proceed = 1; } else if (time_match == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Date/TimeMatch (FAIL) [%s] break=%s\n", + "%sDialplan: %s Date/TimeMatch (FAIL) [%s] break=%s\n", space, switch_channel_get_name(channel), exten_name, do_break_a ? do_break_a : "on-false"); } @@ -178,12 +230,12 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * if (time_match == 1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Date/Time Match (PASS) [%s]\n", + "%sDialplan: %s Date/Time Match (PASS) [%s]\n", space, switch_channel_get_name(channel), exten_name); anti_action = SWITCH_FALSE; } else if (time_match == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Date/TimeMatch (FAIL) [%s]\n", + "%sDialplan: %s Date/TimeMatch (FAIL) [%s]\n", space, switch_channel_get_name(channel), exten_name); } @@ -221,20 +273,21 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ match=%s\n", + "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ match=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); pass++; if (!all && !xor) break; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ match=%s\n", + "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ match=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, all ? "all" : "any"); fail++; if (all && !xor) break; } } else if (time_match == -1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Absolute Condition [%s] match=%s\n", switch_channel_get_name(channel), exten_name, all ? "all" : "any"); + "%sDialplan: %s Absolute Condition [%s] match=%s\n", space, + switch_channel_get_name(channel), exten_name, all ? "all" : "any"); pass++; proceed = 1; if (!all && !xor) break; @@ -314,17 +367,18 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n", + "%sDialplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); anti_action = SWITCH_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n", + "%sDialplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n", space, switch_channel_get_name(channel), exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false"); } } else if (time_match == -1) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Absolute Condition [%s]\n", switch_channel_get_name(channel), exten_name); + "%sDialplan: %s Absolute Condition [%s]\n", space, + switch_channel_get_name(channel), exten_name); anti_action = SWITCH_FALSE; proceed = 1; } @@ -373,7 +427,8 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * for (;loop_count > 0; loop_count--) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s ANTI-Action %s(%s) %s\n", switch_channel_get_name(channel), application, data, xinline ? "INLINE" : ""); + "%sDialplan: %s ANTI-Action %s(%s) %s\n", space, + switch_channel_get_name(channel), application, data, xinline ? "INLINE" : ""); if (xinline) { exec_app(session, application, data); @@ -433,7 +488,8 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * } for (;loop_count > 0; loop_count--) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, - "Dialplan: %s Action %s(%s) %s\n", switch_channel_get_name(channel), application, app_data, xinline ? "INLINE" : ""); + "%sDialplan: %s Action %s(%s) %s\n", space, + switch_channel_get_name(channel), application, app_data, xinline ? "INLINE" : ""); if (xinline) { exec_app(session, application, app_data); @@ -456,6 +512,9 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * switch_regex_safe_free(re); switch_safe_free(field_expanded); switch_safe_free(expression_expanded); + + if (!req_nest) proceed = 1; + return proceed; } @@ -551,7 +610,7 @@ SWITCH_STANDARD_DIALPLAN(dialplan_hunt) "Dialplan: %s parsing [%s->%s] continue=%s\n", switch_channel_get_name(channel), caller_profile->context, exten_name, cont ? cont : "false"); - proceed = parse_exten(session, caller_profile, xexten, &extension); + proceed = parse_exten(session, caller_profile, xexten, &extension, exten_name, 0); if (proceed && !switch_true(cont)) { break;