mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-10 11:58:08 +00:00
Merge "AMI: Escape string values." into 13
This commit is contained in:
@@ -309,6 +309,59 @@ char *ast_unescape_semicolon(char *s);
|
||||
*/
|
||||
char *ast_unescape_c(char *s);
|
||||
|
||||
/*!
|
||||
* \brief Escape the 'to_escape' characters in the given string.
|
||||
*
|
||||
* \note The given output buffer has to have enough memory allocated to store the
|
||||
* original string plus any escaped values.
|
||||
*
|
||||
* \param dest the escaped string
|
||||
* \param s the source string to escape
|
||||
* \param num number of characters to be copied from the source
|
||||
* \param to_escape an array of characters to escape
|
||||
*
|
||||
* \return Pointer to the destination.
|
||||
*/
|
||||
char* ast_escape(char *dest, const char *s, size_t num, const char *to_escape);
|
||||
|
||||
/*!
|
||||
* \brief Escape standard 'C' sequences in the given string.
|
||||
*
|
||||
* \note The given output buffer has to have enough memory allocated to store the
|
||||
* original string plus any escaped values.
|
||||
*
|
||||
* \param dest the escaped string
|
||||
* \param s the source string to escape
|
||||
* \param num number of characters to be copied from the source
|
||||
* \param to_escape an array of characters to escape
|
||||
*
|
||||
* \return Pointer to the escaped string.
|
||||
*/
|
||||
char* ast_escape_c(char *dest, const char *s, size_t num);
|
||||
|
||||
/*!
|
||||
* \brief Escape the 'to_escape' characters in the given string.
|
||||
*
|
||||
* \note Caller is responsible for freeing the returned string
|
||||
*
|
||||
* \param s the source string to escape
|
||||
* \param to_escape an array of characters to escape
|
||||
*
|
||||
* \return Pointer to the escaped string or NULL.
|
||||
*/
|
||||
char *ast_escape_alloc(const char *s, const char *to_escape);
|
||||
|
||||
/*!
|
||||
* \brief Escape standard 'C' sequences in the given string.
|
||||
*
|
||||
* \note Caller is responsible for freeing the returned string
|
||||
*
|
||||
* \param s the source string to escape
|
||||
*
|
||||
* \return Pointer to the escaped string or NULL.
|
||||
*/
|
||||
char *ast_escape_c_alloc(const char *s);
|
||||
|
||||
/*!
|
||||
\brief Size-limited null-terminating string copy.
|
||||
\param dst The destination buffer.
|
||||
|
||||
@@ -408,6 +408,7 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
|
||||
{
|
||||
struct ast_str *out = ast_str_create(1024);
|
||||
int res = 0;
|
||||
char *caller_name, *connected_name;
|
||||
|
||||
if (!out) {
|
||||
return NULL;
|
||||
@@ -418,6 +419,9 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
caller_name = ast_escape_c_alloc(snapshot->caller_name);
|
||||
connected_name = ast_escape_c_alloc(snapshot->connected_name);
|
||||
|
||||
res = ast_str_set(&out, 0,
|
||||
"%sChannel: %s\r\n"
|
||||
"%sChannelState: %u\r\n"
|
||||
@@ -436,9 +440,9 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
|
||||
prefix, snapshot->state,
|
||||
prefix, ast_state2str(snapshot->state),
|
||||
prefix, S_OR(snapshot->caller_number, "<unknown>"),
|
||||
prefix, S_OR(snapshot->caller_name, "<unknown>"),
|
||||
prefix, S_OR(caller_name, "<unknown>"),
|
||||
prefix, S_OR(snapshot->connected_number, "<unknown>"),
|
||||
prefix, S_OR(snapshot->connected_name, "<unknown>"),
|
||||
prefix, S_OR(connected_name, "<unknown>"),
|
||||
prefix, snapshot->language,
|
||||
prefix, snapshot->accountcode,
|
||||
prefix, snapshot->context,
|
||||
@@ -448,18 +452,26 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
|
||||
|
||||
if (!res) {
|
||||
ast_free(out);
|
||||
ast_free(caller_name);
|
||||
ast_free(connected_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (snapshot->manager_vars) {
|
||||
struct ast_var_t *var;
|
||||
char *val;
|
||||
AST_LIST_TRAVERSE(snapshot->manager_vars, var, entries) {
|
||||
val = ast_escape_c_alloc(var->value);
|
||||
ast_str_append(&out, 0, "%sChanVariable: %s=%s\r\n",
|
||||
prefix,
|
||||
var->name, var->value);
|
||||
var->name, S_OR(val, ""));
|
||||
ast_free(val);
|
||||
}
|
||||
}
|
||||
|
||||
ast_free(caller_name);
|
||||
ast_free(connected_name);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -556,6 +568,9 @@ static struct ast_manager_event_blob *channel_new_callerid(
|
||||
struct ast_channel_snapshot *old_snapshot,
|
||||
struct ast_channel_snapshot *new_snapshot)
|
||||
{
|
||||
struct ast_manager_event_blob *res;
|
||||
char *callerid;
|
||||
|
||||
/* No NewCallerid event on cache clear or first event */
|
||||
if (!old_snapshot || !new_snapshot) {
|
||||
return NULL;
|
||||
@@ -565,11 +580,19 @@ static struct ast_manager_event_blob *channel_new_callerid(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ast_manager_event_blob_create(
|
||||
if (!(callerid = ast_escape_c_alloc(
|
||||
ast_describe_caller_presentation(new_snapshot->caller_pres)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = ast_manager_event_blob_create(
|
||||
EVENT_FLAG_CALL, "NewCallerid",
|
||||
"CID-CallingPres: %d (%s)\r\n",
|
||||
new_snapshot->caller_pres,
|
||||
ast_describe_caller_presentation(new_snapshot->caller_pres));
|
||||
callerid);
|
||||
|
||||
ast_free(callerid);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct ast_manager_event_blob *channel_new_connected_line(
|
||||
|
||||
@@ -393,14 +393,23 @@ int ast_presence_state_engine_init(void)
|
||||
static struct ast_manager_event_blob *presence_state_to_ami(struct stasis_message *msg)
|
||||
{
|
||||
struct ast_presence_state_message *presence_state = stasis_message_data(msg);
|
||||
struct ast_manager_event_blob *res;
|
||||
|
||||
return ast_manager_event_blob_create(EVENT_FLAG_CALL, "PresenceStateChange",
|
||||
char *subtype = ast_escape_c_alloc(presence_state->subtype);
|
||||
char *message = ast_escape_c_alloc(presence_state->message);
|
||||
|
||||
res = ast_manager_event_blob_create(EVENT_FLAG_CALL, "PresenceStateChange",
|
||||
"Presentity: %s\r\n"
|
||||
"Status: %s\r\n"
|
||||
"Subtype: %s\r\n"
|
||||
"Message: %s\r\n",
|
||||
presence_state->provider,
|
||||
ast_presence_state2str(presence_state->state),
|
||||
presence_state->subtype,
|
||||
presence_state->message);
|
||||
subtype ?: "",
|
||||
message ?: "");
|
||||
|
||||
ast_free(subtype);
|
||||
ast_free(message);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -793,8 +793,12 @@ static struct ast_manager_event_blob *varset_to_ami(struct stasis_message *msg)
|
||||
struct ast_channel_blob *obj = stasis_message_data(msg);
|
||||
const char *variable =
|
||||
ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
|
||||
const char *value =
|
||||
ast_json_string_get(ast_json_object_get(obj->blob, "value"));
|
||||
RAII_VAR(char *, value, ast_escape_c_alloc(
|
||||
ast_json_string_get(ast_json_object_get(obj->blob, "value"))), ast_free);
|
||||
|
||||
if (!value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (obj->snapshot) {
|
||||
channel_event_string =
|
||||
@@ -1713,4 +1717,4 @@ static void remove_dial_masquerade_caller(struct ast_channel *caller)
|
||||
|
||||
ast_channel_datastore_remove(caller, datastore);
|
||||
ast_datastore_free(datastore);
|
||||
}
|
||||
}
|
||||
|
||||
108
main/utils.c
108
main/utils.c
@@ -1623,6 +1623,114 @@ char *ast_unescape_c(char *src)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard escape sequences - Note, '\0' is not included as a valid character
|
||||
* to escape, but instead is used here as a NULL terminator for the string.
|
||||
*/
|
||||
char escape_sequences[] = {
|
||||
'\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\'', '\"', '\?', '\0'
|
||||
};
|
||||
|
||||
/*
|
||||
* Standard escape sequences output map (has to maintain matching order with
|
||||
* escape_sequences). '\0' is included here as a NULL terminator for the string.
|
||||
*/
|
||||
static char escape_sequences_map[] = {
|
||||
'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"', '?', '\0'
|
||||
};
|
||||
|
||||
char* ast_escape(char *dest, const char *s, size_t num, const char *to_escape)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!dest || ast_strlen_zero(s)) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(to_escape)) {
|
||||
ast_copy_string(dest, s, num);
|
||||
return dest;
|
||||
}
|
||||
|
||||
for (p = dest; *s && num--; ++s, ++p) {
|
||||
/* If in the list of characters to escape then escape it */
|
||||
if (strchr(to_escape, *s)) {
|
||||
/*
|
||||
* See if the character to escape is part of the standard escape
|
||||
* sequences. If so we'll have to use its mapped counterpart
|
||||
* otherwise just use the current character.
|
||||
*/
|
||||
char *c = strchr(escape_sequences, *s);
|
||||
*p++ = '\\';
|
||||
*p = c ? escape_sequences_map[c - escape_sequences] : *s;
|
||||
} else {
|
||||
*p = *s;
|
||||
}
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
char* ast_escape_c(char *dest, const char *s, size_t num)
|
||||
{
|
||||
/*
|
||||
* Note - This is an optimized version of ast_escape. When looking only
|
||||
* for escape_sequences a couple of checks used in the generic case can
|
||||
* be left out thus making it slightly more efficient.
|
||||
*/
|
||||
char *p;
|
||||
|
||||
if (!dest || ast_strlen_zero(s)) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
for (p = dest; *s && num--; ++s, ++p) {
|
||||
/*
|
||||
* See if the character to escape is part of the standard escape
|
||||
* sequences. If so use its mapped counterpart.
|
||||
*/
|
||||
char *c = strchr(escape_sequences, *s);
|
||||
if (c) {
|
||||
*p++ = '\\';
|
||||
*p = escape_sequences_map[c - escape_sequences];
|
||||
} else {
|
||||
*p = *s;
|
||||
}
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
static char *escape_alloc(const char *s, size_t *size)
|
||||
{
|
||||
if (!s || !(*size = strlen(s))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The result string needs to be twice the size of the given
|
||||
* string just in case every character in it needs to be escaped.
|
||||
*/
|
||||
*size = *size * 2 + 1;
|
||||
return ast_calloc(sizeof(char), *size);
|
||||
}
|
||||
|
||||
char *ast_escape_alloc(const char *s, const char *to_escape)
|
||||
{
|
||||
size_t size = 0;
|
||||
char *dest = escape_alloc(s, &size);
|
||||
return ast_escape(dest, s, size, to_escape);
|
||||
}
|
||||
|
||||
char *ast_escape_c_alloc(const char *s)
|
||||
{
|
||||
size_t size = 0;
|
||||
char *dest = escape_alloc(s, &size);
|
||||
return ast_escape_c(dest, s, size);
|
||||
}
|
||||
|
||||
int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
|
||||
{
|
||||
int result;
|
||||
|
||||
@@ -455,6 +455,38 @@ AST_TEST_DEFINE(escape_semicolons_test)
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(escape_test)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
#define TEST_ESCAPE(s, to_escape, expected) \
|
||||
!strcmp(ast_escape(buf, s, sizeof(buf) / sizeof(char), to_escape), expected)
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "escape";
|
||||
info->category = "/main/strings/";
|
||||
info->summary = "Test ast_escape";
|
||||
info->description = "Test escaping values in a string";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
ast_test_validate(test, TEST_ESCAPE("null escape", NULL, "null escape"));
|
||||
ast_test_validate(test, TEST_ESCAPE("no matching escape", "Z", "no matching escape"));
|
||||
ast_test_validate(test, TEST_ESCAPE("escape Z", "Z", "escape \\Z"));
|
||||
ast_test_validate(test, TEST_ESCAPE("Z", "Z", "\\Z"));
|
||||
ast_test_validate(test, TEST_ESCAPE(";;", ";;", "\\;\\;"));
|
||||
ast_test_validate(test, TEST_ESCAPE("escape \n", "\n", "escape \\n"));
|
||||
ast_test_validate(test, TEST_ESCAPE("escape \n again \n", "\n", "escape \\n again \\n"));
|
||||
|
||||
ast_test_validate(test, !strcmp(ast_escape_c(buf, "escape \a\b\f\n\r\t\v\\\'\"\?",
|
||||
sizeof(buf) / sizeof(char)),
|
||||
"escape \\a\\b\\f\\n\\r\\t\\v\\\\\\\'\\\"\\?"));
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
AST_TEST_UNREGISTER(str_test);
|
||||
@@ -462,6 +494,7 @@ static int unload_module(void)
|
||||
AST_TEST_UNREGISTER(ends_with_test);
|
||||
AST_TEST_UNREGISTER(strsep_test);
|
||||
AST_TEST_UNREGISTER(escape_semicolons_test);
|
||||
AST_TEST_UNREGISTER(escape_test);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -472,6 +505,7 @@ static int load_module(void)
|
||||
AST_TEST_REGISTER(ends_with_test);
|
||||
AST_TEST_REGISTER(strsep_test);
|
||||
AST_TEST_REGISTER(escape_semicolons_test);
|
||||
AST_TEST_REGISTER(escape_test);
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user