Thu Oct 11 06:49:34 2012

Asterisk developer's documentation


res_agi.c File Reference

AGI - the Asterisk Gateway Interface. More...

#include "asterisk.h"
#include <math.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <pthread.h>
#include "asterisk/paths.h"
#include "asterisk/network.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/astdb.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/image.h"
#include "asterisk/say.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/musiconhold.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/strings.h"
#include "asterisk/manager.h"
#include "asterisk/ast_version.h"
#include "asterisk/speech.h"
#include "asterisk/features.h"
#include "asterisk/term.h"
#include "asterisk/xmldoc.h"
#include "asterisk/agi.h"

Include dependency graph for res_agi.c:

Go to the source code of this file.

Data Structures

struct  agi_cmd
struct  agi_commands

Defines

#define AGI_BUF_INITSIZE   256
#define AGI_BUF_LEN   2048
#define AGI_BUF_SIZE   1024
#define AGI_NANDFS_RETRY   3
#define AGI_PORT   4573
#define AMI_BUF_SIZE   2048
#define AST_API_MODULE
#define MAX_AGI_CONNECT   2000
#define MAX_ARGS   128
#define MAX_CMD_LEN   80
#define TONE_BLOCK_SIZE   200

Enumerations

enum  agi_result {
  AGI_RESULT_FAILURE = -1, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_FAST, AGI_RESULT_SUCCESS_ASYNC,
  AGI_RESULT_NOTFOUND, AGI_RESULT_HANGUP
}

Functions

static void __fini_agi_commands (void)
static void __init_agi_buf (void)
static void __init_agi_commands (void)
static void __reg_module (void)
static void __unreg_module (void)
static int action_add_agi_cmd (struct mansession *s, const struct message *m)
 Add a new command to execute by the Async AGI application.
static int add_agi_cmd (struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
static int add_to_agi (struct ast_channel *chan)
static void agi_destroy_commands_cb (void *data)
static int agi_exec (struct ast_channel *chan, void *data)
static int agi_exec_full (struct ast_channel *chan, void *data, int enhanced, int dead)
static enum agi_result agi_handle_command (struct ast_channel *chan, AGI *agi, char *buf, int dead)
int ast_agi_register (struct ast_module *mod, agi_command *cmd)
 Registers an AGI command.
int ast_agi_register_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len)
 Registers a group of AGI commands, provided as an array of struct agi_command entries.
int ast_agi_send (int fd, struct ast_channel *chan, char *fmt,...)
 Sends a string of text to an application connected via AGI.
int ast_agi_unregister (struct ast_module *mod, agi_command *cmd)
 Unregisters an AGI command.
int ast_agi_unregister_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len)
 Unregisters a group of AGI commands, provided as an array of struct agi_command entries.
static int deadagi_exec (struct ast_channel *chan, void *data)
static int eagi_exec (struct ast_channel *chan, void *data)
static agi_commandfind_command (char *cmds[], int exact)
static void free_agi_cmd (struct agi_cmd *cmd)
static struct agi_cmdget_agi_cmd (struct ast_channel *chan)
static int handle_answer (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_asyncagi_break (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_autohangup (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_channelstatus (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static char * handle_cli_agi_add_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to add applications to execute in Async AGI.
static char * handle_cli_agi_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_agi_dump_html (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_agi_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int handle_controlstreamfile (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_dbdel (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_dbdeltree (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_dbget (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_dbput (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_exec (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_getdata (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_getoption (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
 get option - really similar to the handle_streamfile, but with a timeout
static int handle_getvariable (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_getvariablefull (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_hangup (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_noop (struct ast_channel *chan, AGI *agi, int arg, char *argv[])
static int handle_recordfile (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_recvchar (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_recvtext (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_sayalpha (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_saydate (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_saydatetime (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_saydigits (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_saynumber (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
 Say number in various language syntaxes.
static int handle_sayphonetic (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_saytime (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_sendimage (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_sendtext (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_setcallerid (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_setcontext (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_setextension (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_setmusic (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_setpriority (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_setvariable (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_speechactivategrammar (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_speechcreate (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_speechdeactivategrammar (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_speechdestroy (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_speechloadgrammar (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_speechrecognize (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_speechset (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_speechunloadgrammar (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_streamfile (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_tddmode (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static int handle_verbose (struct ast_channel *chan, AGI *agi, int argc, char **argv)
static int handle_waitfordigit (struct ast_channel *chan, AGI *agi, int argc, char *argv[])
static char * help_workhorse (int fd, char *match[])
static enum agi_result launch_asyncagi (struct ast_channel *chan, char *argv[], int *efd)
static enum agi_result launch_netscript (char *agiurl, char *argv[], int *fds, int *efd, int *opid)
static enum agi_result launch_script (struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
static int load_module (void)
static int parse_args (char *s, int *max, char *argv[])
static enum agi_result run_agi (struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
static void setup_env (struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
static int speech_streamfile (struct ast_channel *chan, const char *filename, const char *preflang, int offset)
static int unload_module (void)
static void write_html_escaped (FILE *htmlfile, char *str)
 Convert string to use HTML escaped characters.
static int write_htmldump (char *filename)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "Asterisk Gateway Interface (AGI)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static struct ast_threadstorage agi_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_agi_buf , .custom_init = NULL , }
static struct ast_datastore_info agi_commands_datastore_info
static int agidebug = 0
static char * app = "AGI"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_agi []
static struct agi_command commands []
 AGI commands list.
static char * deadapp = "DeadAGI"
static char * deadsynopsis = "Executes AGI on a hungup channel"
static char * descrip
static char * eapp = "EAGI"
static char * esynopsis = "Executes an EAGI compliant application"
static const char mandescr_asyncagi []
static char * synopsis = "Executes an AGI compliant application"
static char usage_autohangup []
static char usage_controlstreamfile []
static char usage_recordfile []
static char usage_recvchar []
static char usage_recvtext []
static char usage_sayalpha []
static char usage_saydate []
static char usage_saydatetime []
static char usage_saydigits []
static char usage_saynumber []
static char usage_sayphonetic []
static char usage_saytime []
static char usage_sendimage []
static char usage_sendtext []
static char usage_setcallerid []
static char usage_setcontext []
static char usage_setextension []
static char usage_setpriority []
static char usage_setvariable []
static char usage_speechactivategrammar []
static char usage_speechcreate []
static char usage_speechdeactivategrammar []
static char usage_speechdestroy []
static char usage_speechloadgrammar []
static char usage_speechrecognize []
static char usage_speechset []
static char usage_speechunloadgrammar []
static char usage_streamfile []
static char usage_tddmode []
static char usage_verbose []
static char usage_waitfordigit []


Detailed Description

AGI - the Asterisk Gateway Interface.

Author:
Mark Spencer <markster@digium.com>
Todo:
Convert the rest of the AGI commands over to XML documentation

Definition in file res_agi.c.


Define Documentation

#define AGI_BUF_INITSIZE   256

Definition at line 374 of file res_agi.c.

Referenced by ast_agi_send().

#define AGI_BUF_LEN   2048

Definition at line 320 of file res_agi.c.

Referenced by agi_exec_full(), and run_agi().

#define AGI_BUF_SIZE   1024

Referenced by launch_asyncagi().

#define AGI_NANDFS_RETRY   3

Definition at line 319 of file res_agi.c.

Referenced by run_agi().

#define AGI_PORT   4573

Definition at line 360 of file res_agi.c.

Referenced by launch_netscript().

#define AMI_BUF_SIZE   2048

Referenced by launch_asyncagi().

#define AST_API_MODULE

Definition at line 64 of file res_agi.c.

#define MAX_AGI_CONNECT   2000

Definition at line 358 of file res_agi.c.

Referenced by launch_netscript().

#define MAX_ARGS   128

Definition at line 317 of file res_agi.c.

#define MAX_CMD_LEN   80

#define TONE_BLOCK_SIZE   200

Definition at line 355 of file res_agi.c.


Enumeration Type Documentation

enum agi_result

Enumerator:
AGI_RESULT_FAILURE 
AGI_RESULT_SUCCESS 
AGI_RESULT_SUCCESS_FAST 
AGI_RESULT_SUCCESS_ASYNC 
AGI_RESULT_NOTFOUND 
AGI_RESULT_HANGUP 

Definition at line 362 of file res_agi.c.


Function Documentation

static void __fini_agi_commands ( void   )  [static]

Definition at line 2531 of file res_agi.c.

02534 {

static void __init_agi_buf ( void   )  [static]

Definition at line 373 of file res_agi.c.

00377 {

static void __init_agi_commands ( void   )  [static]

Definition at line 2531 of file res_agi.c.

02534 {

static void __reg_module ( void   )  [static]

Definition at line 3369 of file res_agi.c.

static void __unreg_module ( void   )  [static]

Definition at line 3369 of file res_agi.c.

static int action_add_agi_cmd ( struct mansession s,
const struct message m 
) [static]

Add a new command to execute by the Async AGI application.

Parameters:
s 
m It will append the application to the specified channel's queue if the channel is not inside Async AGI application it will return an error
Return values:
0 on success or incorrect use
1 on failure to add the command ( most likely because the channel is not in Async AGI loop )

Definition at line 588 of file res_agi.c.

References add_agi_cmd(), ast_channel_unlock, ast_get_channel_by_name_locked(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), buf, chan, and ast_channel::name.

Referenced by load_module().

00589 {
00590    const char *channel = astman_get_header(m, "Channel");
00591    const char *cmdbuff = astman_get_header(m, "Command");
00592    const char *cmdid   = astman_get_header(m, "CommandID");
00593    struct ast_channel *chan;
00594    char buf[256];
00595    if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
00596       astman_send_error(s, m, "Both, Channel and Command are *required*");
00597       return 0;
00598    }
00599    chan = ast_get_channel_by_name_locked(channel);
00600    if (!chan) {
00601       snprintf(buf, sizeof(buf), "Channel %s does not exists or cannot get its lock", channel);
00602       astman_send_error(s, m, buf);
00603       return 0;
00604    }
00605    if (add_agi_cmd(chan, cmdbuff, cmdid)) {
00606       snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
00607       astman_send_error(s, m, buf);
00608       ast_channel_unlock(chan);
00609       return 0;
00610    }
00611    astman_send_ack(s, m, "Added AGI command to queue");
00612    ast_channel_unlock(chan);
00613    return 0;
00614 }

static int add_agi_cmd ( struct ast_channel chan,
const char *  cmd_buff,
const char *  cmd_id 
) [static]

Definition at line 468 of file res_agi.c.

References agi_commands_datastore_info, ast_calloc, ast_channel_datastore_find(), ast_free, AST_LIST_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_strdup, agi_cmd::cmd_buffer, agi_cmd::cmd_id, ast_datastore::data, agi_cmd::entry, LOG_WARNING, and ast_channel::name.

Referenced by action_add_agi_cmd(), and handle_cli_agi_add_cmd().

00469 {
00470    struct ast_datastore *store;
00471    struct agi_cmd *cmd;
00472    AST_LIST_HEAD(, agi_cmd) *agi_commands;
00473 
00474    store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
00475    if (!store) {
00476       ast_log(LOG_WARNING, "Channel %s is not at Async AGI.\n", chan->name);
00477       return -1;
00478    }
00479    agi_commands = store->data;
00480    cmd = ast_calloc(1, sizeof(*cmd));
00481    if (!cmd) {
00482       return -1;
00483    }
00484    cmd->cmd_buffer = ast_strdup(cmd_buff);
00485    if (!cmd->cmd_buffer) {
00486       ast_free(cmd);
00487       return -1;
00488    }
00489    cmd->cmd_id = ast_strdup(cmd_id);
00490    if (!cmd->cmd_id) {
00491       ast_free(cmd->cmd_buffer);
00492       ast_free(cmd);
00493       return -1;
00494    }
00495    AST_LIST_LOCK(agi_commands);
00496    AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
00497    AST_LIST_UNLOCK(agi_commands);
00498    return 0;
00499 }

static int add_to_agi ( struct ast_channel chan  )  [static]

Definition at line 501 of file res_agi.c.

References agi_commands_datastore_info, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), AST_LIST_HEAD, AST_LIST_HEAD_INIT, ast_log(), ast_datastore::data, and LOG_ERROR.

Referenced by launch_asyncagi().

00502 {
00503    struct ast_datastore *datastore;
00504    AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
00505 
00506    /* check if already on AGI */
00507    ast_channel_lock(chan);
00508    datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
00509    ast_channel_unlock(chan);
00510    if (datastore) {
00511       /* we already have an AGI datastore, let's just
00512          return success */
00513       return 0;
00514    }
00515 
00516    /* the channel has never been on Async AGI,
00517       let's allocate it's datastore */
00518    datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI");
00519    if (!datastore) {
00520       return -1;
00521    }
00522    agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
00523    if (!agi_cmds_list) {
00524       ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
00525       ast_datastore_free(datastore);
00526       return -1;
00527    }
00528    datastore->data = agi_cmds_list;
00529    AST_LIST_HEAD_INIT(agi_cmds_list);
00530    ast_channel_lock(chan);
00531    ast_channel_datastore_add(chan, datastore);
00532    ast_channel_unlock(chan);
00533    return 0;
00534 }

static void agi_destroy_commands_cb ( void *  data  )  [static]

Definition at line 420 of file res_agi.c.

References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, agi_cmd::entry, and free_agi_cmd().

00421 {
00422    struct agi_cmd *cmd;
00423    AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
00424    AST_LIST_LOCK(chan_cmds);
00425    while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
00426       free_agi_cmd(cmd);
00427    }
00428    AST_LIST_UNLOCK(chan_cmds);
00429    AST_LIST_HEAD_DESTROY(chan_cmds);
00430    ast_free(chan_cmds);
00431 }

static int agi_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 3297 of file res_agi.c.

References agi_exec_full(), and ast_check_hangup().

Referenced by deadagi_exec(), and load_module().

03298 {
03299    if (!ast_check_hangup(chan))
03300       return agi_exec_full(chan, data, 0, 0);
03301    else
03302       return agi_exec_full(chan, data, 0, 1);
03303 }

static int agi_exec_full ( struct ast_channel chan,
void *  data,
int  enhanced,
int  dead 
) [static]

Definition at line 3230 of file res_agi.c.

References ast_channel::_state, AGI_BUF_LEN, AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_NOTFOUND, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, AGI_RESULT_SUCCESS_FAST, ast_answer(), AST_APP_ARG, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_log(), ast_safe_fork_cleanup(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strlen_zero(), buf, launch_script(), LOG_WARNING, MAX_ARGS, pbx_builtin_setvar_helper(), run_agi(), and status.

Referenced by agi_exec(), and eagi_exec().

03231 {
03232    enum agi_result res;
03233    char buf[AGI_BUF_LEN] = "", *tmp = buf;
03234    int fds[2], efd = -1, pid;
03235    AST_DECLARE_APP_ARGS(args,
03236       AST_APP_ARG(arg)[MAX_ARGS];
03237    );
03238    AGI agi;
03239 
03240    if (ast_strlen_zero(data)) {
03241       ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
03242       return -1;
03243    }
03244    if (dead)
03245       ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
03246    ast_copy_string(buf, data, sizeof(buf));
03247    memset(&agi, 0, sizeof(agi));
03248    AST_STANDARD_APP_ARGS(args, tmp);
03249    args.argv[args.argc] = NULL;
03250 #if 0
03251     /* Answer if need be */
03252    if (chan->_state != AST_STATE_UP) {
03253       if (ast_answer(chan))
03254          return -1;
03255    }
03256 #endif
03257    res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
03258    /* Async AGI do not require run_agi(), so just proceed if normal AGI
03259       or Fast AGI are setup with success. */
03260    if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
03261       int status = 0;
03262       agi.fd = fds[1];
03263       agi.ctrl = fds[0];
03264       agi.audio = efd;
03265       agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
03266       res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
03267       /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
03268       if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
03269          res = AGI_RESULT_FAILURE;
03270       if (fds[1] != fds[0])
03271          close(fds[1]);
03272       if (efd > -1)
03273          close(efd);
03274    }
03275    ast_safe_fork_cleanup();
03276 
03277    switch (res) {
03278    case AGI_RESULT_SUCCESS:
03279    case AGI_RESULT_SUCCESS_FAST:
03280    case AGI_RESULT_SUCCESS_ASYNC:
03281       pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
03282       break;
03283    case AGI_RESULT_FAILURE:
03284       pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
03285       break;
03286    case AGI_RESULT_NOTFOUND:
03287       pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
03288       break;
03289    case AGI_RESULT_HANGUP:
03290       pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
03291       return -1;
03292    }
03293 
03294    return 0;
03295 }

static enum agi_result agi_handle_command ( struct ast_channel chan,
AGI agi,
char *  buf,
int  dead 
) [static]

Definition at line 2780 of file res_agi.c.

References AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, ast_agi_send(), ast_cdr_setapp(), ast_check_hangup(), ast_module_ref(), ast_module_unref(), ast_random(), ast_strdupa, ast_strlen_zero(), ast_channel::cdr, agi_command::dead, EVENT_FLAG_AGI, agi_state::fd, find_command(), agi_command::handler, manager_event, MAX_ARGS, agi_command::mod, ast_channel::name, parse_args(), RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_command::usage.

Referenced by launch_asyncagi(), and run_agi().

02781 {
02782    char *argv[MAX_ARGS];
02783    int argc = MAX_ARGS, res;
02784    agi_command *c;
02785    const char *ami_res = "Unknown Result";
02786    char *ami_cmd = ast_strdupa(buf);
02787    int command_id = ast_random(), resultcode = 200;
02788 
02789    manager_event(EVENT_FLAG_AGI, "AGIExec",
02790          "SubEvent: Start\r\n"
02791          "Channel: %s\r\n"
02792          "CommandId: %d\r\n"
02793          "Command: %s\r\n", chan->name, command_id, ami_cmd);
02794    parse_args(buf, &argc, argv);
02795    if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
02796       /* if this command wasnt registered by res_agi, be sure to usecount
02797       the module we are using */
02798       if (c->mod != ast_module_info->self)
02799          ast_module_ref(c->mod);
02800       /* If the AGI command being executed is an actual application (using agi exec)
02801       the app field will be updated in pbx_exec via handle_exec */
02802       if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
02803          ast_cdr_setapp(chan->cdr, "AGI", buf);
02804 
02805       res = c->handler(chan, agi, argc, argv);
02806       if (c->mod != ast_module_info->self)
02807          ast_module_unref(c->mod);
02808       switch (res) {
02809       case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
02810       case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
02811       case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
02812       }
02813       manager_event(EVENT_FLAG_AGI, "AGIExec",
02814             "SubEvent: End\r\n"
02815             "Channel: %s\r\n"
02816             "CommandId: %d\r\n"
02817             "Command: %s\r\n"
02818             "ResultCode: %d\r\n"
02819             "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
02820       switch(res) {
02821       case RESULT_SHOWUSAGE:
02822          if (ast_strlen_zero(c->usage)) {
02823             ast_agi_send(agi->fd, chan, "520 Invalid command syntax.  Proper usage not available.\n");
02824          } else {
02825             ast_agi_send(agi->fd, chan, "520-Invalid command syntax.  Proper usage follows:\n");
02826             ast_agi_send(agi->fd, chan, "%s", c->usage);
02827             ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
02828          }
02829          break;
02830       case RESULT_FAILURE:
02831          /* The RESULT_FAILURE code is usually because the channel hungup. */
02832          return AGI_RESULT_FAILURE;
02833       default:
02834          break;
02835       }
02836    } else if ((c = find_command(argv, 0))) {
02837       ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
02838       manager_event(EVENT_FLAG_AGI, "AGIExec",
02839             "SubEvent: End\r\n"
02840             "Channel: %s\r\n"
02841             "CommandId: %d\r\n"
02842             "Command: %s\r\n"
02843             "ResultCode: 511\r\n"
02844             "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
02845    } else {
02846       ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
02847       manager_event(EVENT_FLAG_AGI, "AGIExec",
02848             "SubEvent: End\r\n"
02849             "Channel: %s\r\n"
02850             "CommandId: %d\r\n"
02851             "Command: %s\r\n"
02852             "ResultCode: 510\r\n"
02853             "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
02854    }
02855    return AGI_RESULT_SUCCESS;
02856 }

int ast_agi_register ( struct ast_module mod,
agi_command cmd 
)

Registers an AGI command.

Parameters:
mod Pointer to the module_info structure for the module that is registering the command
cmd Pointer to the descriptor for the command
Returns:
1 on success, 0 if the command is already registered

Definition at line 2559 of file res_agi.c.

References ast_join(), AST_LIST_INSERT_TAIL, ast_log(), ast_module_ref(), AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_strdup, ast_strlen_zero(), ast_verb, AST_XML_DOC, agi_command::cmda, agi_command::docsrc, find_command(), agi_command::list, LOG_WARNING, MAX_CMD_LEN, agi_command::mod, agi_command::seealso, agi_command::summary, agi_command::syntax, and agi_command::usage.

Referenced by ast_agi_register_multiple(), and load_module().

02560 {
02561    char fullcmd[MAX_CMD_LEN];
02562 
02563    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
02564 
02565    if (!find_command(cmd->cmda,1)) {
02566       cmd->docsrc = AST_STATIC_DOC;
02567       if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
02568 #ifdef AST_XML_DOCS
02569          *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd);
02570          *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd);
02571          *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd);
02572          *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd);
02573          *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
02574 #elif (!defined(HAVE_NULLSAFE_PRINTF))
02575          *((char **) &cmd->summary) = ast_strdup("");
02576          *((char **) &cmd->usage) = ast_strdup("");
02577          *((char **) &cmd->syntax) = ast_strdup("");
02578          *((char **) &cmd->seealso) = ast_strdup("");
02579 #endif
02580       }
02581 
02582       cmd->mod = mod;
02583       AST_RWLIST_WRLOCK(&agi_commands);
02584       AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
02585       AST_RWLIST_UNLOCK(&agi_commands);
02586       if (mod != ast_module_info->self)
02587          ast_module_ref(ast_module_info->self);
02588       ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
02589       return 1;
02590    } else {
02591       ast_log(LOG_WARNING, "Command already registered!\n");
02592       return 0;
02593    }
02594 }

int ast_agi_register_multiple ( struct ast_module mod,
struct agi_command cmd,
unsigned int  len 
)

Registers a group of AGI commands, provided as an array of struct agi_command entries.

Parameters:
mod Pointer to the module_info structure for the module that is registering the commands
cmd Pointer to the first entry in the array of command descriptors
len Length of the array (use the ARRAY_LEN macro to determine this easily)
Returns:
0 on success, -1 on failure
Note:
If any command fails to register, all commands previously registered during the operation will be unregistered. In other words, this function registers all the provided commands, or none of them.

Definition at line 2633 of file res_agi.c.

References ast_agi_register(), and ast_agi_unregister().

Referenced by load_module().

02634 {
02635    unsigned int i, x = 0;
02636 
02637    for (i = 0; i < len; i++) {
02638       if (ast_agi_register(mod, cmd + i) == 1) {
02639          x++;
02640          continue;
02641       }
02642 
02643       /* registration failed, unregister everything
02644          that had been registered up to that point
02645       */
02646       for (; x > 0; x--) {
02647          /* we are intentionally ignoring the
02648             result of ast_agi_unregister() here,
02649             but it should be safe to do so since
02650             we just registered these commands and
02651             the only possible way for unregistration
02652             to fail is if the command is not
02653             registered
02654          */
02655          (void) ast_agi_unregister(mod, cmd + x - 1);
02656       }
02657       return -1;
02658    }
02659 
02660    return 0;
02661 }

int ast_agi_send ( int  fd,
struct ast_channel chan,
char *  fmt,
  ... 
)

Sends a string of text to an application connected via AGI.

Parameters:
fd The file descriptor for the AGI session (from struct agi_state)
chan Pointer to an associated Asterisk channel, if any
fmt printf-style format string
Returns:
0 for success, -1 for failure

Definition at line 376 of file res_agi.c.

References agi_buf, AGI_BUF_INITSIZE, ast_carefulwrite(), ast_log(), ast_str_buffer(), ast_str_set_va(), ast_str_strlen(), ast_str_thread_get(), ast_verbose, buf, LOG_ERROR, and ast_channel::name.

Referenced by agi_handle_command(), handle_answer(), handle_asyncagi_break(), handle_autohangup(), handle_channelstatus(), handle_controlstreamfile(), handle_dbdel(), handle_dbdeltree(), handle_dbget(), handle_dbput(), handle_exec(), handle_getdata(), handle_getoption(), handle_getvariable(), handle_getvariablefull(), handle_gosub(), handle_hangup(), handle_noop(), handle_recordfile(), handle_recvchar(), handle_recvtext(), handle_sayalpha(), handle_saydate(), handle_saydatetime(), handle_saydigits(), handle_saynumber(), handle_sayphonetic(), handle_saytime(), handle_sendimage(), handle_sendtext(), handle_setcallerid(), handle_setcontext(), handle_setextension(), handle_setmusic(), handle_setpriority(), handle_setvariable(), handle_speechactivategrammar(), handle_speechcreate(), handle_speechdeactivategrammar(), handle_speechdestroy(), handle_speechloadgrammar(), handle_speechrecognize(), handle_speechset(), handle_speechunloadgrammar(), handle_streamfile(), handle_tddmode(), handle_verbose(), handle_waitfordigit(), launch_netscript(), and setup_env().

00377 {
00378    int res = 0;
00379    va_list ap;
00380    struct ast_str *buf;
00381 
00382    if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
00383       return -1;
00384 
00385    va_start(ap, fmt);
00386    res = ast_str_set_va(&buf, 0, fmt, ap);
00387    va_end(ap);
00388 
00389    if (res == -1) {
00390       ast_log(LOG_ERROR, "Out of memory\n");
00391       return -1;
00392    }
00393 
00394    if (agidebug) {
00395       if (chan) {
00396          ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf));
00397       } else {
00398          ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
00399       }
00400    }
00401 
00402    return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
00403 }

int ast_agi_unregister ( struct ast_module mod,
agi_command cmd 
)

Unregisters an AGI command.

Parameters:
mod Pointer to the module_info structure for the module that is unregistering the command
cmd Pointer to the descriptor for the command
Returns:
1 on success, 0 if the command was not already registered

Definition at line 2596 of file res_agi.c.

References ast_free, ast_join(), ast_log(), ast_module_unref(), AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_verb, AST_XML_DOC, agi_command::cmda, agi_command::docsrc, agi_command::list, LOG_WARNING, MAX_CMD_LEN, agi_command::seealso, agi_command::summary, agi_command::syntax, and agi_command::usage.

Referenced by ast_agi_register_multiple(), ast_agi_unregister_multiple(), and unload_module().

02597 {
02598    struct agi_command *e;
02599    int unregistered = 0;
02600    char fullcmd[MAX_CMD_LEN];
02601 
02602    ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
02603 
02604    AST_RWLIST_WRLOCK(&agi_commands);
02605    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
02606       if (cmd == e) {
02607          AST_RWLIST_REMOVE_CURRENT(list);
02608          if (mod != ast_module_info->self)
02609             ast_module_unref(ast_module_info->self);
02610 #ifdef AST_XML_DOCS
02611          if (e->docsrc == AST_XML_DOC) {
02612             ast_free(e->summary);
02613             ast_free(e->usage);
02614             ast_free(e->syntax);
02615             ast_free(e->seealso);
02616             e->summary = NULL, e->usage = NULL;
02617             e->syntax = NULL, e->seealso = NULL;
02618          }
02619 #endif
02620          unregistered=1;
02621          break;
02622       }
02623    }
02624    AST_RWLIST_TRAVERSE_SAFE_END;
02625    AST_RWLIST_UNLOCK(&agi_commands);
02626    if (unregistered)
02627       ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
02628    else
02629       ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
02630    return unregistered;
02631 }

int ast_agi_unregister_multiple ( struct ast_module mod,
struct agi_command cmd,
unsigned int  len 
)

Unregisters a group of AGI commands, provided as an array of struct agi_command entries.

Parameters:
mod Pointer to the module_info structure for the module that is unregistering the commands
cmd Pointer to the first entry in the array of command descriptors
len Length of the array (use the ARRAY_LEN macro to determine this easily)
Returns:
0 on success, -1 on failure
Note:
If any command fails to unregister, this function will continue to unregister the remaining commands in the array; it will not reregister the already-unregistered commands.

Definition at line 2663 of file res_agi.c.

References ast_agi_unregister().

Referenced by unload_module().

02664 {
02665    unsigned int i;
02666    int res = 0;
02667 
02668    for (i = 0; i < len; i++) {
02669       /* remember whether any of the unregistration
02670          attempts failed... there is no recourse if
02671          any of them do
02672       */
02673       res |= ast_agi_unregister(mod, cmd + i);
02674    }
02675 
02676    return res;
02677 }

static int deadagi_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 3327 of file res_agi.c.

References agi_exec(), ast_log(), and LOG_WARNING.

Referenced by load_module().

03328 {
03329    ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
03330    return agi_exec(chan, data);
03331 }

static int eagi_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 3305 of file res_agi.c.

References agi_exec_full(), ast_check_hangup(), AST_FORMAT_SLINEAR, ast_getformatname(), ast_log(), ast_set_read_format(), LOG_ERROR, LOG_WARNING, ast_channel::name, and ast_channel::readformat.

Referenced by load_module().

03306 {
03307    int readformat, res;
03308 
03309    if (ast_check_hangup(chan)) {
03310       ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
03311       return 0;
03312    }
03313    readformat = chan->readformat;
03314    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
03315       ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
03316       return -1;
03317    }
03318    res = agi_exec_full(chan, data, 1, 0);
03319    if (!res) {
03320       if (ast_set_read_format(chan, readformat)) {
03321          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
03322       }
03323    }
03324    return res;
03325 }

static agi_command * find_command ( char *  cmds[],
int  exact 
) [static]

Definition at line 2679 of file res_agi.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, agi_command::cmda, agi_command::list, and match().

02680 {
02681    int y, match;
02682    struct agi_command *e;
02683 
02684    AST_RWLIST_RDLOCK(&agi_commands);
02685    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
02686       if (!e->cmda[0])
02687          break;
02688       /* start optimistic */
02689       match = 1;
02690       for (y = 0; match && cmds[y]; y++) {
02691          /* If there are no more words in the command (and we're looking for
02692             an exact match) or there is a difference between the two words,
02693             then this is not a match */
02694          if (!e->cmda[y] && !exact)
02695             break;
02696          /* don't segfault if the next part of a command doesn't exist */
02697          if (!e->cmda[y]) {
02698             AST_RWLIST_UNLOCK(&agi_commands);
02699             return NULL;
02700          }
02701          if (strcasecmp(e->cmda[y], cmds[y]))
02702             match = 0;
02703       }
02704       /* If more words are needed to complete the command then this is not
02705          a candidate (unless we're looking for a really inexact answer  */
02706       if ((exact > -1) && e->cmda[y])
02707          match = 0;
02708       if (match) {
02709          AST_RWLIST_UNLOCK(&agi_commands);
02710          return e;
02711       }
02712    }
02713    AST_RWLIST_UNLOCK(&agi_commands);
02714    return NULL;
02715 }

static void free_agi_cmd ( struct agi_cmd cmd  )  [static]

Definition at line 412 of file res_agi.c.

References ast_free.

Referenced by agi_destroy_commands_cb(), and launch_asyncagi().

00413 {
00414    ast_free(cmd->cmd_buffer);
00415    ast_free(cmd->cmd_id);
00416    ast_free(cmd);
00417 }

static struct agi_cmd* get_agi_cmd ( struct ast_channel chan  )  [static, read]

Definition at line 447 of file res_agi.c.

References agi_commands_datastore_info, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, agi_cmd::entry, LOG_ERROR, and ast_channel::name.

Referenced by launch_asyncagi().

00448 {
00449    struct ast_datastore *store;
00450    struct agi_cmd *cmd;
00451    AST_LIST_HEAD(, agi_cmd) *agi_commands;
00452 
00453    ast_channel_lock(chan);
00454    store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
00455    ast_channel_unlock(chan);
00456    if (!store) {
00457       ast_log(LOG_ERROR, "Hu? datastore disappeared at Async AGI on Channel %s!\n", chan->name);
00458       return NULL;
00459    }
00460    agi_commands = store->data;
00461    AST_LIST_LOCK(agi_commands);
00462    cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
00463    AST_LIST_UNLOCK(agi_commands);
00464    return cmd;
00465 }

static int handle_answer ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1024 of file res_agi.c.

References ast_channel::_state, ast_agi_send(), ast_answer(), AST_STATE_UP, agi_state::fd, RESULT_FAILURE, and RESULT_SUCCESS.

01025 {
01026    int res = 0;
01027 
01028    /* Answer the channel */
01029    if (chan->_state != AST_STATE_UP)
01030       res = ast_answer(chan);
01031 
01032    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01033    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01034 }

static int handle_asyncagi_break ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1036 of file res_agi.c.

References ast_agi_send(), agi_state::fd, and RESULT_FAILURE.

01037 {
01038    ast_agi_send(agi->fd, chan, "200 result=0\n");
01039    return RESULT_FAILURE;
01040 }

static int handle_autohangup ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1674 of file res_agi.c.

References ast_agi_send(), ast_channel_setwhentohangup_tv(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01675 {
01676    double timeout;
01677    struct timeval whentohangup = { 0, 0 };
01678 
01679    if (argc != 3)
01680       return RESULT_SHOWUSAGE;
01681    if (sscanf(argv[2], "%30lf", &timeout) != 1)
01682       return RESULT_SHOWUSAGE;
01683    if (timeout < 0)
01684       timeout = 0;
01685    if (timeout) {
01686       whentohangup.tv_sec = timeout;
01687       whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
01688    }
01689    ast_channel_setwhentohangup_tv(chan, whentohangup);
01690    ast_agi_send(agi->fd, chan, "200 result=0\n");
01691    return RESULT_SUCCESS;
01692 }

static int handle_channelstatus ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1789 of file res_agi.c.

References ast_channel::_state, ast_agi_send(), ast_channel_unlock, ast_get_channel_by_name_locked(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01790 {
01791    struct ast_channel *c;
01792    if (argc == 2) {
01793       /* no argument: supply info on the current channel */
01794       ast_agi_send(agi->fd, chan, "200 result=%d\n", chan->_state);
01795       return RESULT_SUCCESS;
01796    } else if (argc == 3) {
01797       /* one argument: look for info on the specified channel */
01798       c = ast_get_channel_by_name_locked(argv[2]);
01799       if (c) {
01800          ast_agi_send(agi->fd, chan, "200 result=%d\n", c->_state);
01801          ast_channel_unlock(c);
01802          return RESULT_SUCCESS;
01803       }
01804       /* if we get this far no channel name matched the argument given */
01805       ast_agi_send(agi->fd, chan, "200 result=-1\n");
01806       return RESULT_SUCCESS;
01807    } else {
01808       return RESULT_SHOWUSAGE;
01809    }
01810 }

static char* handle_cli_agi_add_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to add applications to execute in Async AGI.

Parameters:
e 
cmd 
a 
Return values:
CLI_SUCCESS on success
NULL when init or tab completion is used

Definition at line 545 of file res_agi.c.

References add_agi_cmd(), ast_cli_args::argc, ast_cli_args::argv, ast_channel_unlock, ast_complete_channels(), ast_get_channel_by_name_locked(), ast_log(), chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::line, LOG_DEBUG, LOG_WARNING, ast_cli_args::n, ast_channel::name, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

00546 {
00547    struct ast_channel *chan;
00548    switch (cmd) {
00549    case CLI_INIT:
00550       e->command = "agi exec";
00551       e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
00552             "       Add AGI command to the execute queue of the specified channel in Async AGI\n";
00553       return NULL;
00554    case CLI_GENERATE:
00555       if (a->pos == 2)
00556          return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
00557       return NULL;
00558    }
00559 
00560    if (a->argc < 4)
00561       return CLI_SHOWUSAGE;
00562    chan = ast_get_channel_by_name_locked(a->argv[2]);
00563    if (!chan) {
00564       ast_log(LOG_WARNING, "Channel %s does not exists or cannot lock it\n", a->argv[2]);
00565       return CLI_FAILURE;
00566    }
00567    if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
00568       ast_log(LOG_WARNING, "failed to add AGI command to queue of channel %s\n", chan->name);
00569       ast_channel_unlock(chan);
00570       return CLI_FAILURE;
00571    }
00572    ast_log(LOG_DEBUG, "Added AGI command to channel %s queue\n", chan->name);
00573    ast_channel_unlock(chan);
00574    return CLI_SUCCESS;
00575 }

static char* handle_cli_agi_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1954 of file res_agi.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

01955 {
01956    switch (cmd) {
01957    case CLI_INIT:
01958       e->command = "agi set debug [on|off]";
01959       e->usage =
01960          "Usage: agi set debug [on|off]\n"
01961          "       Enables/disables dumping of AGI transactions for\n"
01962          "       debugging purposes.\n";
01963       return NULL;
01964 
01965    case CLI_GENERATE:
01966       return NULL;
01967    }
01968 
01969    if (a->argc != e->args)
01970       return CLI_SHOWUSAGE;
01971 
01972    if (strncasecmp(a->argv[3], "off", 3) == 0) {
01973       agidebug = 0;
01974    } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
01975       agidebug = 1;
01976    } else {
01977       return CLI_SHOWUSAGE;
01978    }
01979    ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
01980    return CLI_SUCCESS;
01981 }

static char* handle_cli_agi_dump_html ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3206 of file res_agi.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_entry::usage, and write_htmldump().

03207 {
03208    switch (cmd) {
03209    case CLI_INIT:
03210       e->command = "agi dump html";
03211       e->usage =
03212          "Usage: agi dump html <filename>\n"
03213          "       Dumps the AGI command list in HTML format to the given\n"
03214          "       file.\n";
03215       return NULL;
03216    case CLI_GENERATE:
03217       return NULL;
03218    }
03219    if (a->argc != e->args + 1)
03220       return CLI_SHOWUSAGE;
03221 
03222    if (write_htmldump(a->argv[e->args]) < 0) {
03223       ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
03224       return CLI_SHOWUSAGE;
03225    }
03226    ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
03227    return CLI_SUCCESS;
03228 }

static char* handle_cli_agi_show ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 3014 of file res_agi.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), ast_free, ast_join(), ast_malloc, AST_TERM_MAX_ESCAPE_CHARS, AST_XML_DOC, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_CYAN, COLOR_MAGENTA, ast_cli_entry::command, agi_command::dead, description, agi_command::docsrc, ast_cli_args::fd, find_command(), help_workhorse(), MAX_CMD_LEN, S_OR, agi_command::seealso, agi_command::summary, agi_command::syntax, term_color(), agi_command::usage, and ast_cli_entry::usage.

03015 {
03016    struct agi_command *command;
03017    char fullcmd[MAX_CMD_LEN];
03018    int error = 0;
03019 
03020    switch (cmd) {
03021    case CLI_INIT:
03022       e->command = "agi show commands [topic]";
03023       e->usage =
03024          "Usage: agi show commands [topic] <topic>\n"
03025          "       When called with a topic as an argument, displays usage\n"
03026          "       information on the given command.  If called without a\n"
03027          "       topic, it provides a list of AGI commands.\n";
03028    case CLI_GENERATE:
03029       return NULL;
03030    }
03031    if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
03032       return CLI_SHOWUSAGE;
03033    if (a->argc > e->args - 1) {
03034       command = find_command(a->argv + e->args, 1);
03035       if (command) {
03036          char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
03037          char info[30 + MAX_CMD_LEN];              /* '-= Info about...' */
03038          char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS];  /* '-= Info about...' with colors */
03039          char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03040          char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Description]\n with colors */
03041          char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS];       /* [Runs Dead]\n with colors */
03042          char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS];      /* 'Yes' or 'No' with colors */
03043          char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS];    /* [See Also]\n with colors */
03044          char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS];        /* [Syntax]\n with colors */
03045          size_t synlen, desclen, seealsolen, stxlen;
03046 
03047          term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
03048          term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
03049          term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
03050          term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
03051          term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
03052          term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
03053 
03054          ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03055          snprintf(info, sizeof(info), "\n  -= Info about agi '%s' =- ", fullcmd);
03056          term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
03057 #ifdef AST_XML_DOCS
03058          if (command->docsrc == AST_XML_DOC) {
03059             synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
03060             description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
03061             seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
03062             if (!seealso || !description || !synopsis) {
03063                error = 1;
03064                goto return_cleanup;
03065             }
03066          } else
03067 #endif
03068          {
03069             synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03070             synopsis = ast_malloc(synlen);
03071 
03072             desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03073             description = ast_malloc(desclen);
03074 
03075             seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03076             seealso = ast_malloc(seealsolen);
03077 
03078             if (!synopsis || !description || !seealso) {
03079                error = 1;
03080                goto return_cleanup;
03081             }
03082             term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
03083             term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
03084             term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
03085          }
03086 
03087          stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03088          syntax = ast_malloc(stxlen);
03089          if (!syntax) {
03090             error = 1;
03091             goto return_cleanup;
03092          }
03093          term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
03094 
03095          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,
03096                desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
03097                seealsotitle, seealso);
03098 return_cleanup:
03099          ast_free(synopsis);
03100          ast_free(description);
03101          ast_free(syntax);
03102          ast_free(seealso);
03103       } else {
03104          if (find_command(a->argv + e->args, -1)) {
03105             return help_workhorse(a->fd, a->argv + e->args);
03106          } else {
03107             ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03108             ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
03109          }
03110       }
03111    } else {
03112       return help_workhorse(a->fd, NULL);
03113    }
03114    return (error ? CLI_FAILURE : CLI_SUCCESS);
03115 }

static int handle_controlstreamfile ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1154 of file res_agi.c.

References ast_agi_send(), ast_control_streamfile(), ast_strlen_zero(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, skipms, and stop.

01155 {
01156    int res = 0, skipms = 3000;
01157    char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
01158 
01159    if (argc < 5 || argc > 9) {
01160       return RESULT_SHOWUSAGE;
01161    }
01162 
01163    if (!ast_strlen_zero(argv[4])) {
01164       stop = argv[4];
01165    }
01166 
01167    if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
01168       return RESULT_SHOWUSAGE;
01169    }
01170 
01171    if (argc > 6 && !ast_strlen_zero(argv[6])) {
01172       fwd = argv[6];
01173    }
01174 
01175    if (argc > 7 && !ast_strlen_zero(argv[7])) {
01176       rev = argv[7];
01177    }
01178 
01179    if (argc > 8 && !ast_strlen_zero(argv[8])) {
01180       suspend = argv[8];
01181    }
01182 
01183    res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
01184 
01185    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01186 
01187    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01188 }

static int handle_dbdel ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1928 of file res_agi.c.

References ast_agi_send(), ast_db_del(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01929 {
01930    int res;
01931 
01932    if (argc != 4)
01933       return RESULT_SHOWUSAGE;
01934    res = ast_db_del(argv[2], argv[3]);
01935    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
01936    return RESULT_SUCCESS;
01937 }

static int handle_dbdeltree ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1939 of file res_agi.c.

References ast_agi_send(), ast_db_deltree(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01940 {
01941    int res;
01942 
01943    if ((argc < 3) || (argc > 4))
01944       return RESULT_SHOWUSAGE;
01945    if (argc == 4)
01946       res = ast_db_deltree(argv[2], argv[3]);
01947    else
01948       res = ast_db_deltree(argv[2], NULL);
01949 
01950    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
01951    return RESULT_SUCCESS;
01952 }

static int handle_dbget ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1884 of file res_agi.c.

References ast_agi_send(), ast_db_get(), ast_free, ast_str_buffer(), ast_str_create(), ast_str_make_space(), ast_str_size(), ast_str_strlen(), ast_str_update(), buf, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01885 {
01886    int res;
01887    struct ast_str *buf;
01888 
01889    if (argc != 4)
01890       return RESULT_SHOWUSAGE;
01891 
01892    if (!(buf = ast_str_create(16))) {
01893       ast_agi_send(agi->fd, chan, "200 result=-1\n");
01894       return RESULT_SUCCESS;
01895    }
01896 
01897    do {
01898       res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
01899       ast_str_update(buf);
01900       if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
01901          break;
01902       }
01903       if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
01904          break;
01905       }
01906    } while (1);
01907    
01908    if (res)
01909       ast_agi_send(agi->fd, chan, "200 result=0\n");
01910    else
01911       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
01912 
01913    ast_free(buf);
01914    return RESULT_SUCCESS;
01915 }

static int handle_dbput ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1917 of file res_agi.c.

References ast_agi_send(), ast_db_put(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01918 {
01919    int res;
01920 
01921    if (argc != 5)
01922       return RESULT_SHOWUSAGE;
01923    res = ast_db_put(argv[2], argv[3], argv[4]);
01924    ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
01925    return RESULT_SUCCESS;
01926 }

static int handle_exec ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1721 of file res_agi.c.

References ast_agi_send(), ast_clear_flag, ast_compat_res_agi, AST_FLAG_DISABLE_WORKAROUNDS, ast_log(), ast_masq_park_call(), ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_verb, agi_state::fd, LOG_WARNING, PARK_APP_NAME, pbx_exec(), pbx_findapp(), and RESULT_SHOWUSAGE.

01722 {
01723    int res, workaround;
01724    struct ast_app *app_to_exec;
01725 
01726    if (argc < 2)
01727       return RESULT_SHOWUSAGE;
01728 
01729    ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
01730 
01731    if ((app_to_exec = pbx_findapp(argv[1]))) {
01732       if(!strcasecmp(argv[1], PARK_APP_NAME)) {
01733          ast_masq_park_call(chan, NULL, 0, NULL);
01734       }
01735       if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) {
01736          ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
01737       }
01738       if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
01739          char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr, *vptr;
01740          for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
01741             if (*vptr == ',') {
01742                *cptr++ = '\\';
01743                *cptr++ = ',';
01744             } else if (*vptr == '|') {
01745                *cptr++ = ',';
01746             } else {
01747                *cptr++ = *vptr;
01748             }
01749          }
01750          *cptr = '\0';
01751          res = pbx_exec(chan, app_to_exec, compat);
01752       } else {
01753          res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
01754       }
01755       if (!workaround) {
01756          ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
01757       }
01758    } else {
01759       ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
01760       res = -2;
01761    }
01762    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01763 
01764    /* Even though this is wrong, users are depending upon this result. */
01765    return res;
01766 }

static int handle_getdata ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1432 of file res_agi.c.

References ast_agi_send(), ast_app_getdata_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01433 {
01434    int res, max, timeout;
01435    char data[1024];
01436 
01437    if (argc < 3)
01438       return RESULT_SHOWUSAGE;
01439    if (argc >= 4)
01440       timeout = atoi(argv[3]);
01441    else
01442       timeout = 0;
01443    if (argc >= 5)
01444       max = atoi(argv[4]);
01445    else
01446       max = 1024;
01447    res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
01448    if (res == 2)        /* New command */
01449       return RESULT_SUCCESS;
01450    else if (res == 1)
01451       ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
01452    else if (res < 0 )
01453       ast_agi_send(agi->fd, chan, "200 result=-1\n");
01454    else
01455       ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
01456    return RESULT_SUCCESS;
01457 }

static int handle_getoption ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

get option - really similar to the handle_streamfile, but with a timeout

Definition at line 1240 of file res_agi.c.

References ast_agi_send(), ast_applystream(), ast_debug, ast_log(), ast_openstream(), ast_openvstream(), ast_playstream(), ast_seekstream(), ast_stopstream(), ast_tellstream(), ast_verb, ast_waitfordigit_full(), ast_waitstream_full(), agi_state::audio, agi_state::ctrl, ast_pbx::dtimeoutms, agi_state::fd, ast_channel::language, LOG_WARNING, ast_channel::pbx, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, and ast_filestream::vfs.

01241 {
01242    int res, vres;
01243    struct ast_filestream *fs, *vfs;
01244    long sample_offset = 0, max_length;
01245    int timeout = 0;
01246    char *edigits = "";
01247 
01248    if ( argc < 4 || argc > 5 )
01249       return RESULT_SHOWUSAGE;
01250 
01251    if ( argv[3] )
01252       edigits = argv[3];
01253 
01254    if ( argc == 5 )
01255       timeout = atoi(argv[4]);
01256    else if (chan->pbx->dtimeoutms) {
01257       /* by default dtimeout is set to 5sec */
01258       timeout = chan->pbx->dtimeoutms; /* in msec */
01259    }
01260 
01261    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01262       ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
01263       ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
01264       return RESULT_SUCCESS;
01265    }
01266 
01267    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01268       ast_debug(1, "Ooh, found a video stream, too\n");
01269 
01270    ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
01271 
01272    ast_seekstream(fs, 0, SEEK_END);
01273    max_length = ast_tellstream(fs);
01274    ast_seekstream(fs, sample_offset, SEEK_SET);
01275    res = ast_applystream(chan, fs);
01276    if (vfs)
01277       vres = ast_applystream(chan, vfs);
01278    ast_playstream(fs);
01279    if (vfs)
01280       ast_playstream(vfs);
01281 
01282    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01283    /* this is to check for if ast_waitstream closed the stream, we probably are at
01284     * the end of the stream, return that amount, else check for the amount */
01285    sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
01286    ast_stopstream(chan);
01287    if (res == 1) {
01288       /* Stop this command, don't print a result line, as there is a new command */
01289       return RESULT_SUCCESS;
01290    }
01291 
01292    /* If the user didnt press a key, wait for digitTimeout*/
01293    if (res == 0 ) {
01294       res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
01295       /* Make sure the new result is in the escape digits of the GET OPTION */
01296       if ( !strchr(edigits,res) )
01297          res=0;
01298    }
01299 
01300    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01301    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01302 }

static int handle_getvariable ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1821 of file res_agi.c.

References ast_agi_send(), ast_func_read(), ast_strlen_zero(), agi_state::fd, pbx_retrieve_variable(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01822 {
01823    char *ret;
01824    char tempstr[1024] = "";
01825 
01826    if (argc != 3)
01827       return RESULT_SHOWUSAGE;
01828 
01829    /* check if we want to execute an ast_custom_function */
01830    if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
01831       ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
01832    } else {
01833       pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
01834    }
01835 
01836    if (ret)
01837       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
01838    else
01839       ast_agi_send(agi->fd, chan, "200 result=0\n");
01840 
01841    return RESULT_SUCCESS;
01842 }

static int handle_getvariablefull ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1844 of file res_agi.c.

References ast_agi_send(), ast_channel_unlock, ast_get_channel_by_name_locked(), agi_state::fd, ast_channel::name, pbx_substitute_variables_helper(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01845 {
01846    char tmp[4096] = "";
01847    struct ast_channel *chan2=NULL;
01848 
01849    if ((argc != 4) && (argc != 5))
01850       return RESULT_SHOWUSAGE;
01851    if (argc == 5 && strcasecmp(chan->name, argv[4])) {
01852       chan2 = ast_get_channel_by_name_locked(argv[4]);
01853    } else {
01854       chan2 = chan;
01855    }
01856    if (chan2) {
01857       pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
01858       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", tmp);
01859    } else {
01860       ast_agi_send(agi->fd, chan, "200 result=0\n");
01861    }
01862    if (chan2 && (chan2 != chan))
01863       ast_channel_unlock(chan2);
01864    return RESULT_SUCCESS;
01865 }

static int handle_hangup ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1694 of file res_agi.c.

References ast_agi_send(), ast_channel_unlock, ast_get_channel_by_name_locked(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01695 {
01696    struct ast_channel *c;
01697 
01698    if (argc == 1) {
01699       /* no argument: hangup the current channel */
01700       ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
01701       ast_agi_send(agi->fd, chan, "200 result=1\n");
01702       return RESULT_SUCCESS;
01703    } else if (argc == 2) {
01704       /* one argument: look for info on the specified channel */
01705       c = ast_get_channel_by_name_locked(argv[1]);
01706       if (c) {
01707          /* we have a matching channel */
01708          ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
01709          ast_agi_send(agi->fd, chan, "200 result=1\n");
01710          ast_channel_unlock(c);
01711          return RESULT_SUCCESS;
01712       }
01713       /* if we get this far no channel name matched the argument given */
01714       ast_agi_send(agi->fd, chan, "200 result=-1\n");
01715       return RESULT_SUCCESS;
01716    } else {
01717       return RESULT_SHOWUSAGE;
01718    }
01719 }

static int handle_noop ( struct ast_channel chan,
AGI agi,
int  arg,
char *  argv[] 
) [static]

Definition at line 1983 of file res_agi.c.

References ast_agi_send(), agi_state::fd, and RESULT_SUCCESS.

01984 {
01985    ast_agi_send(agi->fd, chan, "200 result=0\n");
01986    return RESULT_SUCCESS;
01987 }

static int handle_recordfile ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1495 of file res_agi.c.

References ast_agi_send(), ast_applystream(), ast_closestream(), AST_CONTROL_VIDUPDATE, ast_dsp_free(), ast_dsp_get_threshold_from_settings(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), AST_FILE_MODE, AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate(), ast_log(), ast_read(), ast_seekstream(), ast_set_read_format(), ast_stream_rewind(), ast_streamfile(), ast_tellstream(), ast_truncstream(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), f, agi_state::fd, ast_frame::frametype, ast_channel::language, LOG_WARNING, ast_channel::name, ast_channel::readformat, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, ast_frame::subclass, THRESHOLD_SILENCE, and ast_dsp::totalsilence.

01496 {
01497    struct ast_filestream *fs;
01498    struct ast_frame *f;
01499    struct timeval start;
01500    long sample_offset = 0;
01501    int res = 0;
01502    int ms;
01503 
01504    struct ast_dsp *sildet=NULL;         /* silence detector dsp */
01505    int totalsilence = 0;
01506    int dspsilence = 0;
01507    int silence = 0;                /* amount of silence to allow */
01508    int gotsilence = 0;             /* did we timeout for silence? */
01509    char *silencestr = NULL;
01510    int rfmt = 0;
01511 
01512    /* XXX EAGI FIXME XXX */
01513 
01514    if (argc < 6)
01515       return RESULT_SHOWUSAGE;
01516    if (sscanf(argv[5], "%30d", &ms) != 1)
01517       return RESULT_SHOWUSAGE;
01518 
01519    if (argc > 6)
01520       silencestr = strchr(argv[6],'s');
01521    if ((argc > 7) && (!silencestr))
01522       silencestr = strchr(argv[7],'s');
01523    if ((argc > 8) && (!silencestr))
01524       silencestr = strchr(argv[8],'s');
01525 
01526    if (silencestr) {
01527       if (strlen(silencestr) > 2) {
01528          if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
01529             silencestr++;
01530             silencestr++;
01531             if (silencestr)
01532                silence = atoi(silencestr);
01533             if (silence > 0)
01534                silence *= 1000;
01535          }
01536       }
01537    }
01538 
01539    if (silence > 0) {
01540       rfmt = chan->readformat;
01541       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
01542       if (res < 0) {
01543          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
01544          ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01545          return RESULT_FAILURE;
01546       }
01547       sildet = ast_dsp_new();
01548       if (!sildet) {
01549          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
01550          ast_agi_send(agi->fd, chan, "200 result=-1\n");
01551          return RESULT_FAILURE;
01552       }
01553       ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
01554    }
01555    
01556    /* backward compatibility, if no offset given, arg[6] would have been
01557     * caught below and taken to be a beep, else if it is a digit then it is a
01558     * offset */
01559    if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
01560       res = ast_streamfile(chan, "beep", chan->language);
01561 
01562    if ((argc > 7) && (!strchr(argv[7], '=')))
01563       res = ast_streamfile(chan, "beep", chan->language);
01564 
01565    if (!res)
01566       res = ast_waitstream(chan, argv[4]);
01567    if (res) {
01568       ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
01569    } else {
01570       fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
01571       if (!fs) {
01572          res = -1;
01573          ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
01574          if (sildet)
01575             ast_dsp_free(sildet);
01576          return RESULT_FAILURE;
01577       }
01578 
01579       /* Request a video update */
01580       ast_indicate(chan, AST_CONTROL_VIDUPDATE);
01581 
01582       chan->stream = fs;
01583       ast_applystream(chan,fs);
01584       /* really should have checks */
01585       ast_seekstream(fs, sample_offset, SEEK_SET);
01586       ast_truncstream(fs);
01587 
01588       start = ast_tvnow();
01589       while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
01590          res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
01591          if (res < 0) {
01592             ast_closestream(fs);
01593             ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
01594             if (sildet)
01595                ast_dsp_free(sildet);
01596             return RESULT_FAILURE;
01597          }
01598          f = ast_read(chan);
01599          if (!f) {
01600             ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
01601             ast_closestream(fs);
01602             if (sildet)
01603                ast_dsp_free(sildet);
01604             return RESULT_FAILURE;
01605          }
01606          switch(f->frametype) {
01607          case AST_FRAME_DTMF:
01608             if (strchr(argv[4], f->subclass)) {
01609                /* This is an interrupting chracter, so rewind to chop off any small
01610                   amount of DTMF that may have been recorded
01611                */
01612                ast_stream_rewind(fs, 200);
01613                ast_truncstream(fs);
01614                sample_offset = ast_tellstream(fs);
01615                ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
01616                ast_closestream(fs);
01617                ast_frfree(f);
01618                if (sildet)
01619                   ast_dsp_free(sildet);
01620                return RESULT_SUCCESS;
01621             }
01622             break;
01623          case AST_FRAME_VOICE:
01624             ast_writestream(fs, f);
01625             /* this is a safe place to check progress since we know that fs
01626              * is valid after a write, and it will then have our current
01627              * location */
01628             sample_offset = ast_tellstream(fs);
01629             if (silence > 0) {
01630                dspsilence = 0;
01631                ast_dsp_silence(sildet, f, &dspsilence);
01632                if (dspsilence) {
01633                   totalsilence = dspsilence;
01634                } else {
01635                   totalsilence = 0;
01636                }
01637                if (totalsilence > silence) {
01638                   /* Ended happily with silence */
01639                   gotsilence = 1;
01640                   break;
01641                }
01642             }
01643             break;
01644          case AST_FRAME_VIDEO:
01645             ast_writestream(fs, f);
01646          default:
01647             /* Ignore all other frames */
01648             break;
01649          }
01650          ast_frfree(f);
01651          if (gotsilence)
01652             break;
01653       }
01654 
01655       if (gotsilence) {
01656          ast_stream_rewind(fs, silence-1000);
01657          ast_truncstream(fs);
01658          sample_offset = ast_tellstream(fs);
01659       }
01660       ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
01661       ast_closestream(fs);
01662    }
01663 
01664    if (silence > 0) {
01665       res = ast_set_read_format(chan, rfmt);
01666       if (res)
01667          ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
01668       ast_dsp_free(sildet);
01669    }
01670 
01671    return RESULT_SUCCESS;
01672 }

static int handle_recvchar ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1074 of file res_agi.c.

References ast_agi_send(), ast_recvchar(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01075 {
01076    int res;
01077 
01078    if (argc != 3)
01079       return RESULT_SHOWUSAGE;
01080 
01081    res = ast_recvchar(chan,atoi(argv[2]));
01082    if (res == 0) {
01083       ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
01084       return RESULT_SUCCESS;
01085    }
01086    if (res > 0) {
01087       ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01088       return RESULT_SUCCESS;
01089    }
01090    ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
01091    return RESULT_FAILURE;
01092 }

static int handle_recvtext ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1094 of file res_agi.c.

References ast_agi_send(), ast_free, ast_recvtext(), buf, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01095 {
01096    char *buf;
01097 
01098    if (argc != 3)
01099       return RESULT_SHOWUSAGE;
01100 
01101    buf = ast_recvtext(chan, atoi(argv[2]));
01102    if (buf) {
01103       ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
01104       ast_free(buf);
01105    } else {
01106       ast_agi_send(agi->fd, chan, "200 result=-1\n");
01107    }
01108    return RESULT_SUCCESS;
01109 }

static int handle_sayalpha ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1340 of file res_agi.c.

References ast_agi_send(), ast_say_character_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01341 {
01342    int res;
01343 
01344    if (argc != 4)
01345       return RESULT_SHOWUSAGE;
01346 
01347    res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
01348    if (res == 1) /* New command */
01349       return RESULT_SUCCESS;
01350    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01351    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01352 }

static int handle_saydate ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1354 of file res_agi.c.

References ast_agi_send(), ast_say_date, agi_state::fd, ast_channel::language, num, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01355 {
01356    int res, num;
01357 
01358    if (argc != 4)
01359       return RESULT_SHOWUSAGE;
01360    if (sscanf(argv[2], "%30d", &num) != 1)
01361       return RESULT_SHOWUSAGE;
01362    res = ast_say_date(chan, num, argv[3], chan->language);
01363    if (res == 1)
01364       return RESULT_SUCCESS;
01365    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01366    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01367 }

static int handle_saydatetime ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1384 of file res_agi.c.

References ast_agi_send(), ast_get_time_t(), ast_say_date_with_format, ast_strlen_zero(), agi_state::fd, format, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01385 {
01386    int res = 0;
01387    time_t unixtime;
01388    char *format, *zone = NULL;
01389 
01390    if (argc < 4)
01391       return RESULT_SHOWUSAGE;
01392 
01393    if (argc > 4) {
01394       format = argv[4];
01395    } else {
01396       /* XXX this doesn't belong here, but in the 'say' module */
01397       if (!strcasecmp(chan->language, "de")) {
01398          format = "A dBY HMS";
01399       } else {
01400          format = "ABdY 'digits/at' IMp";
01401       }
01402    }
01403 
01404    if (argc > 5 && !ast_strlen_zero(argv[5]))
01405       zone = argv[5];
01406 
01407    if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
01408       return RESULT_SHOWUSAGE;
01409 
01410    res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
01411    if (res == 1)
01412       return RESULT_SUCCESS;
01413 
01414    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01415    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01416 }

static int handle_saydigits ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1324 of file res_agi.c.

References ast_agi_send(), ast_say_digit_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, num, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01325 {
01326    int res, num;
01327 
01328    if (argc != 4)
01329       return RESULT_SHOWUSAGE;
01330    if (sscanf(argv[2], "%30d", &num) != 1)
01331       return RESULT_SHOWUSAGE;
01332 
01333    res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
01334    if (res == 1) /* New command */
01335       return RESULT_SUCCESS;
01336    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01337    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01338 }

static int handle_saynumber ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Say number in various language syntaxes.

Definition at line 1309 of file res_agi.c.

References ast_agi_send(), ast_say_number_full, agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, num, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01310 {
01311    int res, num;
01312 
01313    if (argc < 4 || argc > 5)
01314       return RESULT_SHOWUSAGE;
01315    if (sscanf(argv[2], "%30d", &num) != 1)
01316       return RESULT_SHOWUSAGE;
01317    res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
01318    if (res == 1)
01319       return RESULT_SUCCESS;
01320    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01321    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01322 }

static int handle_sayphonetic ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1418 of file res_agi.c.

References ast_agi_send(), ast_say_phonetic_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01419 {
01420    int res;
01421 
01422    if (argc != 4)
01423       return RESULT_SHOWUSAGE;
01424 
01425    res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
01426    if (res == 1) /* New command */
01427       return RESULT_SUCCESS;
01428    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01429    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01430 }

static int handle_saytime ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1369 of file res_agi.c.

References ast_agi_send(), ast_say_time, agi_state::fd, ast_channel::language, num, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01370 {
01371    int res, num;
01372 
01373    if (argc != 4)
01374       return RESULT_SHOWUSAGE;
01375    if (sscanf(argv[2], "%30d", &num) != 1)
01376       return RESULT_SHOWUSAGE;
01377    res = ast_say_time(chan, num, argv[3], chan->language);
01378    if (res == 1)
01379       return RESULT_SUCCESS;
01380    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01381    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01382 }

static int handle_sendimage ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1138 of file res_agi.c.

References ast_agi_send(), ast_check_hangup(), ast_send_image(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01139 {
01140    int res;
01141 
01142    if (argc != 3) {
01143       return RESULT_SHOWUSAGE;
01144    }
01145 
01146    res = ast_send_image(chan, argv[2]);
01147    if (!ast_check_hangup(chan)) {
01148       res = 0;
01149    }
01150    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01151    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01152 }

static int handle_sendtext ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1055 of file res_agi.c.

References ast_agi_send(), ast_sendtext(), agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01056 {
01057    int res;
01058 
01059    if (argc != 3)
01060       return RESULT_SHOWUSAGE;
01061 
01062    /* At the moment, the parser (perhaps broken) returns with
01063       the last argument PLUS the newline at the end of the input
01064       buffer. This probably needs to be fixed, but I wont do that
01065       because other stuff may break as a result. The right way
01066       would probably be to strip off the trailing newline before
01067       parsing, then here, add a newline at the end of the string
01068       before sending it to ast_sendtext --DUDE */
01069    res = ast_sendtext(chan, argv[2]);
01070    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01071    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01072 }

static int handle_setcallerid ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1768 of file res_agi.c.

References ast_agi_send(), ast_callerid_parse(), ast_copy_string(), ast_set_callerid(), ast_shrink_phone_number(), agi_state::fd, and RESULT_SUCCESS.

01769 {
01770    char tmp[256]="";
01771    char *l = NULL, *n = NULL;
01772 
01773    if (argv[2]) {
01774       ast_copy_string(tmp, argv[2], sizeof(tmp));
01775       ast_callerid_parse(tmp, &n, &l);
01776       if (l)
01777          ast_shrink_phone_number(l);
01778       else
01779          l = "";
01780       if (!n)
01781          n = "";
01782       ast_set_callerid(chan, l, n, NULL);
01783    }
01784 
01785    ast_agi_send(agi->fd, chan, "200 result=1\n");
01786    return RESULT_SUCCESS;
01787 }

static int handle_setcontext ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1459 of file res_agi.c.

References ast_agi_send(), ast_copy_string(), ast_channel::context, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01460 {
01461 
01462    if (argc != 3)
01463       return RESULT_SHOWUSAGE;
01464    ast_copy_string(chan->context, argv[2], sizeof(chan->context));
01465    ast_agi_send(agi->fd, chan, "200 result=0\n");
01466    return RESULT_SUCCESS;
01467 }

static int handle_setextension ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1469 of file res_agi.c.

References ast_agi_send(), ast_copy_string(), ast_channel::exten, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01470 {
01471    if (argc != 3)
01472       return RESULT_SHOWUSAGE;
01473    ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
01474    ast_agi_send(agi->fd, chan, "200 result=0\n");
01475    return RESULT_SUCCESS;
01476 }

static int handle_setmusic ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1989 of file res_agi.c.

References ast_agi_send(), ast_moh_start(), ast_moh_stop(), agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01990 {
01991    if (argc < 3) {
01992       return RESULT_SHOWUSAGE;
01993    }
01994    if (!strncasecmp(argv[2], "on", 2))
01995       ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
01996    else if (!strncasecmp(argv[2], "off", 3))
01997       ast_moh_stop(chan);
01998    ast_agi_send(agi->fd, chan, "200 result=0\n");
01999    return RESULT_SUCCESS;
02000 }

static int handle_setpriority ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1478 of file res_agi.c.

References ast_agi_send(), ast_explicit_goto(), ast_findlabel_extension(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01479 {
01480    int pri;
01481 
01482    if (argc != 3)
01483       return RESULT_SHOWUSAGE;
01484 
01485    if (sscanf(argv[2], "%30d", &pri) != 1) {
01486       if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
01487          return RESULT_SHOWUSAGE;
01488    }
01489 
01490    ast_explicit_goto(chan, NULL, NULL, pri);
01491    ast_agi_send(agi->fd, chan, "200 result=0\n");
01492    return RESULT_SUCCESS;
01493 }

static int handle_setvariable ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1812 of file res_agi.c.

References ast_agi_send(), agi_state::fd, pbx_builtin_setvar_helper(), and RESULT_SUCCESS.

01813 {
01814    if (argv[3])
01815       pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
01816 
01817    ast_agi_send(agi->fd, chan, "200 result=1\n");
01818    return RESULT_SUCCESS;
01819 }

static int handle_speechactivategrammar ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 2085 of file res_agi.c.

References ast_agi_send(), ast_speech_grammar_activate(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02086 {
02087    if (argc != 4)
02088       return RESULT_SHOWUSAGE;
02089 
02090    if (!agi->speech) {
02091       ast_agi_send(agi->fd, chan, "200 result=0\n");
02092       return RESULT_SUCCESS;
02093    }
02094 
02095    if (ast_speech_grammar_activate(agi->speech, argv[3]))
02096       ast_agi_send(agi->fd, chan, "200 result=0\n");
02097    else
02098       ast_agi_send(agi->fd, chan, "200 result=1\n");
02099 
02100    return RESULT_SUCCESS;
02101 }

static int handle_speechcreate ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 2002 of file res_agi.c.

References ast_agi_send(), AST_FORMAT_SLINEAR, ast_speech_new(), agi_state::fd, RESULT_SUCCESS, and agi_state::speech.

02003 {
02004    /* If a structure already exists, return an error */
02005         if (agi->speech) {
02006       ast_agi_send(agi->fd, chan, "200 result=0\n");
02007       return RESULT_SUCCESS;
02008    }
02009 
02010    if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
02011       ast_agi_send(agi->fd, chan, "200 result=1\n");
02012    else
02013       ast_agi_send(agi->fd, chan, "200 result=0\n");
02014 
02015    return RESULT_SUCCESS;
02016 }

static int handle_speechdeactivategrammar ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 2103 of file res_agi.c.

References ast_agi_send(), ast_speech_grammar_deactivate(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02104 {
02105    if (argc != 4)
02106       return RESULT_SHOWUSAGE;
02107 
02108    if (!agi->speech) {
02109       ast_agi_send(agi->fd, chan, "200 result=0\n");
02110       return RESULT_SUCCESS;
02111    }
02112 
02113    if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
02114       ast_agi_send(agi->fd, chan, "200 result=0\n");
02115    else
02116       ast_agi_send(agi->fd, chan, "200 result=1\n");
02117 
02118    return RESULT_SUCCESS;
02119 }

static int handle_speechdestroy ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 2036 of file res_agi.c.

References ast_agi_send(), ast_speech_destroy(), agi_state::fd, RESULT_SUCCESS, and agi_state::speech.

02037 {
02038    if (agi->speech) {
02039       ast_speech_destroy(agi->speech);
02040       agi->speech = NULL;
02041       ast_agi_send(agi->fd, chan, "200 result=1\n");
02042    } else {
02043       ast_agi_send(agi->fd, chan, "200 result=0\n");
02044    }
02045 
02046    return RESULT_SUCCESS;
02047 }

static int handle_speechloadgrammar ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 2049 of file res_agi.c.

References ast_agi_send(), ast_speech_grammar_load(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02050 {
02051    if (argc != 5)
02052       return RESULT_SHOWUSAGE;
02053 
02054    if (!agi->speech) {
02055       ast_agi_send(agi->fd, chan, "200 result=0\n");
02056       return RESULT_SUCCESS;
02057    }
02058 
02059    if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
02060       ast_agi_send(agi->fd, chan, "200 result=0\n");
02061    else
02062       ast_agi_send(agi->fd, chan, "200 result=1\n");
02063 
02064    return RESULT_SUCCESS;
02065 }

static int handle_speechrecognize ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 2140 of file res_agi.c.

References ast_agi_send(), ast_build_string(), ast_clear_flag, AST_CONTROL_HANGUP, AST_FORMAT_SLINEAR, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, AST_LIST_NEXT, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_sched_runq(), ast_sched_wait(), ast_set_read_format(), ast_speech_change_state(), AST_SPEECH_QUIET, ast_speech_results_get(), ast_speech_start(), AST_SPEECH_STATE_DONE, AST_SPEECH_STATE_NOT_READY, AST_SPEECH_STATE_READY, AST_SPEECH_STATE_WAIT, ast_speech_write(), ast_stopstream(), ast_strlen_zero(), ast_tellstream(), ast_test_flag, ast_waitfor(), buf, ast_frame::data, ast_frame::datalen, agi_state::fd, ast_frame::frametype, ast_speech_result::grammar, ast_channel::language, ast_speech::lock, ast_speech::processing_sound, prompt, ast_frame::ptr, ast_channel::readformat, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_speech::results, ast_channel::sched, ast_speech_result::score, agi_state::speech, speech_streamfile(), ast_speech::state, ast_channel::stream, ast_channel::streamid, ast_frame::subclass, ast_speech_result::text, and ast_channel::timingfunc.

02141 {
02142    struct ast_speech *speech = agi->speech;
02143    char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
02144    int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
02145    long current_offset = 0;
02146    const char *reason = NULL;
02147    struct ast_frame *fr = NULL;
02148    struct ast_speech_result *result = NULL;
02149    size_t left = sizeof(tmp);
02150    time_t start = 0, current;
02151 
02152    if (argc < 4)
02153       return RESULT_SHOWUSAGE;
02154 
02155    if (!speech) {
02156       ast_agi_send(agi->fd, chan, "200 result=0\n");
02157       return RESULT_SUCCESS;
02158    }
02159 
02160    prompt = argv[2];
02161    timeout = atoi(argv[3]);
02162 
02163    /* If offset is specified then convert from text to integer */
02164    if (argc == 5)
02165       offset = atoi(argv[4]);
02166 
02167    /* We want frames coming in signed linear */
02168    old_read_format = chan->readformat;
02169    if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
02170       ast_agi_send(agi->fd, chan, "200 result=0\n");
02171       return RESULT_SUCCESS;
02172    }
02173 
02174    /* Setup speech structure */
02175    if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
02176       ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02177       ast_speech_start(speech);
02178    }
02179 
02180    /* Start playing prompt */
02181    speech_streamfile(chan, prompt, chan->language, offset);
02182 
02183    /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
02184    while (ast_strlen_zero(reason)) {
02185       /* Run scheduled items */
02186                 ast_sched_runq(chan->sched);
02187 
02188       /* See maximum time of waiting */
02189       if ((res = ast_sched_wait(chan->sched)) < 0)
02190          res = 1000;
02191 
02192       /* Wait for frame */
02193       if (ast_waitfor(chan, res) > 0) {
02194          if (!(fr = ast_read(chan))) {
02195             reason = "hangup";
02196             break;
02197          }
02198       }
02199 
02200       /* Perform timeout check */
02201       if ((timeout > 0) && (start > 0)) {
02202          time(&current);
02203          if ((current - start) >= timeout) {
02204             reason = "timeout";
02205             if (fr)
02206                ast_frfree(fr);
02207             break;
02208          }
02209       }
02210 
02211       /* Check the speech structure for any changes */
02212       ast_mutex_lock(&speech->lock);
02213 
02214       /* See if we need to quiet the audio stream playback */
02215       if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
02216          current_offset = ast_tellstream(chan->stream);
02217          ast_stopstream(chan);
02218          ast_clear_flag(speech, AST_SPEECH_QUIET);
02219       }
02220 
02221       /* Check each state */
02222       switch (speech->state) {
02223       case AST_SPEECH_STATE_READY:
02224          /* If the stream is done, start timeout calculation */
02225          if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
02226             ast_stopstream(chan);
02227             time(&start);
02228          }
02229          /* Write audio frame data into speech engine if possible */
02230          if (fr && fr->frametype == AST_FRAME_VOICE)
02231             ast_speech_write(speech, fr->data.ptr, fr->datalen);
02232          break;
02233       case AST_SPEECH_STATE_WAIT:
02234          /* Cue waiting sound if not already playing */
02235          if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
02236             ast_stopstream(chan);
02237             /* If a processing sound exists, or is not none - play it */
02238             if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
02239                speech_streamfile(chan, speech->processing_sound, chan->language, 0);
02240          }
02241          break;
02242       case AST_SPEECH_STATE_DONE:
02243          /* Get the results */
02244          speech->results = ast_speech_results_get(speech);
02245          /* Change state to not ready */
02246          ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02247          reason = "speech";
02248          break;
02249       default:
02250          break;
02251       }
02252       ast_mutex_unlock(&speech->lock);
02253 
02254       /* Check frame for DTMF or hangup */
02255       if (fr) {
02256          if (fr->frametype == AST_FRAME_DTMF) {
02257             reason = "dtmf";
02258             dtmf = fr->subclass;
02259          } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
02260             reason = "hangup";
02261          }
02262          ast_frfree(fr);
02263       }
02264    }
02265 
02266    if (!strcasecmp(reason, "speech")) {
02267       /* Build string containing speech results */
02268                 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
02269          /* Build result string */
02270          ast_build_string(&buf, &left, "%sscore%d=%d text%d=\"%s\" grammar%d=%s", (i > 0 ? " " : ""), i, result->score, i, result->text, i, result->grammar);
02271                         /* Increment result count */
02272          i++;
02273       }
02274                 /* Print out */
02275       ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
02276    } else if (!strcasecmp(reason, "dtmf")) {
02277       ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
02278    } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
02279       ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
02280    } else {
02281       ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
02282    }
02283 
02284    return RESULT_SUCCESS;
02285 }

static int handle_speechset ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 2018 of file res_agi.c.

References ast_agi_send(), ast_speech_change(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02019 {
02020    /* Check for minimum arguments */
02021    if (argc != 4)
02022       return RESULT_SHOWUSAGE;
02023 
02024    /* Check to make sure speech structure exists */
02025    if (!agi->speech) {
02026       ast_agi_send(agi->fd, chan, "200 result=0\n");
02027       return RESULT_SUCCESS;
02028    }
02029 
02030    ast_speech_change(agi->speech, argv[2], argv[3]);
02031    ast_agi_send(agi->fd, chan, "200 result=1\n");
02032 
02033    return RESULT_SUCCESS;
02034 }

static int handle_speechunloadgrammar ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 2067 of file res_agi.c.

References ast_agi_send(), ast_speech_grammar_unload(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and agi_state::speech.

02068 {
02069    if (argc != 4)
02070       return RESULT_SHOWUSAGE;
02071 
02072    if (!agi->speech) {
02073       ast_agi_send(agi->fd, chan, "200 result=0\n");
02074       return RESULT_SUCCESS;
02075    }
02076 
02077    if (ast_speech_grammar_unload(agi->speech, argv[3]))
02078       ast_agi_send(agi->fd, chan, "200 result=0\n");
02079    else
02080       ast_agi_send(agi->fd, chan, "200 result=1\n");
02081 
02082    return RESULT_SUCCESS;
02083 }

static int handle_streamfile ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1190 of file res_agi.c.

References ast_agi_send(), ast_applystream(), ast_debug, ast_openstream(), ast_openvstream(), ast_playstream(), ast_seekstream(), ast_stopstream(), ast_tellstream(), ast_verb, ast_waitstream_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, ast_channel::language, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_channel::stream, and ast_filestream::vfs.

01191 {
01192    int res, vres;
01193    struct ast_filestream *fs, *vfs;
01194    long sample_offset = 0, max_length;
01195    char *edigits = "";
01196 
01197    if (argc < 4 || argc > 5)
01198       return RESULT_SHOWUSAGE;
01199 
01200    if (argv[3])
01201       edigits = argv[3];
01202 
01203    if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1))
01204       return RESULT_SHOWUSAGE;
01205 
01206    if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01207       ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
01208       return RESULT_SUCCESS;
01209    }
01210 
01211    if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01212       ast_debug(1, "Ooh, found a video stream, too\n");
01213 
01214    ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
01215 
01216    ast_seekstream(fs, 0, SEEK_END);
01217    max_length = ast_tellstream(fs);
01218    ast_seekstream(fs, sample_offset, SEEK_SET);
01219    res = ast_applystream(chan, fs);
01220    if (vfs)
01221       vres = ast_applystream(chan, vfs);
01222    ast_playstream(fs);
01223    if (vfs)
01224       ast_playstream(vfs);
01225 
01226    res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01227    /* this is to check for if ast_waitstream closed the stream, we probably are at
01228     * the end of the stream, return that amount, else check for the amount */
01229    sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
01230    ast_stopstream(chan);
01231    if (res == 1) {
01232       /* Stop this command, don't print a result line, as there is a new command */
01233       return RESULT_SUCCESS;
01234    }
01235    ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01236    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01237 }

static int handle_tddmode ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1111 of file res_agi.c.

References ast_agi_send(), ast_channel_setoption(), AST_OPTION_TDD, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01112 {
01113    int res, x;
01114 
01115    if (argc != 3)
01116       return RESULT_SHOWUSAGE;
01117 
01118    if (!strncasecmp(argv[2],"on",2)) {
01119       x = 1;
01120    } else  {
01121       x = 0;
01122    }
01123    if (!strncasecmp(argv[2],"mate",4))  {
01124       x = 2;
01125    }
01126    if (!strncasecmp(argv[2],"tdd",3)) {
01127       x = 1;
01128    }
01129    res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
01130    if (res != RESULT_SUCCESS) {
01131       ast_agi_send(agi->fd, chan, "200 result=0\n");
01132    } else {
01133       ast_agi_send(agi->fd, chan, "200 result=1\n");
01134    }
01135    return RESULT_SUCCESS;
01136 }

static int handle_verbose ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 1867 of file res_agi.c.

References ast_agi_send(), ast_verb, ast_channel::data, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01868 {
01869    int level = 0;
01870 
01871    if (argc < 2)
01872       return RESULT_SHOWUSAGE;
01873 
01874    if (argv[2])
01875       sscanf(argv[2], "%30d", &level);
01876 
01877    ast_verb(level, "%s: %s\n", chan->data, argv[1]);
01878 
01879    ast_agi_send(agi->fd, chan, "200 result=1\n");
01880 
01881    return RESULT_SUCCESS;
01882 }

static int handle_waitfordigit ( struct ast_channel chan,
AGI agi,
int  argc,
char *  argv[] 
) [static]

Definition at line 1042 of file res_agi.c.

References ast_agi_send(), ast_waitfordigit_full(), agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01043 {
01044    int res, to;
01045 
01046    if (argc != 4)
01047       return RESULT_SHOWUSAGE;
01048    if (sscanf(argv[3], "%30d", &to) != 1)
01049       return RESULT_SHOWUSAGE;
01050    res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
01051    ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01052    return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01053 }

static char* help_workhorse ( int  fd,
char *  match[] 
) [static]

Definition at line 2533 of file res_agi.c.

References ast_cli(), ast_join(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, CLI_SUCCESS, agi_command::cmda, agi_command::dead, agi_command::list, MAX_CMD_LEN, S_OR, and agi_command::summary.

Referenced by handle_cli_agi_show().

02534 {
02535    char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
02536    struct agi_command *e;
02537 
02538    if (match)
02539       ast_join(matchstr, sizeof(matchstr), match);
02540 
02541    ast_cli(fd, "%5.5s %30.30s   %s\n","Dead","Command","Description");
02542    AST_RWLIST_RDLOCK(&agi_commands);
02543    AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
02544       if (!e->cmda[0])
02545          break;
02546       /* Hide commands that start with '_' */
02547       if ((e->cmda[0])[0] == '_')
02548          continue;
02549       ast_join(fullcmd, sizeof(fullcmd), e->cmda);
02550       if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
02551          continue;
02552       ast_cli(fd, "%5.5s %30.30s   %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
02553    }
02554    AST_RWLIST_UNLOCK(&agi_commands);
02555 
02556    return CLI_SUCCESS;
02557 }

static enum agi_result launch_asyncagi ( struct ast_channel chan,
char *  argv[],
int *  efd 
) [static]

Definition at line 618 of file res_agi.c.

References add_to_agi(), AGI_BUF_SIZE, agi_handle_command(), AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS_ASYNC, AMI_BUF_SIZE, ast_check_hangup(), AST_CONTROL_HANGUP, AST_FRAME_CONTROL, ast_frfree, ast_log(), ast_read(), ast_speech_destroy(), ast_strlen_zero(), ast_uri_encode(), ast_waitfor(), agi_state::audio, agi_cmd::cmd_buffer, agi_cmd::cmd_id, agi_state::ctrl, EVENT_FLAG_AGI, f, agi_state::fast, agi_state::fd, ast_frame::frametype, free_agi_cmd(), get_agi_cmd(), LOG_DEBUG, LOG_ERROR, LOG_WARNING, manager_event, ast_channel::name, quit, setup_env(), agi_state::speech, and ast_frame::subclass.

Referenced by launch_script().

00619 {
00620 /* This buffer sizes might cause truncation if the AGI command writes more data
00621    than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
00622    that writes a response larger than 1024 bytes?, I don't think so, most of
00623    them are just result=blah stuff. However probably if GET VARIABLE is called
00624    and the variable has large amount of data, that could be a problem. We could
00625    make this buffers dynamic, but let's leave that as a second step.
00626 
00627    AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
00628    number. Some characters of AGI buf will be url encoded to be sent to manager
00629    clients.  An URL encoded character will take 3 bytes, but again, to cause
00630    truncation more than about 70% of the AGI buffer should be URL encoded for
00631    that to happen.  Not likely at all.
00632 
00633    On the other hand. I wonder if read() could eventually return less data than
00634    the amount already available in the pipe? If so, how to deal with that?
00635    So far, my tests on Linux have not had any problems.
00636  */
00637 #define AGI_BUF_SIZE 1024
00638 #define AMI_BUF_SIZE 2048
00639    struct ast_frame *f;
00640    struct agi_cmd *cmd;
00641    int res, fds[2];
00642    int timeout = 100;
00643    char agi_buffer[AGI_BUF_SIZE + 1];
00644    char ami_buffer[AMI_BUF_SIZE];
00645    enum agi_result returnstatus = AGI_RESULT_SUCCESS_ASYNC;
00646    AGI async_agi;
00647 
00648    if (efd) {
00649       ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
00650       return AGI_RESULT_FAILURE;
00651    }
00652 
00653    /* add AsyncAGI datastore to the channel */
00654    if (add_to_agi(chan)) {
00655       ast_log(LOG_ERROR, "failed to start Async AGI on channel %s\n", chan->name);
00656       return AGI_RESULT_FAILURE;
00657    }
00658 
00659    /* this pipe allows us to create a "fake" AGI struct to use
00660       the AGI commands */
00661    res = pipe(fds);
00662    if (res) {
00663       ast_log(LOG_ERROR, "failed to create Async AGI pipe\n");
00664       /* intentionally do not remove datastore, added with
00665          add_to_agi(), from channel. It will be removed when
00666          the channel is hung up anyways */
00667       return AGI_RESULT_FAILURE;
00668    }
00669 
00670    /* handlers will get the pipe write fd and we read the AGI responses
00671       from the pipe read fd */
00672    async_agi.fd = fds[1];
00673    async_agi.ctrl = fds[1];
00674    async_agi.audio = -1; /* no audio support */
00675    async_agi.fast = 0;
00676    async_agi.speech = NULL;
00677 
00678    /* notify possible manager users of a new channel ready to
00679       receive commands */
00680    setup_env(chan, "async", fds[1], 0, 0, NULL);
00681    /* read the environment */
00682    res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
00683    if (!res) {
00684       ast_log(LOG_ERROR, "failed to read from Async AGI pipe on channel %s\n", chan->name);
00685       returnstatus = AGI_RESULT_FAILURE;
00686       goto quit;
00687    }
00688    agi_buffer[res] = '\0';
00689    /* encode it and send it thru the manager so whoever is going to take
00690       care of AGI commands on this channel can decide which AGI commands
00691       to execute based on the setup info */
00692    ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
00693    manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer);
00694    while (1) {
00695       /* bail out if we need to hangup */
00696       if (ast_check_hangup(chan)) {
00697          ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
00698          break;
00699       }
00700       /* retrieve a command
00701          (commands are added via the manager or the cli threads) */
00702       cmd = get_agi_cmd(chan);
00703       if (cmd) {
00704          /* OK, we have a command, let's call the
00705             command handler. */
00706          res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
00707          if (res < 0) {
00708             free_agi_cmd(cmd);
00709             break;
00710          }
00711          /* the command handler must have written to our fake
00712             AGI struct fd (the pipe), let's read the response */
00713          res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
00714          if (!res) {
00715             returnstatus = AGI_RESULT_FAILURE;
00716             ast_log(LOG_ERROR, "failed to read from AsyncAGI pipe on channel %s\n", chan->name);
00717             free_agi_cmd(cmd);
00718             break;
00719          }
00720          /* we have a response, let's send the response thru the
00721             manager. Include the CommandID if it was specified
00722             when the command was added */
00723          agi_buffer[res] = '\0';
00724          ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
00725          if (ast_strlen_zero(cmd->cmd_id))
00726             manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nResult: %s\r\n", chan->name, ami_buffer);
00727          else
00728             manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nCommandID: %s\r\nResult: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
00729          free_agi_cmd(cmd);
00730       } else {
00731          /* no command so far, wait a bit for a frame to read */
00732          res = ast_waitfor(chan, timeout);
00733          if (res < 0) {
00734             ast_log(LOG_DEBUG, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
00735             break;
00736          }
00737          if (res == 0)
00738             continue;
00739          f = ast_read(chan);
00740          if (!f) {
00741             ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
00742             returnstatus = AGI_RESULT_HANGUP;
00743             break;
00744          }
00745          /* is there any other frame we should care about
00746             besides AST_CONTROL_HANGUP? */
00747          if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
00748             ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
00749             ast_frfree(f);
00750             break;
00751          }
00752          ast_frfree(f);
00753       }
00754    }
00755 
00756    if (async_agi.speech) {
00757       ast_speech_destroy(async_agi.speech);
00758    }
00759 quit:
00760    /* notify manager users this channel cannot be
00761       controlled anymore by Async AGI */
00762    manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
00763 
00764    /* close the pipe */
00765    close(fds[0]);
00766    close(fds[1]);
00767 
00768    /* intentionally don't get rid of the datastore. So commands can be
00769       still in the queue in case AsyncAGI gets called again.
00770       Datastore destructor will be called on channel destroy anyway  */
00771 
00772    return returnstatus;
00773 
00774 #undef AGI_BUF_SIZE
00775 #undef AMI_BUF_SIZE
00776 }

static enum agi_result launch_netscript ( char *  agiurl,
char *  argv[],
int *  fds,
int *  efd,
int *  opid 
) [static]

Definition at line 780 of file res_agi.c.

References AGI_PORT, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS_FAST, ast_agi_send(), ast_debug, ast_gethostbyname(), ast_log(), ast_poll, ast_strdupa, ast_strlen_zero(), errno, hp, LOG_WARNING, MAX_AGI_CONNECT, and s.

Referenced by launch_script().

00781 {
00782    int s, flags, res, port = AGI_PORT;
00783    struct pollfd pfds[1];
00784    char *host, *c, *script = "";
00785    struct sockaddr_in addr_in;
00786    struct hostent *hp;
00787    struct ast_hostent ahp;
00788 
00789    /* agiusl is "agi://host.domain[:port][/script/name]" */
00790    host = ast_strdupa(agiurl + 6);  /* Remove agi:// */
00791    /* Strip off any script name */
00792    if ((c = strchr(host, '/'))) {
00793       *c = '\0';
00794       c++;
00795       script = c;
00796    }
00797    if ((c = strchr(host, ':'))) {
00798       *c = '\0';
00799       c++;
00800       port = atoi(c);
00801    }
00802    if (efd) {
00803       ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
00804       return -1;
00805    }
00806    if (!(hp = ast_gethostbyname(host, &ahp))) {
00807       ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
00808       return -1;
00809    }
00810    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00811       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
00812       return -1;
00813    }
00814    if ((flags = fcntl(s, F_GETFL)) < 0) {
00815       ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
00816       close(s);
00817       return -1;
00818    }
00819    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
00820       ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
00821       close(s);
00822       return -1;
00823    }
00824    memset(&addr_in, 0, sizeof(addr_in));
00825    addr_in.sin_family = AF_INET;
00826    addr_in.sin_port = htons(port);
00827    memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr));
00828    if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) {
00829       ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
00830       close(s);
00831       return AGI_RESULT_FAILURE;
00832    }
00833 
00834    pfds[0].fd = s;
00835    pfds[0].events = POLLOUT;
00836    while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
00837       if (errno != EINTR) {
00838          if (!res) {
00839             ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
00840                agiurl, MAX_AGI_CONNECT);
00841          } else
00842             ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
00843          close(s);
00844          return AGI_RESULT_FAILURE;
00845       }
00846    }
00847 
00848    if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
00849       if (errno != EINTR) {
00850          ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
00851          close(s);
00852          return AGI_RESULT_FAILURE;
00853       }
00854    }
00855 
00856    /* If we have a script parameter, relay it to the fastagi server */
00857    /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
00858    if (!ast_strlen_zero(script))
00859       ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
00860 
00861    ast_debug(4, "Wow, connected!\n");
00862    fds[0] = s;
00863    fds[1] = s;
00864    *opid = -1;
00865    return AGI_RESULT_SUCCESS_FAST;
00866 }

static enum agi_result launch_script ( struct ast_channel chan,
char *  script,
char *  argv[],
int *  fds,
int *  efd,
int *  opid 
) [static]

Definition at line 868 of file res_agi.c.

References AGI_RESULT_FAILURE, AGI_RESULT_NOTFOUND, AGI_RESULT_SUCCESS, ast_child_verbose(), ast_close_fds_above_n(), ast_config_AST_AGI_DIR, ast_config_AST_CONFIG_DIR, ast_config_AST_CONFIG_FILE, ast_config_AST_DATA_DIR, ast_config_AST_KEY_DIR, ast_config_AST_LOG_DIR, ast_config_AST_MODULE_DIR, ast_config_AST_MONITOR_DIR, ast_config_AST_RUN_DIR, ast_config_AST_SPOOL_DIR, ast_config_AST_VAR_DIR, ast_log(), ast_safe_fork(), ast_set_priority(), ast_verb, errno, launch_asyncagi(), launch_netscript(), LOG_WARNING, and setenv().

Referenced by agi_exec_full().

00869 {
00870    char tmp[256];
00871    int pid, toast[2], fromast[2], audio[2], res;
00872    struct stat st;
00873 
00874    if (!strncasecmp(script, "agi://", 6))
00875       return launch_netscript(script, argv, fds, efd, opid);
00876    if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
00877       return launch_asyncagi(chan, argv, efd);
00878 
00879    if (script[0] != '/') {
00880       snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
00881       script = tmp;
00882    }
00883 
00884    /* Before even trying let's see if the file actually exists */
00885    if (stat(script, &st)) {
00886       ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
00887       return AGI_RESULT_NOTFOUND;
00888    }
00889 
00890    if (pipe(toast)) {
00891       ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
00892       return AGI_RESULT_FAILURE;
00893    }
00894    if (pipe(fromast)) {
00895       ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
00896       close(toast[0]);
00897       close(toast[1]);
00898       return AGI_RESULT_FAILURE;
00899    }
00900    if (efd) {
00901       if (pipe(audio)) {
00902          ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
00903          close(fromast[0]);
00904          close(fromast[1]);
00905          close(toast[0]);
00906          close(toast[1]);
00907          return AGI_RESULT_FAILURE;
00908       }
00909       res = fcntl(audio[1], F_GETFL);
00910       if (res > -1)
00911          res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
00912       if (res < 0) {
00913          ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
00914          close(fromast[0]);
00915          close(fromast[1]);
00916          close(toast[0]);
00917          close(toast[1]);
00918          close(audio[0]);
00919          close(audio[1]);
00920          return AGI_RESULT_FAILURE;
00921       }
00922    }
00923 
00924    if ((pid = ast_safe_fork(1)) < 0) {
00925       ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
00926       return AGI_RESULT_FAILURE;
00927    }
00928    if (!pid) {
00929       /* Pass paths to AGI via environmental variables */
00930       setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
00931       setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
00932       setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
00933       setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
00934       setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
00935       setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
00936       setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
00937       setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
00938       setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
00939       setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
00940       setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
00941 
00942       /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
00943       ast_set_priority(0);
00944 
00945       /* Redirect stdin and out, provide enhanced audio channel if desired */
00946       dup2(fromast[0], STDIN_FILENO);
00947       dup2(toast[1], STDOUT_FILENO);
00948       if (efd)
00949          dup2(audio[0], STDERR_FILENO + 1);
00950       else
00951          close(STDERR_FILENO + 1);
00952 
00953       /* Close everything but stdin/out/error */
00954       ast_close_fds_above_n(STDERR_FILENO + 1);
00955 
00956       /* Execute script */
00957       /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
00958       execv(script, argv);
00959       /* Can't use ast_log since FD's are closed */
00960       ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
00961       /* Special case to set status of AGI to failure */
00962       fprintf(stdout, "failure\n");
00963       fflush(stdout);
00964       _exit(1);
00965    }
00966    ast_verb(3, "Launched AGI Script %s\n", script);
00967    fds[0] = toast[0];
00968    fds[1] = fromast[1];
00969    if (efd)
00970       *efd = audio[1];
00971    /* close what we're not using in the parent */
00972    close(toast[1]);
00973    close(fromast[0]);
00974 
00975    if (efd)
00976       close(audio[0]);
00977 
00978    *opid = pid;
00979    return AGI_RESULT_SUCCESS;
00980 }

static int load_module ( void   )  [static]

Definition at line 3353 of file res_agi.c.

References action_add_agi_cmd(), agi_exec(), ARRAY_LEN, ast_agi_register_multiple(), ast_cli_register_multiple(), ast_manager_register2(), ast_register_application, cli_agi, commands, deadagi_exec(), eagi_exec(), EVENT_FLAG_AGI, and mandescr_asyncagi.

03354 {
03355    ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
03356    /* we can safely ignore the result of ast_agi_register_multiple() here, since it cannot fail, as
03357       no other commands have been registered yet
03358    */
03359    (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03360    ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
03361    ast_register_application(eapp, eagi_exec, esynopsis, descrip);
03362    ast_manager_register2("AGI", EVENT_FLAG_AGI, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
03363    return ast_register_application(app, agi_exec, synopsis, descrip);
03364 }

static int parse_args ( char *  s,
int *  max,
char *  argv[] 
) [static]

Definition at line 2717 of file res_agi.c.

References ast_log(), LOG_WARNING, and MAX_ARGS.

02718 {
02719    int x = 0, quoted = 0, escaped = 0, whitespace = 1;
02720    char *cur;
02721 
02722    cur = s;
02723    while(*s) {
02724       switch(*s) {
02725       case '"':
02726          /* If it's escaped, put a literal quote */
02727          if (escaped)
02728             goto normal;
02729          else
02730             quoted = !quoted;
02731          if (quoted && whitespace) {
02732             /* If we're starting a quote, coming off white space start a new word, too */
02733             argv[x++] = cur;
02734             whitespace=0;
02735          }
02736          escaped = 0;
02737       break;
02738       case ' ':
02739       case '\t':
02740          if (!quoted && !escaped) {
02741             /* If we're not quoted, mark this as whitespace, and
02742                end the previous argument */
02743             whitespace = 1;
02744             *(cur++) = '\0';
02745          } else
02746             /* Otherwise, just treat it as anything else */
02747             goto normal;
02748          break;
02749       case '\\':
02750          /* If we're escaped, print a literal, otherwise enable escaping */
02751          if (escaped) {
02752             goto normal;
02753          } else {
02754             escaped=1;
02755          }
02756          break;
02757       default:
02758 normal:
02759          if (whitespace) {
02760             if (x >= MAX_ARGS -1) {
02761                ast_log(LOG_WARNING, "Too many arguments, truncating\n");
02762                break;
02763             }
02764             /* Coming off of whitespace, start the next argument */
02765             argv[x++] = cur;
02766             whitespace=0;
02767          }
02768          *(cur++) = *s;
02769          escaped=0;
02770       }
02771       s++;
02772    }
02773    /* Null terminate */
02774    *(cur++) = '\0';
02775    argv[x] = NULL;
02776    *max = x;
02777    return 0;
02778 }

static enum agi_result run_agi ( struct ast_channel chan,
char *  request,
AGI agi,
int  pid,
int *  status,
int  dead,
int  argc,
char *  argv[] 
) [static]

Definition at line 2857 of file res_agi.c.

References AGI_BUF_LEN, agi_handle_command(), AGI_NANDFS_RETRY, AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS, ast_channel_lock, ast_channel_unlock, ast_check_hangup(), ast_debug, ast_false(), AST_FRAME_VOICE, ast_frfree, ast_log(), ast_read(), ast_speech_destroy(), ast_strlen_zero(), ast_verb, ast_verbose, ast_waitfor_nandfds(), agi_state::audio, buf, agi_state::ctrl, ast_frame::data, ast_frame::datalen, errno, f, agi_state::fast, agi_state::fd, ast_frame::frametype, len(), LOG_WARNING, ast_channel::name, pbx_builtin_getvar_helper(), ast_frame::ptr, setup_env(), and agi_state::speech.

Referenced by agi_exec_full().

02858 {
02859    struct ast_channel *c;
02860    int outfd, ms, needhup = 0;
02861    enum agi_result returnstatus = AGI_RESULT_SUCCESS;
02862    struct ast_frame *f;
02863    char buf[AGI_BUF_LEN];
02864    char *res = NULL;
02865    FILE *readf;
02866    /* how many times we'll retry if ast_waitfor_nandfs will return without either
02867      channel or file descriptor in case select is interrupted by a system call (EINTR) */
02868    int retry = AGI_NANDFS_RETRY;
02869    int send_sighup;
02870    const char *sighup_str;
02871    
02872    ast_channel_lock(chan);
02873    sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
02874    send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str);
02875    ast_channel_unlock(chan);
02876 
02877    if (!(readf = fdopen(agi->ctrl, "r"))) {
02878       ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
02879       if (send_sighup && pid > -1)
02880          kill(pid, SIGHUP);
02881       close(agi->ctrl);
02882       return AGI_RESULT_FAILURE;
02883    }
02884    
02885    setlinebuf(readf);
02886    setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
02887    for (;;) {
02888       if (needhup) {
02889          needhup = 0;
02890          dead = 1;
02891          if (send_sighup) {
02892             if (pid > -1) {
02893                kill(pid, SIGHUP);
02894             } else if (agi->fast) {
02895                send(agi->ctrl, "HANGUP\n", 7, 0);
02896             }
02897          }
02898       }
02899       ms = -1;
02900       if (dead) {
02901          c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
02902       } else if (!ast_check_hangup(chan)) {
02903          c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
02904       } else {
02905          /*
02906           * Read the channel control queue until it is dry so we can
02907           * switch to dead mode.
02908           */
02909          c = chan;
02910       }
02911       if (c) {
02912          retry = AGI_NANDFS_RETRY;
02913          /* Idle the channel until we get a command */
02914          f = ast_read(c);
02915          if (!f) {
02916             ast_debug(1, "%s hungup\n", chan->name);
02917             needhup = 1;
02918             if (!returnstatus) {
02919                returnstatus = AGI_RESULT_HANGUP;
02920             }
02921          } else {
02922             /* If it's voice, write it to the audio pipe */
02923             if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
02924                /* Write, ignoring errors */
02925                if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
02926                }
02927             }
02928             ast_frfree(f);
02929          }
02930       } else if (outfd > -1) {
02931          size_t len = sizeof(buf);
02932          size_t buflen = 0;
02933          enum agi_result cmd_status;
02934 
02935          retry = AGI_NANDFS_RETRY;
02936          buf[0] = '\0';
02937 
02938          while (len > 1) {
02939             res = fgets(buf + buflen, len, readf);
02940             if (feof(readf))
02941                break;
02942             if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
02943                break;
02944             if (res != NULL && !agi->fast)
02945                break;
02946             buflen = strlen(buf);
02947             if (buflen && buf[buflen - 1] == '\n')
02948                break;
02949             len = sizeof(buf) - buflen;
02950             if (agidebug)
02951                ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
02952          }
02953 
02954          if (!buf[0]) {
02955             /* Program terminated */
02956             ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
02957             if (pid > 0)
02958                waitpid(pid, status, 0);
02959             /* No need to kill the pid anymore, since they closed us */
02960             pid = -1;
02961             break;
02962          }
02963 
02964          /* Special case for inability to execute child process */
02965          if (*buf && strncasecmp(buf, "failure", 7) == 0) {
02966             returnstatus = AGI_RESULT_FAILURE;
02967             break;
02968          }
02969 
02970          /* get rid of trailing newline, if any */
02971          if (*buf && buf[strlen(buf) - 1] == '\n')
02972             buf[strlen(buf) - 1] = 0;
02973          if (agidebug)
02974             ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
02975          cmd_status = agi_handle_command(chan, agi, buf, dead);
02976          switch (cmd_status) {
02977          case AGI_RESULT_FAILURE:
02978             if (dead || !ast_check_hangup(chan)) {
02979                /* The failure was not because of a hangup. */
02980                returnstatus = AGI_RESULT_FAILURE;
02981             }
02982             break;
02983          default:
02984             break;
02985          }
02986       } else {
02987          if (--retry <= 0) {
02988             ast_log(LOG_WARNING, "No channel, no fd?\n");
02989             returnstatus = AGI_RESULT_FAILURE;
02990             break;
02991          }
02992       }
02993    }
02994    if (agi->speech) {
02995       ast_speech_destroy(agi->speech);
02996    }
02997    /* Notify process */
02998    if (send_sighup) {
02999       if (pid > -1) {
03000          if (kill(pid, SIGHUP)) {
03001             ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
03002          } else { /* Give the process a chance to die */
03003             usleep(1);
03004          }
03005          waitpid(pid, status, WNOHANG);
03006       } else if (agi->fast) {
03007          send(agi->ctrl, "HANGUP\n", 7, 0);
03008       }
03009    }
03010    fclose(readf);
03011    return returnstatus;
03012 }

static void setup_env ( struct ast_channel chan,
char *  request,
int  fd,
int  enhanced,
int  argc,
char *  argv[] 
) [static]

Definition at line 982 of file res_agi.c.

References ast_channel::accountcode, ast_agi_send(), ast_get_version(), ast_channel::cid, ast_callerid::cid_ani2, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_channel::exten, ast_channel::language, ast_channel::name, ast_channel::priority, S_OR, ast_channel::tech, ast_channel_tech::type, and ast_channel::uniqueid.

Referenced by launch_asyncagi(), and run_agi().

00983 {
00984    int count;
00985 
00986    /* Print initial environment, with agi_request always being the first
00987       thing */
00988    ast_agi_send(fd, chan, "agi_request: %s\n", request);
00989    ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name);
00990    ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
00991    ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
00992    ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
00993    ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
00994 
00995    /* ANI/DNIS */
00996    ast_agi_send(fd, chan, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
00997    ast_agi_send(fd, chan, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
00998    ast_agi_send(fd, chan, "agi_callingpres: %d\n", chan->cid.cid_pres);
00999    ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->cid.cid_ani2);
01000    ast_agi_send(fd, chan, "agi_callington: %d\n", chan->cid.cid_ton);
01001    ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->cid.cid_tns);
01002    ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
01003    ast_agi_send(fd, chan, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
01004 
01005    /* Context information */
01006    ast_agi_send(fd, chan, "agi_context: %s\n", chan->context);
01007    ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten);
01008    ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority);
01009    ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
01010 
01011    /* User information */
01012    ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
01013    ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
01014 
01015    /* Send any parameters to the fastagi server that have been passed via the agi application */
01016    /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
01017    for(count = 1; count < argc; count++)
01018       ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
01019 
01020    /* End with empty return */
01021    ast_agi_send(fd, chan, "\n");
01022 }

static int speech_streamfile ( struct ast_channel chan,
const char *  filename,
const char *  preflang,
int  offset 
) [static]

Definition at line 2121 of file res_agi.c.

References ast_applystream(), ast_openstream(), ast_playstream(), and ast_seekstream().

02122 {
02123    struct ast_filestream *fs = NULL;
02124 
02125    if (!(fs = ast_openstream(chan, filename, preflang)))
02126       return -1;
02127 
02128    if (offset)
02129       ast_seekstream(fs, offset, SEEK_SET);
02130 
02131    if (ast_applystream(chan, fs))
02132       return -1;
02133 
02134    if (ast_playstream(fs))
02135       return -1;
02136 
02137    return 0;
02138 }

static int unload_module ( void   )  [static]

Definition at line 3340 of file res_agi.c.

References ARRAY_LEN, ast_agi_unregister_multiple(), ast_cli_unregister_multiple(), ast_manager_unregister(), ast_unregister_application(), cli_agi, and commands.

03341 {
03342    ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
03343    /* we can safely ignore the result of ast_agi_unregister_multiple() here, since it cannot fail, as
03344       we know that these commands were registered by this module and are still registered
03345    */
03346    (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03347    ast_unregister_application(eapp);
03348    ast_unregister_application(deadapp);
03349    ast_manager_unregister("AGI");
03350    return ast_unregister_application(app);
03351 }

static void write_html_escaped ( FILE *  htmlfile,
char *  str 
) [static]

Convert string to use HTML escaped characters.

Note:
Maybe this should be a generic function?

Definition at line 3120 of file res_agi.c.

Referenced by write_htmldump().

03121 {
03122    char *cur = str;
03123 
03124    while(*cur) {
03125       switch (*cur) {
03126       case '<':
03127          fprintf(htmlfile, "%s", "&lt;");
03128          break;
03129       case '>':
03130          fprintf(htmlfile, "%s", "&gt;");
03131          break;
03132       case '&':
03133          fprintf(htmlfile, "%s", "&amp;");
03134          break;
03135       case '"':
03136          fprintf(htmlfile, "%s", "&quot;");
03137          break;
03138       default:
03139          fprintf(htmlfile, "%c", *cur);
03140          break;
03141       }
03142       cur++;
03143    }
03144 
03145    return;
03146 }

static int write_htmldump ( char *  filename  )  [static]

Definition at line 3148 of file res_agi.c.

References ast_free, ast_join(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, agi_command::cmda, agi_command::list, MAX_CMD_LEN, strsep(), agi_command::summary, agi_command::usage, and write_html_escaped().

Referenced by handle_cli_agi_dump_html().

03149 {
03150    struct agi_command *command;
03151    char fullcmd[MAX_CMD_LEN];
03152    FILE *htmlfile;
03153 
03154    if (!(htmlfile = fopen(filename, "wt")))
03155       return -1;
03156 
03157    fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
03158    fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
03159    fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
03160 
03161    AST_RWLIST_RDLOCK(&agi_commands);
03162    AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
03163 #ifdef AST_XML_DOCS
03164       char *stringptmp;
03165 #endif
03166       char *tempstr, *stringp;
03167 
03168       if (!command->cmda[0])  /* end ? */
03169          break;
03170       /* Hide commands that start with '_' */
03171       if ((command->cmda[0])[0] == '_')
03172          continue;
03173       ast_join(fullcmd, sizeof(fullcmd), command->cmda);
03174 
03175       fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
03176       fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
03177 #ifdef AST_XML_DOCS
03178       stringptmp = ast_xmldoc_printable(command->usage, 0);
03179       stringp = stringptmp;
03180 #else
03181       stringp = command->usage;
03182 #endif
03183       tempstr = strsep(&stringp, "\n");
03184 
03185       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
03186       write_html_escaped(htmlfile, tempstr);
03187       fprintf(htmlfile, "</TD></TR>\n");
03188       fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
03189 
03190       while ((tempstr = strsep(&stringp, "\n")) != NULL) {
03191          write_html_escaped(htmlfile, tempstr);
03192          fprintf(htmlfile, "<BR>\n");
03193       }
03194       fprintf(htmlfile, "</TD></TR>\n");
03195       fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
03196 #ifdef AST_XML_DOCS
03197       ast_free(stringptmp);
03198 #endif
03199    }
03200    AST_RWLIST_UNLOCK(&agi_commands);
03201    fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
03202    fclose(htmlfile);
03203    return 0;
03204 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "Asterisk Gateway Interface (AGI)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 3369 of file res_agi.c.

struct ast_threadstorage agi_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_agi_buf , .custom_init = NULL , } [static]

Definition at line 373 of file res_agi.c.

Referenced by ast_agi_send().

Initial value:

 {
   .type = "AsyncAGI",
   .destroy = agi_destroy_commands_cb
}

Definition at line 434 of file res_agi.c.

Referenced by add_agi_cmd(), add_to_agi(), and get_agi_cmd().

int agidebug = 0 [static]

Definition at line 353 of file res_agi.c.

char* app = "AGI" [static]

Definition at line 322 of file res_agi.c.

Definition at line 3369 of file res_agi.c.

struct ast_cli_entry cli_agi[] [static]

Definition at line 3333 of file res_agi.c.

Referenced by load_module(), and unload_module().

struct agi_command commands[] [static]

AGI commands list.

Definition at line 2482 of file res_agi.c.

Referenced by aji_dinfo_handler(), dundi_showframe(), load_module(), and unload_module().

char* deadapp = "DeadAGI" [static]

Definition at line 326 of file res_agi.c.

char* deadsynopsis = "Executes AGI on a hungup channel" [static]

Definition at line 330 of file res_agi.c.

char* descrip [static]

Definition at line 332 of file res_agi.c.

char* eapp = "EAGI" [static]

Definition at line 324 of file res_agi.c.

char* esynopsis = "Executes an EAGI compliant application" [static]

Definition at line 329 of file res_agi.c.

const char mandescr_asyncagi[] [static]

Definition at line 439 of file res_agi.c.

Referenced by load_module().

char* synopsis = "Executes an AGI compliant application" [static]

Definition at line 328 of file res_agi.c.

char usage_autohangup[] [static]

Initial value:

" Usage: SET AUTOHANGUP <time>\n"
"  Cause the channel to automatically hangup at <time> seconds in the\n"
" future.  Of course it can be hungup before then as well. Setting to 0 will\n"
" cause the autohangup feature to be disabled on this channel.\n"

Definition at line 2441 of file res_agi.c.

char usage_controlstreamfile[] [static]

Definition at line 2351 of file res_agi.c.

char usage_recordfile[] [static]

Definition at line 2429 of file res_agi.c.

char usage_recvchar[] [static]

Definition at line 2315 of file res_agi.c.

char usage_recvtext[] [static]

Initial value:

" Usage: RECEIVE TEXT <timeout>\n"
"  Receives a string of text on a channel. Specify timeout to be the\n"
" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
" do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n"

Definition at line 2323 of file res_agi.c.

char usage_sayalpha[] [static]

Definition at line 2375 of file res_agi.c.

char usage_saydate[] [static]

Definition at line 2382 of file res_agi.c.

char usage_saydatetime[] [static]

Definition at line 2398 of file res_agi.c.

char usage_saydigits[] [static]

Definition at line 2368 of file res_agi.c.

char usage_saynumber[] [static]

Definition at line 2361 of file res_agi.c.

char usage_sayphonetic[] [static]

Definition at line 2409 of file res_agi.c.

char usage_saytime[] [static]

Definition at line 2390 of file res_agi.c.

char usage_sendimage[] [static]

Definition at line 2334 of file res_agi.c.

char usage_sendtext[] [static]

Definition at line 2307 of file res_agi.c.

char usage_setcallerid[] [static]

Initial value:

" Usage: SET CALLERID <number>\n"
"  Changes the callerid of the current channel.\n"

Definition at line 2296 of file res_agi.c.

char usage_setcontext[] [static]

Initial value:

" Usage: SET CONTEXT <desired context>\n"
"  Sets the context for continuation upon exiting the application.\n"

Definition at line 2416 of file res_agi.c.

char usage_setextension[] [static]

Initial value:

" Usage: SET EXTENSION <new extension>\n"
"  Changes the extension for continuation upon exiting the application.\n"

Definition at line 2420 of file res_agi.c.

char usage_setpriority[] [static]

Initial value:

" Usage: SET PRIORITY <priority>\n"
"  Changes the priority for continuation upon exiting the application.\n"
" The priority must be a valid priority or label.\n"

Definition at line 2424 of file res_agi.c.

char usage_setvariable[] [static]

Initial value:

" Usage: SET VARIABLE <variablename> <value>\n"

Definition at line 2293 of file res_agi.c.

char usage_speechactivategrammar[] [static]

Initial value:

" Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
"       Activates the specified grammar on the speech object.\n"

Definition at line 2467 of file res_agi.c.

char usage_speechcreate[] [static]

Initial value:

" Usage: SPEECH CREATE <engine>\n"
"       Create a speech object to be used by the other Speech AGI commands.\n"

Definition at line 2447 of file res_agi.c.

Initial value:

" Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
"       Deactivates the specified grammar on the speech object.\n"

Definition at line 2471 of file res_agi.c.

char usage_speechdestroy[] [static]

Initial value:

" Usage: SPEECH DESTROY\n"
"       Destroy the speech object created by SPEECH CREATE.\n"

Definition at line 2455 of file res_agi.c.

char usage_speechloadgrammar[] [static]

Initial value:

" Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
"       Loads the specified grammar as the specified name.\n"

Definition at line 2459 of file res_agi.c.

char usage_speechrecognize[] [static]

Initial value:

" Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
"       Plays back given prompt while listening for speech and dtmf.\n"

Definition at line 2475 of file res_agi.c.

char usage_speechset[] [static]

Initial value:

" Usage: SPEECH SET <name> <value>\n"
"       Set an engine-specific setting.\n"

Definition at line 2451 of file res_agi.c.

char usage_speechunloadgrammar[] [static]

Initial value:

" Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
"       Unloads the specified grammar.\n"

Definition at line 2463 of file res_agi.c.

char usage_streamfile[] [static]

Definition at line 2341 of file res_agi.c.

char usage_tddmode[] [static]

Initial value:

" Usage: TDD MODE <on|off>\n"
"  Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
" successful, or 0 if channel is not TDD-capable.\n"

Definition at line 2329 of file res_agi.c.

char usage_verbose[] [static]

Initial value:

" Usage: VERBOSE <message> <level>\n"
"  Sends <message> to the console via verbose message system.\n"
" <level> is the the verbose level (1-4)\n"
" Always returns 1.\n"

Definition at line 2287 of file res_agi.c.

char usage_waitfordigit[] [static]

Definition at line 2300 of file res_agi.c.


Generated on Thu Oct 11 06:49:35 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6