diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index 955f80ae33..b5f7f5ff8e 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -7896,6 +7896,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
switch_console_set_complete("add uuid_flush_dtmf ::console::list_uuid");
switch_console_set_complete("add uuid_getvar ::console::list_uuid");
switch_console_set_complete("add uuid_hold ::console::list_uuid");
+ switch_console_set_complete("add uuid_hold off ::console::list_uuid");
+ switch_console_set_complete("add uuid_hold toggle ::console::list_uuid");
switch_console_set_complete("add uuid_send_info ::console::list_uuid");
switch_console_set_complete("add uuid_jitterbuffer ::console::list_uuid");
switch_console_set_complete("add uuid_kill ::console::list_uuid");
diff --git a/src/switch_ivr.c b/src/switch_ivr.c
index 4f9d2d0cbd..ddd3a8e529 100644
--- a/src/switch_ivr.c
+++ b/src/switch_ivr.c
@@ -1530,6 +1530,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_hold(switch_core_session_t *session,
const char *other_uuid;
switch_event_t *event;
+ if (channel) {
+ switch_channel_callstate_t callstate;
+
+ callstate = switch_channel_get_callstate(channel);
+ if (callstate == CCS_HELD) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Call is already on hold. No need to hold again.\n");
+ return SWITCH_STATUS_FALSE;
+ }
+ }
+
msg.message_id = SWITCH_MESSAGE_INDICATE_HOLD;
msg.string_arg = message;
msg.from = __FILE__;
@@ -1557,13 +1567,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_hold(switch_core_session_t *session,
SWITCH_DECLARE(switch_status_t) switch_ivr_hold_uuid(const char *uuid, const char *message, switch_bool_t moh)
{
switch_core_session_t *session;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
if ((session = switch_core_session_locate(uuid))) {
- switch_ivr_hold(session, message, moh);
+ status = switch_ivr_hold(session, message, moh);
switch_core_session_rwunlock(session);
}
- return SWITCH_STATUS_SUCCESS;
+ return status;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_hold_toggle_uuid(const char *uuid, const char *message, switch_bool_t moh)
@@ -1571,21 +1582,22 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_hold_toggle_uuid(const char *uuid, co
switch_core_session_t *session;
switch_channel_t *channel;
switch_channel_callstate_t callstate;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
if ((session = switch_core_session_locate(uuid))) {
if ((channel = switch_core_session_get_channel(session))) {
callstate = switch_channel_get_callstate(channel);
- if (callstate == CCS_ACTIVE) {
- switch_ivr_hold(session, message, moh);
+ if (callstate == CCS_ACTIVE || callstate == CCS_UNHELD) {
+ status = switch_ivr_hold(session, message, moh);
} else if (callstate == CCS_HELD) {
- switch_ivr_unhold(session);
+ status = switch_ivr_unhold(session);
}
}
switch_core_session_rwunlock(session);
}
- return SWITCH_STATUS_SUCCESS;
+ return status;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session)
@@ -1596,6 +1608,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session
switch_core_session_t *b_session;
switch_event_t *event;
+ if (channel) {
+ switch_channel_callstate_t callstate;
+
+ callstate = switch_channel_get_callstate(channel);
+ if (callstate != CCS_HELD) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Call is not on hold. No need to unhold.\n");
+ return SWITCH_STATUS_FALSE;
+ }
+ }
+
msg.message_id = SWITCH_MESSAGE_INDICATE_UNHOLD;
msg.from = __FILE__;
@@ -1624,13 +1646,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session
SWITCH_DECLARE(switch_status_t) switch_ivr_unhold_uuid(const char *uuid)
{
switch_core_session_t *session;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
if ((session = switch_core_session_locate(uuid))) {
- switch_ivr_unhold(session);
+ status = switch_ivr_unhold(session);
switch_core_session_rwunlock(session);
}
- return SWITCH_STATUS_SUCCESS;
+ return status;
}
diff --git a/tests/unit/.gitignore b/tests/unit/.gitignore
index 66ea66aa06..4c7b7466c4 100644
--- a/tests/unit/.gitignore
+++ b/tests/unit/.gitignore
@@ -22,6 +22,7 @@ switch_core_video
switch_eavesdrop
switch_event
switch_hash
+switch_hold
switch_ivr_async
switch_ivr_originate
switch_ivr_play_say
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index ee2e92b175..3f41d71dda 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -4,6 +4,7 @@ noinst_PROGRAMS = switch_event switch_hash switch_ivr_originate switch_utils swi
switch_ivr_play_say switch_core_codec switch_rtp switch_xml
noinst_PROGRAMS += switch_core_video switch_core_db switch_vad switch_packetizer switch_core_session test_sofia switch_ivr_async switch_core_asr switch_log
+noinst_PROGRAMS+= switch_hold
AM_LDFLAGS += -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS) $(openssl_LIBS)
AM_LDFLAGS += $(FREESWITCH_LIBS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS)
diff --git a/tests/unit/conf_hold/freeswitch.xml b/tests/unit/conf_hold/freeswitch.xml
new file mode 100644
index 0000000000..883e3846e1
--- /dev/null
+++ b/tests/unit/conf_hold/freeswitch.xml
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/unit/conf_hold/gw/holdtest.xml b/tests/unit/conf_hold/gw/holdtest.xml
new file mode 100644
index 0000000000..d919ddb2d4
--- /dev/null
+++ b/tests/unit/conf_hold/gw/holdtest.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/unit/switch_hold.c b/tests/unit/switch_hold.c
new file mode 100644
index 0000000000..9da8ccfc94
--- /dev/null
+++ b/tests/unit/switch_hold.c
@@ -0,0 +1,105 @@
+#include
+#include
+
+FST_CORE_DB_BEGIN("./conf_hold")
+{
+FST_SUITE_BEGIN(switch_hold)
+{
+ FST_SETUP_BEGIN()
+ {
+ fst_requires_module("mod_sofia");
+ fst_requires_module("mod_commands");
+ }
+ FST_SETUP_END()
+
+ FST_TEARDOWN_BEGIN()
+ {
+ }
+ FST_TEARDOWN_END()
+
+ FST_TEST_BEGIN(hold_unhold_restriction)
+ {
+ switch_core_session_t *session = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+
+ status = switch_ivr_originate(NULL, &session, &cause, "{ignore_early_media=true}sofia/gateway/hold_unhold_test/+15553332900", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+
+ if (session) {
+ const char *uuid = switch_core_session_get_uuid(session);
+ switch_channel_t *channel = NULL;
+
+ channel = switch_core_session_get_channel(session);
+ fst_requires(channel);
+
+ if (uuid) {
+ char *off_uuid = switch_mprintf("off %s", uuid);
+ char *toggle_uuid = switch_mprintf("toggle %s", uuid);
+
+ switch_stream_handle_t stream = { 0 };
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "firing the api.\n");
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("uuid_hold", off_uuid, NULL, &stream);
+ fst_check_string_equals(stream.data, "-ERR Operation failed\n");
+ switch_safe_free(stream.data);
+ switch_sleep(200000);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("uuid_hold", uuid, NULL, &stream);
+ fst_check_string_equals(stream.data, "+OK Success\n");
+ switch_safe_free(stream.data);
+ switch_sleep(200000);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("uuid_hold", uuid, NULL, &stream);
+ fst_check_string_equals(stream.data, "-ERR Operation failed\n");
+ switch_safe_free(stream.data);
+ switch_sleep(200000);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("uuid_hold", uuid, NULL, &stream);
+ fst_check_string_equals(stream.data, "-ERR Operation failed\n");
+ switch_safe_free(stream.data);
+ switch_sleep(200000);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("uuid_hold", toggle_uuid, NULL, &stream);
+ fst_check_string_equals(stream.data, "+OK Success\n");
+ switch_safe_free(stream.data);
+ switch_sleep(200000);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("uuid_hold", off_uuid, NULL, &stream);
+ fst_check_string_equals(stream.data, "-ERR Operation failed\n");
+ switch_safe_free(stream.data);
+ switch_sleep(200000);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("uuid_hold", toggle_uuid, NULL, &stream);
+ fst_check_string_equals(stream.data, "+OK Success\n");
+ switch_safe_free(stream.data);
+ switch_sleep(200000);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("uuid_hold", uuid, NULL, &stream);
+ fst_check_string_equals(stream.data, "-ERR Operation failed\n");
+ switch_safe_free(stream.data);
+ switch_sleep(200000);
+
+ switch_safe_free(off_uuid);
+ switch_safe_free(toggle_uuid);
+ }
+
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ }
+ }
+ FST_TEST_END()
+}
+FST_SUITE_END()
+}
+FST_CORE_END()
+