00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 302548 $")
00031
00032 #include <math.h>
00033 #include <signal.h>
00034 #include <sys/time.h>
00035 #include <sys/wait.h>
00036 #include <sys/stat.h>
00037 #include <pthread.h>
00038
00039 #include "asterisk/paths.h"
00040 #include "asterisk/network.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/astdb.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/cli.h"
00048 #include "asterisk/image.h"
00049 #include "asterisk/say.h"
00050 #include "asterisk/app.h"
00051 #include "asterisk/dsp.h"
00052 #include "asterisk/musiconhold.h"
00053 #include "asterisk/utils.h"
00054 #include "asterisk/lock.h"
00055 #include "asterisk/strings.h"
00056 #include "asterisk/manager.h"
00057 #include "asterisk/ast_version.h"
00058 #include "asterisk/speech.h"
00059 #include "asterisk/manager.h"
00060 #include "asterisk/features.h"
00061 #include "asterisk/term.h"
00062 #include "asterisk/xmldoc.h"
00063
00064 #define AST_API_MODULE
00065 #include "asterisk/agi.h"
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 #define MAX_ARGS 128
00318 #define MAX_CMD_LEN 80
00319 #define AGI_NANDFS_RETRY 3
00320 #define AGI_BUF_LEN 2048
00321
00322 static char *app = "AGI";
00323
00324 static char *eapp = "EAGI";
00325
00326 static char *deadapp = "DeadAGI";
00327
00328 static char *synopsis = "Executes an AGI compliant application";
00329 static char *esynopsis = "Executes an EAGI compliant application";
00330 static char *deadsynopsis = "Executes AGI on a hungup channel";
00331
00332 static char *descrip =
00333 " [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant\n"
00334 "program on a channel. AGI allows Asterisk to launch external programs written\n"
00335 "in any language to control a telephony channel, play audio, read DTMF digits,\n"
00336 "etc. by communicating with the AGI protocol on stdin and stdout.\n"
00337 " As of 1.6.0, this channel will not stop dialplan execution on hangup inside\n"
00338 "of this application. Dialplan execution will continue normally, even upon\n"
00339 "hangup until the AGI application signals a desire to stop (either by exiting\n"
00340 "or, in the case of a net script, by closing the connection).\n"
00341 " A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
00342 "except when using DeadAGI. A fast AGI server will correspondingly receive a\n"
00343 "HANGUP inline with the command dialog. Both of these signals may be disabled\n"
00344 "by setting the AGISIGHUP channel variable to \"no\" before executing the AGI\n"
00345 "application.\n"
00346 " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
00347 "on file descriptor 3.\n\n"
00348 " Use the CLI command 'agi show commands' to list available agi commands.\n"
00349 " This application sets the following channel variable upon completion:\n"
00350 " AGISTATUS The status of the attempt to the run the AGI script\n"
00351 " text string, one of SUCCESS | FAILURE | NOTFOUND | HANGUP\n";
00352
00353 static int agidebug = 0;
00354
00355 #define TONE_BLOCK_SIZE 200
00356
00357
00358 #define MAX_AGI_CONNECT 2000
00359
00360 #define AGI_PORT 4573
00361
00362 enum agi_result {
00363 AGI_RESULT_FAILURE = -1,
00364 AGI_RESULT_SUCCESS,
00365 AGI_RESULT_SUCCESS_FAST,
00366 AGI_RESULT_SUCCESS_ASYNC,
00367 AGI_RESULT_NOTFOUND,
00368 AGI_RESULT_HANGUP,
00369 };
00370
00371 static agi_command *find_command(char *cmds[], int exact);
00372
00373 AST_THREADSTORAGE(agi_buf);
00374 #define AGI_BUF_INITSIZE 256
00375
00376 int ast_agi_send(int fd, struct ast_channel *chan, char *fmt, ...)
00377 {
00378 int res = 0;
00379 va_list ap;
00380 struct ast_str *buf;
00381
00382 if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
00383 return -1;
00384
00385 va_start(ap, fmt);
00386 res = ast_str_set_va(&buf, 0, fmt, ap);
00387 va_end(ap);
00388
00389 if (res == -1) {
00390 ast_log(LOG_ERROR, "Out of memory\n");
00391 return -1;
00392 }
00393
00394 if (agidebug) {
00395 if (chan) {
00396 ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf));
00397 } else {
00398 ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
00399 }
00400 }
00401
00402 return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
00403 }
00404
00405
00406 struct agi_cmd {
00407 char *cmd_buffer;
00408 char *cmd_id;
00409 AST_LIST_ENTRY(agi_cmd) entry;
00410 };
00411
00412 static void free_agi_cmd(struct agi_cmd *cmd)
00413 {
00414 ast_free(cmd->cmd_buffer);
00415 ast_free(cmd->cmd_id);
00416 ast_free(cmd);
00417 }
00418
00419
00420 static void agi_destroy_commands_cb(void *data)
00421 {
00422 struct agi_cmd *cmd;
00423 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
00424 AST_LIST_LOCK(chan_cmds);
00425 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
00426 free_agi_cmd(cmd);
00427 }
00428 AST_LIST_UNLOCK(chan_cmds);
00429 AST_LIST_HEAD_DESTROY(chan_cmds);
00430 ast_free(chan_cmds);
00431 }
00432
00433
00434 static const struct ast_datastore_info agi_commands_datastore_info = {
00435 .type = "AsyncAGI",
00436 .destroy = agi_destroy_commands_cb
00437 };
00438
00439 static const char mandescr_asyncagi[] =
00440 "Description: Add an AGI command to the execute queue of the channel in Async AGI\n"
00441 "Variables:\n"
00442 " *Channel: Channel that is currently in Async AGI\n"
00443 " *Command: Application to execute\n"
00444 " CommandID: command id. This will be sent back in CommandID header of AsyncAGI exec event notification\n"
00445 "\n";
00446
00447 static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
00448 {
00449 struct ast_datastore *store;
00450 struct agi_cmd *cmd;
00451 AST_LIST_HEAD(, agi_cmd) *agi_commands;
00452
00453 ast_channel_lock(chan);
00454 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
00455 ast_channel_unlock(chan);
00456 if (!store) {
00457 ast_log(LOG_ERROR, "Hu? datastore disappeared at Async AGI on Channel %s!\n", chan->name);
00458 return NULL;
00459 }
00460 agi_commands = store->data;
00461 AST_LIST_LOCK(agi_commands);
00462 cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
00463 AST_LIST_UNLOCK(agi_commands);
00464 return cmd;
00465 }
00466
00467
00468 static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
00469 {
00470 struct ast_datastore *store;
00471 struct agi_cmd *cmd;
00472 AST_LIST_HEAD(, agi_cmd) *agi_commands;
00473
00474 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
00475 if (!store) {
00476 ast_log(LOG_WARNING, "Channel %s is not at Async AGI.\n", chan->name);
00477 return -1;
00478 }
00479 agi_commands = store->data;
00480 cmd = ast_calloc(1, sizeof(*cmd));
00481 if (!cmd) {
00482 return -1;
00483 }
00484 cmd->cmd_buffer = ast_strdup(cmd_buff);
00485 if (!cmd->cmd_buffer) {
00486 ast_free(cmd);
00487 return -1;
00488 }
00489 cmd->cmd_id = ast_strdup(cmd_id);
00490 if (!cmd->cmd_id) {
00491 ast_free(cmd->cmd_buffer);
00492 ast_free(cmd);
00493 return -1;
00494 }
00495 AST_LIST_LOCK(agi_commands);
00496 AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
00497 AST_LIST_UNLOCK(agi_commands);
00498 return 0;
00499 }
00500
00501 static int add_to_agi(struct ast_channel *chan)
00502 {
00503 struct ast_datastore *datastore;
00504 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
00505
00506
00507 ast_channel_lock(chan);
00508 datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
00509 ast_channel_unlock(chan);
00510 if (datastore) {
00511
00512
00513 return 0;
00514 }
00515
00516
00517
00518 datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI");
00519 if (!datastore) {
00520 return -1;
00521 }
00522 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
00523 if (!agi_cmds_list) {
00524 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
00525 ast_datastore_free(datastore);
00526 return -1;
00527 }
00528 datastore->data = agi_cmds_list;
00529 AST_LIST_HEAD_INIT(agi_cmds_list);
00530 ast_channel_lock(chan);
00531 ast_channel_datastore_add(chan, datastore);
00532 ast_channel_unlock(chan);
00533 return 0;
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00546 {
00547 struct ast_channel *chan;
00548 switch (cmd) {
00549 case CLI_INIT:
00550 e->command = "agi exec";
00551 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
00552 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
00553 return NULL;
00554 case CLI_GENERATE:
00555 if (a->pos == 2)
00556 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
00557 return NULL;
00558 }
00559
00560 if (a->argc < 4)
00561 return CLI_SHOWUSAGE;
00562 chan = ast_get_channel_by_name_locked(a->argv[2]);
00563 if (!chan) {
00564 ast_log(LOG_WARNING, "Channel %s does not exists or cannot lock it\n", a->argv[2]);
00565 return CLI_FAILURE;
00566 }
00567 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
00568 ast_log(LOG_WARNING, "failed to add AGI command to queue of channel %s\n", chan->name);
00569 ast_channel_unlock(chan);
00570 return CLI_FAILURE;
00571 }
00572 ast_log(LOG_DEBUG, "Added AGI command to channel %s queue\n", chan->name);
00573 ast_channel_unlock(chan);
00574 return CLI_SUCCESS;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
00589 {
00590 const char *channel = astman_get_header(m, "Channel");
00591 const char *cmdbuff = astman_get_header(m, "Command");
00592 const char *cmdid = astman_get_header(m, "CommandID");
00593 struct ast_channel *chan;
00594 char buf[256];
00595 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
00596 astman_send_error(s, m, "Both, Channel and Command are *required*");
00597 return 0;
00598 }
00599 chan = ast_get_channel_by_name_locked(channel);
00600 if (!chan) {
00601 snprintf(buf, sizeof(buf), "Channel %s does not exists or cannot get its lock", channel);
00602 astman_send_error(s, m, buf);
00603 return 0;
00604 }
00605 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
00606 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
00607 astman_send_error(s, m, buf);
00608 ast_channel_unlock(chan);
00609 return 0;
00610 }
00611 astman_send_ack(s, m, "Added AGI command to queue");
00612 ast_channel_unlock(chan);
00613 return 0;
00614 }
00615
00616 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
00617 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
00618 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
00619 {
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 #define AGI_BUF_SIZE 1024
00638 #define AMI_BUF_SIZE 2048
00639 struct ast_frame *f;
00640 struct agi_cmd *cmd;
00641 int res, fds[2];
00642 int timeout = 100;
00643 char agi_buffer[AGI_BUF_SIZE + 1];
00644 char ami_buffer[AMI_BUF_SIZE];
00645 enum agi_result returnstatus = AGI_RESULT_SUCCESS_ASYNC;
00646 AGI async_agi;
00647
00648 if (efd) {
00649 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
00650 return AGI_RESULT_FAILURE;
00651 }
00652
00653
00654 if (add_to_agi(chan)) {
00655 ast_log(LOG_ERROR, "failed to start Async AGI on channel %s\n", chan->name);
00656 return AGI_RESULT_FAILURE;
00657 }
00658
00659
00660
00661 res = pipe(fds);
00662 if (res) {
00663 ast_log(LOG_ERROR, "failed to create Async AGI pipe\n");
00664
00665
00666
00667 return AGI_RESULT_FAILURE;
00668 }
00669
00670
00671
00672 async_agi.fd = fds[1];
00673 async_agi.ctrl = fds[1];
00674 async_agi.audio = -1;
00675 async_agi.fast = 0;
00676 async_agi.speech = NULL;
00677
00678
00679
00680 setup_env(chan, "async", fds[1], 0, 0, NULL);
00681
00682 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
00683 if (!res) {
00684 ast_log(LOG_ERROR, "failed to read from Async AGI pipe on channel %s\n", chan->name);
00685 returnstatus = AGI_RESULT_FAILURE;
00686 goto quit;
00687 }
00688 agi_buffer[res] = '\0';
00689
00690
00691
00692 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
00693 manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Start\r\nChannel: %s\r\nEnv: %s\r\n", chan->name, ami_buffer);
00694 while (1) {
00695
00696 if (ast_check_hangup(chan)) {
00697 ast_log(LOG_DEBUG, "ast_check_hangup returned true on chan %s\n", chan->name);
00698 break;
00699 }
00700
00701
00702 cmd = get_agi_cmd(chan);
00703 if (cmd) {
00704
00705
00706 res = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
00707 if (res < 0) {
00708 free_agi_cmd(cmd);
00709 break;
00710 }
00711
00712
00713 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
00714 if (!res) {
00715 returnstatus = AGI_RESULT_FAILURE;
00716 ast_log(LOG_ERROR, "failed to read from AsyncAGI pipe on channel %s\n", chan->name);
00717 free_agi_cmd(cmd);
00718 break;
00719 }
00720
00721
00722
00723 agi_buffer[res] = '\0';
00724 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
00725 if (ast_strlen_zero(cmd->cmd_id))
00726 manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nResult: %s\r\n", chan->name, ami_buffer);
00727 else
00728 manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: Exec\r\nChannel: %s\r\nCommandID: %s\r\nResult: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
00729 free_agi_cmd(cmd);
00730 } else {
00731
00732 res = ast_waitfor(chan, timeout);
00733 if (res < 0) {
00734 ast_log(LOG_DEBUG, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
00735 break;
00736 }
00737 if (res == 0)
00738 continue;
00739 f = ast_read(chan);
00740 if (!f) {
00741 ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
00742 returnstatus = AGI_RESULT_HANGUP;
00743 break;
00744 }
00745
00746
00747 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
00748 ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
00749 ast_frfree(f);
00750 break;
00751 }
00752 ast_frfree(f);
00753 }
00754 }
00755
00756 if (async_agi.speech) {
00757 ast_speech_destroy(async_agi.speech);
00758 }
00759 quit:
00760
00761
00762 manager_event(EVENT_FLAG_AGI, "AsyncAGI", "SubEvent: End\r\nChannel: %s\r\n", chan->name);
00763
00764
00765 close(fds[0]);
00766 close(fds[1]);
00767
00768
00769
00770
00771
00772 return returnstatus;
00773
00774 #undef AGI_BUF_SIZE
00775 #undef AMI_BUF_SIZE
00776 }
00777
00778
00779
00780 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
00781 {
00782 int s, flags, res, port = AGI_PORT;
00783 struct pollfd pfds[1];
00784 char *host, *c, *script = "";
00785 struct sockaddr_in addr_in;
00786 struct hostent *hp;
00787 struct ast_hostent ahp;
00788
00789
00790 host = ast_strdupa(agiurl + 6);
00791
00792 if ((c = strchr(host, '/'))) {
00793 *c = '\0';
00794 c++;
00795 script = c;
00796 }
00797 if ((c = strchr(host, ':'))) {
00798 *c = '\0';
00799 c++;
00800 port = atoi(c);
00801 }
00802 if (efd) {
00803 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
00804 return -1;
00805 }
00806 if (!(hp = ast_gethostbyname(host, &ahp))) {
00807 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
00808 return -1;
00809 }
00810 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00811 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
00812 return -1;
00813 }
00814 if ((flags = fcntl(s, F_GETFL)) < 0) {
00815 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
00816 close(s);
00817 return -1;
00818 }
00819 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
00820 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
00821 close(s);
00822 return -1;
00823 }
00824 memset(&addr_in, 0, sizeof(addr_in));
00825 addr_in.sin_family = AF_INET;
00826 addr_in.sin_port = htons(port);
00827 memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr));
00828 if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) {
00829 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
00830 close(s);
00831 return AGI_RESULT_FAILURE;
00832 }
00833
00834 pfds[0].fd = s;
00835 pfds[0].events = POLLOUT;
00836 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
00837 if (errno != EINTR) {
00838 if (!res) {
00839 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
00840 agiurl, MAX_AGI_CONNECT);
00841 } else
00842 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
00843 close(s);
00844 return AGI_RESULT_FAILURE;
00845 }
00846 }
00847
00848 if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
00849 if (errno != EINTR) {
00850 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
00851 close(s);
00852 return AGI_RESULT_FAILURE;
00853 }
00854 }
00855
00856
00857
00858 if (!ast_strlen_zero(script))
00859 ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
00860
00861 ast_debug(4, "Wow, connected!\n");
00862 fds[0] = s;
00863 fds[1] = s;
00864 *opid = -1;
00865 return AGI_RESULT_SUCCESS_FAST;
00866 }
00867
00868 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
00869 {
00870 char tmp[256];
00871 int pid, toast[2], fromast[2], audio[2], res;
00872 struct stat st;
00873
00874 if (!strncasecmp(script, "agi://", 6))
00875 return launch_netscript(script, argv, fds, efd, opid);
00876 if (!strncasecmp(script, "agi:async", sizeof("agi:async")-1))
00877 return launch_asyncagi(chan, argv, efd);
00878
00879 if (script[0] != '/') {
00880 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
00881 script = tmp;
00882 }
00883
00884
00885 if (stat(script, &st)) {
00886 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
00887 return AGI_RESULT_NOTFOUND;
00888 }
00889
00890 if (pipe(toast)) {
00891 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
00892 return AGI_RESULT_FAILURE;
00893 }
00894 if (pipe(fromast)) {
00895 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
00896 close(toast[0]);
00897 close(toast[1]);
00898 return AGI_RESULT_FAILURE;
00899 }
00900 if (efd) {
00901 if (pipe(audio)) {
00902 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
00903 close(fromast[0]);
00904 close(fromast[1]);
00905 close(toast[0]);
00906 close(toast[1]);
00907 return AGI_RESULT_FAILURE;
00908 }
00909 res = fcntl(audio[1], F_GETFL);
00910 if (res > -1)
00911 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
00912 if (res < 0) {
00913 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
00914 close(fromast[0]);
00915 close(fromast[1]);
00916 close(toast[0]);
00917 close(toast[1]);
00918 close(audio[0]);
00919 close(audio[1]);
00920 return AGI_RESULT_FAILURE;
00921 }
00922 }
00923
00924 if ((pid = ast_safe_fork(1)) < 0) {
00925 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
00926 return AGI_RESULT_FAILURE;
00927 }
00928 if (!pid) {
00929
00930 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
00931 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
00932 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
00933 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
00934 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
00935 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
00936 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
00937 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
00938 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
00939 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
00940 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
00941
00942
00943 ast_set_priority(0);
00944
00945
00946 dup2(fromast[0], STDIN_FILENO);
00947 dup2(toast[1], STDOUT_FILENO);
00948 if (efd)
00949 dup2(audio[0], STDERR_FILENO + 1);
00950 else
00951 close(STDERR_FILENO + 1);
00952
00953
00954 ast_close_fds_above_n(STDERR_FILENO + 1);
00955
00956
00957
00958 execv(script, argv);
00959
00960 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
00961
00962 fprintf(stdout, "failure\n");
00963 fflush(stdout);
00964 _exit(1);
00965 }
00966 ast_verb(3, "Launched AGI Script %s\n", script);
00967 fds[0] = toast[0];
00968 fds[1] = fromast[1];
00969 if (efd)
00970 *efd = audio[1];
00971
00972 close(toast[1]);
00973 close(fromast[0]);
00974
00975 if (efd)
00976 close(audio[0]);
00977
00978 *opid = pid;
00979 return AGI_RESULT_SUCCESS;
00980 }
00981
00982 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
00983 {
00984 int count;
00985
00986
00987
00988 ast_agi_send(fd, chan, "agi_request: %s\n", request);
00989 ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name);
00990 ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
00991 ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
00992 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
00993 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
00994
00995
00996 ast_agi_send(fd, chan, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
00997 ast_agi_send(fd, chan, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
00998 ast_agi_send(fd, chan, "agi_callingpres: %d\n", chan->cid.cid_pres);
00999 ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->cid.cid_ani2);
01000 ast_agi_send(fd, chan, "agi_callington: %d\n", chan->cid.cid_ton);
01001 ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->cid.cid_tns);
01002 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
01003 ast_agi_send(fd, chan, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
01004
01005
01006 ast_agi_send(fd, chan, "agi_context: %s\n", chan->context);
01007 ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten);
01008 ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority);
01009 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
01010
01011
01012 ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
01013 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
01014
01015
01016
01017 for(count = 1; count < argc; count++)
01018 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
01019
01020
01021 ast_agi_send(fd, chan, "\n");
01022 }
01023
01024 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01025 {
01026 int res = 0;
01027
01028
01029 if (chan->_state != AST_STATE_UP)
01030 res = ast_answer(chan);
01031
01032 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01033 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01034 }
01035
01036 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01037 {
01038 ast_agi_send(agi->fd, chan, "200 result=0\n");
01039 return RESULT_FAILURE;
01040 }
01041
01042 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01043 {
01044 int res, to;
01045
01046 if (argc != 4)
01047 return RESULT_SHOWUSAGE;
01048 if (sscanf(argv[3], "%30d", &to) != 1)
01049 return RESULT_SHOWUSAGE;
01050 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
01051 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01052 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01053 }
01054
01055 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01056 {
01057 int res;
01058
01059 if (argc != 3)
01060 return RESULT_SHOWUSAGE;
01061
01062
01063
01064
01065
01066
01067
01068
01069 res = ast_sendtext(chan, argv[2]);
01070 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01071 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01072 }
01073
01074 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01075 {
01076 int res;
01077
01078 if (argc != 3)
01079 return RESULT_SHOWUSAGE;
01080
01081 res = ast_recvchar(chan,atoi(argv[2]));
01082 if (res == 0) {
01083 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
01084 return RESULT_SUCCESS;
01085 }
01086 if (res > 0) {
01087 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01088 return RESULT_SUCCESS;
01089 }
01090 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
01091 return RESULT_FAILURE;
01092 }
01093
01094 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01095 {
01096 char *buf;
01097
01098 if (argc != 3)
01099 return RESULT_SHOWUSAGE;
01100
01101 buf = ast_recvtext(chan, atoi(argv[2]));
01102 if (buf) {
01103 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
01104 ast_free(buf);
01105 } else {
01106 ast_agi_send(agi->fd, chan, "200 result=-1\n");
01107 }
01108 return RESULT_SUCCESS;
01109 }
01110
01111 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01112 {
01113 int res, x;
01114
01115 if (argc != 3)
01116 return RESULT_SHOWUSAGE;
01117
01118 if (!strncasecmp(argv[2],"on",2)) {
01119 x = 1;
01120 } else {
01121 x = 0;
01122 }
01123 if (!strncasecmp(argv[2],"mate",4)) {
01124 x = 2;
01125 }
01126 if (!strncasecmp(argv[2],"tdd",3)) {
01127 x = 1;
01128 }
01129 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
01130 if (res != RESULT_SUCCESS) {
01131 ast_agi_send(agi->fd, chan, "200 result=0\n");
01132 } else {
01133 ast_agi_send(agi->fd, chan, "200 result=1\n");
01134 }
01135 return RESULT_SUCCESS;
01136 }
01137
01138 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01139 {
01140 int res;
01141
01142 if (argc != 3) {
01143 return RESULT_SHOWUSAGE;
01144 }
01145
01146 res = ast_send_image(chan, argv[2]);
01147 if (!ast_check_hangup(chan)) {
01148 res = 0;
01149 }
01150 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01151 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01152 }
01153
01154 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01155 {
01156 int res = 0, skipms = 3000;
01157 char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL;
01158
01159 if (argc < 5 || argc > 9) {
01160 return RESULT_SHOWUSAGE;
01161 }
01162
01163 if (!ast_strlen_zero(argv[4])) {
01164 stop = argv[4];
01165 }
01166
01167 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
01168 return RESULT_SHOWUSAGE;
01169 }
01170
01171 if (argc > 6 && !ast_strlen_zero(argv[6])) {
01172 fwd = argv[6];
01173 }
01174
01175 if (argc > 7 && !ast_strlen_zero(argv[7])) {
01176 rev = argv[7];
01177 }
01178
01179 if (argc > 8 && !ast_strlen_zero(argv[8])) {
01180 suspend = argv[8];
01181 }
01182
01183 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
01184
01185 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01186
01187 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01188 }
01189
01190 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01191 {
01192 int res, vres;
01193 struct ast_filestream *fs, *vfs;
01194 long sample_offset = 0, max_length;
01195 char *edigits = "";
01196
01197 if (argc < 4 || argc > 5)
01198 return RESULT_SHOWUSAGE;
01199
01200 if (argv[3])
01201 edigits = argv[3];
01202
01203 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1))
01204 return RESULT_SHOWUSAGE;
01205
01206 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01207 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
01208 return RESULT_SUCCESS;
01209 }
01210
01211 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01212 ast_debug(1, "Ooh, found a video stream, too\n");
01213
01214 ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
01215
01216 ast_seekstream(fs, 0, SEEK_END);
01217 max_length = ast_tellstream(fs);
01218 ast_seekstream(fs, sample_offset, SEEK_SET);
01219 res = ast_applystream(chan, fs);
01220 if (vfs)
01221 vres = ast_applystream(chan, vfs);
01222 ast_playstream(fs);
01223 if (vfs)
01224 ast_playstream(vfs);
01225
01226 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01227
01228
01229 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
01230 ast_stopstream(chan);
01231 if (res == 1) {
01232
01233 return RESULT_SUCCESS;
01234 }
01235 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01236 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01237 }
01238
01239
01240 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01241 {
01242 int res, vres;
01243 struct ast_filestream *fs, *vfs;
01244 long sample_offset = 0, max_length;
01245 int timeout = 0;
01246 char *edigits = "";
01247
01248 if ( argc < 4 || argc > 5 )
01249 return RESULT_SHOWUSAGE;
01250
01251 if ( argv[3] )
01252 edigits = argv[3];
01253
01254 if ( argc == 5 )
01255 timeout = atoi(argv[4]);
01256 else if (chan->pbx->dtimeoutms) {
01257
01258 timeout = chan->pbx->dtimeoutms;
01259 }
01260
01261 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01262 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", 0, sample_offset);
01263 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
01264 return RESULT_SUCCESS;
01265 }
01266
01267 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01268 ast_debug(1, "Ooh, found a video stream, too\n");
01269
01270 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
01271
01272 ast_seekstream(fs, 0, SEEK_END);
01273 max_length = ast_tellstream(fs);
01274 ast_seekstream(fs, sample_offset, SEEK_SET);
01275 res = ast_applystream(chan, fs);
01276 if (vfs)
01277 vres = ast_applystream(chan, vfs);
01278 ast_playstream(fs);
01279 if (vfs)
01280 ast_playstream(vfs);
01281
01282 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01283
01284
01285 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
01286 ast_stopstream(chan);
01287 if (res == 1) {
01288
01289 return RESULT_SUCCESS;
01290 }
01291
01292
01293 if (res == 0 ) {
01294 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
01295
01296 if ( !strchr(edigits,res) )
01297 res=0;
01298 }
01299
01300 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01301 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01302 }
01303
01304
01305
01306
01307
01308
01309 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01310 {
01311 int res, num;
01312
01313 if (argc < 4 || argc > 5)
01314 return RESULT_SHOWUSAGE;
01315 if (sscanf(argv[2], "%30d", &num) != 1)
01316 return RESULT_SHOWUSAGE;
01317 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
01318 if (res == 1)
01319 return RESULT_SUCCESS;
01320 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01321 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01322 }
01323
01324 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01325 {
01326 int res, num;
01327
01328 if (argc != 4)
01329 return RESULT_SHOWUSAGE;
01330 if (sscanf(argv[2], "%30d", &num) != 1)
01331 return RESULT_SHOWUSAGE;
01332
01333 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
01334 if (res == 1)
01335 return RESULT_SUCCESS;
01336 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01337 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01338 }
01339
01340 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01341 {
01342 int res;
01343
01344 if (argc != 4)
01345 return RESULT_SHOWUSAGE;
01346
01347 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
01348 if (res == 1)
01349 return RESULT_SUCCESS;
01350 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01351 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01352 }
01353
01354 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01355 {
01356 int res, num;
01357
01358 if (argc != 4)
01359 return RESULT_SHOWUSAGE;
01360 if (sscanf(argv[2], "%30d", &num) != 1)
01361 return RESULT_SHOWUSAGE;
01362 res = ast_say_date(chan, num, argv[3], chan->language);
01363 if (res == 1)
01364 return RESULT_SUCCESS;
01365 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01366 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01367 }
01368
01369 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01370 {
01371 int res, num;
01372
01373 if (argc != 4)
01374 return RESULT_SHOWUSAGE;
01375 if (sscanf(argv[2], "%30d", &num) != 1)
01376 return RESULT_SHOWUSAGE;
01377 res = ast_say_time(chan, num, argv[3], chan->language);
01378 if (res == 1)
01379 return RESULT_SUCCESS;
01380 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01381 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01382 }
01383
01384 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01385 {
01386 int res = 0;
01387 time_t unixtime;
01388 char *format, *zone = NULL;
01389
01390 if (argc < 4)
01391 return RESULT_SHOWUSAGE;
01392
01393 if (argc > 4) {
01394 format = argv[4];
01395 } else {
01396
01397 if (!strcasecmp(chan->language, "de")) {
01398 format = "A dBY HMS";
01399 } else {
01400 format = "ABdY 'digits/at' IMp";
01401 }
01402 }
01403
01404 if (argc > 5 && !ast_strlen_zero(argv[5]))
01405 zone = argv[5];
01406
01407 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
01408 return RESULT_SHOWUSAGE;
01409
01410 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
01411 if (res == 1)
01412 return RESULT_SUCCESS;
01413
01414 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01415 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01416 }
01417
01418 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01419 {
01420 int res;
01421
01422 if (argc != 4)
01423 return RESULT_SHOWUSAGE;
01424
01425 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
01426 if (res == 1)
01427 return RESULT_SUCCESS;
01428 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01429 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01430 }
01431
01432 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01433 {
01434 int res, max, timeout;
01435 char data[1024];
01436
01437 if (argc < 3)
01438 return RESULT_SHOWUSAGE;
01439 if (argc >= 4)
01440 timeout = atoi(argv[3]);
01441 else
01442 timeout = 0;
01443 if (argc >= 5)
01444 max = atoi(argv[4]);
01445 else
01446 max = 1024;
01447 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
01448 if (res == 2)
01449 return RESULT_SUCCESS;
01450 else if (res == 1)
01451 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
01452 else if (res < 0 )
01453 ast_agi_send(agi->fd, chan, "200 result=-1\n");
01454 else
01455 ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
01456 return RESULT_SUCCESS;
01457 }
01458
01459 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01460 {
01461
01462 if (argc != 3)
01463 return RESULT_SHOWUSAGE;
01464 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
01465 ast_agi_send(agi->fd, chan, "200 result=0\n");
01466 return RESULT_SUCCESS;
01467 }
01468
01469 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01470 {
01471 if (argc != 3)
01472 return RESULT_SHOWUSAGE;
01473 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
01474 ast_agi_send(agi->fd, chan, "200 result=0\n");
01475 return RESULT_SUCCESS;
01476 }
01477
01478 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01479 {
01480 int pri;
01481
01482 if (argc != 3)
01483 return RESULT_SHOWUSAGE;
01484
01485 if (sscanf(argv[2], "%30d", &pri) != 1) {
01486 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
01487 return RESULT_SHOWUSAGE;
01488 }
01489
01490 ast_explicit_goto(chan, NULL, NULL, pri);
01491 ast_agi_send(agi->fd, chan, "200 result=0\n");
01492 return RESULT_SUCCESS;
01493 }
01494
01495 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01496 {
01497 struct ast_filestream *fs;
01498 struct ast_frame *f;
01499 struct timeval start;
01500 long sample_offset = 0;
01501 int res = 0;
01502 int ms;
01503
01504 struct ast_dsp *sildet=NULL;
01505 int totalsilence = 0;
01506 int dspsilence = 0;
01507 int silence = 0;
01508 int gotsilence = 0;
01509 char *silencestr = NULL;
01510 int rfmt = 0;
01511
01512
01513
01514 if (argc < 6)
01515 return RESULT_SHOWUSAGE;
01516 if (sscanf(argv[5], "%30d", &ms) != 1)
01517 return RESULT_SHOWUSAGE;
01518
01519 if (argc > 6)
01520 silencestr = strchr(argv[6],'s');
01521 if ((argc > 7) && (!silencestr))
01522 silencestr = strchr(argv[7],'s');
01523 if ((argc > 8) && (!silencestr))
01524 silencestr = strchr(argv[8],'s');
01525
01526 if (silencestr) {
01527 if (strlen(silencestr) > 2) {
01528 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
01529 silencestr++;
01530 silencestr++;
01531 if (silencestr)
01532 silence = atoi(silencestr);
01533 if (silence > 0)
01534 silence *= 1000;
01535 }
01536 }
01537 }
01538
01539 if (silence > 0) {
01540 rfmt = chan->readformat;
01541 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
01542 if (res < 0) {
01543 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
01544 return -1;
01545 }
01546 sildet = ast_dsp_new();
01547 if (!sildet) {
01548 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
01549 return -1;
01550 }
01551 ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
01552 }
01553
01554
01555
01556
01557 if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
01558 res = ast_streamfile(chan, "beep", chan->language);
01559
01560 if ((argc > 7) && (!strchr(argv[7], '=')))
01561 res = ast_streamfile(chan, "beep", chan->language);
01562
01563 if (!res)
01564 res = ast_waitstream(chan, argv[4]);
01565 if (res) {
01566 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
01567 } else {
01568 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
01569 if (!fs) {
01570 res = -1;
01571 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
01572 if (sildet)
01573 ast_dsp_free(sildet);
01574 return RESULT_FAILURE;
01575 }
01576
01577
01578 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
01579
01580 chan->stream = fs;
01581 ast_applystream(chan,fs);
01582
01583 ast_seekstream(fs, sample_offset, SEEK_SET);
01584 ast_truncstream(fs);
01585
01586 start = ast_tvnow();
01587 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
01588 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
01589 if (res < 0) {
01590 ast_closestream(fs);
01591 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
01592 if (sildet)
01593 ast_dsp_free(sildet);
01594 return RESULT_FAILURE;
01595 }
01596 f = ast_read(chan);
01597 if (!f) {
01598 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
01599 ast_closestream(fs);
01600 if (sildet)
01601 ast_dsp_free(sildet);
01602 return RESULT_FAILURE;
01603 }
01604 switch(f->frametype) {
01605 case AST_FRAME_DTMF:
01606 if (strchr(argv[4], f->subclass)) {
01607
01608
01609
01610 ast_stream_rewind(fs, 200);
01611 ast_truncstream(fs);
01612 sample_offset = ast_tellstream(fs);
01613 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset);
01614 ast_closestream(fs);
01615 ast_frfree(f);
01616 if (sildet)
01617 ast_dsp_free(sildet);
01618 return RESULT_SUCCESS;
01619 }
01620 break;
01621 case AST_FRAME_VOICE:
01622 ast_writestream(fs, f);
01623
01624
01625
01626 sample_offset = ast_tellstream(fs);
01627 if (silence > 0) {
01628 dspsilence = 0;
01629 ast_dsp_silence(sildet, f, &dspsilence);
01630 if (dspsilence) {
01631 totalsilence = dspsilence;
01632 } else {
01633 totalsilence = 0;
01634 }
01635 if (totalsilence > silence) {
01636
01637 gotsilence = 1;
01638 break;
01639 }
01640 }
01641 break;
01642 case AST_FRAME_VIDEO:
01643 ast_writestream(fs, f);
01644 default:
01645
01646 break;
01647 }
01648 ast_frfree(f);
01649 if (gotsilence)
01650 break;
01651 }
01652
01653 if (gotsilence) {
01654 ast_stream_rewind(fs, silence-1000);
01655 ast_truncstream(fs);
01656 sample_offset = ast_tellstream(fs);
01657 }
01658 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
01659 ast_closestream(fs);
01660 }
01661
01662 if (silence > 0) {
01663 res = ast_set_read_format(chan, rfmt);
01664 if (res)
01665 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
01666 ast_dsp_free(sildet);
01667 }
01668
01669 return RESULT_SUCCESS;
01670 }
01671
01672 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01673 {
01674 double timeout;
01675 struct timeval whentohangup = { 0, 0 };
01676
01677 if (argc != 3)
01678 return RESULT_SHOWUSAGE;
01679 if (sscanf(argv[2], "%30lf", &timeout) != 1)
01680 return RESULT_SHOWUSAGE;
01681 if (timeout < 0)
01682 timeout = 0;
01683 if (timeout) {
01684 whentohangup.tv_sec = timeout;
01685 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
01686 }
01687 ast_channel_setwhentohangup_tv(chan, whentohangup);
01688 ast_agi_send(agi->fd, chan, "200 result=0\n");
01689 return RESULT_SUCCESS;
01690 }
01691
01692 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01693 {
01694 struct ast_channel *c;
01695
01696 if (argc == 1) {
01697
01698 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
01699 ast_agi_send(agi->fd, chan, "200 result=1\n");
01700 return RESULT_SUCCESS;
01701 } else if (argc == 2) {
01702
01703 c = ast_get_channel_by_name_locked(argv[1]);
01704 if (c) {
01705
01706 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
01707 ast_agi_send(agi->fd, chan, "200 result=1\n");
01708 ast_channel_unlock(c);
01709 return RESULT_SUCCESS;
01710 }
01711
01712 ast_agi_send(agi->fd, chan, "200 result=-1\n");
01713 return RESULT_SUCCESS;
01714 } else {
01715 return RESULT_SHOWUSAGE;
01716 }
01717 }
01718
01719 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01720 {
01721 int res, workaround;
01722 struct ast_app *app_to_exec;
01723
01724 if (argc < 2)
01725 return RESULT_SHOWUSAGE;
01726
01727 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
01728
01729 if ((app_to_exec = pbx_findapp(argv[1]))) {
01730 if(!strcasecmp(argv[1], PARK_APP_NAME)) {
01731 ast_masq_park_call(chan, NULL, 0, NULL);
01732 }
01733 if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) {
01734 ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
01735 }
01736 if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
01737 char *compat = alloca(strlen(argv[2]) * 2 + 1), *cptr, *vptr;
01738 for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
01739 if (*vptr == ',') {
01740 *cptr++ = '\\';
01741 *cptr++ = ',';
01742 } else if (*vptr == '|') {
01743 *cptr++ = ',';
01744 } else {
01745 *cptr++ = *vptr;
01746 }
01747 }
01748 *cptr = '\0';
01749 res = pbx_exec(chan, app_to_exec, compat);
01750 } else {
01751 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
01752 }
01753 if (!workaround) {
01754 ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
01755 }
01756 } else {
01757 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
01758 res = -2;
01759 }
01760 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01761
01762
01763 return res;
01764 }
01765
01766 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01767 {
01768 char tmp[256]="";
01769 char *l = NULL, *n = NULL;
01770
01771 if (argv[2]) {
01772 ast_copy_string(tmp, argv[2], sizeof(tmp));
01773 ast_callerid_parse(tmp, &n, &l);
01774 if (l)
01775 ast_shrink_phone_number(l);
01776 else
01777 l = "";
01778 if (!n)
01779 n = "";
01780 ast_set_callerid(chan, l, n, NULL);
01781 }
01782
01783 ast_agi_send(agi->fd, chan, "200 result=1\n");
01784 return RESULT_SUCCESS;
01785 }
01786
01787 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01788 {
01789 struct ast_channel *c;
01790 if (argc == 2) {
01791
01792 ast_agi_send(agi->fd, chan, "200 result=%d\n", chan->_state);
01793 return RESULT_SUCCESS;
01794 } else if (argc == 3) {
01795
01796 c = ast_get_channel_by_name_locked(argv[2]);
01797 if (c) {
01798 ast_agi_send(agi->fd, chan, "200 result=%d\n", c->_state);
01799 ast_channel_unlock(c);
01800 return RESULT_SUCCESS;
01801 }
01802
01803 ast_agi_send(agi->fd, chan, "200 result=-1\n");
01804 return RESULT_SUCCESS;
01805 } else {
01806 return RESULT_SHOWUSAGE;
01807 }
01808 }
01809
01810 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01811 {
01812 if (argv[3])
01813 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
01814
01815 ast_agi_send(agi->fd, chan, "200 result=1\n");
01816 return RESULT_SUCCESS;
01817 }
01818
01819 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01820 {
01821 char *ret;
01822 char tempstr[1024];
01823
01824 if (argc != 3)
01825 return RESULT_SHOWUSAGE;
01826
01827
01828 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
01829 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
01830 } else {
01831 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
01832 }
01833
01834 if (ret)
01835 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
01836 else
01837 ast_agi_send(agi->fd, chan, "200 result=0\n");
01838
01839 return RESULT_SUCCESS;
01840 }
01841
01842 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01843 {
01844 char tmp[4096];
01845 struct ast_channel *chan2=NULL;
01846
01847 if ((argc != 4) && (argc != 5))
01848 return RESULT_SHOWUSAGE;
01849 if (argc == 5 && strcasecmp(chan->name, argv[4])) {
01850 chan2 = ast_get_channel_by_name_locked(argv[4]);
01851 } else {
01852 chan2 = chan;
01853 }
01854 if (chan2) {
01855 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
01856 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", tmp);
01857 } else {
01858 ast_agi_send(agi->fd, chan, "200 result=0\n");
01859 }
01860 if (chan2 && (chan2 != chan))
01861 ast_channel_unlock(chan2);
01862 return RESULT_SUCCESS;
01863 }
01864
01865 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01866 {
01867 int level = 0;
01868
01869 if (argc < 2)
01870 return RESULT_SHOWUSAGE;
01871
01872 if (argv[2])
01873 sscanf(argv[2], "%30d", &level);
01874
01875 ast_verb(level, "%s: %s\n", chan->data, argv[1]);
01876
01877 ast_agi_send(agi->fd, chan, "200 result=1\n");
01878
01879 return RESULT_SUCCESS;
01880 }
01881
01882 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01883 {
01884 int res;
01885 struct ast_str *buf;
01886
01887 if (argc != 4)
01888 return RESULT_SHOWUSAGE;
01889
01890 if (!(buf = ast_str_create(16))) {
01891 ast_agi_send(agi->fd, chan, "200 result=-1\n");
01892 return RESULT_SUCCESS;
01893 }
01894
01895 do {
01896 res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
01897 ast_str_update(buf);
01898 if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
01899 break;
01900 }
01901 if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
01902 break;
01903 }
01904 } while (1);
01905
01906 if (res)
01907 ast_agi_send(agi->fd, chan, "200 result=0\n");
01908 else
01909 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
01910
01911 ast_free(buf);
01912 return RESULT_SUCCESS;
01913 }
01914
01915 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01916 {
01917 int res;
01918
01919 if (argc != 5)
01920 return RESULT_SHOWUSAGE;
01921 res = ast_db_put(argv[2], argv[3], argv[4]);
01922 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
01923 return RESULT_SUCCESS;
01924 }
01925
01926 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01927 {
01928 int res;
01929
01930 if (argc != 4)
01931 return RESULT_SHOWUSAGE;
01932 res = ast_db_del(argv[2], argv[3]);
01933 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
01934 return RESULT_SUCCESS;
01935 }
01936
01937 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01938 {
01939 int res;
01940
01941 if ((argc < 3) || (argc > 4))
01942 return RESULT_SHOWUSAGE;
01943 if (argc == 4)
01944 res = ast_db_deltree(argv[2], argv[3]);
01945 else
01946 res = ast_db_deltree(argv[2], NULL);
01947
01948 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
01949 return RESULT_SUCCESS;
01950 }
01951
01952 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01953 {
01954 switch (cmd) {
01955 case CLI_INIT:
01956 e->command = "agi set debug [on|off]";
01957 e->usage =
01958 "Usage: agi set debug [on|off]\n"
01959 " Enables/disables dumping of AGI transactions for\n"
01960 " debugging purposes.\n";
01961 return NULL;
01962
01963 case CLI_GENERATE:
01964 return NULL;
01965 }
01966
01967 if (a->argc != e->args)
01968 return CLI_SHOWUSAGE;
01969
01970 if (strncasecmp(a->argv[3], "off", 3) == 0) {
01971 agidebug = 0;
01972 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
01973 agidebug = 1;
01974 } else {
01975 return CLI_SHOWUSAGE;
01976 }
01977 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
01978 return CLI_SUCCESS;
01979 }
01980
01981 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
01982 {
01983 ast_agi_send(agi->fd, chan, "200 result=0\n");
01984 return RESULT_SUCCESS;
01985 }
01986
01987 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01988 {
01989 if (argc < 3) {
01990 return RESULT_SHOWUSAGE;
01991 }
01992 if (!strncasecmp(argv[2], "on", 2))
01993 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
01994 else if (!strncasecmp(argv[2], "off", 3))
01995 ast_moh_stop(chan);
01996 ast_agi_send(agi->fd, chan, "200 result=0\n");
01997 return RESULT_SUCCESS;
01998 }
01999
02000 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, char **argv)
02001 {
02002
02003 if (agi->speech) {
02004 ast_agi_send(agi->fd, chan, "200 result=0\n");
02005 return RESULT_SUCCESS;
02006 }
02007
02008 if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
02009 ast_agi_send(agi->fd, chan, "200 result=1\n");
02010 else
02011 ast_agi_send(agi->fd, chan, "200 result=0\n");
02012
02013 return RESULT_SUCCESS;
02014 }
02015
02016 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, char **argv)
02017 {
02018
02019 if (argc != 4)
02020 return RESULT_SHOWUSAGE;
02021
02022
02023 if (!agi->speech) {
02024 ast_agi_send(agi->fd, chan, "200 result=0\n");
02025 return RESULT_SUCCESS;
02026 }
02027
02028 ast_speech_change(agi->speech, argv[2], argv[3]);
02029 ast_agi_send(agi->fd, chan, "200 result=1\n");
02030
02031 return RESULT_SUCCESS;
02032 }
02033
02034 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, char **argv)
02035 {
02036 if (agi->speech) {
02037 ast_speech_destroy(agi->speech);
02038 agi->speech = NULL;
02039 ast_agi_send(agi->fd, chan, "200 result=1\n");
02040 } else {
02041 ast_agi_send(agi->fd, chan, "200 result=0\n");
02042 }
02043
02044 return RESULT_SUCCESS;
02045 }
02046
02047 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
02048 {
02049 if (argc != 5)
02050 return RESULT_SHOWUSAGE;
02051
02052 if (!agi->speech) {
02053 ast_agi_send(agi->fd, chan, "200 result=0\n");
02054 return RESULT_SUCCESS;
02055 }
02056
02057 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
02058 ast_agi_send(agi->fd, chan, "200 result=0\n");
02059 else
02060 ast_agi_send(agi->fd, chan, "200 result=1\n");
02061
02062 return RESULT_SUCCESS;
02063 }
02064
02065 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
02066 {
02067 if (argc != 4)
02068 return RESULT_SHOWUSAGE;
02069
02070 if (!agi->speech) {
02071 ast_agi_send(agi->fd, chan, "200 result=0\n");
02072 return RESULT_SUCCESS;
02073 }
02074
02075 if (ast_speech_grammar_unload(agi->speech, argv[3]))
02076 ast_agi_send(agi->fd, chan, "200 result=0\n");
02077 else
02078 ast_agi_send(agi->fd, chan, "200 result=1\n");
02079
02080 return RESULT_SUCCESS;
02081 }
02082
02083 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
02084 {
02085 if (argc != 4)
02086 return RESULT_SHOWUSAGE;
02087
02088 if (!agi->speech) {
02089 ast_agi_send(agi->fd, chan, "200 result=0\n");
02090 return RESULT_SUCCESS;
02091 }
02092
02093 if (ast_speech_grammar_activate(agi->speech, argv[3]))
02094 ast_agi_send(agi->fd, chan, "200 result=0\n");
02095 else
02096 ast_agi_send(agi->fd, chan, "200 result=1\n");
02097
02098 return RESULT_SUCCESS;
02099 }
02100
02101 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, char **argv)
02102 {
02103 if (argc != 4)
02104 return RESULT_SHOWUSAGE;
02105
02106 if (!agi->speech) {
02107 ast_agi_send(agi->fd, chan, "200 result=0\n");
02108 return RESULT_SUCCESS;
02109 }
02110
02111 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
02112 ast_agi_send(agi->fd, chan, "200 result=0\n");
02113 else
02114 ast_agi_send(agi->fd, chan, "200 result=1\n");
02115
02116 return RESULT_SUCCESS;
02117 }
02118
02119 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
02120 {
02121 struct ast_filestream *fs = NULL;
02122
02123 if (!(fs = ast_openstream(chan, filename, preflang)))
02124 return -1;
02125
02126 if (offset)
02127 ast_seekstream(fs, offset, SEEK_SET);
02128
02129 if (ast_applystream(chan, fs))
02130 return -1;
02131
02132 if (ast_playstream(fs))
02133 return -1;
02134
02135 return 0;
02136 }
02137
02138 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, char **argv)
02139 {
02140 struct ast_speech *speech = agi->speech;
02141 char *prompt, dtmf = 0, tmp[4096] = "", *buf = tmp;
02142 int timeout = 0, offset = 0, old_read_format = 0, res = 0, i = 0;
02143 long current_offset = 0;
02144 const char *reason = NULL;
02145 struct ast_frame *fr = NULL;
02146 struct ast_speech_result *result = NULL;
02147 size_t left = sizeof(tmp);
02148 time_t start = 0, current;
02149
02150 if (argc < 4)
02151 return RESULT_SHOWUSAGE;
02152
02153 if (!speech) {
02154 ast_agi_send(agi->fd, chan, "200 result=0\n");
02155 return RESULT_SUCCESS;
02156 }
02157
02158 prompt = argv[2];
02159 timeout = atoi(argv[3]);
02160
02161
02162 if (argc == 5)
02163 offset = atoi(argv[4]);
02164
02165
02166 old_read_format = chan->readformat;
02167 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
02168 ast_agi_send(agi->fd, chan, "200 result=0\n");
02169 return RESULT_SUCCESS;
02170 }
02171
02172
02173 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
02174 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02175 ast_speech_start(speech);
02176 }
02177
02178
02179 speech_streamfile(chan, prompt, chan->language, offset);
02180
02181
02182 while (ast_strlen_zero(reason)) {
02183
02184 ast_sched_runq(chan->sched);
02185
02186
02187 if ((res = ast_sched_wait(chan->sched)) < 0)
02188 res = 1000;
02189
02190
02191 if (ast_waitfor(chan, res) > 0) {
02192 if (!(fr = ast_read(chan))) {
02193 reason = "hangup";
02194 break;
02195 }
02196 }
02197
02198
02199 if ((timeout > 0) && (start > 0)) {
02200 time(¤t);
02201 if ((current - start) >= timeout) {
02202 reason = "timeout";
02203 if (fr)
02204 ast_frfree(fr);
02205 break;
02206 }
02207 }
02208
02209
02210 ast_mutex_lock(&speech->lock);
02211
02212
02213 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
02214 current_offset = ast_tellstream(chan->stream);
02215 ast_stopstream(chan);
02216 ast_clear_flag(speech, AST_SPEECH_QUIET);
02217 }
02218
02219
02220 switch (speech->state) {
02221 case AST_SPEECH_STATE_READY:
02222
02223 if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
02224 ast_stopstream(chan);
02225 time(&start);
02226 }
02227
02228 if (fr && fr->frametype == AST_FRAME_VOICE)
02229 ast_speech_write(speech, fr->data.ptr, fr->datalen);
02230 break;
02231 case AST_SPEECH_STATE_WAIT:
02232
02233 if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
02234 ast_stopstream(chan);
02235
02236 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
02237 speech_streamfile(chan, speech->processing_sound, chan->language, 0);
02238 }
02239 break;
02240 case AST_SPEECH_STATE_DONE:
02241
02242 speech->results = ast_speech_results_get(speech);
02243
02244 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02245 reason = "speech";
02246 break;
02247 default:
02248 break;
02249 }
02250 ast_mutex_unlock(&speech->lock);
02251
02252
02253 if (fr) {
02254 if (fr->frametype == AST_FRAME_DTMF) {
02255 reason = "dtmf";
02256 dtmf = fr->subclass;
02257 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass == AST_CONTROL_HANGUP) {
02258 reason = "hangup";
02259 }
02260 ast_frfree(fr);
02261 }
02262 }
02263
02264 if (!strcasecmp(reason, "speech")) {
02265
02266 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
02267
02268 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);
02269
02270 i++;
02271 }
02272
02273 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
02274 } else if (!strcasecmp(reason, "dtmf")) {
02275 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
02276 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
02277 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
02278 } else {
02279 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
02280 }
02281
02282 return RESULT_SUCCESS;
02283 }
02284
02285 static char usage_verbose[] =
02286 " Usage: VERBOSE <message> <level>\n"
02287 " Sends <message> to the console via verbose message system.\n"
02288 " <level> is the the verbose level (1-4)\n"
02289 " Always returns 1.\n";
02290
02291 static char usage_setvariable[] =
02292 " Usage: SET VARIABLE <variablename> <value>\n";
02293
02294 static char usage_setcallerid[] =
02295 " Usage: SET CALLERID <number>\n"
02296 " Changes the callerid of the current channel.\n";
02297
02298 static char usage_waitfordigit[] =
02299 " Usage: WAIT FOR DIGIT <timeout>\n"
02300 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
02301 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
02302 " the numerical value of the ascii of the digit if one is received. Use -1\n"
02303 " for the timeout value if you desire the call to block indefinitely.\n";
02304
02305 static char usage_sendtext[] =
02306 " Usage: SEND TEXT \"<text to send>\"\n"
02307 " Sends the given text on a channel. Most channels do not support the\n"
02308 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
02309 " support text transmission. Returns -1 only on error/hangup. Text\n"
02310 " consisting of greater than one word should be placed in quotes since the\n"
02311 " command only accepts a single argument.\n";
02312
02313 static char usage_recvchar[] =
02314 " Usage: RECEIVE CHAR <timeout>\n"
02315 " Receives a character of text on a channel. Specify timeout to be the\n"
02316 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
02317 " do not support the reception of text. Returns the decimal value of the character\n"
02318 " if one is received, or 0 if the channel does not support text reception. Returns\n"
02319 " -1 only on error/hangup.\n";
02320
02321 static char usage_recvtext[] =
02322 " Usage: RECEIVE TEXT <timeout>\n"
02323 " Receives a string of text on a channel. Specify timeout to be the\n"
02324 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
02325 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
02326
02327 static char usage_tddmode[] =
02328 " Usage: TDD MODE <on|off>\n"
02329 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
02330 " successful, or 0 if channel is not TDD-capable.\n";
02331
02332 static char usage_sendimage[] =
02333 " Usage: SEND IMAGE <image>\n"
02334 " Sends the given image on a channel. Most channels do not support the\n"
02335 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
02336 " support image transmission. Returns -1 only on error/hangup. Image names\n"
02337 " should not include extensions.\n";
02338
02339 static char usage_streamfile[] =
02340 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
02341 " Send the given file, allowing playback to be interrupted by the given\n"
02342 " digits, if any. Use double quotes for the digits if you wish none to be\n"
02343 " permitted. If sample offset is provided then the audio will seek to sample\n"
02344 " offset before play starts. Returns 0 if playback completes without a digit\n"
02345 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
02346 " or -1 on error or if the channel was disconnected. Remember, the file\n"
02347 " extension must not be included in the filename.\n";
02348
02349 static char usage_controlstreamfile[] =
02350 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
02351 " Send the given file, allowing playback to be controled by the given\n"
02352 " digits, if any. Use double quotes for the digits if you wish none to be\n"
02353 " permitted. Returns 0 if playback completes without a digit\n"
02354 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
02355 " or -1 on error or if the channel was disconnected. Remember, the file\n"
02356 " extension must not be included in the filename.\n\n"
02357 " Note: ffchar and rewchar default to * and # respectively.\n";
02358
02359 static char usage_saynumber[] =
02360 " Usage: SAY NUMBER <number> <escape digits> [gender]\n"
02361 " Say a given number, returning early if any of the given DTMF digits\n"
02362 " are received on the channel. Returns 0 if playback completes without a digit\n"
02363 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
02364 " -1 on error/hangup.\n";
02365
02366 static char usage_saydigits[] =
02367 " Usage: SAY DIGITS <number> <escape digits>\n"
02368 " Say a given digit string, returning early if any of the given DTMF digits\n"
02369 " are received on the channel. Returns 0 if playback completes without a digit\n"
02370 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
02371 " -1 on error/hangup.\n";
02372
02373 static char usage_sayalpha[] =
02374 " Usage: SAY ALPHA <number> <escape digits>\n"
02375 " Say a given character string, returning early if any of the given DTMF digits\n"
02376 " are received on the channel. Returns 0 if playback completes without a digit\n"
02377 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
02378 " -1 on error/hangup.\n";
02379
02380 static char usage_saydate[] =
02381 " Usage: SAY DATE <date> <escape digits>\n"
02382 " Say a given date, returning early if any of the given DTMF digits are\n"
02383 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
02384 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
02385 " completes without a digit being pressed, or the ASCII numerical value of the\n"
02386 " digit if one was pressed or -1 on error/hangup.\n";
02387
02388 static char usage_saytime[] =
02389 " Usage: SAY TIME <time> <escape digits>\n"
02390 " Say a given time, returning early if any of the given DTMF digits are\n"
02391 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
02392 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
02393 " completes without a digit being pressed, or the ASCII numerical value of the\n"
02394 " digit if one was pressed or -1 on error/hangup.\n";
02395
02396 static char usage_saydatetime[] =
02397 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
02398 " Say a given time, returning early if any of the given DTMF digits are\n"
02399 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
02400 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
02401 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
02402 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
02403 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
02404 " completes without a digit being pressed, or the ASCII numerical value of the\n"
02405 " digit if one was pressed or -1 on error/hangup.\n";
02406
02407 static char usage_sayphonetic[] =
02408 " Usage: SAY PHONETIC <string> <escape digits>\n"
02409 " Say a given character string with phonetics, returning early if any of the\n"
02410 " given DTMF digits are received on the channel. Returns 0 if playback\n"
02411 " completes without a digit pressed, the ASCII numerical value of the digit\n"
02412 " if one was pressed, or -1 on error/hangup.\n";
02413
02414 static char usage_setcontext[] =
02415 " Usage: SET CONTEXT <desired context>\n"
02416 " Sets the context for continuation upon exiting the application.\n";
02417
02418 static char usage_setextension[] =
02419 " Usage: SET EXTENSION <new extension>\n"
02420 " Changes the extension for continuation upon exiting the application.\n";
02421
02422 static char usage_setpriority[] =
02423 " Usage: SET PRIORITY <priority>\n"
02424 " Changes the priority for continuation upon exiting the application.\n"
02425 " The priority must be a valid priority or label.\n";
02426
02427 static char usage_recordfile[] =
02428 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
02429 " [offset samples] [BEEP] [s=silence]\n"
02430 " Record to a file until a given dtmf digit in the sequence is received\n"
02431 " Returns -1 on hangup or error. The format will specify what kind of file\n"
02432 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
02433 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
02434 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
02435 " of seconds of silence allowed before the function returns despite the\n"
02436 " lack of dtmf digits or reaching timeout. Silence value must be\n"
02437 " preceded by \"s=\" and is also optional.\n";
02438
02439 static char usage_autohangup[] =
02440 " Usage: SET AUTOHANGUP <time>\n"
02441 " Cause the channel to automatically hangup at <time> seconds in the\n"
02442 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
02443 " cause the autohangup feature to be disabled on this channel.\n";
02444
02445 static char usage_speechcreate[] =
02446 " Usage: SPEECH CREATE <engine>\n"
02447 " Create a speech object to be used by the other Speech AGI commands.\n";
02448
02449 static char usage_speechset[] =
02450 " Usage: SPEECH SET <name> <value>\n"
02451 " Set an engine-specific setting.\n";
02452
02453 static char usage_speechdestroy[] =
02454 " Usage: SPEECH DESTROY\n"
02455 " Destroy the speech object created by SPEECH CREATE.\n";
02456
02457 static char usage_speechloadgrammar[] =
02458 " Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar>\n"
02459 " Loads the specified grammar as the specified name.\n";
02460
02461 static char usage_speechunloadgrammar[] =
02462 " Usage: SPEECH UNLOAD GRAMMAR <grammar name>\n"
02463 " Unloads the specified grammar.\n";
02464
02465 static char usage_speechactivategrammar[] =
02466 " Usage: SPEECH ACTIVATE GRAMMAR <grammar name>\n"
02467 " Activates the specified grammar on the speech object.\n";
02468
02469 static char usage_speechdeactivategrammar[] =
02470 " Usage: SPEECH DEACTIVATE GRAMMAR <grammar name>\n"
02471 " Deactivates the specified grammar on the speech object.\n";
02472
02473 static char usage_speechrecognize[] =
02474 " Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>]\n"
02475 " Plays back given prompt while listening for speech and dtmf.\n";
02476
02477
02478
02479
02480 static struct agi_command commands[] = {
02481 { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
02482 { { "asyncagi", "break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
02483 { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
02484 { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
02485 { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
02486 { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
02487 { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
02488 { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
02489 { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
02490 { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
02491 { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
02492 { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
02493 { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
02494 { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
02495 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar , 0 },
02496 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext , 0 },
02497 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile , 0 },
02498 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha , 0 },
02499 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits , 0 },
02500 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber , 0 },
02501 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic , 0 },
02502 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate , 0 },
02503 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime , 0 },
02504 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime , 0 },
02505 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage , 0 },
02506 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext , 0 },
02507 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup , 0 },
02508 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid , 0 },
02509 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext , 0 },
02510 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension , 0 },
02511 { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
02512 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority , 0 },
02513 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable , 1 },
02514 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile , 0 },
02515 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile , 0 },
02516 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode , 0 },
02517 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose , 1 },
02518 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit , 0 },
02519 { { "speech", "create", NULL }, handle_speechcreate, "Creates a speech object", usage_speechcreate, 0 },
02520 { { "speech", "set", NULL }, handle_speechset, "Sets a speech engine setting", usage_speechset, 0 },
02521 { { "speech", "destroy", NULL }, handle_speechdestroy, "Destroys a speech object", usage_speechdestroy, 1 },
02522 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, "Loads a grammar", usage_speechloadgrammar, 0 },
02523 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, "Unloads a grammar", usage_speechunloadgrammar, 1 },
02524 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, "Activates a grammar", usage_speechactivategrammar, 0 },
02525 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, "Deactivates a grammar", usage_speechdeactivategrammar, 0 },
02526 { { "speech", "recognize", NULL }, handle_speechrecognize, "Recognizes speech", usage_speechrecognize, 0 },
02527 };
02528
02529 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
02530
02531 static char *help_workhorse(int fd, char *match[])
02532 {
02533 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
02534 struct agi_command *e;
02535
02536 if (match)
02537 ast_join(matchstr, sizeof(matchstr), match);
02538
02539 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
02540 AST_RWLIST_RDLOCK(&agi_commands);
02541 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
02542 if (!e->cmda[0])
02543 break;
02544
02545 if ((e->cmda[0])[0] == '_')
02546 continue;
02547 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
02548 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
02549 continue;
02550 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
02551 }
02552 AST_RWLIST_UNLOCK(&agi_commands);
02553
02554 return CLI_SUCCESS;
02555 }
02556
02557 int ast_agi_register(struct ast_module *mod, agi_command *cmd)
02558 {
02559 char fullcmd[MAX_CMD_LEN];
02560
02561 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
02562
02563 if (!find_command(cmd->cmda,1)) {
02564 cmd->docsrc = AST_STATIC_DOC;
02565 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
02566 #ifdef AST_XML_DOCS
02567 *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd);
02568 *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd);
02569 *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd);
02570 *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd);
02571 *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
02572 #elif (!defined(HAVE_NULLSAFE_PRINTF))
02573 *((char **) &cmd->summary) = ast_strdup("");
02574 *((char **) &cmd->usage) = ast_strdup("");
02575 *((char **) &cmd->syntax) = ast_strdup("");
02576 *((char **) &cmd->seealso) = ast_strdup("");
02577 #endif
02578 }
02579
02580 cmd->mod = mod;
02581 AST_RWLIST_WRLOCK(&agi_commands);
02582 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
02583 AST_RWLIST_UNLOCK(&agi_commands);
02584 if (mod != ast_module_info->self)
02585 ast_module_ref(ast_module_info->self);
02586 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
02587 return 1;
02588 } else {
02589 ast_log(LOG_WARNING, "Command already registered!\n");
02590 return 0;
02591 }
02592 }
02593
02594 int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
02595 {
02596 struct agi_command *e;
02597 int unregistered = 0;
02598 char fullcmd[MAX_CMD_LEN];
02599
02600 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
02601
02602 AST_RWLIST_WRLOCK(&agi_commands);
02603 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
02604 if (cmd == e) {
02605 AST_RWLIST_REMOVE_CURRENT(list);
02606 if (mod != ast_module_info->self)
02607 ast_module_unref(ast_module_info->self);
02608 #ifdef AST_XML_DOCS
02609 if (e->docsrc == AST_XML_DOC) {
02610 ast_free(e->summary);
02611 ast_free(e->usage);
02612 ast_free(e->syntax);
02613 ast_free(e->seealso);
02614 e->summary = NULL, e->usage = NULL;
02615 e->syntax = NULL, e->seealso = NULL;
02616 }
02617 #endif
02618 unregistered=1;
02619 break;
02620 }
02621 }
02622 AST_RWLIST_TRAVERSE_SAFE_END;
02623 AST_RWLIST_UNLOCK(&agi_commands);
02624 if (unregistered)
02625 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
02626 else
02627 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
02628 return unregistered;
02629 }
02630
02631 int ast_agi_register_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
02632 {
02633 unsigned int i, x = 0;
02634
02635 for (i = 0; i < len; i++) {
02636 if (ast_agi_register(mod, cmd + i) == 1) {
02637 x++;
02638 continue;
02639 }
02640
02641
02642
02643
02644 for (; x > 0; x--) {
02645
02646
02647
02648
02649
02650
02651
02652
02653 (void) ast_agi_unregister(mod, cmd + x - 1);
02654 }
02655 return -1;
02656 }
02657
02658 return 0;
02659 }
02660
02661 int ast_agi_unregister_multiple(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
02662 {
02663 unsigned int i;
02664 int res = 0;
02665
02666 for (i = 0; i < len; i++) {
02667
02668
02669
02670
02671 res |= ast_agi_unregister(mod, cmd + i);
02672 }
02673
02674 return res;
02675 }
02676
02677 static agi_command *find_command(char *cmds[], int exact)
02678 {
02679 int y, match;
02680 struct agi_command *e;
02681
02682 AST_RWLIST_RDLOCK(&agi_commands);
02683 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
02684 if (!e->cmda[0])
02685 break;
02686
02687 match = 1;
02688 for (y = 0; match && cmds[y]; y++) {
02689
02690
02691
02692 if (!e->cmda[y] && !exact)
02693 break;
02694
02695 if (!e->cmda[y]) {
02696 AST_RWLIST_UNLOCK(&agi_commands);
02697 return NULL;
02698 }
02699 if (strcasecmp(e->cmda[y], cmds[y]))
02700 match = 0;
02701 }
02702
02703
02704 if ((exact > -1) && e->cmda[y])
02705 match = 0;
02706 if (match) {
02707 AST_RWLIST_UNLOCK(&agi_commands);
02708 return e;
02709 }
02710 }
02711 AST_RWLIST_UNLOCK(&agi_commands);
02712 return NULL;
02713 }
02714
02715 static int parse_args(char *s, int *max, char *argv[])
02716 {
02717 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
02718 char *cur;
02719
02720 cur = s;
02721 while(*s) {
02722 switch(*s) {
02723 case '"':
02724
02725 if (escaped)
02726 goto normal;
02727 else
02728 quoted = !quoted;
02729 if (quoted && whitespace) {
02730
02731 argv[x++] = cur;
02732 whitespace=0;
02733 }
02734 escaped = 0;
02735 break;
02736 case ' ':
02737 case '\t':
02738 if (!quoted && !escaped) {
02739
02740
02741 whitespace = 1;
02742 *(cur++) = '\0';
02743 } else
02744
02745 goto normal;
02746 break;
02747 case '\\':
02748
02749 if (escaped) {
02750 goto normal;
02751 } else {
02752 escaped=1;
02753 }
02754 break;
02755 default:
02756 normal:
02757 if (whitespace) {
02758 if (x >= MAX_ARGS -1) {
02759 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
02760 break;
02761 }
02762
02763 argv[x++] = cur;
02764 whitespace=0;
02765 }
02766 *(cur++) = *s;
02767 escaped=0;
02768 }
02769 s++;
02770 }
02771
02772 *(cur++) = '\0';
02773 argv[x] = NULL;
02774 *max = x;
02775 return 0;
02776 }
02777
02778 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
02779 {
02780 char *argv[MAX_ARGS];
02781 int argc = MAX_ARGS, res;
02782 agi_command *c;
02783 const char *ami_res = "Unknown Result";
02784 char *ami_cmd = ast_strdupa(buf);
02785 int command_id = ast_random(), resultcode = 200;
02786
02787 manager_event(EVENT_FLAG_AGI, "AGIExec",
02788 "SubEvent: Start\r\n"
02789 "Channel: %s\r\n"
02790 "CommandId: %d\r\n"
02791 "Command: %s\r\n", chan->name, command_id, ami_cmd);
02792 parse_args(buf, &argc, argv);
02793 if ((c = find_command(argv, 0)) && (!dead || (dead && c->dead))) {
02794
02795
02796 if (c->mod != ast_module_info->self)
02797 ast_module_ref(c->mod);
02798
02799
02800 if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
02801 ast_cdr_setapp(chan->cdr, "AGI", buf);
02802
02803 res = c->handler(chan, agi, argc, argv);
02804 if (c->mod != ast_module_info->self)
02805 ast_module_unref(c->mod);
02806 switch (res) {
02807 case RESULT_SHOWUSAGE: ami_res = "Usage"; resultcode = 520; break;
02808 case RESULT_FAILURE: ami_res = "Failure"; resultcode = -1; break;
02809 case RESULT_SUCCESS: ami_res = "Success"; resultcode = 200; break;
02810 }
02811 manager_event(EVENT_FLAG_AGI, "AGIExec",
02812 "SubEvent: End\r\n"
02813 "Channel: %s\r\n"
02814 "CommandId: %d\r\n"
02815 "Command: %s\r\n"
02816 "ResultCode: %d\r\n"
02817 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
02818 switch(res) {
02819 case RESULT_SHOWUSAGE:
02820 if (ast_strlen_zero(c->usage)) {
02821 ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n");
02822 } else {
02823 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
02824 ast_agi_send(agi->fd, chan, "%s", c->usage);
02825 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
02826 }
02827 break;
02828 case RESULT_FAILURE:
02829
02830
02831 return -1;
02832 }
02833 } else if ((c = find_command(argv, 0))) {
02834 ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
02835 manager_event(EVENT_FLAG_AGI, "AGIExec",
02836 "SubEvent: End\r\n"
02837 "Channel: %s\r\n"
02838 "CommandId: %d\r\n"
02839 "Command: %s\r\n"
02840 "ResultCode: 511\r\n"
02841 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
02842 } else {
02843 ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
02844 manager_event(EVENT_FLAG_AGI, "AGIExec",
02845 "SubEvent: End\r\n"
02846 "Channel: %s\r\n"
02847 "CommandId: %d\r\n"
02848 "Command: %s\r\n"
02849 "ResultCode: 510\r\n"
02850 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
02851 }
02852 return 0;
02853 }
02854 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
02855 {
02856 struct ast_channel *c;
02857 int outfd, ms, needhup = 0;
02858 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
02859 struct ast_frame *f;
02860 char buf[AGI_BUF_LEN];
02861 char *res = NULL;
02862 FILE *readf;
02863
02864
02865 int retry = AGI_NANDFS_RETRY;
02866 int send_sighup;
02867 const char *sighup_str;
02868
02869 ast_channel_lock(chan);
02870 sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
02871 send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str);
02872 ast_channel_unlock(chan);
02873
02874 if (!(readf = fdopen(agi->ctrl, "r"))) {
02875 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
02876 if (send_sighup && pid > -1)
02877 kill(pid, SIGHUP);
02878 close(agi->ctrl);
02879 return AGI_RESULT_FAILURE;
02880 }
02881
02882 setlinebuf(readf);
02883 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
02884 for (;;) {
02885 if (needhup) {
02886 needhup = 0;
02887 dead = 1;
02888 if (send_sighup) {
02889 if (pid > -1) {
02890 kill(pid, SIGHUP);
02891 } else if (agi->fast) {
02892 send(agi->ctrl, "HANGUP\n", 7, 0);
02893 }
02894 }
02895 }
02896 ms = -1;
02897 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
02898 if (c) {
02899 retry = AGI_NANDFS_RETRY;
02900
02901 f = ast_read(c);
02902 if (!f) {
02903 ast_debug(1, "%s hungup\n", chan->name);
02904 returnstatus = AGI_RESULT_HANGUP;
02905 needhup = 1;
02906 continue;
02907 } else {
02908
02909 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
02910
02911 if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
02912 }
02913 }
02914 ast_frfree(f);
02915 }
02916 } else if (outfd > -1) {
02917 size_t len = sizeof(buf);
02918 size_t buflen = 0;
02919
02920 retry = AGI_NANDFS_RETRY;
02921 buf[0] = '\0';
02922
02923 while (len > 1) {
02924 res = fgets(buf + buflen, len, readf);
02925 if (feof(readf))
02926 break;
02927 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
02928 break;
02929 if (res != NULL && !agi->fast)
02930 break;
02931 buflen = strlen(buf);
02932 if (buflen && buf[buflen - 1] == '\n')
02933 break;
02934 len = sizeof(buf) - buflen;
02935 if (agidebug)
02936 ast_verbose( "AGI Rx << temp buffer %s - errno %s\n", buf, strerror(errno));
02937 }
02938
02939 if (!buf[0]) {
02940
02941 if (returnstatus) {
02942 returnstatus = -1;
02943 }
02944 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, request, returnstatus);
02945 if (pid > 0)
02946 waitpid(pid, status, 0);
02947
02948 pid = -1;
02949 break;
02950 }
02951
02952
02953 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
02954 returnstatus = AGI_RESULT_FAILURE;
02955 break;
02956 }
02957
02958
02959 if (*buf && buf[strlen(buf) - 1] == '\n')
02960 buf[strlen(buf) - 1] = 0;
02961 if (agidebug)
02962 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
02963 returnstatus |= agi_handle_command(chan, agi, buf, dead);
02964
02965 if (returnstatus < 0) {
02966 needhup = 1;
02967 continue;
02968 }
02969 } else {
02970 if (--retry <= 0) {
02971 ast_log(LOG_WARNING, "No channel, no fd?\n");
02972 returnstatus = AGI_RESULT_FAILURE;
02973 break;
02974 }
02975 }
02976 }
02977 if (agi->speech) {
02978 ast_speech_destroy(agi->speech);
02979 }
02980
02981 if (send_sighup) {
02982 if (pid > -1) {
02983 if (kill(pid, SIGHUP)) {
02984 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
02985 } else {
02986 usleep(1);
02987 }
02988 waitpid(pid, status, WNOHANG);
02989 } else if (agi->fast) {
02990 send(agi->ctrl, "HANGUP\n", 7, 0);
02991 }
02992 }
02993 fclose(readf);
02994 return returnstatus;
02995 }
02996
02997 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02998 {
02999 struct agi_command *command;
03000 char fullcmd[MAX_CMD_LEN];
03001 int error = 0;
03002
03003 switch (cmd) {
03004 case CLI_INIT:
03005 e->command = "agi show commands [topic]";
03006 e->usage =
03007 "Usage: agi show commands [topic] <topic>\n"
03008 " When called with a topic as an argument, displays usage\n"
03009 " information on the given command. If called without a\n"
03010 " topic, it provides a list of AGI commands.\n";
03011 case CLI_GENERATE:
03012 return NULL;
03013 }
03014 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
03015 return CLI_SHOWUSAGE;
03016 if (a->argc > e->args - 1) {
03017 command = find_command(a->argv + e->args, 1);
03018 if (command) {
03019 char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
03020 char info[30 + MAX_CMD_LEN];
03021 char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS];
03022 char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS];
03023 char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS];
03024 char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS];
03025 char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS];
03026 char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS];
03027 char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS];
03028 size_t synlen, desclen, seealsolen, stxlen;
03029
03030 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
03031 term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
03032 term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
03033 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
03034 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
03035 term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
03036
03037 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03038 snprintf(info, sizeof(info), "\n -= Info about agi '%s' =- ", fullcmd);
03039 term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
03040 #ifdef AST_XML_DOCS
03041 if (command->docsrc == AST_XML_DOC) {
03042 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
03043 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
03044 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
03045 if (!seealso || !description || !synopsis) {
03046 error = 1;
03047 goto return_cleanup;
03048 }
03049 } else
03050 #endif
03051 {
03052 synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03053 synopsis = ast_malloc(synlen);
03054
03055 desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03056 description = ast_malloc(desclen);
03057
03058 seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03059 seealso = ast_malloc(seealsolen);
03060
03061 if (!synopsis || !description || !seealso) {
03062 error = 1;
03063 goto return_cleanup;
03064 }
03065 term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
03066 term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
03067 term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
03068 }
03069
03070 stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03071 syntax = ast_malloc(stxlen);
03072 if (!syntax) {
03073 error = 1;
03074 goto return_cleanup;
03075 }
03076 term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
03077
03078 ast_cli(a->fd, "%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n", infotitle, stxtitle, syntax,
03079 desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
03080 seealsotitle, seealso);
03081 return_cleanup:
03082 ast_free(synopsis);
03083 ast_free(description);
03084 ast_free(syntax);
03085 ast_free(seealso);
03086 } else {
03087 if (find_command(a->argv + e->args, -1)) {
03088 return help_workhorse(a->fd, a->argv + e->args);
03089 } else {
03090 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03091 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
03092 }
03093 }
03094 } else {
03095 return help_workhorse(a->fd, NULL);
03096 }
03097 return (error ? CLI_FAILURE : CLI_SUCCESS);
03098 }
03099
03100
03101
03102
03103 static void write_html_escaped(FILE *htmlfile, char *str)
03104 {
03105 char *cur = str;
03106
03107 while(*cur) {
03108 switch (*cur) {
03109 case '<':
03110 fprintf(htmlfile, "%s", "<");
03111 break;
03112 case '>':
03113 fprintf(htmlfile, "%s", ">");
03114 break;
03115 case '&':
03116 fprintf(htmlfile, "%s", "&");
03117 break;
03118 case '"':
03119 fprintf(htmlfile, "%s", """);
03120 break;
03121 default:
03122 fprintf(htmlfile, "%c", *cur);
03123 break;
03124 }
03125 cur++;
03126 }
03127
03128 return;
03129 }
03130
03131 static int write_htmldump(char *filename)
03132 {
03133 struct agi_command *command;
03134 char fullcmd[MAX_CMD_LEN];
03135 FILE *htmlfile;
03136
03137 if (!(htmlfile = fopen(filename, "wt")))
03138 return -1;
03139
03140 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
03141 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
03142 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
03143
03144 AST_RWLIST_RDLOCK(&agi_commands);
03145 AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
03146 #ifdef AST_XML_DOCS
03147 char *stringptmp;
03148 #endif
03149 char *tempstr, *stringp;
03150
03151 if (!command->cmda[0])
03152 break;
03153
03154 if ((command->cmda[0])[0] == '_')
03155 continue;
03156 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
03157
03158 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
03159 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
03160 #ifdef AST_XML_DOCS
03161 stringptmp = ast_xmldoc_printable(command->usage, 0);
03162 stringp = stringptmp;
03163 #else
03164 stringp = command->usage;
03165 #endif
03166 tempstr = strsep(&stringp, "\n");
03167
03168 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
03169 write_html_escaped(htmlfile, tempstr);
03170 fprintf(htmlfile, "</TD></TR>\n");
03171 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
03172
03173 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
03174 write_html_escaped(htmlfile, tempstr);
03175 fprintf(htmlfile, "<BR>\n");
03176 }
03177 fprintf(htmlfile, "</TD></TR>\n");
03178 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
03179 #ifdef AST_XML_DOCS
03180 ast_free(stringptmp);
03181 #endif
03182 }
03183 AST_RWLIST_UNLOCK(&agi_commands);
03184 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
03185 fclose(htmlfile);
03186 return 0;
03187 }
03188
03189 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03190 {
03191 switch (cmd) {
03192 case CLI_INIT:
03193 e->command = "agi dump html";
03194 e->usage =
03195 "Usage: agi dump html <filename>\n"
03196 " Dumps the AGI command list in HTML format to the given\n"
03197 " file.\n";
03198 return NULL;
03199 case CLI_GENERATE:
03200 return NULL;
03201 }
03202 if (a->argc != e->args + 1)
03203 return CLI_SHOWUSAGE;
03204
03205 if (write_htmldump(a->argv[e->args]) < 0) {
03206 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
03207 return CLI_SHOWUSAGE;
03208 }
03209 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
03210 return CLI_SUCCESS;
03211 }
03212
03213 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
03214 {
03215 enum agi_result res;
03216 char buf[AGI_BUF_LEN] = "", *tmp = buf;
03217 int fds[2], efd = -1, pid;
03218 AST_DECLARE_APP_ARGS(args,
03219 AST_APP_ARG(arg)[MAX_ARGS];
03220 );
03221 AGI agi;
03222
03223 if (ast_strlen_zero(data)) {
03224 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
03225 return -1;
03226 }
03227 if (dead)
03228 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
03229 ast_copy_string(buf, data, sizeof(buf));
03230 memset(&agi, 0, sizeof(agi));
03231 AST_STANDARD_APP_ARGS(args, tmp);
03232 args.argv[args.argc] = NULL;
03233 #if 0
03234
03235 if (chan->_state != AST_STATE_UP) {
03236 if (ast_answer(chan))
03237 return -1;
03238 }
03239 #endif
03240 res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
03241
03242
03243 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
03244 int status = 0;
03245 agi.fd = fds[1];
03246 agi.ctrl = fds[0];
03247 agi.audio = efd;
03248 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
03249 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
03250
03251 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
03252 res = AGI_RESULT_FAILURE;
03253 if (fds[1] != fds[0])
03254 close(fds[1]);
03255 if (efd > -1)
03256 close(efd);
03257 }
03258 ast_safe_fork_cleanup();
03259
03260 switch (res) {
03261 case AGI_RESULT_SUCCESS:
03262 case AGI_RESULT_SUCCESS_FAST:
03263 case AGI_RESULT_SUCCESS_ASYNC:
03264 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
03265 break;
03266 case AGI_RESULT_FAILURE:
03267 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
03268 break;
03269 case AGI_RESULT_NOTFOUND:
03270 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
03271 break;
03272 case AGI_RESULT_HANGUP:
03273 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
03274 return -1;
03275 }
03276
03277 return 0;
03278 }
03279
03280 static int agi_exec(struct ast_channel *chan, void *data)
03281 {
03282 if (!ast_check_hangup(chan))
03283 return agi_exec_full(chan, data, 0, 0);
03284 else
03285 return agi_exec_full(chan, data, 0, 1);
03286 }
03287
03288 static int eagi_exec(struct ast_channel *chan, void *data)
03289 {
03290 int readformat, res;
03291
03292 if (ast_check_hangup(chan)) {
03293 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
03294 return 0;
03295 }
03296 readformat = chan->readformat;
03297 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
03298 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
03299 return -1;
03300 }
03301 res = agi_exec_full(chan, data, 1, 0);
03302 if (!res) {
03303 if (ast_set_read_format(chan, readformat)) {
03304 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
03305 }
03306 }
03307 return res;
03308 }
03309
03310 static int deadagi_exec(struct ast_channel *chan, void *data)
03311 {
03312 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
03313 return agi_exec(chan, data);
03314 }
03315
03316 static struct ast_cli_entry cli_agi[] = {
03317 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
03318 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
03319 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
03320 AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
03321 };
03322
03323 static int unload_module(void)
03324 {
03325 ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
03326
03327
03328
03329 (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03330 ast_unregister_application(eapp);
03331 ast_unregister_application(deadapp);
03332 ast_manager_unregister("AGI");
03333 return ast_unregister_application(app);
03334 }
03335
03336 static int load_module(void)
03337 {
03338 ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
03339
03340
03341
03342 (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
03343 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
03344 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
03345 ast_manager_register2("AGI", EVENT_FLAG_AGI, action_add_agi_cmd, "Add an AGI command to execute by Async AGI", mandescr_asyncagi);
03346 return ast_register_application(app, agi_exec, synopsis, descrip);
03347 }
03348
03349 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Asterisk Gateway Interface (AGI)",
03350 .load = load_module,
03351 .unload = unload_module,
03352 );