aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES8
-rw-r--r--include/asterisk/config.h14
-rw-r--r--main/config.c64
-rw-r--r--main/manager.c261
4 files changed, 292 insertions, 55 deletions
diff --git a/CHANGES b/CHANGES
index 79218eef8..1f727f93c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
------------------
diff --git a/include/asterisk/config.h b/include/asterisk/config.h
index fe9d49d30..4757d5126 100644
--- a/include/asterisk/config.h
+++ b/include/asterisk/config.h
@@ -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);
diff --git a/main/config.c b/main/config.c
index d5b0738fc..ce7bb50b2 100644
--- a/main/config.c
+++ b/main/config.c
@@ -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;
diff --git a/main/manager.c b/main/manager.c
index 33973f399..a5319e7e0 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -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 ((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))) {
- 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++;
}
+ 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 );