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
1.0
Anthony Minessale II 21 years ago
parent f4b55b802c
commit 5385ca0a0e

@ -20,6 +20,7 @@
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/say.h>
#include <asterisk/config.h>
#include <asterisk/parking.h>
#include <asterisk/musiconhold.h>
#include <asterisk/callerid.h>
@ -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);

@ -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) {

@ -28,6 +28,7 @@
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/logger.h>
#include <asterisk/say.h>
#include <asterisk/file.h>
#include <asterisk/translate.h>
#include <asterisk/manager.h>
@ -40,7 +41,7 @@
#include <sys/ioctl.h>
#include <linux/zaptel.h>
#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 '#<extension' syntax. */
int flags;
struct ast_channel *cs[3];
int to = -1;
struct ast_frame *f;
struct ast_channel *who = NULL;
int res;
int res=0;
int nativefailed=0;
struct timeval start_time,precise_now;
long elapsed_ms=0,time_left_ms=0;
int playit=0,playitagain=1,first_time=1;
flags = (config->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)

@ -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 [ <module.c> [-set=<varname>:<value>] [-append=<varname>:<value>] [-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);
}

@ -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
/*!

@ -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);

@ -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 '#<extension' syntax. */
int len;
int len;
struct ast_frame *f;
struct ast_channel *who;
char newext[256], *ptr;
@ -226,7 +228,12 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allo
struct ast_option_header *aoh;
struct ast_channel *transferer;
struct ast_channel *transferee;
char *transferer_real_context;
char *transferer_real_context;
int allowdisconnect,allowredirect_in,allowredirect_out;
allowdisconnect = config->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);

Loading…
Cancel
Save