diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/app_dial.c | 107 |
1 files changed, 98 insertions, 9 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c index 8a58932a8..b1de21d5f 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -62,6 +62,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/global_datastores.h" #include "asterisk/dsp.h" #include "asterisk/cel.h" +#include "asterisk/ccss.h" #include "asterisk/indications.h" /*** DOCUMENTATION @@ -810,6 +811,12 @@ static void do_forward(struct chanlist *o, ast_channel_make_compatible(o->chan, in); ast_channel_inherit_variables(in, o->chan); ast_channel_datastore_inherit(in, o->chan); + /* When a call is forwarded, we don't want to track new interfaces + * dialed for CC purposes. Setting the done flag will ensure that + * any Dial operations that happen later won't record CC interfaces. + */ + ast_ignore_cc(o->chan); + ast_log(LOG_NOTICE, "Not accepting call completion offers from call-forward recipient %s\n", o->chan->name); } else ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause); } @@ -904,7 +911,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct chanlist *outgoing, int *to, struct ast_flags64 *peerflags, char *opt_args[], struct privacy_args *pa, - const struct cause_args *num_in, int *result, char *dtmf_progress) + const struct cause_args *num_in, int *result, char *dtmf_progress, + const int ignore_cc) { struct cause_args num = *num_in; int prestart = num.busy + num.congestion + num.nochan; @@ -917,6 +925,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, #endif struct ast_party_connected_line connected_caller; struct ast_str *featurecode = ast_str_alloca(FEATURE_MAX_LEN + 1); + int cc_recall_core_id; + int is_cc_recall; + int cc_frame_received = 0; + int num_ringing = 0; ast_party_connected_line_init(&connected_caller); if (single) { @@ -938,6 +950,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, } } + is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL); + #ifdef HAVE_EPOLL for (epollo = outgoing; epollo; epollo = epollo->next) ast_poll_channel_add(in, epollo->chan); @@ -970,6 +984,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan); } *to = 0; + if (is_cc_recall) { + ast_cc_failed(cc_recall_core_id, "Everyone is busy/congested for the recall. How sad"); + } return NULL; } winner = ast_waitfor_n(watchers, pos, to); @@ -1014,6 +1031,15 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, /* here, o->chan == c == winner */ if (!ast_strlen_zero(c->call_forward)) { pa->sentringing = 0; + if (!ignore_cc && (f = ast_read(c))) { + if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_CC) { + /* This channel is forwarding the call, and is capable of CC, so + * be sure to add the new device interface to the list + */ + ast_handle_cc_control_frame(in, c, f->data.ptr); + } + ast_frfree(f); + } do_forward(o, &num, peerflags, single, to); continue; } @@ -1088,13 +1114,41 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, handle_cause(AST_CAUSE_CONGESTION, &num); break; case AST_CONTROL_RINGING: - ast_verb(3, "%s is ringing\n", c->name); - /* Setup early media if appropriate */ - if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) - ast_channel_early_bridge(in, c); - if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK) && ast_strlen_zero(opt_args[OPT_ARG_RINGBACK])) { - ast_indicate(in, AST_CONTROL_RINGING); - pa->sentringing++; + /* This is a tricky area to get right when using a native + * CC agent. The reason is that we do the best we can to send only a + * single ringing notification to the caller. + * + * Call completion complicates the logic used here. CCNR is typically + * offered during a ringing message. Let's say that party A calls + * parties B, C, and D. B and C do not support CC requests, but D + * does. If we were to receive a ringing notification from B before + * the others, then we would end up sending a ringing message to + * A with no CCNR offer present. + * + * The approach that we have taken is that if we receive a ringing + * response from a party and no CCNR offer is present, we need to + * wait. Specifically, we need to wait until either a) a called party + * offers CCNR in its ringing response or b) all called parties have + * responded in some way to our call and none offers CCNR. + * + * The drawback to this is that if one of the parties has a delayed + * response or, god forbid, one just plain doesn't respond to our + * outgoing call, then this will result in a significant delay between + * when the caller places the call and hears ringback. + * + * Note also that if CC is disabled for this call, then it is perfectly + * fine for ringing frames to get sent through. + */ + ++num_ringing; + if (ignore_cc || cc_frame_received || num_ringing == numlines) { + ast_verb(3, "%s is ringing\n", c->name); + /* Setup early media if appropriate */ + if (single && CAN_EARLY_BRIDGE(peerflags, in, c)) + ast_channel_early_bridge(in, c); + if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK) && ast_strlen_zero(opt_args[OPT_ARG_RINGBACK])) { + ast_indicate(in, AST_CONTROL_RINGING); + pa->sentringing++; + } } break; case AST_CONTROL_PROGRESS: @@ -1163,6 +1217,12 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, case AST_CONTROL_FLASH: /* Ignore going off hook and flash */ break; + case AST_CONTROL_CC: + if (!ignore_cc) { + ast_handle_cc_control_frame(in, c, f->data.ptr); + cc_frame_received = 1; + } + break; case -1: if (!ast_test_flag64(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) { ast_verb(3, "%s stopped sounds\n", c->name); @@ -1212,6 +1272,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, } ast_frfree(f); } + if (is_cc_recall) { + ast_cc_completed(in, "CC completed, although the caller hung up (cancelled)"); + } return NULL; } @@ -1229,6 +1292,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, strcpy(pa->status, "CANCEL"); ast_frfree(f); ast_channel_unlock(in); + if (is_cc_recall) { + ast_cc_completed(in, "CC completed, but the caller used DTMF to exit"); + } return NULL; } ast_channel_unlock(in); @@ -1241,6 +1307,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, strcpy(pa->status, "CANCEL"); ast_cdr_noanswer(in->cdr); ast_frfree(f); + if (is_cc_recall) { + ast_cc_completed(in, "CC completed, but the caller hung up with DTMF"); + } return NULL; } } @@ -1283,6 +1352,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, } #endif + if (is_cc_recall) { + ast_cc_completed(in, "Recall completed!"); + } return peer; } @@ -1656,6 +1728,8 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast char *opt_args[OPT_ARG_ARRAY_SIZE]; struct ast_datastore *datastore = NULL; int fulldial = 0, num_dialed = 0; + int ignore_cc = 0; + char device_name[AST_CHANNEL_NAME]; /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */ pbx_builtin_setvar_helper(chan, "DIALSTATUS", ""); @@ -1686,6 +1760,10 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast goto done; } + if (ast_cc_call_init(chan, &ignore_cc)) { + goto done; + } + if (ast_test_flag64(&opts, OPT_SCREEN_NOINTRO) && !ast_strlen_zero(opt_args[OPT_ARG_SCREEN_NOINTRO])) { delprivintro = atoi(opt_args[OPT_ARG_SCREEN_NOINTRO]); @@ -1871,8 +1949,17 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast if (!rest) /* we are on the last destination */ chan->hangupcause = cause; chanlist_free(tmp); + if (!ignore_cc && (cause == AST_CAUSE_BUSY || cause == AST_CAUSE_CONGESTION)) { + if (!ast_cc_callback(chan, tech, numsubst, ast_cc_busy_interface)) { + ast_cc_extension_monitor_add_dialstring(chan, interface, ""); + } + } continue; } + ast_channel_get_device_name(tc, device_name, sizeof(device_name)); + if (!ignore_cc) { + ast_cc_extension_monitor_add_dialstring(chan, interface, device_name); + } pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", numsubst); ast_channel_lock(tc); @@ -1965,6 +2052,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast chan->hangupcause = tc->hangupcause; } ast_channel_unlock(chan); + ast_cc_call_failed(chan, tc, interface); ast_hangup(tc); tc = NULL; chanlist_free(tmp); @@ -2038,7 +2126,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast } } - peer = wait_for_answer(chan, outgoing, &to, peerflags, opt_args, &pa, &num, &result, dtmf_progress); + peer = wait_for_answer(chan, outgoing, &to, peerflags, opt_args, &pa, &num, &result, dtmf_progress, ignore_cc); /* The ast_channel_datastore_remove() function could fail here if the * datastore was moved to another channel during a masquerade. If this is @@ -2513,6 +2601,7 @@ done: if (config.start_sound) { ast_free((char *)config.start_sound); } + ast_ignore_cc(chan); return res; } |