mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 11:25:35 +00:00
Merge "bridge_softmix: Forward TEXT frames" into 13
This commit is contained in:
13
CHANGES
13
CHANGES
@@ -8,6 +8,19 @@
|
||||
===
|
||||
==============================================================================
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 13.21.0 to Asterisk 13.22.0 ----------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Core
|
||||
------------------
|
||||
* Core bridging and, more specifically, bridge_softmix have been enhanced to
|
||||
relay received frames of type TEXT or TEXT_DATA to all participants in a
|
||||
softmix bridge. res_pjsip_messaging and chan_pjsip have been enhanced to
|
||||
take advantage of this so when res_pjsip_messaging receives an in-dialog
|
||||
MESSAGE message from a user in a conference call, it's relayed to all
|
||||
other participants in the call.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 13.20.0 to Asterisk 13.21.0 ----------
|
||||
------------------------------------------------------------------------------
|
||||
|
@@ -54,6 +54,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/timing.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/message.h"
|
||||
|
||||
#define MAX_DATALEN 8096
|
||||
|
||||
@@ -719,6 +720,42 @@ static void softmix_bridge_check_voice(struct ast_bridge *bridge, struct ast_bri
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Determine what to do with a text frame.
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*
|
||||
* \param bridge Which bridge is getting the frame
|
||||
* \param bridge_channel Which channel is writing the frame.
|
||||
* \param frame What is being written.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void softmix_bridge_write_text(struct ast_bridge *bridge,
|
||||
struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
|
||||
{
|
||||
if (DEBUG_ATLEAST(1)) {
|
||||
struct ast_msg_data *msg = frame->data.ptr;
|
||||
char frame_type[64];
|
||||
|
||||
ast_frame_type2str(frame->frametype, frame_type, sizeof(frame_type));
|
||||
|
||||
if (frame->frametype == AST_FRAME_TEXT_DATA) {
|
||||
ast_log(LOG_DEBUG, "Received %s frame from '%s:%s': %s\n", frame_type,
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_FROM),
|
||||
ast_channel_name(bridge_channel->chan),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY));
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "Received %s frame from '%s': %.*s\n", frame_type,
|
||||
ast_channel_name(bridge_channel->chan), frame->datalen,
|
||||
(char *)frame->data.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Determine what to do with a control frame.
|
||||
@@ -803,6 +840,10 @@ static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_cha
|
||||
case AST_FRAME_VIDEO:
|
||||
softmix_bridge_write_video(bridge, bridge_channel, frame);
|
||||
break;
|
||||
case AST_FRAME_TEXT:
|
||||
case AST_FRAME_TEXT_DATA:
|
||||
softmix_bridge_write_text(bridge, bridge_channel, frame);
|
||||
break;
|
||||
case AST_FRAME_CONTROL:
|
||||
res = softmix_bridge_write_control(bridge, bridge_channel, frame);
|
||||
break;
|
||||
|
@@ -63,6 +63,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/features_config.h"
|
||||
#include "asterisk/pickup.h"
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/message.h"
|
||||
|
||||
#include "asterisk/res_pjsip.h"
|
||||
#include "asterisk/res_pjsip_session.h"
|
||||
@@ -91,6 +92,7 @@ static void chan_pjsip_pvt_dtor(void *obj)
|
||||
|
||||
/* \brief Asterisk core interaction functions */
|
||||
static struct ast_channel *chan_pjsip_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
|
||||
static int chan_pjsip_sendtext_data(struct ast_channel *ast, struct ast_msg_data *msg);
|
||||
static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text);
|
||||
static int chan_pjsip_digit_begin(struct ast_channel *ast, char digit);
|
||||
static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
|
||||
@@ -112,6 +114,7 @@ struct ast_channel_tech chan_pjsip_tech = {
|
||||
.description = "PJSIP Channel Driver",
|
||||
.requester = chan_pjsip_request,
|
||||
.send_text = chan_pjsip_sendtext,
|
||||
.send_text_data = chan_pjsip_sendtext_data,
|
||||
.send_digit_begin = chan_pjsip_digit_begin,
|
||||
.send_digit_end = chan_pjsip_digit_end,
|
||||
.call = chan_pjsip_call,
|
||||
@@ -128,7 +131,7 @@ struct ast_channel_tech chan_pjsip_tech = {
|
||||
.queryoption = chan_pjsip_queryoption,
|
||||
.func_channel_read = pjsip_acf_channel_read,
|
||||
.get_pvt_uniqueid = chan_pjsip_get_uniqueid,
|
||||
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
|
||||
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER | AST_CHAN_TP_SEND_TEXT_DATA
|
||||
};
|
||||
|
||||
/*! \brief SIP session interaction functions */
|
||||
@@ -2261,50 +2264,99 @@ static struct ast_channel *chan_pjsip_request(const char *type, struct ast_forma
|
||||
|
||||
struct sendtext_data {
|
||||
struct ast_sip_session *session;
|
||||
char text[0];
|
||||
struct ast_msg_data *msg;
|
||||
};
|
||||
|
||||
static void sendtext_data_destroy(void *obj)
|
||||
{
|
||||
struct sendtext_data *data = obj;
|
||||
ao2_ref(data->session, -1);
|
||||
ao2_cleanup(data->session);
|
||||
ast_free(data->msg);
|
||||
}
|
||||
|
||||
static struct sendtext_data* sendtext_data_create(struct ast_sip_session *session, const char *text)
|
||||
static struct sendtext_data* sendtext_data_create(struct ast_channel *chan,
|
||||
struct ast_msg_data *msg)
|
||||
{
|
||||
int size = strlen(text) + 1;
|
||||
struct sendtext_data *data = ao2_alloc(sizeof(*data)+size, sendtext_data_destroy);
|
||||
struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
|
||||
struct sendtext_data *data = ao2_alloc(sizeof(*data), sendtext_data_destroy);
|
||||
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->session = session;
|
||||
data->msg = ast_msg_data_dup(msg);
|
||||
if (!data->msg) {
|
||||
ao2_cleanup(data);
|
||||
return NULL;
|
||||
}
|
||||
data->session = channel->session;
|
||||
ao2_ref(data->session, +1);
|
||||
ast_copy_string(data->text, text, size);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int sendtext(void *obj)
|
||||
{
|
||||
RAII_VAR(struct sendtext_data *, data, obj, ao2_cleanup);
|
||||
struct sendtext_data *data = obj;
|
||||
pjsip_tx_data *tdata;
|
||||
|
||||
const struct ast_sip_body body = {
|
||||
const char *body_text = ast_msg_data_get_attribute(data->msg, AST_MSG_DATA_ATTR_BODY);
|
||||
const char *content_type = ast_msg_data_get_attribute(data->msg, AST_MSG_DATA_ATTR_CONTENT_TYPE);
|
||||
char *sep;
|
||||
struct ast_sip_body body = {
|
||||
.type = "text",
|
||||
.subtype = "plain",
|
||||
.body_text = data->text
|
||||
.body_text = body_text,
|
||||
};
|
||||
|
||||
if (!ast_strlen_zero(content_type)) {
|
||||
sep = strchr(content_type, '/');
|
||||
if (sep) {
|
||||
*sep = '\0';
|
||||
body.type = content_type;
|
||||
body.subtype = ++sep;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
|
||||
ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
|
||||
data->session->inv_session->cause,
|
||||
pjsip_get_status_text(data->session->inv_session->cause)->ptr);
|
||||
} else {
|
||||
ast_debug(3, "Sending in dialog SIP message\n");
|
||||
pjsip_from_hdr *hdr;
|
||||
pjsip_name_addr *name_addr;
|
||||
const char *from = ast_msg_data_get_attribute(data->msg, AST_MSG_DATA_ATTR_FROM);
|
||||
const char *to = ast_msg_data_get_attribute(data->msg, AST_MSG_DATA_ATTR_TO);
|
||||
int invalidate_tdata = 0;
|
||||
|
||||
ast_sip_create_request("MESSAGE", data->session->inv_session->dlg, data->session->endpoint, NULL, NULL, &tdata);
|
||||
ast_sip_add_body(tdata, &body);
|
||||
|
||||
/*
|
||||
* If we have a 'from' in the msg, set the display name in the From
|
||||
* header to it.
|
||||
*/
|
||||
if (!ast_strlen_zero(from)) {
|
||||
hdr = PJSIP_MSG_FROM_HDR(tdata->msg);
|
||||
name_addr = (pjsip_name_addr *) hdr->uri;
|
||||
pj_strdup2(tdata->pool, &name_addr->display, from);
|
||||
invalidate_tdata = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a 'to' in the msg, set the display name in the To
|
||||
* header to it.
|
||||
*/
|
||||
if (!ast_strlen_zero(to)) {
|
||||
hdr = PJSIP_MSG_TO_HDR(tdata->msg);
|
||||
name_addr = (pjsip_name_addr *) hdr->uri;
|
||||
pj_strdup2(tdata->pool, &name_addr->display, to);
|
||||
invalidate_tdata = 1;
|
||||
}
|
||||
|
||||
if (invalidate_tdata) {
|
||||
pjsip_tx_data_invalidate_msg(tdata);
|
||||
}
|
||||
|
||||
ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -2312,14 +2364,22 @@ static int sendtext(void *obj)
|
||||
pjsip_inv_dec_ref(data->session->inv_session);
|
||||
#endif
|
||||
|
||||
ao2_cleanup(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Function called by core to send text on PJSIP session */
|
||||
static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
|
||||
static int chan_pjsip_sendtext_data(struct ast_channel *ast, struct ast_msg_data *msg)
|
||||
{
|
||||
struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
|
||||
struct sendtext_data *data = sendtext_data_create(channel->session, text);
|
||||
struct sendtext_data *data = sendtext_data_create(ast, msg);
|
||||
|
||||
ast_debug(1, "Sending MESSAGE from '%s' to '%s:%s': %s\n",
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_FROM),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_TO),
|
||||
ast_channel_name(ast),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY));
|
||||
|
||||
if (!data) {
|
||||
return -1;
|
||||
@@ -2343,6 +2403,28 @@ static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
|
||||
{
|
||||
struct ast_msg_data *msg;
|
||||
int rc;
|
||||
struct ast_msg_data_attribute attrs[] =
|
||||
{
|
||||
{
|
||||
.type = AST_MSG_DATA_ATTR_BODY,
|
||||
.value = (char *)text,
|
||||
}
|
||||
};
|
||||
|
||||
msg = ast_msg_data_alloc(AST_MSG_DATA_SOURCE_TYPE_UNKNOWN, attrs, ARRAY_LEN(attrs));
|
||||
if (!msg) {
|
||||
return -1;
|
||||
}
|
||||
rc = chan_pjsip_sendtext_data(ast, msg);
|
||||
ast_free(msg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! \brief Convert SIP hangup causes to Asterisk hangup causes */
|
||||
static int hangup_sip2cause(int cause)
|
||||
{
|
||||
|
@@ -61,6 +61,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
<enum name = "NULL" />
|
||||
<enum name = "IAX" />
|
||||
<enum name = "TEXT" />
|
||||
<enum name = "TEXT_DATA" />
|
||||
<enum name = "IMAGE" />
|
||||
<enum name = "HTML" />
|
||||
<enum name = "CNG" />
|
||||
@@ -90,6 +91,7 @@ static struct {
|
||||
{ AST_FRAME_NULL, "NULL" },
|
||||
{ AST_FRAME_IAX, "IAX" },
|
||||
{ AST_FRAME_TEXT, "TEXT" },
|
||||
{ AST_FRAME_TEXT_DATA, "TEXT_DATA" },
|
||||
{ AST_FRAME_IMAGE, "IMAGE" },
|
||||
{ AST_FRAME_HTML, "HTML" },
|
||||
{ AST_FRAME_CNG, "CNG" },
|
||||
@@ -372,6 +374,9 @@ static void print_frame(struct ast_frame *frame)
|
||||
}
|
||||
ast_verbose("Bytes: %d\n", frame->datalen);
|
||||
break;
|
||||
case AST_FRAME_RTCP:
|
||||
ast_verbose("FrameType: RTCP\n");
|
||||
break;
|
||||
case AST_FRAME_NULL:
|
||||
ast_verbose("FrameType: NULL\n");
|
||||
break;
|
||||
@@ -381,6 +386,9 @@ static void print_frame(struct ast_frame *frame)
|
||||
case AST_FRAME_TEXT:
|
||||
ast_verbose("FrameType: TXT\n");
|
||||
break;
|
||||
case AST_FRAME_TEXT_DATA:
|
||||
ast_verbose("FrameType: TXT_DATA\n");
|
||||
break;
|
||||
case AST_FRAME_IMAGE:
|
||||
ast_verbose("FrameType: IMAGE\n");
|
||||
break;
|
||||
|
@@ -589,6 +589,11 @@ struct ast_assigned_ids {
|
||||
const char *uniqueid2;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Forward declaration
|
||||
*/
|
||||
struct ast_msg_data;
|
||||
|
||||
/*!
|
||||
* \brief
|
||||
* Structure to describe a channel "technology", ie a channel driver
|
||||
@@ -756,6 +761,9 @@ struct ast_channel_tech {
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int (*pre_call)(struct ast_channel *chan, const char *sub_args);
|
||||
|
||||
/*! \brief Display or transmit text with data*/
|
||||
int (* const send_text_data)(struct ast_channel *chan, struct ast_msg_data *data);
|
||||
};
|
||||
|
||||
/*! Kill the channel channel driver technology descriptor. */
|
||||
@@ -883,6 +891,10 @@ enum {
|
||||
* world
|
||||
*/
|
||||
AST_CHAN_TP_INTERNAL = (1 << 2),
|
||||
/*!
|
||||
* \brief Channels have this property if they implement send_text_data
|
||||
*/
|
||||
AST_CHAN_TP_SEND_TEXT_DATA = (1 << 3),
|
||||
};
|
||||
|
||||
/*! \brief ast_channel flags */
|
||||
@@ -2067,6 +2079,26 @@ int ast_set_write_format(struct ast_channel *chan, struct ast_format *format);
|
||||
*/
|
||||
int ast_sendtext(struct ast_channel *chan, const char *text);
|
||||
|
||||
/*!
|
||||
* \brief Sends text to a channel in an ast_msg_data structure wrapper with ast_sendtext as fallback
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*
|
||||
* \param chan channel to act upon
|
||||
* \param msg ast_msg_data structure
|
||||
*
|
||||
* \details
|
||||
* Write text to a display on a channel. If the channel driver doesn't support the
|
||||
* send_text_data callback. then the original send_text callback will be used if
|
||||
* available.
|
||||
*
|
||||
* \note The channel does not need to be locked before calling this function.
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int ast_sendtext_data(struct ast_channel *chan, struct ast_msg_data *msg);
|
||||
|
||||
/*!
|
||||
* \brief Receives a text character from a channel
|
||||
* \param chan channel to act upon
|
||||
|
@@ -48,6 +48,7 @@ extern "C" {
|
||||
* \arg \b DTMF: A DTMF digit, subclass is the digit
|
||||
* \arg \b IMAGE: Image transport, mostly used in IAX
|
||||
* \arg \b TEXT: Text messages and character by character (real time text)
|
||||
* \arg \b TEXT_DATA: Text messages in an ast_msg_data structure
|
||||
* \arg \b HTML: URL's and web pages
|
||||
* \arg \b MODEM: Modulated data encodings, such as T.38 and V.150
|
||||
* \arg \b IAX: Private frame type for the IAX protocol
|
||||
@@ -127,6 +128,10 @@ enum ast_frame_type {
|
||||
* directly into bridges.
|
||||
*/
|
||||
AST_FRAME_BRIDGE_ACTION_SYNC,
|
||||
/*! RTCP feedback (the subclass will contain the payload type) */
|
||||
AST_FRAME_RTCP,
|
||||
/*! Text message in an ast_msg_data structure */
|
||||
AST_FRAME_TEXT_DATA,
|
||||
};
|
||||
#define AST_FRAME_DTMF AST_FRAME_DTMF_END
|
||||
|
||||
|
@@ -407,6 +407,129 @@ void ast_msg_var_iterator_destroy(struct ast_msg_var_iterator *iter);
|
||||
*/
|
||||
void ast_msg_var_unref_current(struct ast_msg_var_iterator *iter);
|
||||
|
||||
|
||||
/*! \defgroup ast_msg_data Enhanced Messaging
|
||||
* @{
|
||||
* \page Messaging Enhanced Messaging
|
||||
*
|
||||
* The basic messaging framework has a basic drawback... It can only pass
|
||||
* a text string through the core. This causes several issues:
|
||||
* \li Only a content type of text/plain can be passed.
|
||||
* \li If a softmix bridge is used, the original sender identity is lost.
|
||||
*
|
||||
* The Enhanced Messaging framework allows attributes, such as "From", "To"
|
||||
* and "Content-Type" to be attached to the message by the incoming channel
|
||||
* tech which can then be used by the outgoing channel tech to construct
|
||||
* the appropriate technology-specific outgoing message.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Structure used to transport an enhanced message through the frame core
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*/
|
||||
struct ast_msg_data;
|
||||
|
||||
enum ast_msg_data_source_type {
|
||||
AST_MSG_DATA_SOURCE_TYPE_UNKNOWN = 0,
|
||||
AST_MSG_DATA_SOURCE_TYPE_T140,
|
||||
AST_MSG_DATA_SOURCE_TYPE_IN_DIALOG,
|
||||
AST_MSG_DATA_SOURCE_TYPE_OUT_OF_DIALOG,
|
||||
__AST_MSG_DATA_SOURCE_TYPE_LAST,
|
||||
};
|
||||
|
||||
enum ast_msg_data_attribute_type {
|
||||
AST_MSG_DATA_ATTR_TO = 0,
|
||||
AST_MSG_DATA_ATTR_FROM,
|
||||
AST_MSG_DATA_ATTR_CONTENT_TYPE,
|
||||
AST_MSG_DATA_ATTR_BODY,
|
||||
__AST_MSG_DATA_ATTR_LAST,
|
||||
};
|
||||
|
||||
struct ast_msg_data_attribute {
|
||||
enum ast_msg_data_attribute_type type;
|
||||
char *value;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Allocates an ast_msg_data structure.
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*
|
||||
* \param source The source type of the message
|
||||
* \param attributes A pointer to an array of ast_msg_data_attribute structures
|
||||
* \param count The number of elements in the array
|
||||
*
|
||||
* \return Pointer to msg structure or NULL on allocation failure.
|
||||
* Caller must call ast_free when done.
|
||||
*/
|
||||
struct ast_msg_data *ast_msg_data_alloc(enum ast_msg_data_source_type source,
|
||||
struct ast_msg_data_attribute attributes[], size_t count);
|
||||
|
||||
/*!
|
||||
* \brief Clone an ast_msg_data structure
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*
|
||||
* \param msg The message to clone
|
||||
*
|
||||
* \return New message structure or NULL if there was an allocation failure.
|
||||
* Caller must call ast_free when done.
|
||||
*/
|
||||
struct ast_msg_data *ast_msg_data_dup(struct ast_msg_data *msg);
|
||||
|
||||
/*!
|
||||
* \brief Get length of the structure
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*
|
||||
* \param msg Pointer to ast_msg_data structure
|
||||
*
|
||||
* \return The length of the structure itself plus the dynamically allocated attribute buffer.
|
||||
*/
|
||||
size_t ast_msg_data_get_length(struct ast_msg_data *msg);
|
||||
|
||||
/*!
|
||||
* \brief Get "source type" from ast_msg_data
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*
|
||||
* \param msg Pointer to ast_msg_data structure
|
||||
*
|
||||
* \return The source type field.
|
||||
*/
|
||||
enum ast_msg_data_source_type ast_msg_data_get_source_type(struct ast_msg_data *msg);
|
||||
|
||||
/*!
|
||||
* \brief Get attribute from ast_msg_data
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*
|
||||
* \param msg Pointer to ast_msg_data structure
|
||||
* \param attribute_type One of ast_msg_data_attribute_type
|
||||
*
|
||||
* \return The attribute or an empty string ("") if the attribute wasn't set.
|
||||
*/
|
||||
const char *ast_msg_data_get_attribute(struct ast_msg_data *msg,
|
||||
enum ast_msg_data_attribute_type attribute_type);
|
||||
|
||||
/*!
|
||||
* \brief Queue an AST_FRAME_TEXT_DATA frame containing an ast_msg_data structure
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*
|
||||
* \param channel The channel on which to queue the frame
|
||||
* \param msg Pointer to ast_msg_data structure
|
||||
*
|
||||
* \retval -1 Error
|
||||
* \retval 0 Success
|
||||
*/
|
||||
int ast_msg_data_queue_frame(struct ast_channel *channel, struct ast_msg_data *msg);
|
||||
|
||||
/*!
|
||||
* @}
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
#endif
|
||||
|
@@ -57,6 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/sem.h"
|
||||
#include "asterisk/message.h"
|
||||
|
||||
/*!
|
||||
* \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge.
|
||||
@@ -999,6 +1000,20 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (DEBUG_ATLEAST(1)) {
|
||||
if (fr->frametype == AST_FRAME_TEXT) {
|
||||
ast_log(LOG_DEBUG, "Queuing TEXT frame to '%s': %*.s\n", ast_channel_name(bridge_channel->chan),
|
||||
fr->datalen, (char *)fr->data.ptr);
|
||||
} else if (fr->frametype == AST_FRAME_TEXT_DATA) {
|
||||
struct ast_msg_data *msg = fr->data.ptr;
|
||||
ast_log(LOG_DEBUG, "Queueing TEXT_DATA frame from '%s' to '%s:%s': %s\n",
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_FROM),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_TO),
|
||||
ast_channel_name(bridge_channel->chan),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY));
|
||||
}
|
||||
}
|
||||
|
||||
AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list);
|
||||
if (ast_alertpipe_write(bridge_channel->alert_pipe)) {
|
||||
ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n",
|
||||
@@ -2289,6 +2304,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
|
||||
{
|
||||
struct ast_frame *fr;
|
||||
struct sync_payload *sync_payload;
|
||||
struct ast_msg_data *msg;
|
||||
|
||||
ast_bridge_channel_lock(bridge_channel);
|
||||
|
||||
@@ -2321,6 +2337,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
|
||||
ast_bridge_channel_unlock(bridge_channel);
|
||||
|
||||
if (!fr) {
|
||||
/*
|
||||
* Wait some to reduce CPU usage from a tight loop
|
||||
@@ -2344,6 +2361,20 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe
|
||||
break;
|
||||
case AST_FRAME_NULL:
|
||||
break;
|
||||
case AST_FRAME_TEXT:
|
||||
ast_debug(1, "Sending TEXT frame to '%s': %*.s\n",
|
||||
ast_channel_name(bridge_channel->chan), fr->datalen, (char *)fr->data.ptr);
|
||||
ast_sendtext(bridge_channel->chan, fr->data.ptr);
|
||||
break;
|
||||
case AST_FRAME_TEXT_DATA:
|
||||
msg = (struct ast_msg_data *)fr->data.ptr;
|
||||
ast_debug(1, "Sending TEXT_DATA frame from '%s' to '%s:%s': %s\n",
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_FROM),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_TO),
|
||||
ast_channel_name(bridge_channel->chan),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY));
|
||||
ast_sendtext_data(bridge_channel->chan, msg);
|
||||
break;
|
||||
default:
|
||||
/* Write the frame to the channel. */
|
||||
bridge_channel->activity = BRIDGE_CHANNEL_THREAD_SIMPLE;
|
||||
|
@@ -75,6 +75,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/stasis_channels.h"
|
||||
#include "asterisk/max_forwards.h"
|
||||
#include "asterisk/message.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
***/
|
||||
@@ -1513,6 +1514,7 @@ int ast_is_deferrable_frame(const struct ast_frame *frame)
|
||||
case AST_FRAME_BRIDGE_ACTION_SYNC:
|
||||
case AST_FRAME_CONTROL:
|
||||
case AST_FRAME_TEXT:
|
||||
case AST_FRAME_TEXT_DATA:
|
||||
case AST_FRAME_IMAGE:
|
||||
case AST_FRAME_HTML:
|
||||
return 1;
|
||||
@@ -1525,6 +1527,7 @@ int ast_is_deferrable_frame(const struct ast_frame *frame)
|
||||
case AST_FRAME_IAX:
|
||||
case AST_FRAME_CNG:
|
||||
case AST_FRAME_MODEM:
|
||||
case AST_FRAME_RTCP:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
@@ -2883,11 +2886,13 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay)
|
||||
case AST_FRAME_VOICE:
|
||||
case AST_FRAME_VIDEO:
|
||||
case AST_FRAME_TEXT:
|
||||
case AST_FRAME_TEXT_DATA:
|
||||
case AST_FRAME_DTMF_BEGIN:
|
||||
case AST_FRAME_DTMF_END:
|
||||
case AST_FRAME_IMAGE:
|
||||
case AST_FRAME_HTML:
|
||||
case AST_FRAME_MODEM:
|
||||
case AST_FRAME_RTCP:
|
||||
done = 1;
|
||||
break;
|
||||
case AST_FRAME_CONTROL:
|
||||
@@ -4869,9 +4874,11 @@ char *ast_recvtext(struct ast_channel *chan, int timeout)
|
||||
return buf;
|
||||
}
|
||||
|
||||
int ast_sendtext(struct ast_channel *chan, const char *text)
|
||||
int ast_sendtext_data(struct ast_channel *chan, struct ast_msg_data *msg)
|
||||
{
|
||||
int res = 0;
|
||||
const char *body = ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY);
|
||||
const char *content_type = ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_CONTENT_TYPE);
|
||||
|
||||
ast_channel_lock(chan);
|
||||
/* Stop if we're a zombie or need a soft hangup */
|
||||
@@ -4880,35 +4887,76 @@ int ast_sendtext(struct ast_channel *chan, const char *text)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(text)) {
|
||||
ast_channel_unlock(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CHECK_BLOCKING(chan);
|
||||
if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) {
|
||||
if (ast_channel_tech(chan)->write_text
|
||||
&& (ast_strlen_zero(content_type) || strcasecmp(content_type, "text/plain") == 0)
|
||||
&& (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) {
|
||||
struct ast_frame f;
|
||||
size_t body_len = strlen(body) + 1;
|
||||
|
||||
/* Process as T.140 text (moved here from ast_sendtext() */
|
||||
memset(&f, 0, sizeof(f));
|
||||
f.frametype = AST_FRAME_TEXT;
|
||||
f.src = "DIALPLAN";
|
||||
f.mallocd = AST_MALLOCD_DATA;
|
||||
f.datalen = strlen(text);
|
||||
f.data.ptr = ast_strdup(text);
|
||||
f.subclass.format = ast_format_t140;
|
||||
|
||||
f.frametype = AST_FRAME_TEXT;
|
||||
f.datalen = body_len;
|
||||
f.mallocd = AST_MALLOCD_DATA;
|
||||
f.data.ptr = ast_strdup(body);
|
||||
if (f.data.ptr) {
|
||||
res = ast_channel_tech(chan)->write_text(chan, &f);
|
||||
ast_frfree(&f);
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
} else if (ast_channel_tech(chan)->send_text) {
|
||||
res = ast_channel_tech(chan)->send_text(chan, text);
|
||||
ast_frfree(&f);
|
||||
} else if ((ast_channel_tech(chan)->properties & AST_CHAN_TP_SEND_TEXT_DATA)
|
||||
&& ast_channel_tech(chan)->send_text_data) {
|
||||
/* Send enhanced message to a channel driver that supports it */
|
||||
ast_debug(1, "Sending TEXT_DATA from '%s' to %s:%s %s\n",
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_FROM),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_TO),
|
||||
ast_channel_name(chan), body);
|
||||
res = ast_channel_tech(chan)->send_text_data(chan, msg);
|
||||
} else if (ast_channel_tech(chan)->send_text
|
||||
&& (ast_strlen_zero(content_type) || strcasecmp(content_type, "text/plain") == 0)) {
|
||||
/* Send the body of an enhanced message to a channel driver that supports only a char str */
|
||||
ast_debug(1, "Sending TEXT to %s: %s\n", ast_channel_name(chan), body);
|
||||
res = ast_channel_tech(chan)->send_text(chan, body);
|
||||
} else {
|
||||
ast_debug(1, "Channel technology does not support sending text on channel '%s'\n",
|
||||
ast_channel_name(chan));
|
||||
res = -1;
|
||||
}
|
||||
ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING);
|
||||
ast_channel_unlock(chan);
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_sendtext(struct ast_channel *chan, const char *text)
|
||||
{
|
||||
struct ast_msg_data *msg;
|
||||
int rc;
|
||||
struct ast_msg_data_attribute attrs[] =
|
||||
{
|
||||
{
|
||||
.type = AST_MSG_DATA_ATTR_BODY,
|
||||
.value = (char *)text,
|
||||
}
|
||||
};
|
||||
|
||||
if (ast_strlen_zero(text)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg = ast_msg_data_alloc(AST_MSG_DATA_SOURCE_TYPE_UNKNOWN, attrs, ARRAY_LEN(attrs));
|
||||
if (!msg) {
|
||||
return -1;
|
||||
}
|
||||
rc = ast_sendtext_data(chan, msg);
|
||||
ast_free(msg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ast_senddigit_begin(struct ast_channel *chan, char digit)
|
||||
{
|
||||
/* Device does not support DTMF tones, lets fake
|
||||
|
@@ -591,6 +591,9 @@ void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
|
||||
case AST_FRAME_TEXT:
|
||||
ast_copy_string(ftype, "Text", len);
|
||||
break;
|
||||
case AST_FRAME_TEXT_DATA:
|
||||
ast_copy_string(ftype, "Text Data", len);
|
||||
break;
|
||||
case AST_FRAME_IMAGE:
|
||||
ast_copy_string(ftype, "Image", len);
|
||||
break;
|
||||
|
142
main/message.c
142
main/message.c
@@ -1350,6 +1350,148 @@ int ast_msg_send(struct ast_msg *msg, const char *to, const char *from)
|
||||
return res;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Structure used to transport a message through the frame core
|
||||
* \since 13.22.0
|
||||
* \since 15.5.0
|
||||
*/
|
||||
struct ast_msg_data {
|
||||
/*! The length of this structure plus the actual length of the allocated buffer */
|
||||
size_t length;
|
||||
enum ast_msg_data_source_type source;
|
||||
/*! These are indices into the buffer where teh attribute starts */
|
||||
int attribute_value_offsets[__AST_MSG_DATA_ATTR_LAST];
|
||||
/*! The buffer containing the NULL separated attributes */
|
||||
char buf[0];
|
||||
};
|
||||
|
||||
#define ATTRIBUTE_UNSET -1
|
||||
|
||||
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 *msg;
|
||||
size_t len = sizeof(*msg);
|
||||
size_t i;
|
||||
size_t current_offset = 0;
|
||||
enum ast_msg_data_attribute_type attr_type;
|
||||
|
||||
if (!attributes) {
|
||||
ast_assert(attributes != NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
ast_assert(count > 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate the length required for the buffer */
|
||||
for (i=0; i < count; i++) {
|
||||
if (!attributes[i].value) {
|
||||
ast_assert(attributes[i].value != NULL);
|
||||
return NULL;
|
||||
}
|
||||
len += (strlen(attributes[i].value) + 1);
|
||||
}
|
||||
|
||||
msg = ast_calloc(1, len);
|
||||
if (!msg) {
|
||||
return NULL;
|
||||
}
|
||||
msg->source = source;
|
||||
msg->length = len;
|
||||
|
||||
/* Mark all of the attributes as unset */
|
||||
for (attr_type = 0; attr_type < __AST_MSG_DATA_ATTR_LAST; attr_type++) {
|
||||
msg->attribute_value_offsets[attr_type] = ATTRIBUTE_UNSET;
|
||||
}
|
||||
|
||||
/* Set the ones we have and increment the offset */
|
||||
for (i=0; i < count; i++) {
|
||||
len = (strlen(attributes[i].value) + 1);
|
||||
strcpy(msg->buf + current_offset, attributes[i].value); /* Safe */
|
||||
msg->attribute_value_offsets[attributes[i].type] = current_offset;
|
||||
current_offset += len;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct ast_msg_data *ast_msg_data_dup(struct ast_msg_data *msg)
|
||||
{
|
||||
struct ast_msg_data *dest;
|
||||
|
||||
if (!msg) {
|
||||
ast_assert(msg != NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dest = ast_malloc(msg->length);
|
||||
if (!dest) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(dest, msg, msg->length);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
size_t ast_msg_data_get_length(struct ast_msg_data *msg)
|
||||
{
|
||||
if (!msg) {
|
||||
ast_assert(msg != NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return msg->length;
|
||||
}
|
||||
|
||||
enum ast_msg_data_source_type ast_msg_data_get_source_type(struct ast_msg_data *msg)
|
||||
{
|
||||
if (!msg) {
|
||||
ast_assert(msg != NULL);
|
||||
return AST_MSG_DATA_SOURCE_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
return msg->source;
|
||||
}
|
||||
|
||||
const char *ast_msg_data_get_attribute(struct ast_msg_data *msg,
|
||||
enum ast_msg_data_attribute_type attribute_type)
|
||||
{
|
||||
if (!msg) {
|
||||
ast_assert(msg != NULL);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (msg->attribute_value_offsets[attribute_type] > ATTRIBUTE_UNSET) {
|
||||
return msg->buf + msg->attribute_value_offsets[attribute_type];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
int ast_msg_data_queue_frame(struct ast_channel *channel, struct ast_msg_data *msg)
|
||||
{
|
||||
struct ast_frame f;
|
||||
|
||||
if (!channel) {
|
||||
ast_assert(channel != NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!msg) {
|
||||
ast_assert(msg != NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
f.frametype = AST_FRAME_TEXT_DATA;
|
||||
f.data.ptr = msg;
|
||||
f.datalen = msg->length;
|
||||
return ast_queue_frame(channel, &f);
|
||||
}
|
||||
|
||||
int ast_msg_tech_register(const struct ast_msg_tech *tech)
|
||||
{
|
||||
const struct ast_msg_tech *match;
|
||||
|
@@ -76,6 +76,32 @@ static enum pjsip_status_code check_content_type(const pjsip_rx_data *rdata)
|
||||
return res ? PJSIP_SC_OK : PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Checks to make sure the request has the correct content type.
|
||||
*
|
||||
* \details This module supports the following media types: "text/\*".
|
||||
* Return unsupported otherwise.
|
||||
*
|
||||
* \param rdata The SIP request
|
||||
*/
|
||||
static enum pjsip_status_code check_content_type_any_text(const pjsip_rx_data *rdata)
|
||||
{
|
||||
int res = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
|
||||
pj_str_t text = { "text", 4};
|
||||
|
||||
/* We'll accept any text/ content type */
|
||||
if (rdata->msg_info.msg->body && rdata->msg_info.msg->body->len
|
||||
&& pj_stricmp(&rdata->msg_info.msg->body->content_type.type, &text) == 0) {
|
||||
res = PJSIP_SC_OK;
|
||||
} else if (rdata->msg_info.ctype
|
||||
&& pj_stricmp(&rdata->msg_info.ctype->media.type, &text) == 0) {
|
||||
res = PJSIP_SC_OK;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Puts pointer past 'sip[s]:' string that should be at the
|
||||
@@ -756,39 +782,98 @@ static pj_bool_t module_on_rx_request(pjsip_rx_data *rdata)
|
||||
|
||||
static int incoming_in_dialog_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
|
||||
{
|
||||
char buf[MAX_BODY_SIZE];
|
||||
enum pjsip_status_code code;
|
||||
struct ast_frame f;
|
||||
int rc;
|
||||
pjsip_dialog *dlg = session->inv_session->dlg;
|
||||
pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
|
||||
struct ast_msg_data *msg;
|
||||
struct ast_party_caller *caller;
|
||||
pjsip_name_addr *name_addr;
|
||||
size_t from_len;
|
||||
size_t to_len;
|
||||
struct ast_msg_data_attribute attrs[4];
|
||||
int pos = 0;
|
||||
int body_pos;
|
||||
|
||||
if (!session->channel) {
|
||||
send_response(rdata, PJSIP_SC_NOT_FOUND, dlg, tsx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((code = check_content_type(rdata)) != PJSIP_SC_OK) {
|
||||
code = check_content_type_any_text(rdata);
|
||||
if (code != PJSIP_SC_OK) {
|
||||
send_response(rdata, code, dlg, tsx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (print_body(rdata, buf, sizeof(buf)-1) < 1) {
|
||||
/* invalid body size */
|
||||
send_response(rdata, PJSIP_SC_REQUEST_ENTITY_TOO_LARGE, dlg, tsx);
|
||||
caller = ast_channel_caller(session->channel);
|
||||
|
||||
name_addr = (pjsip_name_addr *) rdata->msg_info.from->uri;
|
||||
from_len = pj_strlen(&name_addr->display);
|
||||
if (from_len) {
|
||||
attrs[pos].type = AST_MSG_DATA_ATTR_FROM;
|
||||
from_len++;
|
||||
attrs[pos].value = ast_alloca(from_len);
|
||||
ast_copy_pj_str(attrs[pos].value, &name_addr->display, from_len);
|
||||
pos++;
|
||||
} else if (caller->id.name.valid && !ast_strlen_zero(caller->id.name.str)) {
|
||||
attrs[pos].type = AST_MSG_DATA_ATTR_FROM;
|
||||
attrs[pos].value = caller->id.name.str;
|
||||
pos++;
|
||||
}
|
||||
|
||||
name_addr = (pjsip_name_addr *) rdata->msg_info.to->uri;
|
||||
to_len = pj_strlen(&name_addr->display);
|
||||
if (to_len) {
|
||||
attrs[pos].type = AST_MSG_DATA_ATTR_TO;
|
||||
to_len++;
|
||||
attrs[pos].value = ast_alloca(to_len);
|
||||
ast_copy_pj_str(attrs[pos].value, &name_addr->display, to_len);
|
||||
pos++;
|
||||
}
|
||||
|
||||
attrs[pos].type = AST_MSG_DATA_ATTR_CONTENT_TYPE;
|
||||
attrs[pos].value = ast_alloca(rdata->msg_info.msg->body->content_type.type.slen
|
||||
+ rdata->msg_info.msg->body->content_type.subtype.slen + 2);
|
||||
sprintf(attrs[pos].value, "%.*s/%.*s",
|
||||
(int)rdata->msg_info.msg->body->content_type.type.slen,
|
||||
rdata->msg_info.msg->body->content_type.type.ptr,
|
||||
(int)rdata->msg_info.msg->body->content_type.subtype.slen,
|
||||
rdata->msg_info.msg->body->content_type.subtype.ptr);
|
||||
pos++;
|
||||
|
||||
body_pos = pos;
|
||||
attrs[pos].type = AST_MSG_DATA_ATTR_BODY;
|
||||
attrs[pos].value = ast_malloc(rdata->msg_info.msg->body->len + 1);
|
||||
if (!attrs[pos].value) {
|
||||
send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, dlg, tsx);
|
||||
return 0;
|
||||
}
|
||||
ast_copy_string(attrs[pos].value, rdata->msg_info.msg->body->data, rdata->msg_info.msg->body->len);
|
||||
pos++;
|
||||
|
||||
msg = ast_msg_data_alloc(AST_MSG_DATA_SOURCE_TYPE_IN_DIALOG, attrs, pos);
|
||||
if (!msg) {
|
||||
ast_free(attrs[body_pos].value);
|
||||
send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, dlg, tsx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_debug(3, "Received in dialog SIP message\n");
|
||||
ast_debug(1, "Received in-dialog MESSAGE from '%s:%s': %s %s\n",
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_FROM),
|
||||
ast_channel_name(session->channel),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_TO),
|
||||
ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY));
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
f.frametype = AST_FRAME_TEXT;
|
||||
f.subclass.integer = 0;
|
||||
f.offset = 0;
|
||||
f.data.ptr = buf;
|
||||
f.datalen = strlen(buf) + 1;
|
||||
ast_queue_frame(session->channel, &f);
|
||||
rc = ast_msg_data_queue_frame(session->channel, msg);
|
||||
ast_free(attrs[body_pos].value);
|
||||
ast_free(msg);
|
||||
if (rc != 0) {
|
||||
send_response(rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, dlg, tsx);
|
||||
} else {
|
||||
send_response(rdata, PJSIP_SC_ACCEPTED, dlg, tsx);
|
||||
}
|
||||
|
||||
send_response(rdata, PJSIP_SC_ACCEPTED, dlg, tsx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user