mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-11-04 05:15:22 +00:00 
			
		
		
		
	manager - Add Content-Type parameter to the SendText action
This patch allows a user of AMI to now specify the type of message content contained within by setting the 'Content-Type' parameter. Note, the AMI version has been bumped for this change. ASTERISK-28945 #close Change-Id: Ibb5315702532c6b954e1498beddc8855fabdf4bb
This commit is contained in:
		
				
					committed by
					
						
						Friendly Automation
					
				
			
			
				
	
			
			
			
						parent
						
							8d1064eaaf
						
					
				
				
					commit
					cfed0ea033
				
			
							
								
								
									
										4
									
								
								doc/CHANGES-staging/ami_sendtext_content_type.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								doc/CHANGES-staging/ami_sendtext_content_type.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					Subject: AMI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can now specify an optional 'Content-Type' as an argument for the Asterisk
 | 
				
			||||||
 | 
					SendText manager action.
 | 
				
			||||||
@@ -335,9 +335,16 @@ enum ast_control_frame_type {
 | 
				
			|||||||
	AST_CONTROL_RECORD_MUTE = 1103,	/*!< Indicated to a channel in record to mute/unmute (i.e. write silence) recording */
 | 
						AST_CONTROL_RECORD_MUTE = 1103,	/*!< Indicated to a channel in record to mute/unmute (i.e. write silence) recording */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
					 * \brief Actions to indicate to, and be handled on channel read
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The subtype to specify for an AST_CONTROL_READ_ACTION frame. These
 | 
				
			||||||
 | 
					 * frames are then to be enacted on within a channel's read thread.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
enum ast_frame_read_action {
 | 
					enum ast_frame_read_action {
 | 
				
			||||||
	AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO,
 | 
						AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO,
 | 
				
			||||||
	AST_FRAME_READ_ACTION_SEND_TEXT,
 | 
						AST_FRAME_READ_ACTION_SEND_TEXT,
 | 
				
			||||||
 | 
						AST_FRAME_READ_ACTION_SEND_TEXT_DATA,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ast_control_read_action_payload {
 | 
					struct ast_control_read_action_payload {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -479,6 +479,24 @@ struct ast_msg_data_attribute {
 | 
				
			|||||||
struct ast_msg_data *ast_msg_data_alloc(enum ast_msg_data_source_type source,
 | 
					struct ast_msg_data *ast_msg_data_alloc(enum ast_msg_data_source_type source,
 | 
				
			||||||
	struct ast_msg_data_attribute attributes[], size_t count);
 | 
						struct ast_msg_data_attribute attributes[], size_t count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
					 * \brief Allocates an ast_msg_data structure.
 | 
				
			||||||
 | 
					 * \since 13.35.0
 | 
				
			||||||
 | 
					 * \since 16.12.0
 | 
				
			||||||
 | 
					 * \since 17.6.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param source The source type of the message
 | 
				
			||||||
 | 
					 * \param to Where the message is sent to
 | 
				
			||||||
 | 
					 * \param from Where the message is sent from
 | 
				
			||||||
 | 
					 * \param content_type Content type of the body
 | 
				
			||||||
 | 
					 * \param body The message body
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \return Pointer to msg structure or NULL on allocation failure.
 | 
				
			||||||
 | 
					 *         Caller must call ast_free when done.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct ast_msg_data *ast_msg_data_alloc2(enum ast_msg_data_source_type source_type,
 | 
				
			||||||
 | 
						const char *to, const char *from, const char *content_type, const char *body);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*!
 | 
					/*!
 | 
				
			||||||
 * \brief Clone an ast_msg_data structure
 | 
					 * \brief Clone an ast_msg_data structure
 | 
				
			||||||
 * \since 13.22.0
 | 
					 * \since 13.22.0
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3812,7 +3812,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
 | 
				
			|||||||
					break;
 | 
										break;
 | 
				
			||||||
				case AST_FRAME_READ_ACTION_SEND_TEXT:
 | 
									case AST_FRAME_READ_ACTION_SEND_TEXT:
 | 
				
			||||||
					ast_channel_unlock(chan);
 | 
										ast_channel_unlock(chan);
 | 
				
			||||||
					ast_sendtext(chan, (const char *) read_action_payload->payload);
 | 
										ast_sendtext(chan, (const char *)read_action_payload->payload);
 | 
				
			||||||
 | 
										ast_channel_lock(chan);
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case AST_FRAME_READ_ACTION_SEND_TEXT_DATA:
 | 
				
			||||||
 | 
										ast_channel_unlock(chan);
 | 
				
			||||||
 | 
										ast_sendtext_data(chan, (struct ast_msg_data *)read_action_payload->payload);
 | 
				
			||||||
					ast_channel_lock(chan);
 | 
										ast_channel_lock(chan);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										115
									
								
								main/manager.c
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								main/manager.c
									
									
									
									
									
								
							@@ -100,6 +100,7 @@
 | 
				
			|||||||
#include "asterisk/format_cache.h"
 | 
					#include "asterisk/format_cache.h"
 | 
				
			||||||
#include "asterisk/translate.h"
 | 
					#include "asterisk/translate.h"
 | 
				
			||||||
#include "asterisk/taskprocessor.h"
 | 
					#include "asterisk/taskprocessor.h"
 | 
				
			||||||
 | 
					#include "asterisk/message.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*** DOCUMENTATION
 | 
					/*** DOCUMENTATION
 | 
				
			||||||
	<manager name="Ping" language="en_US">
 | 
						<manager name="Ping" language="en_US">
 | 
				
			||||||
@@ -873,7 +874,8 @@
 | 
				
			|||||||
	</manager>
 | 
						</manager>
 | 
				
			||||||
	<manager name="SendText" language="en_US">
 | 
						<manager name="SendText" language="en_US">
 | 
				
			||||||
		<synopsis>
 | 
							<synopsis>
 | 
				
			||||||
			Send text message to channel.
 | 
								Sends a text message to channel. A content type	can be optionally specified. If not set
 | 
				
			||||||
 | 
								it is set to an empty string allowing a custom handler to default it as it sees fit.
 | 
				
			||||||
		</synopsis>
 | 
							</synopsis>
 | 
				
			||||||
		<syntax>
 | 
							<syntax>
 | 
				
			||||||
			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
 | 
								<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
 | 
				
			||||||
@@ -883,10 +885,16 @@
 | 
				
			|||||||
			<parameter name="Message" required="true">
 | 
								<parameter name="Message" required="true">
 | 
				
			||||||
				<para>Message to send.</para>
 | 
									<para>Message to send.</para>
 | 
				
			||||||
			</parameter>
 | 
								</parameter>
 | 
				
			||||||
 | 
								<parameter name="Content-Type" required="false" default="">
 | 
				
			||||||
 | 
									<para>The type of content in the message</para>
 | 
				
			||||||
 | 
								</parameter>
 | 
				
			||||||
		</syntax>
 | 
							</syntax>
 | 
				
			||||||
		<description>
 | 
							<description>
 | 
				
			||||||
			<para>Sends A Text Message to a channel while in a call.</para>
 | 
								<para>Sends A Text Message to a channel while in a call.</para>
 | 
				
			||||||
		</description>
 | 
							</description>
 | 
				
			||||||
 | 
							<see-also>
 | 
				
			||||||
 | 
								<ref type="application">SendText</ref>
 | 
				
			||||||
 | 
							</see-also>
 | 
				
			||||||
	</manager>
 | 
						</manager>
 | 
				
			||||||
	<manager name="UserEvent" language="en_US">
 | 
						<manager name="UserEvent" language="en_US">
 | 
				
			||||||
		<synopsis>
 | 
							<synopsis>
 | 
				
			||||||
@@ -4839,14 +4847,92 @@ static int action_status(struct mansession *s, const struct message *m)
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
					 * \brief Queue a given read action containing a payload onto a channel
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This queues a READ_ACTION control frame that contains a given "payload", or
 | 
				
			||||||
 | 
					 * data to be triggered and handled on the channel's read side. This ensures
 | 
				
			||||||
 | 
					 * the "action" is handled by the channel's media reading thread.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param chan The channel to queue the action on
 | 
				
			||||||
 | 
					 * \param payload The read action's payload
 | 
				
			||||||
 | 
					 * \param payload_size The size of the given payload
 | 
				
			||||||
 | 
					 * \param action The type of read action to queue
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \return -1 on error, 0 on success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int queue_read_action_payload(struct ast_channel *chan, const unsigned char *payload,
 | 
				
			||||||
 | 
						size_t payload_size, enum ast_frame_read_action action)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ast_control_read_action_payload *obj;
 | 
				
			||||||
 | 
						size_t obj_size;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						obj_size = payload_size + sizeof(*obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						obj = ast_malloc(obj_size);
 | 
				
			||||||
 | 
						if (!obj) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						obj->action = action;
 | 
				
			||||||
 | 
						obj->payload_size = payload_size;
 | 
				
			||||||
 | 
						memcpy(obj->payload, payload, payload_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res = ast_queue_control_data(chan, AST_CONTROL_READ_ACTION, obj, obj_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ast_free(obj);
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
					 * \brief Queue a read action to send a text message
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param chan The channel to queue the action on
 | 
				
			||||||
 | 
					 * \param body The body of the message
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \return -1 on error, 0 on success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int queue_sendtext(struct ast_channel *chan, const char *body)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return queue_read_action_payload(chan, (const unsigned char *)body,
 | 
				
			||||||
 | 
							strlen(body) + 1, AST_FRAME_READ_ACTION_SEND_TEXT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
					 * \brief Queue a read action to send a text data message
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \param chan The channel to queue the action on
 | 
				
			||||||
 | 
					 * \param body The body of the message
 | 
				
			||||||
 | 
					 * \param content_type The message's content type
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \return -1 on error, 0 on success
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int queue_sendtext_data(struct ast_channel *chan, const char *body,
 | 
				
			||||||
 | 
						const char *content_type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
						struct ast_msg_data *obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						obj = ast_msg_data_alloc2(AST_MSG_DATA_SOURCE_TYPE_UNKNOWN,
 | 
				
			||||||
 | 
												NULL, NULL, content_type, body);
 | 
				
			||||||
 | 
						if (!obj) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res = queue_read_action_payload(chan, (const unsigned char *)obj,
 | 
				
			||||||
 | 
							ast_msg_data_get_length(obj), AST_FRAME_READ_ACTION_SEND_TEXT_DATA);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ast_free(obj);
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int action_sendtext(struct mansession *s, const struct message *m)
 | 
					static int action_sendtext(struct mansession *s, const struct message *m)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ast_channel *c;
 | 
						struct ast_channel *c;
 | 
				
			||||||
	const char *name = astman_get_header(m, "Channel");
 | 
						const char *name = astman_get_header(m, "Channel");
 | 
				
			||||||
	const char *textmsg = astman_get_header(m, "Message");
 | 
						const char *textmsg = astman_get_header(m, "Message");
 | 
				
			||||||
	struct ast_control_read_action_payload *frame_payload;
 | 
						const char *content_type = astman_get_header(m, "Content-Type");
 | 
				
			||||||
	int payload_size;
 | 
					 | 
				
			||||||
	int frame_size;
 | 
					 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ast_strlen_zero(name)) {
 | 
						if (ast_strlen_zero(name)) {
 | 
				
			||||||
@@ -4865,22 +4951,13 @@ static int action_sendtext(struct mansession *s, const struct message *m)
 | 
				
			|||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	payload_size = strlen(textmsg) + 1;
 | 
						/*
 | 
				
			||||||
	frame_size = payload_size + sizeof(*frame_payload);
 | 
						 * If the "extra" data is not available, then send using "string" only.
 | 
				
			||||||
 | 
						 * Doing such maintains backward compatibilities.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						res = ast_strlen_zero(content_type) ? queue_sendtext(c, textmsg) :
 | 
				
			||||||
 | 
							queue_sendtext_data(c, textmsg, content_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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);
 | 
						ast_channel_unref(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (res >= 0) {
 | 
						if (res >= 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1429,6 +1429,32 @@ struct ast_msg_data *ast_msg_data_alloc(enum ast_msg_data_source_type source,
 | 
				
			|||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ast_msg_data *ast_msg_data_alloc2(enum ast_msg_data_source_type source_type,
 | 
				
			||||||
 | 
						const char *to, const char *from, const char *content_type, const char *body)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ast_msg_data_attribute attrs[] =
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								.type = AST_MSG_DATA_ATTR_TO,
 | 
				
			||||||
 | 
								.value = (char *)S_OR(to, ""),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								.type = AST_MSG_DATA_ATTR_FROM,
 | 
				
			||||||
 | 
								.value = (char *)S_OR(from, ""),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								.type = AST_MSG_DATA_ATTR_CONTENT_TYPE,
 | 
				
			||||||
 | 
								.value = (char *)S_OR(content_type, ""),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								.type = AST_MSG_DATA_ATTR_BODY,
 | 
				
			||||||
 | 
								.value = (char *)S_OR(body, ""),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ast_msg_data_alloc(source_type, attrs, ARRAY_LEN(attrs));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ast_msg_data *ast_msg_data_dup(struct ast_msg_data *msg)
 | 
					struct ast_msg_data *ast_msg_data_dup(struct ast_msg_data *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ast_msg_data *dest;
 | 
						struct ast_msg_data *dest;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user