static int changrab_exec(struct cw_channel *chan, int argc, char **argv) { int res=0; struct localuser *u; struct cw_channel *newchan; struct cw_channel *oldchan; struct cw_frame *f; struct cw_bridge_config config; if (argc < 1 || argc > 2) { cw_log(LOG_ERROR, "Syntax: %s\n", changrab_syntax); return -1; } if ((oldchan = my_cw_get_channel_by_name_locked(argv[0]))) { cw_mutex_unlock(&oldchan->lock); } else { cw_log(LOG_WARNING, "No Such Channel: %s\n", argv[0]); return -1; } if (argc > 1) { if (oldchan->_bridge && strchr(argv[1], 'b')) oldchan = oldchan->_bridge; if (strchr(argv[1],'r') && oldchan->_state == CW_STATE_UP) return -1; } LOCAL_USER_ADD(u); newchan = cw_channel_alloc(0); snprintf(newchan->name, sizeof (newchan->name), "ChanGrab/%s",oldchan->name); newchan->readformat = oldchan->readformat; newchan->writeformat = oldchan->writeformat; cw_channel_masquerade(newchan, oldchan); if((f = cw_read(newchan))) { cw_fr_free(f); memset(&config,0,sizeof(struct cw_bridge_config)); cw_set_flag(&(config.features_callee), CW_FEATURE_REDIRECT); cw_set_flag(&(config.features_caller), CW_FEATURE_REDIRECT); if(newchan->_state != CW_STATE_UP) { cw_answer(newchan); } chan->appl = "Bridged Call"; res = cw_bridge_call(chan, newchan, &config); cw_hangup(newchan); } LOCAL_USER_REMOVE(u); return res ? 0 : -1; }
static void *cw_bridge_call_thread(void *data) { struct cw_bridge_thread_obj *tobj = data; tobj->chan->appl = "Redirected Call"; tobj->peer->appl = "Redirected Call"; if (tobj->chan->cdr) { cw_cdr_reset(tobj->chan->cdr,0); cw_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); } if (tobj->peer->cdr) { cw_cdr_reset(tobj->peer->cdr,0); cw_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); } cw_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); cw_hangup(tobj->chan); cw_hangup(tobj->peer); tobj->chan = tobj->peer = NULL; free(tobj); tobj=NULL; return NULL; }
static int changrab_cli(int fd, int argc, char *argv[]) { char *chan_name_1, *chan_name_2 = NULL, *context,*exten,*flags=NULL; char *pria = NULL; struct cw_channel *xferchan_1, *xferchan_2; int pri=0,x=1; if(argc < 3) { cw_cli(fd,CGUSAGE); return -1; } chan_name_1 = argv[x++]; if(chan_name_1[0] == '-') { flags = cw_strdupa(chan_name_1); if (strchr(flags,'h')) { chan_name_1 = argv[x++]; if((xferchan_1 = my_cw_get_channel_by_name_locked(chan_name_1))) { cw_mutex_unlock(&xferchan_1->lock); cw_hangup(xferchan_1); cw_verbose("OK, good luck!\n"); return 0; } else return -1; } else if (strchr(flags,'m') || strchr(flags,'M')) { chan_name_1 = argv[x++]; if((xferchan_1 = my_cw_get_channel_by_name_locked(chan_name_1))) { cw_mutex_unlock(&xferchan_1->lock); strchr(flags,'m') ? cw_moh_start(xferchan_1,NULL) : cw_moh_stop(xferchan_1); } else return 1; return 0; } if(argc < 4) { cw_cli(fd,CGUSAGE); return -1; } chan_name_1 = argv[x++]; } exten = cw_strdupa(argv[x++]); if((context = strchr(exten,'@'))) { *context = 0; context++; if(!(context && exten)) { cw_cli(fd,CGUSAGE); return -1; } if((pria = strchr(context,':'))) { *pria = '\0'; pria++; pri = atoi(pria); } else { pri = argv[x] ? atoi(argv[x++]) : 1; } if(!pri) pri = 1; } else if (strchr(exten,'/')) { chan_name_2 = exten; } xferchan_1 = my_cw_get_channel_by_name_locked(chan_name_1); if(!xferchan_1) { cw_log(LOG_WARNING, "No Such Channel: %s\n",chan_name_1); return -1; } cw_mutex_unlock(&xferchan_1->lock); if(flags && strchr(flags,'b')) { if(cw_bridged_channel(xferchan_1)) { xferchan_1 = cw_bridged_channel(xferchan_1); } } if(chan_name_2) { struct cw_frame *f; struct cw_channel *newchan_1, *newchan_2; if (!(newchan_1 = cw_channel_alloc(0))) { cw_log(LOG_WARNING, "Memory Error!\n"); cw_hangup(newchan_1); return -1; } else { snprintf(newchan_1->name, sizeof (newchan_1->name), "ChanGrab/%s", xferchan_1->name); newchan_1->readformat = xferchan_1->readformat; newchan_1->writeformat = xferchan_1->writeformat; cw_channel_masquerade(newchan_1, xferchan_1); if ((f = cw_read(newchan_1))) { cw_fr_free(f); } else { cw_hangup(newchan_1); return -1; } } if(!(xferchan_2 = my_cw_get_channel_by_name_locked(chan_name_2))) { cw_log(LOG_WARNING, "No Such Channel: %s\n",chan_name_2); cw_hangup(newchan_1); return -1; } cw_mutex_unlock(&xferchan_2->lock); if(flags && strchr(flags, 'B')) { if(cw_bridged_channel(xferchan_2)) { xferchan_2 = cw_bridged_channel(xferchan_2); } } if(!(newchan_2 = cw_channel_alloc(0))) { cw_log(LOG_WARNING, "Memory Error!\n"); cw_hangup(newchan_1); return -1; } else { snprintf(newchan_2->name, sizeof (newchan_2->name), "ChanGrab/%s", xferchan_2->name); newchan_2->readformat = xferchan_2->readformat; newchan_2->writeformat = xferchan_2->writeformat; cw_channel_masquerade(newchan_2, xferchan_2); if ((f = cw_read(newchan_2))) { cw_fr_free(f); } else { cw_hangup(newchan_1); cw_hangup(newchan_2); return -1; } } cw_bridge_call_thread_launch(newchan_1, newchan_2); } else { cw_verbose("Transferring_to context %s, extension %s, priority %d\n", context, exten, pri); cw_async_goto(xferchan_1, context, exten, pri); if(xferchan_1) cw_mutex_unlock(&xferchan_1->lock); } return 0; }
void * sccp_pbx_startchannel(void *data) { struct cw_channel * chan = data; sccp_channel_t * c; sccp_line_t * l; sccp_device_t * d; uint8_t res_exten = 0, res_wait = 0, res_timeout = 0; c = CS_CW_CHANNEL_PVT(chan); if ( !c || !(l = c->line) || !(d = c->device) ) { cw_hangup(chan); return NULL; } sccp_log(1)( VERBOSE_PREFIX_3 "%s: New call on line %s\n", d->id, l->name); cw_mutex_lock(&c->lock); c->calltype = SKINNY_CALLTYPE_OUTBOUND; c->hangupok = 0; cw_mutex_unlock(&c->lock); sccp_channel_set_callingparty(c, l->cid_name, l->cid_num); if (!cw_strlen_zero(c->dialedNumber)) { /* we have a number to dial. Let's do it */ sccp_log(10)( VERBOSE_PREFIX_3 "%s: Dialing %s on channel %s-%d\n", l->device->id, c->dialedNumber, l->name, c->callid); sccp_channel_set_calledparty(c, c->dialedNumber, c->dialedNumber); sccp_indicate_lock(c, SCCP_CHANNELSTATE_DIALING); goto dial; } /* we have to collect the number */ /* the phone is on TsOffHook state */ sccp_log(10)( VERBOSE_PREFIX_3 "%s: Waiting for the number to dial on channel %s-%d\n", l->device->id, l->name, c->callid); /* let's use the keypad to collect digits */ cw_mutex_lock(&c->lock); c->digittimeout = time(0)+GLOB(firstdigittimeout); cw_mutex_unlock(&c->lock); res_exten = 1; do { pthread_testcancel(); usleep(100); cw_mutex_lock(&c->lock); if (!cw_strlen_zero(c->dialedNumber)) { res_exten = (c->dialedNumber[0] == '*' || cw_matchmore_extension(chan, chan->context, c->dialedNumber, 1, l->cid_num)); } if (! (res_wait = ( c->state == SCCP_CHANNELSTATE_DOWN || chan->_state == CW_STATE_DOWN || chan->_softhangup || c->calltype == SKINNY_CALLTYPE_INBOUND)) ) { if (CS_CW_CHANNEL_PVT(chan)) { res_timeout = (time(0) < c->digittimeout); } else res_timeout = 0; } cw_mutex_unlock(&c->lock); } while ( (res_wait == 0) && res_exten && res_timeout); if (res_wait != 0) { /* CW_STATE_DOWN or softhangup */ sccp_log(10)(VERBOSE_PREFIX_3 "%s: return from the startchannel for DOWN, HANGUP or PICKUP cause\n", l->device->id); cw_mutex_lock(&c->lock); c->hangupok = 1; cw_mutex_unlock(&c->lock); return NULL; } dial: cw_mutex_lock(&c->lock); cw_copy_string(chan->exten, c->dialedNumber, sizeof(chan->exten)); cw_copy_string(d->lastNumber, c->dialedNumber, sizeof(d->lastNumber)); sccp_channel_set_calledparty(c, c->dialedNumber, c->dialedNumber); /* proceed call state is needed to display the called number. The phone will not display callinfo in offhook state */ sccp_channel_set_callstate(c, SKINNY_CALLSTATE_PROCEED); sccp_channel_send_callinfo(c); sccp_dev_clearprompt(d,c->line->instance, c->callid); sccp_dev_displayprompt(d, c->line->instance, c->callid, SKINNY_DISP_CALL_PROCEED, 0); c->hangupok = 1; cw_mutex_unlock(&c->lock); if ( !cw_strlen_zero(c->dialedNumber) && cw_exists_extension(chan, chan->context, c->dialedNumber, 1, l->cid_num) ) { /* found an extension, let's dial it */ sccp_log(10)(VERBOSE_PREFIX_3 "%s: channel %s-%d is dialing number %s\n", l->device->id, l->name, c->callid, c->dialedNumber); /* Answer dialplan command works only when in RINGING OR RING cw_state */ sccp_cw_setstate(c, CW_STATE_RING); if (cw_pbx_run(chan)) { sccp_indicate_lock(c, SCCP_CHANNELSTATE_INVALIDNUMBER); } } else { /* timeout and no extension match */ sccp_indicate_lock(c, SCCP_CHANNELSTATE_INVALIDNUMBER); } sccp_log(10)(VERBOSE_PREFIX_3 "%s: return from the startchannel on exit\n", l->device->id); return NULL; }