Asterisk - The Open Source Telephony Project  21.4.1
Data Structures | Macros | Enumerations | Functions | Variables
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/term.h"
#include "asterisk/xmldoc.h"
#include "asterisk/srv.h"
#include "asterisk/test.h"
#include "asterisk/netsock2.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_message_router.h"
#include "asterisk/format_cache.h"
#include "asterisk/agi.h"

Go to the source code of this file.

Data Structures

struct  agi_cmd
 
struct  agi_commands
 

Macros

#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 ASYNC_AGI_BREAK   3
 
#define MAX_AGI_CONNECT   2000
 
#define MAX_ARGS   128
 
#define MAX_CMD_LEN   80
 
#define SRV_PREFIX   "_agi._tcp."
 
#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 __init_agi_buf (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. More...
 
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 struct ast_manager_event_blobagi_async_end_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobagi_async_exec_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobagi_async_start_to_ami (struct stasis_message *message)
 
static struct ast_manager_event_blobagi_channel_to_ami (const char *type, struct stasis_message *message)
 
static void agi_destroy_commands_cb (void *data)
 
static int agi_exec (struct ast_channel *chan, const char *data)
 
static struct ast_manager_event_blobagi_exec_end_to_ami (struct stasis_message *message)
 
static int agi_exec_full (struct ast_channel *chan, const char *data, int enhanced, int dead)
 
static struct ast_manager_event_blobagi_exec_start_to_ami (struct stasis_message *message)
 
static enum agi_result agi_handle_command (struct ast_channel *chan, AGI *agi, char *buf, int dead)
 
int AST_OPTIONAL_API_NAME() ast_agi_register (struct ast_module *mod, agi_command *cmd)
 
int AST_OPTIONAL_API_NAME() ast_agi_register_multiple (struct ast_module *mod, struct agi_command *cmd, unsigned int len)
 
int AST_OPTIONAL_API_NAME() ast_agi_send (int fd, struct ast_channel *chan, char *fmt,...)
 
int AST_OPTIONAL_API_NAME() ast_agi_unregister (agi_command *cmd)
 
int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple (struct agi_command *cmd, unsigned int len)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static enum agi_result async_agi_read_frame (struct ast_channel *chan)
 
static int deadagi_exec (struct ast_channel *chan, const char *data)
 
static int eagi_exec (struct ast_channel *chan, const char *data)
 
static agi_commandfind_command (const char *const cmds[], int exact)
 
static void free_agi_cmd (struct agi_cmd *cmd)
 
static int get_agi_cmd (struct ast_channel *chan, struct agi_cmd **cmd)
 Retrieve the list head to the requested channel's AGI datastore. More...
 
static int handle_answer (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_asyncagi_break (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_autohangup (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_channelstatus (struct ast_channel *chan, AGI *agi, int argc, const char *const 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. More...
 
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_connection (const char *agiurl, const struct ast_sockaddr addr, const int netsockfd)
 
static int handle_controlstreamfile (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_dbdel (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_dbdeltree (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_dbget (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_dbput (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_exec (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_getdata (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_getoption (struct ast_channel *chan, AGI *agi, int argc, const char *const 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, const char *const argv[])
 
static int handle_getvariablefull (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_hangup (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_noop (struct ast_channel *chan, AGI *agi, int arg, const char *const argv[])
 
static int handle_recordfile (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_recvchar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_recvtext (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_sayalpha (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_saydate (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_saydatetime (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_saydigits (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_saynumber (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 Say number in various language syntaxes.
 
static int handle_sayphonetic (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_saytime (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_sendimage (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_sendtext (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_setcallerid (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_setcontext (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_setextension (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_setmusic (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_setpriority (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_setvariable (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_speechactivategrammar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_speechcreate (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_speechdeactivategrammar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_speechdestroy (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_speechloadgrammar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_speechrecognize (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_speechset (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_speechunloadgrammar (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_streamfile (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_tddmode (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_verbose (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static int handle_waitfordigit (struct ast_channel *chan, AGI *agi, int argc, const char *const argv[])
 
static char * help_workhorse (int fd, const char *const match[])
 
static enum agi_result launch_asyncagi (struct ast_channel *chan, int argc, char *argv[], int *efd)
 
static enum agi_result launch_ha_netscript (char *agiurl, char *argv[], int *fds)
 
static enum agi_result launch_netscript (char *agiurl, char *argv[], int *fds)
 
static enum agi_result launch_script (struct ast_channel *chan, char *script, int argc, char *argv[], int *fds, int *efd, int *opid)
 
static int load_module (void)
 
static int parse_args (char *s, int *max, const char *argv[])
 
static void publish_async_exec_end (struct ast_channel *chan, int command_id, const char *command, int result_code, const char *result)
 
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)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (agi_exec_start_type,.to_ami=agi_exec_start_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (agi_exec_end_type,.to_ami=agi_exec_end_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (agi_async_start_type,.to_ami=agi_async_start_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (agi_async_exec_type,.to_ami=agi_async_exec_to_ami,)
 
 STASIS_MESSAGE_TYPE_DEFN_LOCAL (agi_async_end_type,.to_ami=agi_async_end_to_ami,)
 
static int unload_module (void)
 
static void write_html_escaped (FILE *htmlfile, char *str)
 Convert string to use HTML escaped characters. More...
 
static int write_htmldump (const char *filename)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .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 = "da6642af068ee5e6490c5b1d2cc1d238" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_speech", }
 
static struct ast_threadstorage agi_buf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_agi_buf , .custom_init = NULL , }
 
static struct agi_commands agi_commands = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static const struct ast_datastore_info agi_commands_datastore_info
 
static int agidebug = 0
 
static char * app = "AGI"
 
static const 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 * eapp = "EAGI"
 

Detailed Description

AGI - the Asterisk Gateway Interface.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file res_agi.c.

Macro Definition Documentation

#define ASYNC_AGI_BREAK   3

Special return code for "asyncagi break" command.

Definition at line 1405 of file res_agi.c.

Function Documentation

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
mIt 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
0on success or incorrect use
1on failure to add the command ( most likely because the channel is not in Async AGI loop )

Definition at line 1704 of file res_agi.c.

References ast_channel_get_by_name(), ast_channel_unref, astman_get_header(), astman_send_ack(), and astman_send_error().

1705 {
1706  const char *channel = astman_get_header(m, "Channel");
1707  const char *cmdbuff = astman_get_header(m, "Command");
1708  const char *cmdid = astman_get_header(m, "CommandID");
1709  struct ast_channel *chan;
1710  char buf[256];
1711 
1712  if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
1713  astman_send_error(s, m, "Both, Channel and Command are *required*");
1714  return 0;
1715  }
1716 
1717  if (!(chan = ast_channel_get_by_name(channel))) {
1718  snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
1719  astman_send_error(s, m, buf);
1720  return 0;
1721  }
1722 
1723  ast_channel_lock(chan);
1724 
1725  if (add_agi_cmd(chan, cmdbuff, cmdid)) {
1726  snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", ast_channel_name(chan));
1727  astman_send_error(s, m, buf);
1728  ast_channel_unlock(chan);
1729  chan = ast_channel_unref(chan);
1730  return 0;
1731  }
1732 
1733  ast_channel_unlock(chan);
1734  chan = ast_channel_unref(chan);
1735 
1736  astman_send_ack(s, m, "Added AGI command to queue");
1737 
1738  return 0;
1739 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3421
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
static int get_agi_cmd ( struct ast_channel chan,
struct agi_cmd **  cmd 
)
static

Retrieve the list head to the requested channel's AGI datastore.

Parameters
chanChannel datastore is requested for
cmdPointer to the struct pointer which will reference the head of the agi command list.
Return values
0if the datastore was valid and the list head was retrieved appropriately (even if it's NULL and the list is empty)
-1if the datastore could not be retrieved causing an error

Definition at line 1553 of file res_agi.c.

References ast_channel_datastore_find(), AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, and ast_datastore::data.

1554 {
1555  struct ast_datastore *store;
1557 
1558  ast_channel_lock(chan);
1559  store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
1560  ast_channel_unlock(chan);
1561  if (!store) {
1562  ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
1563  ast_channel_name(chan));
1564  *cmd = NULL;
1565  return -1;
1566  }
1567  agi_commands = store->data;
1571  return 0;
1572 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
Structure for a data store object.
Definition: datastore.h:64
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
void * data
Definition: datastore.h:66
Definition: search.h:40
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_SUCCESSon success
NULLwhen init or tab completion is used

Definition at line 1652 of file res_agi.c.

References ast_channel_get_by_name(), ast_channel_unref, ast_complete_channels(), ast_debug, ast_cli_entry::command, and ast_cli_entry::usage.

1653 {
1654  struct ast_channel *chan;
1655  switch (cmd) {
1656  case CLI_INIT:
1657  e->command = "agi exec";
1658  e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
1659  " Add AGI command to the execute queue of the specified channel in Async AGI\n";
1660  return NULL;
1661  case CLI_GENERATE:
1662  if (a->pos == 2)
1663  return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1664  return NULL;
1665  }
1666 
1667  if (a->argc < 4) {
1668  return CLI_SHOWUSAGE;
1669  }
1670 
1671  if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
1672  ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
1673  return CLI_FAILURE;
1674  }
1675 
1676  ast_channel_lock(chan);
1677 
1678  if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
1679  ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", ast_channel_name(chan));
1680  ast_channel_unlock(chan);
1681  chan = ast_channel_unref(chan);
1682  return CLI_FAILURE;
1683  }
1684 
1685  ast_debug(1, "Added AGI command to channel %s queue\n", ast_channel_name(chan));
1686 
1687  ast_channel_unlock(chan);
1688  chan = ast_channel_unref(chan);
1689 
1690  return CLI_SUCCESS;
1691 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#define ast_debug(level,...)
Log a DEBUG message.
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1865
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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

Running in an interception routine is like DeadAGI mode. No touchy the channel frames.

Definition at line 4144 of file res_agi.c.

References ast_channel_get_intercept_mode(), ast_check_hangup(), ast_debug, ast_false(), AST_FRAME_VOICE, ast_read(), ast_speech_destroy(), ast_true(), ast_waitfor_nandfds(), agi_state::audio, agi_state::ctrl, ast_frame::data, ast_frame::datalen, agi_state::fast, agi_state::fd, ast_frame::frametype, pbx_builtin_getvar_helper(), and agi_state::speech.

4145 {
4146  struct ast_channel *c;
4147  int outfd;
4148  int ms;
4149  int needhup = 0;
4150  enum agi_result returnstatus = AGI_RESULT_SUCCESS;
4151  struct ast_frame *f;
4152  char buf[AGI_BUF_LEN];
4153  char *res = NULL;
4154  FILE *readf;
4155  /* how many times we'll retry if ast_waitfor_nandfs will return without either
4156  channel or file descriptor in case select is interrupted by a system call (EINTR) */
4157  int retry = AGI_NANDFS_RETRY;
4158  int send_sighup;
4159  const char *sighup_str;
4160  const char *exit_on_hangup_str;
4161  int exit_on_hangup;
4162  /*! Running in an interception routine is like DeadAGI mode. No touchy the channel frames. */
4163  int in_intercept = ast_channel_get_intercept_mode();
4164 
4165  ast_channel_lock(chan);
4166  sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
4167  send_sighup = !ast_false(sighup_str);
4168  exit_on_hangup_str = pbx_builtin_getvar_helper(chan, "AGIEXITONHANGUP");
4169  exit_on_hangup = ast_true(exit_on_hangup_str);
4170  ast_channel_unlock(chan);
4171 
4172  if (!(readf = fdopen(agi->ctrl, "r"))) {
4173  ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
4174  if (send_sighup && pid > -1)
4175  kill(pid, SIGHUP);
4176  close(agi->ctrl);
4177  return AGI_RESULT_FAILURE;
4178  }
4179 
4180  setlinebuf(readf);
4181  setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
4182  for (;;) {
4183  if (needhup) {
4184  needhup = 0;
4185  dead = 1;
4186  if (send_sighup) {
4187  if (pid > -1) {
4188  kill(pid, SIGHUP);
4189  } else if (agi->fast) {
4190  ast_agi_send(agi->fd, chan, "HANGUP\n");
4191  }
4192  }
4193  if (exit_on_hangup) {
4194  break;
4195  }
4196  }
4197  ms = -1;
4198  if (dead || in_intercept) {
4199  c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
4200  } else if (!ast_check_hangup(chan)) {
4201  c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
4202  } else {
4203  /*
4204  * Read the channel control queue until it is dry so we can
4205  * switch to dead mode.
4206  */
4207  c = chan;
4208  }
4209  if (c) {
4210  retry = AGI_NANDFS_RETRY;
4211  /* Idle the channel until we get a command */
4212  f = ast_read(c);
4213  if (!f) {
4214  ast_debug(1, "%s hungup\n", ast_channel_name(chan));
4215  needhup = 1;
4216  if (!returnstatus) {
4217  returnstatus = AGI_RESULT_HANGUP;
4218  }
4219  } else {
4220  /* If it's voice, write it to the audio pipe */
4221  if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
4222  /* Write, ignoring errors */
4223  if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
4224  }
4225  }
4226  ast_frfree(f);
4227  }
4228  } else if (outfd > -1) {
4229  size_t len = sizeof(buf);
4230  size_t buflen = 0;
4231  enum agi_result cmd_status;
4232 
4233  retry = AGI_NANDFS_RETRY;
4234  buf[0] = '\0';
4235 
4236  while (len > 1) {
4237  res = fgets(buf + buflen, len, readf);
4238  if (feof(readf))
4239  break;
4240  if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
4241  break;
4242  if (res != NULL && !agi->fast)
4243  break;
4244  buflen = strlen(buf);
4245  if (buflen && buf[buflen - 1] == '\n')
4246  break;
4247  len = sizeof(buf) - buflen;
4248  if (agidebug)
4249  ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
4250  }
4251 
4252  if (!buf[0]) {
4253  /* Program terminated */
4254  ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", ast_channel_name(chan), request, returnstatus);
4255  if (pid > 0)
4256  waitpid(pid, status, 0);
4257  /* No need to kill the pid anymore, since they closed us */
4258  pid = -1;
4259  break;
4260  }
4261 
4262  /* Special case for inability to execute child process */
4263  if (*buf && strncasecmp(buf, "failure", 7) == 0) {
4264  returnstatus = AGI_RESULT_FAILURE;
4265  break;
4266  }
4267 
4268  /* get rid of trailing newline, if any */
4269  buflen = strlen(buf);
4270  if (buflen && buf[buflen - 1] == '\n') {
4271  buf[buflen - 1] = '\0';
4272  }
4273 
4274  if (agidebug)
4275  ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf);
4276  cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept);
4277  switch (cmd_status) {
4278  case AGI_RESULT_FAILURE:
4279  if (dead || in_intercept || !ast_check_hangup(chan)) {
4280  /* The failure was not because of a hangup. */
4281  returnstatus = AGI_RESULT_FAILURE;
4282  }
4283  break;
4284  default:
4285  break;
4286  }
4287  } else {
4288  if (--retry <= 0) {
4289  ast_log(LOG_WARNING, "No channel, no fd?\n");
4290  returnstatus = AGI_RESULT_FAILURE;
4291  break;
4292  }
4293  }
4294  }
4295 
4296  if (agi->speech) {
4297  ast_speech_destroy(agi->speech);
4298  }
4299  /* Notify process */
4300  if (send_sighup) {
4301  if (pid > -1) {
4302  if (kill(pid, SIGHUP)) {
4303  ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
4304  } else { /* Give the process a chance to die */
4305  usleep(1);
4306  }
4307  waitpid(pid, status, WNOHANG);
4308  } else if (agi->fast) {
4309  ast_agi_send(agi->fd, chan, "HANGUP\n");
4310  }
4311  }
4312  fclose(readf);
4313  return returnstatus;
4314 }
Main Channel structure associated with a channel.
int ast_speech_destroy(struct ast_speech *speech)
Destroy a speech structure.
Definition: res_speech.c:251
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
int ctrl
Definition: agi.h:37
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition: channel.c:2988
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: utils.c:2199
int fd
Definition: agi.h:35
struct ast_speech * speech
Definition: agi.h:39
int audio
Definition: agi.h:36
union ast_frame::@224 data
unsigned int fast
Definition: agi.h:38
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: utils.c:2216
Data structure associated with a single frame of data.
int ast_channel_get_intercept_mode(void)
Am I currently running an intercept dialplan routine.
Definition: channel.c:10333
enum ast_frame_type frametype
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 4422 of file res_agi.c.

4423 {
4424  char *cur = str;
4425 
4426  while(*cur) {
4427  switch (*cur) {
4428  case '<':
4429  fprintf(htmlfile, "%s", "&lt;");
4430  break;
4431  case '>':
4432  fprintf(htmlfile, "%s", "&gt;");
4433  break;
4434  case '&':
4435  fprintf(htmlfile, "%s", "&amp;");
4436  break;
4437  case '"':
4438  fprintf(htmlfile, "%s", "&quot;");
4439  break;
4440  default:
4441  fprintf(htmlfile, "%c", *cur);
4442  break;
4443  }
4444  cur++;
4445  }
4446 
4447  return;
4448 }

Variable Documentation

const struct ast_datastore_info agi_commands_datastore_info
static
Initial value:
= {
.type = "AsyncAGI",
.destroy = agi_destroy_commands_cb
}

Definition at line 1539 of file res_agi.c.