From 5385ca0a0e995904852027e5bc460c483c3263db Mon Sep 17 00:00:00 2001 From: Anthony Minessale II Date: Mon, 26 Apr 2004 23:22:34 +0000 Subject: applied final release of bug 1353 per Mark's permission git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@2782 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_dial.c | 109 ++++++++++++++++++++- apps/app_queue.c | 9 +- channel.c | 231 +++++++++++++++++++++++++++++++++------------ contrib/scripts/astxs | 114 ++++++++++++++++++++++ include/asterisk/channel.h | 20 +++- include/asterisk/parking.h | 6 +- res/res_parking.c | 29 +++++- 7 files changed, 447 insertions(+), 71 deletions(-) create mode 100755 contrib/scripts/astxs diff --git a/apps/app_dial.c b/apps/app_dial.c index af3c70c6d..3492c1004 100755 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,15 @@ static char *descrip = " 'g' -- goes on in context if the destination channel hangs up\n" " 'A(x)' -- play an announcement to the called party, using x as file\n" " 'S(x)' -- hangup the call after x seconds AFTER called party picked up\n" +" 'L(x[:y][:z])' -- Limit the call to 'x' ms warning when 'y' ms are left (repeated every 'z' ms)\n" +" -- Only 'x' is required, 'y' and 'z' are optional.\n" +" -- The following special variables are optional:\n" +" ** LIMIT_PLAYAUDIO_CALLER (default yes) Play sounds to the caller.\n" +" ** LIMIT_PLAYAUDIO_CALLEE Play sounds to the callee.\n" +" ** LIMIT_TIMEOUT_FILE File to play when time is up.\n" +" ** LIMIT_CONNECT_FILE File to play when call begins.\n" +" ** LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n" +" -- 'timeleft' is a special sound macro to auto-say the time left and is the default.\n\n" " In addition to transferring the call, a call may be parked and then picked\n" "up by another user.\n" " The optional URL will be sent to the called party if the channel supports\n" @@ -390,7 +400,19 @@ static int dial_exec(struct ast_channel *chan, void *data) unsigned int calldurationlimit=0; char *cdl; time_t now; - + struct ast_bridge_config config; + long timelimit = 0; + long play_warning = 0; + long warning_freq=0; + char *warning_sound=NULL; + char *end_sound=NULL; + char *start_sound=NULL; + char *limitptr; + char limitdata[256]; + char *stack,*var; + int play_to_caller=0,play_to_callee=0; + int playargs=0; + if (!data) { ast_log(LOG_WARNING, "Dial requires an argument (technology1/number1&technology2/number2...|optional timeout|options)\n"); return -1; @@ -430,13 +452,81 @@ static int dial_exec(struct ast_channel *chan, void *data) if (transfer) { + /* Extract call duration limit */ if ((cdl = strstr(transfer, "S("))) { calldurationlimit=atoi(cdl+2); if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %i seconds.\n",calldurationlimit); } - + + /* XXX LIMIT SUPPORT */ + if ((limitptr = strstr(transfer, "L("))) { + strncpy(limitdata, limitptr + 2, sizeof(limitdata) - 1); + /* Overwrite with X's what was the limit info */ + while(*limitptr && (*limitptr != ')')) + *(limitptr++) = 'X'; + if (*limitptr) + *limitptr = 'X'; + /* Now find the end of the privdb */ + limitptr = strchr(limitdata, ')'); + if (limitptr) + *limitptr = '\0'; + else { + ast_log(LOG_WARNING, "Limit Data lacking trailing ')'\n"); + } + + var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLER"); + play_to_caller = var ? ast_true(var) : 1; + + var = pbx_builtin_getvar_helper(chan,"LIMIT_PLAYAUDIO_CALLEE"); + play_to_callee = var ? ast_true(var) : 0; + + if(! play_to_caller && ! play_to_callee) + play_to_caller=1; + + var = pbx_builtin_getvar_helper(chan,"LIMIT_WARNING_FILE"); + warning_sound = var ? var : "timeleft"; + + var = pbx_builtin_getvar_helper(chan,"LIMIT_TIMEOUT_FILE"); + end_sound = var ? var : NULL; + + var = pbx_builtin_getvar_helper(chan,"LIMIT_CONNECT_FILE"); + start_sound = var ? var : NULL; + + var=stack=limitdata; + + var = strsep(&stack, ":"); + if(var) { + timelimit = atol(var); + playargs++; + } + var = strsep(&stack, ":"); + if(var) { + play_warning = atol(var); + playargs++; + } + + var = strsep(&stack, ":"); + if(var) { + warning_freq = atol(var); + playargs++; + } + + if(! timelimit) { + timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0; + warning_sound=NULL; + } + calldurationlimit=0; /* undo effect of S(x) in case they are both used */ + if(! play_warning && ! start_sound && ! end_sound && timelimit) { /* more efficient do it like S(x) does since no advanced opts*/ + calldurationlimit=timelimit/1000; + timelimit=play_to_caller=play_to_callee=play_warning=warning_freq=0; + } + else + ast_verbose(VERBOSE_PREFIX_3"Limit Data: timelimit=%ld\n -- play_warning=%ld\n -- play_to_caller=%s\n -- play_to_callee=%s\n -- warning_freq=%ld\n -- warning_sound=%s\n -- end_sound=%s\n -- start_sound=%s\n",timelimit,play_warning,play_to_caller ? "yes" : "no",play_to_callee ? "yes" : "no",warning_freq,warning_sound ? warning_sound : "UNDEF",end_sound ? end_sound : "UNDEF",start_sound ? start_sound : "UNDEF"); + + } + /* XXX ANNOUNCE SUPPORT */ if ((ann = strstr(transfer, "A("))) { announce = 1; @@ -729,7 +819,20 @@ static int dial_exec(struct ast_channel *chan, void *data) time(&now); chan->whentohangup = now + calldurationlimit; } - res = ast_bridge_call(chan, peer, allowredir_in, allowredir_out, allowdisconnect); + + memset(&config,0,sizeof(struct ast_bridge_config)); + config.play_to_caller=play_to_caller; + config.play_to_callee=play_to_callee; + config.allowredirect_in = allowredir_in; + config.allowredirect_out = allowredir_out; + config.allowdisconnect = allowdisconnect; + config.timelimit = timelimit; + config.play_warning = play_warning; + config.warning_freq = warning_freq; + config.warning_sound = warning_sound; + config.end_sound = end_sound; + config.start_sound = start_sound; + res = ast_bridge_call(chan,peer,&config); if (res != AST_PBX_NO_HANGUP_PEER) ast_hangup(peer); diff --git a/apps/app_queue.c b/apps/app_queue.c index d8e13313c..611b1f2c9 100755 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -874,6 +874,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri char digit = 0; time_t callstart; time_t now; + struct ast_bridge_config config; /* Hold the lock while we setup the outgoing calls */ ast_mutex_lock(&qe->parent->lock); strncpy(queuename, qe->parent->name, sizeof(queuename) - 1); @@ -1030,7 +1031,13 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1); strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1); time(&callstart); - bridge = ast_bridge_call(qe->chan, peer, allowredir_in, allowredir_out, allowdisconnect); + + memset(&config,0,sizeof(struct ast_bridge_config)); + config.allowredirect_in = allowredir_in; + config.allowredirect_out = allowredir_out; + config.allowdisconnect = allowdisconnect; + bridge = ast_bridge_call(qe->chan,peer,&config); + if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context); } else if (qe->chan->_softhangup) { diff --git a/channel.c b/channel.c index 91b81b9fe..9a083fd36 100755 --- a/channel.c +++ b/channel.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,7 @@ #include #include #ifndef ZT_TIMERPING -#error "You need newer zaptel! Please cvs update zaptel" +#error "You need newer zaptel! Please cvs update zaptel" #endif #endif @@ -140,17 +141,19 @@ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset) time_t myt; time(&myt); - if (offset) + if (offset) chan->whentohangup = myt + offset; - else - chan->whentohangup = 0; + else + chan->whentohangup = 0; return; } + + int ast_channel_register(char *type, char *description, int capabilities, struct ast_channel *(*requester)(char *type, int format, void *data)) { - return ast_channel_register_ex(type, description, capabilities, requester, NULL); + return ast_channel_register_ex(type, description, capabilities, requester, NULL); } int ast_channel_register_ex(char *type, char *description, int capabilities, @@ -271,8 +274,8 @@ struct ast_channel *ast_channel_alloc(int needqueue) struct ast_channel_pvt *pvt; int x; int flags; - struct varshead *headp; - + struct varshead *headp; + /* If shutting down, don't allocate any new channels */ if (shutting_down) @@ -333,7 +336,7 @@ struct ast_channel *ast_channel_alloc(int needqueue) snprintf(tmp->uniqueid, sizeof(tmp->uniqueid), "%li.%d", (long)time(NULL), uniqueint++); headp=&tmp->varshead; ast_mutex_init(&tmp->lock); - AST_LIST_HEAD_INIT(headp); + AST_LIST_HEAD_INIT(headp); tmp->vars=ast_var_assign("tempvar","tempval"); AST_LIST_INSERT_HEAD(headp,tmp->vars,entries); strncpy(tmp->context, "default", sizeof(tmp->context)-1); @@ -461,7 +464,7 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev) } -int ast_safe_sleep_conditional( struct ast_channel *chan, int ms, +int ast_safe_sleep_conditional( struct ast_channel *chan, int ms, int (*cond)(void*), void *data ) { struct ast_frame *f; @@ -569,13 +572,13 @@ void ast_channel_free(struct ast_channel *chan) /* loop over the variables list, freeing all data and deleting list items */ /* no need to lock the list, as the channel is already locked */ - while (!AST_LIST_EMPTY(headp)) { /* List Deletion. */ - vardata = AST_LIST_FIRST(headp); - AST_LIST_REMOVE_HEAD(headp, entries); -// printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata)); - ast_var_delete(vardata); + while (!AST_LIST_EMPTY(headp)) { /* List Deletion. */ + vardata = AST_LIST_FIRST(headp); + AST_LIST_REMOVE_HEAD(headp, entries); +// printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata)); + ast_var_delete(vardata); } - + free(chan->pvt); chan->pvt = NULL; @@ -665,7 +668,7 @@ int ast_hangup(struct ast_channel *chan) } if (chan->blocking) { ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd " - "is blocked by thread %ld in procedure %s! Expect a failure\n", + "is blocked by thread %ld in procedure %s! Expect a failure\n", (long)pthread_self(), chan->name, (long)chan->blocker, chan->blockproc); CRASH; } @@ -681,9 +684,9 @@ int ast_hangup(struct ast_channel *chan) ast_mutex_unlock(&chan->lock); manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n" - "Uniqueid: %s\r\n" - "Cause: %i\r\n", - chan->name, chan->uniqueid, chan->hangupcause); + "Uniqueid: %s\r\n" + "Cause: %i\r\n", + chan->name, chan->uniqueid, chan->hangupcause); ast_channel_free(chan); return res; } @@ -1114,7 +1117,7 @@ struct ast_frame *ast_read(struct ast_channel *chan) ast_log(LOG_WARNING, "Failed to perform masquerade\n"); f = NULL; } else - f = &null_frame; + f = &null_frame; ast_mutex_unlock(&chan->lock); return f; } @@ -1128,7 +1131,7 @@ struct ast_frame *ast_read(struct ast_channel *chan) } if (!chan->deferdtmf && strlen(chan->dtmfq)) { - /* We have DTMF that has been deferred. Return it now */ + /* We have DTMF that has been deferred. Return it now */ chan->dtmff.frametype = AST_FRAME_DTMF; chan->dtmff.subclass = chan->dtmfq[0]; /* Drop first digit */ @@ -1181,7 +1184,7 @@ struct ast_frame *ast_read(struct ast_channel *chan) chan->timingdata = NULL; ast_mutex_unlock(&chan->lock); } - f = &null_frame; + f = &null_frame; return f; } else ast_log(LOG_NOTICE, "No/unknown event '%d' on timer for '%s'?\n", blah, chan->name); @@ -1361,10 +1364,10 @@ int ast_recvchar(struct ast_channel *chan, int timeout) f = ast_read(chan); if (f == NULL) return -1; /* if hangup */ if ((f->frametype == AST_FRAME_CONTROL) && - (f->subclass == AST_CONTROL_HANGUP)) return -1; /* if hangup */ - if (f->frametype == AST_FRAME_TEXT) /* if a text frame */ + (f->subclass == AST_CONTROL_HANGUP)) return -1; /* if hangup */ + if (f->frametype == AST_FRAME_TEXT) /* if a text frame */ { - c = *((char *)f->data); /* get the data */ + c = *((char *)f->data); /* get the data */ ast_frfree(f); return(c); } @@ -1397,21 +1400,21 @@ static int do_senddigit(struct ast_channel *chan, char digit) * it by doing our own generation. (PM2002) */ static const char* dtmf_tones[] = { - "!941+1336/100,!0/100", /* 0 */ - "!697+1209/100,!0/100", /* 1 */ - "!697+1336/100,!0/100", /* 2 */ - "!697+1477/100,!0/100", /* 3 */ - "!770+1209/100,!0/100", /* 4 */ - "!770+1336/100,!0/100", /* 5 */ - "!770+1477/100,!0/100", /* 6 */ - "!852+1209/100,!0/100", /* 7 */ - "!852+1336/100,!0/100", /* 8 */ - "!852+1477/100,!0/100", /* 9 */ - "!697+1633/100,!0/100", /* A */ - "!770+1633/100,!0/100", /* B */ - "!852+1633/100,!0/100", /* C */ - "!941+1633/100,!0/100", /* D */ - "!941+1209/100,!0/100", /* * */ + "!941+1336/100,!0/100", /* 0 */ + "!697+1209/100,!0/100", /* 1 */ + "!697+1336/100,!0/100", /* 2 */ + "!697+1477/100,!0/100", /* 3 */ + "!770+1209/100,!0/100", /* 4 */ + "!770+1336/100,!0/100", /* 5 */ + "!770+1477/100,!0/100", /* 6 */ + "!852+1209/100,!0/100", /* 7 */ + "!852+1336/100,!0/100", /* 8 */ + "!852+1477/100,!0/100", /* 9 */ + "!697+1633/100,!0/100", /* A */ + "!770+1633/100,!0/100", /* B */ + "!852+1633/100,!0/100", /* C */ + "!941+1633/100,!0/100", /* D */ + "!941+1209/100,!0/100", /* * */ "!941+1477/100,!0/100" }; /* # */ if (digit >= '0' && digit <='9') ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0); @@ -1462,7 +1465,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) struct ast_frame *f = NULL; /* Stop if we're a zombie or need a soft hangup */ ast_mutex_lock(&chan->lock); - if (chan->zombie || ast_check_hangup(chan)) { + if (chan->zombie || ast_check_hangup(chan)) { ast_mutex_unlock(&chan->lock); return -1; } @@ -1582,7 +1585,7 @@ int ast_set_write_format(struct ast_channel *chan, int fmts) return -1; } - /* Now we have a good choice for both. We'll write using our native format. */ + /* Now we have a good choice for both. We'll write using our native format. */ chan->pvt->rawwriteformat = native; /* User perspective is fmt */ chan->writeformat = fmt; @@ -1615,7 +1618,7 @@ int ast_set_read_format(struct ast_channel *chan, int fmts) return -1; } - /* Now we have a good choice for both. We'll write using our native format. */ + /* Now we have a good choice for both. We'll write using our native format. */ chan->pvt->rawreadformat = native; /* User perspective is fmt */ chan->readformat = fmt; @@ -1643,7 +1646,7 @@ struct ast_channel *__ast_request_and_dial(char *type, int format, void *data, i char *tmp, *var; /* JDG chanvar */ tmp = oh->variable; - /* FIXME replace this call with strsep NOT*/ + /* FIXME replace this call with strsep NOT*/ while( (var = strtok_r(NULL, "|", &tmp)) ) { pbx_builtin_setvar( chan, var ); } /* /JDG */ @@ -1795,9 +1798,9 @@ int ast_parse_device_state(char *device) strncpy(name, chan->name, sizeof(name)-1); cut = strchr(name,'-'); if (cut) - *cut = 0; + *cut = 0; if (!strcmp(name, device)) - return AST_DEVICE_INUSE; + return AST_DEVICE_INUSE; chan = ast_channel_walk(chan); } return AST_DEVICE_UNKNOWN; @@ -1813,7 +1816,7 @@ int ast_device_state(char *device) strncpy(tech, device, sizeof(tech)-1); number = strchr(tech, '/'); if (!number) { - return AST_DEVICE_INVALID; + return AST_DEVICE_INVALID; } *number = 0; number++; @@ -2090,8 +2093,8 @@ int ast_do_masquerade(struct ast_channel *original) clone->name, clone->_state, original->name, original->_state); #endif /* XXX This is a seriously wacked out operation. We're essentially putting the guts of - the clone channel into the original channel. Start by killing off the original - channel's backend. I'm not sure we're going to keep this function, because + the clone channel into the original channel. Start by killing off the original + channel's backend. I'm not sure we're going to keep this function, because while the features are nice, the cost is very high in terms of pure nastiness. XXX */ /* We need the clone's lock, too */ @@ -2126,7 +2129,7 @@ int ast_do_masquerade(struct ast_channel *original) manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", newn, masqn); manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", orig, newn); - /* Swap the guts */ + /* Swap the guts */ p = original->pvt; original->pvt = clone->pvt; clone->pvt = p; @@ -2175,7 +2178,7 @@ int ast_do_masquerade(struct ast_channel *original) strncpy(clone->name, zombn, sizeof(clone->name) - 1); manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", masqn, zombn); - /* Keep the same language. */ + /* Keep the same language. */ /* Update the type. */ original->type = clone->type; /* Copy the FD's */ @@ -2183,7 +2186,7 @@ int ast_do_masquerade(struct ast_channel *original) original->fds[x] = clone->fds[x]; } /* Append variables from clone channel into original channel */ - /* XXX Is this always correct? We have to in order to keep MACROS working XXX */ + /* XXX Is this always correct? We have to in order to keep MACROS working XXX */ varptr = original->varshead.first; if (varptr) { while(varptr->entries.next) { @@ -2200,12 +2203,12 @@ int ast_do_masquerade(struct ast_channel *original) /* CDR fields remain the same */ /* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */ /* Application and data remain the same */ - /* Clone exception becomes real one, as with fdno */ + /* Clone exception becomes real one, as with fdno */ original->exception = clone->exception; original->fdno = clone->fdno; /* Schedule context remains the same */ /* Stream stuff stays the same */ - /* Keep the original state. The fixup code will need to work with it most likely */ + /* Keep the original state. The fixup code will need to work with it most likely */ /* dnid and callerid change to become the new, HOWEVER, we also link the original's fields back into the defunct 'clone' so that they will be freed when @@ -2229,7 +2232,7 @@ int ast_do_masquerade(struct ast_channel *original) these separate */ original->_state = clone->_state; - /* Context, extension, priority, app data, jump table, remain the same */ + /* Context, extension, priority, app data, jump table, remain the same */ /* pvt switches. pbx stays the same, as does next */ /* Set the write format */ @@ -2327,16 +2330,73 @@ int ast_setstate(struct ast_channel *chan, int state) return 0; } -int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) -{ - /* Copy voice back and forth between the two channels. Give the peer + +static long tvdiff(struct timeval *now,struct timeval *then) { + return (((now->tv_sec * 1000) + now->tv_usec / 1000) - ((then->tv_sec * 1000) + then->tv_usec / 1000)); +} + +static void bridge_playfile(struct ast_channel *chan,char *sound,int remain) { + int res=0,min=0,sec=0; + + if(remain > 0) { + if(remain / 60 > 1) { + min = remain / 60; + sec = remain % 60; + } + else { + sec = remain; + } + } + + if(!strcmp(sound,"timeleft")) { + res=ast_streamfile(chan,"vm-youhave",chan->language); + res = ast_waitstream(chan, ""); + if(min) { + res = ast_say_number(chan,min, AST_DIGIT_ANY, chan->language); + res=ast_streamfile(chan,"minutes",chan->language); + res = ast_waitstream(chan, ""); + } + if(sec) { + res = ast_say_number(chan,sec, AST_DIGIT_ANY, chan->language); + res=ast_streamfile(chan,"seconds",chan->language); + res = ast_waitstream(chan, ""); + } + } + else { + res=ast_streamfile(chan,sound,chan->language); + res = ast_waitstream(chan, ""); + } +} + +int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) { + /* Copy voice back and forth between the two channels. Give the peer the ability to transfer calls with '#allowdisconnect||config->allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0) + (config->allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0); + + /* timestamp */ + gettimeofday(&start_time,NULL); + time_left_ms = config->timelimit; + + if(config->play_to_caller && config->start_sound){ + bridge_playfile(c0,config->start_sound,time_left_ms / 1000); + } + if(config->play_to_callee && config->start_sound){ + bridge_playfile(c1,config->start_sound,time_left_ms / 1000); + } + + /* Stop if we're a zombie or need a soft hangup */ if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) @@ -2366,6 +2426,57 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags c0->name, c1->name, c0->uniqueid, c1->uniqueid); for (/* ever */;;) { + + /* timestamp */ + if(config->timelimit) { + gettimeofday(&precise_now,NULL); + elapsed_ms = tvdiff(&precise_now,&start_time); + time_left_ms = config->timelimit - elapsed_ms; + + if(playitagain && (config->play_to_caller || config->play_to_callee) && (config->play_warning && time_left_ms <= config->play_warning)) { + /* narrowing down to the end */ + if(config->warning_freq == 0) { + playit = 1; + first_time=0; + playitagain=0; + } + else if(first_time) { + playit = 1; + first_time=0; + } + else { + if((time_left_ms % config->warning_freq) <= 50) { + playit = 1; + } + } + } + + if(time_left_ms <= 0) { + if(config->play_to_caller && config->end_sound){ + bridge_playfile(c0,config->end_sound,0); + } + + if(config->play_to_callee && config->end_sound){ + bridge_playfile(c1,config->end_sound,0); + } + break; + } + + if(time_left_ms >= 5000 && playit) { + if(config->play_to_caller && config->warning_sound && config->play_warning){ + bridge_playfile(c0,config->warning_sound,time_left_ms / 1000); + } + + if(config->play_to_callee && config->warning_sound && config->play_warning){ + bridge_playfile(c1,config->warning_sound,time_left_ms / 1000); + } + playit = 0; + } + + } + + + /* Stop if we're a zombie or need a soft hangup */ if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) { *fo = NULL; @@ -2374,7 +2485,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",c0->name,c1->name,c0->zombie?"Yes":"No",ast_check_hangup(c0)?"Yes":"No",c1->zombie?"Yes":"No",ast_check_hangup(c1)?"Yes":"No"); break; } - if (c0->pvt->bridge && + if (c0->pvt->bridge && config->timelimit==0 && (c0->pvt->bridge == c1->pvt->bridge) && !nativefailed && !c0->monitor && !c1->monitor) { /* Looks like they share a bridge code */ if (option_verbose > 2) diff --git a/contrib/scripts/astxs b/contrib/scripts/astxs new file mode 100755 index 000000000..663617ecd --- /dev/null +++ b/contrib/scripts/astxs @@ -0,0 +1,114 @@ +#!/usr/bin/perl + +my $astdir = $ENV{ASTSRC} or "/usr/src/asterisk"; + + +sub esystem($) { + my $cmd = shift; + print "$cmd\n"; + system($cmd); +} +sub usage($) { + my $str = shift; + print "\n$str\n\n"; + print "Usage $0 [ [-set=:] [-append=:] [-install] ] | [-help] \n\n"; + + print "varnames of interest: +=============================================================================== +'INCLUDES' 'ASTLIBDIR' 'AGI_DIR' 'ASTVARRUNDIR' 'CC' 'ASTETCDIR' 'EXTOBJ' +'ASTSPOOLDIR' 'ASTLOGDIR' 'MODULES_DIR' 'ASTSBINDIR' 'ASTHEADERDIR' 'LDFLAGS' +'ASTVARLIBDIR' 'ASTBINDIR' 'INSTALL_PREFIX' 'ASTCONFPATH' 'ASTSRC' 'CFLAGS' +=============================================================================== +"; + + exit; + +} + + +my %avars = (); +my %svars = (); +my %vars = (); + + + + +my %args = (); + + +foreach(@ARGV) { + + if(/^\-set=([^\:]+):(.*)/) { + $svars{$1} = $2; + } + elsif(/^\-append=([^\:]+):(.*)/) { + $avars{$1} .= " $2"; + } + elsif(/^\-([^\=]+)=(.*)/) { + $args{$1} = $2; + } + elsif(/^\-([^\=]+)$/) { + $args{$1}++; + } + else { + push(@{$args{plain}},$_); + } +} + +if($args{help} or $args{h}) { + usage "Help"; +} + + +my $pwd = `/bin/pwd`; +chomp($pwd); + +$vars{astdir} ||= $astdir; + +chdir($vars{astdir}); +my $type = $args{type} || "apps"; +my $env = `make ${type}_env`; +chdir($pwd); + +foreach(split("\n",$env)) { + my($var,$val) = /([^\=]+)\=(.*)/; + $vars{$var} = $val; +} + + + + +foreach(keys %svars) { + $vars{$_} = $svars{$_}; +} + +foreach(keys %avars) { + $vars{$_} .= $avars{$_}; +} + + +if($args{print}) { + print "$vars{$args{print}}"; + exit; +} + + +my($base,$ext); +my $cfile = $args{plain}->[0]; +if($cfile) { + ($base,$ext) = $cfile =~ /^([^\.]+)\.(.)/; +} + +if($ext ne "c") { + usage "Bad Input File"; +} + +my $bad=0; + +$bad = esystem("$vars{CC} $vars{CFLAGS} -c ${base}.c -o ${base}.o"); +$bad = esystem("$vars{CC} $vars{SOLINK} -o $vars{LDFLAGS} ${base}.so $base.o $vars{EXTOBJ}") if(!$bad); + +if($args{install} and $vars{MODULES_DIR}) { + $bad = esystem("/bin/cp -p ${base}.so $vars{MODULES_DIR}") if(!$bad); +} + diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index ef1d84756..2a2a96a7a 100755 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -267,6 +267,22 @@ static inline void ast_dup_flag(struct ast_channel *dstchan, struct ast_channel ast_clear_flag(dstchan, mode); } + +struct ast_bridge_config { + int play_to_caller; + int play_to_callee; + int allowredirect_in; + int allowredirect_out; + int allowdisconnect; + long timelimit; + long play_warning; + long warning_freq; + char *warning_sound; + char *end_sound; + char *start_sound; +}; + + struct chanmon; #define LOAD_OH(oh) { \ @@ -666,7 +682,9 @@ int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1); * \param rc destination channel(?) * Bridge two channels (c0 and c1) together. If an important frame occurs, we return that frame in *rf (remember, it could be NULL) and which channel (0 or 1) in rc */ -int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); +//int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); +int ast_channel_bridge(struct ast_channel *c0,struct ast_channel *c1,struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc); + //! Weird function made for call transfers /*! diff --git a/include/asterisk/parking.h b/include/asterisk/parking.h index 4b9859592..836909d71 100755 --- a/include/asterisk/parking.h +++ b/include/asterisk/parking.h @@ -44,9 +44,13 @@ extern int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *hos extern char *ast_parking_ext(void); extern char *ast_pickup_ext(void); + + //! Bridge a call, optionally allowing redirection -extern int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect_in, int allowredirect_out, int allowdisconnect); +extern int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config); + + extern int ast_pickup_call(struct ast_channel *chan); diff --git a/res/res_parking.c b/res/res_parking.c index 1c9c11b7c..9c11f6a38 100755 --- a/res/res_parking.c +++ b/res/res_parking.c @@ -214,11 +214,13 @@ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int return 0; } -int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect_in, int allowredirect_out, int allowdisconnect) + +int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config) { /* Copy voice back and forth between the two channels. Give the peer the ability to transfer calls with '#allowdisconnect; + allowredirect_in = config->allowredirect_in; + allowredirect_out = config->allowredirect_out; /* Answer if need be */ if (ast_answer(chan)) @@ -246,7 +253,7 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allo peer->cdr = NULL; } for (;;) { - res = ast_channel_bridge(chan, peer, (allowdisconnect||allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0) + (allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0), &f, &who); + res = ast_channel_bridge(chan,peer,config,&f, &who); if (res < 0) { ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); return -1; @@ -534,6 +541,8 @@ static int park_exec(struct ast_channel *chan, void *data) struct parkeduser *pu, *pl=NULL; int park; int dres; + struct ast_bridge_config config; + if (!data) { ast_log(LOG_WARNING, "Park requires an argument (extension number)\n"); return -1; @@ -575,7 +584,17 @@ static int park_exec(struct ast_channel *chan, void *data) were the person called. */ if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); - res = ast_bridge_call(chan, peer, 1, 1, 0); + + memset(&config,0,sizeof(struct ast_bridge_config)); + config.allowredirect_in = 1; + config.allowredirect_out = 1; + config.allowdisconnect = 0; + config.timelimit = 0; + config.play_warning = 0; + config.warning_freq = 0; + config.warning_sound=NULL; + res = ast_bridge_call(chan,peer,&config); + /* Simulate the PBX hanging up */ if (res != AST_PBX_NO_HANGUP_PEER) ast_hangup(peer); -- cgit v1.2.3