From 6cdb46889cdbc282f15ce95be16fa997871e32b1 Mon Sep 17 00:00:00 2001
From: Anthony Minessale <anthm@freeswitch.org>
Date: Wed, 22 May 2013 11:01:39 -0500
Subject: [PATCH] FS-5402 --resolve the problem is ent originate has many
 channels and many causes to parse so we need to check it against all the
 causes

---
 src/include/switch_channel.h                  |   2 +-
 .../applications/mod_dptools/mod_dptools.c    | 131 +---------------
 src/switch_channel.c                          | 142 ++++++++++++++++++
 src/switch_ivr_originate.c                    |  25 ++-
 4 files changed, 165 insertions(+), 135 deletions(-)

diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h
index f7ace52676..219663b0e0 100644
--- a/src/include/switch_channel.h
+++ b/src/include/switch_channel.h
@@ -658,7 +658,7 @@ SWITCH_DECLARE(switch_hold_record_t *) switch_channel_get_hold_record(switch_cha
 SWITCH_DECLARE(void) switch_channel_state_thread_lock(switch_channel_t *channel);
 SWITCH_DECLARE(void) switch_channel_state_thread_unlock(switch_channel_t *channel);
 SWITCH_DECLARE(switch_status_t) switch_channel_state_thread_trylock(switch_channel_t *channel);
-
+SWITCH_DECLARE(void) switch_channel_handle_cause(switch_channel_t *channel, switch_call_cause_t cause);
 
 SWITCH_END_EXTERN_C
 #endif
diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c
index 5818bd0752..52c94633bf 100755
--- a/src/mod/applications/mod_dptools/mod_dptools.c
+++ b/src/mod/applications/mod_dptools/mod_dptools.c
@@ -2933,11 +2933,6 @@ SWITCH_STANDARD_APP(audio_bridge_function)
 {
 	switch_channel_t *caller_channel = switch_core_session_get_channel(session);
 	switch_core_session_t *peer_session = NULL;
-	
-	const char *transfer_on_fail = NULL;
-	char *tof_data = NULL;
-	char *tof_array[4] = { 0 };
-	//int tof_arrayc = 0;
 	const char *v_campon = NULL, *v_campon_retries, *v_campon_sleep, *v_campon_timeout, *v_campon_fallback_exten = NULL;
 	switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
 	int campon_retries = 100, campon_timeout = 10, campon_sleep = 10, tmp, camping = 0, fail = 0, thread_started = 0;
@@ -2953,11 +2948,6 @@ SWITCH_STANDARD_APP(audio_bridge_function)
 		return;
 	}
 
-	transfer_on_fail = switch_channel_get_variable(caller_channel, "transfer_on_fail");
-	tof_data = switch_core_session_strdup(session, transfer_on_fail);
-	switch_split(tof_data, ' ', tof_array);
-   	transfer_on_fail = tof_array[0];
-	
 	if ((v_campon = switch_channel_get_variable(caller_channel, "campon")) && switch_true(v_campon)) {
 		const char *cid_name = NULL;
 		const char *cid_number = NULL;
@@ -3105,126 +3095,7 @@ SWITCH_STANDARD_APP(audio_bridge_function)
 	if (fail) {
 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Originate Failed.  Cause: %s\n", switch_channel_cause2str(cause));
 
-		/* 
-		   if the variable continue_on_fail is set it can be:
-		   'true' to continue on all failures.
-		   'false' to not continue.
-		   A list of codes either names or numbers eg "user_busy,normal_temporary_failure,603"
-		   failure_causes acts as the opposite version  
-		   EXCEPTION... ATTENDED_TRANSFER never is a reason to continue.......
-		 */
-		if (cause != SWITCH_CAUSE_ATTENDED_TRANSFER) {
-			const char *continue_on_fail = NULL, *failure_causes = NULL;
-
-			continue_on_fail = switch_channel_get_variable(caller_channel, "continue_on_fail");
-			failure_causes = switch_channel_get_variable(caller_channel, "failure_causes");
-
-			if (continue_on_fail || failure_causes) {
-				const char *cause_str;
-				char cause_num[35] = "";
-
-				cause_str = switch_channel_cause2str(cause);
-				switch_snprintf(cause_num, sizeof(cause_num), "%u", cause);
-
-				if (failure_causes) {
-					char *lbuf = switch_core_session_strdup(session, failure_causes);
-					char *argv[256] = { 0 };
-					int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
-					int i, x = 0;
-
-					for (i = 0; i < argc; i++) {
-						if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
-							x++;
-							break;
-						}
-					}
-					if (!x) {
-						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
-										  "Failure causes [%s]:  Cause: %s\n", failure_causes, cause_str);
-						return;
-					}
-				}
-
-				if (continue_on_fail) {
-					if (switch_true(continue_on_fail)) {
-						return;
-					} else {
-						char *lbuf = switch_core_session_strdup(session, continue_on_fail);
-						char *argv[256] = { 0 };
-						int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
-						int i;
-
-						for (i = 0; i < argc; i++) {
-							if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
-								switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
-												  "Continue on fail [%s]:  Cause: %s\n", continue_on_fail, cause_str);
-								return;
-							}
-						}
-					}
-				}
-			} else {
-				/* no answer is *always* a reason to continue */
-				if (cause == SWITCH_CAUSE_NO_ANSWER || cause == SWITCH_CAUSE_NO_USER_RESPONSE || cause == SWITCH_CAUSE_ORIGINATOR_CANCEL) {
-					return;
-				}
-			}
-			
-			if (transfer_on_fail || failure_causes) {
-				const char *cause_str;
-				char cause_num[35] = "";
-
-				cause_str = switch_channel_cause2str(cause);
-				switch_snprintf(cause_num, sizeof(cause_num), "%u", cause);
-
-				if ((tof_array[1] == NULL ) || (!strcasecmp(tof_array[1], "auto_cause"))){
-					tof_array[1] = (char *) cause_str;
-				}
-
-				if (failure_causes) {
-					char *lbuf = switch_core_session_strdup(session, failure_causes);
-					char *argv[256] = { 0 };
-					int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
-					int i, x = 0;
-
-					for (i = 0; i < argc; i++) {
-						if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
-							x++;
-							break;
-						}
-					}
-					if (!x) {
-						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
-										  "Failure causes [%s]:  Cause: %s\n", failure_causes, cause_str);
-										  
-						switch_ivr_session_transfer(session, tof_array[1], tof_array[2], tof_array[3]);
-					}
-				}
-
-				if (transfer_on_fail) {
-					if (switch_true(transfer_on_fail)) {
-						return;
-					} else {
-						char *lbuf = switch_core_session_strdup(session, transfer_on_fail);
-						char *argv[256] = { 0 };
-						int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
-						int i;
-
-						for (i = 0; i < argc; i++) {
-							if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
-								switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
-												  "Transfer on fail [%s]:  Cause: %s\n", transfer_on_fail, cause_str);
-								switch_ivr_session_transfer(session, tof_array[1], tof_array[2], tof_array[3]);
-							}
-						}
-					}
-				}
-			} 
-		}
-		if (!switch_channel_test_flag(caller_channel, CF_TRANSFER) && !switch_channel_test_flag(caller_channel, CF_CONFIRM_BLIND_TRANSFER) && 
-			switch_channel_get_state(caller_channel) != CS_ROUTING) {
-			switch_channel_hangup(caller_channel, cause);
-		}
+		switch_channel_handle_cause(caller_channel, cause);
 		return;
 	} else {
 
diff --git a/src/switch_channel.c b/src/switch_channel.c
index 2295153b0f..fb3175abad 100644
--- a/src/switch_channel.c
+++ b/src/switch_channel.c
@@ -4401,6 +4401,148 @@ SWITCH_DECLARE(const char *) switch_channel_get_partner_uuid(switch_channel_t *c
 	return uuid;
 }
 
+SWITCH_DECLARE(void) switch_channel_handle_cause(switch_channel_t *channel, switch_call_cause_t cause)
+{
+	switch_core_session_t *session = channel->session;
+	const char *transfer_on_fail = NULL;
+	char *tof_data = NULL;
+	char *tof_array[4] = { 0 };
+	//int tof_arrayc = 0;
+
+	if (!switch_channel_up_nosig(channel)) {
+		return;
+	}
+
+	transfer_on_fail = switch_channel_get_variable(channel, "transfer_on_fail");
+	tof_data = switch_core_session_strdup(session, transfer_on_fail);
+	switch_split(tof_data, ' ', tof_array);
+   	transfer_on_fail = tof_array[0];
+
+	/* 
+	   if the variable continue_on_fail is set it can be:
+	   'true' to continue on all failures.
+	   'false' to not continue.
+	   A list of codes either names or numbers eg "user_busy,normal_temporary_failure,603"
+	   failure_causes acts as the opposite version  
+	   EXCEPTION... ATTENDED_TRANSFER never is a reason to continue.......
+	*/
+	if (cause != SWITCH_CAUSE_ATTENDED_TRANSFER) {
+		const char *continue_on_fail = NULL, *failure_causes = NULL;
+
+		continue_on_fail = switch_channel_get_variable(channel, "continue_on_fail");
+		failure_causes = switch_channel_get_variable(channel, "failure_causes");
+
+		if (continue_on_fail || failure_causes) {
+			const char *cause_str;
+			char cause_num[35] = "";
+
+			cause_str = switch_channel_cause2str(cause);
+			switch_snprintf(cause_num, sizeof(cause_num), "%u", cause);
+
+			if (failure_causes) {
+				char *lbuf = switch_core_session_strdup(session, failure_causes);
+				char *argv[256] = { 0 };
+				int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
+				int i, x = 0;
+
+				for (i = 0; i < argc; i++) {
+					if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
+						x++;
+						break;
+					}
+				}
+				if (!x) {
+					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+									  "Failure causes [%s]:  Cause: %s\n", failure_causes, cause_str);
+					return;
+				}
+			}
+
+			if (continue_on_fail) {
+				if (switch_true(continue_on_fail)) {
+					return;
+				} else {
+					char *lbuf = switch_core_session_strdup(session, continue_on_fail);
+					char *argv[256] = { 0 };
+					int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
+					int i;
+
+					for (i = 0; i < argc; i++) {
+						if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
+							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+											  "Continue on fail [%s]:  Cause: %s\n", continue_on_fail, cause_str);
+							return;
+						}
+					}
+				}
+			}
+		} else {
+			/* no answer is *always* a reason to continue */
+			if (cause == SWITCH_CAUSE_NO_ANSWER || cause == SWITCH_CAUSE_NO_USER_RESPONSE || cause == SWITCH_CAUSE_ORIGINATOR_CANCEL) {
+				return;
+			}
+		}
+			
+		if (transfer_on_fail || failure_causes) {
+			const char *cause_str;
+			char cause_num[35] = "";
+
+			cause_str = switch_channel_cause2str(cause);
+			switch_snprintf(cause_num, sizeof(cause_num), "%u", cause);
+
+			if ((tof_array[1] == NULL ) || (!strcasecmp(tof_array[1], "auto_cause"))){
+				tof_array[1] = (char *) cause_str;
+			}
+
+			if (failure_causes) {
+				char *lbuf = switch_core_session_strdup(session, failure_causes);
+				char *argv[256] = { 0 };
+				int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
+				int i, x = 0;
+
+				for (i = 0; i < argc; i++) {
+					if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
+						x++;
+						break;
+					}
+				}
+				if (!x) {
+					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+									  "Failure causes [%s]:  Cause: %s\n", failure_causes, cause_str);
+										  
+					switch_ivr_session_transfer(session, tof_array[1], tof_array[2], tof_array[3]);
+				}
+			}
+
+			if (transfer_on_fail) {
+				if (switch_true(transfer_on_fail)) {
+					return;
+				} else {
+					char *lbuf = switch_core_session_strdup(session, transfer_on_fail);
+					char *argv[256] = { 0 };
+					int argc = switch_separate_string(lbuf, ',', argv, (sizeof(argv) / sizeof(argv[0])));
+					int i;
+
+					for (i = 0; i < argc; i++) {
+						if (!strcasecmp(argv[i], cause_str) || !strcasecmp(argv[i], cause_num)) {
+							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+											  "Transfer on fail [%s]:  Cause: %s\n", transfer_on_fail, cause_str);
+							switch_ivr_session_transfer(session, tof_array[1], tof_array[2], tof_array[3]);
+						}
+					}
+				}
+			}
+		} 
+	}
+
+
+	if (!switch_channel_test_flag(channel, CF_TRANSFER) && !switch_channel_test_flag(channel, CF_CONFIRM_BLIND_TRANSFER) && 
+		switch_channel_get_state(channel) != CS_ROUTING) {
+		switch_channel_hangup(channel, cause);
+	}
+}
+
+
 /* For Emacs:
  * Local Variables:
  * mode:c
diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c
index 13896f7b13..d1b5874795 100644
--- a/src/switch_ivr_originate.c
+++ b/src/switch_ivr_originate.c
@@ -1644,6 +1644,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
 	}
 
 	for (i = 0; i < x_argc; i++) {
+
+		if (channel) {
+			switch_channel_handle_cause(channel, handles[i].cause);
+		}
+
 		if (hp == &handles[i]) {
 			continue;
 		}
@@ -1861,6 +1866,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 	const char *ringback_data = NULL;
 	switch_event_t *var_event = NULL;
 	int8_t fail_on_single_reject = 0;
+	int8_t hangup_on_single_reject = 0;
 	char *fail_on_single_reject_var = NULL;
 	char *loop_data = NULL;
 	uint32_t progress_timelimit_sec = 0;
@@ -2119,6 +2125,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 					ok = 1;
 				} else if (!strcasecmp((char *) hi->name, "fail_on_single_reject")) {
 					ok = 1;
+				} else if (!strcasecmp((char *) hi->name, "hangup_on_single_reject")) {
+					ok = 1;
 				} else if (!strcasecmp((char *) hi->name, "ignore_early_media")) {
 					ok = 1;
 				} else if (!strcasecmp((char *) hi->name, "bridge_early_media")) {
@@ -2216,7 +2224,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 	   If the value is set to 'true' any fail cause will end the attempt otherwise it can contain a comma (,) separated
 	   list of cause names which should be considered fatal
 	 */
-	if ((var = switch_event_get_header(var_event, "fail_on_single_reject"))) {
+	if ((var = switch_event_get_header(var_event, "hangup_on_single_reject"))) {
+		hangup_on_single_reject = 1;
+	}
+
+	if (hangup_on_single_reject || (var = switch_event_get_header(var_event, "fail_on_single_reject"))) {
 		fail_on_single_reject_var = strdup(var);
 		if (switch_true(var)) {
 			fail_on_single_reject = 1;
@@ -3807,6 +3819,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 	switch_safe_free(write_frame.data);
 	switch_safe_free(fail_on_single_reject_var);
 
+	if (force_reason != SWITCH_CAUSE_NONE) {
+		*cause = force_reason;
+	}
+
 	if (caller_channel) {
 
 		switch_channel_execute_on(caller_channel, SWITCH_CHANNEL_EXECUTE_ON_POST_ORIGINATE_VARIABLE);
@@ -3814,11 +3830,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 
 		switch_channel_clear_flag(caller_channel, CF_ORIGINATOR);
 		switch_channel_clear_flag(caller_channel, CF_XFER_ZOMBIE);
+
+		if (hangup_on_single_reject) {
+			switch_channel_hangup(caller_channel, *cause);
+		}
 	}
 
-	if (force_reason != SWITCH_CAUSE_NONE) {
-		*cause = force_reason;
-	}
 
 	switch_core_destroy_memory_pool(&oglobals.pool);