Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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"
Include dependency graph for res_agi.c:

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)
 Registers an AGI command. More...
 
int AST_OPTIONAL_API_NAME() 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. More...
 
int AST_OPTIONAL_API_NAME() ast_agi_send (int fd, struct ast_channel *chan, char *fmt,...)
 Sends a string of text to an application connected via AGI. More...
 
int AST_OPTIONAL_API_NAME() ast_agi_unregister (agi_command *cmd)
 Unregisters an AGI command. More...
 
int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple (struct agi_command *cmd, unsigned int len)
 Unregisters a group of AGI commands, provided as an array of struct agi_command entries. More...
 
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 More...
 
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. More...
 
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, int *safe_fork_called)
 
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_async_end_type,.to_ami=agi_async_end_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_start_type,.to_ami=agi_async_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_exec_start_type,.to_ami=agi_exec_start_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 = AST_BUILDOPT_SUM, .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. More...
 
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

◆ AGI_BUF_INITSIZE

#define AGI_BUF_INITSIZE   256

Definition at line 1644 of file res_agi.c.

◆ AGI_BUF_LEN

#define AGI_BUF_LEN   2048

Definition at line 1551 of file res_agi.c.

◆ AGI_BUF_SIZE

#define AGI_BUF_SIZE   1024

◆ AGI_NANDFS_RETRY

#define AGI_NANDFS_RETRY   3

Definition at line 1550 of file res_agi.c.

◆ AGI_PORT

#define AGI_PORT   4573

Definition at line 1567 of file res_agi.c.

◆ AMI_BUF_SIZE

#define AMI_BUF_SIZE   2048

◆ AST_API_MODULE

#define AST_API_MODULE

Definition at line 71 of file res_agi.c.

◆ ASYNC_AGI_BREAK

#define ASYNC_AGI_BREAK   3

Special return code for "asyncagi break" command.

Definition at line 1570 of file res_agi.c.

◆ MAX_AGI_CONNECT

#define MAX_AGI_CONNECT   2000

Definition at line 1565 of file res_agi.c.

◆ MAX_ARGS

#define MAX_ARGS   128

Definition at line 1548 of file res_agi.c.

◆ MAX_CMD_LEN

#define MAX_CMD_LEN   80

Definition at line 1549 of file res_agi.c.

◆ SRV_PREFIX

#define SRV_PREFIX   "_agi._tcp."

Definition at line 1552 of file res_agi.c.

◆ TONE_BLOCK_SIZE

#define TONE_BLOCK_SIZE   200

Definition at line 1562 of file res_agi.c.

Enumeration Type Documentation

◆ agi_result

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 1572 of file res_agi.c.

1572 {
1573 AGI_RESULT_FAILURE = -1,
1579};
@ AGI_RESULT_HANGUP
Definition: res_agi.c:1578
@ AGI_RESULT_SUCCESS
Definition: res_agi.c:1574
@ AGI_RESULT_FAILURE
Definition: res_agi.c:1573
@ AGI_RESULT_SUCCESS_ASYNC
Definition: res_agi.c:1576
@ AGI_RESULT_SUCCESS_FAST
Definition: res_agi.c:1575
@ AGI_RESULT_NOTFOUND
Definition: res_agi.c:1577

Function Documentation

◆ __init_agi_buf()

static void __init_agi_buf ( void  )
static

Definition at line 1643 of file res_agi.c.

1647{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 4923 of file res_agi.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 4923 of file res_agi.c.

◆ action_add_agi_cmd()

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
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 1869 of file res_agi.c.

1870{
1871 const char *channel = astman_get_header(m, "Channel");
1872 const char *cmdbuff = astman_get_header(m, "Command");
1873 const char *cmdid = astman_get_header(m, "CommandID");
1874 struct ast_channel *chan;
1875 char buf[256];
1876
1877 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
1878 astman_send_error(s, m, "Both, Channel and Command are *required*");
1879 return 0;
1880 }
1881
1882 if (!(chan = ast_channel_get_by_name(channel))) {
1883 snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
1884 astman_send_error(s, m, buf);
1885 return 0;
1886 }
1887
1888 ast_channel_lock(chan);
1889
1890 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
1891 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", ast_channel_name(chan));
1892 astman_send_error(s, m, buf);
1893 ast_channel_unlock(chan);
1894 chan = ast_channel_unref(chan);
1895 return 0;
1896 }
1897
1898 ast_channel_unlock(chan);
1899 chan = ast_channel_unref(chan);
1900
1901 astman_send_ack(s, m, "Added AGI command to queue");
1902
1903 return 0;
1904}
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2972
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition: channel.c:1397
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3008
#define ast_channel_unlock(chan)
Definition: channel.h:2973
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1986
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2018
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
Definition: res_agi.c:1740
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Main Channel structure associated with a channel.

References add_agi_cmd(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), and buf.

Referenced by load_module().

◆ add_agi_cmd()

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

Definition at line 1740 of file res_agi.c.

1741{
1742 struct ast_datastore *store;
1743 struct agi_cmd *cmd;
1745
1747 if (!store) {
1748 ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", ast_channel_name(chan));
1749 return -1;
1750 }
1751 agi_commands = store->data;
1752 cmd = ast_calloc(1, sizeof(*cmd));
1753 if (!cmd) {
1754 return -1;
1755 }
1756 cmd->cmd_buffer = ast_strdup(cmd_buff);
1757 if (!cmd->cmd_buffer) {
1758 ast_free(cmd);
1759 return -1;
1760 }
1761 cmd->cmd_id = ast_strdup(cmd_id);
1762 if (!cmd->cmd_id) {
1763 ast_free(cmd->cmd_buffer);
1764 ast_free(cmd);
1765 return -1;
1766 }
1770 return 0;
1771}
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
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:2368
#define LOG_WARNING
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
static struct agi_commands agi_commands
static const struct ast_datastore_info agi_commands_datastore_info
Definition: res_agi.c:1704
#define NULL
Definition: resample.c:96
char * cmd_buffer
Definition: res_agi.c:1677
char * cmd_id
Definition: res_agi.c:1678
struct agi_cmd::@425 entry
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66

References agi_commands, agi_commands_datastore_info, ast_calloc, ast_channel_datastore_find(), ast_channel_name(), 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 NULL.

Referenced by action_add_agi_cmd(), and handle_cli_agi_add_cmd().

◆ add_to_agi()

static int add_to_agi ( struct ast_channel chan)
static

Definition at line 1773 of file res_agi.c.

1774{
1775 struct ast_datastore *datastore;
1776 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
1777
1778 /* check if already on AGI */
1779 ast_channel_lock(chan);
1781 ast_channel_unlock(chan);
1782 if (datastore) {
1783 /* we already have an AGI datastore, let's just
1784 return success */
1785 return 0;
1786 }
1787
1788 /* the channel has never been on Async AGI,
1789 let's allocate it's datastore */
1791 if (!datastore) {
1792 return -1;
1793 }
1794 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
1795 if (!agi_cmds_list) {
1796 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
1797 ast_datastore_free(datastore);
1798 return -1;
1799 }
1800 datastore->data = agi_cmds_list;
1801 AST_LIST_HEAD_INIT(agi_cmds_list);
1802 ast_channel_lock(chan);
1803 ast_channel_datastore_add(chan, datastore);
1804 ast_channel_unlock(chan);
1805 return 0;
1806}
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2354
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define LOG_ERROR
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626

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, LOG_ERROR, and NULL.

Referenced by launch_asyncagi().

◆ agi_async_end_to_ami()

static struct ast_manager_event_blob * agi_async_end_to_ami ( struct stasis_message message)
static

Definition at line 1620 of file res_agi.c.

1621{
1622 return agi_channel_to_ami("AsyncAGIEnd", message);
1623}
static struct ast_manager_event_blob * agi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: res_agi.c:1581

References agi_channel_to_ami().

◆ agi_async_exec_to_ami()

static struct ast_manager_event_blob * agi_async_exec_to_ami ( struct stasis_message message)
static

Definition at line 1615 of file res_agi.c.

1616{
1617 return agi_channel_to_ami("AsyncAGIExec", message);
1618}

References agi_channel_to_ami().

◆ agi_async_start_to_ami()

static struct ast_manager_event_blob * agi_async_start_to_ami ( struct stasis_message message)
static

Definition at line 1610 of file res_agi.c.

1611{
1612 return agi_channel_to_ami("AsyncAGIStart", message);
1613}

References agi_channel_to_ami().

◆ agi_channel_to_ami()

static struct ast_manager_event_blob * agi_channel_to_ami ( const char *  type,
struct stasis_message message 
)
static

Definition at line 1581 of file res_agi.c.

1582{
1584 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
1585 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1586
1587 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1588 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
1589 if (!channel_string || !event_string) {
1590 return NULL;
1591 }
1592
1594 "%s"
1595 "%s",
1596 ast_str_buffer(channel_string),
1597 ast_str_buffer(event_string));
1598}
static const char type[]
Definition: chan_ooh323.c:109
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:555
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10237
#define EVENT_FLAG_AGI
Definition: manager.h:88
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
Support for dynamic strings.
Definition: strings.h:623
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References ast_free, ast_manager_build_channel_state_string(), ast_manager_event_blob_create(), ast_manager_str_from_json_object(), ast_str_buffer(), ast_channel_blob::blob, EVENT_FLAG_AGI, NULL, RAII_VAR, ast_channel_blob::snapshot, stasis_message_data(), and type.

Referenced by agi_async_end_to_ami(), agi_async_exec_to_ami(), agi_async_start_to_ami(), agi_exec_end_to_ami(), and agi_exec_start_to_ami().

◆ agi_destroy_commands_cb()

static void agi_destroy_commands_cb ( void *  data)
static

Definition at line 1690 of file res_agi.c.

1691{
1692 struct agi_cmd *cmd;
1693 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
1694 AST_LIST_LOCK(chan_cmds);
1695 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
1696 free_agi_cmd(cmd);
1697 }
1698 AST_LIST_UNLOCK(chan_cmds);
1699 AST_LIST_HEAD_DESTROY(chan_cmds);
1700 ast_free(chan_cmds);
1701}
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
static void free_agi_cmd(struct agi_cmd *cmd)
Definition: res_agi.c:1682

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().

◆ agi_exec()

static int agi_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 4769 of file res_agi.c.

4770{
4771 if (!ast_check_hangup(chan))
4772 return agi_exec_full(chan, data, 0, 0);
4773 else
4774 return agi_exec_full(chan, data, 0, 1);
4775}
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:444
static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
Definition: res_agi.c:4699

References agi_exec_full(), and ast_check_hangup().

Referenced by deadagi_exec(), and load_module().

◆ agi_exec_end_to_ami()

static struct ast_manager_event_blob * agi_exec_end_to_ami ( struct stasis_message message)
static

Definition at line 1605 of file res_agi.c.

1606{
1607 return agi_channel_to_ami("AGIExecEnd", message);
1608}

References agi_channel_to_ami().

◆ agi_exec_full()

static int agi_exec_full ( struct ast_channel chan,
const char *  data,
int  enhanced,
int  dead 
)
static

Definition at line 4699 of file res_agi.c.

4700{
4701 enum agi_result res;
4702 char *buf;
4703 int fds[2], efd = -1, pid = -1;
4704 int safe_fork_called = 0;
4706 AST_APP_ARG(arg)[MAX_ARGS];
4707 );
4708 AGI agi;
4709
4710 if (ast_strlen_zero(data)) {
4711 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
4712 return -1;
4713 }
4714 if (dead)
4715 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
4716 memset(&agi, 0, sizeof(agi));
4717 buf = ast_strdupa(data);
4719 args.arg[args.argc] = NULL;
4720#if 0
4721 /* Answer if need be */
4722 if (chan->_state != AST_STATE_UP) {
4723 if (ast_answer(chan))
4724 return -1;
4725 }
4726#endif
4727 res = launch_script(chan, args.arg[0], args.argc, args.arg, fds, enhanced ? &efd : NULL, &pid, &safe_fork_called);
4728 /* Async AGI do not require run_agi(), so just proceed if normal AGI
4729 or Fast AGI are setup with success. */
4730 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
4731 int status = 0;
4732 agi.fd = fds[1];
4733 agi.ctrl = fds[0];
4734 agi.audio = efd;
4735 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
4736 res = run_agi(chan, args.arg[0], &agi, pid, &status, dead, args.argc, args.arg);
4737 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
4738 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
4739 res = AGI_RESULT_FAILURE;
4740 if (fds[1] != fds[0])
4741 close(fds[1]);
4742 if (efd > -1)
4743 close(efd);
4744 }
4745 if (safe_fork_called) {
4747 }
4748
4749 switch (res) {
4750 case AGI_RESULT_SUCCESS:
4753 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
4754 break;
4755 case AGI_RESULT_FAILURE:
4756 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
4757 break;
4759 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
4760 break;
4761 case AGI_RESULT_HANGUP:
4762 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
4763 return -1;
4764 }
4765
4766 return 0;
4767}
jack_status_t status
Definition: app_jack.c:149
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2774
@ AST_STATE_UP
Definition: channelstate.h:42
#define AST_APP_ARG(name)
Define an application argument.
void ast_safe_fork_cleanup(void)
Common routine to cleanup after fork'ed process is complete (if reaping was stopped)
Definition: main/app.c:3268
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define ast_debug(level,...)
Log a DEBUG message.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define MAX_ARGS
Definition: res_agi.c:1548
static enum agi_result launch_script(struct ast_channel *chan, char *script, int argc, char *argv[], int *fds, int *efd, int *opid, int *safe_fork_called)
Definition: res_agi.c:2360
static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
Definition: res_agi.c:4323
agi_result
Definition: res_agi.c:1572
Definition: agi.h:34
const char * args

References AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_NOTFOUND, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, AGI_RESULT_SUCCESS_FAST, args, ast_answer(), AST_APP_ARG, ast_debug, AST_DECLARE_APP_ARGS, ast_log, ast_safe_fork_cleanup(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), buf, agi_command::dead, launch_script(), LOG_WARNING, MAX_ARGS, NULL, pbx_builtin_setvar_helper(), run_agi(), and status.

Referenced by agi_exec(), eagi_exec(), and handle_exec().

◆ agi_exec_start_to_ami()

static struct ast_manager_event_blob * agi_exec_start_to_ami ( struct stasis_message message)
static

Definition at line 1600 of file res_agi.c.

1601{
1602 return agi_channel_to_ami("AGIExecStart", message);
1603}

References agi_channel_to_ami().

◆ agi_handle_command()

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

Definition at line 4232 of file res_agi.c.

4233{
4234 const char *argv[MAX_ARGS] = {0};
4235 int argc = MAX_ARGS;
4236 int res;
4237 agi_command *c;
4238 char *ami_cmd = ast_strdupa(buf);
4239 const char *ami_res;
4240 int command_id = ast_random();
4241 int resultcode = 0;
4242 RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
4243
4244 startblob = ast_json_pack("{s: i, s: s}",
4245 "CommandId", command_id,
4246 "Command", ami_cmd);
4247 ast_channel_publish_cached_blob(chan, agi_exec_start_type(), startblob);
4248
4249 parse_args(buf, &argc, argv);
4250 c = find_command(argv, 0);
4251 if (!c || !ast_module_running_ref(c->mod)) {
4252 ami_res = "Invalid or unknown command";
4253 resultcode = 510;
4254
4255 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4256
4257 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4258
4259 return AGI_RESULT_SUCCESS;
4260 }
4261
4262 if (!dead || (dead && c->dead)) {
4263 res = c->handler(chan, agi, argc, argv);
4264 switch (res) {
4265 case RESULT_SHOWUSAGE:
4266 ami_res = "Usage";
4267 resultcode = 520;
4268
4269 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4270
4271 if (ast_strlen_zero(c->usage)) {
4272 ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n");
4273 } else {
4274 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
4275 ast_agi_send(agi->fd, chan, "%s\n", c->usage);
4276 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
4277 }
4278
4279 break;
4280 case RESULT_FAILURE:
4281 ami_res = "Failure";
4282 resultcode = -1;
4283
4284 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4285
4286 /* The RESULT_FAILURE code is usually because the channel hungup. */
4287 return AGI_RESULT_FAILURE;
4288 case ASYNC_AGI_BREAK:
4289 ami_res = "Success";
4290 resultcode = 200;
4291
4292 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4293
4295 case RESULT_SUCCESS:
4296 ami_res = "Success";
4297 resultcode = 200;
4298
4299 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4300
4301 break;
4302 default:
4303 ami_res = "Unknown Result";
4304 resultcode = 200;
4305
4306 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4307
4308 break;
4309 }
4310 } else {
4311 ami_res = "Command Not Permitted on a dead channel or intercept routine";
4312 resultcode = 511;
4313
4314 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4315
4316 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4317 }
4318 ast_module_unref(c->mod);
4319
4320 return AGI_RESULT_SUCCESS;
4321}
#define RESULT_SHOWUSAGE
Definition: cli.h:41
#define RESULT_SUCCESS
Definition: cli.h:40
#define RESULT_FAILURE
Definition: cli.h:42
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition: module.h:469
static int parse_args(char *s, int *max, const char *argv[])
Definition: res_agi.c:4158
static agi_command * find_command(const char *const cmds[], int exact)
Definition: res_agi.c:4120
#define ASYNC_AGI_BREAK
Definition: res_agi.c:1570
static void publish_async_exec_end(struct ast_channel *chan, int command_id, const char *command, int result_code, const char *result)
Definition: res_agi.c:4221
int AST_OPTIONAL_API_NAME() ast_agi_send(int fd, struct ast_channel *chan, char *fmt,...)
Sends a string of text to an application connected via AGI.
Definition: res_agi.c:1646
int fd
Definition: agi.h:35
Abstract JSON element (object, array, string, int, ...).
static struct test_val c
long int ast_random(void)
Definition: utils.c:2312

References AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, ast_agi_send(), ast_channel_publish_cached_blob(), ast_json_pack(), ast_json_unref(), ast_module_running_ref, ast_module_unref, ast_random(), ast_strdupa, ast_strlen_zero(), ASYNC_AGI_BREAK, buf, c, agi_command::dead, agi_state::fd, find_command(), MAX_ARGS, NULL, parse_args(), publish_async_exec_end(), RAII_VAR, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

Referenced by launch_asyncagi(), and run_agi().

◆ ast_agi_register()

int AST_OPTIONAL_API_NAME() ast_agi_register ( struct ast_module mod,
agi_command cmd 
)

Registers an AGI command.

Parameters
modPointer to the module_info structure for the module that is registering the command
cmdPointer to the descriptor for the command
Return values
1on success
0the command is already registered
AST_OPTIONAL_API_UNAVAILABLEthe module is not loaded.

Definition at line 3988 of file res_agi.c.

3989{
3990 char fullcmd[MAX_CMD_LEN];
3991
3992 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
3993
3994 if (!find_command(cmd->cmda, 1)) {
3995 *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
3996 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
3997#ifdef AST_XML_DOCS
3998 *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
3999 *((char **) &cmd->since) = ast_xmldoc_build_since("agi", fullcmd, NULL);
4000 *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
4001 *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
4002 *((char **) &cmd->arguments) = ast_xmldoc_build_arguments("agi", fullcmd, NULL);
4003 *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
4004 *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
4005#endif
4006#ifndef HAVE_NULLSAFE_PRINTF
4007 if (!cmd->summary) {
4008 *((char **) &cmd->summary) = ast_strdup("");
4009 }
4010 if (!cmd->usage) {
4011 *((char **) &cmd->usage) = ast_strdup("");
4012 }
4013 if (!cmd->syntax) {
4014 *((char **) &cmd->syntax) = ast_strdup("");
4015 }
4016 if (!cmd->seealso) {
4017 *((char **) &cmd->seealso) = ast_strdup("");
4018 }
4019#endif
4020 }
4021
4022 cmd->mod = mod;
4026 ast_verb(5, "AGI Command '%s' registered\n",fullcmd);
4027 return 1;
4028 } else {
4029 ast_log(LOG_WARNING, "Command already registered!\n");
4030 return 0;
4031 }
4032}
#define ast_verb(level,...)
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define MAX_CMD_LEN
Definition: res_agi.c:1549
#define ast_join(s, len, w)
Join an array of strings into a single string.
Definition: strings.h:520
const char *const since
Definition: agi.h:64
const char *const summary
Definition: agi.h:48
const char *const arguments
Definition: agi.h:66
struct ast_module * mod
Definition: agi.h:60
enum ast_doc_src docsrc
Definition: agi.h:58
const char *const usage
Definition: agi.h:50
const char *const seealso
Definition: agi.h:56
const char *const syntax
Definition: agi.h:54
const char *const cmda[AST_MAX_CMD_LEN]
Definition: agi.h:43
char * ast_xmldoc_build_description(const char *type, const char *name, const char *module)
Generate description documentation from XML.
Definition: xmldoc.c:2356
char * ast_xmldoc_build_syntax(const char *type, const char *name, const char *module)
Get the syntax for a specified application or function.
Definition: xmldoc.c:1252
char * ast_xmldoc_build_arguments(const char *type, const char *name, const char *module)
Generate the [arguments] tag based on type of node ('application', 'function' or 'agi') and name.
Definition: xmldoc.c:2169
char * ast_xmldoc_build_synopsis(const char *type, const char *name, const char *module)
Generate synopsis documentation from XML.
Definition: xmldoc.c:2333
char * ast_xmldoc_build_since(const char *type, const char *name, const char *module)
Parse the <since> node content.
Definition: xmldoc.c:1787
ast_doc_src
From where the documentation come from, this structure is useful for use it inside application/functi...
Definition: xmldoc.h:30
@ AST_XML_DOC
Definition: xmldoc.h:31
@ AST_STATIC_DOC
Definition: xmldoc.h:32
char * ast_xmldoc_build_seealso(const char *type, const char *name, const char *module)
Parse the <see-also> node content.
Definition: xmldoc.c:1702

References ast_join, AST_LIST_INSERT_TAIL, ast_log, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, AST_STATIC_DOC, ast_strdup, ast_strlen_zero(), ast_verb, AST_XML_DOC, ast_xmldoc_build_arguments(), ast_xmldoc_build_description(), ast_xmldoc_build_seealso(), ast_xmldoc_build_since(), ast_xmldoc_build_synopsis(), ast_xmldoc_build_syntax(), find_command(), LOG_WARNING, MAX_CMD_LEN, and NULL.

Referenced by ast_agi_register_multiple(), AST_TEST_DEFINE(), and load_module().

◆ ast_agi_register_multiple()

int AST_OPTIONAL_API_NAME() 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
modPointer to the module_info structure for the module that is registering the commands
cmdPointer to the first entry in the array of command descriptors
lenLength of the array (use the ARRAY_LEN macro to determine this easily)
Returns
0 on success, -1 on failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded
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 4074 of file res_agi.c.

4075{
4076 unsigned int i, x = 0;
4077
4078 for (i = 0; i < len; i++) {
4079 if (ast_agi_register(mod, cmd + i) == 1) {
4080 x++;
4081 continue;
4082 }
4083
4084 /* registration failed, unregister everything
4085 that had been registered up to that point
4086 */
4087 for (; x > 0; x--) {
4088 /* we are intentionally ignoring the
4089 result of ast_agi_unregister() here,
4090 but it should be safe to do so since
4091 we just registered these commands and
4092 the only possible way for unregistration
4093 to fail is if the command is not
4094 registered
4095 */
4096 (void) ast_agi_unregister(cmd + x - 1);
4097 }
4098 return -1;
4099 }
4100
4101 return 0;
4102}
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int AST_OPTIONAL_API_NAME() ast_agi_unregister(agi_command *cmd)
Unregisters an AGI command.
Definition: res_agi.c:4034
int AST_OPTIONAL_API_NAME() ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition: res_agi.c:3988

References ast_agi_register(), ast_agi_unregister(), len(), and agi_command::mod.

Referenced by load_module().

◆ ast_agi_send()

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

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

Parameters
fdThe file descriptor for the AGI session (from struct agi_state)
chanPointer to an associated Asterisk channel, if any
fmtprintf-style format string
Returns
0 for success, -1 for failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded

Definition at line 1646 of file res_agi.c.

1647{
1648 int res = 0;
1649 va_list ap;
1650 struct ast_str *buf;
1651
1653 return -1;
1654
1655 va_start(ap, fmt);
1656 res = ast_str_set_va(&buf, 0, fmt, ap);
1657 va_end(ap);
1658
1659 if (res == -1) {
1660 ast_log(LOG_ERROR, "Out of memory\n");
1661 return -1;
1662 }
1663
1664 if (agidebug) {
1665 if (chan) {
1666 ast_verbose("<%s>AGI Tx >> %s", ast_channel_name(chan), ast_str_buffer(buf));
1667 } else {
1668 ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
1669 }
1670 }
1671
1673}
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
static struct ast_threadstorage agi_buf
Definition: res_agi.c:1643
static int agidebug
Definition: res_agi.c:1560
#define AGI_BUF_INITSIZE
Definition: res_agi.c:1644
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition: strings.h:1030
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
Try to write string, but wait no more than ms milliseconds before timing out.
Definition: utils.c:1771

References agi_buf, AGI_BUF_INITSIZE, agidebug, ast_carefulwrite(), ast_channel_name(), ast_log, ast_str_buffer(), ast_str_set_va(), ast_str_strlen(), ast_str_thread_get(), ast_verbose(), buf, and LOG_ERROR.

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(), run_agi(), and setup_env().

◆ ast_agi_unregister()

int AST_OPTIONAL_API_NAME() ast_agi_unregister ( agi_command cmd)

Unregisters an AGI command.

Parameters
cmdPointer to the descriptor for the command
Returns
1 on success, 0 if the command was not already registered

Definition at line 4034 of file res_agi.c.

4035{
4036 struct agi_command *e;
4037 int unregistered = 0;
4038 char fullcmd[MAX_CMD_LEN];
4039
4040 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
4041
4044 if (cmd == e) {
4046#ifdef AST_XML_DOCS
4047 if (e->docsrc == AST_XML_DOC) {
4048 ast_free((char *) e->summary);
4049 ast_free((char *) e->since);
4050 ast_free((char *) e->usage);
4051 ast_free((char *) e->syntax);
4052 ast_free((char *) e->arguments);
4053 ast_free((char *) e->seealso);
4054 *((char **) &e->summary) = NULL;
4055 *((char **) &e->since) = NULL;
4056 *((char **) &e->usage) = NULL;
4057 *((char **) &e->syntax) = NULL;
4058 *((char **) &e->arguments) = NULL;
4059 *((char **) &e->seealso) = NULL;
4060 }
4061#endif
4062 unregistered=1;
4063 break;
4064 }
4065 }
4068 if (unregistered) {
4069 ast_verb(5, "AGI Command '%s' unregistered\n",fullcmd);
4070 }
4071 return unregistered;
4072}
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
struct agi_command::@181 list

References agi_command::arguments, ast_free, ast_join, 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::docsrc, agi_command::list, MAX_CMD_LEN, NULL, agi_command::seealso, agi_command::since, agi_command::summary, agi_command::syntax, and agi_command::usage.

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

◆ ast_agi_unregister_multiple()

int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple ( struct agi_command cmd,
unsigned int  len 
)

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

Parameters
cmdPointer to the first entry in the array of command descriptors
lenLength of the array (use the ARRAY_LEN macro to determine this easily)
Returns
0 on success, -1 on failure, AST_OPTIONAL_API_UNAVAILABLE if res_agi is not loaded
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 4104 of file res_agi.c.

4105{
4106 unsigned int i;
4107 int res = 0;
4108
4109 for (i = 0; i < len; i++) {
4110 /* remember whether any of the unregistration
4111 attempts failed... there is no recourse if
4112 any of them do
4113 */
4114 res |= ast_agi_unregister(cmd + i);
4115 }
4116
4117 return res;
4118}

References ast_agi_unregister(), and len().

Referenced by unload_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 4923 of file res_agi.c.

◆ async_agi_read_frame()

static enum agi_result async_agi_read_frame ( struct ast_channel chan)
static

Definition at line 1919 of file res_agi.c.

1920{
1921 struct ast_frame *f;
1922
1923 f = ast_read(chan);
1924 if (!f) {
1925 ast_debug(3, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
1926 return AGI_RESULT_HANGUP;
1927 }
1928 if (f->frametype == AST_FRAME_CONTROL) {
1929 /*
1930 * Is there any other frame we should care about besides
1931 * AST_CONTROL_HANGUP?
1932 */
1933 switch (f->subclass.integer) {
1934 case AST_CONTROL_HANGUP:
1935 ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
1936 ast_frfree(f);
1937 return AGI_RESULT_HANGUP;
1938 default:
1939 break;
1940 }
1941 }
1942 ast_frfree(f);
1943
1944 return AGI_RESULT_SUCCESS;
1945}
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4214
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_HANGUP
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype

References AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS, ast_channel_name(), AST_CONTROL_HANGUP, ast_debug, AST_FRAME_CONTROL, ast_frfree, ast_read(), ast_frame::frametype, ast_frame_subclass::integer, and ast_frame::subclass.

Referenced by launch_asyncagi().

◆ deadagi_exec()

static int deadagi_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 4819 of file res_agi.c.

4820{
4821 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
4822 return agi_exec(chan, data);
4823}
static int agi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4769

References agi_exec(), ast_log, and LOG_WARNING.

Referenced by load_module().

◆ eagi_exec()

static int eagi_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 4777 of file res_agi.c.

4778{
4779 int res;
4780 struct ast_format *readformat;
4781 struct ast_format *requested_format = NULL;
4782 const char *requested_format_name;
4783
4784 if (ast_check_hangup(chan)) {
4785 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
4786 return 0;
4787 }
4788
4789 requested_format_name = pbx_builtin_getvar_helper(chan, "EAGI_AUDIO_FORMAT");
4790 if (requested_format_name) {
4791 requested_format = ast_format_cache_get(requested_format_name);
4792 if (requested_format) {
4793 ast_verb(3, "<%s> Setting EAGI audio pipe format to %s\n",
4794 ast_channel_name(chan), ast_format_get_name(requested_format));
4795 } else {
4796 ast_log(LOG_ERROR, "Could not find requested format: %s\n", requested_format_name);
4797 }
4798 }
4799
4800 readformat = ao2_bump(ast_channel_readformat(chan));
4801 if (ast_set_read_format(chan, requested_format ?: ast_format_slin)) {
4802 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan));
4803 ao2_cleanup(requested_format);
4804 ao2_cleanup(readformat);
4805 return -1;
4806 }
4807 res = agi_exec_full(chan, data, 1, 0);
4808 if (!res) {
4809 if (ast_set_read_format(chan, readformat)) {
4810 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan),
4811 ast_format_get_name(readformat));
4812 }
4813 }
4814 ao2_cleanup(requested_format);
4815 ao2_cleanup(readformat);
4816 return res;
4817}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5721
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define ast_format_cache_get(name)
Retrieve a named format from the cache.
Definition: format_cache.h:278
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition of a media format.
Definition: format.c:43

References agi_exec_full(), ao2_bump, ao2_cleanup, ast_channel_name(), ast_channel_readformat(), ast_check_hangup(), ast_format_cache_get, ast_format_get_name(), ast_format_slin, ast_log, ast_set_read_format(), ast_verb, LOG_ERROR, LOG_WARNING, NULL, and pbx_builtin_getvar_helper().

Referenced by load_module().

◆ find_command()

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

Definition at line 4120 of file res_agi.c.

4121{
4122 int y, match;
4123 struct agi_command *e;
4124
4127 if (!e->cmda[0])
4128 break;
4129 /* start optimistic */
4130 match = 1;
4131 for (y = 0; match && cmds[y]; y++) {
4132 /* If there are no more words in the command (and we're looking for
4133 an exact match) or there is a difference between the two words,
4134 then this is not a match */
4135 if (!e->cmda[y] && !exact)
4136 break;
4137 /* don't segfault if the next part of a command doesn't exist */
4138 if (!e->cmda[y]) {
4140 return NULL;
4141 }
4142 if (strcasecmp(e->cmda[y], cmds[y]))
4143 match = 0;
4144 }
4145 /* If more words are needed to complete the command then this is not
4146 a candidate (unless we're looking for a really inexact answer */
4147 if ((exact > -1) && e->cmda[y])
4148 match = 0;
4149 if (match) {
4151 return e;
4152 }
4153 }
4155 return NULL;
4156}
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2388
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494

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

Referenced by agi_handle_command(), ast_agi_register(), and handle_cli_agi_show().

◆ free_agi_cmd()

static void free_agi_cmd ( struct agi_cmd cmd)
static

Definition at line 1682 of file res_agi.c.

1683{
1684 ast_free(cmd->cmd_buffer);
1685 ast_free(cmd->cmd_id);
1686 ast_free(cmd);
1687}

References ast_free, agi_cmd::cmd_buffer, and agi_cmd::cmd_id.

Referenced by agi_destroy_commands_cb(), and launch_asyncagi().

◆ get_agi_cmd()

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 1718 of file res_agi.c.

1719{
1720 struct ast_datastore *store;
1722
1723 ast_channel_lock(chan);
1725 ast_channel_unlock(chan);
1726 if (!store) {
1727 ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
1728 ast_channel_name(chan));
1729 *cmd = NULL;
1730 return -1;
1731 }
1732 agi_commands = store->data;
1736 return 0;
1737}
struct ast_datastore::@216 entry

References agi_commands, agi_commands_datastore_info, ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_datastore::data, ast_datastore::entry, LOG_ERROR, and NULL.

Referenced by launch_asyncagi().

◆ handle_answer()

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

Definition at line 2529 of file res_agi.c.

2530{
2531 int res = 0;
2532
2533 /* Answer the channel */
2534 if (ast_channel_state(chan) != AST_STATE_UP)
2535 res = ast_answer(chan);
2536
2537 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2538 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2539}
ast_channel_state
ast_channel states
Definition: channelstate.h:35

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

◆ handle_asyncagi_break()

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

Definition at line 2541 of file res_agi.c.

2542{
2543 ast_agi_send(agi->fd, chan, "200 result=0\n");
2544 return ASYNC_AGI_BREAK;
2545}

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

◆ handle_autohangup()

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

Definition at line 3264 of file res_agi.c.

3265{
3266 double timeout;
3267 struct timeval whentohangup = { 0, 0 };
3268
3269 if (argc != 3)
3270 return RESULT_SHOWUSAGE;
3271 if (sscanf(argv[2], "%30lf", &timeout) != 1)
3272 return RESULT_SHOWUSAGE;
3273 if (timeout < 0)
3274 timeout = 0;
3275 if (timeout) {
3276 whentohangup.tv_sec = timeout;
3277 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
3278 }
3279 ast_channel_lock(chan);
3280 ast_channel_setwhentohangup_tv(chan, whentohangup);
3281 ast_channel_unlock(chan);
3282 ast_agi_send(agi->fd, chan, "200 result=0\n");
3283 return RESULT_SUCCESS;
3284}
void ast_channel_setwhentohangup_tv(struct ast_channel *chan, struct timeval offset)
Set when to hang a channel up.
Definition: channel.c:509

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

◆ handle_channelstatus()

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

Definition at line 3381 of file res_agi.c.

3382{
3383 if (argc == 2) {
3384 /* no argument: supply info on the current channel */
3385 ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));
3386 return RESULT_SUCCESS;
3387 } else if (argc == 3) {
3388 struct ast_channel_snapshot *snapshot;
3389
3390 /* one argument: look for info on the specified channel */
3391 snapshot = ast_channel_snapshot_get_latest_by_name(argv[2]);
3392 if (snapshot) {
3393 ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);
3394 ao2_ref(snapshot, -1);
3395 return RESULT_SUCCESS;
3396 }
3397 /* if we get this far no channel name matched the argument given */
3398 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3399 return RESULT_SUCCESS;
3400 } else {
3401 return RESULT_SHOWUSAGE;
3402 }
3403}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_channel_snapshot * ast_channel_snapshot_get_latest_by_name(const char *name)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
Structure representing a snapshot of channel state.
enum ast_channel_state state

References ao2_ref, ast_agi_send(), ast_channel_snapshot_get_latest_by_name(), agi_state::fd, RESULT_SHOWUSAGE, RESULT_SUCCESS, and ast_channel_snapshot::state.

◆ handle_cli_agi_add_cmd()

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 1817 of file res_agi.c.

1818{
1819 struct ast_channel *chan;
1820 switch (cmd) {
1821 case CLI_INIT:
1822 e->command = "agi exec";
1823 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
1824 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
1825 return NULL;
1826 case CLI_GENERATE:
1827 if (a->pos == 2)
1828 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1829 return NULL;
1830 }
1831
1832 if (a->argc < 4) {
1833 return CLI_SHOWUSAGE;
1834 }
1835
1836 if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
1837 ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
1838 return CLI_FAILURE;
1839 }
1840
1841 ast_channel_lock(chan);
1842
1843 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
1844 ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", ast_channel_name(chan));
1845 ast_channel_unlock(chan);
1846 chan = ast_channel_unref(chan);
1847 return CLI_FAILURE;
1848 }
1849
1850 ast_debug(1, "Added AGI command to channel %s queue\n", ast_channel_name(chan));
1851
1852 ast_channel_unlock(chan);
1853 chan = ast_channel_unref(chan);
1854
1855 return CLI_SUCCESS;
1856}
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
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:1872
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
static struct test_val a

References a, add_agi_cmd(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), ast_debug, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, and ast_cli_entry::usage.

◆ handle_cli_agi_debug()

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

Definition at line 3564 of file res_agi.c.

3565{
3566 switch (cmd) {
3567 case CLI_INIT:
3568 e->command = "agi set debug [on|off]";
3569 e->usage =
3570 "Usage: agi set debug [on|off]\n"
3571 " Enables/disables dumping of AGI transactions for\n"
3572 " debugging purposes.\n";
3573 return NULL;
3574
3575 case CLI_GENERATE:
3576 return NULL;
3577 }
3578
3579 if (a->argc != e->args)
3580 return CLI_SHOWUSAGE;
3581
3582 if (strncasecmp(a->argv[3], "off", 3) == 0) {
3583 agidebug = 0;
3584 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
3585 agidebug = 1;
3586 } else {
3587 return CLI_SHOWUSAGE;
3588 }
3589 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
3590 return CLI_SUCCESS;
3591}
int args
This gets set in ast_cli_register()
Definition: cli.h:185

References a, agidebug, ast_cli_entry::args, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, and ast_cli_entry::usage.

◆ handle_cli_agi_dump_html()

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

Definition at line 4675 of file res_agi.c.

4676{
4677 switch (cmd) {
4678 case CLI_INIT:
4679 e->command = "agi dump html";
4680 e->usage =
4681 "Usage: agi dump html <filename>\n"
4682 " Dumps the AGI command list in HTML format to the given\n"
4683 " file.\n";
4684 return NULL;
4685 case CLI_GENERATE:
4686 return NULL;
4687 }
4688 if (a->argc != e->args + 1)
4689 return CLI_SHOWUSAGE;
4690
4691 if (write_htmldump(a->argv[e->args]) < 0) {
4692 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
4693 return CLI_SHOWUSAGE;
4694 }
4695 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
4696 return CLI_SUCCESS;
4697}
static int write_htmldump(const char *filename)
Definition: res_agi.c:4623

References a, ast_cli_entry::args, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, ast_cli_entry::usage, and write_htmldump().

◆ handle_cli_agi_show()

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

Definition at line 4495 of file res_agi.c.

4496{
4497 struct agi_command *command;
4498 char fullcmd[MAX_CMD_LEN];
4499 int error = 0;
4500
4501 switch (cmd) {
4502 case CLI_INIT:
4503 e->command = "agi show commands [topic]";
4504 e->usage =
4505 "Usage: agi show commands [topic] <topic>\n"
4506 " When called with a topic as an argument, displays usage\n"
4507 " information on the given command. If called without a\n"
4508 " topic, it provides a list of AGI commands.\n";
4509 case CLI_GENERATE:
4510 return NULL;
4511 }
4512 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
4513 return CLI_SHOWUSAGE;
4514 if (a->argc > e->args - 1) {
4515 command = find_command(a->argv + e->args, 1);
4516 if (command) {
4517 char *synopsis = NULL, *since = NULL, *description = NULL, *syntax = NULL, *arguments = NULL, *seealso = NULL;
4518
4519 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4520
4521#ifdef AST_XML_DOCS
4522 if (command->docsrc == AST_XML_DOC) {
4523 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
4524 since = ast_xmldoc_printable(S_OR(command->since, "Not available"), 1);
4525 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
4526 syntax = ast_xmldoc_printable(S_OR(command->syntax, "Not available"), 1);
4527 arguments = ast_xmldoc_printable(S_OR(command->arguments, "Not available"), 1);
4528 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
4529 } else
4530#endif
4531 {
4532 synopsis = ast_strdup(S_OR(command->summary, "Not Available"));
4533 since = ast_strdup(S_OR(command->since, "Not Available"));
4534 description = ast_strdup(S_OR(command->usage, "Not Available"));
4535 syntax = ast_strdup(S_OR(command->syntax, "Not Available"));
4536 arguments = ast_strdup(S_OR(command->arguments, "Not Available"));
4537 seealso = ast_strdup(S_OR(command->seealso, "Not Available"));
4538 }
4539
4540 if (!synopsis || !since || !description || !syntax || !arguments || !seealso) {
4541 error = 1;
4542 goto return_cleanup;
4543 }
4544
4545 ast_cli(a->fd, "\n"
4546 "%s -= Info about AGI '%s' =- %s\n\n"
4547 COLORIZE_FMT "\n"
4548 "%s\n\n"
4549 COLORIZE_FMT "\n"
4550 "%s\n\n"
4551 COLORIZE_FMT "\n"
4552 "%s\n\n"
4553 COLORIZE_FMT "\n"
4554 "%s\n\n"
4555 COLORIZE_FMT "\n"
4556 "%s\n\n"
4557 COLORIZE_FMT "\n"
4558 "%s\n\n"
4559 COLORIZE_FMT "\n"
4560 "%s\n\n",
4562 COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"), synopsis,
4563 COLORIZE(COLOR_MAGENTA, 0, "[Since]"), since,
4564 COLORIZE(COLOR_MAGENTA, 0, "[Description]"), description,
4565 COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"), syntax,
4566 COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"), arguments,
4567 COLORIZE(COLOR_MAGENTA, 0, "[Runs Dead]"), command->dead ? "Yes" : "No",
4568 COLORIZE(COLOR_MAGENTA, 0, "[See Also]"), seealso
4569 );
4570
4571return_cleanup:
4573 ast_free(since);
4574 ast_free(description);
4578 } else {
4579 if (find_command(a->argv + e->args, -1)) {
4580 return help_workhorse(a->fd, a->argv + e->args);
4581 } else {
4582 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4583 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
4584 }
4585 }
4586 } else {
4587 return help_workhorse(a->fd, NULL);
4588 }
4589 return (error ? CLI_FAILURE : CLI_SUCCESS);
4590}
static char * synopsis
Definition: func_enum.c:166
static char * help_workhorse(int fd, const char *const match[])
Definition: res_agi.c:3962
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
const int dead
Definition: agi.h:52
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
#define COLOR_MAGENTA
Definition: term.h:60
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:341
#define COLORIZE(fg, bg, str)
Definition: term.h:72
#define COLORIZE_FMT
Shortcut macros for coloring a set of text.
Definition: term.h:71
int error(const char *format,...)
Definition: utils/frame.c:999
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:241

References a, ast_cli_entry::args, agi_command::arguments, ast_cli(), ast_free, ast_join, ast_strdup, ast_term_color(), ast_term_reset(), AST_XML_DOC, ast_xmldoc_printable(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, COLOR_MAGENTA, COLORIZE, COLORIZE_FMT, ast_cli_entry::command, agi_command::dead, agi_command::docsrc, error(), find_command(), help_workhorse(), MAX_CMD_LEN, NULL, S_OR, agi_command::seealso, agi_command::since, agi_command::summary, synopsis, agi_command::syntax, agi_command::usage, and ast_cli_entry::usage.

◆ handle_connection()

static int handle_connection ( const char *  agiurl,
const struct ast_sockaddr  addr,
const int  netsockfd 
)
static

Definition at line 2172 of file res_agi.c.

2173{
2174 struct pollfd pfds[1];
2175 int res, conresult;
2176 socklen_t reslen;
2177
2178 reslen = sizeof(conresult);
2179
2180 pfds[0].fd = netsockfd;
2181 pfds[0].events = POLLOUT;
2182
2183 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
2184 if (errno != EINTR) {
2185 if (!res) {
2186 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
2187 agiurl, MAX_AGI_CONNECT);
2188 } else {
2189 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2190 }
2191
2192 return 1;
2193 }
2194 }
2195
2196 if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &conresult, &reslen) < 0) {
2197 ast_log(LOG_WARNING, "Connection to %s failed with error: %s\n",
2198 ast_sockaddr_stringify(&addr), strerror(errno));
2199 return 1;
2200 }
2201
2202 if (conresult) {
2203 ast_log(LOG_WARNING, "Connecting to '%s' failed for url '%s': %s\n",
2204 ast_sockaddr_stringify(&addr), agiurl, strerror(conresult));
2205 return 1;
2206 }
2207
2208 return 0;
2209}
int errno
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
#define MAX_AGI_CONNECT
Definition: res_agi.c:1565

References ast_log, ast_poll, ast_sockaddr_stringify(), errno, LOG_WARNING, and MAX_AGI_CONNECT.

Referenced by launch_netscript().

◆ handle_controlstreamfile()

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

Definition at line 2660 of file res_agi.c.

2661{
2662 int res = 0, skipms = 3000;
2663 const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
2664 char stopkeybuf[2];
2665 long offsetms = 0;
2666 char offsetbuf[20];
2667
2668 if (argc < 5 || argc > 10) {
2669 return RESULT_SHOWUSAGE;
2670 }
2671
2672 if (!ast_strlen_zero(argv[4])) {
2673 stop = argv[4];
2674 }
2675
2676 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
2677 return RESULT_SHOWUSAGE;
2678 }
2679
2680 if (argc > 6 && !ast_strlen_zero(argv[6])) {
2681 fwd = argv[6];
2682 }
2683
2684 if (argc > 7 && !ast_strlen_zero(argv[7])) {
2685 rev = argv[7];
2686 }
2687
2688 if (argc > 8 && !ast_strlen_zero(argv[8])) {
2689 suspend = argv[8];
2690 }
2691
2692 if (argc > 9 && (sscanf(argv[9], "%30ld", &offsetms) != 1)) {
2693 return RESULT_SHOWUSAGE;
2694 }
2695
2696 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, &offsetms);
2697
2698 /* If we stopped on one of our stop keys, return 0 */
2699 if (res > 0 && stop && strchr(stop, res)) {
2700 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
2701 snprintf(stopkeybuf, sizeof(stopkeybuf), "%c", res);
2702 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTOPKEY", stopkeybuf);
2703 } else if (res > 0 && res == AST_CONTROL_STREAM_STOP) {
2704 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "REMOTESTOPPED");
2705 res = 0;
2706 } else {
2707 if (res < 0) {
2708 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
2709 } else {
2710 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
2711 }
2712 }
2713
2714 snprintf(offsetbuf, sizeof(offsetbuf), "%ld", offsetms);
2715 pbx_builtin_setvar_helper(chan, "CPLAYBACKOFFSET", offsetbuf);
2716
2717 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, offsetms);
2718
2719 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2720}
unsigned int stop
Definition: app_sla.c:342
static int skipms
static void suspend(struct cc_core_instance *core_instance)
Definition: ccss.c:3166
int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms, long *offsetms)
Stream a file with fast forward, pause, reverse, restart.
Definition: main/app.c:1465
@ AST_CONTROL_STREAM_STOP

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

◆ handle_dbdel()

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

Definition at line 3536 of file res_agi.c.

3537{
3538 int res;
3539
3540 if (argc != 4)
3541 return RESULT_SHOWUSAGE;
3542 res = ast_db_del(argv[2], argv[3]);
3543 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3544 return RESULT_SUCCESS;
3545}
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: db.c:472

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

◆ handle_dbdeltree()

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

Definition at line 3547 of file res_agi.c.

3548{
3549 int num_deleted;
3550
3551 if ((argc < 3) || (argc > 4)) {
3552 return RESULT_SHOWUSAGE;
3553 }
3554 if (argc == 4) {
3555 num_deleted = ast_db_deltree(argv[2], argv[3]);
3556 } else {
3557 num_deleted = ast_db_deltree(argv[2], NULL);
3558 }
3559
3560 ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
3561 return RESULT_SUCCESS;
3562}
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb.
Definition: db.c:559

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

◆ handle_dbget()

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

Definition at line 3492 of file res_agi.c.

3493{
3494 int res;
3495 struct ast_str *buf;
3496
3497 if (argc != 4)
3498 return RESULT_SHOWUSAGE;
3499
3500 if (!(buf = ast_str_create(16))) {
3501 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3502 return RESULT_SUCCESS;
3503 }
3504
3505 do {
3506 res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
3508 if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
3509 break;
3510 }
3511 if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
3512 break;
3513 }
3514 } while (1);
3515
3516 if (res)
3517 ast_agi_send(agi->fd, chan, "200 result=0\n");
3518 else
3519 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
3520
3521 ast_free(buf);
3522 return RESULT_SUCCESS;
3523}
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
Definition: db.c:421
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
#define ast_str_make_space(buf, new_len)
Definition: strings.h:828
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:703
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:742

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.

◆ handle_dbput()

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

Definition at line 3525 of file res_agi.c.

3526{
3527 int res;
3528
3529 if (argc != 5)
3530 return RESULT_SHOWUSAGE;
3531 res = ast_db_put(argv[2], argv[3], argv[4]);
3532 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3533 return RESULT_SUCCESS;
3534}
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: db.c:335

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

◆ handle_exec()

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

Definition at line 3314 of file res_agi.c.

3315{
3316 int res, workaround;
3317 struct ast_app *app_to_exec;
3318 const char *agi_exec_full_str;
3319 int agi_exec_full;
3320 struct ast_str *data_with_var = NULL;
3321
3322 if (argc < 2)
3323 return RESULT_SHOWUSAGE;
3324
3325 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
3326
3327 if ((app_to_exec = pbx_findapp(argv[1]))) {
3328 ast_channel_lock(chan);
3329 if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) {
3331 }
3332 agi_exec_full_str = pbx_builtin_getvar_helper(chan, "AGIEXECFULL");
3333 agi_exec_full = ast_true(agi_exec_full_str);
3334 ast_channel_unlock(chan);
3335
3336 if (agi_exec_full) {
3337 if ((data_with_var = ast_str_create(16))) {
3338 ast_str_substitute_variables(&data_with_var, 0, chan, argv[2]);
3339 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : ast_str_buffer(data_with_var));
3340 ast_free(data_with_var);
3341 } else {
3342 res = -2;
3343 }
3344 } else {
3345 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
3346 }
3347 if (!workaround) {
3349 }
3350 } else {
3351 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
3352 res = -2;
3353 }
3354 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3355
3356 /* Even though this is wrong, users are depending upon this result. */
3357 return res;
3358}
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11039
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
@ AST_FLAG_DISABLE_WORKAROUNDS
Definition: channel.h:1042
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
ast_app: A registered application
Definition: pbx_app.c:45
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set_flag(p, flag)
Definition: utils.h:70

References agi_exec_full(), ast_agi_send(), ast_channel_clear_flag(), ast_channel_flags(), ast_channel_lock, ast_channel_unlock, AST_FLAG_DISABLE_WORKAROUNDS, ast_free, ast_log, ast_set_flag, ast_str_buffer(), ast_str_create, ast_str_substitute_variables(), ast_test_flag, ast_true(), ast_verb, agi_state::fd, LOG_WARNING, NULL, pbx_builtin_getvar_helper(), pbx_exec(), pbx_findapp(), and RESULT_SHOWUSAGE.

◆ handle_getdata()

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

Definition at line 2999 of file res_agi.c.

3000{
3001 int res, max, timeout;
3002 char data[1024];
3003
3004 if (argc < 3)
3005 return RESULT_SHOWUSAGE;
3006 if (argc >= 4)
3007 timeout = atoi(argv[3]);
3008 else
3009 timeout = 0;
3010 if (argc >= 5)
3011 max = atoi(argv[4]);
3012 else
3013 max = 1024;
3014 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
3015 if (res == 2) /* New command */
3016 return RESULT_SUCCESS;
3017 else if (res == 1)
3018 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
3019 else if (res < 0 )
3020 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3021 else
3022 ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
3023 return RESULT_SUCCESS;
3024}
#define max(a, b)
Definition: f2c.h:198
int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other fu...
Definition: main/app.c:247
int ctrl
Definition: agi.h:37
int audio
Definition: agi.h:36

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

◆ handle_getoption()

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

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

Definition at line 2781 of file res_agi.c.

2782{
2783 int res;
2784 struct ast_filestream *fs, *vfs;
2785 long sample_offset = 0, max_length;
2786 int timeout = 0;
2787 const char *edigits = "";
2788
2789 if ( argc < 4 || argc > 5 )
2790 return RESULT_SHOWUSAGE;
2791
2792 if ( argv[3] )
2793 edigits = argv[3];
2794
2795 if ( argc == 5 )
2796 timeout = atoi(argv[4]);
2797 else if (ast_channel_pbx(chan)->dtimeoutms) {
2798 /* by default dtimeout is set to 5sec */
2799 timeout = ast_channel_pbx(chan)->dtimeoutms; /* in msec */
2800 }
2801
2802 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2803 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2804 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
2805 return RESULT_FAILURE;
2806 }
2807
2808 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan))))
2809 ast_debug(1, "Ooh, found a video stream, too\n");
2810
2811 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
2812
2813 ast_seekstream(fs, 0, SEEK_END);
2814 max_length = ast_tellstream(fs);
2815 ast_seekstream(fs, sample_offset, SEEK_SET);
2816 res = ast_applystream(chan, fs);
2817 if (vfs)
2818 ast_applystream(chan, vfs);
2819 ast_playstream(fs);
2820 if (vfs)
2822
2823 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2824 /* this is to check for if ast_waitstream closed the stream, we probably are at
2825 * the end of the stream, return that amount, else check for the amount */
2826 sample_offset = (ast_channel_stream(chan))?ast_tellstream(fs):max_length;
2827 ast_stopstream(chan);
2828 if (res == 1) {
2829 /* Stop this command, don't print a result line, as there is a new command */
2830 return RESULT_SUCCESS;
2831 }
2832
2833 /* If the user didnt press a key, wait for digitTimeout*/
2834 if (res == 0 ) {
2835 res = ast_waitfordigit_full(chan, timeout, NULL, agi->audio, agi->ctrl);
2836 /* Make sure the new result is in the escape digits of the GET OPTION */
2837 if ( !strchr(edigits,res) )
2838 res=0;
2839 }
2840
2841 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2842 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2843}
const char * ast_channel_language(const struct ast_channel *chan)
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
int ast_waitfordigit_full(struct ast_channel *c, int ms, const char *breakon, int audiofd, int ctrlfd)
Wait for a digit Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to mon...
Definition: channel.c:3207
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition: file.c:1093
struct ast_filestream * ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
Definition: file.c:845
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int monfd)
Definition: file.c:1857
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:1083
int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
Applies a open stream to a channel.
Definition: file.c:1065
struct ast_filestream * ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
Definition: file.c:856
int ast_playstream(struct ast_filestream *s)
Play a open stream on a channel.
Definition: file.c:1071
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
struct ast_filestream * vfs
Definition: mod_format.h:110
int dtimeoutms
Definition: pbx.h:216

References ast_agi_send(), ast_applystream(), ast_channel_language(), ast_channel_pbx(), ast_channel_stream(), 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, LOG_WARNING, NULL, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and ast_filestream::vfs.

◆ handle_getvariable()

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

Definition at line 3418 of file res_agi.c.

3419{
3420 char *ret;
3421 char tempstr[1024] = "";
3422
3423 if (argc != 3)
3424 return RESULT_SHOWUSAGE;
3425
3426 /* check if we want to execute an ast_custom_function */
3427 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
3428 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
3429 } else {
3430 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
3431 }
3432
3433 if (ret)
3434 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
3435 else
3436 ast_agi_send(agi->fd, chan, "200 result=0\n");
3437
3438 return RESULT_SUCCESS;
3439}
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Retrieve the value of a builtin variable or variable from the channel variable stack.

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

◆ handle_getvariablefull()

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

Definition at line 3441 of file res_agi.c.

3442{
3443 struct ast_channel *chan2 = NULL;
3444
3445 if (argc != 4 && argc != 5) {
3446 return RESULT_SHOWUSAGE;
3447 }
3448
3449 if (argc == 5) {
3450 chan2 = ast_channel_get_by_name(argv[4]);
3451 } else {
3452 chan2 = ast_channel_ref(chan);
3453 }
3454
3455 if (chan2) {
3456 struct ast_str *str = ast_str_create(16);
3457 if (!str) {
3458 ast_agi_send(agi->fd, chan, "200 result=0\n");
3459 return RESULT_SUCCESS;
3460 }
3461 ast_str_substitute_variables(&str, 0, chan2, argv[3]);
3462 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
3463 ast_free(str);
3464 } else {
3465 ast_agi_send(agi->fd, chan, "200 result=0\n");
3466 }
3467
3468 if (chan2) {
3469 chan2 = ast_channel_unref(chan2);
3470 }
3471
3472 return RESULT_SUCCESS;
3473}
const char * str
Definition: app_jack.c:150
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2997

References ast_agi_send(), ast_channel_get_by_name(), ast_channel_ref, ast_channel_unref, ast_free, ast_str_buffer(), ast_str_create, ast_str_substitute_variables(), agi_state::fd, NULL, RESULT_SHOWUSAGE, RESULT_SUCCESS, and str.

◆ handle_hangup()

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

Definition at line 3286 of file res_agi.c.

3287{
3288 struct ast_channel *c;
3289
3290 if (argc == 1) {
3291 /* no argument: hangup the current channel */
3292 ast_set_hangupsource(chan, "dialplan/agi", 0);
3294 ast_agi_send(agi->fd, chan, "200 result=1\n");
3295 return RESULT_SUCCESS;
3296 } else if (argc == 2) {
3297 /* one argument: look for info on the specified channel */
3298 if ((c = ast_channel_get_by_name(argv[1]))) {
3299 /* we have a matching channel */
3300 ast_set_hangupsource(c, "dialplan/agi", 0);
3303 ast_agi_send(agi->fd, chan, "200 result=1\n");
3304 return RESULT_SUCCESS;
3305 }
3306 /* if we get this far no channel name matched the argument given */
3307 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3308 return RESULT_SUCCESS;
3309 } else {
3310 return RESULT_SHOWUSAGE;
3311 }
3312}
void ast_set_hangupsource(struct ast_channel *chan, const char *source, int force)
Set the source of the hangup in this channel and it's bridge.
Definition: channel.c:2468
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2440
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168

References ast_agi_send(), ast_channel_get_by_name(), ast_channel_unref, ast_set_hangupsource(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, c, agi_state::fd, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

◆ handle_noop()

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

Definition at line 3593 of file res_agi.c.

3594{
3595 ast_agi_send(agi->fd, chan, "200 result=0\n");
3596 return RESULT_SUCCESS;
3597}

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

◆ handle_recordfile()

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

Definition at line 3064 of file res_agi.c.

3065{
3066 struct ast_filestream *fs;
3067 struct ast_frame *f;
3068 struct timeval start;
3069 long sample_offset = 0;
3070 int res = 0;
3071 int ms;
3072
3073 struct ast_dsp *sildet=NULL; /* silence detector dsp */
3074 int totalsilence = 0;
3075 int dspsilence = 0;
3076 int silence = 0; /* amount of silence to allow */
3077 int gotsilence = 0; /* did we timeout for silence? */
3078 char *silencestr = NULL;
3079 RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
3080 struct ast_silence_generator *silgen = NULL;
3081
3082 /* XXX EAGI FIXME XXX */
3083
3084 if (argc < 6)
3085 return RESULT_SHOWUSAGE;
3086 if (sscanf(argv[5], "%30d", &ms) != 1)
3087 return RESULT_SHOWUSAGE;
3088
3089 if (argc > 6)
3090 silencestr = strchr(argv[6],'s');
3091 if ((argc > 7) && (!silencestr))
3092 silencestr = strchr(argv[7],'s');
3093 if ((argc > 8) && (!silencestr))
3094 silencestr = strchr(argv[8],'s');
3095
3096 if (silencestr) {
3097 if (strlen(silencestr) > 2) {
3098 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
3099 silencestr++;
3100 silencestr++;
3101 if (silencestr)
3102 silence = atoi(silencestr);
3103 if (silence > 0)
3104 silence *= 1000;
3105 }
3106 }
3107 }
3108
3109 if (silence > 0) {
3110 rfmt = ao2_bump(ast_channel_readformat(chan));
3112 if (res < 0) {
3113 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
3114 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3115 return RESULT_FAILURE;
3116 }
3117 sildet = ast_dsp_new();
3118 if (!sildet) {
3119 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
3120 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3121 return RESULT_FAILURE;
3122 }
3124 }
3125
3126 /* backward compatibility, if no offset given, arg[6] would have been
3127 * caught below and taken to be a beep, else if it is a digit then it is a
3128 * offset.
3129 *
3130 * In other words, if the argument does not look like the offset_samples
3131 * argument (a number) and it doesn't look like the silence argument (starts
3132 * with "s=") then it must be the beep argument. The beep argument has no
3133 * required value, the presence of anything in the argument slot we are
3134 * inspecting is an indication that the user wants a beep played.
3135 */
3136 if ((argc > 6 && sscanf(argv[6], "%30ld", &sample_offset) != 1 && !ast_begins_with(argv[6], "s="))
3137 || (argc > 7 && !ast_begins_with(argv[7], "s="))) {
3138 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
3139 }
3140
3141 if (!res)
3142 res = ast_waitstream(chan, argv[4]);
3143 if (res) {
3144 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
3145 } else {
3146 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
3147 if (!fs) {
3148 res = -1;
3149 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
3150 if (sildet)
3151 ast_dsp_free(sildet);
3152 return RESULT_FAILURE;
3153 }
3154
3155 /* Request a video update */
3157
3158 ast_channel_stream_set(chan, fs);
3159 ast_applystream(chan,fs);
3160 /* really should have checks */
3161 ast_seekstream(fs, sample_offset, SEEK_SET);
3162 ast_truncstream(fs);
3163
3166 }
3167
3168 start = ast_tvnow();
3169 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
3170 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
3171 if (res < 0) {
3172 ast_closestream(fs);
3173 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
3174 if (sildet)
3175 ast_dsp_free(sildet);
3176 if (silgen)
3178 return RESULT_FAILURE;
3179 }
3180 f = ast_read(chan);
3181 if (!f) {
3182 ast_closestream(fs);
3183 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
3184 if (sildet)
3185 ast_dsp_free(sildet);
3186 if (silgen)
3188 return RESULT_FAILURE;
3189 }
3190 switch(f->frametype) {
3191 case AST_FRAME_DTMF:
3192 if (strchr(argv[4], f->subclass.integer)) {
3193 /* This is an interrupting character, so rewind to chop off any small
3194 amount of DTMF that may have been recorded
3195 */
3196 ast_stream_rewind(fs, 200);
3197 ast_truncstream(fs);
3198 sample_offset = ast_tellstream(fs);
3199 ast_closestream(fs);
3200 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
3201 ast_frfree(f);
3202 if (sildet)
3203 ast_dsp_free(sildet);
3204 if (silgen)
3206 return RESULT_SUCCESS;
3207 }
3208 break;
3209 case AST_FRAME_VOICE:
3210 ast_writestream(fs, f);
3211 /* this is a safe place to check progress since we know that fs
3212 * is valid after a write, and it will then have our current
3213 * location */
3214 sample_offset = ast_tellstream(fs);
3215 if (silence > 0) {
3216 dspsilence = 0;
3217 ast_dsp_silence(sildet, f, &dspsilence);
3218 if (dspsilence) {
3219 totalsilence = dspsilence;
3220 } else {
3221 totalsilence = 0;
3222 }
3223 if (totalsilence > silence) {
3224 /* Ended happily with silence */
3225 gotsilence = 1;
3226 break;
3227 }
3228 }
3229 break;
3230 case AST_FRAME_VIDEO:
3231 ast_writestream(fs, f);
3232 default:
3233 /* Ignore all other frames */
3234 break;
3235 }
3236 ast_frfree(f);
3237 if (gotsilence)
3238 break;
3239 }
3240
3241 if (gotsilence) {
3242 ast_stream_rewind(fs, silence-1000);
3243 ast_truncstream(fs);
3244 sample_offset = ast_tellstream(fs);
3245 }
3246 ast_closestream(fs);
3247 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
3248 }
3249
3250 if (silence > 0) {
3251 res = ast_set_read_format(chan, rfmt);
3252 if (res)
3253 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
3254 ast_dsp_free(sildet);
3255 }
3256
3257 if (silgen) {
3259 }
3260
3261 return RESULT_SUCCESS;
3262}
#define AST_FILE_MODE
Definition: asterisk.h:32
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8169
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3130
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
Definition: channel.c:8215
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4234
void ast_dsp_set_threshold(struct ast_dsp *dsp, int threshold)
Set the minimum average magnitude threshold to determine talking by the DSP.
Definition: dsp.c:1788
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1783
@ THRESHOLD_SILENCE
Definition: dsp.h:73
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1488
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:2009
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1758
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:244
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition: file.c:1108
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1301
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition: file.c:1431
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition: file.c:1088
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1119
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1848
#define AST_FRAME_DTMF
@ AST_FRAME_VIDEO
@ AST_FRAME_VOICE
@ AST_CONTROL_VIDUPDATE
#define ast_opt_transmit_silence
Definition: options.h:125
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
Definition: dsp.c:407
int totalsilence
Definition: dsp.c:411
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ao2_bump, ao2_cleanup, ast_agi_send(), ast_applystream(), ast_begins_with(), ast_channel_language(), ast_channel_name(), ast_channel_readformat(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_stream_set(), 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_slin, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate(), ast_log, ast_opt_transmit_silence, 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(), agi_state::fd, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, NULL, RAII_VAR, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_frame::subclass, THRESHOLD_SILENCE, and ast_dsp::totalsilence.

◆ handle_recvchar()

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

Definition at line 2579 of file res_agi.c.

2580{
2581 int res;
2582
2583 if (argc != 3)
2584 return RESULT_SHOWUSAGE;
2585
2586 res = ast_recvchar(chan,atoi(argv[2]));
2587 if (res == 0) {
2588 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
2589 return RESULT_SUCCESS;
2590 }
2591 if (res > 0) {
2592 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2593 return RESULT_SUCCESS;
2594 }
2595 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
2596 return RESULT_FAILURE;
2597}
int ast_recvchar(struct ast_channel *chan, int timeout)
Receives a text character from a channel.
Definition: channel.c:4665

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

◆ handle_recvtext()

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

Definition at line 2599 of file res_agi.c.

2600{
2601 char *buf;
2602
2603 if (argc != 3)
2604 return RESULT_SHOWUSAGE;
2605
2606 buf = ast_recvtext(chan, atoi(argv[2]));
2607 if (buf) {
2608 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
2609 ast_free(buf);
2610 } else {
2611 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2612 }
2613 return RESULT_SUCCESS;
2614}
char * ast_recvtext(struct ast_channel *chan, int timeout)
Receives a text string from a channel Read a string of text from a channel.
Definition: channel.c:4676

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

◆ handle_sayalpha()

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

Definition at line 2881 of file res_agi.c.

2882{
2883 int res;
2884 int sensitivity = AST_SAY_CASE_NONE;
2885
2886 if (argc < 4 || argc > 5) {
2887 return RESULT_SHOWUSAGE;
2888 }
2889
2890 if (argc > 4) {
2891 switch (argv[4][0]) {
2892 case 'a':
2893 case 'A':
2894 sensitivity = AST_SAY_CASE_ALL;
2895 break;
2896 case 'l':
2897 case 'L':
2898 sensitivity = AST_SAY_CASE_LOWER;
2899 break;
2900 case 'n':
2901 case 'N':
2902 sensitivity = AST_SAY_CASE_NONE;
2903 break;
2904 case 'u':
2905 case 'U':
2906 sensitivity = AST_SAY_CASE_UPPER;
2907 break;
2908 case '\0':
2909 break;
2910 default:
2911 return RESULT_SHOWUSAGE;
2912 }
2913 }
2914 res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->audio, agi->ctrl);
2915 if (res == 1) /* New command */
2916 return RESULT_SUCCESS;
2917 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2918 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2919}
SAY_EXTERN int(* ast_say_character_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity, int audiofd, int ctrlfd) SAY_INIT(ast_say_character_str_full)
Definition: say.h:194
@ AST_SAY_CASE_LOWER
Definition: say.h:183
@ AST_SAY_CASE_ALL
Definition: say.h:185
@ AST_SAY_CASE_UPPER
Definition: say.h:184
@ AST_SAY_CASE_NONE
Definition: say.h:182

References ast_agi_send(), ast_channel_language(), AST_SAY_CASE_ALL, AST_SAY_CASE_LOWER, AST_SAY_CASE_NONE, AST_SAY_CASE_UPPER, ast_say_character_str_full, agi_state::audio, agi_state::ctrl, agi_state::fd, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

◆ handle_saydate()

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

Definition at line 2921 of file res_agi.c.

2922{
2923 int res, num;
2924
2925 if (argc != 4)
2926 return RESULT_SHOWUSAGE;
2927 if (sscanf(argv[2], "%30d", &num) != 1)
2928 return RESULT_SHOWUSAGE;
2929 res = ast_say_date(chan, num, argv[3], ast_channel_language(chan));
2930 if (res == 1)
2931 return RESULT_SUCCESS;
2932 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2933 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2934}
SAY_EXTERN int(* ast_say_date)(struct ast_channel *chan, time_t t, const char *ints, const char *lang) SAY_INIT(ast_say_date)
Definition: say.h:204

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

◆ handle_saydatetime()

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

Definition at line 2951 of file res_agi.c.

2952{
2953 int res = 0;
2954 time_t unixtime;
2955 const char *format, *zone = NULL;
2956
2957 if (argc < 4)
2958 return RESULT_SHOWUSAGE;
2959
2960 if (argc > 4) {
2961 format = argv[4];
2962 } else {
2963 /* XXX this doesn't belong here, but in the 'say' module */
2964 if (!strcasecmp(ast_channel_language(chan), "de")) {
2965 format = "A dBY HMS";
2966 } else {
2967 format = "ABdY 'digits/at' IMp";
2968 }
2969 }
2970
2971 if (argc > 5 && !ast_strlen_zero(argv[5]))
2972 zone = argv[5];
2973
2974 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
2975 return RESULT_SHOWUSAGE;
2976
2977 res = ast_say_date_with_format(chan, unixtime, argv[3], ast_channel_language(chan), format, zone);
2978 if (res == 1)
2979 return RESULT_SUCCESS;
2980
2981 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2982 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2983}
SAY_EXTERN int(* ast_say_date_with_format)(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezone) SAY_INIT(ast_say_date_with_format)
Definition: say.h:208
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
Parse a time (integer) string.
Definition: utils.c:2446

References ast_agi_send(), ast_channel_language(), ast_get_time_t(), ast_say_date_with_format, ast_strlen_zero(), agi_state::fd, NULL, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

◆ handle_saydigits()

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

Definition at line 2865 of file res_agi.c.

2866{
2867 int res, num;
2868
2869 if (argc != 4)
2870 return RESULT_SHOWUSAGE;
2871 if (sscanf(argv[2], "%30d", &num) != 1)
2872 return RESULT_SHOWUSAGE;
2873
2874 res = ast_say_digit_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2875 if (res == 1) /* New command */
2876 return RESULT_SUCCESS;
2877 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2878 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2879}
SAY_EXTERN int(* ast_say_digit_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_digit_str_full)
Same as ast_say_digit_str() with audiofd for received audio and returns 1 on ctrlfd being readable.
Definition: say.h:162

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

◆ handle_saynumber()

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

Say number in various language syntaxes.

Definition at line 2850 of file res_agi.c.

2851{
2852 int res, num;
2853
2854 if (argc < 4 || argc > 5)
2855 return RESULT_SHOWUSAGE;
2856 if (sscanf(argv[2], "%30d", &num) != 1)
2857 return RESULT_SHOWUSAGE;
2858 res = ast_say_number_full(chan, num, argv[3], ast_channel_language(chan), argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
2859 if (res == 1)
2860 return RESULT_SUCCESS;
2861 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2862 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2863}
SAY_EXTERN int(* ast_say_number_full)(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_number_full)
Same as ast_say_number() with audiofd for received audio and returns 1 on ctrlfd being readable.
Definition: say.h:86

References ast_agi_send(), ast_channel_language(), ast_say_number_full, agi_state::audio, agi_state::ctrl, agi_state::fd, NULL, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

◆ handle_sayphonetic()

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

Definition at line 2985 of file res_agi.c.

2986{
2987 int res;
2988
2989 if (argc != 4)
2990 return RESULT_SHOWUSAGE;
2991
2992 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2993 if (res == 1) /* New command */
2994 return RESULT_SUCCESS;
2995 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2996 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2997}
SAY_EXTERN int(* ast_say_phonetic_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_phonetic_str_full)
Definition: say.h:199

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

◆ handle_saytime()

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

Definition at line 2936 of file res_agi.c.

2937{
2938 int res, num;
2939
2940 if (argc != 4)
2941 return RESULT_SHOWUSAGE;
2942 if (sscanf(argv[2], "%30d", &num) != 1)
2943 return RESULT_SHOWUSAGE;
2944 res = ast_say_time(chan, num, argv[3], ast_channel_language(chan));
2945 if (res == 1)
2946 return RESULT_SUCCESS;
2947 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2948 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2949}
SAY_EXTERN int(* ast_say_time)(struct ast_channel *chan, time_t t, const char *ints, const char *lang) SAY_INIT(ast_say_time)
Definition: say.h:202

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

◆ handle_sendimage()

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

Definition at line 2644 of file res_agi.c.

2645{
2646 int res;
2647
2648 if (argc != 3) {
2649 return RESULT_SHOWUSAGE;
2650 }
2651
2652 res = ast_send_image(chan, argv[2]);
2653 if (!ast_check_hangup(chan)) {
2654 res = 0;
2655 }
2656 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2657 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2658}
int ast_send_image(struct ast_channel *chan, const char *filename)
Sends an image.
Definition: image.c:158

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

◆ handle_sendtext()

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

Definition at line 2560 of file res_agi.c.

2561{
2562 int res;
2563
2564 if (argc != 3)
2565 return RESULT_SHOWUSAGE;
2566
2567 /* At the moment, the parser (perhaps broken) returns with
2568 the last argument PLUS the newline at the end of the input
2569 buffer. This probably needs to be fixed, but I wont do that
2570 because other stuff may break as a result. The right way
2571 would probably be to strip off the trailing newline before
2572 parsing, then here, add a newline at the end of the string
2573 before sending it to ast_sendtext --DUDE */
2574 res = ast_sendtext(chan, argv[2]);
2575 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2576 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2577}
int ast_sendtext(struct ast_channel *chan, const char *text)
Sends text to a channel.
Definition: channel.c:4768

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

◆ handle_setcallerid()

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

Definition at line 3360 of file res_agi.c.

3361{
3362 char tmp[256]="";
3363 char *l = NULL, *n = NULL;
3364
3365 if (argv[2]) {
3366 ast_copy_string(tmp, argv[2], sizeof(tmp));
3367 ast_callerid_parse(tmp, &n, &l);
3368 if (l)
3370 else
3371 l = "";
3372 if (!n)
3373 n = "";
3374 ast_set_callerid(chan, l, n, NULL);
3375 }
3376
3377 ast_agi_send(agi->fd, chan, "200 result=1\n");
3378 return RESULT_SUCCESS;
3379}
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
Definition: callerid.c:1162
void ast_shrink_phone_number(char *n)
Shrink a phone number in place to just digits (more accurately it just removes ()'s,...
Definition: callerid.c:1101
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7307
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425

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

◆ handle_setcontext()

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

Definition at line 3026 of file res_agi.c.

3027{
3028
3029 if (argc != 3)
3030 return RESULT_SHOWUSAGE;
3031 ast_channel_context_set(chan, argv[2]);
3032 ast_agi_send(agi->fd, chan, "200 result=0\n");
3033 return RESULT_SUCCESS;
3034}
void ast_channel_context_set(struct ast_channel *chan, const char *value)

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

◆ handle_setextension()

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

Definition at line 3036 of file res_agi.c.

3037{
3038 if (argc != 3)
3039 return RESULT_SHOWUSAGE;
3040 ast_channel_exten_set(chan, argv[2]);
3041 ast_agi_send(agi->fd, chan, "200 result=0\n");
3042 return RESULT_SUCCESS;
3043}
void ast_channel_exten_set(struct ast_channel *chan, const char *value)

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

◆ handle_setmusic()

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

Definition at line 3599 of file res_agi.c.

3600{
3601 if (argc < 3) {
3602 return RESULT_SHOWUSAGE;
3603 }
3604 if (!strncasecmp(argv[2], "on", 2))
3605 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
3606 else if (!strncasecmp(argv[2], "off", 3))
3607 ast_moh_stop(chan);
3608 ast_agi_send(agi->fd, chan, "200 result=0\n");
3609 return RESULT_SUCCESS;
3610}
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7739
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7749

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

◆ handle_setpriority()

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

Definition at line 3045 of file res_agi.c.

3046{
3047 int pri;
3048
3049 if (argc != 3)
3050 return RESULT_SHOWUSAGE;
3051
3052 if (sscanf(argv[2], "%30d", &pri) != 1) {
3053 pri = ast_findlabel_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), argv[2],
3054 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
3055 if (pri < 1)
3056 return RESULT_SHOWUSAGE;
3057 }
3058
3059 ast_explicit_goto(chan, NULL, NULL, pri);
3060 ast_agi_send(agi->fd, chan, "200 result=0\n");
3061 return RESULT_SUCCESS;
3062}
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: pbx.c:4195
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6960
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
Number structure.
Definition: app_followme.c:157

References ast_agi_send(), ast_channel_caller(), ast_channel_context(), ast_channel_exten(), ast_explicit_goto(), ast_findlabel_extension(), agi_state::fd, NULL, RESULT_SHOWUSAGE, RESULT_SUCCESS, and S_COR.

◆ handle_setvariable()

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

Definition at line 3405 of file res_agi.c.

3406{
3407 if (argc != 4) {
3408 return RESULT_SHOWUSAGE;
3409 }
3410
3411 if (argv[3])
3412 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
3413
3414 ast_agi_send(agi->fd, chan, "200 result=1\n");
3415 return RESULT_SUCCESS;
3416}

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

◆ handle_speechactivategrammar()

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

Definition at line 3703 of file res_agi.c.

3704{
3705 if (argc != 4)
3706 return RESULT_SHOWUSAGE;
3707
3708 if (!agi->speech) {
3709 ast_agi_send(agi->fd, chan, "200 result=0\n");
3710 return RESULT_SUCCESS;
3711 }
3712
3713 if (ast_speech_grammar_activate(agi->speech, argv[3]))
3714 ast_agi_send(agi->fd, chan, "200 result=0\n");
3715 else
3716 ast_agi_send(agi->fd, chan, "200 result=1\n");
3717
3718 return RESULT_SUCCESS;
3719}
int ast_speech_grammar_activate(struct ast_speech *speech, const char *grammar_name)
Activate a grammar on a speech structure.
Definition: res_speech.c:66
struct ast_speech * speech
Definition: agi.h:39

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

◆ handle_speechcreate()

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

Definition at line 3612 of file res_agi.c.

3613{
3614 struct ast_format_cap *cap;
3615
3616 /* If a structure already exists, return an error */
3617 if (agi->speech) {
3618 ast_agi_send(agi->fd, chan, "200 result=0\n");
3619 return RESULT_SUCCESS;
3620 }
3621
3623 return RESULT_FAILURE;
3624 }
3626 if ((agi->speech = ast_speech_new(argv[2], cap))) {
3627 ast_agi_send(agi->fd, chan, "200 result=1\n");
3628 } else {
3629 ast_agi_send(agi->fd, chan, "200 result=0\n");
3630 }
3631 ao2_ref(cap, -1);
3632
3633 return RESULT_SUCCESS;
3634}
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
struct ast_speech * ast_speech_new(const char *engine_name, const struct ast_format_cap *formats)
Create a new speech structure.
Definition: res_speech.c:181
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54

References ao2_ref, ast_agi_send(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_slin, ast_speech_new(), agi_state::fd, RESULT_FAILURE, RESULT_SUCCESS, and agi_state::speech.

◆ handle_speechdeactivategrammar()

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

Definition at line 3721 of file res_agi.c.

3722{
3723 if (argc != 4)
3724 return RESULT_SHOWUSAGE;
3725
3726 if (!agi->speech) {
3727 ast_agi_send(agi->fd, chan, "200 result=0\n");
3728 return RESULT_SUCCESS;
3729 }
3730
3731 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
3732 ast_agi_send(agi->fd, chan, "200 result=0\n");
3733 else
3734 ast_agi_send(agi->fd, chan, "200 result=1\n");
3735
3736 return RESULT_SUCCESS;
3737}
int ast_speech_grammar_deactivate(struct ast_speech *speech, const char *grammar_name)
Deactivate a grammar on a speech structure.
Definition: res_speech.c:72

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

◆ handle_speechdestroy()

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

Definition at line 3654 of file res_agi.c.

3655{
3656 if (agi->speech) {
3658 agi->speech = NULL;
3659 ast_agi_send(agi->fd, chan, "200 result=1\n");
3660 } else {
3661 ast_agi_send(agi->fd, chan, "200 result=0\n");
3662 }
3663
3664 return RESULT_SUCCESS;
3665}
int ast_speech_destroy(struct ast_speech *speech)
Destroy a speech structure.
Definition: res_speech.c:251

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

◆ handle_speechloadgrammar()

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

Definition at line 3667 of file res_agi.c.

3668{
3669 if (argc != 5)
3670 return RESULT_SHOWUSAGE;
3671
3672 if (!agi->speech) {
3673 ast_agi_send(agi->fd, chan, "200 result=0\n");
3674 return RESULT_SUCCESS;
3675 }
3676
3677 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
3678 ast_agi_send(agi->fd, chan, "200 result=0\n");
3679 else
3680 ast_agi_send(agi->fd, chan, "200 result=1\n");
3681
3682 return RESULT_SUCCESS;
3683}
int ast_speech_grammar_load(struct ast_speech *speech, const char *grammar_name, const char *grammar)
Load a grammar on a speech structure (not globally)
Definition: res_speech.c:78

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

◆ handle_speechrecognize()

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

Definition at line 3758 of file res_agi.c.

3759{
3760 struct ast_speech *speech = agi->speech;
3761 const char *prompt;
3762 char dtmf = 0, tmp[4096] = "", *buf = tmp;
3763 int timeout = 0, offset = 0, res = 0, i = 0;
3764 long current_offset = 0;
3765 const char *reason = NULL;
3766 struct ast_frame *fr = NULL;
3767 struct ast_speech_result *result = NULL;
3768 size_t left = sizeof(tmp);
3769 time_t start = 0, current;
3770
3771 if (argc < 4)
3772 return RESULT_SHOWUSAGE;
3773
3774 if (!speech) {
3775 ast_agi_send(agi->fd, chan, "200 result=0\n");
3776 return RESULT_SUCCESS;
3777 }
3778
3779 prompt = argv[2];
3780 timeout = atoi(argv[3]);
3781
3782 /* If offset is specified then convert from text to integer */
3783 if (argc == 5)
3784 offset = atoi(argv[4]);
3785
3786 /* We want frames coming in signed linear */
3788 ast_agi_send(agi->fd, chan, "200 result=0\n");
3789 return RESULT_SUCCESS;
3790 }
3791
3792 /* Setup speech structure */
3793 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
3795 ast_speech_start(speech);
3796 }
3797
3798 /* Start playing prompt */
3799 speech_streamfile(chan, prompt, ast_channel_language(chan), offset);
3800
3801 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
3802 while (ast_strlen_zero(reason)) {
3803 /* Run scheduled items */
3805
3806 /* See maximum time of waiting */
3807 if ((res = ast_sched_wait(ast_channel_sched(chan))) < 0)
3808 res = 1000;
3809
3810 /* Wait for frame */
3811 if (ast_waitfor(chan, res) > 0) {
3812 if (!(fr = ast_read(chan))) {
3813 reason = "hangup";
3814 break;
3815 }
3816 }
3817
3818 /* Perform timeout check */
3819 if ((timeout > 0) && (start > 0)) {
3820 time(&current);
3821 if ((current - start) >= timeout) {
3822 reason = "timeout";
3823 if (fr) {
3824 ast_frfree(fr);
3825 fr = NULL;
3826 }
3827 break;
3828 }
3829 }
3830
3831 /* Check the speech structure for any changes */
3832 ast_mutex_lock(&speech->lock);
3833
3834 /* See if we need to quiet the audio stream playback */
3835 if (ast_test_flag(speech, AST_SPEECH_QUIET) && ast_channel_stream(chan)) {
3836 current_offset = ast_tellstream(ast_channel_stream(chan));
3837 ast_stopstream(chan);
3839 }
3840
3841 /* Check each state */
3842 switch (speech->state) {
3844 /* If the stream is done, start timeout calculation */
3845 if ((timeout > 0) && start == 0 && ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL))) {
3846 ast_stopstream(chan);
3847 time(&start);
3848 }
3849 /* Write audio frame data into speech engine if possible */
3850 if (fr && fr->frametype == AST_FRAME_VOICE)
3851 ast_speech_write(speech, fr->data.ptr, fr->datalen);
3852 break;
3854 /* Cue waiting sound if not already playing */
3855 if ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL)) {
3856 ast_stopstream(chan);
3857 /* If a processing sound exists, or is not none - play it */
3858 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
3860 }
3861 break;
3863 /* Get the results */
3864 speech->results = ast_speech_results_get(speech);
3865 /* Change state to not ready */
3867 reason = "speech";
3868 break;
3869 default:
3870 break;
3871 }
3872 ast_mutex_unlock(&speech->lock);
3873
3874 /* Check frame for DTMF or hangup */
3875 if (fr) {
3876 if (fr->frametype == AST_FRAME_DTMF) {
3877 reason = "dtmf";
3878 dtmf = fr->subclass.integer;
3879 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
3880 reason = "hangup";
3881 }
3882 ast_frfree(fr);
3883 fr = NULL;
3884 }
3885 }
3886
3887 if (!strcasecmp(reason, "speech")) {
3888 /* Build string containing speech results */
3889 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
3890 /* Build result string */
3891 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);
3892 /* Increment result count */
3893 i++;
3894 }
3895 /* Print out */
3896 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
3897 } else if (!strcasecmp(reason, "dtmf")) {
3898 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
3899 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
3900 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
3901 } else {
3902 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
3903 }
3904
3905 return RESULT_SUCCESS;
3906}
static struct ast_str * prompt
Definition: asterisk.c:2789
static PGresult * result
Definition: cel_pgsql.c:84
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
int ast_channel_streamid(const struct ast_channel *chan)
struct ast_sched_context * ast_channel_sched(const struct ast_channel *chan)
size_t current
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
#define ast_mutex_unlock(a)
Definition: lock.h:197
#define ast_mutex_lock(a)
Definition: lock.h:196
static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
Definition: res_agi.c:3739
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:786
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:433
void ast_speech_start(struct ast_speech *speech)
Indicate to the speech engine that audio is now going to start being written.
Definition: res_speech.c:122
int ast_speech_write(struct ast_speech *speech, void *data, int len)
Write audio to the speech engine.
Definition: res_speech.c:144
int ast_speech_change_state(struct ast_speech *speech, int state)
Change state of a speech structure.
Definition: res_speech.c:278
@ AST_SPEECH_STATE_DONE
Definition: speech.h:42
@ AST_SPEECH_STATE_READY
Definition: speech.h:40
@ AST_SPEECH_STATE_NOT_READY
Definition: speech.h:39
@ AST_SPEECH_STATE_WAIT
Definition: speech.h:41
struct ast_speech_result * ast_speech_results_get(struct ast_speech *speech)
Get speech recognition results.
Definition: res_speech.c:90
@ AST_SPEECH_QUIET
Definition: speech.h:32
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
Definition: utils.c:2167
union ast_frame::@228 data
char * processing_sound
Definition: speech.h:60
int state
Definition: speech.h:62
ast_mutex_t lock
Definition: speech.h:56
struct ast_speech_result * results
Definition: speech.h:68
#define ast_clear_flag(p, flag)
Definition: utils.h:77

References ast_agi_send(), ast_build_string(), ast_channel_language(), ast_channel_sched(), ast_channel_stream(), ast_channel_streamid(), ast_channel_timingfunc(), ast_clear_flag, AST_CONTROL_HANGUP, ast_format_slin, 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, current, ast_frame::data, ast_frame::datalen, agi_state::fd, ast_frame::frametype, ast_frame_subclass::integer, ast_speech::lock, NULL, ast_speech::processing_sound, prompt, ast_frame::ptr, result, RESULT_SHOWUSAGE, RESULT_SUCCESS, ast_speech::results, agi_state::speech, speech_streamfile(), ast_speech::state, and ast_frame::subclass.

◆ handle_speechset()

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

Definition at line 3636 of file res_agi.c.

3637{
3638 /* Check for minimum arguments */
3639 if (argc != 4)
3640 return RESULT_SHOWUSAGE;
3641
3642 /* Check to make sure speech structure exists */
3643 if (!agi->speech) {
3644 ast_agi_send(agi->fd, chan, "200 result=0\n");
3645 return RESULT_SUCCESS;
3646 }
3647
3648 ast_speech_change(agi->speech, argv[2], argv[3]);
3649 ast_agi_send(agi->fd, chan, "200 result=1\n");
3650
3651 return RESULT_SUCCESS;
3652}
int ast_speech_change(struct ast_speech *speech, const char *name, const char *value)
Change an engine specific attribute.
Definition: res_speech.c:169

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

◆ handle_speechunloadgrammar()

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

Definition at line 3685 of file res_agi.c.

3686{
3687 if (argc != 4)
3688 return RESULT_SHOWUSAGE;
3689
3690 if (!agi->speech) {
3691 ast_agi_send(agi->fd, chan, "200 result=0\n");
3692 return RESULT_SUCCESS;
3693 }
3694
3695 if (ast_speech_grammar_unload(agi->speech, argv[3]))
3696 ast_agi_send(agi->fd, chan, "200 result=0\n");
3697 else
3698 ast_agi_send(agi->fd, chan, "200 result=1\n");
3699
3700 return RESULT_SUCCESS;
3701}
int ast_speech_grammar_unload(struct ast_speech *speech, const char *grammar_name)
Unload a grammar.
Definition: res_speech.c:84

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

◆ handle_streamfile()

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

Definition at line 2722 of file res_agi.c.

2723{
2724 int res;
2725 struct ast_filestream *fs, *vfs;
2726 long sample_offset = 0, max_length;
2727 const char *edigits = "";
2728
2729 if (argc < 4 || argc > 5) {
2730 return RESULT_SHOWUSAGE;
2731 }
2732
2733 if (argv[3]) {
2734 edigits = argv[3];
2735 }
2736
2737 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1)) {
2738 return RESULT_SHOWUSAGE;
2739 }
2740
2741 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2742 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2743 return RESULT_FAILURE;
2744 }
2745
2746 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan)))) {
2747 ast_debug(1, "Ooh, found a video stream, too\n");
2748 }
2749 ast_verb(3, "<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
2751 edigits, sample_offset, S_OR(ast_channel_language(chan), "default"));
2752
2753 ast_seekstream(fs, 0, SEEK_END);
2754 max_length = ast_tellstream(fs);
2755 ast_seekstream(fs, sample_offset, SEEK_SET);
2756 res = ast_applystream(chan, fs);
2757 if (vfs) {
2758 ast_applystream(chan, vfs);
2759 }
2760 ast_playstream(fs);
2761 if (vfs) {
2763 }
2764
2765 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2766 /* this is to check for if ast_waitstream closed the stream, we probably are at
2767 * the end of the stream, return that amount, else check for the amount */
2768 sample_offset = (ast_channel_stream(chan)) ? ast_tellstream(fs) : max_length;
2769 ast_stopstream(chan);
2770 if (res == 1) {
2771 /* Stop this command, don't print a result line, as there is a new command */
2772 return RESULT_SUCCESS;
2773 }
2774 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2775 pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
2776
2777 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2778}
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)

References ast_agi_send(), ast_applystream(), ast_channel_language(), ast_channel_name(), ast_channel_stream(), ast_channel_writeformat(), ast_debug, ast_format_get_name(), 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, pbx_builtin_setvar_helper(), RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_OR, and ast_filestream::vfs.

◆ handle_tddmode()

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

Definition at line 2616 of file res_agi.c.

2617{
2618 int res, x;
2619
2620 if (argc != 3)
2621 return RESULT_SHOWUSAGE;
2622
2623 if (!strncasecmp(argv[2],"on",2)) {
2624 x = 1;
2625 } else {
2626 x = 0;
2627 }
2628 if (!strncasecmp(argv[2],"mate",4)) {
2629 x = 2;
2630 }
2631 if (!strncasecmp(argv[2],"tdd",3)) {
2632 x = 1;
2633 }
2634 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
2635 if (res) {
2636 /* Set channel option failed */
2637 ast_agi_send(agi->fd, chan, "200 result=0\n");
2638 } else {
2639 ast_agi_send(agi->fd, chan, "200 result=1\n");
2640 }
2641 return RESULT_SUCCESS;
2642}
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7395
#define AST_OPTION_TDD

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

◆ handle_verbose()

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

Definition at line 3475 of file res_agi.c.

3476{
3477 int level = 0;
3478
3479 if (argc < 2)
3480 return RESULT_SHOWUSAGE;
3481
3482 if (argv[2])
3483 sscanf(argv[2], "%30d", &level);
3484
3485 ast_verb(level, "%s: %s\n", ast_channel_data(chan), argv[1]);
3486
3487 ast_agi_send(agi->fd, chan, "200 result=1\n");
3488
3489 return RESULT_SUCCESS;
3490}
const char * ast_channel_data(const struct ast_channel *chan)

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

◆ handle_waitfordigit()

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

Definition at line 2547 of file res_agi.c.

2548{
2549 int res, to;
2550
2551 if (argc != 4)
2552 return RESULT_SHOWUSAGE;
2553 if (sscanf(argv[3], "%30d", &to) != 1)
2554 return RESULT_SHOWUSAGE;
2555 res = ast_waitfordigit_full(chan, to, NULL, agi->audio, agi->ctrl);
2556 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2557 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2558}

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

◆ help_workhorse()

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

Definition at line 3962 of file res_agi.c.

3963{
3964 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
3965 struct agi_command *e;
3966
3967 if (match)
3968 ast_join(matchstr, sizeof(matchstr), match);
3969
3970 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
3973 if (!e->cmda[0])
3974 break;
3975 /* Hide commands that start with '_' */
3976 if ((e->cmda[0])[0] == '_')
3977 continue;
3978 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
3979 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
3980 continue;
3981 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
3982 }
3984
3985 return CLI_SUCCESS;
3986}

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, match(), MAX_CMD_LEN, S_OR, and agi_command::summary.

Referenced by handle_cli_agi_show().

◆ launch_asyncagi()

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

Definition at line 1947 of file res_agi.c.

1948{
1949/* This buffer sizes might cause truncation if the AGI command writes more data
1950 than AGI_BUF_SIZE as result. But let's be serious, is there an AGI command
1951 that writes a response larger than 1024 bytes?, I don't think so, most of
1952 them are just result=blah stuff. However probably if GET VARIABLE is called
1953 and the variable has large amount of data, that could be a problem. We could
1954 make this buffers dynamic, but let's leave that as a second step.
1955
1956 AMI_BUF_SIZE is twice AGI_BUF_SIZE just for the sake of choosing a safe
1957 number. Some characters of AGI buf will be url encoded to be sent to manager
1958 clients. An URL encoded character will take 3 bytes, but again, to cause
1959 truncation more than about 70% of the AGI buffer should be URL encoded for
1960 that to happen. Not likely at all.
1961
1962 On the other hand. I wonder if read() could eventually return less data than
1963 the amount already available in the pipe? If so, how to deal with that?
1964 So far, my tests on Linux have not had any problems.
1965 */
1966#define AGI_BUF_SIZE 1024
1967#define AMI_BUF_SIZE 2048
1968 enum agi_result cmd_status;
1969 struct agi_cmd *cmd;
1970 int res;
1971 int fds[2];
1972 int hungup;
1973 int timeout = 100;
1974 char agi_buffer[AGI_BUF_SIZE + 1];
1975 char ami_buffer[AMI_BUF_SIZE];
1976 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
1977 AGI async_agi;
1978 RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
1979
1980 if (efd) {
1981 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
1982 return AGI_RESULT_FAILURE;
1983 }
1984
1985 /* add AsyncAGI datastore to the channel */
1986 if (add_to_agi(chan)) {
1987 ast_log(LOG_ERROR, "Failed to start Async AGI on channel %s\n", ast_channel_name(chan));
1988 return AGI_RESULT_FAILURE;
1989 }
1990
1991 /* this pipe allows us to create a "fake" AGI struct to use
1992 the AGI commands */
1993 res = pipe(fds);
1994 if (res) {
1995 ast_log(LOG_ERROR, "Failed to create Async AGI pipe\n");
1996 /*
1997 * Intentionally do not remove the datastore added with
1998 * add_to_agi() the from channel. It will be removed when the
1999 * channel is hung up anyway.
2000 */
2001 return AGI_RESULT_FAILURE;
2002 }
2003
2004 /* handlers will get the pipe write fd and we read the AGI responses
2005 from the pipe read fd */
2006 async_agi.fd = fds[1];
2007 async_agi.ctrl = fds[1];
2008 async_agi.audio = -1; /* no audio support */
2009 async_agi.fast = 0;
2010 async_agi.speech = NULL;
2011
2012 /* notify possible manager users of a new channel ready to
2013 receive commands */
2014 setup_env(chan, "async", fds[1], 0, argc, argv);
2015 /* read the environment */
2016 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
2017 if (res <= 0) {
2018 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
2019 ast_channel_name(chan), res < 0 ? strerror(errno) : "EOF");
2020 returnstatus = AGI_RESULT_FAILURE;
2021 goto async_agi_abort;
2022 }
2023 agi_buffer[res] = '\0';
2024 /* encode it and send it thru the manager so whoever is going to take
2025 care of AGI commands on this channel can decide which AGI commands
2026 to execute based on the setup info */
2027 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
2028 startblob = ast_json_pack("{s: s}", "Env", ami_buffer);
2029
2030 ast_channel_publish_cached_blob(chan, agi_async_start_type(), startblob);
2031
2032 hungup = ast_check_hangup_locked(chan);
2033
2034 for (;;) {
2035 /*
2036 * Process as many commands as we can. Commands are added via
2037 * the manager or the cli threads.
2038 */
2039 while (!hungup) {
2040 RAII_VAR(struct ast_json *, execblob, NULL, ast_json_unref);
2041 res = get_agi_cmd(chan, &cmd);
2042
2043 if (res) {
2044 returnstatus = AGI_RESULT_FAILURE;
2045 goto async_agi_done;
2046 } else if (!cmd) {
2047 break;
2048 }
2049
2050 /* OK, we have a command, let's call the command handler. */
2051 cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
2052
2053 /*
2054 * The command handler must have written to our fake AGI struct
2055 * fd (the pipe), let's read the response.
2056 */
2057 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
2058 if (res <= 0) {
2059 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
2060 ast_channel_name(chan), res < 0 ? strerror(errno) : "EOF");
2061 free_agi_cmd(cmd);
2062 returnstatus = AGI_RESULT_FAILURE;
2063 goto async_agi_done;
2064 }
2065 /*
2066 * We have a response, let's send the response thru the manager.
2067 * Include the CommandID if it was specified when the command
2068 * was added.
2069 */
2070 agi_buffer[res] = '\0';
2071 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
2072
2073 execblob = ast_json_pack("{s: s}", "Result", ami_buffer);
2074 if (execblob && !ast_strlen_zero(cmd->cmd_id)) {
2075 ast_json_object_set(execblob, "CommandId", ast_json_string_create(cmd->cmd_id));
2076 }
2077 ast_channel_publish_cached_blob(chan, agi_async_exec_type(), execblob);
2078
2079 free_agi_cmd(cmd);
2080
2081 /*
2082 * Check the command status to determine if we should continue
2083 * executing more commands.
2084 */
2085 hungup = ast_check_hangup(chan);
2086 switch (cmd_status) {
2087 case AGI_RESULT_FAILURE:
2088 if (!hungup) {
2089 /* The failure was not because of a hangup. */
2090 returnstatus = AGI_RESULT_FAILURE;
2091 goto async_agi_done;
2092 }
2093 break;
2095 /* Only the "asyncagi break" command does this. */
2096 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
2097 goto async_agi_done;
2098 default:
2099 break;
2100 }
2101 }
2102
2103 if (!hungup) {
2104 /* Wait a bit for a frame to read or to poll for a new command. */
2105 res = ast_waitfor(chan, timeout);
2106 if (res < 0) {
2107 ast_debug(1, "ast_waitfor returned <= 0 on chan %s\n", ast_channel_name(chan));
2108 returnstatus = AGI_RESULT_FAILURE;
2109 break;
2110 }
2111 } else {
2112 /*
2113 * Read the channel control queue until it is dry so we can
2114 * quit.
2115 */
2116 res = 1;
2117 }
2118 if (0 < res) {
2119 do {
2120 cmd_status = async_agi_read_frame(chan);
2121 if (cmd_status != AGI_RESULT_SUCCESS) {
2122 returnstatus = cmd_status;
2123 goto async_agi_done;
2124 }
2125 hungup = ast_check_hangup(chan);
2126 } while (hungup);
2127 } else {
2128 hungup = ast_check_hangup(chan);
2129 }
2130 }
2131async_agi_done:
2132
2133 if (async_agi.speech) {
2134 ast_speech_destroy(async_agi.speech);
2135 }
2136 /* notify manager users this channel cannot be controlled anymore by Async AGI */
2137 ast_channel_publish_cached_blob(chan, agi_async_end_type(), NULL);
2138
2139async_agi_abort:
2140 /* close the pipe */
2141 close(fds[0]);
2142 close(fds[1]);
2143
2144 /*
2145 * Intentionally do not remove the datastore added with
2146 * add_to_agi() the from channel. There might be commands still
2147 * in the queue or in-flight to us and AsyncAGI may get called
2148 * again. The datastore destructor will be called on channel
2149 * destruction anyway.
2150 */
2151
2152 if (returnstatus == AGI_RESULT_SUCCESS) {
2153 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
2154 }
2155 return returnstatus;
2156
2157#undef AGI_BUF_SIZE
2158#undef AMI_BUF_SIZE
2159}
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:458
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
Definition: res_agi.c:2483
#define AMI_BUF_SIZE
static enum agi_result async_agi_read_frame(struct ast_channel *chan)
Definition: res_agi.c:1919
static int add_to_agi(struct ast_channel *chan)
Definition: res_agi.c:1773
static int get_agi_cmd(struct ast_channel *chan, struct agi_cmd **cmd)
Retrieve the list head to the requested channel's AGI datastore.
Definition: res_agi.c:1718
#define AGI_BUF_SIZE
static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
Definition: res_agi.c:4232
unsigned int fast
Definition: agi.h:38
char * ast_uri_encode(const char *string, char *outbuf, int buflen, struct ast_flags spec)
Turn text string to URI-encoded XX version.
Definition: utils.c:723
const struct ast_flags ast_uri_http
Definition: utils.c:719

References add_to_agi(), AGI_BUF_SIZE, agi_handle_command(), AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS, AGI_RESULT_SUCCESS_ASYNC, AMI_BUF_SIZE, ast_channel_name(), ast_channel_publish_cached_blob(), ast_check_hangup(), ast_check_hangup_locked(), ast_debug, ast_json_object_set(), ast_json_pack(), ast_json_string_create(), ast_json_unref(), ast_log, ast_speech_destroy(), ast_strlen_zero(), ast_uri_encode(), ast_uri_http, ast_waitfor(), async_agi_read_frame(), agi_state::audio, agi_cmd::cmd_buffer, agi_cmd::cmd_id, agi_state::ctrl, errno, agi_state::fast, agi_state::fd, free_agi_cmd(), get_agi_cmd(), LOG_ERROR, LOG_WARNING, NULL, RAII_VAR, setup_env(), and agi_state::speech.

Referenced by launch_script().

◆ launch_ha_netscript()

static enum agi_result launch_ha_netscript ( char *  agiurl,
char *  argv[],
int *  fds 
)
static

Definition at line 2306 of file res_agi.c.

2307{
2308 char *host, *script;
2309 enum agi_result result;
2310 struct srv_context *context = NULL;
2311 int srv_ret;
2312 char service[256];
2313 char resolved_uri[1024];
2314 const char *srvhost;
2315 unsigned short srvport;
2316
2317 /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
2318 if (strlen(agiurl) < 7) { /* Remove hagi:// */
2319 ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
2320 return AGI_RESULT_FAILURE;
2321 }
2322 host = ast_strdupa(agiurl + 7);
2323
2324 /* Strip off any script name */
2325 if ((script = strchr(host, '/'))) {
2326 *script++ = '\0';
2327 } else {
2328 script = "";
2329 }
2330
2331 if (strchr(host, ':')) {
2332 ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
2333 return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
2334 }
2335
2336 snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
2337
2338 while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
2339 snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
2340 result = launch_netscript(resolved_uri, argv, fds);
2342 ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
2343 } else {
2344 /* The script launched so we must cleanup the context. */
2346 return result;
2347 }
2348 }
2349 /*
2350 * The DNS SRV lookup failed or we ran out of servers to check.
2351 * ast_srv_lookup() has already cleaned up the context for us.
2352 */
2353 if (srv_ret < 0) {
2354 ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
2355 }
2356
2357 return AGI_RESULT_FAILURE;
2358}
enum ast_cc_service_type service
Definition: ccss.c:389
static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
Definition: res_agi.c:2213
#define SRV_PREFIX
Definition: res_agi.c:1552
void ast_srv_cleanup(struct srv_context **context)
Cleanup resources associated with ast_srv_lookup.
Definition: srv.c:248
int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
Retrieve set of SRV lookups, in order.
Definition: srv.c:202

References AGI_RESULT_FAILURE, AGI_RESULT_NOTFOUND, ast_log, ast_srv_cleanup(), ast_srv_lookup(), ast_strdupa, voicemailpwcheck::context, launch_netscript(), LOG_WARNING, NULL, result, service, and SRV_PREFIX.

Referenced by launch_script().

◆ launch_netscript()

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

Definition at line 2213 of file res_agi.c.

2214{
2215 int s = 0;
2216 char *host, *script;
2217 int num_addrs = 0, i = 0;
2218 struct ast_sockaddr *addrs;
2219
2220 /* agiurl is "agi://host.domain[:port][/script/name]" */
2221 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
2222
2223 /* Strip off any script name */
2224 if ((script = strchr(host, '/'))) {
2225 *script++ = '\0';
2226 } else {
2227 script = "";
2228 }
2229
2230 if (!(num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC))) {
2231 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
2232 return AGI_RESULT_FAILURE;
2233 }
2234
2235 for (i = 0; i < num_addrs; i++) {
2236 if (!ast_sockaddr_port(&addrs[i])) {
2237 ast_sockaddr_set_port(&addrs[i], AGI_PORT);
2238 }
2239
2240 if ((s = ast_socket_nonblock(addrs[i].ss.ss_family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
2241 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
2242 continue;
2243 }
2244
2245 if (ast_connect(s, &addrs[i]) && errno == EINPROGRESS) {
2246
2247 if (handle_connection(agiurl, addrs[i], s)) {
2248 close(s);
2249 continue;
2250 }
2251
2252 } else {
2253 ast_log(LOG_WARNING, "Connection to %s failed with unexpected error: %s\n",
2254 ast_sockaddr_stringify(&addrs[i]), strerror(errno));
2255 }
2256
2257 break;
2258 }
2259
2260 ast_free(addrs);
2261
2262 if (i == num_addrs) {
2263 ast_log(LOG_WARNING, "Couldn't connect to any host. FastAGI failed.\n");
2264 return AGI_RESULT_FAILURE;
2265 }
2266
2267 if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
2268 if (errno != EINTR) {
2269 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2270 close(s);
2271 return AGI_RESULT_FAILURE;
2272 }
2273 }
2274
2275 /* If we have a script parameter, relay it to the fastagi server */
2276 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
2277 if (!ast_strlen_zero(script)) {
2278 ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
2279 }
2280
2281 ast_debug(4, "Wow, connected!\n");
2282 fds[0] = s;
2283 fds[1] = s;
2285}
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Definition: netsock2.c:595
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition: netsock2.h:517
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
Definition: netsock2.c:280
@ AST_AF_UNSPEC
Definition: netsock2.h:54
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition: netsock2.h:532
static int handle_connection(const char *agiurl, const struct ast_sockaddr addr, const int netsockfd)
Definition: res_agi.c:2172
#define AGI_PORT
Definition: res_agi.c:1567
Socket address structure.
Definition: netsock2.h:97
struct sockaddr_storage ss
Definition: netsock2.h:98
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
Definition: utils.h:1073

References AGI_PORT, AGI_RESULT_FAILURE, AGI_RESULT_SUCCESS_FAST, AST_AF_UNSPEC, ast_agi_send(), ast_connect(), ast_debug, ast_free, ast_log, ast_sockaddr_port, ast_sockaddr_resolve(), ast_sockaddr_set_port, ast_sockaddr_stringify(), ast_socket_nonblock, ast_strdupa, ast_strlen_zero(), errno, handle_connection(), LOG_WARNING, NULL, and ast_sockaddr::ss.

Referenced by launch_ha_netscript(), and launch_script().

◆ launch_script()

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

Definition at line 2360 of file res_agi.c.

2361{
2362 char tmp[256];
2363 int pid, toast[2], fromast[2], audio[2], res;
2364 struct stat st;
2365
2366 /* We should not call ast_safe_fork_cleanup() if we never call ast_safe_fork(1) */
2367 *safe_fork_called = 0;
2368
2369 if (!strncasecmp(script, "agi://", 6)) {
2370 return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2371 }
2372 if (!strncasecmp(script, "hagi://", 7)) {
2373 return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2374 }
2375 if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
2376 return launch_asyncagi(chan, argc, argv, efd);
2377 }
2378
2379 if (script[0] != '/') {
2380 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
2381 script = tmp;
2382 }
2383
2384 /* Before even trying let's see if the file actually exists */
2385 if (stat(script, &st)) {
2386 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
2387 return AGI_RESULT_NOTFOUND;
2388 }
2389
2390 if (pipe(toast)) {
2391 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
2392 return AGI_RESULT_FAILURE;
2393 }
2394 if (pipe(fromast)) {
2395 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
2396 close(toast[0]);
2397 close(toast[1]);
2398 return AGI_RESULT_FAILURE;
2399 }
2400 if (efd) {
2401 if (pipe(audio)) {
2402 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
2403 close(fromast[0]);
2404 close(fromast[1]);
2405 close(toast[0]);
2406 close(toast[1]);
2407 return AGI_RESULT_FAILURE;
2408 }
2409
2410 res = ast_fd_set_flags(audio[1], O_NONBLOCK);
2411 if (res < 0) {
2412 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
2413 close(fromast[0]);
2414 close(fromast[1]);
2415 close(toast[0]);
2416 close(toast[1]);
2417 close(audio[0]);
2418 close(audio[1]);
2419 return AGI_RESULT_FAILURE;
2420 }
2421 }
2422
2423 *safe_fork_called = 1;
2424
2425 if ((pid = ast_safe_fork(1)) < 0) {
2426 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
2427 return AGI_RESULT_FAILURE;
2428 }
2429 if (!pid) {
2430 /* Pass paths to AGI via environmental variables */
2431 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
2432 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
2433 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
2434 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
2435 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
2436 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
2437 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
2438 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
2439 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
2440 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
2441 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
2442
2443 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
2445
2446 /* Redirect stdin and out, provide enhanced audio channel if desired */
2447 dup2(fromast[0], STDIN_FILENO);
2448 dup2(toast[1], STDOUT_FILENO);
2449 if (efd)
2450 dup2(audio[0], STDERR_FILENO + 1);
2451 else
2452 close(STDERR_FILENO + 1);
2453
2454 /* Close everything but stdin/out/error */
2455 ast_close_fds_above_n(STDERR_FILENO + 1);
2456
2457 /* Execute script */
2458 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
2459 execv(script, argv);
2460 /* Can't use ast_log since FD's are closed */
2461 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
2462 /* Special case to set status of AGI to failure */
2463 fprintf(stdout, "failure\n");
2464 fflush(stdout);
2465 _exit(1);
2466 }
2467 ast_verb(3, "Launched AGI Script %s\n", script);
2468 fds[0] = toast[0];
2469 fds[1] = fromast[1];
2470 if (efd)
2471 *efd = audio[1];
2472 /* close what we're not using in the parent */
2473 close(toast[1]);
2474 close(fromast[0]);
2475
2476 if (efd)
2477 close(audio[0]);
2478
2479 *opid = pid;
2480 return AGI_RESULT_SUCCESS;
2481}
int setenv(const char *name, const char *value, int overwrite)
int ast_set_priority(int)
We set ourselves to a high priority, that we might pre-empt everything else. If your PBX has heavy ac...
Definition: asterisk.c:1851
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child.
Definition: main/app.c:3207
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: main/app.c:3202
void ast_child_verbose(int level, const char *fmt,...)
Definition: logger.c:918
const char * ast_config_AST_KEY_DIR
Definition: options.c:162
const char * ast_config_AST_MODULE_DIR
Definition: options.c:154
const char * ast_config_AST_RUN_DIR
Definition: options.c:163
const char * ast_config_AST_DATA_DIR
Definition: options.c:159
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:152
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:155
const char * ast_config_AST_AGI_DIR
Definition: options.c:161
const char * ast_config_AST_VAR_DIR
Definition: options.c:158
const char * ast_config_AST_CONFIG_FILE
Definition: options.c:153
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:156
const char * ast_config_AST_LOG_DIR
Definition: options.c:160
static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
Definition: res_agi.c:2306
static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char *argv[], int *efd)
Definition: res_agi.c:1947
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition: utils.h:1039

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_fd_set_flags, ast_log, ast_safe_fork(), ast_set_priority(), ast_verb, errno, launch_asyncagi(), launch_ha_netscript(), launch_netscript(), LOG_WARNING, NULL, and setenv().

Referenced by agi_exec_full().

◆ load_module()

static int load_module ( void  )
static

Definition at line 4890 of file res_agi.c.

4891{
4892 int err = 0;
4893
4894 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_start_type);
4895 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_end_type);
4896 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_start_type);
4897 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_exec_type);
4898 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_end_type);
4899
4906
4907 AST_TEST_REGISTER(test_agi_null_docs);
4908
4909 if (err) {
4910 unload_module();
4912 }
4913
4915}
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
static char * eapp
Definition: res_agi.c:1556
static struct ast_cli_entry cli_agi[]
Definition: res_agi.c:4825
static int eagi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4777
static char * deadapp
Definition: res_agi.c:1558
static char * app
Definition: res_agi.c:1554
static int action_add_agi_cmd(struct mansession *s, const struct message *m)
Add a new command to execute by the Async AGI application.
Definition: res_agi.c:1869
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3911
static int unload_module(void)
Definition: res_agi.c:4872
int AST_OPTIONAL_API_NAME() 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.
Definition: res_agi.c:4074
static int deadagi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4819
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
struct ast_module * self
Definition: module.h:356
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ARRAY_LEN(a)
Definition: utils.h:666

References action_add_agi_cmd(), agi_exec(), app, ARRAY_LEN, ast_agi_register_multiple(), ast_cli_register_multiple, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, AST_TEST_REGISTER, cli_agi, commands, deadagi_exec(), deadapp, eagi_exec(), eapp, EVENT_FLAG_AGI, ast_module_info::self, STASIS_MESSAGE_TYPE_INIT, and unload_module().

◆ parse_args()

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

Definition at line 4158 of file res_agi.c.

4159{
4160 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
4161 char *cur;
4162
4163 cur = s;
4164 while(*s) {
4165 switch(*s) {
4166 case '"':
4167 /* If it's escaped, put a literal quote */
4168 if (escaped)
4169 goto normal;
4170 else
4171 quoted = !quoted;
4172 if (quoted && whitespace) {
4173 /* If we're starting a quote, coming off white space start a new word, too */
4174 argv[x++] = cur;
4175 whitespace=0;
4176 }
4177 escaped = 0;
4178 break;
4179 case ' ':
4180 case '\t':
4181 if (!quoted && !escaped) {
4182 /* If we're not quoted, mark this as whitespace, and
4183 end the previous argument */
4184 whitespace = 1;
4185 *(cur++) = '\0';
4186 } else
4187 /* Otherwise, just treat it as anything else */
4188 goto normal;
4189 break;
4190 case '\\':
4191 /* If we're escaped, print a literal, otherwise enable escaping */
4192 if (escaped) {
4193 goto normal;
4194 } else {
4195 escaped=1;
4196 }
4197 break;
4198 default:
4199normal:
4200 if (whitespace) {
4201 if (x >= MAX_ARGS -1) {
4202 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
4203 break;
4204 }
4205 /* Coming off of whitespace, start the next argument */
4206 argv[x++] = cur;
4207 whitespace=0;
4208 }
4209 *(cur++) = *s;
4210 escaped=0;
4211 }
4212 s++;
4213 }
4214 /* Null terminate */
4215 *(cur++) = '\0';
4216 argv[x] = NULL;
4217 *max = x;
4218 return 0;
4219}

References ast_log, LOG_WARNING, max, MAX_ARGS, and NULL.

Referenced by agi_handle_command().

◆ publish_async_exec_end()

static void publish_async_exec_end ( struct ast_channel chan,
int  command_id,
const char *  command,
int  result_code,
const char *  result 
)
static

Definition at line 4221 of file res_agi.c.

4222{
4223 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4224 blob = ast_json_pack("{s: i, s: s, s: i, s: s}",
4225 "CommandId", command_id,
4226 "Command", command,
4227 "ResultCode", result_code,
4228 "Result", result);
4229 ast_channel_publish_cached_blob(chan, agi_exec_end_type(), blob);
4230}

References ast_channel_publish_cached_blob(), ast_json_pack(), ast_json_unref(), NULL, RAII_VAR, and result.

Referenced by agi_handle_command().

◆ run_agi()

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 4323 of file res_agi.c.

4324{
4325 struct ast_channel *c;
4326 int outfd;
4327 int ms;
4328 int needhup = 0;
4329 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
4330 struct ast_frame *f;
4331 char buf[AGI_BUF_LEN];
4332 char *res = NULL;
4333 FILE *readf;
4334 /* how many times we'll retry if ast_waitfor_nandfs will return without either
4335 channel or file descriptor in case select is interrupted by a system call (EINTR) */
4336 int retry = AGI_NANDFS_RETRY;
4337 int send_sighup;
4338 const char *sighup_str;
4339 const char *exit_on_hangup_str;
4340 int exit_on_hangup;
4341 /*! Running in an interception routine is like DeadAGI mode. No touchy the channel frames. */
4342 int in_intercept = ast_channel_get_intercept_mode();
4343
4344 ast_channel_lock(chan);
4345 sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
4346 send_sighup = !ast_false(sighup_str);
4347 exit_on_hangup_str = pbx_builtin_getvar_helper(chan, "AGIEXITONHANGUP");
4348 exit_on_hangup = ast_true(exit_on_hangup_str);
4349 ast_channel_unlock(chan);
4350
4351 if (!(readf = fdopen(agi->ctrl, "r"))) {
4352 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
4353 if (send_sighup && pid > -1)
4354 kill(pid, SIGHUP);
4355 close(agi->ctrl);
4356 return AGI_RESULT_FAILURE;
4357 }
4358
4359 setlinebuf(readf);
4360 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
4361 for (;;) {
4362 if (needhup) {
4363 needhup = 0;
4364 dead = 1;
4365 if (send_sighup) {
4366 if (pid > -1) {
4367 kill(pid, SIGHUP);
4368 } else if (agi->fast) {
4369 ast_agi_send(agi->fd, chan, "HANGUP\n");
4370 }
4371 }
4372 if (exit_on_hangup) {
4373 break;
4374 }
4375 }
4376 ms = -1;
4377 if (dead || in_intercept) {
4378 c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
4379 } else if (!ast_check_hangup(chan)) {
4380 c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
4381 } else {
4382 /*
4383 * Read the channel control queue until it is dry so we can
4384 * switch to dead mode.
4385 */
4386 c = chan;
4387 }
4388 if (c) {
4389 retry = AGI_NANDFS_RETRY;
4390 /* Idle the channel until we get a command */
4391 f = ast_read(c);
4392 if (!f) {
4393 ast_debug(1, "%s hungup\n", ast_channel_name(chan));
4394 needhup = 1;
4395 if (!returnstatus) {
4396 returnstatus = AGI_RESULT_HANGUP;
4397 }
4398 } else {
4399 /* If it's voice, write it to the audio pipe */
4400 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
4401 /* Write, ignoring errors */
4402 if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
4403 }
4404 }
4405 ast_frfree(f);
4406 }
4407 } else if (outfd > -1) {
4408 size_t len = sizeof(buf);
4409 size_t buflen = 0;
4410 enum agi_result cmd_status;
4411
4412 retry = AGI_NANDFS_RETRY;
4413 buf[0] = '\0';
4414
4415 while (len > 1) {
4416 res = fgets(buf + buflen, len, readf);
4417 if (feof(readf))
4418 break;
4419 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
4420 break;
4421 if (res != NULL && !agi->fast)
4422 break;
4423 buflen = strlen(buf);
4424 if (buflen && buf[buflen - 1] == '\n')
4425 break;
4426 len = sizeof(buf) - buflen;
4427 if (agidebug)
4428 ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
4429 }
4430
4431 if (!buf[0]) {
4432 /* Program terminated */
4433 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", ast_channel_name(chan), request, returnstatus);
4434 if (pid > 0)
4435 waitpid(pid, status, 0);
4436 /* No need to kill the pid anymore, since they closed us */
4437 pid = -1;
4438 break;
4439 }
4440
4441 /* Special case for inability to execute child process */
4442 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
4443 returnstatus = AGI_RESULT_FAILURE;
4444 break;
4445 }
4446
4447 /* get rid of trailing newline, if any */
4448 buflen = strlen(buf);
4449 if (buflen && buf[buflen - 1] == '\n') {
4450 buf[buflen - 1] = '\0';
4451 }
4452
4453 if (agidebug)
4454 ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf);
4455 cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept);
4456 switch (cmd_status) {
4457 case AGI_RESULT_FAILURE:
4458 if (dead || in_intercept || !ast_check_hangup(chan)) {
4459 /* The failure was not because of a hangup. */
4460 returnstatus = AGI_RESULT_FAILURE;
4461 }
4462 break;
4463 default:
4464 break;
4465 }
4466 } else {
4467 if (--retry <= 0) {
4468 ast_log(LOG_WARNING, "No channel, no fd?\n");
4469 returnstatus = AGI_RESULT_FAILURE;
4470 break;
4471 }
4472 }
4473 }
4474
4475 if (agi->speech) {
4477 }
4478 /* Notify process */
4479 if (send_sighup) {
4480 if (pid > -1) {
4481 if (kill(pid, SIGHUP)) {
4482 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
4483 } else { /* Give the process a chance to die */
4484 usleep(1);
4485 }
4486 waitpid(pid, status, WNOHANG);
4487 } else if (agi->fast) {
4488 ast_agi_send(agi->fd, chan, "HANGUP\n");
4489 }
4490 }
4491 fclose(readf);
4492 return returnstatus;
4493}
static int request(void *obj)
Definition: chan_pjsip.c:2605
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:2956
int ast_channel_get_intercept_mode(void)
Am I currently running an intercept dialplan routine.
Definition: channel.c:10338
#define AGI_NANDFS_RETRY
Definition: res_agi.c:1550
#define AGI_BUF_LEN
Definition: res_agi.c:1551
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

References AGI_BUF_LEN, agi_handle_command(), AGI_NANDFS_RETRY, AGI_RESULT_FAILURE, AGI_RESULT_HANGUP, AGI_RESULT_SUCCESS, agidebug, ast_agi_send(), ast_channel_get_intercept_mode(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_check_hangup(), ast_debug, ast_false(), AST_FRAME_VOICE, ast_frfree, ast_log, ast_read(), ast_speech_destroy(), ast_true(), ast_verb, ast_verbose(), ast_waitfor_nandfds(), agi_state::audio, buf, c, agi_state::ctrl, ast_frame::data, ast_frame::datalen, errno, agi_state::fast, agi_state::fd, ast_frame::frametype, len(), LOG_WARNING, NULL, pbx_builtin_getvar_helper(), ast_frame::ptr, request(), setup_env(), agi_state::speech, and status.

Referenced by agi_exec_full().

◆ setup_env()

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

Definition at line 2483 of file res_agi.c.

2484{
2485 int count;
2486
2487 /* Print initial environment, with agi_request always being the first
2488 thing */
2489 ast_agi_send(fd, chan, "agi_request: %s\n", request);
2490 ast_agi_send(fd, chan, "agi_channel: %s\n", ast_channel_name(chan));
2491 ast_agi_send(fd, chan, "agi_language: %s\n", ast_channel_language(chan));
2492 ast_agi_send(fd, chan, "agi_type: %s\n", ast_channel_tech(chan)->type);
2493 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", ast_channel_uniqueid(chan));
2494 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
2495
2496 /* ANI/DNIS */
2497 ast_agi_send(fd, chan, "agi_callerid: %s\n",
2498 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "unknown"));
2499 ast_agi_send(fd, chan, "agi_calleridname: %s\n",
2500 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "unknown"));
2501 ast_agi_send(fd, chan, "agi_callingpres: %d\n",
2503 ast_agi_send(fd, chan, "agi_callingani2: %d\n", ast_channel_caller(chan)->ani2);
2504 ast_agi_send(fd, chan, "agi_callington: %d\n", ast_channel_caller(chan)->id.number.plan);
2505 ast_agi_send(fd, chan, "agi_callingtns: %d\n", ast_channel_dialed(chan)->transit_network_select);
2506 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(ast_channel_dialed(chan)->number.str, "unknown"));
2507 ast_agi_send(fd, chan, "agi_rdnis: %s\n",
2508 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "unknown"));
2509
2510 /* Context information */
2511 ast_agi_send(fd, chan, "agi_context: %s\n", ast_channel_context(chan));
2512 ast_agi_send(fd, chan, "agi_extension: %s\n", ast_channel_exten(chan));
2513 ast_agi_send(fd, chan, "agi_priority: %d\n", ast_channel_priority(chan));
2514 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
2515
2516 /* User information */
2517 ast_agi_send(fd, chan, "agi_accountcode: %s\n", ast_channel_accountcode(chan) ? ast_channel_accountcode(chan) : "");
2518 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
2519
2520 /* Send any parameters to the fastagi server that have been passed via the agi application */
2521 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
2522 for(count = 1; count < argc; count++)
2523 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
2524
2525 /* End with empty return */
2526 ast_agi_send(fd, chan, "\n");
2527}
const char * ast_get_version(void)
Retrieve the Asterisk version string.
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1788
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_accountcode(const struct ast_channel *chan)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
static const char name[]
Definition: format_mp3.c:68

References ast_agi_send(), ast_channel_accountcode(), ast_channel_caller(), ast_channel_context(), ast_channel_dialed(), ast_channel_exten(), ast_channel_language(), ast_channel_name(), ast_channel_priority(), ast_channel_redirecting(), ast_channel_tech(), ast_channel_uniqueid(), ast_get_version(), ast_party_id_presentation(), name, request(), S_COR, S_OR, and type.

Referenced by launch_asyncagi(), and run_agi().

◆ speech_streamfile()

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

Definition at line 3739 of file res_agi.c.

3740{
3741 struct ast_filestream *fs = NULL;
3742
3743 if (!(fs = ast_openstream(chan, filename, preflang)))
3744 return -1;
3745
3746 if (offset)
3747 ast_seekstream(fs, offset, SEEK_SET);
3748
3749 if (ast_applystream(chan, fs))
3750 return -1;
3751
3752 if (ast_playstream(fs))
3753 return -1;
3754
3755 return 0;
3756}
char * filename
Definition: mod_format.h:107

References ast_applystream(), ast_openstream(), ast_playstream(), ast_seekstream(), ast_filestream::filename, and NULL.

Referenced by handle_speechrecognize().

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [1/5]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( agi_async_end_type  ,
to_ami = agi_async_end_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [2/5]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( agi_async_exec_type  ,
to_ami = agi_async_exec_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [3/5]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( agi_async_start_type  ,
to_ami = agi_async_start_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [4/5]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( agi_exec_end_type  ,
to_ami = agi_exec_end_to_ami 
)

◆ STASIS_MESSAGE_TYPE_DEFN_LOCAL() [5/5]

STASIS_MESSAGE_TYPE_DEFN_LOCAL ( agi_exec_start_type  ,
to_ami = agi_exec_start_to_ami 
)

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 4872 of file res_agi.c.

4873{
4874 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_start_type);
4875 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_end_type);
4876 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_start_type);
4877 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_exec_type);
4878 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_end_type);
4879
4886 AST_TEST_UNREGISTER(test_agi_null_docs);
4887 return 0;
4888}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int AST_OPTIONAL_API_NAME() ast_agi_unregister_multiple(struct agi_command *cmd, unsigned int len)
Unregisters a group of AGI commands, provided as an array of struct agi_command entries.
Definition: res_agi.c:4104
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References app, ARRAY_LEN, ast_agi_unregister_multiple(), ast_cli_unregister_multiple(), ast_manager_unregister(), AST_TEST_UNREGISTER, ast_unregister_application(), cli_agi, commands, deadapp, eapp, and STASIS_MESSAGE_TYPE_CLEANUP.

Referenced by load_module().

◆ write_html_escaped()

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 4595 of file res_agi.c.

4596{
4597 char *cur = str;
4598
4599 while(*cur) {
4600 switch (*cur) {
4601 case '<':
4602 fprintf(htmlfile, "%s", "&lt;");
4603 break;
4604 case '>':
4605 fprintf(htmlfile, "%s", "&gt;");
4606 break;
4607 case '&':
4608 fprintf(htmlfile, "%s", "&amp;");
4609 break;
4610 case '"':
4611 fprintf(htmlfile, "%s", "&quot;");
4612 break;
4613 default:
4614 fprintf(htmlfile, "%c", *cur);
4615 break;
4616 }
4617 cur++;
4618 }
4619
4620 return;
4621}

References str.

Referenced by write_htmldump().

◆ write_htmldump()

static int write_htmldump ( const char *  filename)
static

Definition at line 4623 of file res_agi.c.

4624{
4625 struct agi_command *command;
4626 char fullcmd[MAX_CMD_LEN];
4627 FILE *htmlfile;
4628
4629 if (!(htmlfile = fopen(filename, "wt")))
4630 return -1;
4631
4632 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
4633 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
4634 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
4635
4638 char *tempstr, *stringp;
4639
4640 if (!command->cmda[0]) /* end ? */
4641 break;
4642 /* Hide commands that start with '_' */
4643 if ((command->cmda[0])[0] == '_')
4644 continue;
4645 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
4646
4647 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
4648 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
4649#ifdef AST_XML_DOCS
4650 stringp = ast_xmldoc_printable(command->usage, 0);
4651#else
4652 stringp = ast_strdup(command->usage);
4653#endif
4654 tempstr = strsep(&stringp, "\n");
4655
4656 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
4657 write_html_escaped(htmlfile, tempstr);
4658 fprintf(htmlfile, "</TD></TR>\n");
4659 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
4660
4661 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
4662 write_html_escaped(htmlfile, tempstr);
4663 fprintf(htmlfile, "<BR>\n");
4664 }
4665 fprintf(htmlfile, "</TD></TR>\n");
4666 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
4667 ast_free(stringp);
4668 }
4670 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
4671 fclose(htmlfile);
4672 return 0;
4673}
char * strsep(char **str, const char *delims)
static void write_html_escaped(FILE *htmlfile, char *str)
Convert string to use HTML escaped characters.
Definition: res_agi.c:4595

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

Referenced by handle_cli_agi_dump_html().

Variable Documentation

◆ __mod_info

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_speech", }
static

Definition at line 4923 of file res_agi.c.

◆ agi_buf

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

Definition at line 1643 of file res_agi.c.

Referenced by ast_agi_send().

◆ agi_commands

struct agi_commands agi_commands = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
static

Referenced by add_agi_cmd(), and get_agi_cmd().

◆ agi_commands_datastore_info

const struct ast_datastore_info agi_commands_datastore_info
static
Initial value:
= {
.type = "AsyncAGI",
}
static void agi_destroy_commands_cb(void *data)
Definition: res_agi.c:1690

Definition at line 1704 of file res_agi.c.

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

◆ agidebug

int agidebug = 0
static

Definition at line 1560 of file res_agi.c.

Referenced by ast_agi_send(), handle_cli_agi_debug(), and run_agi().

◆ app

char* app = "AGI"
static

Definition at line 1554 of file res_agi.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 4923 of file res_agi.c.

◆ cli_agi

struct ast_cli_entry cli_agi[]
static

Definition at line 4825 of file res_agi.c.

Referenced by load_module(), and unload_module().

◆ commands

struct agi_command commands[]
static

AGI commands list.

Definition at line 3911 of file res_agi.c.

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

◆ deadapp

char* deadapp = "DeadAGI"
static

Definition at line 1558 of file res_agi.c.

Referenced by load_module(), and unload_module().

◆ eapp

char* eapp = "EAGI"
static

Definition at line 1556 of file res_agi.c.

Referenced by load_module(), and unload_module().