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