summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorMark Spencer <markster@digium.com>2005-01-05 19:56:47 +0000
committerMark Spencer <markster@digium.com>2005-01-05 19:56:47 +0000
commit526622d6e017a1a66aeb2fc4e2edec2cb70a4ba9 (patch)
tree69c3623b6d48846b6aba6bcdb42dec663d2fc808 /res
parent68c634721a5785279bea8a749d956044c8341e09 (diff)
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
Diffstat (limited to 'res')
-rwxr-xr-xres/res_features.c265
1 files changed, 254 insertions, 11 deletions
diff --git a/res/res_features.c b/res/res_features.c
index b725564c7..f1e58b5ec 100755
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -133,6 +133,54 @@ char *ast_pickup_ext(void)
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)
{
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_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)
{
if (option_verbose > 3)
@@ -369,18 +441,8 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
ptr++;
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) {
ast_moh_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;
}
+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 {
int feature_mask;
char *fname;
@@ -457,10 +697,13 @@ struct ast_call_feature {
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]))
struct ast_call_feature builtin_features[] =
{
{ 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 },
};