mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-19 19:52:48 +00:00
Add LISTFILTER dialplan function, along with supporting documentation. See
documentation for more information on how to use it. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@154915 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -32,6 +32,9 @@ Dialplan Functions
|
|||||||
* Added debugging CLI functions to func_odbc, 'odbc read' and 'odbc write'.
|
* Added debugging CLI functions to func_odbc, 'odbc read' and 'odbc write'.
|
||||||
* func_odbc now may specify an insert query to execute, when the write query
|
* func_odbc now may specify an insert query to execute, when the write query
|
||||||
affects 0 rows (usually indicating that no such row exists).
|
affects 0 rows (usually indicating that no such row exists).
|
||||||
|
* Added a new dialplan function, LISTFILTER, which permits removing elements
|
||||||
|
from a set list, by name. Uses the same general syntax as the existing CUT
|
||||||
|
and FIELDQTY dialplan functions, which also manage lists.
|
||||||
|
|
||||||
Applications
|
Applications
|
||||||
------------
|
------------
|
||||||
|
@@ -39,6 +39,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include "asterisk/app.h"
|
#include "asterisk/app.h"
|
||||||
#include "asterisk/localtime.h"
|
#include "asterisk/localtime.h"
|
||||||
|
|
||||||
|
AST_THREADSTORAGE(result_buf);
|
||||||
|
|
||||||
/*** DOCUMENTATION
|
/*** DOCUMENTATION
|
||||||
<function name="FIELDQTY" language="en_US">
|
<function name="FIELDQTY" language="en_US">
|
||||||
<synopsis>
|
<synopsis>
|
||||||
@@ -52,6 +54,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
<para>Example: ${FIELDQTY(ex-amp-le,-)} returns 3</para>
|
<para>Example: ${FIELDQTY(ex-amp-le,-)} returns 3</para>
|
||||||
</description>
|
</description>
|
||||||
</function>
|
</function>
|
||||||
|
<function name="LISTFILTER" language="en_US">
|
||||||
|
<synopsis>Remove an item from a list, by name.</synopsis>
|
||||||
|
<syntax>
|
||||||
|
<parameter name="varname" required="true" />
|
||||||
|
<parameter name="delim" required="true" default="," />
|
||||||
|
<parameter name="value" required="true" />
|
||||||
|
</syntax>
|
||||||
|
<description>
|
||||||
|
<para>Remove <replaceable>value</replaceable> from the list contained in the <replaceable>varname</replaceable>
|
||||||
|
variable, where the list delimiter is specified by the <replaceable>delim</replaceable> parameter. This is
|
||||||
|
very useful for removing a single channel name from a list of channels, for example.</para>
|
||||||
|
</description>
|
||||||
|
</function>
|
||||||
<function name="FILTER" language="en_US">
|
<function name="FILTER" language="en_US">
|
||||||
<synopsis>
|
<synopsis>
|
||||||
Filter the string to include only the allowed characters
|
Filter the string to include only the allowed characters
|
||||||
@@ -322,6 +337,105 @@ static struct ast_custom_function fieldqty_function = {
|
|||||||
.read = function_fieldqty,
|
.read = function_fieldqty,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
AST_DECLARE_APP_ARGS(args,
|
||||||
|
AST_APP_ARG(listname);
|
||||||
|
AST_APP_ARG(delimiter);
|
||||||
|
AST_APP_ARG(fieldvalue);
|
||||||
|
);
|
||||||
|
const char *orig_list, *ptr;
|
||||||
|
const char *begin, *cur, *next;
|
||||||
|
int dlen, flen;
|
||||||
|
struct ast_str *result = ast_str_thread_get(&result_buf, 16);
|
||||||
|
char *delim;
|
||||||
|
|
||||||
|
AST_STANDARD_APP_ARGS(args, parse);
|
||||||
|
|
||||||
|
if (args.argc < 3) {
|
||||||
|
ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't lock the channel, the variable could disappear out from underneath us. */
|
||||||
|
if (chan) {
|
||||||
|
ast_channel_lock(chan);
|
||||||
|
}
|
||||||
|
if (!(orig_list = pbx_builtin_getvar_helper(chan, args.listname))) {
|
||||||
|
ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname);
|
||||||
|
if (chan) {
|
||||||
|
ast_channel_unlock(chan);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the string isn't there, just copy out the string and be done with it. */
|
||||||
|
if (!(ptr = strstr(orig_list, args.fieldvalue))) {
|
||||||
|
ast_copy_string(buf, orig_list, len);
|
||||||
|
if (chan) {
|
||||||
|
ast_channel_unlock(chan);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlen = strlen(args.delimiter);
|
||||||
|
delim = alloca(dlen + 1);
|
||||||
|
ast_get_encoded_str(args.delimiter, delim, dlen + 1);
|
||||||
|
|
||||||
|
if ((dlen = strlen(delim)) == 0) {
|
||||||
|
delim = ",";
|
||||||
|
dlen = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flen = strlen(args.fieldvalue);
|
||||||
|
|
||||||
|
ast_str_reset(result);
|
||||||
|
/* Enough space for any result */
|
||||||
|
ast_str_make_space(&result, strlen(orig_list) + 1);
|
||||||
|
|
||||||
|
begin = orig_list;
|
||||||
|
next = strstr(begin, delim);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Find next boundary */
|
||||||
|
if (next) {
|
||||||
|
cur = next;
|
||||||
|
next = strstr(cur + dlen, delim);
|
||||||
|
} else {
|
||||||
|
cur = strchr(begin + dlen, '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flen == cur - begin && !strncmp(begin, args.fieldvalue, flen)) {
|
||||||
|
/* Skip field */
|
||||||
|
begin += flen + dlen;
|
||||||
|
} else {
|
||||||
|
/* Copy field to output */
|
||||||
|
if (result->used) {
|
||||||
|
ast_str_append(&result, 0, "%s", delim);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Have to do it this way, since we're not null-terminated. */
|
||||||
|
strncpy(result->str + result->used, begin, cur - begin);
|
||||||
|
result->used += cur - begin;
|
||||||
|
result->str[result->used] = '\0';
|
||||||
|
|
||||||
|
begin = cur + dlen;
|
||||||
|
}
|
||||||
|
} while (*cur != '\0');
|
||||||
|
if (chan) {
|
||||||
|
ast_channel_unlock(chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_copy_string(buf, result->str, len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_custom_function listfilter_function = {
|
||||||
|
.name = "LISTFILTER",
|
||||||
|
.read = listfilter,
|
||||||
|
};
|
||||||
|
|
||||||
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
|
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
@@ -997,6 +1111,7 @@ static int unload_module(void)
|
|||||||
|
|
||||||
res |= ast_custom_function_unregister(&fieldqty_function);
|
res |= ast_custom_function_unregister(&fieldqty_function);
|
||||||
res |= ast_custom_function_unregister(&filter_function);
|
res |= ast_custom_function_unregister(&filter_function);
|
||||||
|
res |= ast_custom_function_unregister(&listfilter_function);
|
||||||
res |= ast_custom_function_unregister(®ex_function);
|
res |= ast_custom_function_unregister(®ex_function);
|
||||||
res |= ast_custom_function_unregister(&array_function);
|
res |= ast_custom_function_unregister(&array_function);
|
||||||
res |= ast_custom_function_unregister("e_function);
|
res |= ast_custom_function_unregister("e_function);
|
||||||
@@ -1021,6 +1136,7 @@ static int load_module(void)
|
|||||||
|
|
||||||
res |= ast_custom_function_register(&fieldqty_function);
|
res |= ast_custom_function_register(&fieldqty_function);
|
||||||
res |= ast_custom_function_register(&filter_function);
|
res |= ast_custom_function_register(&filter_function);
|
||||||
|
res |= ast_custom_function_register(&listfilter_function);
|
||||||
res |= ast_custom_function_register(®ex_function);
|
res |= ast_custom_function_register(®ex_function);
|
||||||
res |= ast_custom_function_register(&array_function);
|
res |= ast_custom_function_register(&array_function);
|
||||||
res |= ast_custom_function_register("e_function);
|
res |= ast_custom_function_register("e_function);
|
||||||
|
@@ -488,6 +488,9 @@ int ast_record_review(struct ast_channel *chan, const char *playfile, const char
|
|||||||
/*! \brief Decode an encoded control or extended ASCII character */
|
/*! \brief Decode an encoded control or extended ASCII character */
|
||||||
int ast_get_encoded_char(const char *stream, char *result, size_t *consumed);
|
int ast_get_encoded_char(const char *stream, char *result, size_t *consumed);
|
||||||
|
|
||||||
|
/*! \brief Decode a stream of encoded control or extended ASCII characters */
|
||||||
|
int ast_get_encoded_str(const char *stream, char *result, size_t result_len);
|
||||||
|
|
||||||
/*! \brief Common routine for child processes, to close all fds prior to exec(2) */
|
/*! \brief Common routine for child processes, to close all fds prior to exec(2) */
|
||||||
void ast_close_fds_above_n(int n);
|
void ast_close_fds_above_n(int n);
|
||||||
|
|
||||||
|
13
main/app.c
13
main/app.c
@@ -1815,6 +1815,19 @@ int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ast_get_encoded_str(const char *stream, char *result, size_t result_size)
|
||||||
|
{
|
||||||
|
char *cur = result;
|
||||||
|
size_t consumed;
|
||||||
|
|
||||||
|
while (cur < result + result_size - 1 && !ast_get_encoded_char(stream, cur, &consumed)) {
|
||||||
|
cur++;
|
||||||
|
stream += consumed;
|
||||||
|
}
|
||||||
|
*cur = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ast_close_fds_above_n(int n)
|
void ast_close_fds_above_n(int n)
|
||||||
{
|
{
|
||||||
int x, null;
|
int x, null;
|
||||||
|
Reference in New Issue
Block a user