From 7a238fe74d19c6d0ff663940acd6f3caea7dad0f Mon Sep 17 00:00:00 2001
From: Richard Mudgett <rmudgett@digium.com>
Date: Thu, 28 Jun 2018 12:07:01 -0500
Subject: [PATCH] AMI SendText action: Fix to use correct thread to send the
 text.

The AMI action was directly sending the text to the channel driver.
However, this makes two threads attempt to handle media and runs afowl of
CHECK_BLOCKING.

* Queue a read action to make the channel's media handling thread actually
send the text message.  This changes the AMI actions success/fail response
to just mean the text was queued to be sent not that the text actually got
sent.  The channel driver may not even support sending text messages.

ASTERISK-27943

Change-Id: I9dce343d8fa634ba5a416a1326d8a6340f98c379
---
 include/asterisk/frame.h |  1 +
 main/channel.c           |  5 +++++
 main/manager.c           | 29 ++++++++++++++++++++++++-----
 3 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 542407ecc9..b618d1965f 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -337,6 +337,7 @@ enum ast_control_frame_type {
 
 enum ast_frame_read_action {
 	AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO,
+	AST_FRAME_READ_ACTION_SEND_TEXT,
 };
 
 struct ast_control_read_action_payload {
diff --git a/main/channel.c b/main/channel.c
index dcb284b631..c0e3cb43ec 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3773,6 +3773,11 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
 					ast_party_connected_line_free(&connected);
 					ast_channel_lock(chan);
 					break;
+				case AST_FRAME_READ_ACTION_SEND_TEXT:
+					ast_channel_unlock(chan);
+					ast_sendtext(chan, (const char *) read_action_payload->payload);
+					ast_channel_lock(chan);
+					break;
 				}
 				ast_frfree(f);
 				f = &ast_null_frame;
diff --git a/main/manager.c b/main/manager.c
index ec50cb82cc..ab42432446 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -4745,10 +4745,13 @@ static int action_status(struct mansession *s, const struct message *m)
 
 static int action_sendtext(struct mansession *s, const struct message *m)
 {
-	struct ast_channel *c = NULL;
+	struct ast_channel *c;
 	const char *name = astman_get_header(m, "Channel");
 	const char *textmsg = astman_get_header(m, "Message");
-	int res = 0;
+	struct ast_control_read_action_payload *frame_payload;
+	int payload_size;
+	int frame_size;
+	int res;
 
 	if (ast_strlen_zero(name)) {
 		astman_send_error(s, m, "No channel specified");
@@ -4760,13 +4763,29 @@ static int action_sendtext(struct mansession *s, const struct message *m)
 		return 0;
 	}
 
-	if (!(c = ast_channel_get_by_name(name))) {
+	c = ast_channel_get_by_name(name);
+	if (!c) {
 		astman_send_error(s, m, "No such channel");
 		return 0;
 	}
 
-	res = ast_sendtext(c, textmsg);
-	c = ast_channel_unref(c);
+	payload_size = strlen(textmsg) + 1;
+	frame_size = payload_size + sizeof(*frame_payload);
+
+	frame_payload = ast_malloc(frame_size);
+	if (!frame_payload) {
+		ast_channel_unref(c);
+		astman_send_error(s, m, "Failure");
+		return 0;
+	}
+
+	frame_payload->action = AST_FRAME_READ_ACTION_SEND_TEXT;
+	frame_payload->payload_size = payload_size;
+	memcpy(frame_payload->payload, textmsg, payload_size);
+	res = ast_queue_control_data(c, AST_CONTROL_READ_ACTION, frame_payload, frame_size);
+
+	ast_free(frame_payload);
+	ast_channel_unref(c);
 
 	if (res >= 0) {
 		astman_send_ack(s, m, "Success");
-- 
GitLab