From 8ce222478dd4a01ef0704468b28118baa87338b9 Mon Sep 17 00:00:00 2001 From: Mark Spencer Date: Thu, 6 Feb 2003 22:11:43 +0000 Subject: Version 0.3.0 from FTP git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@608 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_agi.c | 477 +++++++++++++++++++++++++++++++++++++++++++---- file.c | 233 ++++++++++++++++------- formats/format_g723.c | 29 ++- formats/format_g729.c | 351 ++++++++++++++++++++++++++++++++++ formats/format_gsm.c | 44 ++++- formats/format_pcm.c | 44 ++++- formats/format_vox.c | 29 ++- formats/format_wav.c | 86 +++++++-- formats/format_wav_gsm.c | 63 ++++++- include/asterisk/file.h | 83 +++++++++ 10 files changed, 1308 insertions(+), 131 deletions(-) create mode 100755 formats/format_g729.c diff --git a/apps/app_agi.c b/apps/app_agi.c index a4e0f17d5..add410a80 100755 --- a/apps/app_agi.c +++ b/apps/app_agi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -23,12 +24,16 @@ #include #include #include +#include +#include +#include #include #include #include #include #include #include "../asterisk.h" +#include "../astconf.h" #include @@ -67,6 +72,9 @@ STANDARD_LOCAL_USER; LOCAL_USER_DECL; +extern char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name); +extern void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value); + #define TONE_BLOCK_SIZE 200 static float loudness = 8192.0; @@ -97,7 +105,7 @@ static int launch_script(char *script, char *args, int *fds, int *opid) int fromast[2]; int x; if (script[0] != '/') { - snprintf(tmp, sizeof(tmp), "%s/%s", AST_AGI_DIR, script); + snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script); script = tmp; } if (pipe(toast)) { @@ -124,7 +132,8 @@ static int launch_script(char *script, char *args, int *fds, int *opid) close(x); /* Execute script */ execl(script, script, args, NULL); - ast_log(LOG_WARNING, "Failed to execute '%s': %s\n", script, strerror(errno)); + /* Can't use ast_log since FD's are closed */ + fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno)); exit(1); } if (option_verbose > 2) @@ -151,6 +160,7 @@ static void setup_env(struct ast_channel *chan, char *request, int fd) /* ANI/DNIS */ fdprintf(fd, "agi_callerid: %s\n", chan->callerid ? chan->callerid : ""); fdprintf(fd, "agi_dnid: %s\n", chan->dnid ? chan->dnid : ""); + fdprintf(fd, "agi_rdnis: %s\n", chan->rdnis ? chan->rdnis : ""); /* Context information */ fdprintf(fd, "agi_context: %s\n", chan->context); @@ -266,19 +276,41 @@ static int handle_sendimage(struct ast_channel *chan, int fd, int argc, char *ar static int handle_streamfile(struct ast_channel *chan, int fd, int argc, char *argv[]) { int res; - if (argc != 4) + struct ast_filestream *fs; + long sample_offset = 0; + long max_length; + + if (argc < 4) + return RESULT_SHOWUSAGE; + if (argc > 5) return RESULT_SHOWUSAGE; - res = ast_streamfile(chan, argv[2],chan->language); + if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1)) + return RESULT_SHOWUSAGE; + + fs = ast_openstream(chan, argv[2], chan->language); + if(!fs){ + fdprintf(fd, "200 result=%d endpos=%ld\n", 0, sample_offset); + ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]); + return RESULT_FAILURE; + } + ast_seekstream(fs, 0, SEEK_END); + max_length = ast_tellstream(fs); + ast_seekstream(fs, sample_offset, SEEK_SET); + res = ast_applystream(chan, fs); + res = ast_playstream(fs); if (res) { - fdprintf(fd, "200 result=%d\n", res); + fdprintf(fd, "200 result=%d endpos=%ld\n", res, sample_offset); if (res >= 0) return RESULT_SHOWUSAGE; else return RESULT_FAILURE; } res = ast_waitstream(chan, argv[3]); + /* this is to check for if ast_waitstream closed the stream, we probably are at + * the end of the stream, return that amount, else check for the amount */ + sample_offset = (chan->stream)?ast_tellstream(fs):max_length; ast_stopstream(chan); - fdprintf(fd, "200 result=%d\n", res); + fdprintf(fd, "200 result=%d endpos=%ld\n", res, sample_offset); if (res >= 0) return RESULT_SUCCESS; else @@ -386,6 +418,7 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a struct ast_filestream *fs; struct ast_frame *f; struct timeval tv, start; + long sample_offset = 0; int res = 0; int ms; @@ -393,30 +426,42 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a return RESULT_SHOWUSAGE; if (sscanf(argv[5], "%i", &ms) != 1) return RESULT_SHOWUSAGE; + /* backward compatibility, if no offset given, arg[6] would have been + * caught below and taken to be a beep, else if it is a digit then it is a + * offset */ + if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1)) + res = ast_streamfile(chan, "beep", chan->language); - if (argc > 6) + if (argc > 7) res = ast_streamfile(chan, "beep", chan->language); if (!res) res = ast_waitstream(chan, argv[4]); if (!res) { - fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_TRUNC | O_WRONLY, 0, 0644); + fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY, 0, 0644); if (!fs) { res = -1; fdprintf(fd, "200 result=%d (writefile)\n", res); return RESULT_FAILURE; } + + chan->stream = fs; + ast_applystream(chan,fs); + /* really should have checks */ + ast_seekstream(fs, sample_offset, SEEK_SET); + ast_truncstream(fs); + gettimeofday(&start, NULL); gettimeofday(&tv, NULL); while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) { res = ast_waitfor(chan, -1); if (res < 0) { ast_closestream(fs); - fdprintf(fd, "200 result=%d (waitfor)\n", res); + fdprintf(fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset); return RESULT_FAILURE; } f = ast_read(chan); if (!f) { - fdprintf(fd, "200 result=%d (hangup)\n", 0); + fdprintf(fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset); ast_closestream(fs); return RESULT_FAILURE; } @@ -424,7 +469,8 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a case AST_FRAME_DTMF: if (strchr(argv[4], f->subclass)) { /* This is an interrupting chracter */ - fdprintf(fd, "200 result=%d (dtmf)\n", f->subclass); + sample_offset = ast_tellstream(fs); + fdprintf(fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset); ast_closestream(fs); ast_frfree(f); return RESULT_SUCCESS; @@ -432,15 +478,19 @@ static int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *a break; case AST_FRAME_VOICE: ast_writestream(fs, f); + /* this is a safe place to check progress since we know that fs + * is valid after a write, and it will then have our current + * location */ + sample_offset = ast_tellstream(fs); break; } ast_frfree(f); - } - gettimeofday(&tv, NULL); - fdprintf(fd, "200 result=%d (timeout)\n", res); + gettimeofday(&tv, NULL); + } + fdprintf(fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); ast_closestream(fs); } else - fdprintf(fd, "200 result=%d (randomerror)\n", res); + fdprintf(fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset); return RESULT_SUCCESS; } @@ -464,9 +514,30 @@ static int handle_autohangup(struct ast_channel *chan, int fd, int argc, char *a static int handle_hangup(struct ast_channel *chan, int fd, int argc, char **argv) { - ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT); - fdprintf(fd, "200 result=1\n"); - return RESULT_SUCCESS; + struct ast_channel *c; + if (argc==1) { + /* no argument: hangup the current channel */ + ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT); + fdprintf(fd, "200 result=1\n"); + return RESULT_SUCCESS; + } else if (argc==2) { + /* one argument: look for info on the specified channel */ + c = ast_channel_walk(NULL); + while (c) { + if (strcasecmp(argv[1],c->name)==0) { + /* we have a matching channel */ + ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT); + fdprintf(fd, "200 result=1\n"); + return RESULT_SUCCESS; + } + c = ast_channel_walk(c); + } + /* if we get this far no channel name matched the argument given */ + fdprintf(fd, "200 result=-1\n"); + return RESULT_SUCCESS; + } else { + return RESULT_SHOWUSAGE; + } } static int handle_exec(struct ast_channel *chan, int fd, int argc, char **argv) @@ -496,7 +567,7 @@ static int handle_exec(struct ast_channel *chan, int fd, int argc, char **argv) static int handle_setcallerid(struct ast_channel *chan, int fd, int argc, char **argv) { if (argv[2]) - ast_set_callerid(chan, argv[2]); + ast_set_callerid(chan, argv[2], 0); /* strncpy(chan->callerid, argv[2], sizeof(chan->callerid)-1); */ fdprintf(fd, "200 result=1\n"); @@ -505,13 +576,192 @@ static int handle_setcallerid(struct ast_channel *chan, int fd, int argc, char * static int handle_channelstatus(struct ast_channel *chan, int fd, int argc, char **argv) { - fdprintf(fd, "200 result=%d\n", chan->_state); + struct ast_channel *c; + if (argc==2) { + /* no argument: supply info on the current channel */ + fdprintf(fd, "200 result=%d\n", chan->_state); + return RESULT_SUCCESS; + } else if (argc==3) { + /* one argument: look for info on the specified channel */ + c = ast_channel_walk(NULL); + while (c) { + if (strcasecmp(argv[2],c->name)==0) { + fdprintf(fd, "200 result=%d\n", c->_state); + return RESULT_SUCCESS; + } + c = ast_channel_walk(c); + } + /* if we get this far no channel name matched the argument given */ + fdprintf(fd, "200 result=-1\n"); + return RESULT_SUCCESS; + } else { + return RESULT_SHOWUSAGE; + } +} + +static int handle_setvariable(struct ast_channel *chan, int fd, int argc, char **argv) +{ + if (argv[3]) + pbx_builtin_setvar_helper(chan, argv[2], argv[3]); + + fdprintf(fd, "200 result=1\n"); + return RESULT_SUCCESS; +} + +static int handle_getvariable(struct ast_channel *chan, int fd, int argc, char **argv) +{ + char *tempstr; + + if ((tempstr = pbx_builtin_getvar_helper(chan, argv[2])) ) + fdprintf(fd, "200 result=1 (%s)\n", tempstr); + else + fdprintf(fd, "200 result=0\n"); + + return RESULT_SUCCESS; +} + +static int handle_verbose(struct ast_channel *chan, int fd, int argc, char **argv) +{ + int level = 0; + char *prefix; + + if (argc < 2) + return RESULT_SHOWUSAGE; + + if (argv[2]) + sscanf(argv[2], "%d", &level); + + switch (level) { + case 4: + prefix = VERBOSE_PREFIX_4; + break; + case 3: + prefix = VERBOSE_PREFIX_3; + break; + case 2: + prefix = VERBOSE_PREFIX_2; + break; + case 1: + default: + prefix = VERBOSE_PREFIX_1; + break; + } + + if (level <= option_verbose) + ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]); + + fdprintf(fd, "200 result=1\n"); + return RESULT_SUCCESS; } +static int handle_dbget(struct ast_channel *chan, int fd, int argc, char **argv) +{ + int res; + char tmp[256]; + if (argc != 4) + return RESULT_SHOWUSAGE; + res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp)); + if (res) + fdprintf(fd, "200 result=0\n"); + else + fdprintf(fd, "200 result=1 (%s)\n", tmp); + + return RESULT_SUCCESS; +} + +static int handle_dbput(struct ast_channel *chan, int fd, int argc, char **argv) +{ + int res; + if (argc != 5) + return RESULT_SHOWUSAGE; + res = ast_db_put(argv[2], argv[3], argv[4]); + if (res) + fdprintf(fd, "200 result=0\n"); + else + fdprintf(fd, "200 result=1\n"); + + return RESULT_SUCCESS; +} + +static int handle_dbdel(struct ast_channel *chan, int fd, int argc, char **argv) +{ + int res; + if (argc != 4) + return RESULT_SHOWUSAGE; + res = ast_db_del(argv[2], argv[3]); + if (res) + fdprintf(fd, "200 result=0\n"); + else + fdprintf(fd, "200 result=1\n"); + + return RESULT_SUCCESS; +} + +static int handle_dbdeltree(struct ast_channel *chan, int fd, int argc, char **argv) +{ + int res; + if ((argc < 3) || (argc > 4)) + return RESULT_SHOWUSAGE; + if (argc == 4) + res = ast_db_deltree(argv[2], argv[3]); + else + res = ast_db_deltree(argv[2], NULL); + + if (res) + fdprintf(fd, "200 result=0\n"); + else + fdprintf(fd, "200 result=1\n"); + return RESULT_SUCCESS; +} + +static char usage_dbput[] = +" Usage: DATABASE PUT \n" +" Adds or updates an entry in the Asterisk database for a\n" +" given family, key, and value.\n" +" Returns 1 if succesful, 0 otherwise\n"; + +static char usage_dbget[] = +" Usage: DATABASE GET \n" +" Retrieves an entry in the Asterisk database for a\n" +" given family and key.\n" +" Returns 0 if is not set. Returns 1 if \n" +" is set and returns the variable in parenthesis\n" +" example return code: 200 result=1 (testvariable)\n"; + +static char usage_dbdel[] = +" Usage: DATABASE DEL \n" +" Deletes an entry in the Asterisk database for a\n" +" given family and key.\n" +" Returns 1 if succesful, 0 otherwise\n"; + +static char usage_dbdeltree[] = +" Usage: DATABASE DELTREE [keytree]\n" +" Deletes a family or specific keytree withing a family\n" +" in the Asterisk database.\n" +" Returns 1 if succesful, 0 otherwise\n"; + +static char usage_verbose[] = +" Usage: VERBOSE \n" +" Sends to the console via verbose message system.\n" +" is the the verbose level (1-4)\n" +" Always returns 1\n"; + +static char usage_getvariable[] = +" Usage: GET VARIABLE \n" +" Returns 0 if is not set. Returns 1 if \n" +" is set and returns the variable in parenthesis\n" +" example return code: 200 result=1 (testvariable)\n"; + +static char usage_setvariable[] = +" Usage: SET VARIABLE \n"; + static char usage_channelstatus[] = -" Usage: CHANNEL STATUS\n" -" Returns the status of the connected channel. Return values:\n" +" Usage: CHANNEL STATUS []\n" +" Returns the status of the specified channel.\n" +" If no channel name is given the returns the status of the\n" +" current channel.\n" +" Return values:\n" " 0 Channel is down and available\n" " 1 Channel is down, but reserved\n" " 2 Channel is off hook\n" @@ -531,9 +781,9 @@ static char usage_exec[] = " Returns whatever the application returns, or -2 on failure to find application\n"; static char usage_hangup[] = -" Usage: HANGUP\n" -" Hangs up the current channel.\n"; - +" Usage: HANGUP []\n" +" Hangs up the specified channel.\n" +" If no channel name is given, hangs up the current channel\n"; static char usage_answer[] = " Usage: ANSWER\n" @@ -576,13 +826,14 @@ static char usage_sendimage[] = " should not include extensions.\n"; static char usage_streamfile[] = -" Usage: STREAM FILE \n" +" Usage: STREAM FILE [sample offset]\n" " Send the given file, allowing playback to be interrupted by the given\n" " digits, if any. Use double quotes for the digits if you wish none to be\n" -" permitted. Returns 0 if playback completes without a digit being pressed, or\n" -" the ASCII numerical value of the digit if one was pressed, or -1 on error or\n" -" if the channel was disconnected. Remember, the file extension must not be\n" -" included in the filename.\n"; +" permitted. If sample offset is provided then the audio will seek to sample\n" +" offset before play starts. Returns 0 if playback completes without a digit\n" +" being pressed, or the ASCII numerical value of the digit if one was pressed,\n" +" or -1 on error or if the channel was disconnected. Remember, the file\n" +" extension must not be included in the filename.\n"; static char usage_saynumber[] = " Usage: SAY NUMBER \n" @@ -616,11 +867,12 @@ static char usage_setpriority[] = " Changes the priority for continuation upon exiting the application.\n"; static char usage_recordfile[] = -" Usage: RECORD FILE [BEEP]\n" +" Usage: RECORD FILE [offset samples] [BEEP]\n" " Record to a file until a given dtmf digit in the sequence is received\n" " Returns -1 on hangup or error. The format will specify what kind of file\n" " will be recorded. The timeout is the maximum record time in milliseconds, or\n" -" -1 for no timeout\n"; +" -1 for no timeout. Offset samples is optional, and if provided will seek to\n" +" the offset without exceeding the end of the file\n"; static char usage_autohangup[] = " Usage: SET AUTOHANGUP