mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 04:30:28 +00:00
Merge Tony's attended # transfer with changes (bug #3241)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4677 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
45
app.c
45
app.c
@@ -30,11 +30,56 @@
|
|||||||
#include <asterisk/options.h>
|
#include <asterisk/options.h>
|
||||||
#include <asterisk/utils.h>
|
#include <asterisk/utils.h>
|
||||||
#include <asterisk/lock.h>
|
#include <asterisk/lock.h>
|
||||||
|
#include <asterisk/indications.h>
|
||||||
#include "asterisk.h"
|
#include "asterisk.h"
|
||||||
#include "astconf.h"
|
#include "astconf.h"
|
||||||
|
|
||||||
#define MAX_OTHER_FORMATS 10
|
#define MAX_OTHER_FORMATS 10
|
||||||
|
|
||||||
|
|
||||||
|
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
|
||||||
|
{
|
||||||
|
struct tone_zone_sound *ts;
|
||||||
|
int res=0, x=0;
|
||||||
|
|
||||||
|
if(!timeout && chan->pbx)
|
||||||
|
timeout = chan->pbx->dtimeout;
|
||||||
|
else if(!timeout)
|
||||||
|
timeout = 5;
|
||||||
|
|
||||||
|
ts = ast_get_indication_tone(chan->zone,"dial");
|
||||||
|
if (ts && ts->data[0]) {
|
||||||
|
res = ast_playtones_start(chan, 0, ts->data, 0);
|
||||||
|
} else
|
||||||
|
ast_log(LOG_NOTICE,"Huh....? no dial for indications?\n");
|
||||||
|
|
||||||
|
memset(collect, 0, size);
|
||||||
|
for (x=0; strlen(collect) < size; ) {
|
||||||
|
res = ast_waitfordigit(chan, timeout);
|
||||||
|
if (!ast_ignore_pattern(context, collect))
|
||||||
|
ast_playtones_stop(chan);
|
||||||
|
if (res < 1)
|
||||||
|
break;
|
||||||
|
collect[x++] = res;
|
||||||
|
if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num)) {
|
||||||
|
if (collect[x-1] == '#') {
|
||||||
|
/* Not a valid extension, ending in #, assume the # was to finish dialing */
|
||||||
|
collect[x-1] = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res >= 0) {
|
||||||
|
if (ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num))
|
||||||
|
res = 1;
|
||||||
|
else
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* set timeout to 0 for "standard" timeouts. Set timeout to -1 for
|
/* set timeout to 0 for "standard" timeouts. Set timeout to -1 for
|
||||||
"ludicrous time" (essentially never times out) */
|
"ludicrous time" (essentially never times out) */
|
||||||
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
|
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
|
||||||
|
@@ -60,8 +60,10 @@ static char *descrip =
|
|||||||
" This application returns -1 if the originating channel hangs up, or if the\n"
|
" This application returns -1 if the originating channel hangs up, or if the\n"
|
||||||
"call is bridged and either of the parties in the bridge terminate the call.\n"
|
"call is bridged and either of the parties in the bridge terminate the call.\n"
|
||||||
"The option string may contain zero or more of the following characters:\n"
|
"The option string may contain zero or more of the following characters:\n"
|
||||||
" 't' -- allow the called user transfer the calling user by hitting #.\n"
|
" 't' -- allow the called user to transfer the calling user by hitting #.\n"
|
||||||
" 'T' -- allow the calling user to transfer the call by hitting #.\n"
|
" 'T' -- allow the calling user to transfer the call by hitting #.\n"
|
||||||
|
" 'w' -- allow the called user to write the conversation to disk via app_monitor\n"
|
||||||
|
" 'W' -- allow the calling user to write the conversation to disk via app_monitor\n"
|
||||||
" 'f' -- Forces callerid to be set as the extension of the line \n"
|
" 'f' -- Forces callerid to be set as the extension of the line \n"
|
||||||
" making/redirecting the outgoing call. For example, some PSTNs\n"
|
" making/redirecting the outgoing call. For example, some PSTNs\n"
|
||||||
" don't allow callerids from other extensions then the ones\n"
|
" don't allow callerids from other extensions then the ones\n"
|
||||||
@@ -474,6 +476,8 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
|||||||
int to;
|
int to;
|
||||||
int allowredir_in=0;
|
int allowredir_in=0;
|
||||||
int allowredir_out=0;
|
int allowredir_out=0;
|
||||||
|
int monitor_in = 0;
|
||||||
|
int monitor_out = 0;
|
||||||
int allowdisconnect_in=0;
|
int allowdisconnect_in=0;
|
||||||
int allowdisconnect_out=0;
|
int allowdisconnect_out=0;
|
||||||
int hasmacro = 0;
|
int hasmacro = 0;
|
||||||
@@ -789,21 +793,25 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
|||||||
}
|
}
|
||||||
memset(tmp, 0, sizeof(struct localuser));
|
memset(tmp, 0, sizeof(struct localuser));
|
||||||
if (transfer) {
|
if (transfer) {
|
||||||
|
if (strchr(transfer, 'w'))
|
||||||
|
monitor_in = 1;
|
||||||
|
if (strchr(transfer, 'W'))
|
||||||
|
monitor_out = 1;
|
||||||
if (strchr(transfer, 't'))
|
if (strchr(transfer, 't'))
|
||||||
tmp->allowredirect_in = 1;
|
tmp->allowredirect_in = 1;
|
||||||
else tmp->allowredirect_in = 0;
|
else tmp->allowredirect_in = 0;
|
||||||
if (strchr(transfer, 'T'))
|
if (strchr(transfer, 'T'))
|
||||||
tmp->allowredirect_out = 1;
|
tmp->allowredirect_out = 1;
|
||||||
else tmp->allowredirect_out = 0;
|
else tmp->allowredirect_out = 0;
|
||||||
if (strchr(transfer, 'r'))
|
if (strchr(transfer, 'r'))
|
||||||
tmp->ringbackonly = 1;
|
tmp->ringbackonly = 1;
|
||||||
else tmp->ringbackonly = 0;
|
else tmp->ringbackonly = 0;
|
||||||
if (strchr(transfer, 'm'))
|
if (strchr(transfer, 'm'))
|
||||||
tmp->musiconhold = 1;
|
tmp->musiconhold = 1;
|
||||||
else tmp->musiconhold = 0;
|
else tmp->musiconhold = 0;
|
||||||
if (strchr(transfer, 'H'))
|
if (strchr(transfer, 'H'))
|
||||||
allowdisconnect_out = tmp->allowdisconnect_out = 1;
|
allowdisconnect_out = tmp->allowdisconnect_out = 1;
|
||||||
else allowdisconnect_out = tmp->allowdisconnect_out = 0;
|
else allowdisconnect_out = tmp->allowdisconnect_out = 0;
|
||||||
if(strchr(transfer, 'h'))
|
if(strchr(transfer, 'h'))
|
||||||
allowdisconnect_in = tmp->allowdisconnect_in = 1;
|
allowdisconnect_in = tmp->allowdisconnect_in = 1;
|
||||||
else allowdisconnect_in = tmp->allowdisconnect_in = 0;
|
else allowdisconnect_in = tmp->allowdisconnect_in = 0;
|
||||||
@@ -1143,6 +1151,10 @@ static int dial_exec(struct ast_channel *chan, void *data)
|
|||||||
config.features_callee |= AST_FEATURE_REDIRECT;
|
config.features_callee |= AST_FEATURE_REDIRECT;
|
||||||
if (allowredir_out)
|
if (allowredir_out)
|
||||||
config.features_caller |= AST_FEATURE_REDIRECT;
|
config.features_caller |= AST_FEATURE_REDIRECT;
|
||||||
|
if (monitor_in)
|
||||||
|
config.features_callee |= AST_FEATURE_AUTOMON;
|
||||||
|
if (monitor_out)
|
||||||
|
config.features_caller |= AST_FEATURE_AUTOMON;
|
||||||
if (allowdisconnect_in)
|
if (allowdisconnect_in)
|
||||||
config.features_callee |= AST_FEATURE_DISCONNECT;
|
config.features_callee |= AST_FEATURE_DISCONNECT;
|
||||||
if (allowdisconnect_out)
|
if (allowdisconnect_out)
|
||||||
|
@@ -17,5 +17,7 @@ context => parkedcalls ; Which context parked calls are in
|
|||||||
; feature activation. Default is 500
|
; feature activation. Default is 500
|
||||||
|
|
||||||
[featuremap]
|
[featuremap]
|
||||||
;blindxfer => # ; Blind transfer
|
;blindxfer => #1 ; Blind transfer
|
||||||
;disconnect => * ; Disconnect
|
;disconnect => *0 ; Disconnect
|
||||||
|
;automon => *1 ; One Touch Record
|
||||||
|
;atxfer => *2 ; Attended transfer
|
||||||
|
@@ -90,6 +90,9 @@ int ast_app_group_match_get_count(char *groupmatch, char *category);
|
|||||||
//! Create an argc argv type structure for app args
|
//! Create an argc argv type structure for app args
|
||||||
int ast_seperate_app_args(char *buf, char delim, char **array, int arraylen);
|
int ast_seperate_app_args(char *buf, char delim, char **array, int arraylen);
|
||||||
|
|
||||||
|
//! Present a dialtone and collect a certain length extension. Returns 1 on valid extension entered, -1 on hangup, or 0 on invalid extension.
|
||||||
|
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout);
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -236,6 +236,8 @@ struct ast_channel {
|
|||||||
#define AST_FEATURE_PLAY_WARNING (1 << 0)
|
#define AST_FEATURE_PLAY_WARNING (1 << 0)
|
||||||
#define AST_FEATURE_REDIRECT (1 << 1)
|
#define AST_FEATURE_REDIRECT (1 << 1)
|
||||||
#define AST_FEATURE_DISCONNECT (1 << 2)
|
#define AST_FEATURE_DISCONNECT (1 << 2)
|
||||||
|
#define AST_FEATURE_ATXFER (1 << 3)
|
||||||
|
#define AST_FEATURE_AUTOMON (1 << 4)
|
||||||
|
|
||||||
#define AST_FEATURE_FLAG_NEEDSDTMF (1 << 0)
|
#define AST_FEATURE_FLAG_NEEDSDTMF (1 << 0)
|
||||||
|
|
||||||
|
@@ -133,6 +133,54 @@ char *ast_pickup_ext(void)
|
|||||||
return pickup_ext;
|
return pickup_ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ast_bridge_thread_obj
|
||||||
|
{
|
||||||
|
struct ast_bridge_config bconfig;
|
||||||
|
struct ast_channel *chan;
|
||||||
|
struct ast_channel *peer;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *ast_bridge_call_thread(void *data)
|
||||||
|
{
|
||||||
|
struct ast_bridge_thread_obj *tobj = data;
|
||||||
|
tobj->chan->appl = "Transferred Call";
|
||||||
|
tobj->chan->data = tobj->peer->name;
|
||||||
|
tobj->peer->appl = "Transferred Call";
|
||||||
|
tobj->peer->data = tobj->chan->name;
|
||||||
|
if (tobj->chan->cdr) {
|
||||||
|
ast_cdr_reset(tobj->chan->cdr,0);
|
||||||
|
ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
|
||||||
|
}
|
||||||
|
if (tobj->peer->cdr) {
|
||||||
|
ast_cdr_reset(tobj->peer->cdr,0);
|
||||||
|
ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
|
||||||
|
ast_hangup(tobj->chan);
|
||||||
|
ast_hangup(tobj->peer);
|
||||||
|
tobj->chan = tobj->peer = NULL;
|
||||||
|
free(tobj);
|
||||||
|
tobj=NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ast_bridge_call_thread_launch(void *data)
|
||||||
|
{
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = pthread_attr_init(&attr);
|
||||||
|
pthread_attr_setschedpolicy(&attr, SCHED_RR);
|
||||||
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||||
|
result = ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
|
||||||
|
result = pthread_attr_destroy(&attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
|
static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@@ -311,6 +359,30 @@ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int
|
|||||||
#define FEATURE_SENSE_PEER (1 << 1)
|
#define FEATURE_SENSE_PEER (1 << 1)
|
||||||
#define FEATURE_MAX_LEN 11
|
#define FEATURE_MAX_LEN 11
|
||||||
|
|
||||||
|
static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
|
||||||
|
{
|
||||||
|
char *args;
|
||||||
|
if (option_verbose > 3)
|
||||||
|
ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call.\n", code);
|
||||||
|
if (monitor_ok) {
|
||||||
|
if (!monitor_app) {
|
||||||
|
if (!(monitor_app = pbx_findapp("Monitor")))
|
||||||
|
monitor_ok=0;
|
||||||
|
}
|
||||||
|
/* Copy to local variable just in case one of the channels goes away */
|
||||||
|
args = pbx_builtin_getvar_helper(chan, "TOUCH_MONITOR");
|
||||||
|
if (!args)
|
||||||
|
args = pbx_builtin_getvar_helper(peer, "TOUCH_MONITOR");
|
||||||
|
if (!args)
|
||||||
|
args = "WAV||m";
|
||||||
|
|
||||||
|
pbx_exec(peer, monitor_app, args, 1);
|
||||||
|
return FEATURE_RETURN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
|
static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
|
||||||
{
|
{
|
||||||
if (option_verbose > 3)
|
if (option_verbose > 3)
|
||||||
@@ -369,18 +441,8 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
|
|||||||
ptr++;
|
ptr++;
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
res = 0;
|
|
||||||
while (strlen(newext) < sizeof(newext) - 1) {
|
|
||||||
res = ast_waitfordigit(transferer, transferdigittimeout);
|
|
||||||
if (res < 1)
|
|
||||||
break;
|
|
||||||
if (res == '#')
|
|
||||||
break;
|
|
||||||
*(ptr++) = res;
|
|
||||||
if (!ast_matchmore_extension(transferer, transferer_real_context, newext, 1, transferer->cid.cid_num))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
ast_moh_stop(transferee);
|
ast_moh_stop(transferee);
|
||||||
ast_autoservice_stop(transferee);
|
ast_autoservice_stop(transferee);
|
||||||
@@ -447,6 +509,184 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
|
|||||||
return FEATURE_RETURN_SUCCESS;
|
return FEATURE_RETURN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
|
||||||
|
{
|
||||||
|
struct ast_channel *transferer;
|
||||||
|
struct ast_channel *transferee;
|
||||||
|
struct ast_channel *newchan, *xferchan=NULL;
|
||||||
|
int outstate=0;
|
||||||
|
struct ast_bridge_config bconfig;
|
||||||
|
char *transferer_real_context;
|
||||||
|
char xferto[256],dialstr[265];
|
||||||
|
char *cid_num;
|
||||||
|
char *cid_name;
|
||||||
|
int res;
|
||||||
|
struct ast_frame *f = NULL;
|
||||||
|
struct ast_bridge_thread_obj *tobj;
|
||||||
|
|
||||||
|
ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
|
||||||
|
if (sense == FEATURE_SENSE_PEER) {
|
||||||
|
transferer = peer;
|
||||||
|
transferee = chan;
|
||||||
|
} else {
|
||||||
|
transferer = chan;
|
||||||
|
transferee = peer;
|
||||||
|
}
|
||||||
|
if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
|
||||||
|
!(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
|
||||||
|
/* Use the non-macro context to transfer the call */
|
||||||
|
if (!ast_strlen_zero(transferer->macrocontext))
|
||||||
|
transferer_real_context = transferer->macrocontext;
|
||||||
|
else
|
||||||
|
transferer_real_context = transferer->context;
|
||||||
|
}
|
||||||
|
/* Start autoservice on chan while we talk
|
||||||
|
to the originator */
|
||||||
|
ast_autoservice_start(transferee);
|
||||||
|
ast_moh_start(transferee, NULL);
|
||||||
|
|
||||||
|
/* Transfer */
|
||||||
|
if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
|
||||||
|
ast_moh_stop(transferee);
|
||||||
|
ast_autoservice_stop(transferee);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
|
||||||
|
ast_moh_stop(transferee);
|
||||||
|
ast_autoservice_stop(transferee);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
|
||||||
|
cid_num = transferer->cid.cid_num;
|
||||||
|
cid_name = transferer->cid.cid_name;
|
||||||
|
if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
|
||||||
|
snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
|
||||||
|
if((newchan = ast_request_and_dial("Local", ast_best_codec(transferer->nativeformats), dialstr,30000, &outstate, cid_num, cid_name))) {
|
||||||
|
res = ast_channel_make_compatible(transferer, newchan);
|
||||||
|
if (res < 0) {
|
||||||
|
ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
|
||||||
|
ast_hangup(newchan);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(&bconfig,0,sizeof(struct ast_bridge_config));
|
||||||
|
bconfig.features_caller |= AST_FEATURE_DISCONNECT;
|
||||||
|
bconfig.features_callee |= AST_FEATURE_DISCONNECT;
|
||||||
|
res = ast_bridge_call(transferer,newchan,&bconfig);
|
||||||
|
if(newchan->_softhangup || newchan->_state != AST_STATE_UP) {
|
||||||
|
ast_hangup(newchan);
|
||||||
|
if (f) {
|
||||||
|
ast_frfree(f);
|
||||||
|
f = NULL;
|
||||||
|
}
|
||||||
|
if (!ast_streamfile(transferer, "beep", transferer->language)) {
|
||||||
|
if (ast_waitstream(transferer, "") < 0) {
|
||||||
|
ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast_moh_stop(transferee);
|
||||||
|
ast_autoservice_stop(transferee);
|
||||||
|
transferer->_softhangup = 0;
|
||||||
|
return FEATURE_RETURN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ast_channel_make_compatible(transferee, newchan);
|
||||||
|
if (res < 0) {
|
||||||
|
ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
|
||||||
|
ast_hangup(newchan);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ast_moh_stop(transferee);
|
||||||
|
|
||||||
|
if((ast_autoservice_stop(transferee) < 0)
|
||||||
|
||(ast_waitfordigit(transferee,100) < 0)
|
||||||
|
|| (ast_waitfordigit(newchan,100) < 0)
|
||||||
|
|| ast_check_hangup(transferee)
|
||||||
|
|| ast_check_hangup(newchan)) {
|
||||||
|
ast_hangup(newchan);
|
||||||
|
res = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xferchan = ast_channel_alloc(0))) {
|
||||||
|
snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
|
||||||
|
/* Make formats okay */
|
||||||
|
xferchan->readformat = transferee->readformat;
|
||||||
|
xferchan->writeformat = transferee->writeformat;
|
||||||
|
ast_channel_masquerade(xferchan, transferee);
|
||||||
|
ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
|
||||||
|
xferchan->_state = AST_STATE_UP;
|
||||||
|
xferchan->flags = 0;
|
||||||
|
xferchan->_softhangup = 0;
|
||||||
|
|
||||||
|
if((f = ast_read(xferchan))) {
|
||||||
|
ast_frfree(f);
|
||||||
|
f = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ast_hangup(newchan);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
newchan->_state = AST_STATE_UP;
|
||||||
|
newchan->flags = 0;
|
||||||
|
newchan->_softhangup = 0;
|
||||||
|
|
||||||
|
tobj = malloc(sizeof(struct ast_bridge_thread_obj));
|
||||||
|
if (tobj) {
|
||||||
|
memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
|
||||||
|
tobj->chan = xferchan;
|
||||||
|
tobj->peer = newchan;
|
||||||
|
tobj->bconfig = *config;
|
||||||
|
|
||||||
|
if (!ast_streamfile(newchan, "beep", newchan->language)) {
|
||||||
|
if (ast_waitstream(newchan, "") < 0) {
|
||||||
|
ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast_bridge_call_thread_launch(tobj);
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_WARNING, "Out of memory!\n");
|
||||||
|
ast_hangup(xferchan);
|
||||||
|
ast_hangup(newchan);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_WARNING, "Unable to create channel Local/%s do you have chan_local?\n",dialstr);
|
||||||
|
ast_moh_stop(transferee);
|
||||||
|
ast_autoservice_stop(transferee);
|
||||||
|
res = ast_streamfile(transferer, "beeperr", transferer->language);
|
||||||
|
if (!res && (ast_waitstream(transferer, "") < 0)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
|
||||||
|
ast_moh_stop(transferee);
|
||||||
|
ast_autoservice_stop(transferee);
|
||||||
|
res = ast_streamfile(transferer, "beeperr", transferer->language);
|
||||||
|
if (!res && (ast_waitstream(transferer, "") < 0)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ast_log(LOG_WARNING, "Did not read data.\n");
|
||||||
|
res = ast_streamfile(transferer, "beeperr", transferer->language);
|
||||||
|
if (ast_waitstream(transferer, "") < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast_moh_stop(transferee);
|
||||||
|
ast_autoservice_stop(transferee);
|
||||||
|
|
||||||
|
|
||||||
|
return FEATURE_RETURN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
struct ast_call_feature {
|
struct ast_call_feature {
|
||||||
int feature_mask;
|
int feature_mask;
|
||||||
char *fname;
|
char *fname;
|
||||||
@@ -457,10 +697,13 @@ struct ast_call_feature {
|
|||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* add atxfer and automon as undefined so you can only use em if you configure them */
|
||||||
#define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
|
#define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
|
||||||
struct ast_call_feature builtin_features[] =
|
struct ast_call_feature builtin_features[] =
|
||||||
{
|
{
|
||||||
{ AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
|
{ AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
|
||||||
|
{ AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
|
||||||
|
{ AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
|
||||||
{ AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
|
{ AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
%beep.gsm%(this is a simple beep tone)
|
%beep.gsm%(this is a simple beep tone)
|
||||||
|
|
||||||
|
%beeperr.gsm%(this is an error beep tone)
|
||||||
|
|
||||||
%conf-getconfno.gsm%Please enter your conference number followed by the pound key.
|
%conf-getconfno.gsm%Please enter your conference number followed by the pound key.
|
||||||
|
|
||||||
%conf-getchannel.gsm%Please enter your channel number followed by the pound key.
|
%conf-getchannel.gsm%Please enter your channel number followed by the pound key.
|
||||||
|
Reference in New Issue
Block a user