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 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 146129 $")
00029
00030 #include <sys/types.h>
00031 #include <netdb.h>
00032 #include <sys/socket.h>
00033 #include <netinet/in.h>
00034 #include <netinet/tcp.h>
00035 #include <arpa/inet.h>
00036 #include <math.h>
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 #include <string.h>
00040 #include <stdlib.h>
00041 #include <signal.h>
00042 #include <sys/time.h>
00043 #include <stdio.h>
00044 #include <fcntl.h>
00045 #include <errno.h>
00046 #include <sys/wait.h>
00047
00048 #include "asterisk/file.h"
00049 #include "asterisk/logger.h"
00050 #include "asterisk/channel.h"
00051 #include "asterisk/pbx.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/astdb.h"
00054 #include "asterisk/callerid.h"
00055 #include "asterisk/cli.h"
00056 #include "asterisk/logger.h"
00057 #include "asterisk/options.h"
00058 #include "asterisk/image.h"
00059 #include "asterisk/say.h"
00060 #include "asterisk/app.h"
00061 #include "asterisk/dsp.h"
00062 #include "asterisk/musiconhold.h"
00063 #include "asterisk/utils.h"
00064 #include "asterisk/lock.h"
00065 #include "asterisk/strings.h"
00066 #include "asterisk/agi.h"
00067 #include "asterisk/features.h"
00068
00069 #define MAX_ARGS 128
00070 #define MAX_COMMANDS 128
00071 #define AGI_NANDFS_RETRY 3
00072 #define AGI_BUF_LEN 2048
00073
00074
00075 #define fdprintf agi_debug_cli
00076
00077 static char *app = "AGI";
00078
00079 static char *eapp = "EAGI";
00080
00081 static char *deadapp = "DeadAGI";
00082
00083 static char *synopsis = "Executes an AGI compliant application";
00084 static char *esynopsis = "Executes an EAGI compliant application";
00085 static char *deadsynopsis = "Executes AGI on a hungup channel";
00086
00087 static char *descrip =
00088 " [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
00089 "program on a channel. AGI allows Asterisk to launch external programs\n"
00090 "written in any language to control a telephony channel, play audio,\n"
00091 "read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
00092 "and stdout.\n"
00093 " This channel will stop dialplan execution on hangup inside of this\n"
00094 "application, except when using DeadAGI. Otherwise, dialplan execution\n"
00095 "will continue normally.\n"
00096 " A locally executed AGI script will receive SIGHUP on hangup from the channel\n"
00097 "except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel\n"
00098 "variable to \"no\" before executing the AGI application.\n"
00099 " Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n"
00100 "on file descriptor 3\n\n"
00101 " Use the CLI command 'agi show' to list available agi commands\n"
00102 " This application sets the following channel variable upon completion:\n"
00103 " AGISTATUS The status of the attempt to the run the AGI script\n"
00104 " text string, one of SUCCESS | FAILURE | HANGUP\n";
00105
00106 static int agidebug = 0;
00107
00108 #define TONE_BLOCK_SIZE 200
00109
00110
00111 #define MAX_AGI_CONNECT 2000
00112
00113 #define AGI_PORT 4573
00114
00115 enum agi_result {
00116 AGI_RESULT_FAILURE = -1,
00117 AGI_RESULT_SUCCESS,
00118 AGI_RESULT_SUCCESS_FAST,
00119 AGI_RESULT_HANGUP
00120 };
00121
00122 static int agi_debug_cli(int fd, char *fmt, ...)
00123 {
00124 char *stuff;
00125 int res = 0;
00126
00127 va_list ap;
00128 va_start(ap, fmt);
00129 res = vasprintf(&stuff, fmt, ap);
00130 va_end(ap);
00131 if (res == -1) {
00132 ast_log(LOG_ERROR, "Out of memory\n");
00133 } else {
00134 if (agidebug)
00135 ast_verbose("AGI Tx >> %s", stuff);
00136 res = ast_carefulwrite(fd, stuff, strlen(stuff), 100);
00137 free(stuff);
00138 }
00139
00140 return res;
00141 }
00142
00143
00144
00145 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid)
00146 {
00147 int s;
00148 int flags;
00149 struct pollfd pfds[1];
00150 char *host;
00151 char *c; int port = AGI_PORT;
00152 char *script="";
00153 struct sockaddr_in sin;
00154 struct hostent *hp;
00155 struct ast_hostent ahp;
00156 int res;
00157
00158
00159 host = ast_strdupa(agiurl + 6);
00160
00161 if ((c = strchr(host, '/'))) {
00162 *c = '\0';
00163 c++;
00164 script = c;
00165 }
00166 if ((c = strchr(host, ':'))) {
00167 *c = '\0';
00168 c++;
00169 port = atoi(c);
00170 }
00171 if (efd) {
00172 ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n");
00173 return -1;
00174 }
00175 hp = ast_gethostbyname(host, &ahp);
00176 if (!hp) {
00177 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
00178 return -1;
00179 }
00180 s = socket(AF_INET, SOCK_STREAM, 0);
00181 if (s < 0) {
00182 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
00183 return -1;
00184 }
00185 flags = fcntl(s, F_GETFL);
00186 if (flags < 0) {
00187 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
00188 close(s);
00189 return -1;
00190 }
00191 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
00192 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
00193 close(s);
00194 return -1;
00195 }
00196 memset(&sin, 0, sizeof(sin));
00197 sin.sin_family = AF_INET;
00198 sin.sin_port = htons(port);
00199 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
00200 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) {
00201 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
00202 close(s);
00203 return AGI_RESULT_FAILURE;
00204 }
00205
00206 pfds[0].fd = s;
00207 pfds[0].events = POLLOUT;
00208 while ((res = poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
00209 if (errno != EINTR) {
00210 if (!res) {
00211 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
00212 agiurl, MAX_AGI_CONNECT);
00213 } else
00214 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
00215 close(s);
00216 return AGI_RESULT_FAILURE;
00217 }
00218 }
00219
00220 if (fdprintf(s, "agi_network: yes\n") < 0) {
00221 if (errno != EINTR) {
00222 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
00223 close(s);
00224 return AGI_RESULT_FAILURE;
00225 }
00226 }
00227
00228
00229 if (!ast_strlen_zero(script))
00230 fdprintf(s, "agi_network_script: %s\n", script);
00231
00232 if (option_debug > 3)
00233 ast_log(LOG_DEBUG, "Wow, connected!\n");
00234 fds[0] = s;
00235 fds[1] = s;
00236 *opid = -1;
00237 return AGI_RESULT_SUCCESS_FAST;
00238 }
00239
00240 static enum agi_result launch_script(char *script, char *argv[], int *fds, int *efd, int *opid)
00241 {
00242 char tmp[256];
00243 int pid;
00244 int toast[2];
00245 int fromast[2];
00246 int audio[2];
00247 int x;
00248 int res;
00249 sigset_t signal_set, old_set;
00250
00251 if (!strncasecmp(script, "agi://", 6))
00252 return launch_netscript(script, argv, fds, efd, opid);
00253
00254 if (script[0] != '/') {
00255 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script);
00256 script = tmp;
00257 }
00258 if (pipe(toast)) {
00259 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
00260 return AGI_RESULT_FAILURE;
00261 }
00262 if (pipe(fromast)) {
00263 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
00264 close(toast[0]);
00265 close(toast[1]);
00266 return AGI_RESULT_FAILURE;
00267 }
00268 if (efd) {
00269 if (pipe(audio)) {
00270 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
00271 close(fromast[0]);
00272 close(fromast[1]);
00273 close(toast[0]);
00274 close(toast[1]);
00275 return AGI_RESULT_FAILURE;
00276 }
00277 res = fcntl(audio[1], F_GETFL);
00278 if (res > -1)
00279 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
00280 if (res < 0) {
00281 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
00282 close(fromast[0]);
00283 close(fromast[1]);
00284 close(toast[0]);
00285 close(toast[1]);
00286 close(audio[0]);
00287 close(audio[1]);
00288 return AGI_RESULT_FAILURE;
00289 }
00290 }
00291
00292
00293 sigfillset(&signal_set);
00294 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
00295 pid = fork();
00296 if (pid < 0) {
00297 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
00298 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
00299 return AGI_RESULT_FAILURE;
00300 }
00301 if (!pid) {
00302
00303 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
00304 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
00305 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
00306 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
00307 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
00308 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
00309 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
00310 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
00311 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
00312 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
00313 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
00314
00315
00316 ast_set_priority(0);
00317
00318
00319 dup2(fromast[0], STDIN_FILENO);
00320 dup2(toast[1], STDOUT_FILENO);
00321 if (efd) {
00322 dup2(audio[0], STDERR_FILENO + 1);
00323 } else {
00324 close(STDERR_FILENO + 1);
00325 }
00326
00327
00328 signal(SIGHUP, SIG_DFL);
00329 signal(SIGCHLD, SIG_DFL);
00330 signal(SIGINT, SIG_DFL);
00331 signal(SIGURG, SIG_DFL);
00332 signal(SIGTERM, SIG_DFL);
00333 signal(SIGPIPE, SIG_DFL);
00334 signal(SIGXFSZ, SIG_DFL);
00335
00336
00337 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
00338 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
00339 _exit(1);
00340 }
00341
00342
00343 for (x=STDERR_FILENO + 2;x<1024;x++)
00344 close(x);
00345
00346
00347 execv(script, argv);
00348
00349 fprintf(stdout, "verbose \"Failed to execute '%s': %s\" 2\n", script, strerror(errno));
00350
00351 fprintf(stdout, "failure\n");
00352 fflush(stdout);
00353 _exit(1);
00354 }
00355 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
00356 if (option_verbose > 2)
00357 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
00358 fds[0] = toast[0];
00359 fds[1] = fromast[1];
00360 if (efd) {
00361 *efd = audio[1];
00362 }
00363
00364 close(toast[1]);
00365 close(fromast[0]);
00366
00367 if (efd)
00368 close(audio[0]);
00369
00370 *opid = pid;
00371 return AGI_RESULT_SUCCESS;
00372 }
00373
00374 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
00375 {
00376
00377
00378 fdprintf(fd, "agi_request: %s\n", request);
00379 fdprintf(fd, "agi_channel: %s\n", chan->name);
00380 fdprintf(fd, "agi_language: %s\n", chan->language);
00381 fdprintf(fd, "agi_type: %s\n", chan->tech->type);
00382 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
00383
00384
00385 fdprintf(fd, "agi_callerid: %s\n", S_OR(chan->cid.cid_num, "unknown"));
00386 fdprintf(fd, "agi_calleridname: %s\n", S_OR(chan->cid.cid_name, "unknown"));
00387 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
00388 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
00389 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
00390 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
00391 fdprintf(fd, "agi_dnid: %s\n", S_OR(chan->cid.cid_dnid, "unknown"));
00392 fdprintf(fd, "agi_rdnis: %s\n", S_OR(chan->cid.cid_rdnis, "unknown"));
00393
00394
00395 fdprintf(fd, "agi_context: %s\n", chan->context);
00396 fdprintf(fd, "agi_extension: %s\n", chan->exten);
00397 fdprintf(fd, "agi_priority: %d\n", chan->priority);
00398 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
00399
00400
00401 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
00402
00403
00404 fdprintf(fd, "\n");
00405 }
00406
00407 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00408 {
00409 int res;
00410 res = 0;
00411 if (chan->_state != AST_STATE_UP) {
00412
00413 res = ast_answer(chan);
00414 }
00415 fdprintf(agi->fd, "200 result=%d\n", res);
00416 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00417 }
00418
00419 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00420 {
00421 int res;
00422 int to;
00423 if (argc != 4)
00424 return RESULT_SHOWUSAGE;
00425 if (sscanf(argv[3], "%d", &to) != 1)
00426 return RESULT_SHOWUSAGE;
00427 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
00428 fdprintf(agi->fd, "200 result=%d\n", res);
00429 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00430 }
00431
00432 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00433 {
00434 int res;
00435 if (argc != 3)
00436 return RESULT_SHOWUSAGE;
00437
00438
00439
00440
00441
00442
00443
00444 res = ast_sendtext(chan, argv[2]);
00445 fdprintf(agi->fd, "200 result=%d\n", res);
00446 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00447 }
00448
00449 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00450 {
00451 int res;
00452 if (argc != 3)
00453 return RESULT_SHOWUSAGE;
00454 res = ast_recvchar(chan,atoi(argv[2]));
00455 if (res == 0) {
00456 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
00457 return RESULT_SUCCESS;
00458 }
00459 if (res > 0) {
00460 fdprintf(agi->fd, "200 result=%d\n", res);
00461 return RESULT_SUCCESS;
00462 }
00463 else {
00464 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
00465 return RESULT_FAILURE;
00466 }
00467 }
00468
00469 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00470 {
00471 char *buf;
00472
00473 if (argc != 3)
00474 return RESULT_SHOWUSAGE;
00475 buf = ast_recvtext(chan,atoi(argv[2]));
00476 if (buf) {
00477 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
00478 free(buf);
00479 } else {
00480 fdprintf(agi->fd, "200 result=-1\n");
00481 }
00482 return RESULT_SUCCESS;
00483 }
00484
00485 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00486 {
00487 int res,x;
00488 if (argc != 3)
00489 return RESULT_SHOWUSAGE;
00490 if (!strncasecmp(argv[2],"on",2))
00491 x = 1;
00492 else
00493 x = 0;
00494 if (!strncasecmp(argv[2],"mate",4))
00495 x = 2;
00496 if (!strncasecmp(argv[2],"tdd",3))
00497 x = 1;
00498 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
00499 if (res != RESULT_SUCCESS)
00500 fdprintf(agi->fd, "200 result=0\n");
00501 else
00502 fdprintf(agi->fd, "200 result=1\n");
00503 return RESULT_SUCCESS;
00504 }
00505
00506 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00507 {
00508 int res;
00509 if (argc != 3)
00510 return RESULT_SHOWUSAGE;
00511 res = ast_send_image(chan, argv[2]);
00512 if (!ast_check_hangup(chan))
00513 res = 0;
00514 fdprintf(agi->fd, "200 result=%d\n", res);
00515 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00516 }
00517
00518 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00519 {
00520 int res = 0;
00521 int skipms = 3000;
00522 char *fwd = NULL;
00523 char *rev = NULL;
00524 char *pause = NULL;
00525 char *stop = NULL;
00526
00527 if (argc < 5 || argc > 9)
00528 return RESULT_SHOWUSAGE;
00529
00530 if (!ast_strlen_zero(argv[4]))
00531 stop = argv[4];
00532 else
00533 stop = NULL;
00534
00535 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
00536 return RESULT_SHOWUSAGE;
00537
00538 if (argc > 6 && !ast_strlen_zero(argv[6]))
00539 fwd = argv[6];
00540 else
00541 fwd = "#";
00542
00543 if (argc > 7 && !ast_strlen_zero(argv[7]))
00544 rev = argv[7];
00545 else
00546 rev = "*";
00547
00548 if (argc > 8 && !ast_strlen_zero(argv[8]))
00549 pause = argv[8];
00550 else
00551 pause = NULL;
00552
00553 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
00554
00555 fdprintf(agi->fd, "200 result=%d\n", res);
00556
00557 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00558 }
00559
00560 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00561 {
00562 int res;
00563 int vres;
00564 struct ast_filestream *fs;
00565 struct ast_filestream *vfs;
00566 long sample_offset = 0;
00567 long max_length;
00568 char *edigits = "";
00569
00570 if (argc < 4 || argc > 5)
00571 return RESULT_SHOWUSAGE;
00572
00573 if (argv[3])
00574 edigits = argv[3];
00575
00576 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
00577 return RESULT_SHOWUSAGE;
00578
00579 fs = ast_openstream(chan, argv[2], chan->language);
00580
00581 if (!fs) {
00582 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
00583 return RESULT_SUCCESS;
00584 }
00585 vfs = ast_openvstream(chan, argv[2], chan->language);
00586 if (vfs)
00587 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
00588
00589 if (option_verbose > 2)
00590 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
00591
00592 ast_seekstream(fs, 0, SEEK_END);
00593 max_length = ast_tellstream(fs);
00594 ast_seekstream(fs, sample_offset, SEEK_SET);
00595 res = ast_applystream(chan, fs);
00596 if (vfs)
00597 vres = ast_applystream(chan, vfs);
00598 ast_playstream(fs);
00599 if (vfs)
00600 ast_playstream(vfs);
00601
00602 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
00603
00604
00605 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
00606 ast_stopstream(chan);
00607 if (res == 1) {
00608
00609 return RESULT_SUCCESS;
00610 }
00611 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
00612 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00613 }
00614
00615
00616 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00617 {
00618 int res;
00619 int vres;
00620 struct ast_filestream *fs;
00621 struct ast_filestream *vfs;
00622 long sample_offset = 0;
00623 long max_length;
00624 int timeout = 0;
00625 char *edigits = "";
00626
00627 if ( argc < 4 || argc > 5 )
00628 return RESULT_SHOWUSAGE;
00629
00630 if ( argv[3] )
00631 edigits = argv[3];
00632
00633 if ( argc == 5 )
00634 timeout = atoi(argv[4]);
00635 else if (chan->pbx->dtimeout) {
00636
00637 timeout = chan->pbx->dtimeout * 1000;
00638 }
00639
00640 fs = ast_openstream(chan, argv[2], chan->language);
00641 if (!fs) {
00642 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
00643 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
00644 return RESULT_SUCCESS;
00645 }
00646 vfs = ast_openvstream(chan, argv[2], chan->language);
00647 if (vfs)
00648 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
00649
00650 if (option_verbose > 2)
00651 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
00652
00653 ast_seekstream(fs, 0, SEEK_END);
00654 max_length = ast_tellstream(fs);
00655 ast_seekstream(fs, sample_offset, SEEK_SET);
00656 res = ast_applystream(chan, fs);
00657 if (vfs)
00658 vres = ast_applystream(chan, vfs);
00659 ast_playstream(fs);
00660 if (vfs)
00661 ast_playstream(vfs);
00662
00663 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
00664
00665
00666 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
00667 ast_stopstream(chan);
00668 if (res == 1) {
00669
00670 return RESULT_SUCCESS;
00671 }
00672
00673
00674 if (res == 0 ) {
00675 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
00676
00677 if ( !strchr(edigits,res) )
00678 res=0;
00679 }
00680
00681 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
00682 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00683 }
00684
00685
00686
00687
00688
00689
00690
00691 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00692 {
00693 int res;
00694 int num;
00695 if (argc != 4)
00696 return RESULT_SHOWUSAGE;
00697 if (sscanf(argv[2], "%d", &num) != 1)
00698 return RESULT_SHOWUSAGE;
00699 res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl);
00700 if (res == 1)
00701 return RESULT_SUCCESS;
00702 fdprintf(agi->fd, "200 result=%d\n", res);
00703 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00704 }
00705
00706 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00707 {
00708 int res;
00709 int num;
00710
00711 if (argc != 4)
00712 return RESULT_SHOWUSAGE;
00713 if (sscanf(argv[2], "%d", &num) != 1)
00714 return RESULT_SHOWUSAGE;
00715
00716 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
00717 if (res == 1)
00718 return RESULT_SUCCESS;
00719 fdprintf(agi->fd, "200 result=%d\n", res);
00720 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00721 }
00722
00723 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00724 {
00725 int res;
00726
00727 if (argc != 4)
00728 return RESULT_SHOWUSAGE;
00729
00730 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
00731 if (res == 1)
00732 return RESULT_SUCCESS;
00733 fdprintf(agi->fd, "200 result=%d\n", res);
00734 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00735 }
00736
00737 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00738 {
00739 int res;
00740 int num;
00741 if (argc != 4)
00742 return RESULT_SHOWUSAGE;
00743 if (sscanf(argv[2], "%d", &num) != 1)
00744 return RESULT_SHOWUSAGE;
00745 res = ast_say_date(chan, num, argv[3], chan->language);
00746 if (res == 1)
00747 return RESULT_SUCCESS;
00748 fdprintf(agi->fd, "200 result=%d\n", res);
00749 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00750 }
00751
00752 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00753 {
00754 int res;
00755 int num;
00756 if (argc != 4)
00757 return RESULT_SHOWUSAGE;
00758 if (sscanf(argv[2], "%d", &num) != 1)
00759 return RESULT_SHOWUSAGE;
00760 res = ast_say_time(chan, num, argv[3], chan->language);
00761 if (res == 1)
00762 return RESULT_SUCCESS;
00763 fdprintf(agi->fd, "200 result=%d\n", res);
00764 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00765 }
00766
00767 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00768 {
00769 int res=0;
00770 time_t unixtime;
00771 char *format, *zone=NULL;
00772
00773 if (argc < 4)
00774 return RESULT_SHOWUSAGE;
00775
00776 if (argc > 4) {
00777 format = argv[4];
00778 } else {
00779
00780 if (!strcasecmp(chan->language, "de")) {
00781 format = "A dBY HMS";
00782 } else {
00783 format = "ABdY 'digits/at' IMp";
00784 }
00785 }
00786
00787 if (argc > 5 && !ast_strlen_zero(argv[5]))
00788 zone = argv[5];
00789
00790 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
00791 return RESULT_SHOWUSAGE;
00792
00793 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
00794 if (res == 1)
00795 return RESULT_SUCCESS;
00796
00797 fdprintf(agi->fd, "200 result=%d\n", res);
00798 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00799 }
00800
00801 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00802 {
00803 int res;
00804
00805 if (argc != 4)
00806 return RESULT_SHOWUSAGE;
00807
00808 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
00809 if (res == 1)
00810 return RESULT_SUCCESS;
00811 fdprintf(agi->fd, "200 result=%d\n", res);
00812 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
00813 }
00814
00815 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00816 {
00817 int res;
00818 char data[1024];
00819 int max;
00820 int timeout;
00821
00822 if (argc < 3)
00823 return RESULT_SHOWUSAGE;
00824 if (argc >= 4)
00825 timeout = atoi(argv[3]);
00826 else
00827 timeout = 0;
00828 if (argc >= 5)
00829 max = atoi(argv[4]);
00830 else
00831 max = 1024;
00832 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
00833 if (res == 2)
00834 return RESULT_SUCCESS;
00835 else if (res == 1)
00836 fdprintf(agi->fd, "200 result=%s (timeout)\n", data);
00837 else if (res < 0 )
00838 fdprintf(agi->fd, "200 result=-1\n");
00839 else
00840 fdprintf(agi->fd, "200 result=%s\n", data);
00841 return RESULT_SUCCESS;
00842 }
00843
00844 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00845 {
00846
00847 if (argc != 3)
00848 return RESULT_SHOWUSAGE;
00849 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
00850 fdprintf(agi->fd, "200 result=0\n");
00851 return RESULT_SUCCESS;
00852 }
00853
00854 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv)
00855 {
00856 if (argc != 3)
00857 return RESULT_SHOWUSAGE;
00858 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
00859 fdprintf(agi->fd, "200 result=0\n");
00860 return RESULT_SUCCESS;
00861 }
00862
00863 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv)
00864 {
00865 int pri;
00866 if (argc != 3)
00867 return RESULT_SHOWUSAGE;
00868
00869 if (sscanf(argv[2], "%d", &pri) != 1) {
00870 if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1)
00871 return RESULT_SHOWUSAGE;
00872 }
00873
00874 ast_explicit_goto(chan, NULL, NULL, pri);
00875 fdprintf(agi->fd, "200 result=0\n");
00876 return RESULT_SUCCESS;
00877 }
00878
00879 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00880 {
00881 struct ast_filestream *fs;
00882 struct ast_frame *f;
00883 struct timeval start;
00884 long sample_offset = 0;
00885 int res = 0;
00886 int ms;
00887
00888 struct ast_dsp *sildet=NULL;
00889 int totalsilence = 0;
00890 int dspsilence = 0;
00891 int silence = 0;
00892 int gotsilence = 0;
00893 char *silencestr=NULL;
00894 int rfmt=0;
00895
00896
00897
00898
00899 if (argc < 6)
00900 return RESULT_SHOWUSAGE;
00901 if (sscanf(argv[5], "%d", &ms) != 1)
00902 return RESULT_SHOWUSAGE;
00903
00904 if (argc > 6)
00905 silencestr = strchr(argv[6],'s');
00906 if ((argc > 7) && (!silencestr))
00907 silencestr = strchr(argv[7],'s');
00908 if ((argc > 8) && (!silencestr))
00909 silencestr = strchr(argv[8],'s');
00910
00911 if (silencestr) {
00912 if (strlen(silencestr) > 2) {
00913 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
00914 silencestr++;
00915 silencestr++;
00916 if (silencestr)
00917 silence = atoi(silencestr);
00918 if (silence > 0)
00919 silence *= 1000;
00920 }
00921 }
00922 }
00923
00924 if (silence > 0) {
00925 rfmt = chan->readformat;
00926 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00927 if (res < 0) {
00928 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00929 return -1;
00930 }
00931 sildet = ast_dsp_new();
00932 if (!sildet) {
00933 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00934 return -1;
00935 }
00936 ast_dsp_set_threshold(sildet, 256);
00937 }
00938
00939
00940
00941
00942 if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
00943 res = ast_streamfile(chan, "beep", chan->language);
00944
00945 if ((argc > 7) && (!strchr(argv[7], '=')))
00946 res = ast_streamfile(chan, "beep", chan->language);
00947
00948 if (!res)
00949 res = ast_waitstream(chan, argv[4]);
00950 if (res) {
00951 fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
00952 } else {
00953 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
00954 if (!fs) {
00955 res = -1;
00956 fdprintf(agi->fd, "200 result=%d (writefile)\n", res);
00957 if (sildet)
00958 ast_dsp_free(sildet);
00959 return RESULT_FAILURE;
00960 }
00961
00962
00963 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
00964
00965 chan->stream = fs;
00966 ast_applystream(chan,fs);
00967
00968 ast_seekstream(fs, sample_offset, SEEK_SET);
00969 ast_truncstream(fs);
00970
00971 start = ast_tvnow();
00972 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
00973 res = ast_waitfor(chan, -1);
00974 if (res < 0) {
00975 ast_closestream(fs);
00976 fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
00977 if (sildet)
00978 ast_dsp_free(sildet);
00979 return RESULT_FAILURE;
00980 }
00981 f = ast_read(chan);
00982 if (!f) {
00983 fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
00984 ast_closestream(fs);
00985 if (sildet)
00986 ast_dsp_free(sildet);
00987 return RESULT_FAILURE;
00988 }
00989 switch(f->frametype) {
00990 case AST_FRAME_DTMF:
00991 if (strchr(argv[4], f->subclass)) {
00992
00993
00994
0