Index: include/asterisk/agi.h =================================================================== --- include/asterisk/agi.h (revision 77232) +++ include/asterisk/agi.h (working copy) @@ -23,6 +23,8 @@ #ifndef _ASTERISK_AGI_H #define _ASTERISK_AGI_H +#define AGI_MAX_DEPTH 8 + #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif @@ -30,12 +32,12 @@ typedef struct agi_state { int fd; /* FD for general output */ int audio; /* FD for audio output */ - int ctrl; /* FD for input control */ + int ctrl; /* FD for input control */ } AGI; typedef struct agi_command { /* Null terminated list of the words of the command */ - char *cmda[AST_MAX_CMD_LEN]; + char *cmda[AGI_MAX_DEPTH]; /* 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[]); @@ -45,12 +47,17 @@ char *usage; /* Does this application run dead */ int dead; + /* Pointer to module that registered the agi command */ + struct ast_module *mod; /* Linked list pointer */ AST_LIST_ENTRY(agi_command) list; } agi_command; -int ast_agi_register(agi_command *cmd); -int ast_agi_unregister(agi_command *cmd); +void ast_agi_fdprintf(int fd, char *fmt, ...); +int ast_agi_register(struct ast_module *mod, agi_command *cmd); +int ast_agi_unregister(struct ast_module *mod, agi_command *cmd); +void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len); +void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len); #if defined(__cplusplus) || defined(c_plusplus) } Index: res/res_agi.c =================================================================== --- res/res_agi.c (revision 77232) +++ res/res_agi.c (working copy) @@ -67,11 +67,7 @@ #include "asterisk/agi.h" #define MAX_ARGS 128 -#define MAX_COMMANDS 128 -/* Recycle some stuff from the CLI interface */ -#define fdprintf agi_debug_cli - static char *app = "AGI"; static char *eapp = "EAGI"; @@ -119,7 +115,7 @@ static agi_command *find_command(char *cmds[], int exact); -static void agi_debug_cli(int fd, char *fmt, ...) +void ast_agi_fdprintf(int fd, char *fmt, ...) { char *stuff; int res = 0; @@ -221,7 +217,7 @@ /* If we have a script parameter, relay it to the fastagi server */ /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */ if (!ast_strlen_zero(script)) - fdprintf(s, "agi_network_script: %s\n", script); + ast_agi_fdprintf(s, "agi_network_script: %s\n", script); ast_debug(4, "Wow, connected!\n"); fds[0] = s; @@ -1025,10 +1021,10 @@ break; } - if (gotsilence) { - ast_stream_rewind(fs, silence-1000); - ast_truncstream(fs); - sample_offset = ast_tellstream(fs); + if (gotsilence) { + ast_stream_rewind(fs, silence-1000); + ast_truncstream(fs); + sample_offset = ast_tellstream(fs); } fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); ast_closestream(fs); @@ -1589,7 +1585,7 @@ /*! * \brief AGI commands list */ -static struct agi_command commands[MAX_COMMANDS] = { +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 }, { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel , 1 }, @@ -1656,12 +1652,19 @@ return 0; } -int ast_agi_register(agi_command *agi) +int ast_agi_register(struct ast_module *mod, agi_command *cmd) { - if (!find_command(agi->cmda,1)) { + char fullcmd[80]; + + ast_join(fullcmd, sizeof(fullcmd), cmd->cmda); + + if (!find_command(cmd->cmda,1)) { AST_RWLIST_WRLOCK(&agi_commands); - AST_LIST_INSERT_TAIL(&agi_commands, agi, list); + AST_LIST_INSERT_TAIL(&agi_commands, cmd, list); AST_RWLIST_UNLOCK(&agi_commands); + if (mod != ast_module_info->self) + ast_module_ref(ast_module_info->self); + ast_verb(2, "AGI Command '%s' registered\n",fullcmd); return 1; } else { ast_log(LOG_WARNING, "Command already registered!\n"); @@ -1669,26 +1672,50 @@ } } -int ast_agi_unregister(agi_command *cmd) +int ast_agi_unregister(struct ast_module *mod, agi_command *cmd) { struct agi_command *e; int unregistered = 0; + char fullcmd[80]; + + ast_join(fullcmd, sizeof(fullcmd), cmd->cmda); AST_RWLIST_WRLOCK(&agi_commands); AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) { if (cmd == e) { AST_RWLIST_REMOVE_CURRENT(&agi_commands, list); + if (mod != ast_module_info->self) + ast_module_unref(ast_module_info->self); unregistered=1; break; } } AST_RWLIST_TRAVERSE_SAFE_END AST_RWLIST_UNLOCK(&agi_commands); - if (!unregistered) - ast_log(LOG_WARNING, "Unable to unregister command!\n"); + if (unregistered) + ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd); + else + ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd); return unregistered; } +void ast_agi_register_multiple(struct ast_module *mod, agi_command *cmd, int len) +{ + int i; + + for (i = 0; i < len; i++) + ast_agi_register(mod, cmd + i); + +} + +void ast_agi_unregister_multiple(struct ast_module *mod, agi_command *cmd, int len) +{ + int i; + + for (i = 0; i < len; i++) + ast_agi_unregister(mod, cmd + i); +} + static agi_command *find_command(char *cmds[], int exact) { int y, match; @@ -1794,7 +1821,13 @@ parse_args(buf, &argc, argv); if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) { + /* if this command wasnt registered by res_agi, be sure to usecount + the module we are using */ + if (c->mod != ast_module_info->self) + ast_module_ref(c->mod); res = c->handler(chan, agi, argc, argv); + if (c->mod != ast_module_info->self) + ast_module_unref(c->mod); switch(res) { case RESULT_SHOWUSAGE: fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n"); @@ -2160,15 +2193,9 @@ static int unload_module(void) { - struct agi_command *e; ast_cli_unregister_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry)); - AST_RWLIST_WRLOCK(&agi_commands); - AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) { - AST_RWLIST_REMOVE_CURRENT(&agi_commands, list); - } - AST_RWLIST_TRAVERSE_SAFE_END - AST_RWLIST_UNLOCK(&agi_commands); + ast_agi_unregister_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command)); ast_unregister_application(eapp); ast_unregister_application(deadapp); return ast_unregister_application(app); @@ -2176,12 +2203,8 @@ static int load_module(void) { - int i; - ast_cli_register_multiple(cli_agi, sizeof(cli_agi) / sizeof(struct ast_cli_entry)); - for (i=0; i < (sizeof(commands) / sizeof(struct agi_command)); i++) { - ast_agi_register(&commands[i]); - } + ast_agi_register_multiple(ast_module_info->self, commands, sizeof(commands) / sizeof(struct agi_command)); ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip); ast_register_application(eapp, eagi_exec, esynopsis, descrip); return ast_register_application(app, agi_exec, synopsis, descrip);