diff options
author | Matthew Jordan <mjordan@digium.com> | 2013-07-25 14:34:09 +0000 |
---|---|---|
committer | Matthew Jordan <mjordan@digium.com> | 2013-07-25 14:34:09 +0000 |
commit | fbcc3addf87ebaa64d66482faa98903112804842 (patch) | |
tree | 9f2c235e16912a66e86c35cced11a438ff2c4216 /main/features.c | |
parent | 56a90d435c328bd1500646559c8fe5d047722496 (diff) |
Remove dead bridging code from features
This removes the previously #if 0'd code. The functionality removed has either
been subsumed by the Bridging API or is no longer applicable.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@395400 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/features.c')
-rw-r--r-- | main/features.c | 1383 |
1 files changed, 0 insertions, 1383 deletions
diff --git a/main/features.c b/main/features.c index 346e4afd4..49f771838 100644 --- a/main/features.c +++ b/main/features.c @@ -775,109 +775,11 @@ static void set_c_e_p(struct ast_channel *chan, const char *context, const char ast_channel_priority_set(chan, pri); } -#if 0 -static struct ast_channel *feature_request_and_dial(struct ast_channel *caller, - const char *caller_name, struct ast_channel *requestor, - struct ast_channel *transferee, const char *type, struct ast_format_cap *cap, const char *addr, - int timeout, int *outstate, const char *language); -#endif - static const struct ast_datastore_info channel_app_data_datastore = { .type = "Channel appdata datastore", .destroy = ast_free_ptr, }; -#if 0 -static int set_chan_app_data(struct ast_channel *chan, const char *src_app_data) -{ - struct ast_datastore *datastore; - char *dst_app_data; - - datastore = ast_datastore_alloc(&channel_app_data_datastore, NULL); - if (!datastore) { - return -1; - } - - dst_app_data = ast_malloc(strlen(src_app_data) + 1); - if (!dst_app_data) { - ast_datastore_free(datastore); - return -1; - } - - ast_channel_data_set(chan, strcpy(dst_app_data, src_app_data)); - datastore->data = dst_app_data; - ast_channel_datastore_add(chan, datastore); - return 0; -} -#endif - -#if 0 -/*! - * \brief bridge the call - * \param data thread bridge. - * - * Set Last Data for respective channels, reset cdr for channels - * bridge call, check if we're going back to dialplan - * if not hangup both legs of the call - */ -static void *bridge_call_thread(void *data) -{ - struct ast_bridge_thread_obj *tobj = data; - - if (tobj->callid) { - ast_callid_threadassoc_add(tobj->callid); - /* Need to deref and set to null since ast_bridge_thread_obj has no common destructor */ - tobj->callid = ast_callid_unref(tobj->callid); - } - - ast_channel_appl_set(tobj->chan, !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"); - if (set_chan_app_data(tobj->chan, ast_channel_name(tobj->peer))) { - ast_channel_data_set(tobj->chan, "(Empty)"); - } - ast_channel_appl_set(tobj->peer, !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge"); - if (set_chan_app_data(tobj->peer, ast_channel_name(tobj->chan))) { - ast_channel_data_set(tobj->peer, "(Empty)"); - } - - if (tobj->return_to_pbx) { - ast_bridge_set_after_goto(tobj->chan, ast_channel_context(tobj->chan), - ast_channel_exten(tobj->chan), ast_channel_priority(tobj->chan)); - ast_bridge_set_after_goto(tobj->peer, ast_channel_context(tobj->peer), - ast_channel_exten(tobj->peer), ast_channel_priority(tobj->peer)); - } - - ast_bridge_call(tobj->chan, tobj->peer, &tobj->bconfig); - - ast_bridge_run_after_goto(tobj->chan); - - ast_free(tobj); - - return NULL; -} -#endif - -#if 0 -/*! - * \brief create thread for the bridging call - * \param tobj - */ -static void bridge_call_thread_launch(struct ast_bridge_thread_obj *tobj) -{ - pthread_t thread; - - /* This needs to be unreffed once it has been associated with the new thread. */ - tobj->callid = ast_read_threadstorage_callid(); - - if (ast_pthread_create_detached(&thread, NULL, bridge_call_thread, tobj)) { - ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n"); - ast_callid_unref(tobj->callid); - ast_hangup(tobj->chan); - ast_hangup(tobj->peer); - ast_free(tobj); - } -} -#endif - /*! * \brief Announce call parking by ADSI * \param chan . @@ -1707,156 +1609,6 @@ int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int return masq_park_call(rchan, peer, &args); } -#if 0 -static int finishup(struct ast_channel *chan) -{ - ast_indicate(chan, AST_CONTROL_UNHOLD); - - return ast_autoservice_stop(chan); -} -#endif - -#if 0 -/*! - * \internal - * \brief Builtin transfer park call helper. - * - * \param park_me Channel to be parked. - * \param parker Channel parking the call. - * \param park_exten Parking lot dialplan access ramp extension. - * - * \note Assumes park_me is on hold and in autoservice. - * - * \retval -1 on successful park. - * \retval -1 on park_me hangup. - * \retval AST_FEATURE_RETURN_SUCCESS on error to keep the bridge connected. - */ -static int xfer_park_call_helper(struct ast_channel *park_me, struct ast_channel *parker, struct ast_exten *park_exten) -{ - char *parse; - const char *app_data; - const char *pl_name; - struct ast_park_call_args args = { 0, }; - struct park_app_args app_args; - int res; - - app_data = ast_get_extension_app_data(park_exten); - if (!app_data) { - app_data = ""; - } - parse = ast_strdupa(app_data); - AST_STANDARD_APP_ARGS(app_args, parse); - - /* Find the parking lot */ - if (!ast_strlen_zero(app_args.pl_name)) { - pl_name = app_args.pl_name; - } else { - pl_name = findparkinglotname(parker); - } - if (ast_strlen_zero(pl_name)) { - /* Parking lot is not specified, so use the default parking lot. */ - args.parkinglot = parkinglot_addref(default_parkinglot); - } else { - args.parkinglot = find_parkinglot(pl_name); - if (!args.parkinglot && parkeddynamic) { - args.parkinglot = create_dynamic_parkinglot(pl_name, park_me); - } - } - - if (args.parkinglot) { - /* Park the call */ - res = finishup(park_me); - if (res) { - /* park_me hungup on us. */ - parkinglot_unref(args.parkinglot); - return -1; - } - res = masq_park_call(park_me, parker, &args); - parkinglot_unref(args.parkinglot); - } else { - /* Parking failed because parking lot does not exist. */ - if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) { - ast_stream_and_wait(parker, "pbx-parkingfailed", ""); - } - finishup(park_me); - res = -1; - } - - return res ? AST_FEATURE_RETURN_SUCCESS : -1; -} -#endif - -#if 0 -/*! - * \brief set caller and callee according to the direction - * \param caller, callee, peer, chan, sense - * - * Detect who triggered feature and set callee/caller variables accordingly - */ -static void set_peers(struct ast_channel **caller, struct ast_channel **callee, - struct ast_channel *peer, struct ast_channel *chan, int sense) -{ - if (sense == FEATURE_SENSE_PEER) { - *caller = peer; - *callee = chan; - } else { - *callee = peer; - *caller = chan; - } -} -#endif - -#if 0 -/*! - * \brief support routing for one touch call parking - * \param chan channel parking call - * \param peer channel to be parked - * \param config unsed - * \param code unused - * \param sense feature options - * \param data unused - * - * \retval -1 on successful park. - * \retval -1 on chan hangup. - * \retval AST_FEATURE_RETURN_SUCCESS on error to keep the bridge connected. - */ -static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) -{ - struct ast_channel *parker; - struct ast_channel *parkee; - struct ast_park_call_args args = { 0, }; - - /* - * We used to set chan's exten and priority to "s" and 1 here, - * but this generates (in some cases) an invalid extension, and - * if "s" exists, could errantly cause execution of extensions - * you don't expect. It makes more sense to let nature take its - * course when chan finishes, and let the pbx do its thing and - * hang up when the park is over. - */ - - /* Answer if call is not up */ - if (ast_channel_state(chan) != AST_STATE_UP) { - /* - * XXX Why are we doing this? Both of the channels should be up - * since you cannot do DTMF features unless you are bridged. - */ - if (ast_answer(chan)) { - return -1; - } - - /* Sleep to allow VoIP streams to settle down */ - if (ast_safe_sleep(chan, 1000)) { - return -1; - } - } - - /* one direction used to call park_call.... */ - set_peers(&parker, &parkee, peer, chan, sense); - return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1; -} -#endif - /*! * \internal * \brief Play file to specified channel. @@ -1888,800 +1640,6 @@ static int play_message_on_chan(struct ast_channel *play_to, struct ast_channel return 0; } -#if 0 -/*! - * \internal - * \brief Play file to specified channels. - * - * \param left Channel on left to play file. - * \param right Channel on right to play file. - * \param which Play file on indicated channels: which < 0 play left, which == 0 play both, which > 0 play right - * \param msg Descriptive name of message type being played. - * \param audiofile Audio file to play to channels. - * - * \note Plays file to the indicated channels in turn so please - * don't use this for very long messages. - * - * \retval 0 on success. - * \retval -1 on error. (Couldn't play file, channel hung up,...) - */ -static int play_message_to_chans(struct ast_channel *left, struct ast_channel *right, int which, const char *msg, const char *audiofile) -{ - /* First play the file to the left channel if requested. */ - if (which <= 0 && play_message_on_chan(left, right, msg, audiofile)) { - return -1; - } - - /* Then play the file to the right channel if requested. */ - if (which >= 0 && play_message_on_chan(right, left, msg, audiofile)) { - return -1; - } - - return 0; -} -#endif - -#if 0 -/*! - * \brief Play message to both caller and callee in bridged call, plays synchronously, autoservicing the - * other channel during the message, so please don't use this for very long messages - */ -static int play_message_in_bridged_call(struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile) -{ - return play_message_to_chans(caller_chan, callee_chan, 0, "automon message", - audiofile); -} -#endif - -#if 0 -/*! - * \brief Monitor a channel by DTMF - * \param chan channel requesting monitor - * \param peer channel to be monitored - * \param config - * \param code - * \param sense feature options - * - * \param data - * Check monitor app enabled, setup channels, both caller/callee chans not null - * get TOUCH_MONITOR variable for filename if exists, exec monitor app. - * \retval AST_FEATURE_RETURN_SUCCESS on success. - * \retval -1 on error. - */ -static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) -{ - char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; - int x = 0; - size_t len; - struct ast_channel *caller_chan, *callee_chan; - const char *automon_message_start = NULL; - const char *automon_message_stop = NULL; - const char *touch_format = NULL; - const char *touch_monitor = NULL; - const char *touch_monitor_prefix = NULL; - struct ast_app *monitor_app; - - monitor_app = pbx_findapp("Monitor"); - if (!monitor_app) { - ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); - return -1; - } - - set_peers(&caller_chan, &callee_chan, peer, chan, sense); - - /* Find extra messages */ - automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START"); - automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP"); - - if (!ast_strlen_zero(courtesytone)) { /* Play courtesy tone if configured */ - if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) { - return -1; - } - } - - if (ast_channel_monitor(callee_chan)) { - ast_verb(4, "User hit '%s' to stop recording call.\n", code); - if (!ast_strlen_zero(automon_message_stop)) { - play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop); - } - ast_channel_monitor(callee_chan)->stop(callee_chan, 1); - return AST_FEATURE_RETURN_SUCCESS; - } - - touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); - touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); - touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX"); - - if (!touch_format) - touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); - - if (!touch_monitor) - touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); - - if (!touch_monitor_prefix) - touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX"); - - if (touch_monitor) { - len = strlen(touch_monitor) + 50; - args = ast_alloca(len); - touch_filename = ast_alloca(len); - snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor); - snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); - } else { - caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(caller_chan)->id.number.valid, - ast_channel_caller(caller_chan)->id.number.str, ast_channel_name(caller_chan))); - callee_chan_id = ast_strdupa(S_COR(ast_channel_caller(callee_chan)->id.number.valid, - ast_channel_caller(callee_chan)->id.number.str, ast_channel_name(callee_chan))); - len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; - args = ast_alloca(len); - touch_filename = ast_alloca(len); - snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id); - snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename); - } - - for(x = 0; x < strlen(args); x++) { - if (args[x] == '/') - args[x] = '-'; - } - - ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args); - - pbx_exec(callee_chan, monitor_app, args); - pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); - pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); - - if (!ast_strlen_zero(automon_message_start)) { /* Play start message for both channels */ - play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start); - } - - return AST_FEATURE_RETURN_SUCCESS; -} -#endif - -#if 0 -static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) -{ - char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL; - int x = 0; - size_t len; - struct ast_channel *caller_chan, *callee_chan; - const char *mixmonitor_spy_type = "MixMonitor"; - const char *touch_format; - const char *touch_monitor; - struct ast_app *mixmonitor_app; - int count = 0; - - mixmonitor_app = pbx_findapp("MixMonitor"); - if (!mixmonitor_app) { - ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n"); - return -1; - } - - set_peers(&caller_chan, &callee_chan, peer, chan, sense); - - if (!ast_strlen_zero(courtesytone)) { - if (ast_autoservice_start(callee_chan)) - return -1; - ast_autoservice_ignore(callee_chan, AST_FRAME_DTMF_END); - if (ast_stream_and_wait(caller_chan, courtesytone, "")) { - ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); - ast_autoservice_stop(callee_chan); - return -1; - } - if (ast_autoservice_stop(callee_chan)) - return -1; - } - - ast_channel_lock(callee_chan); - count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); - ast_channel_unlock(callee_chan); - - /* This means a mixmonitor is attached to the channel, running or not is unknown. */ - if (count > 0) { - ast_verb(3, "User hit '%s' to stop recording call.\n", code); - - /* Make sure they are running */ - ast_channel_lock(callee_chan); - count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY); - ast_channel_unlock(callee_chan); - if (count > 0) { - struct ast_app *stopmixmonitor_app; - - stopmixmonitor_app = pbx_findapp("StopMixMonitor"); - if (!stopmixmonitor_app) { - ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n"); - return -1; - } - pbx_exec(callee_chan, stopmixmonitor_app, ""); - return AST_FEATURE_RETURN_SUCCESS; - } - - ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); - } - - touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT"); - touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR"); - - if (!touch_format) - touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT"); - - if (!touch_monitor) - touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR"); - - if (touch_monitor) { - len = strlen(touch_monitor) + 50; - args = ast_alloca(len); - touch_filename = ast_alloca(len); - snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor); - snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav"); - } else { - caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(caller_chan)->id.number.valid, - ast_channel_caller(caller_chan)->id.number.str, ast_channel_name(caller_chan))); - callee_chan_id = ast_strdupa(S_COR(ast_channel_caller(callee_chan)->id.number.valid, - ast_channel_caller(callee_chan)->id.number.str, ast_channel_name(callee_chan))); - len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; - args = ast_alloca(len); - touch_filename = ast_alloca(len); - snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id); - snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav")); - } - - for( x = 0; x < strlen(args); x++) { - if (args[x] == '/') - args[x] = '-'; - } - - ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename); - - pbx_exec(callee_chan, mixmonitor_app, args); - pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); - pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); - return AST_FEATURE_RETURN_SUCCESS; -} -#endif - -#if 0 -static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) -{ - ast_verb(4, "User hit '%s' to disconnect call.\n", code); - return AST_FEATURE_RETURN_HANGUP; -} -#endif - -#if 0 -/*! - * \brief Find the context for the transfer - * \param transferer - * \param transferee - * - * Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext. - * \return a context string - */ -static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee) -{ - const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"); - if (ast_strlen_zero(s)) { - s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT"); - } - if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */ - s = ast_channel_macrocontext(transferer); - } - if (ast_strlen_zero(s)) { - s = ast_channel_context(transferer); - } - return s; -} -#endif - -#if 0 -/*! - * \brief make channels compatible - * \param c - * \param newchan - * \retval 0 on success. - * \retval -1 on failure. - */ -static int check_compat(struct ast_channel *c, struct ast_channel *newchan) -{ - if (ast_channel_make_compatible(c, newchan) < 0) { - ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", - ast_channel_name(c), ast_channel_name(newchan)); - ast_autoservice_chan_hangup_peer(c, newchan); - return -1; - } - return 0; -} -#endif - -#if 0 -/*! - * \internal - * \brief Builtin attended transfer failed cleanup. - * \since 10.0 - * - * \param transferee Party A in the transfer. - * \param transferer Party B in the transfer. - * \param connected_line Saved connected line info about party A. - * - * \note The connected_line data is freed. - * - * \return Nothing - */ -static void atxfer_fail_cleanup(struct ast_channel *transferee, struct ast_channel *transferer, struct ast_party_connected_line *connected_line) -{ - finishup(transferee); - - /* - * Restore party B connected line info about party A. - * - * Party B was the caller to party C and is the last known mode - * for party B. - */ - if (ast_channel_connected_line_sub(transferee, transferer, connected_line, 0) && - ast_channel_connected_line_macro(transferee, transferer, connected_line, 1, 0)) { - ast_channel_update_connected_line(transferer, connected_line, NULL); - } - ast_party_connected_line_free(connected_line); -} -#endif - -#if 0 -/*! - * \brief Attended transfer - * \param chan transfered user - * \param peer person transfering call - * \param config - * \param code - * \param sense feature options - * - * \param data - * Get extension to transfer to, if you cannot generate channel (or find extension) - * return to host channel. After called channel answered wait for hangup of transferer, - * bridge call between transfer peer (taking them off hold) to attended transfer channel. - * - * \return -1 on failure - */ -static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data) -{ - struct ast_channel *transferer;/* Party B */ - struct ast_channel *transferee;/* Party A */ - struct ast_exten *park_exten; - const char *chan1_attended_sound; - const char *chan2_attended_sound; - const char *transferer_real_context; - char xferto[256] = ""; - int res; - int outstate=0; - struct ast_channel *newchan; - struct ast_channel *xferchan; - struct ast_bridge_thread_obj *tobj; - struct ast_bridge_config bconfig; - int l; - struct ast_party_connected_line connected_line; - struct ast_datastore *features_datastore; - struct ast_dial_features *dialfeatures; - char *transferer_tech; - char *transferer_name; - char *transferer_name_orig; - char *dash; - RAII_VAR(struct ast_features_xfer_config *, xfer_cfg, NULL, ao2_cleanup); - - ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", ast_channel_name(chan), ast_channel_name(peer), sense); - set_peers(&transferer, &transferee, peer, chan, sense); - transferer_real_context = real_ctx(transferer, transferee); - - /* Start autoservice on transferee while we talk to the transferer */ - ast_autoservice_start(transferee); - ast_indicate(transferee, AST_CONTROL_HOLD); - - /* Transfer */ - res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY); - if (res < 0) { - finishup(transferee); - return -1; - } - if (res > 0) { /* If they've typed a digit already, handle it */ - xferto[0] = (char) res; - } - - ast_channel_lock(transferer); - xfer_cfg = ast_get_chan_features_xfer_config(transferer); - ast_channel_unlock(transferer); - - /* XXX All accesses to the xfer_cfg structure after this point are not thread-safe, - * but I don't care because this is dead code. - */ - - /* this is specific of atxfer */ - res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, xfer_cfg->transferdigittimeout); - if (res < 0) { /* hangup or error, (would be 0 for invalid and 1 for valid) */ - finishup(transferee); - return -1; - } - l = strlen(xferto); - if (res == 0) { - if (l) { - ast_log(LOG_WARNING, "Extension '%s' does not exist in context '%s'\n", - xferto, transferer_real_context); - } else { - /* Does anyone care about this case? */ - ast_log(LOG_WARNING, "No digits dialed for atxfer.\n"); - } - ast_stream_and_wait(transferer, "pbx-invalid", ""); - finishup(transferee); - return AST_FEATURE_RETURN_SUCCESS; - } - - park_exten = get_parking_exten(xferto, transferer, transferer_real_context); - if (park_exten) { - /* We are transfering the transferee to a parking lot. */ - return xfer_park_call_helper(transferee, transferer, park_exten); - } - - /* - * Append context to dialed transfer number. - * - * NOTE: The local channel needs the /n flag so party C will use - * the feature flags set by the dialplan when calling that - * party. - */ - snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); - - /* If we are performing an attended transfer and we have two channels involved then - copy sound file information to play upon attended transfer completion */ - chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND"); - chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND"); - if (!ast_strlen_zero(chan1_attended_sound)) { - pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound); - } - if (!ast_strlen_zero(chan2_attended_sound)) { - pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound); - } - - /* Extract redial transferer information from the channel name. */ - transferer_name_orig = ast_strdupa(ast_channel_name(transferer)); - transferer_name = ast_strdupa(transferer_name_orig); - transferer_tech = strsep(&transferer_name, "/"); - dash = strrchr(transferer_name, '-'); - if (dash) { - /* Trim off channel name sequence/serial number. */ - *dash = '\0'; - } - - /* Stop autoservice so we can monitor all parties involved in the transfer. */ - if (ast_autoservice_stop(transferee) < 0) { - ast_indicate(transferee, AST_CONTROL_UNHOLD); - return -1; - } - - /* Save connected line info for party B about party A in case transfer fails. */ - ast_party_connected_line_init(&connected_line); - ast_channel_lock(transferer); - ast_party_connected_line_copy(&connected_line, ast_channel_connected(transferer)); - ast_channel_unlock(transferer); - connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - - /* Dial party C */ - newchan = feature_request_and_dial(transferer, transferer_name_orig, transferer, - transferee, "Local", ast_channel_nativeformats(transferer), xferto, - xfer_cfg->atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); - ast_debug(2, "Dial party C result: newchan:%d, outstate:%d\n", !!newchan, outstate); - - if (!ast_check_hangup(transferer)) { - /* Transferer (party B) is up */ - ast_debug(1, "Actually doing an attended transfer.\n"); - - /* Start autoservice on transferee while the transferer deals with party C. */ - ast_autoservice_start(transferee); - - ast_indicate(transferer, -1); - if (!newchan) { - /* any reason besides user requested cancel and busy triggers the failed sound */ - switch (outstate) { - case AST_CONTROL_UNHOLD:/* Caller requested cancel or party C answer timeout. */ - case AST_CONTROL_BUSY: - case AST_CONTROL_CONGESTION: - if (ast_stream_and_wait(transferer, xfer_cfg->xfersound, "")) { - ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); - } - break; - default: - if (ast_stream_and_wait(transferer, xfer_cfg->xferfailsound, "")) { - ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); - } - break; - } - atxfer_fail_cleanup(transferee, transferer, &connected_line); - return AST_FEATURE_RETURN_SUCCESS; - } - - if (check_compat(transferer, newchan)) { - if (ast_stream_and_wait(transferer, xfer_cfg->xferfailsound, "")) { - ast_log(LOG_WARNING, "Failed to play transfer failed sound!\n"); - } - atxfer_fail_cleanup(transferee, transferer, &connected_line); - return AST_FEATURE_RETURN_SUCCESS; - } - memset(&bconfig,0,sizeof(struct ast_bridge_config)); - ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); - ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); - - /* - * Let party B and C talk as long as they want while party A - * languishes in autoservice listening to MOH. - */ - ast_bridge_call(transferer, newchan, &bconfig); - - if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) { - ast_autoservice_chan_hangup_peer(transferer, newchan); - if (ast_stream_and_wait(transferer, xfer_cfg->xfersound, "")) { - ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); - } - atxfer_fail_cleanup(transferee, transferer, &connected_line); - return AST_FEATURE_RETURN_SUCCESS; - } - - /* Transferer (party B) is confirmed hung up at this point. */ - if (check_compat(transferee, newchan)) { - finishup(transferee); - ast_party_connected_line_free(&connected_line); - return -1; - } - - ast_indicate(transferee, AST_CONTROL_UNHOLD); - 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); - ast_party_connected_line_free(&connected_line); - return -1; - } - } else if (!ast_check_hangup(transferee)) { - /* Transferer (party B) has hung up at this point. Doing blonde transfer. */ - ast_debug(1, "Actually doing a blonde transfer.\n"); - - if (!newchan && !xfer_cfg->atxferdropcall) { - /* Party C is not available, try to call party B back. */ - unsigned int tries = 0; - - if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) { - ast_log(LOG_WARNING, - "Transferer channel name: '%s' cannot be used for callback.\n", - transferer_name_orig); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - ast_party_connected_line_free(&connected_line); - return -1; - } - - tries = 0; - for (;;) { - /* Try to get party B back. */ - ast_debug(1, "We're trying to callback %s/%s\n", - transferer_tech, transferer_name); - newchan = feature_request_and_dial(transferer, transferer_name_orig, - transferee, transferee, transferer_tech, - ast_channel_nativeformats(transferee), transferer_name, - xfer_cfg->atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); - ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n", - !!newchan, outstate); - if (newchan) { - /* - * We have recalled party B (newchan). We need to give this - * call leg the same feature flags as the original party B call - * leg. - */ - ast_channel_lock(transferer); - features_datastore = ast_channel_datastore_find(transferer, - &dial_features_info, NULL); - if (features_datastore && (dialfeatures = features_datastore->data)) { - struct ast_flags my_features = { 0 }; - struct ast_flags peer_features = { 0 }; - - ast_copy_flags(&my_features, &dialfeatures->my_features, - AST_FLAGS_ALL); - ast_copy_flags(&peer_features, &dialfeatures->peer_features, - AST_FLAGS_ALL); - ast_channel_unlock(transferer); - add_features_datastore(newchan, &my_features, &peer_features); - } else { - ast_channel_unlock(transferer); - } - break; - } - if (ast_check_hangup(transferee)) { - break; - } - - ++tries; - if (xfer_cfg->atxfercallbackretries <= tries) { - /* No more callback tries remaining. */ - break; - } - - if (xfer_cfg->atxferloopdelay) { - /* Transfer failed, sleeping */ - ast_debug(1, "Sleeping for %d ms before retrying atxfer.\n", - xfer_cfg->atxferloopdelay); - ast_safe_sleep(transferee, xfer_cfg->atxferloopdelay); - if (ast_check_hangup(transferee)) { - ast_party_connected_line_free(&connected_line); - return -1; - } - } - - /* Retry dialing party C. */ - ast_debug(1, "We're retrying to call %s/%s\n", "Local", xferto); - newchan = feature_request_and_dial(transferer, transferer_name_orig, - transferer, transferee, "Local", - ast_channel_nativeformats(transferee), xferto, - xfer_cfg->atxfernoanswertimeout, &outstate, ast_channel_language(transferer)); - ast_debug(2, "Redial party C result: newchan:%d, outstate:%d\n", - !!newchan, outstate); - if (newchan || ast_check_hangup(transferee)) { - break; - } - } - } - ast_indicate(transferee, AST_CONTROL_UNHOLD); - if (!newchan) { - /* No party C or could not callback party B. */ - ast_party_connected_line_free(&connected_line); - return -1; - } - - /* newchan is up, we should prepare transferee and bridge them */ - if (ast_check_hangup(newchan)) { - ast_autoservice_chan_hangup_peer(transferee, newchan); - ast_party_connected_line_free(&connected_line); - return -1; - } - if (check_compat(transferee, newchan)) { - ast_party_connected_line_free(&connected_line); - return -1; - } - } else { - /* - * Both the transferer and transferee have hungup. If newchan - * is up, hang it up as it has no one to talk to. - */ - ast_debug(1, "Everyone is hungup.\n"); - ast_hangup(newchan); - ast_party_connected_line_free(&connected_line); - return -1; - } - - /* Initiate the channel transfer of party A to party C (or recalled party B). */ - xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee)); - if (!xferchan) { - ast_autoservice_chan_hangup_peer(transferee, newchan); - ast_party_connected_line_free(&connected_line); - return -1; - } - - /* Give party A a momentary ringback tone during transfer. */ - ast_channel_visible_indication_set(xferchan, AST_CONTROL_RINGING); - - /* Make formats okay */ - ast_format_copy(ast_channel_readformat(xferchan), ast_channel_readformat(transferee)); - ast_format_copy(ast_channel_writeformat(xferchan), ast_channel_writeformat(transferee)); - - if (ast_channel_masquerade(xferchan, transferee)) { - ast_hangup(xferchan); - ast_autoservice_chan_hangup_peer(transferee, newchan); - ast_party_connected_line_free(&connected_line); - return -1; - } - - dash = strrchr(xferto, '@'); - if (dash) { - /* Trim off the context. */ - *dash = '\0'; - } - ast_explicit_goto(xferchan, transferer_real_context, xferto, 1); - ast_channel_state_set(xferchan, AST_STATE_UP); - ast_clear_flag(ast_channel_flags(xferchan), AST_FLAGS_ALL); - - /* Do the masquerade manually to make sure that is is completed. */ - ast_do_masquerade(xferchan); - - ast_channel_state_set(newchan, AST_STATE_UP); - ast_clear_flag(ast_channel_flags(newchan), AST_FLAGS_ALL); - tobj = ast_calloc(1, sizeof(*tobj)); - if (!tobj) { - ast_hangup(xferchan); - ast_hangup(newchan); - ast_party_connected_line_free(&connected_line); - return -1; - } - - tobj->chan = newchan; - tobj->peer = xferchan; - tobj->bconfig = *config; - - ast_channel_lock(newchan); - features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL); - if (features_datastore && (dialfeatures = features_datastore->data)) { - ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features, - AST_FLAGS_ALL); - } - ast_channel_unlock(newchan); - - ast_channel_lock(xferchan); - features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL); - if (features_datastore && (dialfeatures = features_datastore->data)) { - ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features, - AST_FLAGS_ALL); - } - ast_channel_unlock(xferchan); - - if (tobj->bconfig.end_bridge_callback_data_fixup) { - tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); - } - - /* - * xferchan is transferee, and newchan is the transfer target - * So...in a transfer, who is the caller and who is the callee? - * - * When the call is originally made, it is clear who is caller and callee. - * When a transfer occurs, it is my humble opinion that the transferee becomes - * the caller, and the transfer target is the callee. - * - * The problem is that these macros were set with the intention of the original - * caller and callee taking those roles. A transfer can totally mess things up, - * to be technical. What sucks even more is that you can't effectively change - * the macros in the dialplan during the call from the transferer to the transfer - * target because the transferee is stuck with whatever role he originally had. - * - * I think the answer here is just to make sure that it is well documented that - * during a transfer, the transferee is the "caller" and the transfer target - * is the "callee." - * - * This means that if party B calls party A, and party B transfers party A to - * party C, then A has switched roles for the call. Now party A will have the - * caller macro called on his channel instead of the callee macro. - * - * Luckily, the method by which the party B to party C bridge is - * launched above ensures that the transferee is the "chan" on - * the bridge and the transfer target is the "peer," so my idea - * for the roles post-transfer does not require extensive code - * changes. - */ - - /* Transfer party C connected line to party A */ - ast_channel_lock(transferer); - /* - * Due to a limitation regarding when callerID is set on a Local channel, - * we use the transferer's connected line information here. - */ - ast_party_connected_line_copy(&connected_line, ast_channel_connected(transferer)); - ast_channel_unlock(transferer); - connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - if (ast_channel_connected_line_sub(newchan, xferchan, &connected_line, 0) && - ast_channel_connected_line_macro(newchan, xferchan, &connected_line, 1, 0)) { - ast_channel_update_connected_line(xferchan, &connected_line, NULL); - } - - /* Transfer party A connected line to party C */ - ast_channel_lock(xferchan); - ast_connected_line_copy_from_caller(&connected_line, ast_channel_caller(xferchan)); - ast_channel_unlock(xferchan); - connected_line.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER; - if (ast_channel_connected_line_sub(xferchan, newchan, &connected_line, 0) && - ast_channel_connected_line_macro(xferchan, newchan, &connected_line, 0, 0)) { - ast_channel_update_connected_line(newchan, &connected_line, NULL); - } - - if (ast_stream_and_wait(newchan, xfer_cfg->xfersound, "")) - ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); - bridge_call_thread_launch(tobj); - - ast_party_connected_line_free(&connected_line); - return -1;/* The transferee is masqueraded and the original bridged channels can be hungup. */ -} -#endif - /*! * \internal * \brief Get the extension for a given builtin feature @@ -2729,347 +1687,6 @@ static void set_config_flags(struct ast_channel *chan, struct ast_bridge_config } } -#if 0 -/*! - * \internal - * \brief Get feature and dial. - * - * \param caller Channel to represent as the calling channel for the dialed channel. - * \param caller_name Original caller channel name. - * \param requestor Channel to say is requesting the dial (usually the caller). - * \param transferee Channel that the dialed channel will be transferred to. - * \param type Channel technology type to dial. - * \param format Codec formats for dialed channel. - * \param addr destination of the call - * \param timeout Time limit for dialed channel to answer in ms. Must be greater than zero. - * \param outstate Status of dialed channel if unsuccessful. - * \param language Language of the caller. - * - * \note - * outstate can be: - * 0, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, - * AST_CONTROL_ANSWER, or AST_CONTROL_UNHOLD. If - * AST_CONTROL_UNHOLD then the caller channel cancelled the - * transfer or the dialed channel did not answer before the - * timeout. - * - * \details - * Request channel, set channel variables, initiate call, - * check if they want to disconnect, go into loop, check if timeout has elapsed, - * check if person to be transfered hung up, check for answer break loop, - * set cdr return channel. - * - * \retval Channel Connected channel for transfer. - * \retval NULL on failure to get third party connected. - * - * \note This is similar to __ast_request_and_dial() in channel.c - */ -static struct ast_channel *feature_request_and_dial(struct ast_channel *caller, - const char *caller_name, struct ast_channel *requestor, - struct ast_channel *transferee, const char *type, struct ast_format_cap *cap, const char *addr, - int timeout, int *outstate, const char *language) -{ - int state = 0; - int cause = 0; - int to; - int caller_hungup; - int transferee_hungup; - struct ast_channel *chan; - struct ast_channel *monitor_chans[3]; - struct ast_channel *active_channel; - int res; - int ready = 0; - struct timeval started; - int x, len = 0; - char disconnect_code[AST_FEATURE_MAX_LEN]; - char *dialed_code = NULL; - struct ast_format_cap *tmp_cap; - struct ast_format best_audio_fmt; - struct ast_frame *f; - int disconnect_res; - AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames; - - tmp_cap = ast_format_cap_alloc_nolock(); - if (!tmp_cap) { - if (outstate) { - *outstate = 0; - } - return NULL; - } - ast_best_codec(cap, &best_audio_fmt); - ast_format_cap_add(tmp_cap, &best_audio_fmt); - - caller_hungup = ast_check_hangup(caller); - - if (!(chan = ast_request(type, tmp_cap, requestor, addr, &cause))) { - ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, addr); - switch (cause) { - case AST_CAUSE_BUSY: - state = AST_CONTROL_BUSY; - break; - case AST_CAUSE_CONGESTION: - state = AST_CONTROL_CONGESTION; - break; - default: - state = 0; - break; - } - goto done; - } - - ast_channel_language_set(chan, language); - ast_channel_inherit_variables(caller, chan); - pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller_name); - - ast_channel_lock(chan); - ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(requestor)); - ast_channel_unlock(chan); - - if (ast_call(chan, addr, timeout)) { - ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, addr); - switch (ast_channel_hangupcause(chan)) { - case AST_CAUSE_BUSY: - state = AST_CONTROL_BUSY; - break; - case AST_CAUSE_CONGESTION: - state = AST_CONTROL_CONGESTION; - break; - default: - state = 0; - break; - } - goto done; - } - - /* support dialing of the featuremap disconnect code while performing an attended tranfer */ - ast_channel_lock(chan); - disconnect_res = ast_get_builtin_feature(chan, "disconnect", - disconnect_code, sizeof(disconnect_code)); - ast_channel_unlock(chan); - - if (!disconnect_res) { - len = strlen(disconnect_code) + 1; - dialed_code = ast_alloca(len); - memset(dialed_code, 0, len); - } - - x = 0; - started = ast_tvnow(); - to = timeout; - AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames); - - ast_poll_channel_add(caller, chan); - - transferee_hungup = 0; - while (!ast_check_hangup(transferee) && (ast_channel_state(chan) != AST_STATE_UP)) { - int num_chans = 0; - - monitor_chans[num_chans++] = transferee; - monitor_chans[num_chans++] = chan; - if (!caller_hungup) { - if (ast_check_hangup(caller)) { - caller_hungup = 1; - -#if defined(ATXFER_NULL_TECH) - /* Change caller's name to ensure that it will remain unique. */ - set_new_chan_name(caller); - - /* - * Get rid of caller's physical technology so it is free for - * other calls. - */ - set_kill_chan_tech(caller); -#endif /* defined(ATXFER_NULL_TECH) */ - } else { - /* caller is not hungup so monitor it. */ - monitor_chans[num_chans++] = caller; - } - } - - /* see if the timeout has been violated */ - if (ast_tvdiff_ms(ast_tvnow(), started) > timeout) { - state = AST_CONTROL_UNHOLD; - ast_log(LOG_NOTICE, "We exceeded our AT-timeout for %s\n", ast_channel_name(chan)); - break; /*doh! timeout*/ - } - - active_channel = ast_waitfor_n(monitor_chans, num_chans, &to); - if (!active_channel) - continue; - - f = NULL; - if (transferee == active_channel) { - struct ast_frame *dup_f; - - f = ast_read(transferee); - if (f == NULL) { /*doh! where'd he go?*/ - transferee_hungup = 1; - state = 0; - break; - } - if (ast_is_deferrable_frame(f)) { - dup_f = ast_frisolate(f); - if (dup_f) { - if (dup_f == f) { - f = NULL; - } - AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list); - } - } - } else if (chan == active_channel) { - if (!ast_strlen_zero(ast_channel_call_forward(chan))) { - state = 0; - ast_autoservice_start(transferee); - chan = ast_call_forward(caller, chan, NULL, tmp_cap, NULL, &state); - ast_autoservice_stop(transferee); - if (!chan) { - break; - } - continue; - } - f = ast_read(chan); - if (f == NULL) { /*doh! where'd he go?*/ - switch (ast_channel_hangupcause(chan)) { - case AST_CAUSE_BUSY: - state = AST_CONTROL_BUSY; - break; - case AST_CAUSE_CONGESTION: - state = AST_CONTROL_CONGESTION; - break; - default: - state = 0; - break; - } - break; - } - - if (f->frametype == AST_FRAME_CONTROL) { - if (f->subclass.integer == AST_CONTROL_RINGING) { - ast_verb(3, "%s is ringing\n", ast_channel_name(chan)); - ast_indicate(caller, AST_CONTROL_RINGING); - } else if (f->subclass.integer == AST_CONTROL_BUSY) { - state = f->subclass.integer; - ast_verb(3, "%s is busy\n", ast_channel_name(chan)); - ast_indicate(caller, AST_CONTROL_BUSY); - ast_frfree(f); - break; - } else if (f->subclass.integer == AST_CONTROL_INCOMPLETE) { - ast_verb(3, "%s dialed incomplete extension %s; ignoring\n", ast_channel_name(chan), ast_channel_exten(chan)); - } else if (f->subclass.integer == AST_CONTROL_CONGESTION) { - state = f->subclass.integer; - ast_verb(3, "%s is congested\n", ast_channel_name(chan)); - ast_indicate(caller, AST_CONTROL_CONGESTION); - ast_frfree(f); - break; - } else if (f->subclass.integer == AST_CONTROL_ANSWER) { - /* This is what we are hoping for */ - state = f->subclass.integer; - ast_frfree(f); - ready=1; - break; - } else if (f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) { - ast_indicate_data(caller, AST_CONTROL_PVT_CAUSE_CODE, f->data.ptr, f->datalen); - } else if (f->subclass.integer == AST_CONTROL_CONNECTED_LINE) { - if (caller_hungup) { - struct ast_party_connected_line connected; - - /* Just save it for the transfer. */ - ast_party_connected_line_set_init(&connected, ast_channel_connected(caller)); - res = ast_connected_line_parse_data(f->data.ptr, f->datalen, - &connected); - if (!res) { - ast_channel_set_connected_line(caller, &connected, NULL); - } - ast_party_connected_line_free(&connected); - } else { - ast_autoservice_start(transferee); - if (ast_channel_connected_line_sub(chan, caller, f, 1) && - ast_channel_connected_line_macro(chan, caller, f, 1, 1)) { - ast_indicate_data(caller, AST_CONTROL_CONNECTED_LINE, - f->data.ptr, f->datalen); - } - ast_autoservice_stop(transferee); - } - } else if (f->subclass.integer == AST_CONTROL_REDIRECTING) { - if (!caller_hungup) { - ast_autoservice_start(transferee); - if (ast_channel_redirecting_sub(chan, caller, f, 1) && - ast_channel_redirecting_macro(chan, caller, f, 1, 1)) { - ast_indicate_data(caller, AST_CONTROL_REDIRECTING, - f->data.ptr, f->datalen); - } - ast_autoservice_stop(transferee); - } - } else if (f->subclass.integer != -1 - && f->subclass.integer != AST_CONTROL_PROGRESS - && f->subclass.integer != AST_CONTROL_PROCEEDING) { - ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass.integer); - } - /* else who cares */ - } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { - ast_write(caller, f); - } - } else if (caller == active_channel) { - f = ast_read(caller); - if (f) { - if (f->frametype == AST_FRAME_DTMF && dialed_code) { - dialed_code[x++] = f->subclass.integer; - dialed_code[x] = '\0'; - if (strlen(dialed_code) == len) { - x = 0; - } else if (x && strncmp(dialed_code, disconnect_code, x)) { - x = 0; - dialed_code[x] = '\0'; - } - if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { - /* Caller Canceled the call */ - state = AST_CONTROL_UNHOLD; - ast_frfree(f); - break; - } - } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) { - ast_write(chan, f); - } - } - } - if (f) - ast_frfree(f); - } /* end while */ - - ast_poll_channel_del(caller, chan); - - /* - * We need to free all the deferred frames, but we only need to - * queue the deferred frames if no hangup was received. - */ - ast_channel_lock(transferee); - transferee_hungup = (transferee_hungup || ast_check_hangup(transferee)); - while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) { - if (!transferee_hungup) { - ast_queue_frame_head(transferee, f); - } - ast_frfree(f); - } - ast_channel_unlock(transferee); - -done: - ast_indicate(caller, -1); - if (chan && (ready || ast_channel_state(chan) == AST_STATE_UP)) { - state = AST_CONTROL_ANSWER; - } else if (chan) { - ast_hangup(chan); - chan = NULL; - } - - tmp_cap = ast_format_cap_destroy(tmp_cap); - - if (outstate) - *outstate = state; - - return chan; -} -#endif - void ast_channel_log(char *title, struct ast_channel *chan); void ast_channel_log(char *title, struct ast_channel *chan) /* for debug, this is handy enough to justify keeping it in the source */ |