dect
/
asterisk
Archived
13
0
Fork 0

Requested changes from Pari, reviewed by Russell.

Added ability to retrieve list of categories in a config file.
Added ability to retrieve the content of a particular category.
Added ability to empty a context.
Created new action to create a new file.
Updated delete action to allow deletion by line number with respect to category.
Added new action insert to add new variable to category at specified line.
Updated action newcat to allow new category to be inserted in file above another existing category.



git-svn-id: http://svn.digium.com/svn/asterisk/trunk@103331 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
jpeeler 2008-02-12 00:24:36 +00:00
parent 509fcae480
commit 3847faed34
4 changed files with 295 additions and 58 deletions

View File

@ -39,6 +39,14 @@ AMI - The manager (TCP/TLS/HTTP)
Reporting privilege, instead of only under Call or System.
* The IAX* commands now require either System or Reporting privilege, to
mirror the privileges of the SIP* commands.
* Added ability to retrieve list of categories in a config file.
* Added ability to retrieve the content of a particular category.
* Added ability to empty a context.
* Created new action to create a new file.
* Updated delete action to allow deletion by line number with respect to category.
* Added new action insert to add new variable to category at specified line.
* Updated action newcat to allow new category to be inserted in file above another
existing category.
Dialplan functions
------------------

View File

@ -254,7 +254,18 @@ const char *ast_config_option(struct ast_config *cfg, const char *cat, const cha
struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno);
void ast_category_append(struct ast_config *config, struct ast_category *cat);
/*!
* \brief Inserts new category
* \param config which config to use
* \param cat newly created category to insert
* \param match which category to insert above
* This function is used to insert a new category above another category
* matching the match parameter.
*/
void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match);
int ast_category_delete(struct ast_config *cfg, const char *category);
int ast_category_empty(struct ast_config *cfg, const char *category);
void ast_category_destroy(struct ast_category *cat);
struct ast_variable *ast_category_detach_variables(struct ast_category *cat);
void ast_category_rename(struct ast_category *cat, const char *name);
@ -264,7 +275,8 @@ struct ast_config_include *ast_include_new(struct ast_config *conf, const char *
struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match);
void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line);
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line);
int ast_variable_update(struct ast_category *category, const char *variable,
const char *value, const char *match, unsigned int object);

View File

@ -354,6 +354,28 @@ void ast_variable_append(struct ast_category *category, struct ast_variable *var
category->last = category->last->next;
}
void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
{
struct ast_variable *cur = category->root;
int lineno;
int insertline;
if (!variable || sscanf(line, "%d", &insertline) != 1)
return;
if (!insertline) {
variable->next = category->root;
category->root = variable;
} else {
for (lineno = 1; lineno < insertline; lineno++) {
cur = cur->next;
if (!cur->next)
break;
}
variable->next = cur->next;
cur->next = variable;
}
}
void ast_variables_destroy(struct ast_variable *v)
{
struct ast_variable *vn;
@ -481,6 +503,26 @@ void ast_category_append(struct ast_config *config, struct ast_category *categor
config->current = category;
}
void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
{
struct ast_category *cur_category;
if (!cat || !match)
return;
if (!strcasecmp(config->root->name, match)) {
cat->next = config->root;
config->root = cat;
return;
}
for (cur_category = config->root; cur_category; cur_category = cur_category->next) {
if (!strcasecmp(cur_category->next->name, match)) {
cat->next = cur_category->next;
cur_category->next = cat;
break;
}
}
}
static void ast_destroy_comments(struct ast_category *cat)
{
struct ast_comment *n, *p;
@ -629,10 +671,11 @@ struct ast_config *ast_config_new(void)
return config;
}
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match)
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
{
struct ast_variable *cur, *prev=NULL, *curn;
int res = -1;
int lineno = 0;
cur = category->root;
while (cur) {
@ -658,7 +701,7 @@ int ast_variable_delete(struct ast_category *category, const char *variable, con
cur = category->root;
while (cur) {
curn = cur->next;
if (!strcasecmp(cur->name, variable) && (ast_strlen_zero(match) || !strcasecmp(cur->value, match))) {
if ((!ast_strlen_zero(line) && lineno == atoi(line)) || (ast_strlen_zero(line) && !strcasecmp(cur->name, variable) && (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
if (prev) {
prev->next = cur->next;
if (cur == category->last)
@ -675,6 +718,7 @@ int ast_variable_delete(struct ast_category *category, const char *variable, con
prev = cur;
cur = curn;
lineno++;
}
return res;
}
@ -760,6 +804,22 @@ int ast_category_delete(struct ast_config *cfg, const char *category)
return -1;
}
int ast_category_empty(struct ast_config *cfg, const char *category)
{
struct ast_category *cat;
for (cat = cfg->root; cat; cat = cat->next) {
if (!strcasecmp(cat->name, category))
continue;
ast_variables_destroy(cat->root);
cat->root = NULL;
cat->last = NULL;
return 0;
}
return -1;
}
void ast_config_destroy(struct ast_config *cfg)
{
struct ast_category *cat, *catn;

View File

@ -74,6 +74,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/term.h"
#include "asterisk/astobj2.h"
enum error_type {
UNKNOWN_ACTION = 1,
UNKNOWN_CATEGORY,
UNSPECIFIED_CATEGORY,
UNSPECIFIED_ARGUMENT,
FAILURE_ALLOCATION,
FAILURE_DELCAT,
FAILURE_EMPTYCAT,
FAILURE_UPDATE,
FAILURE_DELETE,
FAILURE_APPEND
};
/*!
* Linked list of events.
* Global events are appended to the list by append_event().
@ -1053,17 +1067,19 @@ static int action_ping(struct mansession *s, const struct message *m)
static char mandescr_getconfig[] =
"Description: A 'GetConfig' action will dump the contents of a configuration\n"
"file by category and contents.\n"
"Variables:\n"
" Filename: Configuration filename (e.g. foo.conf)\n";
"file by category and contents or optionally by specified category only.\n"
"Variables: (Names marked with * are required)\n"
" *Filename: Configuration filename (e.g. foo.conf)\n"
" Category: Category in configuration file\n";
static int action_getconfig(struct mansession *s, const struct message *m)
{
struct ast_config *cfg;
const char *fn = astman_get_header(m, "Filename");
const char *category = astman_get_header(m, "Category");
int catcount = 0;
int lineno = 0;
char *category=NULL;
char *cur_category = NULL;
struct ast_variable *v;
struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
@ -1075,20 +1091,63 @@ static int action_getconfig(struct mansession *s, const struct message *m)
astman_send_error(s, m, "Config file not found");
return 0;
}
astman_start_ack(s, m);
while ((category = ast_category_browse(cfg, category))) {
lineno = 0;
astman_append(s, "Category-%06d: %s\r\n", catcount, category);
for (v = ast_variable_browse(cfg, category); v; v = v->next)
astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
catcount++;
while ((cur_category = ast_category_browse(cfg, cur_category))) {
if (ast_strlen_zero(category) || (!ast_strlen_zero(category) && !strcmp(category, cur_category))) {
lineno = 0;
astman_append(s, "Category-%06d: %s\r\n", catcount, cur_category);
for (v = ast_variable_browse(cfg, cur_category); v; v = v->next)
astman_append(s, "Line-%06d-%06d: %s=%s\r\n", catcount, lineno++, v->name, v->value);
catcount++;
}
}
if (!ast_strlen_zero(category) && catcount == 0) /* TODO: actually, a config with no categories doesn't even get loaded */
astman_append(s, "No categories found");
ast_config_destroy(cfg);
astman_append(s, "\r\n");
return 0;
}
static char mandescr_listcategories[] =
"Description: A 'ListCategories' action will dump the categories in\n"
"a given file.\n"
"Variables:\n"
" Filename: Configuration filename (e.g. foo.conf)\n";
static int action_listcategories(struct mansession *s, const struct message *m)
{
struct ast_config *cfg;
const char *fn = astman_get_header(m, "Filename");
char *category = NULL;
struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
int catcount = 0;
if (ast_strlen_zero(fn)) {
astman_send_error(s, m, "Filename not specified");
return 0;
}
if (!(cfg = ast_config_load(fn, config_flags))) {
astman_send_error(s, m, "Config file not found or file has invalid syntax");
return 0;
}
astman_start_ack(s, m);
while ((category = ast_category_browse(cfg, category))) {
astman_append(s, "Category-%06d: %s\r\n", catcount, category);
catcount++;
}
if (catcount == 0) /* TODO: actually, a config with no categories doesn't even get loaded */
astman_append(s, "Error: no categories found");
ast_config_destroy(cfg);
astman_append(s, "\r\n");
return 0;
}
/*! The amount of space in out must be at least ( 2 * strlen(in) + 1 ) */
static void json_escape(char *out, const char *in)
{
@ -1171,11 +1230,11 @@ static int action_getconfigjson(struct mansession *s, const struct message *m)
}
/* helper function for action_updateconfig */
static void handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
static enum error_type handle_updates(struct mansession *s, const struct message *m, struct ast_config *cfg, const char *dfn)
{
int x;
char hdr[40];
const char *action, *cat, *var, *value, *match;
const char *action, *cat, *var, *value, *match, *line;
struct ast_category *category;
struct ast_variable *v;
@ -1198,38 +1257,72 @@ static void handle_updates(struct mansession *s, const struct message *m, struct
}
snprintf(hdr, sizeof(hdr), "Match-%06d", x);
match = astman_get_header(m, hdr);
snprintf(hdr, sizeof(hdr), "Line-%06d", x);
line = astman_get_header(m, hdr);
if (!strcasecmp(action, "newcat")) {
if (!ast_strlen_zero(cat)) {
category = ast_category_new(cat, dfn, 99999);
if (category) {
ast_category_append(cfg, category);
}
}
if (ast_strlen_zero(cat))
return UNSPECIFIED_CATEGORY;
if (!(category = ast_category_new(cat, dfn, -1)))
return FAILURE_ALLOCATION;
if (ast_strlen_zero(match)) {
ast_category_append(cfg, category);
} else
ast_category_insert(cfg, category, match);
} else if (!strcasecmp(action, "renamecat")) {
if (!ast_strlen_zero(cat) && !ast_strlen_zero(value)) {
category = ast_category_get(cfg, cat);
if (category)
ast_category_rename(category, value);
}
if (ast_strlen_zero(cat) || ast_strlen_zero(value))
return UNSPECIFIED_ARGUMENT;
if (!(category = ast_category_get(cfg, cat)))
return UNKNOWN_CATEGORY;
ast_category_rename(category, value);
} else if (!strcasecmp(action, "delcat")) {
if (!ast_strlen_zero(cat))
ast_category_delete(cfg, cat);
if (ast_strlen_zero(cat))
return UNSPECIFIED_CATEGORY;
if (ast_category_delete(cfg, cat))
return FAILURE_DELCAT;
} else if (!strcasecmp(action, "emptycat")) {
if (ast_strlen_zero(cat))
return UNSPECIFIED_CATEGORY;
if (ast_category_empty(cfg, cat))
return FAILURE_EMPTYCAT;
} else if (!strcasecmp(action, "update")) {
if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) && (category = ast_category_get(cfg, cat)))
ast_variable_update(category, var, value, match, object);
if (ast_strlen_zero(cat) || ast_strlen_zero(var))
return UNSPECIFIED_ARGUMENT;
if (!(category = ast_category_get(cfg,cat)))
return UNKNOWN_CATEGORY;
if (ast_variable_update(category, var, value, match, object))
return FAILURE_UPDATE;
} else if (!strcasecmp(action, "delete")) {
if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) && (category = ast_category_get(cfg, cat)))
ast_variable_delete(category, var, match);
if (ast_strlen_zero(cat) || (ast_strlen_zero(var) && ast_strlen_zero(line)))
return UNSPECIFIED_ARGUMENT;
if (!(category = ast_category_get(cfg, cat)))
return UNKNOWN_CATEGORY;
if (ast_variable_delete(category, var, match, line))
return FAILURE_DELETE;
} else if (!strcasecmp(action, "append")) {
if (!ast_strlen_zero(cat) && !ast_strlen_zero(var) &&
(category = ast_category_get(cfg, cat)) &&
(v = ast_variable_new(var, value, dfn))) {
if (object || (match && !strcasecmp(match, "object")))
v->object = 1;
ast_variable_append(category, v);
}
if (ast_strlen_zero(cat) || ast_strlen_zero(var))
return UNSPECIFIED_ARGUMENT;
if (!(category = ast_category_get(cfg, cat)))
return UNKNOWN_CATEGORY;
if (!(v = ast_variable_new(var, value, dfn)))
return FAILURE_ALLOCATION;
if (object || (match && !strcasecmp(match, "object")))
v->object = 1;
ast_variable_append(category, v);
} else if (!strcasecmp(action, "insert")) {
if (ast_strlen_zero(cat) || ast_strlen_zero(var) || ast_strlen_zero(line))
return UNSPECIFIED_ARGUMENT;
if (!(category = ast_category_get(cfg, cat)))
return UNKNOWN_CATEGORY;
if (!(v = ast_variable_new(var, value, dfn)))
return FAILURE_ALLOCATION;
ast_variable_insert(category, v, line);
}
else {
ast_log(LOG_WARNING, "Action-%06d: %s not handled\n", x, action);
return UNKNOWN_ACTION;
}
}
return 0;
}
static char mandescr_updateconfig[] =
@ -1239,11 +1332,12 @@ static char mandescr_updateconfig[] =
" SrcFilename: Configuration filename to read(e.g. foo.conf)\n"
" DstFilename: Configuration filename to write(e.g. foo.conf)\n"
" Reload: Whether or not a reload should take place (or name of specific module)\n"
" Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,Update,Delete,Append)\n"
" Action-XXXXXX: Action to Take (NewCat,RenameCat,DelCat,EmptyCat,Update,Delete,Append,Insert)\n"
" Cat-XXXXXX: Category to operate on\n"
" Var-XXXXXX: Variable to work on\n"
" Value-XXXXXX: Value to work on\n"
" Match-XXXXXX: Extra match required to match line\n";
" Match-XXXXXX: Extra match required to match line\n"
" Line-XXXXXX: Line in category to operate on (used with delete and insert actions)\n";
static int action_updateconfig(struct mansession *s, const struct message *m)
{
@ -1253,32 +1347,93 @@ static int action_updateconfig(struct mansession *s, const struct message *m)
int res;
const char *rld = astman_get_header(m, "Reload");
struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS | CONFIG_FLAG_NOCACHE };
enum error_type result;
if (ast_strlen_zero(sfn) || ast_strlen_zero(dfn)) {
astman_send_error(s, m, "Filename not specified");
return 0;
}
if (!(cfg = ast_config_load(sfn, config_flags))) {
astman_send_error(s, m, "Config file not found");
return 0;
}
handle_updates(s, m, cfg, dfn);
ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
res = config_text_file_save(dfn, cfg, "Manager");
ast_config_destroy(cfg);
if (res) {
astman_send_error(s, m, "Save of config failed");
return 0;
}
astman_send_ack(s, m, NULL);
if (!ast_strlen_zero(rld)) {
if (ast_true(rld))
rld = NULL;
ast_module_reload(rld);
if (!(cfg = ast_config_load(sfn, config_flags))) {
astman_send_error(s, m, "Config file not found");
return 0;
}
result = handle_updates(s, m, cfg, dfn);
if (!result) {
ast_include_rename(cfg, sfn, dfn); /* change the include references from dfn to sfn, so things match up */
res = config_text_file_save(dfn, cfg, "Manager");
ast_config_destroy(cfg);
if (res) {
astman_send_error(s, m, "Save of config failed");
return 0;
}
astman_send_ack(s, m, NULL);
if (!ast_strlen_zero(rld)) {
if (ast_true(rld))
rld = NULL;
ast_module_reload(rld);
}
} else {
ast_config_destroy(cfg);
switch(result) {
case UNKNOWN_ACTION:
astman_send_error(s, m, "Unknown action command");
break;
case UNKNOWN_CATEGORY:
astman_send_error(s, m, "Given category does not exist");
break;
case UNSPECIFIED_CATEGORY:
astman_send_error(s, m, "Category not specified");
break;
case UNSPECIFIED_ARGUMENT:
astman_send_error(s, m, "Problem with category, value, or line (if required)");
break;
case FAILURE_ALLOCATION:
astman_send_error(s, m, "Memory allocation failure, this should not happen");
break;
case FAILURE_DELCAT:
astman_send_error(s, m, "Delete category did not complete successfully");
break;
case FAILURE_EMPTYCAT:
astman_send_error(s, m, "Empty category did not complete successfully");
break;
case FAILURE_UPDATE:
astman_send_error(s, m, "Update did not complete successfully");
break;
case FAILURE_DELETE:
astman_send_error(s, m, "Delete did not complete successfully");
break;
case FAILURE_APPEND:
astman_send_error(s, m, "Append did not complete successfully");
break;
}
}
return 0;
}
static char mandescr_createconfig[] =
"Description: A 'CreateConfig' action will create an empty file in the\n"
"configuration directory. This action is intended to be used before an\n"
"UpdateConfig action.\n"
"Variables\n"
" Filename: The configuration filename to create (e.g. foo.conf)\n";
static int action_createconfig(struct mansession *s, const struct message *m)
{
int fd;
const char *fn = astman_get_header(m, "Filename");
struct ast_str *filepath = ast_str_alloca(PATH_MAX);
ast_str_set(&filepath, 0, "%s/", ast_config_AST_CONFIG_DIR);
ast_str_append(&filepath, 0, "%s", fn);
if ((fd = open(filepath->str, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH)) != -1) {
close(fd);
astman_send_ack(s, m, "New configuration file created successfully");
} else
astman_send_error(s, m, strerror(errno));
return 0;
}
/*! \brief Manager WAITEVENT */
static char mandescr_waitevent[] =
"Description: A 'WaitEvent' action will ellicit a 'Success' response. Whenever\n"
@ -3483,6 +3638,8 @@ static int __init_manager(int reload)
ast_manager_register2("GetConfig", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfig, "Retrieve configuration", mandescr_getconfig);
ast_manager_register2("GetConfigJSON", EVENT_FLAG_SYSTEM | EVENT_FLAG_CONFIG, action_getconfigjson, "Retrieve configuration (JSON format)", mandescr_getconfigjson);
ast_manager_register2("UpdateConfig", EVENT_FLAG_CONFIG, action_updateconfig, "Update basic configuration", mandescr_updateconfig);
ast_manager_register2("CreateConfig", EVENT_FLAG_CONFIG, action_createconfig, "Creates an empty file in the configuration directory", mandescr_createconfig);
ast_manager_register2("ListCategories", EVENT_FLAG_CONFIG, action_listcategories, "List categories in configuration file", mandescr_listcategories);
ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );