[asterisk-commits] jpeeler: trunk r103331 - in /trunk: ./ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Feb 11 18:24:37 CST 2008


Author: jpeeler
Date: Mon Feb 11 18:24:36 2008
New Revision: 103331

URL: http://svn.digium.com/view/asterisk?view=rev&rev=103331
Log:
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.


Modified:
    trunk/CHANGES
    trunk/include/asterisk/config.h
    trunk/main/config.c
    trunk/main/manager.c

Modified: trunk/CHANGES
URL: http://svn.digium.com/view/asterisk/trunk/CHANGES?view=diff&rev=103331&r1=103330&r2=103331
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Mon Feb 11 18:24:36 2008
@@ -39,6 +39,14 @@
      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
 ------------------

Modified: trunk/include/asterisk/config.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/config.h?view=diff&rev=103331&r1=103330&r2=103331
==============================================================================
--- trunk/include/asterisk/config.h (original)
+++ trunk/include/asterisk/config.h Mon Feb 11 18:24:36 2008
@@ -254,7 +254,18 @@
 
 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_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);
 

Modified: trunk/main/config.c
URL: http://svn.digium.com/view/asterisk/trunk/main/config.c?view=diff&rev=103331&r1=103330&r2=103331
==============================================================================
--- trunk/main/config.c (original)
+++ trunk/main/config.c Mon Feb 11 18:24:36 2008
@@ -354,6 +354,28 @@
 		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;
@@ -479,6 +501,26 @@
 	category->include_level = config->include_level;
 	config->last = category;
 	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)
@@ -629,10 +671,11 @@
 	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 @@
 	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 @@
 			prev = cur;
 
 		cur = curn;
+		lineno++;
 	}
 	return res;
 }
@@ -757,6 +801,22 @@
 		prev = cat;
 		cat = cat->next;
 	}
+	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;
 }
 

Modified: trunk/main/manager.c
URL: http://svn.digium.com/view/asterisk/trunk/main/manager.c?view=diff&rev=103331&r1=103330&r2=103331
==============================================================================
--- trunk/main/manager.c (original)
+++ trunk/main/manager.c Mon Feb 11 18:24:36 2008
@@ -73,6 +73,20 @@
 #include "asterisk/version.h"
 #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.
@@ -1053,17 +1067,19 @@
 
 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,19 +1091,62 @@
 		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 @@
 }
 
 /* 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 @@
 		}
 		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 @@
 "   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,29 +1347,90 @@
 	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;
 }
 
@@ -3483,6 +3638,8 @@
 		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 );




More information about the asterisk-commits mailing list