summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/appdocsxml.dtd27
-rw-r--r--include/asterisk/agi.h21
-rw-r--r--main/xmldoc.c203
-rw-r--r--res/res_agi.c199
4 files changed, 389 insertions, 61 deletions
diff --git a/doc/appdocsxml.dtd b/doc/appdocsxml.dtd
index 057bf099b..0c0b8256f 100644
--- a/doc/appdocsxml.dtd
+++ b/doc/appdocsxml.dtd
@@ -1,4 +1,4 @@
- <!ELEMENT docs (application|function)* >
+ <!ELEMENT docs (application|function|agi)* >
<!ELEMENT application (synopsis?,syntax?,description?,see-also?)>
<!ATTLIST application name CDATA #REQUIRED>
@@ -6,36 +6,42 @@
<!ELEMENT function (synopsis?,syntax?,description?,see-also?)>
<!ATTLIST function name CDATA #REQUIRED>
- <!ATTLIST function language CDATA #REQUIRED>
+ <!ATTLIST function language CDATA #REQUIRED>
+
+ <!ELEMENT agi (synopsis?,syntax?,description?,see-also?)>
+ <!ATTLIST agi name CDATA #REQUIRED>
+ <!ATTLIST agi language CDATA #REQUIRED>
<!ELEMENT see-also (ref*)>
<!ELEMENT ref (#PCDATA)*>
- <!ATTLIST ref type (application|function|astcli|link|manpage|filename) #REQUIRED>
+ <!ATTLIST ref type (application|function|astcli|link|manpage|filename|agi) #REQUIRED>
<!ELEMENT synopsis (#PCDATA)>
-
+
<!ELEMENT syntax (parameter*)>
<!ATTLIST syntax argsep CDATA ",">
<!ELEMENT description (para|note|warning|variablelist|enumlist)*>
- <!ELEMENT parameter (optionlist|enumlist|argument|para|note|warning)*>
- <!ATTLIST parameter name CDATA #REQUIRED>
+ <!ELEMENT parameter (optionlist|enumlist|argument|para|note|warning|parameter)*>
+ <!ATTLIST parameter name CDATA "">
<!ATTLIST parameter required (yes|no|true|false) "false">
<!ATTLIST parameter multiple (yes|no|true|false) "false">
<!ATTLIST parameter hasparams (yes|no|true|false|optional) "false">
+ <!ATTLIST parameter literal (yes|no|true|false) "false">
+ <!ATTLIST parameter default CDATA "">
<!ATTLIST parameter argsep CDATA ",">
<!ELEMENT optionlist (option+)>
<!ELEMENT option (argument|para|note|warning|variablelist|enumlist)*>
- <!ATTLIST option name CDATA #REQUIRED>
+ <!ATTLIST option name CDATA #REQUIRED>
<!ATTLIST option argsep CDATA ",">
<!ATTLIST option implies CDATA "">
<!ELEMENT enumlist (enum+)>
<!ELEMENT enum (para|note|warning)*>
- <!ATTLIST enum name CDATA #REQUIRED>
+ <!ATTLIST enum name CDATA "">
<!ELEMENT argument (para|note|warning|variablelist|argument)*>
<!ATTLIST argument name CDATA #REQUIRED>
@@ -53,12 +59,11 @@
<!ELEMENT note (para+)>
<!ELEMENT warning (para+)>
-
+
<!ELEMENT variablelist (variable+)>
<!ELEMENT variable (#PCDATA|value|para)*>
<!ATTLIST variable name CDATA "">
-
+
<!ELEMENT value (#PCDATA)>
<!ATTLIST value name CDATA #REQUIRED>
<!ATTLIST value default CDATA "">
-
diff --git a/include/asterisk/agi.h b/include/asterisk/agi.h
index 609e98815..48de8c954 100644
--- a/include/asterisk/agi.h
+++ b/include/asterisk/agi.h
@@ -38,20 +38,25 @@ typedef struct agi_state {
} AGI;
typedef struct agi_command {
- /* Null terminated list of the words of the command */
- char *cmda[AST_MAX_CMD_LEN];
- /* Handler for the command (channel, AGI state, # of arguments, argument list).
+ char *cmda[AST_MAX_CMD_LEN]; /*!< Null terminated list of the words of the command */
+ /*! Handler for the command (channel, AGI state, # of arguments, argument list).
Returns RESULT_SHOWUSAGE for improper arguments */
int (*handler)(struct ast_channel *chan, AGI *agi, int argc, char *argv[]);
- /* Summary of the command (< 60 characters) */
+ /*! Summary of the command (< 60 characters) */
char *summary;
- /* Detailed usage information */
+ /*! Detailed usage information */
char *usage;
- /* Does this application run dead */
+ /*! Does this application run dead */
int dead;
- /* Pointer to module that registered the agi command */
+ /*! AGI command syntax description */
+ char *syntax;
+ /*! See also content */
+ char *seealso;
+ /*! Where the documentation come from. */
+ enum ast_doc_src docsrc;
+ /*! Pointer to module that registered the agi command */
struct ast_module *mod;
- /* Linked list pointer */
+ /*! Linked list pointer */
AST_LIST_ENTRY(agi_command) list;
} agi_command;
diff --git a/main/xmldoc.c b/main/xmldoc.c
index c24a6b7a5..3a68b6cab 100644
--- a/main/xmldoc.c
+++ b/main/xmldoc.c
@@ -57,6 +57,8 @@ struct documentation_tree {
AST_RWLIST_ENTRY(documentation_tree) entry;
};
+static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname);
+
/*!
* \brief Container of documentation trees
*
@@ -548,17 +550,18 @@ static __attribute__((format(printf,4,5))) void xmldoc_reverse_helper(int revers
}
/*! \internal
- * \brief Check if the passed node has <argument> tags inside it.
- * \param node Root node to search argument elements.
+ * \brief Check if the passed node has 'what' tags inside it.
+ * \param node Root node to search 'what' elements.
+ * \param what node name to search inside node.
* \retval 1 If a <argument> element is found inside 'node'.
* \retval 0 If no <argument> is found inside 'node'.
*/
-static int xmldoc_has_arguments(struct ast_xml_node *fixnode)
+static int xmldoc_has_inside(struct ast_xml_node *fixnode, const char *what)
{
struct ast_xml_node *node = fixnode;
for (node = ast_xml_node_get_children(fixnode); node; node = ast_xml_node_get_next(node)) {
- if (!strcasecmp(ast_xml_node_get_name(node), "argument")) {
+ if (!strcasecmp(ast_xml_node_get_name(node), what)) {
return 1;
}
}
@@ -575,7 +578,7 @@ static int xmldoc_has_arguments(struct ast_xml_node *fixnode)
* \retval NULL on error.
* \retval An ast_malloc'ed string with the syntax generated.
*/
-static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootname, const char *childname, int printparenthesis, int printrootname)
+static char *xmldoc_get_syntax_fun(struct ast_xml_node *rootnode, const char *rootname, const char *childname, int printparenthesis, int printrootname)
{
#define GOTONEXT(__rev, __a) (__rev ? ast_xml_node_get_prev(__a) : ast_xml_node_get_next(__a))
#define ISLAST(__rev, __a) (__rev == 1 ? (ast_xml_node_get_prev(__a) ? 0 : 1) : (ast_xml_node_get_next(__a) ? 0 : 1))
@@ -679,7 +682,7 @@ static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootna
}
/* Get the argument name, if it is not the leaf, go inside that parameter. */
- if (xmldoc_has_arguments(node)) {
+ if (xmldoc_has_inside(node, "arguments")) {
parenthesis = ast_xml_get_attribute(node, "hasparams");
prnparenthesis = 0;
if (parenthesis) {
@@ -691,7 +694,7 @@ static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootna
}
argname = ast_xml_get_attribute(node, "name");
if (argname) {
- paramname = xmldoc_get_syntax(node, argname, "argument", prnparenthesis, prnparenthesis);
+ paramname = xmldoc_get_syntax_fun(node, argname, "argument", prnparenthesis, prnparenthesis);
ast_xml_free_attr(argname);
paramnamemalloc = 1;
} else {
@@ -805,6 +808,182 @@ static char *xmldoc_get_syntax(struct ast_xml_node *rootnode, const char *rootna
#undef MP
}
+/*! \internal
+ * \brief Parse an enumlist inside a <parameter> to generate a COMMAND
+ * syntax.
+ * \param fixnode A pointer to the <enumlist> node.
+ * \retval {<unknown>} on error.
+ * \retval A string inside brackets {} with the enum's separated by pipes |.
+ */
+static char *xmldoc_parse_cmd_enumlist(struct ast_xml_node *fixnode)
+{
+ struct ast_xml_node *node = fixnode;
+ struct ast_str *paramname;
+ char *enumname, *ret;
+ int first = 1;
+
+ paramname = ast_str_create(128);
+ if (!paramname) {
+ return ast_strdup("{<unkown>}");
+ }
+
+ ast_str_append(&paramname, 0, "{");
+
+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
+ if (strcasecmp(ast_xml_node_get_name(node), "enum")) {
+ continue;
+ }
+
+ enumname = xmldoc_get_syntax_cmd(node, "", 0);
+ if (!enumname) {
+ continue;
+ }
+ if (!first) {
+ ast_str_append(&paramname, 0, "|");
+ }
+ ast_str_append(&paramname, 0, "%s", enumname);
+ first = 0;
+ ast_free(enumname);
+ }
+
+ ast_str_append(&paramname, 0, "}");
+
+ ret = ast_strdup(paramname->str);
+ ast_free(paramname);
+
+ return ret;
+}
+
+/*! \internal
+ * \brief Generate a syntax of COMMAND type.
+ * \param fixnode The <syntax> node pointer.
+ * \param name The name of the 'command'.
+ * \param printname Print the name of the command before the paramters?
+ * \retval On error, return just 'name'.
+ * \retval On success return the generated syntax.
+ */
+static char *xmldoc_get_syntax_cmd(struct ast_xml_node *fixnode, const char *name, int printname)
+{
+ struct ast_str *syntax;
+ struct ast_xml_node *tmpnode, *node = fixnode;
+ char *ret;
+ const char *paramname, *paramtype, *attrname, *literal;
+ int required, isenum, first = 1, isliteral;
+
+ syntax = ast_str_create(128);
+ if (!syntax) {
+ /* at least try to return something... */
+ return ast_strdup(name);
+ }
+
+ /* append name to output string. */
+ if (printname) {
+ ast_str_append(&syntax, 0, "%s", name);
+ first = 0;
+ }
+
+ for (node = ast_xml_node_get_children(node); node; node = ast_xml_node_get_next(node)) {
+ if (strcasecmp(ast_xml_node_get_name(node), "parameter")) {
+ continue;
+ }
+
+ if (xmldoc_has_inside(node, "parameter")) {
+ /* is this a recursive parameter. */
+ paramname = xmldoc_get_syntax_cmd(node, "", 0);
+ isenum = 1;
+ } else if (!xmldoc_has_inside(node, "enumlist")) {
+ /* this is a simple parameter. */
+ attrname = ast_xml_get_attribute(node, "name");
+ if (!attrname) {
+ /* ignore this bogus parameter and continue. */
+ continue;
+ }
+ paramname = ast_strdup(attrname);
+ ast_xml_free_attr(attrname);
+ isenum = 0;
+ } else {
+ /* parse enumlist (note that this is a special enumlist
+ that is used to describe a syntax like {<param1>|<param2>|...} */
+ for (tmpnode = ast_xml_node_get_children(node); tmpnode; tmpnode = ast_xml_node_get_next(tmpnode)) {
+ if (!strcasecmp(ast_xml_node_get_name(tmpnode), "enumlist")) {
+ break;
+ }
+ }
+ paramname = xmldoc_parse_cmd_enumlist(tmpnode);
+ isenum = 1;
+ }
+
+ /* Is this parameter required? */
+ required = 0;
+ paramtype = ast_xml_get_attribute(node, "required");
+ if (paramtype) {
+ required = ast_true(paramtype);
+ ast_xml_free_attr(paramtype);
+ }
+
+ /* Is this a replaceable value or a fixed parameter value? */
+ isliteral = 0;
+ literal = ast_xml_get_attribute(node, "literal");
+ if (literal) {
+ isliteral = ast_true(literal);
+ ast_xml_free_attr(literal);
+ }
+
+ /* if required="false" print with [...].
+ * if literal="true" or is enum print without <..>.
+ * if not first print a space at the beginning.
+ */
+ ast_str_append(&syntax, 0, "%s%s%s%s%s%s",
+ (first ? "" : " "),
+ (required ? "" : "["),
+ (isenum || isliteral ? "" : "<"),
+ paramname,
+ (isenum || isliteral ? "" : ">"),
+ (required ? "" : "]"));
+ first = 0;
+ ast_xml_free_attr(paramname);
+ }
+
+ /* return a common string. */
+ ret = ast_strdup(syntax->str);
+ ast_free(syntax);
+
+ return ret;
+}
+
+/*! \brief Types of syntax that we are able to generate. */
+enum syntaxtype {
+ FUNCTION_SYNTAX,
+ COMMAND_SYNTAX
+};
+
+/*! \brief Mapping between type of node and type of syntax to generate. */
+struct strsyntaxtype {
+ const char *type;
+ enum syntaxtype stxtype;
+} stxtype[] = {
+ { "function", FUNCTION_SYNTAX },
+ { "application", FUNCTION_SYNTAX },
+ { "agi", COMMAND_SYNTAX }
+};
+
+/*! \internal
+ * \brief Get syntax type based on type of node.
+ * \param type Type of node.
+ * \retval The type of syntax to generate based on the type of node.
+ */
+static enum syntaxtype xmldoc_get_syntax_type(const char *type)
+{
+ int i;
+ for (i=0; i < ARRAY_LEN(stxtype); i++) {
+ if (!strcasecmp(stxtype[i].type, type)) {
+ return stxtype[i].stxtype;
+ }
+ }
+
+ return FUNCTION_SYNTAX;
+}
+
char *ast_xmldoc_build_syntax(const char *type, const char *name)
{
struct ast_xml_node *node;
@@ -822,7 +1001,11 @@ char *ast_xmldoc_build_syntax(const char *type, const char *name)
}
if (node) {
- syntax = xmldoc_get_syntax(node, name, "parameter", 1, 1);
+ if (xmldoc_get_syntax_type(type) == FUNCTION_SYNTAX) {
+ syntax = xmldoc_get_syntax_fun(node, name, "parameter", 1, 1);
+ } else {
+ syntax = xmldoc_get_syntax_cmd(node, name, 1);
+ }
}
return syntax;
}
@@ -1294,7 +1477,7 @@ static void xmldoc_parse_optionlist(struct ast_xml_node *fixnode, const char *ta
continue;
}
- optionsyntax = xmldoc_get_syntax(node, optname, "argument", 0, 1);
+ optionsyntax = xmldoc_get_syntax_fun(node, optname, "argument", 0, 1);
if (!optionsyntax) {
continue;
}
@@ -1325,7 +1508,7 @@ static void xmldoc_parse_parameter(struct ast_xml_node *fixnode, const char *tab
return;
}
- hasarguments = xmldoc_has_arguments(node);
+ hasarguments = xmldoc_has_inside(node, "arguments");
if (!(paramname = ast_xml_get_attribute(node, "name"))) {
/* parameter MUST have an attribute name. */
return;
diff --git a/res/res_agi.c b/res/res_agi.c
index eba9ddb9c..45799aea0 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -57,8 +57,66 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/speech.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
+#include "asterisk/term.h"
+#include "asterisk/xmldoc.h"
+
+/*** DOCUMENTATION
+ <agi name="answer" language="en_US">
+ <synopsis>
+ Answer channel
+ </synopsis>
+ <syntax />
+ <description>
+ <para>Answers channel if not already in answer state. Returns <literal>-1</literal> on
+ channel failure, or <literal>0</literal> if successful.</para>
+ </description>
+ <see-also>
+ <ref type="agi">hangup</ref>
+ </see-also>
+ </agi>
+ <agi name="channel status" language="en_US">
+ <synopsis>
+ Returns status of the connected channel.
+ </synopsis>
+ <syntax>
+ <parameter name="channelname" />
+ </syntax>
+ <description>
+ <para>Returns the status of the specified <replaceable>channelname</replaceable>.
+ If no channel name is given then returns the status of the current channel.</para>
+ <para>Return values:</para>
+ <enumlist>
+ <enum name="0">
+ <para>Channel is down and available.</para>
+ </enum>
+ <enum name="1">
+ <para>Channel is down, but reserved.</para>
+ </enum>
+ <enum name="2">
+ <para>Channel is off hook.</para>
+ </enum>
+ <enum name="3">
+ <para>Digits (or equivalent) have been dialed.</para>
+ </enum>
+ <enum name="4">
+ <para>Line is ringing.</para>
+ </enum>
+ <enum name="5">
+ <para>Remote end is ringing.</para>
+ </enum>
+ <enum name="6">
+ <para>Line is up.</para>
+ </enum>
+ <enum name="7">
+ <para>Line is busy.</para>
+ </enum>
+ </enumlist>
+ </description>
+ </agi>
+ ***/
#define MAX_ARGS 128
+#define MAX_CMD_LEN 80
#define AGI_NANDFS_RETRY 3
#define AGI_BUF_LEN 2048
@@ -2047,20 +2105,6 @@ static char usage_getvariablefull[] =
static char usage_setvariable[] =
" Usage: SET VARIABLE <variablename> <value>\n";
-static char usage_channelstatus[] =
-" Usage: CHANNEL STATUS [<channelname>]\n"
-" Returns the status of the specified channel.\n"
-" If no channel name is given the returns the status of the\n"
-" current channel. Return values:\n"
-" 0 Channel is down and available\n"
-" 1 Channel is down, but reserved\n"
-" 2 Channel is off hook\n"
-" 3 Digits (or equivalent) have been dialed\n"
-" 4 Line is ringing\n"
-" 5 Remote end is ringing\n"
-" 6 Line is up\n"
-" 7 Line is busy\n";
-
static char usage_setcallerid[] =
" Usage: SET CALLERID <number>\n"
" Changes the callerid of the current channel.\n";
@@ -2075,11 +2119,6 @@ static char usage_hangup[] =
" Hangs up the specified channel.\n"
" If no channel name is given, hangs up the current channel\n";
-static char usage_answer[] =
-" Usage: ANSWER\n"
-" Answers channel if not already in answer state. Returns -1 on\n"
-" channel failure, or 0 if successful.\n";
-
static char usage_waitfordigit[] =
" Usage: WAIT FOR DIGIT <timeout>\n"
" Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
@@ -2280,8 +2319,8 @@ static char usage_speechrecognize[] =
* \brief AGI commands list
*/
static struct agi_command commands[] = {
- { { "answer", NULL }, handle_answer, "Answer channel", usage_answer , 0 },
- { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus , 0 },
+ { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
+ { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
{ { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 },
{ { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree , 1 },
{ { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget , 1 },
@@ -2332,7 +2371,7 @@ static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
static char *help_workhorse(int fd, char *match[])
{
- char fullcmd[80], matchstr[80];
+ char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
struct agi_command *e;
if (match)
@@ -2358,11 +2397,21 @@ static char *help_workhorse(int fd, char *match[])
int ast_agi_register(struct ast_module *mod, agi_command *cmd)
{
- char fullcmd[80];
+ char fullcmd[MAX_CMD_LEN];
ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
- if (!find_command(cmd->cmda,1)) {
+ if (!find_command(cmd->cmda,1)) {
+ cmd->docsrc = AST_STATIC_DOC;
+#ifdef AST_XML_DOCS
+ if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
+ cmd->summary = ast_xmldoc_build_synopsis("agi", fullcmd);
+ cmd->usage = ast_xmldoc_build_description("agi", fullcmd);
+ cmd->syntax = ast_xmldoc_build_syntax("agi", fullcmd);
+ cmd->seealso = ast_xmldoc_build_seealso("agi", fullcmd);
+ cmd->docsrc = AST_XML_DOC;
+ }
+#endif
cmd->mod = mod;
AST_RWLIST_WRLOCK(&agi_commands);
AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
@@ -2381,7 +2430,7 @@ int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
{
struct agi_command *e;
int unregistered = 0;
- char fullcmd[80];
+ char fullcmd[MAX_CMD_LEN];
ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
@@ -2391,6 +2440,16 @@ int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
AST_RWLIST_REMOVE_CURRENT(list);
if (mod != ast_module_info->self)
ast_module_unref(ast_module_info->self);
+#ifdef AST_XML_DOCS
+ if (e->docsrc == AST_XML_DOC) {
+ ast_free(e->summary);
+ ast_free(e->usage);
+ ast_free(e->syntax);
+ ast_free(e->seealso);
+ e->summary = NULL, e->usage = NULL;
+ e->syntax = NULL, e->seealso = NULL;
+ }
+#endif
unregistered=1;
break;
}
@@ -2728,7 +2787,8 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct agi_command *command;
- char fullcmd[80];
+ char fullcmd[MAX_CMD_LEN];
+ int error = 0;
switch (cmd) {
case CLI_INIT:
@@ -2746,8 +2806,73 @@ static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cl
if (a->argc > e->args - 1) {
command = find_command(a->argv + e->args, 1);
if (command) {
- ast_cli(a->fd, "%s", command->usage);
- ast_cli(a->fd, " Runs Dead : %s\n", command->dead ? "Yes" : "No");
+ char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
+ char info[30 + MAX_CMD_LEN]; /* '-= Info about...' */
+ char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS]; /* '-= Info about...' with colors */
+ char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
+ char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Description]\n with colors */
+ char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Runs Dead]\n with colors */
+ char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS]; /* 'Yes' or 'No' with colors */
+ char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS]; /* [See Also]\n with colors */
+ char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS]; /* [Syntax]\n with colors */
+ size_t synlen, desclen, seealsolen, stxlen;
+
+ term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
+ term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
+ term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
+ term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
+ term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
+ term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
+
+ ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
+ snprintf(info, sizeof(info), "\n -= Info about agi '%s' =- ", fullcmd);
+ term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
+#ifdef AST_XML_DOCS
+ if (command->docsrc == AST_XML_DOC) {
+ synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
+ description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
+ seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
+ if (!seealso || !description || !synopsis) {
+ error = 1;
+ goto return_cleanup;
+ }
+ } else
+#endif
+ {
+ synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
+ synopsis = ast_malloc(synlen);
+
+ desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
+ description = ast_malloc(desclen);
+
+ seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
+ seealso = ast_malloc(seealsolen);
+
+ if (!synopsis || !description || !seealso) {
+ error = 1;
+ goto return_cleanup;
+ }
+ term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
+ term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
+ term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
+ }
+
+ stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
+ syntax = ast_malloc(stxlen);
+ if (!syntax) {
+ error = 1;
+ goto return_cleanup;
+ }
+ term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
+
+ ast_cli(a->fd, "%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n", infotitle, stxtitle, syntax,
+ desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
+ seealsotitle, seealso);
+return_cleanup:
+ ast_free(synopsis);
+ ast_free(description);
+ ast_free(syntax);
+ ast_free(seealso);
} else {
if (find_command(a->argv + e->args, -1)) {
return help_workhorse(a->fd, a->argv + e->args);
@@ -2759,7 +2884,7 @@ static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cl
} else {
return help_workhorse(a->fd, NULL);
}
- return CLI_SUCCESS;
+ return (error ? CLI_FAILURE : CLI_SUCCESS);
}
/*! \brief Convert string to use HTML escaped characters
@@ -2796,7 +2921,7 @@ static void write_html_escaped(FILE *htmlfile, char *str)
static int write_htmldump(char *filename)
{
struct agi_command *command;
- char fullcmd[80];
+ char fullcmd[MAX_CMD_LEN];
FILE *htmlfile;
if (!(htmlfile = fopen(filename, "wt")))
@@ -2808,7 +2933,10 @@ static int write_htmldump(char *filename)
AST_RWLIST_RDLOCK(&agi_commands);
AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
- char *stringp, *tempstr;
+#ifdef AST_XML_DOCS
+ char *stringptmp;
+#endif
+ char *tempstr, *stringp;
if (!command->cmda[0]) /* end ? */
break;
@@ -2819,8 +2947,12 @@ static int write_htmldump(char *filename)
fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
-
+#ifdef AST_XML_DOCS
+ stringptmp = ast_xmldoc_printable(command->usage, 0);
+ stringp = stringptmp;
+#else
stringp = command->usage;
+#endif
tempstr = strsep(&stringp, "\n");
fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
@@ -2834,6 +2966,9 @@ static int write_htmldump(char *filename)
}
fprintf(htmlfile, "</TD></TR>\n");
fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
+#ifdef AST_XML_DOCS
+ ast_free(stringptmp);
+#endif
}
AST_RWLIST_UNLOCK(&agi_commands);
fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");