AMI: Allow for command response documentation

Allow for responses to AMI actions/commands to be documented properly
in XML and displayed via the CLI. Response events are documented
exactly as standard AMI events are documented.

Review: https://reviewboard.asterisk.org/r/3812/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419342 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kinsey Moore
2014-07-24 13:00:59 +00:00
parent ccc6e8bd17
commit 4445ee7fc0
7 changed files with 304 additions and 69 deletions

View File

@@ -2300,9 +2300,9 @@ static void ast_xml_doc_item_destructor(void *obj)
ast_free(doc->description);
ast_string_field_free_memory(doc);
if (doc->next) {
ao2_ref(doc->next, -1);
doc->next = NULL;
if (AST_LIST_NEXT(doc, next)) {
ao2_ref(AST_LIST_NEXT(doc, next), -1);
AST_LIST_NEXT(doc, next) = NULL;
}
}
@@ -2428,6 +2428,139 @@ static struct ast_xml_doc_item *xmldoc_build_documentation_item(struct ast_xml_n
return item;
}
/*!
* \internal
* \brief Build the list responses for an item
*
* \param manager_action The action node to parse
*
* \note This method exists for when you already have the node. This
* prevents having to lock the documentation tree twice
*
* \retval A list of ast_xml_doc_items
* \retval NULL on failure
*
* \since 13.0.0
*/
static struct ast_xml_doc_item *xmldoc_build_list_responses(struct ast_xml_node *manager_action)
{
struct ast_xml_node *event;
struct ast_xml_node *responses;
struct ast_xml_node *list_elements;
struct ast_xml_doc_item_list root;
AST_LIST_HEAD_INIT(&root);
responses = ast_xml_find_element(ast_xml_node_get_children(manager_action), "responses", NULL, NULL);
if (!responses) {
return NULL;
}
list_elements = ast_xml_find_element(ast_xml_node_get_children(responses), "list-elements", NULL, NULL);
if (!list_elements) {
return NULL;
}
/* Iterate over managerEvent nodes */
for (event = ast_xml_node_get_children(list_elements); event; event = ast_xml_node_get_next(event)) {
struct ast_xml_node *event_instance;
const char *name = ast_xml_get_attribute(event, "name");
struct ast_xml_doc_item *new_item;
if (!name || strcmp(ast_xml_node_get_name(event), "managerEvent")) {
continue;
}
event_instance = ast_xml_find_element(ast_xml_node_get_children(event),
"managerEventInstance", NULL, NULL);
new_item = xmldoc_build_documentation_item(event_instance, name, "managerEvent");
if (!new_item) {
ao2_cleanup(AST_LIST_FIRST(&root));
return NULL;
}
AST_LIST_INSERT_TAIL(&root, new_item, next);
}
return AST_LIST_FIRST(&root);
}
struct ast_xml_doc_item *ast_xmldoc_build_list_responses(const char *type, const char *name, const char *module)
{
struct ast_xml_node *node;
if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
return NULL;
}
node = xmldoc_get_node(type, name, module, documentation_language);
if (!node || !ast_xml_node_get_children(node)) {
return NULL;
}
return xmldoc_build_list_responses(node);
}
/*!
* \internal
* \brief Build the final response for an item
*
* \param manager_action The action node to parse
*
* \note This method exists for when you already have the node. This
* prevents having to lock the documentation tree twice
*
* \retval An ast_xml_doc_item
* \retval NULL on failure
*
* \since 13.0.0
*/
static struct ast_xml_doc_item *xmldoc_build_final_response(struct ast_xml_node *manager_action)
{
struct ast_xml_node *responses;
struct ast_xml_node *final_response_event;
struct ast_xml_node *event_instance;
responses = ast_xml_find_element(ast_xml_node_get_children(manager_action),
"responses", NULL, NULL);
if (!responses) {
return NULL;
}
final_response_event = ast_xml_find_element(ast_xml_node_get_children(responses),
"managerEvent", NULL, NULL);
if (!final_response_event) {
return NULL;
}
event_instance = ast_xml_find_element(ast_xml_node_get_children(final_response_event),
"managerEventInstance", NULL, NULL);
if (!event_instance) {
return NULL;
}
return xmldoc_build_documentation_item(event_instance,
ast_xml_get_attribute(final_response_event, "name"), "managerEvent");
}
struct ast_xml_doc_item *ast_xmldoc_build_final_response(const char *type, const char *name, const char *module)
{
struct ast_xml_node *node;
if (ast_strlen_zero(type) || ast_strlen_zero(name)) {
return NULL;
}
node = xmldoc_get_node(type, name, module, documentation_language);
if (!node || !ast_xml_node_get_children(node)) {
return NULL;
}
return xmldoc_build_final_response(node);
}
struct ast_xml_xpath_results *__attribute__((format(printf, 1, 2))) ast_xmldoc_query(const char *fmt, ...)
{
struct ast_xml_xpath_results *results = NULL;
@@ -2455,7 +2588,7 @@ struct ast_xml_xpath_results *__attribute__((format(printf, 1, 2))) ast_xmldoc_q
return results;
}
static void build_config_docs(struct ast_xml_node *cur, struct ast_xml_doc_item **tail)
static void build_config_docs(struct ast_xml_node *cur, struct ast_xml_doc_item_list *root)
{
struct ast_xml_node *iter;
struct ast_xml_doc_item *item;
@@ -2478,9 +2611,8 @@ static void build_config_docs(struct ast_xml_node *cur, struct ast_xml_doc_item
ast_string_field_set(item, ref, name);
ast_xml_free_attr(name);
}
(*tail)->next = item;
*tail = (*tail)->next;
build_config_docs(iter, tail);
AST_LIST_INSERT_TAIL(root, item, next);
build_config_docs(iter, root);
}
}
@@ -2536,7 +2668,6 @@ int ast_xmldoc_regenerate_doc_item(struct ast_xml_doc_item *item)
struct ao2_container *ast_xmldoc_build_documentation(const char *type)
{
struct ao2_container *docs;
struct ast_xml_doc_item *item = NULL, *root = NULL;
struct ast_xml_node *node = NULL, *instance = NULL;
struct documentation_tree *doctree;
const char *name;
@@ -2555,6 +2686,8 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
}
for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
struct ast_xml_doc_item *item = NULL;
/* Ignore empty nodes or nodes that aren't of the type requested */
if (!ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), type)) {
continue;
@@ -2566,6 +2699,10 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
switch (xmldoc_get_syntax_type(type)) {
case MANAGER_EVENT_SYNTAX:
{
struct ast_xml_doc_item_list root;
AST_LIST_HEAD_INIT(&root);
for (instance = ast_xml_node_get_children(node); instance; instance = ast_xml_node_get_next(instance)) {
struct ast_xml_doc_item *temp;
if (!ast_xml_node_get_children(instance) || strcasecmp(ast_xml_node_get_name(instance), "managerEventInstance")) {
@@ -2575,28 +2712,27 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
if (!temp) {
break;
}
if (!item) {
item = temp;
root = item;
} else {
item->next = temp;
item = temp;
}
AST_LIST_INSERT_TAIL(&root, temp, next);
}
item = root;
item = AST_LIST_FIRST(&root);
break;
}
case CONFIG_INFO_SYNTAX:
{
struct ast_xml_doc_item *tail;
RAII_VAR(const char *, name, ast_xml_get_attribute(node, "name"), ast_xml_free_attr);
if (item || !ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), "configInfo")) {
if (!ast_xml_node_get_children(node) || strcasecmp(ast_xml_node_get_name(node), "configInfo")) {
break;
}
if (!(item = xmldoc_build_documentation_item(node, name, "configInfo"))) {
break;
item = xmldoc_build_documentation_item(node, name, "configInfo");
if (item) {
struct ast_xml_doc_item_list root;
AST_LIST_HEAD_INIT(&root);
AST_LIST_INSERT_TAIL(&root, item, next);
build_config_docs(node, &root);
}
tail = item;
build_config_docs(node, &tail);
break;
}
default:
@@ -2607,7 +2743,6 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
if (item) {
ao2_link(docs, item);
ao2_t_ref(item, -1, "Dispose of creation ref");
item = NULL;
}
}
}