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: 37419 $")
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;
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 pid = fork();
00280 if (pid < 0) {
00281 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
00282 return -1;
00283 }
00284 if (!pid) {
00285
00286 ast_set_priority(0);
00287
00288
00289 dup2(fromast[0], STDIN_FILENO);
00290 dup2(toast[1], STDOUT_FILENO);
00291 if (efd) {
00292 dup2(audio[0], STDERR_FILENO + 1);
00293 } else {
00294 close(STDERR_FILENO + 1);
00295 }
00296
00297
00298 if (sigfillset(&signal_set) || pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
00299 ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno));
00300 exit(1);
00301 }
00302
00303
00304 for (x=STDERR_FILENO + 2;x<1024;x++)
00305 close(x);
00306
00307
00308 execv(script, argv);
00309
00310 fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
00311 exit(1);
00312 }
00313 if (option_verbose > 2)
00314 ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
00315 fds[0] = toast[0];
00316 fds[1] = fromast[1];
00317 if (efd) {
00318 *efd = audio[1];
00319 }
00320
00321 close(toast[1]);
00322 close(fromast[0]);
00323
00324 if (efd) {
00325
00326 close(audio[0]);
00327 }
00328
00329 *opid = pid;
00330 return 0;
00331
00332 }
00333
00334 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced)
00335 {
00336
00337
00338 fdprintf(fd, "agi_request: %s\n", request);
00339 fdprintf(fd, "agi_channel: %s\n", chan->name);
00340 fdprintf(fd, "agi_language: %s\n", chan->language);
00341 fdprintf(fd, "agi_type: %s\n", chan->type);
00342 fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid);
00343
00344
00345 fdprintf(fd, "agi_callerid: %s\n", chan->cid.cid_num ? chan->cid.cid_num : "unknown");
00346 fdprintf(fd, "agi_calleridname: %s\n", chan->cid.cid_name ? chan->cid.cid_name : "unknown");
00347 fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres);
00348 fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2);
00349 fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton);
00350 fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns);
00351 fdprintf(fd, "agi_dnid: %s\n", chan->cid.cid_dnid ? chan->cid.cid_dnid : "unknown");
00352 fdprintf(fd, "agi_rdnis: %s\n", chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "unknown");
00353
00354
00355 fdprintf(fd, "agi_context: %s\n", chan->context);
00356 fdprintf(fd, "agi_extension: %s\n", chan->exten);
00357 fdprintf(fd, "agi_priority: %d\n", chan->priority);
00358 fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
00359
00360
00361 fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
00362
00363
00364 fdprintf(fd, "\n");
00365 }
00366
00367 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00368 {
00369 int res;
00370 res = 0;
00371 if (chan->_state != AST_STATE_UP) {
00372
00373 res = ast_answer(chan);
00374 }
00375 fdprintf(agi->fd, "200 result=%d\n", res);
00376 if (res >= 0)
00377 return RESULT_SUCCESS;
00378 else
00379 return RESULT_FAILURE;
00380 }
00381
00382 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00383 {
00384 int res;
00385 int to;
00386 if (argc != 4)
00387 return RESULT_SHOWUSAGE;
00388 if (sscanf(argv[3], "%d", &to) != 1)
00389 return RESULT_SHOWUSAGE;
00390 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
00391 fdprintf(agi->fd, "200 result=%d\n", res);
00392 if (res >= 0)
00393 return RESULT_SUCCESS;
00394 else
00395 return RESULT_FAILURE;
00396 }
00397
00398 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00399 {
00400 int res;
00401 if (argc != 3)
00402 return RESULT_SHOWUSAGE;
00403
00404
00405
00406
00407
00408
00409
00410 res = ast_sendtext(chan, argv[2]);
00411 fdprintf(agi->fd, "200 result=%d\n", res);
00412 if (res >= 0)
00413 return RESULT_SUCCESS;
00414 else
00415 return RESULT_FAILURE;
00416 }
00417
00418 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00419 {
00420 int res;
00421 if (argc != 3)
00422 return RESULT_SHOWUSAGE;
00423 res = ast_recvchar(chan,atoi(argv[2]));
00424 if (res == 0) {
00425 fdprintf(agi->fd, "200 result=%d (timeout)\n", res);
00426 return RESULT_SUCCESS;
00427 }
00428 if (res > 0) {
00429 fdprintf(agi->fd, "200 result=%d\n", res);
00430 return RESULT_SUCCESS;
00431 }
00432 else {
00433 fdprintf(agi->fd, "200 result=%d (hangup)\n", res);
00434 return RESULT_FAILURE;
00435 }
00436 }
00437
00438 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00439 {
00440 char *buf;
00441
00442 if (argc != 3)
00443 return RESULT_SHOWUSAGE;
00444 buf = ast_recvtext(chan,atoi(argv[2]));
00445 if (buf) {
00446 fdprintf(agi->fd, "200 result=1 (%s)\n", buf);
00447 free(buf);
00448 } else {
00449 fdprintf(agi->fd, "200 result=-1\n");
00450 }
00451 return RESULT_SUCCESS;
00452 }
00453
00454 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00455 {
00456 int res,x;
00457 if (argc != 3)
00458 return RESULT_SHOWUSAGE;
00459 if (!strncasecmp(argv[2],"on",2))
00460 x = 1;
00461 else
00462 x = 0;
00463 if (!strncasecmp(argv[2],"mate",4))
00464 x = 2;
00465 if (!strncasecmp(argv[2],"tdd",3))
00466 x = 1;
00467 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
00468 if (res != RESULT_SUCCESS)
00469 fdprintf(agi->fd, "200 result=0\n");
00470 else
00471 fdprintf(agi->fd, "200 result=1\n");
00472 return RESULT_SUCCESS;
00473 }
00474
00475 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00476 {
00477 int res;
00478 if (argc != 3)
00479 return RESULT_SHOWUSAGE;
00480 res = ast_send_image(chan, argv[2]);
00481 if (!ast_check_hangup(chan))
00482 res = 0;
00483 fdprintf(agi->fd, "200 result=%d\n", res);
00484 if (res >= 0)
00485 return RESULT_SUCCESS;
00486 else
00487 return RESULT_FAILURE;
00488 }
00489
00490 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00491 {
00492 int res = 0;
00493 int skipms = 3000;
00494 char *fwd = NULL;
00495 char *rev = NULL;
00496 char *pause = NULL;
00497 char *stop = NULL;
00498
00499 if (argc < 5 || argc > 9)
00500 return RESULT_SHOWUSAGE;
00501
00502 if (!ast_strlen_zero(argv[4]))
00503 stop = argv[4];
00504 else
00505 stop = NULL;
00506
00507 if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1))
00508 return RESULT_SHOWUSAGE;
00509
00510 if (argc > 6 && !ast_strlen_zero(argv[8]))
00511 fwd = argv[6];
00512 else
00513 fwd = "#";
00514
00515 if (argc > 7 && !ast_strlen_zero(argv[8]))
00516 rev = argv[7];
00517 else
00518 rev = "*";
00519
00520 if (argc > 8 && !ast_strlen_zero(argv[8]))
00521 pause = argv[8];
00522 else
00523 pause = NULL;
00524
00525 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms);
00526
00527 fdprintf(agi->fd, "200 result=%d\n", res);
00528
00529 if (res >= 0)
00530 return RESULT_SUCCESS;
00531 else
00532 return RESULT_FAILURE;
00533 }
00534
00535 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00536 {
00537 int res;
00538 struct ast_filestream *fs;
00539 long sample_offset = 0;
00540 long max_length;
00541
00542 if (argc < 4)
00543 return RESULT_SHOWUSAGE;
00544 if (argc > 5)
00545 return RESULT_SHOWUSAGE;
00546 if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1))
00547 return RESULT_SHOWUSAGE;
00548
00549 fs = ast_openstream(chan, argv[2], chan->language);
00550 if (!fs){
00551 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
00552 return RESULT_SUCCESS;
00553 }
00554 ast_seekstream(fs, 0, SEEK_END);
00555 max_length = ast_tellstream(fs);
00556 ast_seekstream(fs, sample_offset, SEEK_SET);
00557 res = ast_applystream(chan, fs);
00558 res = ast_playstream(fs);
00559 if (res) {
00560 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
00561 if (res >= 0)
00562 return RESULT_SHOWUSAGE;
00563 else
00564 return RESULT_FAILURE;
00565 }
00566 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
00567
00568
00569 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
00570 ast_stopstream(chan);
00571 if (res == 1) {
00572
00573 return RESULT_SUCCESS;
00574 }
00575 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
00576 if (res >= 0)
00577 return RESULT_SUCCESS;
00578 else
00579 return RESULT_FAILURE;
00580 }
00581
00582
00583 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
00584 {
00585 int res;
00586 struct ast_filestream *fs;
00587 long sample_offset = 0;
00588 long max_length;
00589 int timeout = 0;
00590 char *edigits = NULL;
00591
00592 if ( argc < 4 || argc > 5 )
00593 return RESULT_SHOWUSAGE;
00594
00595 if ( argv[3] )
00596 edigits = argv[3];
00597
00598 if ( argc == 5 )
00599 timeout = atoi(argv[4]);
00600 else if (chan->pbx->dtimeout) {
00601
00602 timeout = chan->pbx->dtimeout * 1000;
00603 }
00604
00605 fs = ast_openstream(chan, argv[2], chan->language);
00606 if (!fs){
00607 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset);
00608 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
00609 return RESULT_SUCCESS;
00610 }
00611 if (option_verbose > 2)
00612 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
00613
00614 ast_seekstream(fs, 0, SEEK_END);
00615 max_length = ast_tellstream(fs);
00616 ast_seekstream(fs, sample_offset, SEEK_SET);
00617 res = ast_applystream(chan, fs);
00618 res = ast_playstream(fs);
00619 if (res) {
00620 fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset);
00621 if (res >= 0)
00622 return RESULT_SHOWUSAGE;
00623 else
00624 return RESULT_FAILURE;
00625 }
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 }
01040
01041 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01042 {
01043 int timeout;
01044
01045 if (argc != 3)
01046 return RESULT_SHOWUSAGE;
01047 if (sscanf(argv[2], "%d", &timeout) != 1)
01048 return RESULT_SHOWUSAGE;
01049 if (timeout < 0)
01050 timeout = 0;
01051 if (timeout)
01052 chan->whentohangup = time(NULL) + timeout;
01053 else
01054 chan->whentohangup = 0;
01055 fdprintf(agi->fd, "200 result=0\n");
01056 return RESULT_SUCCESS;
01057 }
01058
01059 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01060 {
01061 struct ast_channel *c;
01062 if (argc == 1) {
01063
01064 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
01065 fdprintf(agi->fd, "200 result=1\n");
01066 return RESULT_SUCCESS;
01067 } else if (argc == 2) {
01068
01069 c = ast_get_channel_by_name_locked(argv[1]);
01070 if (c) {
01071
01072 ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT);
01073 fdprintf(agi->fd, "200 result=1\n");
01074 ast_mutex_unlock(&c->lock);
01075 return RESULT_SUCCESS;
01076 }
01077
01078 fdprintf(agi->fd, "200 result=-1\n");
01079 return RESULT_SUCCESS;
01080 } else {
01081 return RESULT_SHOWUSAGE;
01082 }
01083 }
01084
01085 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01086 {
01087 int res;
01088 struct ast_app *app;
01089
01090 if (argc < 2)
01091 return RESULT_SHOWUSAGE;
01092
01093 if (option_verbose > 2)
01094 ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]);
01095
01096 app = pbx_findapp(argv[1]);
01097
01098 if (app) {
01099 res = pbx_exec(chan, app, argv[2], 1);
01100 } else {
01101 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
01102 res = -2;
01103 }
01104 fdprintf(agi->fd, "200 result=%d\n", res);
01105
01106 return res;
01107 }
01108
01109 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01110 {
01111 char tmp[256]="";
01112 char *l = NULL, *n = NULL;
01113
01114 if (argv[2]) {
01115 ast_copy_string(tmp, argv[2], sizeof(tmp));
01116 ast_callerid_parse(tmp, &n, &l);
01117 if (l)
01118 ast_shrink_phone_number(l);
01119 else
01120 l = "";
01121 if (!n)
01122 n = "";
01123 ast_set_callerid(chan, l, n, NULL);
01124 }
01125
01126 fdprintf(agi->fd, "200 result=1\n");
01127 return RESULT_SUCCESS;
01128 }
01129
01130 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01131 {
01132 struct ast_channel *c;
01133 if (argc == 2) {
01134
01135 fdprintf(agi->fd, "200 result=%d\n", chan->_state);
01136 return RESULT_SUCCESS;
01137 } else if (argc == 3) {
01138
01139 c = ast_get_channel_by_name_locked(argv[2]);
01140 if (c) {
01141 fdprintf(agi->fd, "200 result=%d\n", c->_state);
01142 ast_mutex_unlock(&c->lock);
01143 return RESULT_SUCCESS;
01144 }
01145
01146 fdprintf(agi->fd, "200 result=-1\n");
01147 return RESULT_SUCCESS;
01148 } else {
01149 return RESULT_SHOWUSAGE;
01150 }
01151 }
01152
01153 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01154 {
01155 if (argv[3])
01156 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
01157
01158 fdprintf(agi->fd, "200 result=1\n");
01159 return RESULT_SUCCESS;
01160 }
01161
01162 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01163 {
01164 char *ret;
01165 char tempstr[1024];
01166
01167 if (argc != 3)
01168 return RESULT_SHOWUSAGE;
01169
01170
01171 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
01172 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr));
01173 } else {
01174 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
01175 }
01176
01177 if (ret)
01178 fdprintf(agi->fd, "200 result=1 (%s)\n", ret);
01179 else
01180 fdprintf(agi->fd, "200 result=0\n");
01181
01182 return RESULT_SUCCESS;
01183 }
01184
01185 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01186 {
01187 char tmp[4096] = "";
01188 struct ast_channel *chan2=NULL;
01189
01190 if ((argc != 4) && (argc != 5))
01191 return RESULT_SHOWUSAGE;
01192 if (argc == 5) {
01193 chan2 = ast_get_channel_by_name_locked(argv[4]);
01194 } else {
01195 chan2 = chan;
01196 }
01197 if (chan) {
01198 pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1);
01199 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
01200 } else {
01201 fdprintf(agi->fd, "200 result=0\n");
01202 }
01203 if (chan2 && (chan2 != chan))
01204 ast_mutex_unlock(&chan2->lock);
01205 return RESULT_SUCCESS;
01206 }
01207
01208 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01209 {
01210 int level = 0;
01211 char *prefix;
01212
01213 if (argc < 2)
01214 return RESULT_SHOWUSAGE;
01215
01216 if (argv[2])
01217 sscanf(argv[2], "%d", &level);
01218
01219 switch (level) {
01220 case 4:
01221 prefix = VERBOSE_PREFIX_4;
01222 break;
01223 case 3:
01224 prefix = VERBOSE_PREFIX_3;
01225 break;
01226 case 2:
01227 prefix = VERBOSE_PREFIX_2;
01228 break;
01229 case 1:
01230 default:
01231 prefix = VERBOSE_PREFIX_1;
01232 break;
01233 }
01234
01235 if (level <= option_verbose)
01236 ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]);
01237
01238 fdprintf(agi->fd, "200 result=1\n");
01239
01240 return RESULT_SUCCESS;
01241 }
01242
01243 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01244 {
01245 int res;
01246 char tmp[256];
01247
01248 if (argc != 4)
01249 return RESULT_SHOWUSAGE;
01250 res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
01251 if (res)
01252 fdprintf(agi->fd, "200 result=0\n");
01253 else
01254 fdprintf(agi->fd, "200 result=1 (%s)\n", tmp);
01255
01256 return RESULT_SUCCESS;
01257 }
01258
01259 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01260 {
01261 int res;
01262
01263 if (argc != 5)
01264 return RESULT_SHOWUSAGE;
01265 res = ast_db_put(argv[2], argv[3], argv[4]);
01266 if (res)
01267 fdprintf(agi->fd, "200 result=0\n");
01268 else
01269 fdprintf(agi->fd, "200 result=1\n");
01270
01271 return RESULT_SUCCESS;
01272 }
01273
01274 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01275 {
01276 int res;
01277
01278 if (argc != 4)
01279 return RESULT_SHOWUSAGE;
01280 res = ast_db_del(argv[2], argv[3]);
01281 if (res)
01282 fdprintf(agi->fd, "200 result=0\n");
01283 else
01284 fdprintf(agi->fd, "200 result=1\n");
01285
01286 return RESULT_SUCCESS;
01287 }
01288
01289 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv)
01290 {
01291 int res;
01292 if ((argc < 3) || (argc > 4))
01293 return RESULT_SHOWUSAGE;
01294 if (argc == 4)
01295 res = ast_db_deltree(argv[2], argv[3]);
01296 else
01297 res = ast_db_deltree(argv[2], NULL);
01298
01299 if (res)
01300 fdprintf(agi->fd, "200 result=0\n");
01301 else
01302 fdprintf(agi->fd, "200 result=1\n");
01303 return RESULT_SUCCESS;
01304 }
01305
01306 static char debug_usage[] =
01307 "Usage: agi debug\n"
01308 " Enables dumping of AGI transactions for debugging purposes\n";
01309
01310 static char no_debug_usage[] =
01311 "Usage: agi no debug\n"
01312 " Disables dumping of AGI transactions for debugging purposes\n";
01313
01314 static int agi_do_debug(int fd, int argc, char *argv[])
01315 {
01316 if (argc != 2)
01317 return RESULT_SHOWUSAGE;
01318 agidebug = 1;
01319 ast_cli(fd, "AGI Debugging Enabled\n");
01320 return RESULT_SUCCESS;
01321 }
01322
01323 static int agi_no_debug(int fd, int argc, char *argv[])
01324 {
01325 if (argc != 3)
01326 return RESULT_SHOWUSAGE;
01327 agidebug = 0;
01328 ast_cli(fd, "AGI Debugging Disabled\n");
01329 return RESULT_SUCCESS;
01330 }
01331
01332 static struct ast_cli_entry cli_debug =
01333 { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage };
01334
01335 static struct ast_cli_entry cli_no_debug =
01336 { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage };
01337
01338 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[])
01339 {
01340 fdprintf(agi->fd, "200 result=0\n");
01341 return RESULT_SUCCESS;
01342 }
01343
01344 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
01345 {
01346 if (!strncasecmp(argv[2],"on",2)) {
01347 if (argc > 3)
01348 ast_moh_start(chan, argv[3]);
01349 else
01350 ast_moh_start(chan, NULL);
01351 }
01352 if (!strncasecmp(argv[2],"off",3)) {
01353 ast_moh_stop(chan);
01354 }
01355 fdprintf(agi->fd, "200 result=0\n");
01356 return RESULT_SUCCESS;
01357 }
01358
01359 static char usage_setmusic[] =
01360 " Usage: SET MUSIC ON <on|off> <class>\n"
01361 " Enables/Disables the music on hold generator. If <class> is\n"
01362 " not specified, then the default music on hold class will be used.\n"
01363 " Always returns 0.\n";
01364
01365 static char usage_dbput[] =
01366 " Usage: DATABASE PUT <family> <key> <value>\n"
01367 " Adds or updates an entry in the Asterisk database for a\n"
01368 " given family, key, and value.\n"
01369 " Returns 1 if successful, 0 otherwise.\n";
01370
01371 static char usage_dbget[] =
01372 " Usage: DATABASE GET <family> <key>\n"
01373 " Retrieves an entry in the Asterisk database for a\n"
01374 " given family and key.\n"
01375 " Returns 0 if <key> is not set. Returns 1 if <key>\n"
01376 " is set and returns the variable in parentheses.\n"
01377 " Example return code: 200 result=1 (testvariable)\n";
01378
01379 static char usage_dbdel[] =
01380 " Usage: DATABASE DEL <family> <key>\n"
01381 " Deletes an entry in the Asterisk database for a\n"
01382 " given family and key.\n"
01383 " Returns 1 if successful, 0 otherwise.\n";
01384
01385 static char usage_dbdeltree[] =
01386 " Usage: DATABASE DELTREE <family> [keytree]\n"
01387 " Deletes a family or specific keytree within a family\n"
01388 " in the Asterisk database.\n"
01389 " Returns 1 if successful, 0 otherwise.\n";
01390
01391 static char usage_verbose[] =
01392 " Usage: VERBOSE <message> <level>\n"
01393 " Sends <message> to the console via verbose message system.\n"
01394 " <level> is the the verbose level (1-4)\n"
01395 " Always returns 1.\n";
01396
01397 static char usage_getvariable[] =
01398 " Usage: GET VARIABLE <variablename>\n"
01399 " Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n"
01400 " is set and returns the variable in parentheses.\n"
01401 " example return code: 200 result=1 (testvariable)\n";
01402
01403 static char usage_getvariablefull[] =
01404 " Usage: GET FULL VARIABLE <variablename> [<channel name>]\n"
01405 " Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n"
01406 "if <variablename> is set and returns the variable in parenthesis. Understands\n"
01407 "complex variable names and builtin variables, unlike GET VARIABLE.\n"
01408 " example return code: 200 result=1 (testvariable)\n";
01409
01410 static char usage_setvariable[] =
01411 " Usage: SET VARIABLE <variablename> <value>\n";
01412
01413 static char usage_channelstatus[] =
01414 " Usage: CHANNEL STATUS [<channelname>]\n"
01415 " Returns the status of the specified channel.\n"
01416 " If no channel name is given the returns the status of the\n"
01417 " current channel. Return values:\n"
01418 " 0 Channel is down and available\n"
01419 " 1 Channel is down, but reserved\n"
01420 " 2 Channel is off hook\n"
01421 " 3 Digits (or equivalent) have been dialed\n"
01422 " 4 Line is ringing\n"
01423 " 5 Remote end is ringing\n"
01424 " 6 Line is up\n"
01425 " 7 Line is busy\n";
01426
01427 static char usage_setcallerid[] =
01428 " Usage: SET CALLERID <number>\n"
01429 " Changes the callerid of the current channel.\n";
01430
01431 static char usage_exec[] =
01432 " Usage: EXEC <application> <options>\n"
01433 " Executes <application> with given <options>.\n"
01434 " Returns whatever the application returns, or -2 on failure to find application\n";
01435
01436 static char usage_hangup[] =
01437 " Usage: HANGUP [<channelname>]\n"
01438 " Hangs up the specified channel.\n"
01439 " If no channel name is given, hangs up the current channel\n";
01440
01441 static char usage_answer[] =
01442 " Usage: ANSWER\n"
01443 " Answers channel if not already in answer state. Returns -1 on\n"
01444 " channel failure, or 0 if successful.\n";
01445
01446 static char usage_waitfordigit[] =
01447 " Usage: WAIT FOR DIGIT <timeout>\n"
01448 " Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n"
01449 " Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
01450 " the numerical value of the ascii of the digit if one is received. Use -1\n"
01451 " for the timeout value if you desire the call to block indefinitely.\n";
01452
01453 static char usage_sendtext[] =
01454 " Usage: SEND TEXT \"<text to send>\"\n"
01455 " Sends the given text on a channel. Most channels do not support the\n"
01456 " transmission of text. Returns 0 if text is sent, or if the channel does not\n"
01457 " support text transmission. Returns -1 only on error/hangup. Text\n"
01458 " consisting of greater than one word should be placed in quotes since the\n"
01459 " command only accepts a single argument.\n";
01460
01461 static char usage_recvchar[] =
01462 " Usage: RECEIVE CHAR <timeout>\n"
01463 " Receives a character of text on a channel. Specify timeout to be the\n"
01464 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
01465 " do not support the reception of text. Returns the decimal value of the character\n"
01466 " if one is received, or 0 if the channel does not support text reception. Returns\n"
01467 " -1 only on error/hangup.\n";
01468
01469 static char usage_recvtext[] =
01470 " Usage: RECEIVE TEXT <timeout>\n"
01471 " Receives a string of text on a channel. Specify timeout to be the\n"
01472 " maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
01473 " do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n";
01474
01475 static char usage_tddmode[] =
01476 " Usage: TDD MODE <on|off>\n"
01477 " Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
01478 " successful, or 0 if channel is not TDD-capable.\n";
01479
01480 static char usage_sendimage[] =
01481 " Usage: SEND IMAGE <image>\n"
01482 " Sends the given image on a channel. Most channels do not support the\n"
01483 " transmission of images. Returns 0 if image is sent, or if the channel does not\n"
01484 " support image transmission. Returns -1 only on error/hangup. Image names\n"
01485 " should not include extensions.\n";
01486
01487 static char usage_streamfile[] =
01488 " Usage: STREAM FILE <filename> <escape digits> [sample offset]\n"
01489 " Send the given file, allowing playback to be interrupted by the given\n"
01490 " digits, if any. Use double quotes for the digits if you wish none to be\n"
01491 " permitted. If sample offset is provided then the audio will seek to sample\n"
01492 " offset before play starts. Returns 0 if playback completes without a digit\n"
01493 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
01494 " or -1 on error or if the channel was disconnected. Remember, the file\n"
01495 " extension must not be included in the filename.\n";
01496
01497 static char usage_controlstreamfile[] =
01498 " Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n"
01499 " Send the given file, allowing playback to be controled by the given\n"
01500 " digits, if any. Use double quotes for the digits if you wish none to be\n"
01501 " permitted. Returns 0 if playback completes without a digit\n"
01502 " being pressed, or the ASCII numerical value of the digit if one was pressed,\n"
01503 " or -1 on error or if the channel was disconnected. Remember, the file\n"
01504 " extension must not be included in the filename.\n\n"
01505 " Note: ffchar and rewchar default to * and # respectively.\n";
01506
01507 static char usage_getoption[] =
01508 " Usage: GET OPTION <filename> <escape_digits> [timeout]\n"
01509 " Behaves similar to STREAM FILE but used with a timeout option.\n";
01510
01511 static char usage_saynumber[] =
01512 " Usage: SAY NUMBER <number> <escape digits>\n"
01513 " Say a given number, returning early if any of the given DTMF digits\n"
01514 " are received on the channel. Returns 0 if playback completes without a digit\n"
01515 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
01516 " -1 on error/hangup.\n";
01517
01518 static char usage_saydigits[] =
01519 " Usage: SAY DIGITS <number> <escape digits>\n"
01520 " Say a given digit string, returning early if any of the given DTMF digits\n"
01521 " are received on the channel. Returns 0 if playback completes without a digit\n"
01522 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
01523 " -1 on error/hangup.\n";
01524
01525 static char usage_sayalpha[] =
01526 " Usage: SAY ALPHA <number> <escape digits>\n"
01527 " Say a given character string, returning early if any of the given DTMF digits\n"
01528 " are received on the channel. Returns 0 if playback completes without a digit\n"
01529 " being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
01530 " -1 on error/hangup.\n";
01531
01532 static char usage_saydate[] =
01533 " Usage: SAY DATE <date> <escape digits>\n"
01534 " Say a given date, returning early if any of the given DTMF digits are\n"
01535 " received on the channel. <date> is number of seconds elapsed since 00:00:00\n"
01536 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
01537 " completes without a digit being pressed, or the ASCII numerical value of the\n"
01538 " digit if one was pressed or -1 on error/hangup.\n";
01539
01540 static char usage_saytime[] =
01541 " Usage: SAY TIME <time> <escape digits>\n"
01542 " Say a given time, returning early if any of the given DTMF digits are\n"
01543 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
01544 " on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n"
01545 " completes without a digit being pressed, or the ASCII numerical value of the\n"
01546 " digit if one was pressed or -1 on error/hangup.\n";
01547
01548 static char usage_saydatetime[] =
01549 " Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n"
01550 " Say a given time, returning early if any of the given DTMF digits are\n"
01551 " received on the channel. <time> is number of seconds elapsed since 00:00:00\n"
01552 " on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n"
01553 " the time should be said in. See voicemail.conf (defaults to \"ABdY\n"
01554 " 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n"
01555 " /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n"
01556 " completes without a digit being pressed, or the ASCII numerical value of the\n"
01557 " digit if one was pressed or -1 on error/hangup.\n";
01558
01559 static char usage_sayphonetic[] =
01560 " Usage: SAY PHONETIC <string> <escape digits>\n"
01561 " Say a given character string with phonetics, returning early if any of the\n"
01562 " given DTMF digits are received on the channel. Returns 0 if playback\n"
01563 " completes without a digit pressed, the ASCII numerical value of the digit\n"
01564 " if one was pressed, or -1 on error/hangup.\n";
01565
01566 static char usage_getdata[] =
01567 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
01568 " Stream the given file, and recieve DTMF data. Returns the digits received\n"
01569 "from the channel at the other end.\n";
01570
01571 static char usage_setcontext[] =
01572 " Usage: SET CONTEXT <desired context>\n"
01573 " Sets the context for continuation upon exiting the application.\n";
01574
01575 static char usage_setextension[] =
01576 " Usage: SET EXTENSION <new extension>\n"
01577 " Changes the extension for continuation upon exiting the application.\n";
01578
01579 static char usage_setpriority[] =
01580 " Usage: SET PRIORITY <priority>\n"
01581 " Changes the priority for continuation upon exiting the application.\n"
01582 " The priority must be a valid priority or label.\n";
01583
01584 static char usage_recordfile[] =
01585 " Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n"
01586 " [offset samples] [BEEP] [s=silence]\n"
01587 " Record to a file until a given dtmf digit in the sequence is received\n"
01588 " Returns -1 on hangup or error. The format will specify what kind of file\n"
01589 " will be recorded. The timeout is the maximum record time in milliseconds, or\n"
01590 " -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n"
01591 " to the offset without exceeding the end of the file. \"silence\" is the number\n"
01592 " of seconds of silence allowed before the function returns despite the\n"
01593 " lack of dtmf digits or reaching timeout. Silence value must be\n"
01594 " preceeded by \"s=\" and is also optional.\n";
01595
01596 static char usage_autohangup[] =
01597 " Usage: SET AUTOHANGUP <time>\n"
01598 " Cause the channel to automatically hangup at <time> seconds in the\n"
01599 " future. Of course it can be hungup before then as well. Setting to 0 will\n"
01600 " cause the autohangup feature to be disabled on this channel.\n";
01601
01602 static char usage_noop[] =
01603 " Usage: NoOp\n"
01604 " Does nothing.\n";
01605
01606 static agi_command commands[MAX_COMMANDS] = {
01607 { { "answer", NULL }, handle_answer, "Answer channel", usage_answer },
01608 { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus },
01609 { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel },
01610 { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree },
01611 { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget },
01612 { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput },
01613 { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec },
01614 { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata },
01615 { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull },
01616 { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption },
01617 { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable },
01618 { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup },
01619 { { "noop", NULL }, handle_noop, "Does nothing", usage_noop },
01620 { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar },
01621 { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext },
01622 { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile },
01623 { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha },
01624 { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
01625 { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
01626 { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
01627 { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate },
01628 { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
01629 { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime },
01630 { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
01631 { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
01632 { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup },
01633 { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid },
01634 { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
01635 { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
01636 { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic },
01637 { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority },
01638 { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable },
01639 { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
01640 { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile },
01641 { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode },
01642 { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose },
01643 { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
01644 };
01645
01646 static void join(char *s, size_t len, char *w[])
01647 {
01648 int x;
01649
01650
01651 if (!s) {
01652 return;
01653 }
01654 s[0] = '\0';
01655 for (x=0; w[x]; x++) {
01656 if (x)
01657 strncat(s, " ", len - strlen(s) - 1);
01658 strncat(s, w[x], len - strlen(s) - 1);
01659 }
01660 }
01661
01662 static int help_workhorse(int fd, char *match[])
01663 {
01664 char fullcmd[80];
01665 char matchstr[80];
01666 int x;
01667 struct agi_command *e;
01668 if (match)
01669 join(matchstr, sizeof(matchstr), match);
01670 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
01671 if (!commands[x].cmda[0]) break;
01672 e = &commands[x];
01673 if (e)
01674 join(fullcmd, sizeof(fullcmd), e->cmda);
01675
01676 if (fullcmd[0] == '_')
01677 continue;
01678 if (match) {
01679 if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
01680 continue;
01681 }
01682 }
01683 ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary);
01684 }
01685 return 0;
01686 }
01687
01688 int agi_register(agi_command *agi)
01689 {
01690 int x;
01691 for (x=0; x<MAX_COMMANDS - 1; x++) {
01692 if (commands[x].cmda[0] == agi->cmda[0]) {
01693 ast_log(LOG_WARNING, "Command already registered!\n");
01694 return -1;
01695 }
01696 }
01697 for (x=0; x<MAX_COMMANDS - 1; x++) {
01698 if (!commands[x].cmda[0]) {
01699 commands[x] = *agi;
01700 return 0;
01701 }
01702 }
01703 ast_log(LOG_WARNING, "No more room for new commands!\n");
01704 return -1;
01705 }
01706
01707 void agi_unregister(agi_command *agi)
01708 {
01709 int x;
01710 for (x=0; x<MAX_COMMANDS - 1; x++) {
01711 if (commands[x].cmda[0] == agi->cmda[0]) {
01712 memset(&commands[x], 0, sizeof(agi_command));
01713 }
01714 }
01715 }
01716
01717 static agi_command *find_command(char *cmds[], int exact)
01718 {
01719 int x;
01720 int y;
01721 int match;
01722
01723 for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) {
01724 if (!commands[x].cmda[0])
01725 break;
01726
01727 match = 1;
01728 for (y=0; match && cmds[y]; y++) {
01729
01730
01731
01732 if (!commands[x].cmda[y] && !exact)
01733 break;
01734
01735 if (!commands[x].cmda[y])
01736 return NULL;
01737 if (strcasecmp(commands[x].cmda[y], cmds[y]))
01738 match = 0;
01739 }
01740
01741
01742 if ((exact > -1) && commands[x].cmda[y])
01743 match = 0;
01744 if (match)
01745 return &commands[x];
01746 }
01747 return NULL;
01748 }
01749
01750
01751 static int parse_args(char *s, int *max, char *argv[])
01752 {
01753 int x=0;
01754 int quoted=0;
01755 int escaped=0;
01756 int whitespace=1;
01757 char *cur;
01758
01759 cur = s;
01760 while(*s) {
01761 switch(*s) {
01762 case '"':
01763
01764 if (escaped)
01765 goto normal;
01766 else
01767 quoted = !quoted;
01768 if (quoted && whitespace) {
01769
01770 argv[x++] = cur;
01771 whitespace=0;
01772 }
01773 escaped = 0;
01774 break;
01775 case ' ':
01776 case '\t':
01777 if (!quoted && !escaped) {
01778
01779
01780 whitespace = 1;
01781 *(cur++) = '\0';
01782 } else
01783
01784 goto normal;
01785 break;
01786 case '\\':
01787
01788 if (escaped) {
01789 goto normal;
01790 } else {
01791 escaped=1;
01792 }
01793 break;
01794 default:
01795 normal:
01796 if (whitespace) {
01797 if (x >= MAX_ARGS -1) {
01798 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
01799 break;
01800 }
01801
01802 argv[x++] = cur;
01803 whitespace=0;
01804 }
01805 *(cur++) = *s;
01806 escaped=0;
01807 }
01808 s++;
01809 }
01810
01811 *(cur++) = '\0';
01812 argv[x] = NULL;
01813 *max = x;
01814 return 0;
01815 }
01816
01817 static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
01818 {
01819 char *argv[MAX_ARGS];
01820 int argc = 0;
01821 int res;
01822 agi_command *c;
01823 argc = MAX_ARGS;
01824
01825 parse_args(buf, &argc, argv);
01826 c = find_command(argv, 0);
01827 if (c) {
01828 res = c->handler(chan, agi, argc, argv);
01829 switch(res) {
01830 case RESULT_SHOWUSAGE:
01831 fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n");
01832 fdprintf(agi->fd, c->usage);
01833 fdprintf(agi->fd, "520 End of proper usage.\n");
01834 break;
01835 case AST_PBX_KEEPALIVE:
01836
01837 return AST_PBX_KEEPALIVE;
01838 break;
01839 case RESULT_FAILURE:
01840
01841
01842 return -1;
01843 }
01844 } else {
01845 fdprintf(agi->fd, "510 Invalid or unknown command\n");
01846 }
01847 return 0;
01848 }
01849 #define RETRY 3
01850 static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
01851 {
01852 struct ast_channel *c;
01853 int outfd;
01854 int ms;
01855 int returnstatus = 0;
01856 struct ast_frame *f;
01857 char buf[2048];
01858 FILE *readf;
01859
01860
01861 int retry = RETRY;
01862
01863 if (!(readf = fdopen(agi->ctrl, "r"))) {
01864 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
01865 if (pid > -1)
01866 kill(pid, SIGHUP);
01867 close(agi->ctrl);
01868 return -1;
01869 }
01870 setlinebuf(readf);
01871 setup_env(chan, request, agi->fd, (agi->audio > -1));
01872 for (;;) {
01873 ms = -1;
01874 c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms);
01875 if (c) {
01876 retry = RETRY;
01877
01878 f = ast_read(c);
01879 if (!f) {
01880 ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
01881 returnstatus = -1;
01882 break;
01883 } else {
01884
01885 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
01886
01887 write(agi->audio, f->data, f->datalen);
01888 }
01889 ast_frfree(f);
01890 }
01891 } else if (outfd > -1) {
01892 retry = RETRY;
01893 if (!fgets(buf, sizeof(buf), readf)) {
01894
01895 if (returnstatus)
01896 returnstatus = -1;
01897 if (option_verbose > 2)
01898 ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
01899
01900 pid = -1;
01901 break;
01902 }
01903
01904 if (*buf && buf[strlen(buf) - 1] == '\n')
01905 buf[strlen(buf) - 1] = 0;
01906 if (agidebug)
01907 ast_verbose("AGI Rx << %s\n", buf);
01908 returnstatus |= agi_handle_command(chan, agi, buf);
01909
01910 if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) {
01911 break;
01912 }
01913 } else {
01914 if (--retry <= 0) {
01915 ast_log(LOG_WARNING, "No channel, no fd?\n");
01916 returnstatus = -1;
01917 break;
01918 }
01919 }
01920 }
01921
01922 if (pid > -1) {
01923 if (kill(pid, SIGHUP))
01924 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
01925 }
01926 fclose(readf);
01927 return returnstatus;
01928 }
01929
01930 static int handle_showagi(int fd, int argc, char *argv[]) {
01931 struct agi_command *e;
01932 char fullcmd[80];
01933 if ((argc < 2))
01934 return RESULT_SHOWUSAGE;
01935 if (argc > 2) {
01936 e = find_command(argv + 2, 1);
01937 if (e)
01938 ast_cli(fd, e->usage);
01939 else {
01940 if (find_command(argv + 2, -1)) {
01941 return help_workhorse(fd, argv + 1);
01942 } else {
01943 join(fullcmd, sizeof(fullcmd), argv+1);
01944 ast_cli(fd, "No such command '%s'.\n", fullcmd);
01945 }
01946 }
01947 } else {
01948 return help_workhorse(fd, NULL);
01949 }
01950 return RESULT_SUCCESS;
01951 }
01952
01953 static int handle_dumpagihtml(int fd, int argc, char *argv[]) {
01954 struct agi_command *e;
01955 char fullcmd[80];
01956 char *tempstr;
01957 int x;
01958 FILE *htmlfile;
01959
01960 if ((argc < 3))
01961 return RESULT_SHOWUSAGE;
01962
01963 if (!(htmlfile = fopen(argv[2], "wt"))) {
01964 ast_cli(fd, "Could not create file '%s'\n", argv[2]);
01965 return RESULT_SHOWUSAGE;
01966 }
01967
01968 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
01969 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
01970
01971
01972 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
01973
01974 for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) {
01975 char *stringp=NULL;
01976 if (!commands[x].cmda[0]) break;
01977 e = &commands[x];
01978 if (e)
01979 join(fullcmd, sizeof(fullcmd), e->cmda);
01980
01981 if (fullcmd[0] == '_')
01982 continue;
01983
01984 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
01985 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary);
01986
01987
01988 stringp=e->usage;
01989 tempstr = strsep(&stringp, "\n");
01990
01991 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr);
01992
01993 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
01994 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
01995 fprintf(htmlfile, "%s<BR>\n",tempstr);
01996
01997 }
01998 fprintf(htmlfile, "</TD></TR>\n");
01999 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
02000
02001 }
02002
02003 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
02004 fclose(htmlfile);
02005 ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]);
02006 return RESULT_SUCCESS;
02007 }
02008
02009 static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead)
02010 {
02011 int res=0;
02012 struct localuser *u;
02013 char *argv[MAX_ARGS];
02014 char buf[2048]="";
02015 char *tmp = (char *)buf;
02016 int argc = 0;
02017 int fds[2];
02018 int efd = -1;
02019 int pid;
02020 char *stringp;
02021 AGI agi;
02022
02023 if (ast_strlen_zero(data)) {
02024 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
02025 return -1;
02026 }
02027 ast_copy_string(buf, data, sizeof(buf));
02028
02029 memset(&agi, 0, sizeof(agi));
02030 while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS - 1)
02031 argv[argc++] = stringp;
02032 argv[argc] = NULL;
02033
02034 LOCAL_USER_ADD(u);
02035 #if 0
02036
02037 if (chan->_state != AST_STATE_UP) {
02038 if (ast_answer(chan)) {
02039 LOCAL_USER_REMOVE(u);
02040 return -1;
02041 }
02042 }
02043 #endif
02044 res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
02045 if (!res) {
02046 agi.fd = fds[1];
02047 agi.ctrl = fds[0];
02048 agi.audio = efd;
02049 res = run_agi(chan, argv[0], &agi, pid, dead);
02050 close(fds[1]);
02051 if (efd > -1)
02052 close(efd);
02053 }
02054 LOCAL_USER_REMOVE(u);
02055 return res;
02056 }
02057
02058 static int agi_exec(struct ast_channel *chan, void *data)
02059 {
02060 if (chan->_softhangup)
02061 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
02062 return agi_exec_full(chan, data, 0, 0);
02063 }
02064
02065 static int eagi_exec(struct ast_channel *chan, void *data)
02066 {
02067 int readformat;
02068 int res;
02069
02070 if (chan->_softhangup)
02071 ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n");
02072 readformat = chan->readformat;
02073 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
02074 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
02075 return -1;
02076 }
02077 res = agi_exec_full(chan, data, 1, 0);
02078 if (!res) {
02079 if (ast_set_read_format(chan, readformat)) {
02080 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
02081 }
02082 }
02083 return res;
02084 }
02085
02086 static int deadagi_exec(struct ast_channel *chan, void *data)
02087 {
02088 return agi_exec_full(chan, data, 0, 1);
02089 }
02090
02091 static char showagi_help[] =
02092 "Usage: show agi [topic]\n"
02093 " When called with a topic as an argument, displays usage\n"
02094 " information on the given command. If called without a\n"
02095 " topic, it provides a list of AGI commands.\n";
02096
02097
02098 static char dumpagihtml_help[] =
02099 "Usage: dump agihtml <filename>\n"
02100 " Dumps the agi command list in html format to given filename\n";
02101
02102 static struct ast_cli_entry showagi =
02103 { { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help };
02104
02105 static struct ast_cli_entry dumpagihtml =
02106 { { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help };
02107
02108 int unload_module(void)
02109 {
02110 STANDARD_HANGUP_LOCALUSERS;
02111 ast_cli_unregister(&showagi);
02112 ast_cli_unregister(&dumpagihtml);
02113 ast_cli_unregister(&cli_debug);
02114 ast_cli_unregister(&cli_no_debug);
02115 ast_unregister_application(eapp);
02116 ast_unregister_application(deadapp);
02117 return ast_unregister_application(app);
02118 }
02119
02120 int load_module(void)
02121 {
02122 ast_cli_register(&showagi);
02123 ast_cli_register(&dumpagihtml);
02124 ast_cli_register(&cli_debug);
02125 ast_cli_register(&cli_no_debug);
02126 ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip);
02127 ast_register_application(eapp, eagi_exec, esynopsis, descrip);
02128 return ast_register_application(app, agi_exec, synopsis, descrip);
02129 }
02130
02131 char *description(void)
02132 {
02133 return tdesc;
02134 }
02135
02136 int usecount(void)
02137 {
02138 int res;
02139 STANDARD_USECOUNT(res);
02140 return res;
02141 }
02142
02143 char *key()
02144 {
02145 return ASTERISK_GPL_KEY;
02146 }
02147