diff options
-rw-r--r-- | doc/appdocsxml.dtd | 27 | ||||
-rw-r--r-- | include/asterisk/agi.h | 21 | ||||
-rw-r--r-- | main/xmldoc.c | 203 | ||||
-rw-r--r-- | res/res_agi.c | 199 |
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(¶mname, 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(¶mname, 0, "|"); + } + ast_str_append(¶mname, 0, "%s", enumname); + first = 0; + ast_free(enumname); + } + + ast_str_append(¶mname, 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"); |