Improve groupcount handling (bug #2529) thanks!

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3898 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.2-netsec
Mark Spencer 22 years ago
parent b4142e0cd2
commit 292e397759

108
app.c

@ -19,6 +19,8 @@
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <regex.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/file.h>
@ -961,3 +963,109 @@ int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordf
return res;
}
/* Channel group core functions */
int ast_app_group_split_group(char *data, char *group, int group_max, char *category, int category_max)
{
int res=0;
char tmp[256] = "";
char *grp=NULL, *cat=NULL;
if (data && !ast_strlen_zero(data)) {
strncpy(tmp, data, sizeof(tmp) - 1);
grp = tmp;
cat = strchr(tmp, '@');
if (cat) {
*cat = '\0';
cat++;
}
}
if (grp && !ast_strlen_zero(grp))
strncpy(group, grp, group_max -1);
else
res = -1;
if (cat)
snprintf(category, category_max, "%s_%s", GROUP_CATEGORY_PREFIX, cat);
else
strncpy(category, GROUP_CATEGORY_PREFIX, category_max - 1);
return res;
}
int ast_app_group_set_channel(struct ast_channel *chan, char *data)
{
int res=0;
char group[80] = "";
char category[80] = "";
if (!ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
pbx_builtin_setvar_helper(chan, category, group);
} else
res = -1;
return res;
}
int ast_app_group_get_count(char *group, char *category)
{
struct ast_channel *chan;
int count = 0;
char *test;
char cat[80] = "";
if (category && !ast_strlen_zero(category)) {
strncpy(cat, category, sizeof(cat) - 1);
} else {
strncpy(cat, GROUP_CATEGORY_PREFIX, sizeof(cat) - 1);
}
if (group && !ast_strlen_zero(group)) {
chan = ast_channel_walk_locked(NULL);
while(chan) {
test = pbx_builtin_getvar_helper(chan, cat);
if (test && !strcasecmp(test, group))
count++;
ast_mutex_unlock(&chan->lock);
chan = ast_channel_walk_locked(chan);
}
}
return count;
}
int ast_app_group_match_get_count(char *groupmatch, char *category)
{
regex_t regexbuf;
struct ast_channel *chan;
int count = 0;
char *test;
char cat[80] = "";
if (!groupmatch || ast_strlen_zero(groupmatch))
return 0;
/* if regex compilation fails, return zero matches */
if (regcomp(&regexbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
return 0;
if (category && !ast_strlen_zero(category)) {
strncpy(cat, category, sizeof(cat) - 1);
} else {
strncpy(cat, GROUP_CATEGORY_PREFIX, sizeof(cat) - 1);
}
chan = ast_channel_walk_locked(NULL);
while(chan) {
test = pbx_builtin_getvar_helper(chan, cat);
if (test && !regexec(&regexbuf, test, 0, NULL, 0))
count++;
ast_mutex_unlock(&chan->lock);
chan = ast_channel_walk_locked(chan);
}
regfree(&regexbuf);
return count;
}

@ -15,6 +15,8 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
@ -22,125 +24,73 @@
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/utils.h>
#include <asterisk/cli.h>
#include <asterisk/app.h>
static char *tdesc = "Group Management Routines";
STANDARD_LOCAL_USER;
static char *app_group_count = "GetGroupCount";
static char *app_group_set = "SetGroup";
static char *app_group_check = "CheckGroup";
LOCAL_USER_DECL;
static char *group_count_synopsis = "GetGroupCount([groupname][@category])";
static char *group_set_synopsis = "SetGroup(groupname[@category])";
static char *group_check_synopsis = "CheckGroup(max[@category])";
static int group_count_exec(struct ast_channel *chan, void *data)
{
int res = 0;
int count;
struct localuser *u;
char group[80] = "";
char category[80] = "";
char ret[80] = "";
char *grp;
static char *group_count_descrip =
"GetGroupCount([group][@category])\n"
" Calculates the group count for the specified group, or uses\n"
"the current channel's group if not specifed (and non-empty).\n"
"Stores result in GROUPCOUNT. Always returns 0.\n";
LOCAL_USER_ADD(u);
static char *group_set_descrip =
"SetGroup(group)\n"
" Sets the channel group to the specified value. Equivalent to\n"
"SetVar(GROUP=group). Always returns 0.\n";
ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
static char *group_check_descrip =
"CheckGroup(max)\n"
" Checks that the current number of total channels in the\n"
"current channel's group does not exceed 'max'. If the number\n"
"does not exceed 'max', we continue to the next step. If the\n"
"number does in fact exceed max, if priority n+101 exists, then\n"
"execution continues at that step, otherwise -1 is returned.\n";
STANDARD_LOCAL_USER;
if (ast_strlen_zero(group)) {
grp = pbx_builtin_getvar_helper(chan, category);
strncpy(group, grp, sizeof(group) - 1);
}
LOCAL_USER_DECL;
count = ast_app_group_get_count(group, category);
snprintf(ret, sizeof(ret), "%d", count);
pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
#define DEFAULT_CATEGORY "GROUP"
LOCAL_USER_REMOVE(u);
static int group_get_count(char *group, char *category)
{
struct ast_channel *chan;
int count = 0;
char *test;
if (group && !ast_strlen_zero(group)) {
chan = ast_channel_walk_locked(NULL);
while(chan) {
test = pbx_builtin_getvar_helper(chan, category);
if (test && !strcasecmp(test, group))
count++;
ast_mutex_unlock(&chan->lock);
chan = ast_channel_walk_locked(chan);
}
}
return count;
return res;
}
static int group_count_exec(struct ast_channel *chan, void *data)
static int group_match_count_exec(struct ast_channel *chan, void *data)
{
int res=0;
int res = 0;
int count;
struct localuser *u;
char *group=NULL;
char *cat = NULL;
char ret[80]="";
char tmp[256]="";
char group[80] = "";
char category[80] = "";
char ret[80] = "";
LOCAL_USER_ADD(u);
/* Check and parse arguments */
if (data && !ast_strlen_zero(data)) {
strncpy(tmp, data, sizeof(tmp) - 1);
group = tmp;
cat = strchr(tmp, '@');
if (cat) {
*cat = '\0';
cat++;
}
}
if (cat)
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
else
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
if (!group || ast_strlen_zero(group)) {
group = pbx_builtin_getvar_helper(chan, ret);
if (!ast_strlen_zero(group)) {
count = ast_app_group_match_get_count(group, category);
snprintf(ret, sizeof(ret), "%d", count);
pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
}
count = group_get_count(group, ret);
snprintf(ret, sizeof(ret), "%d", count);
pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
LOCAL_USER_REMOVE(u);
return res;
}
static int group_set_exec(struct ast_channel *chan, void *data)
{
int res=0;
int res = 0;
struct localuser *u;
char ret[80] = "";
char tmp[256] = "";
char *cat=NULL, *group=NULL;
LOCAL_USER_ADD(u);
/* Check and parse arguments */
if (data && !ast_strlen_zero(data)) {
strncpy(tmp, data, sizeof(tmp) - 1);
group = tmp;
cat = strchr(tmp, '@');
if (cat) {
*cat = '\0';
cat++;
}
}
if (cat)
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
else
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
if (group && !ast_strlen_zero(group)) {
pbx_builtin_setvar_helper(chan, ret, group);
} else
if (ast_app_group_set_channel(chan, data))
ast_log(LOG_WARNING, "SetGroup requires an argument (group name)\n");
LOCAL_USER_REMOVE(u);
@ -149,51 +99,139 @@ static int group_set_exec(struct ast_channel *chan, void *data)
static int group_check_exec(struct ast_channel *chan, void *data)
{
int res=0;
int res = 0;
int max, count;
struct localuser *u;
char ret[80] = "";
char tmp[256] = "";
char *cat, *group;
char limit[80]="";
char category[80]="";
LOCAL_USER_ADD(u);
if (data && !ast_strlen_zero(data)) {
strncpy(tmp, data, sizeof(tmp) - 1);
group = tmp;
cat = strchr(tmp, '@');
if (cat) {
*cat = '\0';
cat++;
}
if ((sscanf((char *)tmp, "%i", &max) == 1) && (max > -1)) {
if (cat)
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
if (!data || ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "CheckGroup requires an argument(max[@category])\n");
return res;
}
ast_app_group_split_group(data, limit, sizeof(limit), category, sizeof(category));
if ((sscanf(limit, "%i", &max) == 1) && (max > -1)) {
count = ast_app_group_get_count(pbx_builtin_getvar_helper(chan, category), category);
if (count > max) {
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num))
chan->priority += 100;
else
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
count = group_get_count(pbx_builtin_getvar_helper(chan, ret), ret);
if (count > max) {
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num))
chan->priority += 100;
else
res = -1;
}
} else
ast_log(LOG_WARNING, "CheckGroup requires a positive integer argument (max)\n");
res = -1;
}
} else
ast_log(LOG_WARNING, "CheckGroup requires an argument(max)\n");
ast_log(LOG_WARNING, "CheckGroup requires a positive integer argument (max)\n");
LOCAL_USER_REMOVE(u);
return res;
}
static int group_show_channels(int fd, int argc, char *argv[])
{
#define FORMAT_STRING "%-25s %-20s %-20s\n"
struct ast_channel *c = NULL;
int numchans = 0;
struct ast_var_t *current;
struct varshead *headp;
regex_t regexbuf;
int havepattern = 0;
if (argc < 3 || argc > 4)
return RESULT_SHOWUSAGE;
if (argc == 4) {
if (regcomp(&regexbuf, argv[3], REG_EXTENDED | REG_NOSUB))
return RESULT_SHOWUSAGE;
havepattern = 1;
}
c = ast_channel_walk_locked(NULL);
ast_cli(fd, FORMAT_STRING, "Channel", "Group", "Category");
while(c) {
headp=&c->varshead;
AST_LIST_TRAVERSE(headp,current,entries) {
if (!strncmp(ast_var_name(current), GROUP_CATEGORY_PREFIX "_", strlen(GROUP_CATEGORY_PREFIX) + 1)) {
if (!havepattern || !regexec(&regexbuf, ast_var_value(current), 0, NULL, 0)) {
ast_cli(fd, FORMAT_STRING, c->name, ast_var_value(current),
(ast_var_name(current) + strlen(GROUP_CATEGORY_PREFIX) + 1));
numchans++;
}
} else if (!strcmp(ast_var_name(current), GROUP_CATEGORY_PREFIX)) {
if (!havepattern || !regexec(&regexbuf, ast_var_value(current), 0, NULL, 0)) {
ast_cli(fd, FORMAT_STRING, c->name, ast_var_value(current), "(default)");
numchans++;
}
}
}
numchans++;
ast_mutex_unlock(&c->lock);
c = ast_channel_walk_locked(c);
}
if (havepattern)
regfree(&regexbuf);
ast_cli(fd, "%d active channel(s)\n", numchans);
return RESULT_SUCCESS;
}
static char *tdesc = "Group Management Routines";
static char *app_group_count = "GetGroupCount";
static char *app_group_set = "SetGroup";
static char *app_group_check = "CheckGroup";
static char *app_group_match_count = "GetGroupMatchCount";
static char *group_count_synopsis = "GetGroupCount([groupname][@category])";
static char *group_set_synopsis = "SetGroup(groupname[@category])";
static char *group_check_synopsis = "CheckGroup(max[@category])";
static char *group_match_count_synopsis = "GetGroupMatchCount(groupmatch[@category])";
static char *group_count_descrip =
"GetGroupCount([group][@category])\n"
" Calculates the group count for the specified group, or uses\n"
"the current channel's group if not specifed (and non-empty).\n"
"Stores result in GROUPCOUNT. Always returns 0.\n";
static char *group_set_descrip =
"SetGroup(group)\n"
" Sets the channel group to the specified value. Equivalent to\n"
"SetVar(GROUP=group). Always returns 0.\n";
static char *group_check_descrip =
"CheckGroup(max[@category])\n"
" Checks that the current number of total channels in the\n"
"current channel's group does not exceed 'max'. If the number\n"
"does not exceed 'max', we continue to the next step. If the\n"
"number does in fact exceed max, if priority n+101 exists, then\n"
"execution continues at that step, otherwise -1 is returned.\n";
static char *group_match_count_descrip =
"GetGroupMatchCount(groupmatch[@category])\n"
" Calculates the group count for all groups that match the specified\n"
"pattern. Uses standard regular expression matching (see regex(7)).\n"
"Stores result in GROUPCOUNT. Always returns 0.\n";
static char show_channels_usage[] =
"Usage: group show channels [pattern]\n"
" Lists all currently active channels with channel group(s) specified.\n Optional regular expression pattern is matched to group names for each channel.\n";
static struct ast_cli_entry cli_show_channels =
{ { "group", "show", "channels", NULL }, group_show_channels, "Show active channels with group(s)", show_channels_usage};
int unload_module(void)
{
int res;
STANDARD_HANGUP_LOCALUSERS;
ast_cli_unregister(&cli_show_channels);
res = ast_unregister_application(app_group_count);
res |= ast_unregister_application(app_group_set);
res |= ast_unregister_application(app_group_check);
res |= ast_unregister_application(app_group_match_count);
return res;
}
@ -203,6 +241,8 @@ int load_module(void)
res = ast_register_application(app_group_count, group_count_exec, group_count_synopsis, group_count_descrip);
res |= ast_register_application(app_group_set, group_set_exec, group_set_synopsis, group_set_descrip);
res |= ast_register_application(app_group_check, group_check_exec, group_check_synopsis, group_check_descrip);
res |= ast_register_application(app_group_match_count, group_match_count_exec, group_match_count_synopsis, group_match_count_descrip);
ast_cli_register(&cli_show_channels);
return res;
}

@ -68,6 +68,20 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
// permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults.
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence_ms);
#define GROUP_CATEGORY_PREFIX "GROUP"
//! Split a group string into group and category, returning a default category if none is provided.
int ast_app_group_split_group(char *data, char *group, int group_max, char *category, int category_max);
//! Set the group for a channel, splitting the provided data into group and category, if specified.
int ast_app_group_set_channel(struct ast_channel *chan, char *data);
//! Get the current channel count of the specified group and category.
int ast_app_group_get_count(char *group, char *category);
//! Get the current channel count of all groups that match the specified pattern and category.
int ast_app_group_match_get_count(char *groupmatch, char *category);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

Loading…
Cancel
Save