aboutsummaryrefslogtreecommitdiffstats
path: root/res/res_agi.c
diff options
context:
space:
mode:
authoreliel <eliel@f38db490-d61c-443f-a65b-d21fe96a405b>2008-11-12 00:17:43 +0000
committereliel <eliel@f38db490-d61c-443f-a65b-d21fe96a405b>2008-11-12 00:17:43 +0000
commitf4ab4abaf3f24f01cc695a96649585ab7fc91948 (patch)
treeea3966ab1c52341565ff036f510bb7ecddaef0b4 /res/res_agi.c
parentd8c640af72a7468ebf5a492093b8148a8dfeb62d (diff)
Implement AGI XML documentation parsing functions.
A new <agi> element is used to describe the XML documentation. We have the usual synopsis,syntax,description and seealso for AGI commands. The CLI 'agi show commands' command was changed to show all the documentation se ctions. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@156051 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res/res_agi.c')
-rw-r--r--res/res_agi.c199
1 files changed, 167 insertions, 32 deletions
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");