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:
parent
ccc6e8bd17
commit
4445ee7fc0
|
@ -26,11 +26,15 @@
|
|||
<!ATTLIST agi language CDATA #REQUIRED>
|
||||
<!ATTLIST agi module CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT manager (synopsis?,syntax?,description?,see-also?)>
|
||||
<!ELEMENT manager (synopsis?,syntax?,description?,see-also?,responses?)>
|
||||
<!ATTLIST manager name CDATA #REQUIRED>
|
||||
<!ATTLIST manager language CDATA #REQUIRED>
|
||||
<!ATTLIST manager module CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT responses (list-elements?,(managerEvent|xi:include))>
|
||||
|
||||
<!ELEMENT list-elements (managerEvent+|xi:include+)>
|
||||
|
||||
<!ELEMENT managerEvent (managerEventInstance+)>
|
||||
<!ATTLIST managerEvent name CDATA #REQUIRED>
|
||||
<!ATTLIST managerEvent language CDATA #REQUIRED>
|
||||
|
|
|
@ -148,6 +148,10 @@ struct manager_action {
|
|||
AST_STRING_FIELD(arguments); /*!< Description of each argument. */
|
||||
AST_STRING_FIELD(seealso); /*!< See also */
|
||||
);
|
||||
/*! Possible list element response events. */
|
||||
struct ast_xml_doc_item *list_responses;
|
||||
/*! Final response event. */
|
||||
struct ast_xml_doc_item *final_response;
|
||||
/*! Permission required for action. EVENT_FLAG_* */
|
||||
int authority;
|
||||
/*! Function to be called */
|
||||
|
|
|
@ -37,6 +37,13 @@ enum ast_doc_src {
|
|||
struct ao2_container;
|
||||
struct ast_xml_node;
|
||||
|
||||
/*!
|
||||
* \brief The struct to be used as the head of an ast_xml_doc_item list
|
||||
* when being manipulated
|
||||
* \since 13.0.0
|
||||
*/
|
||||
AST_LIST_HEAD(ast_xml_doc_item_list, ast_xml_doc_item);
|
||||
|
||||
/*! \brief Struct that contains the XML documentation for a particular item. Note
|
||||
* that this is an ao2 ref counted object.
|
||||
*
|
||||
|
@ -70,7 +77,7 @@ struct ast_xml_doc_item {
|
|||
*/
|
||||
struct ast_xml_node *node;
|
||||
/*! The next XML documentation item that matches the same name/item type */
|
||||
struct ast_xml_doc_item *next;
|
||||
AST_LIST_ENTRY(ast_xml_doc_item) next;
|
||||
};
|
||||
|
||||
/*! \brief Execute an XPath query on the loaded XML documentation
|
||||
|
@ -114,6 +121,34 @@ char *ast_xmldoc_build_seealso(const char *type, const char *name, const char *m
|
|||
*/
|
||||
char *ast_xmldoc_build_arguments(const char *type, const char *name, const char *module);
|
||||
|
||||
/*!
|
||||
* \brief Generate the [final response] tag based on type of node ('application',
|
||||
* 'function' or 'agi') and name.
|
||||
*
|
||||
* \param type 'application', 'function' or 'agi'
|
||||
* \param name Name of the application or function to build the 'responses' tag.
|
||||
* \param module The module the item is in (optional, can be NULL)
|
||||
*
|
||||
* \return An XMLDoc item list with the [final response] tag content.
|
||||
*
|
||||
* \since 13.0.0
|
||||
*/
|
||||
struct ast_xml_doc_item *ast_xmldoc_build_final_response(const char *type, const char *name, const char *module);
|
||||
|
||||
/*!
|
||||
* \brief Generate the [list responses] tag based on type of node ('application',
|
||||
* 'function' or 'agi') and name.
|
||||
*
|
||||
* \param type 'application', 'function' or 'agi'
|
||||
* \param name Name of the application or function to build the 'responses' tag.
|
||||
* \param module The module the item is in (optional, can be NULL)
|
||||
*
|
||||
* \return An XMLDoc item list with the [list responses] tag content.
|
||||
*
|
||||
* \since 13.0.0
|
||||
*/
|
||||
struct ast_xml_doc_item *ast_xmldoc_build_list_responses(const char *type, const char *name, const char *module);
|
||||
|
||||
/*!
|
||||
* \brief Colorize and put delimiters (instead of tags) to the xmldoc output.
|
||||
* \param bwinput Not colorized input with tags.
|
||||
|
|
|
@ -249,7 +249,7 @@ static struct ast_xml_doc_item *find_xmldoc_option(struct ast_xml_doc_item *conf
|
|||
return NULL;
|
||||
}
|
||||
/* First is just the configInfo, we can skip it */
|
||||
while ((iter = iter->next)) {
|
||||
while ((iter = AST_LIST_NEXT(iter, next))) {
|
||||
size_t x;
|
||||
if (strcasecmp(iter->name, name)) {
|
||||
continue;
|
||||
|
@ -274,7 +274,7 @@ static struct ast_xml_doc_item *find_xmldoc_type(struct ast_xml_doc_item *config
|
|||
return NULL;
|
||||
}
|
||||
/* First is just the config Info, skip it */
|
||||
while ((iter = iter->next)) {
|
||||
while ((iter = AST_LIST_NEXT(iter, next))) {
|
||||
if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
|
||||
break;
|
||||
}
|
||||
|
@ -915,7 +915,7 @@ static char *complete_config_type(const char *module, const char *word, int pos,
|
|||
}
|
||||
|
||||
cur = info;
|
||||
while ((cur = cur->next)) {
|
||||
while ((cur = AST_LIST_NEXT(cur, next))) {
|
||||
if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
|
||||
c = ast_strdup(cur->name);
|
||||
break;
|
||||
|
@ -944,7 +944,7 @@ static char *complete_config_option(const char *module, const char *option, cons
|
|||
}
|
||||
|
||||
cur = info;
|
||||
while ((cur = cur->next)) {
|
||||
while ((cur = AST_LIST_NEXT(cur, next))) {
|
||||
if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
|
||||
c = ast_strdup(cur->name);
|
||||
break;
|
||||
|
@ -1109,7 +1109,7 @@ static void cli_show_module_types(struct ast_cli_args *a)
|
|||
|
||||
tmp = item;
|
||||
ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
|
||||
while ((tmp = tmp->next)) {
|
||||
while ((tmp = AST_LIST_NEXT(tmp, next))) {
|
||||
if (!strcasecmp(tmp->type, "configObject")) {
|
||||
ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
|
||||
ast_str_buffer(tmp->synopsis));
|
||||
|
@ -1135,7 +1135,7 @@ static void cli_show_module_type(struct ast_cli_args *a)
|
|||
}
|
||||
|
||||
tmp = item;
|
||||
while ((tmp = tmp->next)) {
|
||||
while ((tmp = AST_LIST_NEXT(tmp, next))) {
|
||||
if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
|
||||
match = 1;
|
||||
term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
|
||||
|
@ -1161,7 +1161,7 @@ static void cli_show_module_type(struct ast_cli_args *a)
|
|||
|
||||
/* Now iterate over the options for the type */
|
||||
tmp = item;
|
||||
while ((tmp = tmp->next)) {
|
||||
while ((tmp = AST_LIST_NEXT(tmp, next))) {
|
||||
if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
|
||||
ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
|
||||
ast_str_buffer(tmp->synopsis));
|
||||
|
@ -1186,7 +1186,7 @@ static void cli_show_module_options(struct ast_cli_args *a)
|
|||
return;
|
||||
}
|
||||
tmp = item;
|
||||
while ((tmp = tmp->next)) {
|
||||
while ((tmp = AST_LIST_NEXT(tmp, next))) {
|
||||
if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
|
||||
if (match) {
|
||||
ast_cli(a->fd, "\n");
|
||||
|
|
109
main/manager.c
109
main/manager.c
|
@ -1912,6 +1912,8 @@ static int manager_displayconnects(struct mansession_session *session)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance);
|
||||
|
||||
static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
struct manager_action *cur;
|
||||
|
@ -1919,7 +1921,8 @@ static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_
|
|||
int num, l, which;
|
||||
char *ret = NULL;
|
||||
#ifdef AST_XML_DOCS
|
||||
char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64], privilege_title[64];
|
||||
char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64];
|
||||
char arguments_title[64], privilege_title[64], final_response_title[64], list_responses_title[64];
|
||||
#endif
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -1955,6 +1958,8 @@ static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_
|
|||
term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(privilege_title, "[Privilege]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(final_response_title, "[Final Response]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(list_responses_title, "[List Responses]\n", COLOR_MAGENTA, 0, 40);
|
||||
#endif
|
||||
|
||||
AST_RWLIST_RDLOCK(&actions);
|
||||
|
@ -1971,13 +1976,34 @@ static char *handle_showmancmd(struct ast_cli_entry *e, int cmd, struct ast_cli_
|
|||
char *arguments = ast_xmldoc_printable(S_OR(cur->arguments, "Not available"), 1);
|
||||
char *seealso = ast_xmldoc_printable(S_OR(cur->seealso, "Not available"), 1);
|
||||
char *privilege = ast_xmldoc_printable(S_OR(authority->str, "Not available"), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n",
|
||||
char *responses = ast_xmldoc_printable("None", 1);
|
||||
ast_cli(a->fd, "%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s",
|
||||
syntax_title, syntax,
|
||||
synopsis_title, synopsis,
|
||||
description_title, description,
|
||||
arguments_title, arguments,
|
||||
seealso_title, seealso,
|
||||
privilege_title, privilege);
|
||||
privilege_title, privilege,
|
||||
list_responses_title);
|
||||
|
||||
if (!cur->list_responses) {
|
||||
ast_cli(a->fd, "%s\n\n", responses);
|
||||
} else {
|
||||
struct ast_xml_doc_item *temp;
|
||||
for (temp = cur->list_responses; temp; temp = AST_LIST_NEXT(temp, next)) {
|
||||
ast_cli(a->fd, "Event: %s\n", temp->name);
|
||||
print_event_instance(a, temp);
|
||||
}
|
||||
}
|
||||
|
||||
ast_cli(a->fd, "%s", final_response_title);
|
||||
|
||||
if (!cur->final_response) {
|
||||
ast_cli(a->fd, "%s\n\n", responses);
|
||||
} else {
|
||||
ast_cli(a->fd, "Event: %s\n", cur->final_response->name);
|
||||
print_event_instance(a, cur->final_response);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
@ -6309,6 +6335,8 @@ static void action_destroy(void *obj)
|
|||
/* The string fields were initialized. */
|
||||
ast_string_field_free_memory(doomed);
|
||||
}
|
||||
ao2_cleanup(doomed->final_response);
|
||||
ao2_cleanup(doomed->list_responses);
|
||||
}
|
||||
|
||||
/*! \brief register a new command with manager, including online help. This is
|
||||
|
@ -6354,6 +6382,9 @@ int ast_manager_register2(const char *action, int auth, int (*func)(struct manse
|
|||
ast_string_field_set(cur, arguments, tmpxml);
|
||||
ast_free(tmpxml);
|
||||
|
||||
cur->final_response = ast_xmldoc_build_final_response("manager", action, NULL);
|
||||
cur->list_responses = ast_xmldoc_build_list_responses("manager", action, NULL);
|
||||
|
||||
cur->docsrc = AST_XML_DOC;
|
||||
} else
|
||||
#endif
|
||||
|
@ -7745,6 +7776,43 @@ static char *handle_manager_show_events(struct ast_cli_entry *e, int cmd, struct
|
|||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static void print_event_instance(struct ast_cli_args *a, struct ast_xml_doc_item *instance)
|
||||
{
|
||||
char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
|
||||
|
||||
term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
|
||||
|
||||
if (!ast_strlen_zero(ast_str_buffer(instance->synopsis))) {
|
||||
char *synopsis = ast_xmldoc_printable(ast_str_buffer(instance->synopsis), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
|
||||
ast_free(synopsis);
|
||||
}
|
||||
if (!ast_strlen_zero(ast_str_buffer(instance->syntax))) {
|
||||
char *syntax = ast_xmldoc_printable(ast_str_buffer(instance->syntax), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
|
||||
ast_free(syntax);
|
||||
}
|
||||
if (!ast_strlen_zero(ast_str_buffer(instance->description))) {
|
||||
char *description = ast_xmldoc_printable(ast_str_buffer(instance->description), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", description_title, description);
|
||||
ast_free(description);
|
||||
}
|
||||
if (!ast_strlen_zero(ast_str_buffer(instance->arguments))) {
|
||||
char *arguments = ast_xmldoc_printable(ast_str_buffer(instance->arguments), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
|
||||
ast_free(arguments);
|
||||
}
|
||||
if (!ast_strlen_zero(ast_str_buffer(instance->seealso))) {
|
||||
char *seealso = ast_xmldoc_printable(ast_str_buffer(instance->seealso), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
|
||||
ast_free(seealso);
|
||||
}
|
||||
}
|
||||
|
||||
static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
RAII_VAR(struct ao2_container *, events, NULL, ao2_cleanup);
|
||||
|
@ -7753,7 +7821,6 @@ static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct
|
|||
int length;
|
||||
int which;
|
||||
char *match = NULL;
|
||||
char syntax_title[64], description_title[64], synopsis_title[64], seealso_title[64], arguments_title[64];
|
||||
|
||||
if (cmd == CLI_INIT) {
|
||||
e->command = "manager show event";
|
||||
|
@ -7794,39 +7861,9 @@ static char *handle_manager_show_event(struct ast_cli_entry *e, int cmd, struct
|
|||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
term_color(synopsis_title, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(description_title, "[Description]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(syntax_title, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(seealso_title, "[See Also]\n", COLOR_MAGENTA, 0, 40);
|
||||
term_color(arguments_title, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
|
||||
|
||||
ast_cli(a->fd, "Event: %s\n", a->argv[3]);
|
||||
for (temp = item; temp; temp = temp->next) {
|
||||
if (!ast_strlen_zero(ast_str_buffer(temp->synopsis))) {
|
||||
char *synopsis = ast_xmldoc_printable(ast_str_buffer(temp->synopsis), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", synopsis_title, synopsis);
|
||||
ast_free(synopsis);
|
||||
}
|
||||
if (!ast_strlen_zero(ast_str_buffer(temp->syntax))) {
|
||||
char *syntax = ast_xmldoc_printable(ast_str_buffer(temp->syntax), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", syntax_title, syntax);
|
||||
ast_free(syntax);
|
||||
}
|
||||
if (!ast_strlen_zero(ast_str_buffer(temp->description))) {
|
||||
char *description = ast_xmldoc_printable(ast_str_buffer(temp->description), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", description_title, description);
|
||||
ast_free(description);
|
||||
}
|
||||
if (!ast_strlen_zero(ast_str_buffer(temp->arguments))) {
|
||||
char *arguments = ast_xmldoc_printable(ast_str_buffer(temp->arguments), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", arguments_title, arguments);
|
||||
ast_free(arguments);
|
||||
}
|
||||
if (!ast_strlen_zero(ast_str_buffer(temp->seealso))) {
|
||||
char *seealso = ast_xmldoc_printable(ast_str_buffer(temp->seealso), 1);
|
||||
ast_cli(a->fd, "%s%s\n\n", seealso_title, seealso);
|
||||
ast_free(seealso);
|
||||
}
|
||||
for (temp = item; temp; temp = AST_LIST_NEXT(temp, next)) {
|
||||
print_event_instance(a, temp);
|
||||
}
|
||||
|
||||
ao2_ref(item, -1);
|
||||
|
|
|
@ -100,6 +100,26 @@ static struct stasis_message_router *bridge_state_router;
|
|||
<description>
|
||||
<para>Returns detailed information about a bridge and the channels in it.</para>
|
||||
</description>
|
||||
<responses>
|
||||
<list-elements>
|
||||
<managerEvent language="en_US" name="BridgeInfoChannel">
|
||||
<managerEventInstance class="EVENT_FLAG_COMMAND">
|
||||
<synopsis>Information about a channel in a bridge.</synopsis>
|
||||
<syntax>
|
||||
<channel_snapshot/>
|
||||
</syntax>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
</list-elements>
|
||||
<managerEvent language="en_US" name="BridgeInfoComplete">
|
||||
<managerEventInstance class="EVENT_FLAG_COMMAND">
|
||||
<synopsis>Information about a bridge.</synopsis>
|
||||
<syntax>
|
||||
<bridge_snapshot/>
|
||||
</syntax>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
</responses>
|
||||
</manager>
|
||||
<manager name="BridgeDestroy" language="en_US">
|
||||
<synopsis>
|
||||
|
|
181
main/xmldoc.c
181
main/xmldoc.c
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue