Asterisk - The Open Source Telephony Project GIT-master-43bf8a4
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   8192
 
#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 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 * 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 1610 of file res_agi.c.

◆ AGI_BUF_LEN

#define AGI_BUF_LEN   8192

Definition at line 1519 of file res_agi.c.

◆ AGI_BUF_SIZE

#define AGI_BUF_SIZE   1024

◆ AGI_NANDFS_RETRY

#define AGI_NANDFS_RETRY   3

Definition at line 1518 of file res_agi.c.

◆ AGI_PORT

#define AGI_PORT   4573

Definition at line 1533 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 1536 of file res_agi.c.

◆ MAX_AGI_CONNECT

#define MAX_AGI_CONNECT   2000

Definition at line 1531 of file res_agi.c.

◆ MAX_ARGS

#define MAX_ARGS   128

Definition at line 1516 of file res_agi.c.

◆ MAX_CMD_LEN

#define MAX_CMD_LEN   80

Definition at line 1517 of file res_agi.c.

◆ SRV_PREFIX

#define SRV_PREFIX   "_agi._tcp."

Definition at line 1520 of file res_agi.c.

◆ TONE_BLOCK_SIZE

#define TONE_BLOCK_SIZE   200

Definition at line 1528 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 1538 of file res_agi.c.

1538 {
1539 AGI_RESULT_FAILURE = -1,
1545};
@ AGI_RESULT_HANGUP
Definition: res_agi.c:1544
@ AGI_RESULT_SUCCESS
Definition: res_agi.c:1540
@ AGI_RESULT_FAILURE
Definition: res_agi.c:1539
@ AGI_RESULT_SUCCESS_ASYNC
Definition: res_agi.c:1542
@ AGI_RESULT_SUCCESS_FAST
Definition: res_agi.c:1541
@ AGI_RESULT_NOTFOUND
Definition: res_agi.c:1543

Function Documentation

◆ __init_agi_buf()

static void __init_agi_buf ( void  )
static

Definition at line 1609 of file res_agi.c.

1613{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 4881 of file res_agi.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 4881 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 1835 of file res_agi.c.

1836{
1837 const char *channel = astman_get_header(m, "Channel");
1838 const char *cmdbuff = astman_get_header(m, "Command");
1839 const char *cmdid = astman_get_header(m, "CommandID");
1840 struct ast_channel *chan;
1841 char buf[256];
1842
1843 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
1844 astman_send_error(s, m, "Both, Channel and Command are *required*");
1845 return 0;
1846 }
1847
1848 if (!(chan = ast_channel_get_by_name(channel))) {
1849 snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
1850 astman_send_error(s, m, buf);
1851 return 0;
1852 }
1853
1854 ast_channel_lock(chan);
1855
1856 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
1857 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", ast_channel_name(chan));
1858 astman_send_error(s, m, buf);
1859 ast_channel_unlock(chan);
1860 chan = ast_channel_unref(chan);
1861 return 0;
1862 }
1863
1864 ast_channel_unlock(chan);
1865 chan = ast_channel_unref(chan);
1866
1867 astman_send_ack(s, m, "Added AGI command to queue");
1868
1869 return 0;
1870}
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:1982
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2014
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1643
static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
Definition: res_agi.c:1706
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 1706 of file res_agi.c.

1707{
1708 struct ast_datastore *store;
1709 struct agi_cmd *cmd;
1711
1713 if (!store) {
1714 ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", ast_channel_name(chan));
1715 return -1;
1716 }
1717 agi_commands = store->data;
1718 cmd = ast_calloc(1, sizeof(*cmd));
1719 if (!cmd) {
1720 return -1;
1721 }
1722 cmd->cmd_buffer = ast_strdup(cmd_buff);
1723 if (!cmd->cmd_buffer) {
1724 ast_free(cmd);
1725 return -1;
1726 }
1727 cmd->cmd_id = ast_strdup(cmd_id);
1728 if (!cmd->cmd_id) {
1729 ast_free(cmd->cmd_buffer);
1730 ast_free(cmd);
1731 return -1;
1732 }
1736 return 0;
1737}
#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:1670
#define NULL
Definition: resample.c:96
char * cmd_buffer
Definition: res_agi.c:1643
char * cmd_id
Definition: res_agi.c:1644
struct agi_cmd::@428 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 1739 of file res_agi.c.

1740{
1741 struct ast_datastore *datastore;
1742 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
1743
1744 /* check if already on AGI */
1745 ast_channel_lock(chan);
1747 ast_channel_unlock(chan);
1748 if (datastore) {
1749 /* we already have an AGI datastore, let's just
1750 return success */
1751 return 0;
1752 }
1753
1754 /* the channel has never been on Async AGI,
1755 let's allocate it's datastore */
1757 if (!datastore) {
1758 return -1;
1759 }
1760 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
1761 if (!agi_cmds_list) {
1762 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
1763 ast_datastore_free(datastore);
1764 return -1;
1765 }
1766 datastore->data = agi_cmds_list;
1767 AST_LIST_HEAD_INIT(agi_cmds_list);
1768 ast_channel_lock(chan);
1769 ast_channel_datastore_add(chan, datastore);
1770 ast_channel_unlock(chan);
1771 return 0;
1772}
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 1586 of file res_agi.c.

1587{
1588 return agi_channel_to_ami("AsyncAGIEnd", message);
1589}
static struct ast_manager_event_blob * agi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: res_agi.c:1547

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

1582{
1583 return agi_channel_to_ami("AsyncAGIExec", message);
1584}

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

1577{
1578 return agi_channel_to_ami("AsyncAGIStart", message);
1579}

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

1548{
1550 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
1551 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
1552
1553 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1554 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
1555 if (!channel_string || !event_string) {
1556 return NULL;
1557 }
1558
1560 "%s"
1561 "%s",
1562 ast_str_buffer(channel_string),
1563 ast_str_buffer(event_string));
1564}
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:551
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:10141
#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:965

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

1657{
1658 struct agi_cmd *cmd;
1659 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
1660 AST_LIST_LOCK(chan_cmds);
1661 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
1662 free_agi_cmd(cmd);
1663 }
1664 AST_LIST_UNLOCK(chan_cmds);
1665 AST_LIST_HEAD_DESTROY(chan_cmds);
1666 ast_free(chan_cmds);
1667}
#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:1648

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

4736{
4737 if (!ast_check_hangup(chan))
4738 return agi_exec_full(chan, data, 0, 0);
4739 else
4740 return agi_exec_full(chan, data, 0, 1);
4741}
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:4665

References agi_exec_full(), and ast_check_hangup().

Referenced by 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 1571 of file res_agi.c.

1572{
1573 return agi_channel_to_ami("AGIExecEnd", message);
1574}

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

4666{
4667 enum agi_result res;
4668 char *buf;
4669 int fds[2], efd = -1, pid = -1;
4670 int safe_fork_called = 0;
4672 AST_APP_ARG(arg)[MAX_ARGS];
4673 );
4674 AGI agi;
4675
4676 if (ast_strlen_zero(data)) {
4677 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
4678 return -1;
4679 }
4680 if (dead)
4681 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
4682 memset(&agi, 0, sizeof(agi));
4683 buf = ast_strdupa(data);
4685 args.arg[args.argc] = NULL;
4686#if 0
4687 /* Answer if need be */
4688 if (chan->_state != AST_STATE_UP) {
4689 if (ast_answer(chan))
4690 return -1;
4691 }
4692#endif
4693 res = launch_script(chan, args.arg[0], args.argc, args.arg, fds, enhanced ? &efd : NULL, &pid, &safe_fork_called);
4694 /* Async AGI do not require run_agi(), so just proceed if normal AGI
4695 or Fast AGI are setup with success. */
4696 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
4697 int status = 0;
4698 agi.fd = fds[1];
4699 agi.ctrl = fds[0];
4700 agi.audio = efd;
4701 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
4702 res = run_agi(chan, args.arg[0], &agi, pid, &status, dead, args.argc, args.arg);
4703 /* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
4704 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
4705 res = AGI_RESULT_FAILURE;
4706 if (fds[1] != fds[0])
4707 close(fds[1]);
4708 if (efd > -1)
4709 close(efd);
4710 }
4711 if (safe_fork_called) {
4713 }
4714
4715 switch (res) {
4716 case AGI_RESULT_SUCCESS:
4719 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
4720 break;
4721 case AGI_RESULT_FAILURE:
4722 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
4723 break;
4725 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
4726 break;
4727 case AGI_RESULT_HANGUP:
4728 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
4729 return -1;
4730 }
4731
4732 return 0;
4733}
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:1516
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:2326
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:4289
agi_result
Definition: res_agi.c:1538
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 1566 of file res_agi.c.

1567{
1568 return agi_channel_to_ami("AGIExecStart", message);
1569}

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

4199{
4200 const char *argv[MAX_ARGS] = {0};
4201 int argc = MAX_ARGS;
4202 int res;
4203 agi_command *c;
4204 char *ami_cmd = ast_strdupa(buf);
4205 const char *ami_res;
4206 int command_id = ast_random();
4207 int resultcode = 0;
4208 RAII_VAR(struct ast_json *, startblob, NULL, ast_json_unref);
4209
4210 startblob = ast_json_pack("{s: i, s: s}",
4211 "CommandId", command_id,
4212 "Command", ami_cmd);
4213 ast_channel_publish_cached_blob(chan, agi_exec_start_type(), startblob);
4214
4215 parse_args(buf, &argc, argv);
4216 c = find_command(argv, 0);
4217 if (!c || !ast_module_running_ref(c->mod)) {
4218 ami_res = "Invalid or unknown command";
4219 resultcode = 510;
4220
4221 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4222
4223 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4224
4225 return AGI_RESULT_SUCCESS;
4226 }
4227
4228 if (!dead || (dead && c->dead)) {
4229 res = c->handler(chan, agi, argc, argv);
4230 switch (res) {
4231 case RESULT_SHOWUSAGE:
4232 ami_res = "Usage";
4233 resultcode = 520;
4234
4235 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4236
4237 if (ast_strlen_zero(c->usage)) {
4238 ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n");
4239 } else {
4240 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
4241 ast_agi_send(agi->fd, chan, "%s\n", c->usage);
4242 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
4243 }
4244
4245 break;
4246 case RESULT_FAILURE:
4247 ami_res = "Failure";
4248 resultcode = -1;
4249
4250 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4251
4252 /* The RESULT_FAILURE code is usually because the channel hungup. */
4253 return AGI_RESULT_FAILURE;
4254 case ASYNC_AGI_BREAK:
4255 ami_res = "Success";
4256 resultcode = 200;
4257
4258 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4259
4261 case RESULT_SUCCESS:
4262 ami_res = "Success";
4263 resultcode = 200;
4264
4265 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4266
4267 break;
4268 default:
4269 ami_res = "Unknown Result";
4270 resultcode = 200;
4271
4272 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4273
4274 break;
4275 }
4276 } else {
4277 ami_res = "Command Not Permitted on a dead channel or intercept routine";
4278 resultcode = 511;
4279
4280 ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
4281
4282 publish_async_exec_end(chan, command_id, ami_cmd, resultcode, ami_res);
4283 }
4284 ast_module_unref(c->mod);
4285
4286 return AGI_RESULT_SUCCESS;
4287}
#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:4124
static agi_command * find_command(const char *const cmds[], int exact)
Definition: res_agi.c:4086
#define ASYNC_AGI_BREAK
Definition: res_agi.c:1536
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:4187
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:1612
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 3954 of file res_agi.c.

3955{
3956 char fullcmd[MAX_CMD_LEN];
3957
3958 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
3959
3960 if (!find_command(cmd->cmda, 1)) {
3961 *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
3962 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
3963#ifdef AST_XML_DOCS
3964 *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
3965 *((char **) &cmd->since) = ast_xmldoc_build_since("agi", fullcmd, NULL);
3966 *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
3967 *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
3968 *((char **) &cmd->arguments) = ast_xmldoc_build_arguments("agi", fullcmd, NULL);
3969 *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
3970 *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
3971#endif
3972#ifndef HAVE_NULLSAFE_PRINTF
3973 if (!cmd->summary) {
3974 *((char **) &cmd->summary) = ast_strdup("");
3975 }
3976 if (!cmd->usage) {
3977 *((char **) &cmd->usage) = ast_strdup("");
3978 }
3979 if (!cmd->syntax) {
3980 *((char **) &cmd->syntax) = ast_strdup("");
3981 }
3982 if (!cmd->seealso) {
3983 *((char **) &cmd->seealso) = ast_strdup("");
3984 }
3985#endif
3986 }
3987
3988 cmd->mod = mod;
3992 ast_verb(5, "AGI Command '%s' registered\n",fullcmd);
3993 return 1;
3994 } else {
3995 ast_log(LOG_WARNING, "Command already registered!\n");
3996 return 0;
3997 }
3998}
#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:1517
#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 4040 of file res_agi.c.

4041{
4042 unsigned int i, x = 0;
4043
4044 for (i = 0; i < len; i++) {
4045 if (ast_agi_register(mod, cmd + i) == 1) {
4046 x++;
4047 continue;
4048 }
4049
4050 /* registration failed, unregister everything
4051 that had been registered up to that point
4052 */
4053 for (; x > 0; x--) {
4054 /* we are intentionally ignoring the
4055 result of ast_agi_unregister() here,
4056 but it should be safe to do so since
4057 we just registered these commands and
4058 the only possible way for unregistration
4059 to fail is if the command is not
4060 registered
4061 */
4062 (void) ast_agi_unregister(cmd + x - 1);
4063 }
4064 return -1;
4065 }
4066
4067 return 0;
4068}
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:4000
int AST_OPTIONAL_API_NAME() ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition: res_agi.c:3954

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

1613{
1614 int res = 0;
1615 va_list ap;
1616 struct ast_str *buf;
1617
1619 return -1;
1620
1621 va_start(ap, fmt);
1622 res = ast_str_set_va(&buf, 0, fmt, ap);
1623 va_end(ap);
1624
1625 if (res == -1) {
1626 ast_log(LOG_ERROR, "Out of memory\n");
1627 return -1;
1628 }
1629
1630 if (agidebug) {
1631 if (chan) {
1632 ast_verbose("<%s>AGI Tx >> %s", ast_channel_name(chan), ast_str_buffer(buf));
1633 } else {
1634 ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
1635 }
1636 }
1637
1639}
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
static struct ast_threadstorage agi_buf
Definition: res_agi.c:1609
static int agidebug
Definition: res_agi.c:1526
#define AGI_BUF_INITSIZE
Definition: res_agi.c:1610
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 4000 of file res_agi.c.

4001{
4002 struct agi_command *e;
4003 int unregistered = 0;
4004 char fullcmd[MAX_CMD_LEN];
4005
4006 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
4007
4010 if (cmd == e) {
4012#ifdef AST_XML_DOCS
4013 if (e->docsrc == AST_XML_DOC) {
4014 ast_free((char *) e->summary);
4015 ast_free((char *) e->since);
4016 ast_free((char *) e->usage);
4017 ast_free((char *) e->syntax);
4018 ast_free((char *) e->arguments);
4019 ast_free((char *) e->seealso);
4020 *((char **) &e->summary) = NULL;
4021 *((char **) &e->since) = NULL;
4022 *((char **) &e->usage) = NULL;
4023 *((char **) &e->syntax) = NULL;
4024 *((char **) &e->arguments) = NULL;
4025 *((char **) &e->seealso) = NULL;
4026 }
4027#endif
4028 unregistered=1;
4029 break;
4030 }
4031 }
4034 if (unregistered) {
4035 ast_verb(5, "AGI Command '%s' unregistered\n",fullcmd);
4036 }
4037 return unregistered;
4038}
#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::@184 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 4070 of file res_agi.c.

4071{
4072 unsigned int i;
4073 int res = 0;
4074
4075 for (i = 0; i < len; i++) {
4076 /* remember whether any of the unregistration
4077 attempts failed... there is no recourse if
4078 any of them do
4079 */
4080 res |= ast_agi_unregister(cmd + i);
4081 }
4082
4083 return res;
4084}

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

1886{
1887 struct ast_frame *f;
1888
1889 f = ast_read(chan);
1890 if (!f) {
1891 ast_debug(3, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
1892 return AGI_RESULT_HANGUP;
1893 }
1894 if (f->frametype == AST_FRAME_CONTROL) {
1895 /*
1896 * Is there any other frame we should care about besides
1897 * AST_CONTROL_HANGUP?
1898 */
1899 switch (f->subclass.integer) {
1900 case AST_CONTROL_HANGUP:
1901 ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", ast_channel_name(chan));
1902 ast_frfree(f);
1903 return AGI_RESULT_HANGUP;
1904 default:
1905 break;
1906 }
1907 }
1908 ast_frfree(f);
1909
1910 return AGI_RESULT_SUCCESS;
1911}
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4210
#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().

◆ eagi_exec()

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

Definition at line 4743 of file res_agi.c.

4744{
4745 int res;
4746 struct ast_format *readformat;
4747 struct ast_format *requested_format = NULL;
4748 const char *requested_format_name;
4749
4750 if (ast_check_hangup(chan)) {
4751 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
4752 return 0;
4753 }
4754
4755 requested_format_name = pbx_builtin_getvar_helper(chan, "EAGI_AUDIO_FORMAT");
4756 if (requested_format_name) {
4757 requested_format = ast_format_cache_get(requested_format_name);
4758 if (requested_format) {
4759 ast_verb(3, "<%s> Setting EAGI audio pipe format to %s\n",
4760 ast_channel_name(chan), ast_format_get_name(requested_format));
4761 } else {
4762 ast_log(LOG_ERROR, "Could not find requested format: %s\n", requested_format_name);
4763 }
4764 }
4765
4766 readformat = ao2_bump(ast_channel_readformat(chan));
4767 if (ast_set_read_format(chan, requested_format ?: ast_format_slin)) {
4768 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", ast_channel_name(chan));
4769 ao2_cleanup(requested_format);
4770 ao2_cleanup(readformat);
4771 return -1;
4772 }
4773 res = agi_exec_full(chan, data, 1, 0);
4774 if (!res) {
4775 if (ast_set_read_format(chan, readformat)) {
4776 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", ast_channel_name(chan),
4777 ast_format_get_name(readformat));
4778 }
4779 }
4780 ao2_cleanup(requested_format);
4781 ao2_cleanup(readformat);
4782 return res;
4783}
#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:5717
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 4086 of file res_agi.c.

4087{
4088 int y, match;
4089 struct agi_command *e;
4090
4093 if (!e->cmda[0])
4094 break;
4095 /* start optimistic */
4096 match = 1;
4097 for (y = 0; match && cmds[y]; y++) {
4098 /* If there are no more words in the command (and we're looking for
4099 an exact match) or there is a difference between the two words,
4100 then this is not a match */
4101 if (!e->cmda[y] && !exact)
4102 break;
4103 /* don't segfault if the next part of a command doesn't exist */
4104 if (!e->cmda[y]) {
4106 return NULL;
4107 }
4108 if (strcasecmp(e->cmda[y], cmds[y]))
4109 match = 0;
4110 }
4111 /* If more words are needed to complete the command then this is not
4112 a candidate (unless we're looking for a really inexact answer */
4113 if ((exact > -1) && e->cmda[y])
4114 match = 0;
4115 if (match) {
4117 return e;
4118 }
4119 }
4121 return NULL;
4122}
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 1648 of file res_agi.c.

1649{
1650 ast_free(cmd->cmd_buffer);
1651 ast_free(cmd->cmd_id);
1652 ast_free(cmd);
1653}

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

1685{
1686 struct ast_datastore *store;
1688
1689 ast_channel_lock(chan);
1691 ast_channel_unlock(chan);
1692 if (!store) {
1693 ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
1694 ast_channel_name(chan));
1695 *cmd = NULL;
1696 return -1;
1697 }
1698 agi_commands = store->data;
1702 return 0;
1703}
struct ast_datastore::@219 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 2495 of file res_agi.c.

2496{
2497 int res = 0;
2498
2499 /* Answer the channel */
2500 if (ast_channel_state(chan) != AST_STATE_UP)
2501 res = ast_answer(chan);
2502
2503 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2504 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2505}
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 2507 of file res_agi.c.

2508{
2509 ast_agi_send(agi->fd, chan, "200 result=0\n");
2510 return ASYNC_AGI_BREAK;
2511}

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

3231{
3232 double timeout;
3233 struct timeval whentohangup = { 0, 0 };
3234
3235 if (argc != 3)
3236 return RESULT_SHOWUSAGE;
3237 if (sscanf(argv[2], "%30lf", &timeout) != 1)
3238 return RESULT_SHOWUSAGE;
3239 if (timeout < 0)
3240 timeout = 0;
3241 if (timeout) {
3242 whentohangup.tv_sec = timeout;
3243 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
3244 }
3245 ast_channel_lock(chan);
3246 ast_channel_setwhentohangup_tv(chan, whentohangup);
3247 ast_channel_unlock(chan);
3248 ast_agi_send(agi->fd, chan, "200 result=0\n");
3249 return RESULT_SUCCESS;
3250}
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 3347 of file res_agi.c.

3348{
3349 if (argc == 2) {
3350 /* no argument: supply info on the current channel */
3351 ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));
3352 return RESULT_SUCCESS;
3353 } else if (argc == 3) {
3354 struct ast_channel_snapshot *snapshot;
3355
3356 /* one argument: look for info on the specified channel */
3357 snapshot = ast_channel_snapshot_get_latest_by_name(argv[2]);
3358 if (snapshot) {
3359 ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);
3360 ao2_ref(snapshot, -1);
3361 return RESULT_SUCCESS;
3362 }
3363 /* if we get this far no channel name matched the argument given */
3364 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3365 return RESULT_SUCCESS;
3366 } else {
3367 return RESULT_SHOWUSAGE;
3368 }
3369}
#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 1783 of file res_agi.c.

1784{
1785 struct ast_channel *chan;
1786 switch (cmd) {
1787 case CLI_INIT:
1788 e->command = "agi exec";
1789 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
1790 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
1791 return NULL;
1792 case CLI_GENERATE:
1793 if (a->pos == 2)
1794 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1795 return NULL;
1796 }
1797
1798 if (a->argc < 4) {
1799 return CLI_SHOWUSAGE;
1800 }
1801
1802 if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
1803 ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
1804 return CLI_FAILURE;
1805 }
1806
1807 ast_channel_lock(chan);
1808
1809 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
1810 ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", ast_channel_name(chan));
1811 ast_channel_unlock(chan);
1812 chan = ast_channel_unref(chan);
1813 return CLI_FAILURE;
1814 }
1815
1816 ast_debug(1, "Added AGI command to channel %s queue\n", ast_channel_name(chan));
1817
1818 ast_channel_unlock(chan);
1819 chan = ast_channel_unref(chan);
1820
1821 return CLI_SUCCESS;
1822}
#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 3530 of file res_agi.c.

3531{
3532 switch (cmd) {
3533 case CLI_INIT:
3534 e->command = "agi set debug [on|off]";
3535 e->usage =
3536 "Usage: agi set debug [on|off]\n"
3537 " Enables/disables dumping of AGI transactions for\n"
3538 " debugging purposes.\n";
3539 return NULL;
3540
3541 case CLI_GENERATE:
3542 return NULL;
3543 }
3544
3545 if (a->argc != e->args)
3546 return CLI_SHOWUSAGE;
3547
3548 if (strncasecmp(a->argv[3], "off", 3) == 0) {
3549 agidebug = 0;
3550 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
3551 agidebug = 1;
3552 } else {
3553 return CLI_SHOWUSAGE;
3554 }
3555 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
3556 return CLI_SUCCESS;
3557}
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 4641 of file res_agi.c.

4642{
4643 switch (cmd) {
4644 case CLI_INIT:
4645 e->command = "agi dump html";
4646 e->usage =
4647 "Usage: agi dump html <filename>\n"
4648 " Dumps the AGI command list in HTML format to the given\n"
4649 " file.\n";
4650 return NULL;
4651 case CLI_GENERATE:
4652 return NULL;
4653 }
4654 if (a->argc != e->args + 1)
4655 return CLI_SHOWUSAGE;
4656
4657 if (write_htmldump(a->argv[e->args]) < 0) {
4658 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
4659 return CLI_SHOWUSAGE;
4660 }
4661 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
4662 return CLI_SUCCESS;
4663}
static int write_htmldump(const char *filename)
Definition: res_agi.c:4589

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

4462{
4463 struct agi_command *command;
4464 char fullcmd[MAX_CMD_LEN];
4465 int error = 0;
4466
4467 switch (cmd) {
4468 case CLI_INIT:
4469 e->command = "agi show commands [topic]";
4470 e->usage =
4471 "Usage: agi show commands [topic] <topic>\n"
4472 " When called with a topic as an argument, displays usage\n"
4473 " information on the given command. If called without a\n"
4474 " topic, it provides a list of AGI commands.\n";
4475 case CLI_GENERATE:
4476 return NULL;
4477 }
4478 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
4479 return CLI_SHOWUSAGE;
4480 if (a->argc > e->args - 1) {
4481 command = find_command(a->argv + e->args, 1);
4482 if (command) {
4483 char *synopsis = NULL, *since = NULL, *description = NULL, *syntax = NULL, *arguments = NULL, *seealso = NULL;
4484
4485 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4486
4487#ifdef AST_XML_DOCS
4488 if (command->docsrc == AST_XML_DOC) {
4489 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
4490 since = ast_xmldoc_printable(S_OR(command->since, "Not available"), 1);
4491 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
4492 syntax = ast_xmldoc_printable(S_OR(command->syntax, "Not available"), 1);
4493 arguments = ast_xmldoc_printable(S_OR(command->arguments, "Not available"), 1);
4494 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
4495 } else
4496#endif
4497 {
4498 synopsis = ast_strdup(S_OR(command->summary, "Not Available"));
4499 since = ast_strdup(S_OR(command->since, "Not Available"));
4500 description = ast_strdup(S_OR(command->usage, "Not Available"));
4501 syntax = ast_strdup(S_OR(command->syntax, "Not Available"));
4502 arguments = ast_strdup(S_OR(command->arguments, "Not Available"));
4503 seealso = ast_strdup(S_OR(command->seealso, "Not Available"));
4504 }
4505
4506 if (!synopsis || !since || !description || !syntax || !arguments || !seealso) {
4507 error = 1;
4508 goto return_cleanup;
4509 }
4510
4511 ast_cli(a->fd, "\n"
4512 "%s -= Info about AGI '%s' =- %s\n\n"
4513 COLORIZE_FMT "\n"
4514 "%s\n\n"
4515 COLORIZE_FMT "\n"
4516 "%s\n\n"
4517 COLORIZE_FMT "\n"
4518 "%s\n\n"
4519 COLORIZE_FMT "\n"
4520 "%s\n\n"
4521 COLORIZE_FMT "\n"
4522 "%s\n\n"
4523 COLORIZE_FMT "\n"
4524 "%s\n\n"
4525 COLORIZE_FMT "\n"
4526 "%s\n\n",
4528 COLORIZE(COLOR_MAGENTA, 0, "[Synopsis]"), synopsis,
4529 COLORIZE(COLOR_MAGENTA, 0, "[Since]"), since,
4530 COLORIZE(COLOR_MAGENTA, 0, "[Description]"), description,
4531 COLORIZE(COLOR_MAGENTA, 0, "[Syntax]"), syntax,
4532 COLORIZE(COLOR_MAGENTA, 0, "[Arguments]"), arguments,
4533 COLORIZE(COLOR_MAGENTA, 0, "[Runs Dead]"), command->dead ? "Yes" : "No",
4534 COLORIZE(COLOR_MAGENTA, 0, "[See Also]"), seealso
4535 );
4536
4537return_cleanup:
4539 ast_free(since);
4540 ast_free(description);
4544 } else {
4545 if (find_command(a->argv + e->args, -1)) {
4546 return help_workhorse(a->fd, a->argv + e->args);
4547 } else {
4548 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
4549 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
4550 }
4551 }
4552 } else {
4553 return help_workhorse(a->fd, NULL);
4554 }
4555 return (error ? CLI_FAILURE : CLI_SUCCESS);
4556}
static char * synopsis
Definition: func_enum.c:166
static char * help_workhorse(int fd, const char *const match[])
Definition: res_agi.c:3928
#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 2138 of file res_agi.c.

2139{
2140 struct pollfd pfds[1];
2141 int res, conresult;
2142 socklen_t reslen;
2143
2144 reslen = sizeof(conresult);
2145
2146 pfds[0].fd = netsockfd;
2147 pfds[0].events = POLLOUT;
2148
2149 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
2150 if (errno != EINTR) {
2151 if (!res) {
2152 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
2153 agiurl, MAX_AGI_CONNECT);
2154 } else {
2155 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2156 }
2157
2158 return 1;
2159 }
2160 }
2161
2162 if (getsockopt(pfds[0].fd, SOL_SOCKET, SO_ERROR, &conresult, &reslen) < 0) {
2163 ast_log(LOG_WARNING, "Connection to %s failed with error: %s\n",
2164 ast_sockaddr_stringify(&addr), strerror(errno));
2165 return 1;
2166 }
2167
2168 if (conresult) {
2169 ast_log(LOG_WARNING, "Connecting to '%s' failed for url '%s': %s\n",
2170 ast_sockaddr_stringify(&addr), agiurl, strerror(conresult));
2171 return 1;
2172 }
2173
2174 return 0;
2175}
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:1531

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

2627{
2628 int res = 0, skipms = 3000;
2629 const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL; /* Default values */
2630 char stopkeybuf[2];
2631 long offsetms = 0;
2632 char offsetbuf[20];
2633
2634 if (argc < 5 || argc > 10) {
2635 return RESULT_SHOWUSAGE;
2636 }
2637
2638 if (!ast_strlen_zero(argv[4])) {
2639 stop = argv[4];
2640 }
2641
2642 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
2643 return RESULT_SHOWUSAGE;
2644 }
2645
2646 if (argc > 6 && !ast_strlen_zero(argv[6])) {
2647 fwd = argv[6];
2648 }
2649
2650 if (argc > 7 && !ast_strlen_zero(argv[7])) {
2651 rev = argv[7];
2652 }
2653
2654 if (argc > 8 && !ast_strlen_zero(argv[8])) {
2655 suspend = argv[8];
2656 }
2657
2658 if (argc > 9 && (sscanf(argv[9], "%30ld", &offsetms) != 1)) {
2659 return RESULT_SHOWUSAGE;
2660 }
2661
2662 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, &offsetms);
2663
2664 /* If we stopped on one of our stop keys, return 0 */
2665 if (res > 0 && stop && strchr(stop, res)) {
2666 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
2667 snprintf(stopkeybuf, sizeof(stopkeybuf), "%c", res);
2668 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTOPKEY", stopkeybuf);
2669 } else if (res > 0 && res == AST_CONTROL_STREAM_STOP) {
2670 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "REMOTESTOPPED");
2671 res = 0;
2672 } else {
2673 if (res < 0) {
2674 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
2675 } else {
2676 pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
2677 }
2678 }
2679
2680 snprintf(offsetbuf, sizeof(offsetbuf), "%ld", offsetms);
2681 pbx_builtin_setvar_helper(chan, "CPLAYBACKOFFSET", offsetbuf);
2682
2683 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, offsetms);
2684
2685 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2686}
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 3502 of file res_agi.c.

3503{
3504 int res;
3505
3506 if (argc != 4)
3507 return RESULT_SHOWUSAGE;
3508 res = ast_db_del(argv[2], argv[3]);
3509 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3510 return RESULT_SUCCESS;
3511}
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 3513 of file res_agi.c.

3514{
3515 int num_deleted;
3516
3517 if ((argc < 3) || (argc > 4)) {
3518 return RESULT_SHOWUSAGE;
3519 }
3520 if (argc == 4) {
3521 num_deleted = ast_db_deltree(argv[2], argv[3]);
3522 } else {
3523 num_deleted = ast_db_deltree(argv[2], NULL);
3524 }
3525
3526 ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
3527 return RESULT_SUCCESS;
3528}
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 3458 of file res_agi.c.

3459{
3460 int res;
3461 struct ast_str *buf;
3462
3463 if (argc != 4)
3464 return RESULT_SHOWUSAGE;
3465
3466 if (!(buf = ast_str_create(16))) {
3467 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3468 return RESULT_SUCCESS;
3469 }
3470
3471 do {
3472 res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
3474 if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
3475 break;
3476 }
3477 if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
3478 break;
3479 }
3480 } while (1);
3481
3482 if (res)
3483 ast_agi_send(agi->fd, chan, "200 result=0\n");
3484 else
3485 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
3486
3487 ast_free(buf);
3488 return RESULT_SUCCESS;
3489}
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 3491 of file res_agi.c.

3492{
3493 int res;
3494
3495 if (argc != 5)
3496 return RESULT_SHOWUSAGE;
3497 res = ast_db_put(argv[2], argv[3], argv[4]);
3498 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
3499 return RESULT_SUCCESS;
3500}
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 3280 of file res_agi.c.

3281{
3282 int res, workaround;
3283 struct ast_app *app_to_exec;
3284 const char *agi_exec_full_str;
3285 int agi_exec_full;
3286 struct ast_str *data_with_var = NULL;
3287
3288 if (argc < 2)
3289 return RESULT_SHOWUSAGE;
3290
3291 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
3292
3293 if ((app_to_exec = pbx_findapp(argv[1]))) {
3294 ast_channel_lock(chan);
3295 if (!(workaround = ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS))) {
3297 }
3298 agi_exec_full_str = pbx_builtin_getvar_helper(chan, "AGIEXECFULL");
3299 agi_exec_full = ast_true(agi_exec_full_str);
3300 ast_channel_unlock(chan);
3301
3302 if (agi_exec_full) {
3303 if ((data_with_var = ast_str_create(16))) {
3304 ast_str_substitute_variables(&data_with_var, 0, chan, argv[2]);
3305 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : ast_str_buffer(data_with_var));
3306 ast_free(data_with_var);
3307 } else {
3308 res = -2;
3309 }
3310 } else {
3311 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
3312 }
3313 if (!workaround) {
3315 }
3316 } else {
3317 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
3318 res = -2;
3319 }
3320 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3321
3322 /* Even though this is wrong, users are depending upon this result. */
3323 return res;
3324}
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11035
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 2965 of file res_agi.c.

2966{
2967 int res, max, timeout;
2968 char data[1024];
2969
2970 if (argc < 3)
2971 return RESULT_SHOWUSAGE;
2972 if (argc >= 4)
2973 timeout = atoi(argv[3]);
2974 else
2975 timeout = 0;
2976 if (argc >= 5)
2977 max = atoi(argv[4]);
2978 else
2979 max = 1024;
2980 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
2981 if (res == 2) /* New command */
2982 return RESULT_SUCCESS;
2983 else if (res == 1)
2984 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
2985 else if (res < 0 )
2986 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2987 else
2988 ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
2989 return RESULT_SUCCESS;
2990}
#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 2747 of file res_agi.c.

2748{
2749 int res;
2750 struct ast_filestream *fs, *vfs;
2751 long sample_offset = 0, max_length;
2752 int timeout = 0;
2753 const char *edigits = "";
2754
2755 if ( argc < 4 || argc > 5 )
2756 return RESULT_SHOWUSAGE;
2757
2758 if ( argv[3] )
2759 edigits = argv[3];
2760
2761 if ( argc == 5 )
2762 timeout = atoi(argv[4]);
2763 else if (ast_channel_pbx(chan)->dtimeoutms) {
2764 /* by default dtimeout is set to 5sec */
2765 timeout = ast_channel_pbx(chan)->dtimeoutms; /* in msec */
2766 }
2767
2768 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2769 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2770 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
2771 return RESULT_FAILURE;
2772 }
2773
2774 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan))))
2775 ast_debug(1, "Ooh, found a video stream, too\n");
2776
2777 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
2778
2779 ast_seekstream(fs, 0, SEEK_END);
2780 max_length = ast_tellstream(fs);
2781 ast_seekstream(fs, sample_offset, SEEK_SET);
2782 res = ast_applystream(chan, fs);
2783 if (vfs)
2784 ast_applystream(chan, vfs);
2785 ast_playstream(fs);
2786 if (vfs)
2788
2789 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2790 /* this is to check for if ast_waitstream closed the stream, we probably are at
2791 * the end of the stream, return that amount, else check for the amount */
2792 sample_offset = (ast_channel_stream(chan))?ast_tellstream(fs):max_length;
2793 ast_stopstream(chan);
2794 if (res == 1) {
2795 /* Stop this command, don't print a result line, as there is a new command */
2796 return RESULT_SUCCESS;
2797 }
2798
2799 /* If the user didnt press a key, wait for digitTimeout*/
2800 if (res == 0 ) {
2801 res = ast_waitfordigit_full(chan, timeout, NULL, agi->audio, agi->ctrl);
2802 /* Make sure the new result is in the escape digits of the GET OPTION */
2803 if ( !strchr(edigits,res) )
2804 res=0;
2805 }
2806
2807 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2808 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2809}
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 3384 of file res_agi.c.

3385{
3386 char *ret;
3387 char tempstr[1024] = "";
3388
3389 if (argc != 3)
3390 return RESULT_SHOWUSAGE;
3391
3392 /* check if we want to execute an ast_custom_function */
3393 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
3394 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
3395 } else {
3396 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
3397 }
3398
3399 if (ret)
3400 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
3401 else
3402 ast_agi_send(agi->fd, chan, "200 result=0\n");
3403
3404 return RESULT_SUCCESS;
3405}
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 3407 of file res_agi.c.

3408{
3409 struct ast_channel *chan2 = NULL;
3410
3411 if (argc != 4 && argc != 5) {
3412 return RESULT_SHOWUSAGE;
3413 }
3414
3415 if (argc == 5) {
3416 chan2 = ast_channel_get_by_name(argv[4]);
3417 } else {
3418 chan2 = ast_channel_ref(chan);
3419 }
3420
3421 if (chan2) {
3422 struct ast_str *str = ast_str_create(16);
3423 if (!str) {
3424 ast_agi_send(agi->fd, chan, "200 result=0\n");
3425 return RESULT_SUCCESS;
3426 }
3427 ast_str_substitute_variables(&str, 0, chan2, argv[3]);
3428 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
3429 ast_free(str);
3430 } else {
3431 ast_agi_send(agi->fd, chan, "200 result=0\n");
3432 }
3433
3434 if (chan2) {
3435 chan2 = ast_channel_unref(chan2);
3436 }
3437
3438 return RESULT_SUCCESS;
3439}
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 3252 of file res_agi.c.

3253{
3254 struct ast_channel *c;
3255
3256 if (argc == 1) {
3257 /* no argument: hangup the current channel */
3258 ast_set_hangupsource(chan, "dialplan/agi", 0);
3260 ast_agi_send(agi->fd, chan, "200 result=1\n");
3261 return RESULT_SUCCESS;
3262 } else if (argc == 2) {
3263 /* one argument: look for info on the specified channel */
3264 if ((c = ast_channel_get_by_name(argv[1]))) {
3265 /* we have a matching channel */
3266 ast_set_hangupsource(c, "dialplan/agi", 0);
3269 ast_agi_send(agi->fd, chan, "200 result=1\n");
3270 return RESULT_SUCCESS;
3271 }
3272 /* if we get this far no channel name matched the argument given */
3273 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3274 return RESULT_SUCCESS;
3275 } else {
3276 return RESULT_SHOWUSAGE;
3277 }
3278}
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168
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

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

3560{
3561 ast_agi_send(agi->fd, chan, "200 result=0\n");
3562 return RESULT_SUCCESS;
3563}

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

3031{
3032 struct ast_filestream *fs;
3033 struct ast_frame *f;
3034 struct timeval start;
3035 long sample_offset = 0;
3036 int res = 0;
3037 int ms;
3038
3039 struct ast_dsp *sildet=NULL; /* silence detector dsp */
3040 int totalsilence = 0;
3041 int dspsilence = 0;
3042 int silence = 0; /* amount of silence to allow */
3043 int gotsilence = 0; /* did we timeout for silence? */
3044 char *silencestr = NULL;
3045 RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
3046 struct ast_silence_generator *silgen = NULL;
3047
3048 /* XXX EAGI FIXME XXX */
3049
3050 if (argc < 6)
3051 return RESULT_SHOWUSAGE;
3052 if (sscanf(argv[5], "%30d", &ms) != 1)
3053 return RESULT_SHOWUSAGE;
3054
3055 if (argc > 6)
3056 silencestr = strchr(argv[6],'s');
3057 if ((argc > 7) && (!silencestr))
3058 silencestr = strchr(argv[7],'s');
3059 if ((argc > 8) && (!silencestr))
3060 silencestr = strchr(argv[8],'s');
3061
3062 if (silencestr) {
3063 if (strlen(silencestr) > 2) {
3064 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
3065 silencestr++;
3066 silencestr++;
3067 if (silencestr)
3068 silence = atoi(silencestr);
3069 if (silence > 0)
3070 silence *= 1000;
3071 }
3072 }
3073 }
3074
3075 if (silence > 0) {
3076 rfmt = ao2_bump(ast_channel_readformat(chan));
3078 if (res < 0) {
3079 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
3080 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
3081 return RESULT_FAILURE;
3082 }
3083 sildet = ast_dsp_new();
3084 if (!sildet) {
3085 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
3086 ast_agi_send(agi->fd, chan, "200 result=-1\n");
3087 return RESULT_FAILURE;
3088 }
3090 }
3091
3092 /* backward compatibility, if no offset given, arg[6] would have been
3093 * caught below and taken to be a beep, else if it is a digit then it is a
3094 * offset.
3095 *
3096 * In other words, if the argument does not look like the offset_samples
3097 * argument (a number) and it doesn't look like the silence argument (starts
3098 * with "s=") then it must be the beep argument. The beep argument has no
3099 * required value, the presence of anything in the argument slot we are
3100 * inspecting is an indication that the user wants a beep played.
3101 */
3102 if ((argc > 6 && sscanf(argv[6], "%30ld", &sample_offset) != 1 && !ast_begins_with(argv[6], "s="))
3103 || (argc > 7 && !ast_begins_with(argv[7], "s="))) {
3104 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
3105 }
3106
3107 if (!res)
3108 res = ast_waitstream(chan, argv[4]);
3109 if (res) {
3110 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
3111 } else {
3112 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
3113 if (!fs) {
3114 res = -1;
3115 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
3116 if (sildet)
3117 ast_dsp_free(sildet);
3118 return RESULT_FAILURE;
3119 }
3120
3121 /* Request a video update */
3123
3124 ast_channel_stream_set(chan, fs);
3125 ast_applystream(chan,fs);
3126 /* really should have checks */
3127 ast_seekstream(fs, sample_offset, SEEK_SET);
3128 ast_truncstream(fs);
3129
3132 }
3133
3134 start = ast_tvnow();
3135 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
3136 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
3137 if (res < 0) {
3138 ast_closestream(fs);
3139 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
3140 if (sildet)
3141 ast_dsp_free(sildet);
3142 if (silgen)
3144 return RESULT_FAILURE;
3145 }
3146 f = ast_read(chan);
3147 if (!f) {
3148 ast_closestream(fs);
3149 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
3150 if (sildet)
3151 ast_dsp_free(sildet);
3152 if (silgen)
3154 return RESULT_FAILURE;
3155 }
3156 switch(f->frametype) {
3157 case AST_FRAME_DTMF:
3158 if (strchr(argv[4], f->subclass.integer)) {
3159 /* This is an interrupting character, so rewind to chop off any small
3160 amount of DTMF that may have been recorded
3161 */
3162 ast_stream_rewind(fs, 200);
3163 ast_truncstream(fs);
3164 sample_offset = ast_tellstream(fs);
3165 ast_closestream(fs);
3166 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
3167 ast_frfree(f);
3168 if (sildet)
3169 ast_dsp_free(sildet);
3170 if (silgen)
3172 return RESULT_SUCCESS;
3173 }
3174 break;
3175 case AST_FRAME_VOICE:
3176 ast_writestream(fs, f);
3177 /* this is a safe place to check progress since we know that fs
3178 * is valid after a write, and it will then have our current
3179 * location */
3180 sample_offset = ast_tellstream(fs);
3181 if (silence > 0) {
3182 dspsilence = 0;
3183 ast_dsp_silence(sildet, f, &dspsilence);
3184 if (dspsilence) {
3185 totalsilence = dspsilence;
3186 } else {
3187 totalsilence = 0;
3188 }
3189 if (totalsilence > silence) {
3190 /* Ended happily with silence */
3191 gotsilence = 1;
3192 break;
3193 }
3194 }
3195 break;
3196 case AST_FRAME_VIDEO:
3197 ast_writestream(fs, f);
3198 default:
3199 /* Ignore all other frames */
3200 break;
3201 }
3202 ast_frfree(f);
3203 if (gotsilence)
3204 break;
3205 }
3206
3207 if (gotsilence) {
3208 ast_stream_rewind(fs, silence-1000);
3209 ast_truncstream(fs);
3210 sample_offset = ast_tellstream(fs);
3211 }
3212 ast_closestream(fs);
3213 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
3214 }
3215
3216 if (silence > 0) {
3217 res = ast_set_read_format(chan, rfmt);
3218 if (res)
3219 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(chan));
3220 ast_dsp_free(sildet);
3221 }
3222
3223 if (silgen) {
3225 }
3226
3227 return RESULT_SUCCESS;
3228}
#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:8165
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:8211
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4230
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:134
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 2545 of file res_agi.c.

2546{
2547 int res;
2548
2549 if (argc != 3)
2550 return RESULT_SHOWUSAGE;
2551
2552 res = ast_recvchar(chan,atoi(argv[2]));
2553 if (res == 0) {
2554 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
2555 return RESULT_SUCCESS;
2556 }
2557 if (res > 0) {
2558 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2559 return RESULT_SUCCESS;
2560 }
2561 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
2562 return RESULT_FAILURE;
2563}
int ast_recvchar(struct ast_channel *chan, int timeout)
Receives a text character from a channel.
Definition: channel.c:4661

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

2566{
2567 char *buf;
2568
2569 if (argc != 3)
2570 return RESULT_SHOWUSAGE;
2571
2572 buf = ast_recvtext(chan, atoi(argv[2]));
2573 if (buf) {
2574 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
2575 ast_free(buf);
2576 } else {
2577 ast_agi_send(agi->fd, chan, "200 result=-1\n");
2578 }
2579 return RESULT_SUCCESS;
2580}
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:4672

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

2848{
2849 int res;
2850 int sensitivity = AST_SAY_CASE_NONE;
2851
2852 if (argc < 4 || argc > 5) {
2853 return RESULT_SHOWUSAGE;
2854 }
2855
2856 if (argc > 4) {
2857 switch (argv[4][0]) {
2858 case 'a':
2859 case 'A':
2860 sensitivity = AST_SAY_CASE_ALL;
2861 break;
2862 case 'l':
2863 case 'L':
2864 sensitivity = AST_SAY_CASE_LOWER;
2865 break;
2866 case 'n':
2867 case 'N':
2868 sensitivity = AST_SAY_CASE_NONE;
2869 break;
2870 case 'u':
2871 case 'U':
2872 sensitivity = AST_SAY_CASE_UPPER;
2873 break;
2874 case '\0':
2875 break;
2876 default:
2877 return RESULT_SHOWUSAGE;
2878 }
2879 }
2880 res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->audio, agi->ctrl);
2881 if (res == 1) /* New command */
2882 return RESULT_SUCCESS;
2883 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2884 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2885}
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 2887 of file res_agi.c.

2888{
2889 int res, num;
2890
2891 if (argc != 4)
2892 return RESULT_SHOWUSAGE;
2893 if (sscanf(argv[2], "%30d", &num) != 1)
2894 return RESULT_SHOWUSAGE;
2895 res = ast_say_date(chan, num, argv[3], ast_channel_language(chan));
2896 if (res == 1)
2897 return RESULT_SUCCESS;
2898 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2899 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2900}
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 2917 of file res_agi.c.

2918{
2919 int res = 0;
2920 time_t unixtime;
2921 const char *format, *zone = NULL;
2922
2923 if (argc < 4)
2924 return RESULT_SHOWUSAGE;
2925
2926 if (argc > 4) {
2927 format = argv[4];
2928 } else {
2929 /* XXX this doesn't belong here, but in the 'say' module */
2930 if (!strcasecmp(ast_channel_language(chan), "de")) {
2931 format = "A dBY HMS";
2932 } else {
2933 format = "ABdY 'digits/at' IMp";
2934 }
2935 }
2936
2937 if (argc > 5 && !ast_strlen_zero(argv[5]))
2938 zone = argv[5];
2939
2940 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
2941 return RESULT_SHOWUSAGE;
2942
2943 res = ast_say_date_with_format(chan, unixtime, argv[3], ast_channel_language(chan), format, zone);
2944 if (res == 1)
2945 return RESULT_SUCCESS;
2946
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_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 2831 of file res_agi.c.

2832{
2833 int res, num;
2834
2835 if (argc != 4)
2836 return RESULT_SHOWUSAGE;
2837 if (sscanf(argv[2], "%30d", &num) != 1)
2838 return RESULT_SHOWUSAGE;
2839
2840 res = ast_say_digit_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2841 if (res == 1) /* New command */
2842 return RESULT_SUCCESS;
2843 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2844 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2845}
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 2816 of file res_agi.c.

2817{
2818 int res, num;
2819
2820 if (argc < 4 || argc > 5)
2821 return RESULT_SHOWUSAGE;
2822 if (sscanf(argv[2], "%30d", &num) != 1)
2823 return RESULT_SHOWUSAGE;
2824 res = ast_say_number_full(chan, num, argv[3], ast_channel_language(chan), argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
2825 if (res == 1)
2826 return RESULT_SUCCESS;
2827 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2828 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2829}
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 2951 of file res_agi.c.

2952{
2953 int res;
2954
2955 if (argc != 4)
2956 return RESULT_SHOWUSAGE;
2957
2958 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl);
2959 if (res == 1) /* New command */
2960 return RESULT_SUCCESS;
2961 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2962 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2963}
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 2902 of file res_agi.c.

2903{
2904 int res, num;
2905
2906 if (argc != 4)
2907 return RESULT_SHOWUSAGE;
2908 if (sscanf(argv[2], "%30d", &num) != 1)
2909 return RESULT_SHOWUSAGE;
2910 res = ast_say_time(chan, num, argv[3], ast_channel_language(chan));
2911 if (res == 1)
2912 return RESULT_SUCCESS;
2913 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2914 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2915}
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 2610 of file res_agi.c.

2611{
2612 int res;
2613
2614 if (argc != 3) {
2615 return RESULT_SHOWUSAGE;
2616 }
2617
2618 res = ast_send_image(chan, argv[2]);
2619 if (!ast_check_hangup(chan)) {
2620 res = 0;
2621 }
2622 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2623 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2624}
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 2526 of file res_agi.c.

2527{
2528 int res;
2529
2530 if (argc != 3)
2531 return RESULT_SHOWUSAGE;
2532
2533 /* At the moment, the parser (perhaps broken) returns with
2534 the last argument PLUS the newline at the end of the input
2535 buffer. This probably needs to be fixed, but I wont do that
2536 because other stuff may break as a result. The right way
2537 would probably be to strip off the trailing newline before
2538 parsing, then here, add a newline at the end of the string
2539 before sending it to ast_sendtext --DUDE */
2540 res = ast_sendtext(chan, argv[2]);
2541 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2542 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2543}
int ast_sendtext(struct ast_channel *chan, const char *text)
Sends text to a channel.
Definition: channel.c:4764

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

3327{
3328 char tmp[256]="";
3329 char *l = NULL, *n = NULL;
3330
3331 if (argv[2]) {
3332 ast_copy_string(tmp, argv[2], sizeof(tmp));
3333 ast_callerid_parse(tmp, &n, &l);
3334 if (l)
3336 else
3337 l = "";
3338 if (!n)
3339 n = "";
3340 ast_set_callerid(chan, l, n, NULL);
3341 }
3342
3343 ast_agi_send(agi->fd, chan, "200 result=1\n");
3344 return RESULT_SUCCESS;
3345}
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:7303
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 2992 of file res_agi.c.

2993{
2994
2995 if (argc != 3)
2996 return RESULT_SHOWUSAGE;
2997 ast_channel_context_set(chan, argv[2]);
2998 ast_agi_send(agi->fd, chan, "200 result=0\n");
2999 return RESULT_SUCCESS;
3000}
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 3002 of file res_agi.c.

3003{
3004 if (argc != 3)
3005 return RESULT_SHOWUSAGE;
3006 ast_channel_exten_set(chan, argv[2]);
3007 ast_agi_send(agi->fd, chan, "200 result=0\n");
3008 return RESULT_SUCCESS;
3009}
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 3565 of file res_agi.c.

3566{
3567 if (argc < 3) {
3568 return RESULT_SHOWUSAGE;
3569 }
3570 if (!strncasecmp(argv[2], "on", 2))
3571 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
3572 else if (!strncasecmp(argv[2], "off", 3))
3573 ast_moh_stop(chan);
3574 ast_agi_send(agi->fd, chan, "200 result=0\n");
3575 return RESULT_SUCCESS;
3576}
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:7735
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7745

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

3012{
3013 int pri;
3014
3015 if (argc != 3)
3016 return RESULT_SHOWUSAGE;
3017
3018 if (sscanf(argv[2], "%30d", &pri) != 1) {
3019 pri = ast_findlabel_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), argv[2],
3020 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
3021 if (pri < 1)
3022 return RESULT_SHOWUSAGE;
3023 }
3024
3025 ast_explicit_goto(chan, NULL, NULL, pri);
3026 ast_agi_send(agi->fd, chan, "200 result=0\n");
3027 return RESULT_SUCCESS;
3028}
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:4201
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6966
#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 3371 of file res_agi.c.

3372{
3373 if (argc != 4) {
3374 return RESULT_SHOWUSAGE;
3375 }
3376
3377 if (argv[3])
3378 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
3379
3380 ast_agi_send(agi->fd, chan, "200 result=1\n");
3381 return RESULT_SUCCESS;
3382}

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

3670{
3671 if (argc != 4)
3672 return RESULT_SHOWUSAGE;
3673
3674 if (!agi->speech) {
3675 ast_agi_send(agi->fd, chan, "200 result=0\n");
3676 return RESULT_SUCCESS;
3677 }
3678
3679 if (ast_speech_grammar_activate(agi->speech, argv[3]))
3680 ast_agi_send(agi->fd, chan, "200 result=0\n");
3681 else
3682 ast_agi_send(agi->fd, chan, "200 result=1\n");
3683
3684 return RESULT_SUCCESS;
3685}
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 3578 of file res_agi.c.

3579{
3580 struct ast_format_cap *cap;
3581
3582 /* If a structure already exists, return an error */
3583 if (agi->speech) {
3584 ast_agi_send(agi->fd, chan, "200 result=0\n");
3585 return RESULT_SUCCESS;
3586 }
3587
3589 return RESULT_FAILURE;
3590 }
3592 if ((agi->speech = ast_speech_new(argv[2], cap))) {
3593 ast_agi_send(agi->fd, chan, "200 result=1\n");
3594 } else {
3595 ast_agi_send(agi->fd, chan, "200 result=0\n");
3596 }
3597 ao2_ref(cap, -1);
3598
3599 return RESULT_SUCCESS;
3600}
@ 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 3687 of file res_agi.c.

3688{
3689 if (argc != 4)
3690 return RESULT_SHOWUSAGE;
3691
3692 if (!agi->speech) {
3693 ast_agi_send(agi->fd, chan, "200 result=0\n");
3694 return RESULT_SUCCESS;
3695 }
3696
3697 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
3698 ast_agi_send(agi->fd, chan, "200 result=0\n");
3699 else
3700 ast_agi_send(agi->fd, chan, "200 result=1\n");
3701
3702 return RESULT_SUCCESS;
3703}
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 3620 of file res_agi.c.

3621{
3622 if (agi->speech) {
3624 agi->speech = NULL;
3625 ast_agi_send(agi->fd, chan, "200 result=1\n");
3626 } else {
3627 ast_agi_send(agi->fd, chan, "200 result=0\n");
3628 }
3629
3630 return RESULT_SUCCESS;
3631}
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 3633 of file res_agi.c.

3634{
3635 if (argc != 5)
3636 return RESULT_SHOWUSAGE;
3637
3638 if (!agi->speech) {
3639 ast_agi_send(agi->fd, chan, "200 result=0\n");
3640 return RESULT_SUCCESS;
3641 }
3642
3643 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
3644 ast_agi_send(agi->fd, chan, "200 result=0\n");
3645 else
3646 ast_agi_send(agi->fd, chan, "200 result=1\n");
3647
3648 return RESULT_SUCCESS;
3649}
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 3724 of file res_agi.c.

3725{
3726 struct ast_speech *speech = agi->speech;
3727 const char *prompt;
3728 char dtmf = 0, tmp[4096] = "", *buf = tmp;
3729 int timeout = 0, offset = 0, res = 0, i = 0;
3730 long current_offset = 0;
3731 const char *reason = NULL;
3732 struct ast_frame *fr = NULL;
3733 struct ast_speech_result *result = NULL;
3734 size_t left = sizeof(tmp);
3735 time_t start = 0, current;
3736
3737 if (argc < 4)
3738 return RESULT_SHOWUSAGE;
3739
3740 if (!speech) {
3741 ast_agi_send(agi->fd, chan, "200 result=0\n");
3742 return RESULT_SUCCESS;
3743 }
3744
3745 prompt = argv[2];
3746 timeout = atoi(argv[3]);
3747
3748 /* If offset is specified then convert from text to integer */
3749 if (argc == 5)
3750 offset = atoi(argv[4]);
3751
3752 /* We want frames coming in signed linear */
3754 ast_agi_send(agi->fd, chan, "200 result=0\n");
3755 return RESULT_SUCCESS;
3756 }
3757
3758 /* Setup speech structure */
3759 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
3761 ast_speech_start(speech);
3762 }
3763
3764 /* Start playing prompt */
3765 speech_streamfile(chan, prompt, ast_channel_language(chan), offset);
3766
3767 /* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
3768 while (ast_strlen_zero(reason)) {
3769 /* Run scheduled items */
3771
3772 /* See maximum time of waiting */
3773 if ((res = ast_sched_wait(ast_channel_sched(chan))) < 0)
3774 res = 1000;
3775
3776 /* Wait for frame */
3777 if (ast_waitfor(chan, res) > 0) {
3778 if (!(fr = ast_read(chan))) {
3779 reason = "hangup";
3780 break;
3781 }
3782 }
3783
3784 /* Perform timeout check */
3785 if ((timeout > 0) && (start > 0)) {
3786 time(&current);
3787 if ((current - start) >= timeout) {
3788 reason = "timeout";
3789 if (fr) {
3790 ast_frfree(fr);
3791 fr = NULL;
3792 }
3793 break;
3794 }
3795 }
3796
3797 /* Check the speech structure for any changes */
3798 ast_mutex_lock(&speech->lock);
3799
3800 /* See if we need to quiet the audio stream playback */
3801 if (ast_test_flag(speech, AST_SPEECH_QUIET) && ast_channel_stream(chan)) {
3802 current_offset = ast_tellstream(ast_channel_stream(chan));
3803 ast_stopstream(chan);
3805 }
3806
3807 /* Check each state */
3808 switch (speech->state) {
3810 /* If the stream is done, start timeout calculation */
3811 if ((timeout > 0) && start == 0 && ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL))) {
3812 ast_stopstream(chan);
3813 time(&start);
3814 }
3815 /* Write audio frame data into speech engine if possible */
3816 if (fr && fr->frametype == AST_FRAME_VOICE)
3817 ast_speech_write(speech, fr->data.ptr, fr->datalen);
3818 break;
3820 /* Cue waiting sound if not already playing */
3821 if ((!ast_channel_stream(chan)) || (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL)) {
3822 ast_stopstream(chan);
3823 /* If a processing sound exists, or is not none - play it */
3824 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
3826 }
3827 break;
3829 /* Get the results */
3830 speech->results = ast_speech_results_get(speech);
3831 /* Change state to not ready */
3833 reason = "speech";
3834 break;
3835 default:
3836 break;
3837 }
3838 ast_mutex_unlock(&speech->lock);
3839
3840 /* Check frame for DTMF or hangup */
3841 if (fr) {
3842 if (fr->frametype == AST_FRAME_DTMF) {
3843 reason = "dtmf";
3844 dtmf = fr->subclass.integer;
3845 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
3846 reason = "hangup";
3847 }
3848 ast_frfree(fr);
3849 fr = NULL;
3850 }
3851 }
3852
3853 if (!strcasecmp(reason, "speech")) {
3854 /* Build string containing speech results */
3855 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
3856 /* Build result string */
3857 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);
3858 /* Increment result count */
3859 i++;
3860 }
3861 /* Print out */
3862 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
3863 } else if (!strcasecmp(reason, "dtmf")) {
3864 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
3865 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
3866 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
3867 } else {
3868 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
3869 }
3870
3871 return RESULT_SUCCESS;
3872}
static struct ast_str * prompt
Definition: asterisk.c:2795
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:3705
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::@231 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 3602 of file res_agi.c.

3603{
3604 /* Check for minimum arguments */
3605 if (argc != 4)
3606 return RESULT_SHOWUSAGE;
3607
3608 /* Check to make sure speech structure exists */
3609 if (!agi->speech) {
3610 ast_agi_send(agi->fd, chan, "200 result=0\n");
3611 return RESULT_SUCCESS;
3612 }
3613
3614 ast_speech_change(agi->speech, argv[2], argv[3]);
3615 ast_agi_send(agi->fd, chan, "200 result=1\n");
3616
3617 return RESULT_SUCCESS;
3618}
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 3651 of file res_agi.c.

3652{
3653 if (argc != 4)
3654 return RESULT_SHOWUSAGE;
3655
3656 if (!agi->speech) {
3657 ast_agi_send(agi->fd, chan, "200 result=0\n");
3658 return RESULT_SUCCESS;
3659 }
3660
3661 if (ast_speech_grammar_unload(agi->speech, argv[3]))
3662 ast_agi_send(agi->fd, chan, "200 result=0\n");
3663 else
3664 ast_agi_send(agi->fd, chan, "200 result=1\n");
3665
3666 return RESULT_SUCCESS;
3667}
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 2688 of file res_agi.c.

2689{
2690 int res;
2691 struct ast_filestream *fs, *vfs;
2692 long sample_offset = 0, max_length;
2693 const char *edigits = "";
2694
2695 if (argc < 4 || argc > 5) {
2696 return RESULT_SHOWUSAGE;
2697 }
2698
2699 if (argv[3]) {
2700 edigits = argv[3];
2701 }
2702
2703 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1)) {
2704 return RESULT_SHOWUSAGE;
2705 }
2706
2707 if (!(fs = ast_openstream(chan, argv[2], ast_channel_language(chan)))) {
2708 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
2709 return RESULT_FAILURE;
2710 }
2711
2712 if ((vfs = ast_openvstream(chan, argv[2], ast_channel_language(chan)))) {
2713 ast_debug(1, "Ooh, found a video stream, too\n");
2714 }
2715 ast_verb(3, "<%s> Playing '%s.%s' (escape_digits=%s) (sample_offset %ld) (language '%s')\n",
2717 edigits, sample_offset, S_OR(ast_channel_language(chan), "default"));
2718
2719 ast_seekstream(fs, 0, SEEK_END);
2720 max_length = ast_tellstream(fs);
2721 ast_seekstream(fs, sample_offset, SEEK_SET);
2722 res = ast_applystream(chan, fs);
2723 if (vfs) {
2724 ast_applystream(chan, vfs);
2725 }
2726 ast_playstream(fs);
2727 if (vfs) {
2729 }
2730
2731 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
2732 /* this is to check for if ast_waitstream closed the stream, we probably are at
2733 * the end of the stream, return that amount, else check for the amount */
2734 sample_offset = (ast_channel_stream(chan)) ? ast_tellstream(fs) : max_length;
2735 ast_stopstream(chan);
2736 if (res == 1) {
2737 /* Stop this command, don't print a result line, as there is a new command */
2738 return RESULT_SUCCESS;
2739 }
2740 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
2741 pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
2742
2743 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2744}
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 2582 of file res_agi.c.

2583{
2584 int res, x;
2585
2586 if (argc != 3)
2587 return RESULT_SHOWUSAGE;
2588
2589 if (!strncasecmp(argv[2],"on",2)) {
2590 x = 1;
2591 } else {
2592 x = 0;
2593 }
2594 if (!strncasecmp(argv[2],"mate",4)) {
2595 x = 2;
2596 }
2597 if (!strncasecmp(argv[2],"tdd",3)) {
2598 x = 1;
2599 }
2600 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
2601 if (res) {
2602 /* Set channel option failed */
2603 ast_agi_send(agi->fd, chan, "200 result=0\n");
2604 } else {
2605 ast_agi_send(agi->fd, chan, "200 result=1\n");
2606 }
2607 return RESULT_SUCCESS;
2608}
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:7391
#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 3441 of file res_agi.c.

3442{
3443 int level = 0;
3444
3445 if (argc < 2)
3446 return RESULT_SHOWUSAGE;
3447
3448 if (argv[2])
3449 sscanf(argv[2], "%30d", &level);
3450
3451 ast_verb(level, "%s: %s\n", ast_channel_data(chan), argv[1]);
3452
3453 ast_agi_send(agi->fd, chan, "200 result=1\n");
3454
3455 return RESULT_SUCCESS;
3456}
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 2513 of file res_agi.c.

2514{
2515 int res, to;
2516
2517 if (argc != 4)
2518 return RESULT_SHOWUSAGE;
2519 if (sscanf(argv[3], "%30d", &to) != 1)
2520 return RESULT_SHOWUSAGE;
2521 res = ast_waitfordigit_full(chan, to, NULL, agi->audio, agi->ctrl);
2522 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
2523 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
2524}

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

3929{
3930 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
3931 struct agi_command *e;
3932
3933 if (match)
3934 ast_join(matchstr, sizeof(matchstr), match);
3935
3936 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
3939 if (!e->cmda[0])
3940 break;
3941 /* Hide commands that start with '_' */
3942 if ((e->cmda[0])[0] == '_')
3943 continue;
3944 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
3945 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
3946 continue;
3947 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
3948 }
3950
3951 return CLI_SUCCESS;
3952}

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

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

2273{
2274 char *host, *script;
2275 enum agi_result result;
2276 struct srv_context *context = NULL;
2277 int srv_ret;
2278 char service[256];
2279 char resolved_uri[1024];
2280 const char *srvhost;
2281 unsigned short srvport;
2282
2283 /* format of agiurl is "hagi://host.domain[:port][/script/name]" */
2284 if (strlen(agiurl) < 7) { /* Remove hagi:// */
2285 ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
2286 return AGI_RESULT_FAILURE;
2287 }
2288 host = ast_strdupa(agiurl + 7);
2289
2290 /* Strip off any script name */
2291 if ((script = strchr(host, '/'))) {
2292 *script++ = '\0';
2293 } else {
2294 script = "";
2295 }
2296
2297 if (strchr(host, ':')) {
2298 ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
2299 return launch_netscript(agiurl + 1, argv, fds); /* +1 to strip off leading h from hagi:// */
2300 }
2301
2302 snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
2303
2304 while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
2305 snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
2306 result = launch_netscript(resolved_uri, argv, fds);
2308 ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
2309 } else {
2310 /* The script launched so we must cleanup the context. */
2312 return result;
2313 }
2314 }
2315 /*
2316 * The DNS SRV lookup failed or we ran out of servers to check.
2317 * ast_srv_lookup() has already cleaned up the context for us.
2318 */
2319 if (srv_ret < 0) {
2320 ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
2321 }
2322
2323 return AGI_RESULT_FAILURE;
2324}
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:2179
#define SRV_PREFIX
Definition: res_agi.c:1520
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 2179 of file res_agi.c.

2180{
2181 int s = 0;
2182 char *host, *script;
2183 int num_addrs = 0, i = 0;
2184 struct ast_sockaddr *addrs;
2185
2186 /* agiurl is "agi://host.domain[:port][/script/name]" */
2187 host = ast_strdupa(agiurl + 6); /* Remove agi:// */
2188
2189 /* Strip off any script name */
2190 if ((script = strchr(host, '/'))) {
2191 *script++ = '\0';
2192 } else {
2193 script = "";
2194 }
2195
2196 if (!(num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC))) {
2197 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
2198 return AGI_RESULT_FAILURE;
2199 }
2200
2201 for (i = 0; i < num_addrs; i++) {
2202 if (!ast_sockaddr_port(&addrs[i])) {
2203 ast_sockaddr_set_port(&addrs[i], AGI_PORT);
2204 }
2205
2206 if ((s = ast_socket_nonblock(addrs[i].ss.ss_family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
2207 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
2208 continue;
2209 }
2210
2211 if (ast_connect(s, &addrs[i]) && errno == EINPROGRESS) {
2212
2213 if (handle_connection(agiurl, addrs[i], s)) {
2214 close(s);
2215 continue;
2216 }
2217
2218 } else {
2219 ast_log(LOG_WARNING, "Connection to %s failed with unexpected error: %s\n",
2220 ast_sockaddr_stringify(&addrs[i]), strerror(errno));
2221 }
2222
2223 break;
2224 }
2225
2226 ast_free(addrs);
2227
2228 if (i == num_addrs) {
2229 ast_log(LOG_WARNING, "Couldn't connect to any host. FastAGI failed.\n");
2230 return AGI_RESULT_FAILURE;
2231 }
2232
2233 if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
2234 if (errno != EINTR) {
2235 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
2236 close(s);
2237 return AGI_RESULT_FAILURE;
2238 }
2239 }
2240
2241 /* If we have a script parameter, relay it to the fastagi server */
2242 /* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
2243 if (!ast_strlen_zero(script)) {
2244 ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
2245 }
2246
2247 ast_debug(4, "Wow, connected!\n");
2248 fds[0] = s;
2249 fds[1] = s;
2251}
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:2138
#define AGI_PORT
Definition: res_agi.c:1533
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:1097

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

2327{
2328 char tmp[256];
2329 int pid, toast[2], fromast[2], audio[2], res;
2330 struct stat st;
2331
2332 /* We should not call ast_safe_fork_cleanup() if we never call ast_safe_fork(1) */
2333 *safe_fork_called = 0;
2334
2335 if (!strncasecmp(script, "agi://", 6)) {
2336 return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2337 }
2338 if (!strncasecmp(script, "hagi://", 7)) {
2339 return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
2340 }
2341 if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
2342 return launch_asyncagi(chan, argc, argv, efd);
2343 }
2344
2345 if (script[0] != '/') {
2346 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
2347 script = tmp;
2348 }
2349
2350 /* Before even trying let's see if the file actually exists */
2351 if (stat(script, &st)) {
2352 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
2353 return AGI_RESULT_NOTFOUND;
2354 }
2355
2356 if (pipe(toast)) {
2357 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
2358 return AGI_RESULT_FAILURE;
2359 }
2360 if (pipe(fromast)) {
2361 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
2362 close(toast[0]);
2363 close(toast[1]);
2364 return AGI_RESULT_FAILURE;
2365 }
2366 if (efd) {
2367 if (pipe(audio)) {
2368 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
2369 close(fromast[0]);
2370 close(fromast[1]);
2371 close(toast[0]);
2372 close(toast[1]);
2373 return AGI_RESULT_FAILURE;
2374 }
2375
2376 res = ast_fd_set_flags(audio[1], O_NONBLOCK);
2377 if (res < 0) {
2378 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
2379 close(fromast[0]);
2380 close(fromast[1]);
2381 close(toast[0]);
2382 close(toast[1]);
2383 close(audio[0]);
2384 close(audio[1]);
2385 return AGI_RESULT_FAILURE;
2386 }
2387 }
2388
2389 *safe_fork_called = 1;
2390
2391 if ((pid = ast_safe_fork(1)) < 0) {
2392 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
2393 return AGI_RESULT_FAILURE;
2394 }
2395 if (!pid) {
2396 /* Pass paths to AGI via environmental variables */
2397 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
2398 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
2399 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
2400 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
2401 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
2402 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
2403 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
2404 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
2405 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
2406 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
2407 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
2408
2409 /* Don't run AGI scripts with realtime priority -- it causes audio stutter */
2411
2412 /* Redirect stdin and out, provide enhanced audio channel if desired */
2413 dup2(fromast[0], STDIN_FILENO);
2414 dup2(toast[1], STDOUT_FILENO);
2415 if (efd)
2416 dup2(audio[0], STDERR_FILENO + 1);
2417 else
2418 close(STDERR_FILENO + 1);
2419
2420 /* Close everything but stdin/out/error */
2421 ast_close_fds_above_n(STDERR_FILENO + 1);
2422
2423 /* Execute script */
2424 /* XXX argv should be deprecated in favor of passing agi_argX paramaters */
2425 execv(script, argv);
2426 /* Can't use ast_log since FD's are closed */
2427 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
2428 /* Special case to set status of AGI to failure */
2429 fprintf(stdout, "failure\n");
2430 fflush(stdout);
2431 _exit(1);
2432 }
2433 ast_verb(3, "Launched AGI Script %s\n", script);
2434 fds[0] = toast[0];
2435 fds[1] = fromast[1];
2436 if (efd)
2437 *efd = audio[1];
2438 /* close what we're not using in the parent */
2439 close(toast[1]);
2440 close(fromast[0]);
2441
2442 if (efd)
2443 close(audio[0]);
2444
2445 *opid = pid;
2446 return AGI_RESULT_SUCCESS;
2447}
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:1853
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:2272
static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char *argv[], int *efd)
Definition: res_agi.c:1913
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition: utils.h:1063

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

4850{
4851 int err = 0;
4852
4853 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_start_type);
4854 err |= STASIS_MESSAGE_TYPE_INIT(agi_exec_end_type);
4855 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_start_type);
4856 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_exec_type);
4857 err |= STASIS_MESSAGE_TYPE_INIT(agi_async_end_type);
4858
4864
4865 AST_TEST_REGISTER(test_agi_null_docs);
4866
4867 if (err) {
4868 unload_module();
4870 }
4871
4873}
#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:1524
static struct ast_cli_entry cli_agi[]
Definition: res_agi.c:4785
static int eagi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4743
static int agi_exec(struct ast_channel *chan, const char *data)
Definition: res_agi.c:4735
static char * app
Definition: res_agi.c:1522
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:1835
static struct agi_command commands[]
AGI commands list.
Definition: res_agi.c:3877
static int unload_module(void)
Definition: res_agi.c:4832
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:4040
#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:690

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

4125{
4126 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
4127 char *cur;
4128
4129 cur = s;
4130 while(*s) {
4131 switch(*s) {
4132 case '"':
4133 /* If it's escaped, put a literal quote */
4134 if (escaped)
4135 goto normal;
4136 else
4137 quoted = !quoted;
4138 if (quoted && whitespace) {
4139 /* If we're starting a quote, coming off white space start a new word, too */
4140 argv[x++] = cur;
4141 whitespace=0;
4142 }
4143 escaped = 0;
4144 break;
4145 case ' ':
4146 case '\t':
4147 if (!quoted && !escaped) {
4148 /* If we're not quoted, mark this as whitespace, and
4149 end the previous argument */
4150 whitespace = 1;
4151 *(cur++) = '\0';
4152 } else
4153 /* Otherwise, just treat it as anything else */
4154 goto normal;
4155 break;
4156 case '\\':
4157 /* If we're escaped, print a literal, otherwise enable escaping */
4158 if (escaped) {
4159 goto normal;
4160 } else {
4161 escaped=1;
4162 }
4163 break;
4164 default:
4165normal:
4166 if (whitespace) {
4167 if (x >= MAX_ARGS -1) {
4168 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
4169 break;
4170 }
4171 /* Coming off of whitespace, start the next argument */
4172 argv[x++] = cur;
4173 whitespace=0;
4174 }
4175 *(cur++) = *s;
4176 escaped=0;
4177 }
4178 s++;
4179 }
4180 /* Null terminate */
4181 *(cur++) = '\0';
4182 argv[x] = NULL;
4183 *max = x;
4184 return 0;
4185}

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

4188{
4189 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4190 blob = ast_json_pack("{s: i, s: s, s: i, s: s}",
4191 "CommandId", command_id,
4192 "Command", command,
4193 "ResultCode", result_code,
4194 "Result", result);
4195 ast_channel_publish_cached_blob(chan, agi_exec_end_type(), blob);
4196}

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 when channel is hung up. No touchy the channel frames.

Definition at line 4289 of file res_agi.c.

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

2450{
2451 int count;
2452
2453 /* Print initial environment, with agi_request always being the first
2454 thing */
2455 ast_agi_send(fd, chan, "agi_request: %s\n", request);
2456 ast_agi_send(fd, chan, "agi_channel: %s\n", ast_channel_name(chan));
2457 ast_agi_send(fd, chan, "agi_language: %s\n", ast_channel_language(chan));
2458 ast_agi_send(fd, chan, "agi_type: %s\n", ast_channel_tech(chan)->type);
2459 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", ast_channel_uniqueid(chan));
2460 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
2461
2462 /* ANI/DNIS */
2463 ast_agi_send(fd, chan, "agi_callerid: %s\n",
2464 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "unknown"));
2465 ast_agi_send(fd, chan, "agi_calleridname: %s\n",
2466 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "unknown"));
2467 ast_agi_send(fd, chan, "agi_callingpres: %d\n",
2469 ast_agi_send(fd, chan, "agi_callingani2: %d\n", ast_channel_caller(chan)->ani2);
2470 ast_agi_send(fd, chan, "agi_callington: %d\n", ast_channel_caller(chan)->id.number.plan);
2471 ast_agi_send(fd, chan, "agi_callingtns: %d\n", ast_channel_dialed(chan)->transit_network_select);
2472 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(ast_channel_dialed(chan)->number.str, "unknown"));
2473 ast_agi_send(fd, chan, "agi_rdnis: %s\n",
2474 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "unknown"));
2475
2476 /* Context information */
2477 ast_agi_send(fd, chan, "agi_context: %s\n", ast_channel_context(chan));
2478 ast_agi_send(fd, chan, "agi_extension: %s\n", ast_channel_exten(chan));
2479 ast_agi_send(fd, chan, "agi_priority: %d\n", ast_channel_priority(chan));
2480 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
2481
2482 /* User information */
2483 ast_agi_send(fd, chan, "agi_accountcode: %s\n", ast_channel_accountcode(chan) ? ast_channel_accountcode(chan) : "");
2484 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
2485
2486 /* Send any parameters to the fastagi server that have been passed via the agi application */
2487 /* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
2488 for(count = 1; count < argc; count++)
2489 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
2490
2491 /* End with empty return */
2492 ast_agi_send(fd, chan, "\n");
2493}
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 3705 of file res_agi.c.

3706{
3707 struct ast_filestream *fs = NULL;
3708
3709 if (!(fs = ast_openstream(chan, filename, preflang)))
3710 return -1;
3711
3712 if (offset)
3713 ast_seekstream(fs, offset, SEEK_SET);
3714
3715 if (ast_applystream(chan, fs))
3716 return -1;
3717
3718 if (ast_playstream(fs))
3719 return -1;
3720
3721 return 0;
3722}
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 4832 of file res_agi.c.

4833{
4834 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_start_type);
4835 STASIS_MESSAGE_TYPE_CLEANUP(agi_exec_end_type);
4836 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_start_type);
4837 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_exec_type);
4838 STASIS_MESSAGE_TYPE_CLEANUP(agi_async_end_type);
4839
4845 AST_TEST_UNREGISTER(test_agi_null_docs);
4846 return 0;
4847}
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:7695
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:4070
#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, 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 4561 of file res_agi.c.

4562{
4563 char *cur = str;
4564
4565 while(*cur) {
4566 switch (*cur) {
4567 case '<':
4568 fprintf(htmlfile, "%s", "&lt;");
4569 break;
4570 case '>':
4571 fprintf(htmlfile, "%s", "&gt;");
4572 break;
4573 case '&':
4574 fprintf(htmlfile, "%s", "&amp;");
4575 break;
4576 case '"':
4577 fprintf(htmlfile, "%s", "&quot;");
4578 break;
4579 default:
4580 fprintf(htmlfile, "%c", *cur);
4581 break;
4582 }
4583 cur++;
4584 }
4585
4586 return;
4587}

References str.

Referenced by write_htmldump().

◆ write_htmldump()

static int write_htmldump ( const char *  filename)
static

Definition at line 4589 of file res_agi.c.

4590{
4591 struct agi_command *command;
4592 char fullcmd[MAX_CMD_LEN];
4593 FILE *htmlfile;
4594
4595 if (!(htmlfile = fopen(filename, "wt")))
4596 return -1;
4597
4598 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
4599 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
4600 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
4601
4604 char *tempstr, *stringp;
4605
4606 if (!command->cmda[0]) /* end ? */
4607 break;
4608 /* Hide commands that start with '_' */
4609 if ((command->cmda[0])[0] == '_')
4610 continue;
4611 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
4612
4613 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
4614 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
4615#ifdef AST_XML_DOCS
4616 stringp = ast_xmldoc_printable(command->usage, 0);
4617#else
4618 stringp = ast_strdup(command->usage);
4619#endif
4620 tempstr = strsep(&stringp, "\n");
4621
4622 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
4623 write_html_escaped(htmlfile, tempstr);
4624 fprintf(htmlfile, "</TD></TR>\n");
4625 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
4626
4627 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
4628 write_html_escaped(htmlfile, tempstr);
4629 fprintf(htmlfile, "<BR>\n");
4630 }
4631 fprintf(htmlfile, "</TD></TR>\n");
4632 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
4633 ast_free(stringp);
4634 }
4636 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
4637 fclose(htmlfile);
4638 return 0;
4639}
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:4561

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 4881 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 1609 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:1656

Definition at line 1670 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 1526 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 1522 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 4881 of file res_agi.c.

◆ cli_agi

struct ast_cli_entry cli_agi[]
static

Definition at line 4785 of file res_agi.c.

Referenced by load_module(), and unload_module().

◆ commands

struct agi_command commands[]
static

AGI commands list.

Definition at line 3877 of file res_agi.c.

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

◆ eapp

char* eapp = "EAGI"
static

Definition at line 1524 of file res_agi.c.

Referenced by load_module(), and unload_module().