Newer
Older
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
default:
ast_verb(2, "core_id:%d %s CC request unknown status %d\n",
monitor->core_id, sig_pri_cc_type_name,
subcmd->u.cc_request_rsp.status);
ast_cc_monitor_failed(monitor->core_id, monitor->name,
"%s CC request unknown status", sig_pri_cc_type_name);
break;
}
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_REMOTE_USER_FREE:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_remote_user_free.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_remote_user_free.cc_id);
break;
}
ast_cc_monitor_callee_available(monitor->core_id,
"%s callee has become available", sig_pri_cc_type_name);
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_B_FREE:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_b_free.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_b_free.cc_id);
break;
}
ast_cc_monitor_party_b_free(monitor->core_id);
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_STATUS_REQ:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_status_req.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_status_req.cc_id);
break;
}
ast_cc_monitor_status_request(monitor->core_id);
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_STATUS_REQ_RSP:
agent = sig_pri_find_cc_agent_by_cc_id(pri, subcmd->u.cc_status_req_rsp.cc_id);
if (!agent) {
pri_cc_cancel(pri->pri, subcmd->u.cc_status_req_rsp.cc_id);
break;
}
ast_cc_agent_status_response(agent->core_id,
subcmd->u.cc_status_req_rsp.status ? AST_DEVICE_INUSE
: AST_DEVICE_NOT_INUSE);
ao2_ref(agent, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_STATUS:
agent = sig_pri_find_cc_agent_by_cc_id(pri, subcmd->u.cc_status.cc_id);
if (!agent) {
pri_cc_cancel(pri->pri, subcmd->u.cc_status.cc_id);
break;
}
if (subcmd->u.cc_status.status) {
ast_cc_agent_caller_busy(agent->core_id, "%s agent caller is busy",
sig_pri_cc_type_name);
} else {
ast_cc_agent_caller_available(agent->core_id,
"%s agent caller is available", sig_pri_cc_type_name);
}
ao2_ref(agent, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_CANCEL:
sig_pri_cc_link_canceled(pri, subcmd->u.cc_cancel.cc_id,
subcmd->u.cc_cancel.is_agent);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_STOP_ALERTING:
monitor = sig_pri_find_cc_monitor_by_cc_id(pri,
subcmd->u.cc_stop_alerting.cc_id);
if (!monitor) {
pri_cc_cancel(pri->pri, subcmd->u.cc_stop_alerting.cc_id);
break;
}
ast_cc_monitor_stop_ringing(monitor->core_id);
ao2_ref(monitor, -1);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_E:
/* Queue AST_CONTROL_AOC frame */
sig_pri_aoc_e_from_pri(&subcmd->u.aoc_e, NULL, 0);
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
ast_debug(2, "Span %d: Unknown CIS subcommand(%d) in %s event.\n", pri->span,
subcmd->cmd, pri_event2str(event_id));
break;
}
}
}
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
#if defined(HAVE_PRI_AOC_EVENTS)
/*!
* \internal
* \brief detect if AOC-S subcmd is present.
* \since 1.8
*
* \param subcmds Subcommands to process if any. (Could be NULL).
*
* \note Knowing whether or not an AOC-E subcmd is present on certain
* PRI hangup events is necessary to determine what method to use to hangup
* the ast_channel. If an AOC-E subcmd just came in, then a new AOC-E was queued
* on the ast_channel. If a soft hangup is used, the AOC-E msg will never make it
* across the bridge, but if a AST_CONTROL_HANGUP frame is queued behind it
* we can ensure the AOC-E frame makes it to it's destination before the hangup
* frame is read.
*
*
* \retval 0 AOC-E is not present in subcmd list
* \retval 1 AOC-E is present in subcmd list
*/
static int detect_aoc_e_subcmd(const struct pri_subcommands *subcmds)
{
int i;
if (!subcmds) {
return 0;
}
for (i = 0; i < subcmds->counter_subcmd; ++i) {
const struct pri_subcommand *subcmd = &subcmds->subcmd[i];
if (subcmd->cmd == PRI_SUBCMD_AOC_E) {
return 1;
}
}
return 0;
}
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
/*!
* \internal
* \brief Handle the call associated PRI subcommand events.
* \since 1.8
*
* \param pri PRI span control structure.
* \param chanpos Channel position in the span.
* \param event_id PRI event id
* \param subcmds Subcommands to process if any. (Could be NULL).
* \param call_rsp libpri opaque call structure to send any responses toward.
* Could be NULL either because it is not available or the call is for the
* dummy call reference. However, this should not be NULL in the cases that
* need to use the pointer to send a response message back.
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
*
* \return Nothing
*/
static void sig_pri_handle_subcmds(struct sig_pri_span *pri, int chanpos, int event_id,
const struct pri_subcommands *subcmds, q931_call *call_rsp)
{
int index;
struct ast_channel *owner;
struct ast_party_redirecting ast_redirecting;
#if defined(HAVE_PRI_TRANSFER)
struct xfer_rsp_data xfer_rsp;
#endif /* defined(HAVE_PRI_TRANSFER) */
if (!subcmds) {
return;
}
for (index = 0; index < subcmds->counter_subcmd; ++index) {
const struct pri_subcommand *subcmd = &subcmds->subcmd[index];
switch (subcmd->cmd) {
case PRI_SUBCMD_CONNECTED_LINE:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
struct ast_party_connected_line ast_connected;
int caller_id_update;
/* Extract the connected line information */
ast_party_connected_line_init(&ast_connected);
sig_pri_party_id_convert(&ast_connected.id, &subcmd->u.connected_line.id,
pri);
ast_connected.id.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
/* Save name for Caller-ID update */
ast_copy_string(pri->pvts[chanpos]->cid_name,
ast_connected.id.name.str, sizeof(pri->pvts[chanpos]->cid_name));
caller_id_update = 1;
}
/* Save number for Caller-ID update */
ast_copy_string(pri->pvts[chanpos]->cid_num,
ast_connected.id.number.str, sizeof(pri->pvts[chanpos]->cid_num));
pri->pvts[chanpos]->cid_ton = ast_connected.id.number.plan;
caller_id_update = 1;
}
ast_connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
pri->pvts[chanpos]->cid_subaddr[0] = '\0';
#if defined(HAVE_PRI_SUBADDR)
if (ast_connected.id.subaddress.valid) {
ast_party_subaddress_set(&ast_channel_caller(owner)->id.subaddress,
&ast_connected.id.subaddress);
if (ast_connected.id.subaddress.str) {
ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
ast_connected.id.subaddress.str,
sizeof(pri->pvts[chanpos]->cid_subaddr));
}
}
#endif /* defined(HAVE_PRI_SUBADDR) */
if (caller_id_update) {
struct ast_party_caller ast_caller;
pri->pvts[chanpos]->callingpres =
ast_party_id_presentation(&ast_connected.id);
sig_pri_set_caller_id(pri->pvts[chanpos]);
ast_party_caller_set_init(&ast_caller, ast_channel_caller(owner));
ast_caller.id = ast_connected.id;
ast_caller.ani = ast_connected.id;
ast_channel_set_caller_event(owner, &ast_caller, NULL);
}
/* Update the connected line information on the other channel */
if (event_id != PRI_EVENT_RING) {
/* This connected_line update was not from a SETUP message. */
ast_channel_queue_connected_line_update(owner, &ast_connected, NULL);
}
ast_party_connected_line_free(&ast_connected);
ast_channel_unlock(owner);
}
break;
case PRI_SUBCMD_REDIRECTING:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
sig_pri_redirecting_convert(&ast_redirecting, &subcmd->u.redirecting,
ast_channel_redirecting(owner), pri);
ast_redirecting.orig.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_redirecting.from.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_redirecting.to.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_channel_set_redirecting(owner, &ast_redirecting, NULL);
if (event_id != PRI_EVENT_RING) {
/* This redirection was not from a SETUP message. */
Richard Mudgett
committed
/* Invalidate any earlier private redirecting id representations */
ast_party_id_invalidate(&ast_redirecting.priv_orig);
ast_party_id_invalidate(&ast_redirecting.priv_from);
ast_party_id_invalidate(&ast_redirecting.priv_to);
ast_channel_queue_redirecting_update(owner, &ast_redirecting, NULL);
}
ast_party_redirecting_free(&ast_redirecting);
ast_channel_unlock(owner);
}
break;
#if defined(HAVE_PRI_CALL_REROUTING)
case PRI_SUBCMD_REROUTING:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
struct pri_party_redirecting pri_deflection;
if (!call_rsp) {
ast_log(LOG_WARNING,
"Span %d: %s tried CallRerouting/CallDeflection to '%s' without call!\n",
pri->span, ast_channel_name(owner), subcmd->u.rerouting.deflection.to.number.str);
break;
}
if (ast_strlen_zero(subcmd->u.rerouting.deflection.to.number.str)) {
"Span %d: %s tried CallRerouting/CallDeflection to empty number!\n",
pri->span, ast_channel_name(owner));
pri_rerouting_rsp(pri->pri, call_rsp, subcmd->u.rerouting.invoke_id,
PRI_REROUTING_RSP_INVALID_NUMBER);
ast_channel_unlock(owner);
ast_verb(3, "Span %d: %s is CallRerouting/CallDeflection to '%s'.\n",
pri->span, ast_channel_name(owner), subcmd->u.rerouting.deflection.to.number.str);
/*
* Send back positive ACK to CallRerouting/CallDeflection.
*
* Note: This call will be hungup by the core when it processes
* the call_forward string.
*/
pri_rerouting_rsp(pri->pri, call_rsp, subcmd->u.rerouting.invoke_id,
PRI_REROUTING_RSP_OK_CLEAR);
pri_deflection = subcmd->u.rerouting.deflection;
/* Adjust the deflecting to number based upon the subscription option. */
switch (subcmd->u.rerouting.subscription_option) {
case 0: /* noNotification */
case 1: /* notificationWithoutDivertedToNr */
/* Delete the number because the far end is not supposed to see it. */
pri_deflection.to.number.presentation =
PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
pri_deflection.to.number.plan =
(PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
pri_deflection.to.number.str[0] = '\0';
break;
case 2: /* notificationWithDivertedToNr */
break;
case 3: /* notApplicable */
default:
break;
}
sig_pri_redirecting_convert(&ast_redirecting, &pri_deflection,
ast_channel_redirecting(owner), pri);
ast_redirecting.orig.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_redirecting.from.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_redirecting.to.tag = ast_strdup(pri->pvts[chanpos]->user_tag);
ast_channel_set_redirecting(owner, &ast_redirecting, NULL);
ast_party_redirecting_free(&ast_redirecting);
/* Request the core to forward to the new number. */
ast_channel_call_forward_set(owner, subcmd->u.rerouting.deflection.to.number.str);
/* Wake up the channel. */
ast_queue_frame(owner, &ast_null_frame);
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_CALL_REROUTING) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_AVAILABLE:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
enum ast_cc_service_type service;
switch (event_id) {
case PRI_EVENT_RINGING:
service = AST_CC_CCNR;
break;
case PRI_EVENT_HANGUP_REQ:
/* We will assume that the cause was busy/congestion. */
service = AST_CC_CCBS;
break;
default:
service = AST_CC_NONE;
break;
}
if (service == AST_CC_NONE
|| sig_pri_cc_available(pri, chanpos, subcmd->u.cc_available.cc_id,
service)) {
pri_cc_cancel(pri->pri, subcmd->u.cc_available.cc_id);
}
ast_channel_unlock(owner);
} else {
/* No asterisk channel. */
pri_cc_cancel(pri->pri, subcmd->u.cc_available.cc_id);
}
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_CALL:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
struct ast_cc_agent *agent;
agent = sig_pri_find_cc_agent_by_cc_id(pri, subcmd->u.cc_call.cc_id);
if (agent) {
ast_setup_cc_recall_datastore(owner, agent->core_id);
ast_cc_agent_set_interfaces_chanvar(owner);
ast_cc_agent_recalling(agent->core_id,
"%s caller is attempting recall", sig_pri_cc_type_name);
ao2_ref(agent, -1);
}
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_CCSS)
case PRI_SUBCMD_CC_CANCEL:
sig_pri_cc_link_canceled(pri, subcmd->u.cc_cancel.cc_id,
subcmd->u.cc_cancel.is_agent);
break;
#endif /* defined(HAVE_PRI_CCSS) */
#if defined(HAVE_PRI_TRANSFER)
case PRI_SUBCMD_TRANSFER_CALL:
if (!call_rsp) {
/* Should never happen. */
ast_log(LOG_ERROR,
"Call transfer subcommand without call to send response!\n");
break;
}
sig_pri_unlock_private(pri->pvts[chanpos]);
xfer_rsp.pri = pri;
xfer_rsp.call = call_rsp;
xfer_rsp.invoke_id = subcmd->u.transfer.invoke_id;
sig_pri_attempt_transfer(pri,
subcmd->u.transfer.call_1, subcmd->u.transfer.is_call_1_held,
subcmd->u.transfer.call_2, subcmd->u.transfer.is_call_2_held,
sig_pri_transfer_rsp, &xfer_rsp);
sig_pri_lock_private(pri->pvts[chanpos]);
break;
#endif /* defined(HAVE_PRI_TRANSFER) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_S:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
sig_pri_aoc_s_from_pri(&subcmd->u.aoc_s, owner,
(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S));
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_D:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
/* Queue AST_CONTROL_AOC frame on channel */
sig_pri_aoc_d_from_pri(&subcmd->u.aoc_d, owner,
(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_D));
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_E:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
sig_pri_aoc_e_from_pri(&subcmd->u.aoc_e, owner,
(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E));
if (owner) {
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_CHARGING_REQ:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
sig_pri_aoc_request_from_pri(&subcmd->u.aoc_request, pri->pvts[chanpos],
call_rsp);
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_AOC_EVENTS)
case PRI_SUBCMD_AOC_CHARGING_REQ_RSP:
/*
* An AOC request response may contain an AOC-S rate list.
* If this is the case handle this just like we
* would an incoming AOC-S msg.
*/
if (subcmd->u.aoc_request_response.valid_aoc_s) {
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
sig_pri_aoc_s_from_pri(&subcmd->u.aoc_request_response.aoc_s, owner,
(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S));
ast_channel_unlock(owner);
}
}
break;
#endif /* defined(HAVE_PRI_AOC_EVENTS) */
#if defined(HAVE_PRI_MCID)
case PRI_SUBCMD_MCID_REQ:
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
sig_pri_mcid_event(pri, &subcmd->u.mcid_req, owner);
if (owner) {
ast_channel_unlock(owner);
}
break;
#endif /* defined(HAVE_PRI_MCID) */
#if defined(HAVE_PRI_MCID)
case PRI_SUBCMD_MCID_RSP:
/* Ignore for now. */
break;
#endif /* defined(HAVE_PRI_MCID) */
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
#if defined(HAVE_PRI_DISPLAY_TEXT)
case PRI_SUBCMD_DISPLAY_TEXT:
if (event_id != PRI_EVENT_RING) {
/*
* This display text was not from a SETUP message. We can do
* something with this display text string.
*/
sig_pri_lock_owner(pri, chanpos);
owner = pri->pvts[chanpos]->owner;
if (owner) {
struct ast_frame f;
/* Pass the display text to the peer channel. */
memset(&f, 0, sizeof(f));
f.frametype = AST_FRAME_TEXT;
f.subclass.integer = 0;
f.offset = 0;
f.data.ptr = &subcmd->u.display.text;
f.datalen = subcmd->u.display.length + 1;
ast_queue_frame(owner, &f);
ast_channel_unlock(owner);
}
}
break;
#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
ast_debug(2, "Span %d: Unknown call subcommand(%d) in %s event.\n",
pri->span, subcmd->cmd, pri_event2str(event_id));
break;
}
}
}
Richard Mudgett
committed
/*!
* \internal
* \brief Convert the MOH state to string.
Richard Mudgett
committed
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
*
* \param state MOH state to process.
*
* \return String version of MOH state.
*/
static const char *sig_pri_moh_state_str(enum sig_pri_moh_state state)
{
const char *str;
str = "Unknown";
switch (state) {
case SIG_PRI_MOH_STATE_IDLE:
str = "SIG_PRI_MOH_STATE_IDLE";
break;
case SIG_PRI_MOH_STATE_NOTIFY:
str = "SIG_PRI_MOH_STATE_NOTIFY";
break;
case SIG_PRI_MOH_STATE_MOH:
str = "SIG_PRI_MOH_STATE_MOH";
break;
#if defined(HAVE_PRI_CALL_HOLD)
case SIG_PRI_MOH_STATE_HOLD_REQ:
str = "SIG_PRI_MOH_STATE_HOLD_REQ";
break;
case SIG_PRI_MOH_STATE_PEND_UNHOLD:
str = "SIG_PRI_MOH_STATE_PEND_UNHOLD";
break;
case SIG_PRI_MOH_STATE_HOLD:
str = "SIG_PRI_MOH_STATE_HOLD";
break;
case SIG_PRI_MOH_STATE_RETRIEVE_REQ:
str = "SIG_PRI_MOH_STATE_RETRIEVE_REQ";
break;
case SIG_PRI_MOH_STATE_PEND_HOLD:
str = "SIG_PRI_MOH_STATE_PEND_HOLD";
break;
case SIG_PRI_MOH_STATE_RETRIEVE_FAIL:
str = "SIG_PRI_MOH_STATE_RETRIEVE_FAIL";
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
case SIG_PRI_MOH_STATE_NUM:
/* Not a real state. */
break;
}
return str;
}
/*!
* \internal
* \brief Convert the MOH event to string.
Richard Mudgett
committed
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
*
* \param event MOH event to process.
*
* \return String version of MOH event.
*/
static const char *sig_pri_moh_event_str(enum sig_pri_moh_event event)
{
const char *str;
str = "Unknown";
switch (event) {
case SIG_PRI_MOH_EVENT_RESET:
str = "SIG_PRI_MOH_EVENT_RESET";
break;
case SIG_PRI_MOH_EVENT_HOLD:
str = "SIG_PRI_MOH_EVENT_HOLD";
break;
case SIG_PRI_MOH_EVENT_UNHOLD:
str = "SIG_PRI_MOH_EVENT_UNHOLD";
break;
#if defined(HAVE_PRI_CALL_HOLD)
case SIG_PRI_MOH_EVENT_HOLD_ACK:
str = "SIG_PRI_MOH_EVENT_HOLD_ACK";
break;
case SIG_PRI_MOH_EVENT_HOLD_REJ:
str = "SIG_PRI_MOH_EVENT_HOLD_REJ";
break;
case SIG_PRI_MOH_EVENT_RETRIEVE_ACK:
str = "SIG_PRI_MOH_EVENT_RETRIEVE_ACK";
break;
case SIG_PRI_MOH_EVENT_RETRIEVE_REJ:
str = "SIG_PRI_MOH_EVENT_RETRIEVE_REJ";
break;
case SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK:
str = "SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK";
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
case SIG_PRI_MOH_EVENT_NUM:
/* Not a real event. */
break;
}
return str;
}
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
* \brief Retrieve a call that was placed on hold by the HOLD message.
Richard Mudgett
committed
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
*
* \param pvt Channel private control structure.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state
*/
static enum sig_pri_moh_state sig_pri_moh_retrieve_call(struct sig_pri_chan *pvt)
{
int chanpos;
int channel;
if (pvt->pri->nodetype == PRI_NETWORK) {
/* Find an available channel to propose */
chanpos = pri_find_empty_chan(pvt->pri, 1);
if (chanpos < 0) {
/* No channels available. */
return SIG_PRI_MOH_STATE_RETRIEVE_FAIL;
}
channel = PVT_TO_CHANNEL(pvt->pri->pvts[chanpos]);
/*
* We cannot occupy or reserve this channel at this time because
* the retrieve may fail or we could have a RETRIEVE collision.
*/
} else {
/* Let the network pick the channel. */
channel = 0;
}
if (pri_retrieve(pvt->pri->pri, pvt->call, channel)) {
return SIG_PRI_MOH_STATE_RETRIEVE_FAIL;
}
return SIG_PRI_MOH_STATE_RETRIEVE_REQ;
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
/*!
* \internal
* \brief MOH FSM state idle.
Richard Mudgett
committed
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
*
* \param chan Channel to post event to (Usually pvt->owner)
* \param pvt Channel private control structure.
* \param event MOH event to process.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state
*/
static enum sig_pri_moh_state sig_pri_moh_fsm_idle(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
{
enum sig_pri_moh_state next_state;
next_state = pvt->moh_state;
switch (event) {
case SIG_PRI_MOH_EVENT_HOLD:
if (!strcasecmp(pvt->mohinterpret, "passthrough")) {
/*
* This config setting is deprecated.
* The old way did not send MOH just in case the notification was ignored.
*/
pri_notify(pvt->pri->pri, pvt->call, pvt->prioffset, PRI_NOTIFY_REMOTE_HOLD);
next_state = SIG_PRI_MOH_STATE_NOTIFY;
break;
}
switch (pvt->pri->moh_signaling) {
default:
case SIG_PRI_MOH_SIGNALING_MOH:
ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
next_state = SIG_PRI_MOH_STATE_MOH;
break;
case SIG_PRI_MOH_SIGNALING_NOTIFY:
/* Send MOH anyway in case the far end does not interpret the notification. */
ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
pri_notify(pvt->pri->pri, pvt->call, pvt->prioffset, PRI_NOTIFY_REMOTE_HOLD);
next_state = SIG_PRI_MOH_STATE_NOTIFY;
break;
#if defined(HAVE_PRI_CALL_HOLD)
case SIG_PRI_MOH_SIGNALING_HOLD:
if (pri_hold(pvt->pri->pri, pvt->call)) {
/* Fall back to MOH instead */
ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
next_state = SIG_PRI_MOH_STATE_MOH;
} else {
next_state = SIG_PRI_MOH_STATE_HOLD_REQ;
}
break;
#endif /* defined(HAVE_PRI_CALL_HOLD) */
}
break;
default:
break;
}
pvt->moh_state = next_state;
return next_state;
}
/*!
* \internal
* \brief MOH FSM state notify remote party.
Richard Mudgett
committed
*
* \param chan Channel to post event to (Usually pvt->owner)
* \param pvt Channel private control structure.
* \param event MOH event to process.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state
*/
static enum sig_pri_moh_state sig_pri_moh_fsm_notify(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
{
enum sig_pri_moh_state next_state;
next_state = pvt->moh_state;
switch (event) {
Richard Mudgett
committed
case SIG_PRI_MOH_EVENT_HOLD:
if (strcasecmp(pvt->mohinterpret, "passthrough")) {
/* Restart MOH in case it was stopped by other means. */
ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
}
break;
Richard Mudgett
committed
case SIG_PRI_MOH_EVENT_UNHOLD:
pri_notify(pvt->pri->pri, pvt->call, pvt->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
/* Fall through */
case SIG_PRI_MOH_EVENT_RESET:
ast_moh_stop(chan);
next_state = SIG_PRI_MOH_STATE_IDLE;
break;
default:
break;
}
pvt->moh_state = next_state;
return next_state;
}
/*!
* \internal
* \brief MOH FSM state generate moh.
Richard Mudgett
committed
*
* \param chan Channel to post event to (Usually pvt->owner)
* \param pvt Channel private control structure.
* \param event MOH event to process.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state
*/
static enum sig_pri_moh_state sig_pri_moh_fsm_moh(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
{
enum sig_pri_moh_state next_state;
next_state = pvt->moh_state;
switch (event) {
Richard Mudgett
committed
case SIG_PRI_MOH_EVENT_HOLD:
/* Restart MOH in case it was stopped by other means. */
ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
break;
Richard Mudgett
committed
case SIG_PRI_MOH_EVENT_RESET:
case SIG_PRI_MOH_EVENT_UNHOLD:
ast_moh_stop(chan);
next_state = SIG_PRI_MOH_STATE_IDLE;
break;
default:
break;
}
pvt->moh_state = next_state;
return next_state;
}
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
* \brief MOH FSM state hold requested.
Richard Mudgett
committed
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
*
* \param chan Channel to post event to (Usually pvt->owner)
* \param pvt Channel private control structure.
* \param event MOH event to process.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state
*/
static enum sig_pri_moh_state sig_pri_moh_fsm_hold_req(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
{
enum sig_pri_moh_state next_state;
next_state = pvt->moh_state;
switch (event) {
case SIG_PRI_MOH_EVENT_RESET:
next_state = SIG_PRI_MOH_STATE_IDLE;
break;
case SIG_PRI_MOH_EVENT_UNHOLD:
next_state = SIG_PRI_MOH_STATE_PEND_UNHOLD;
break;
case SIG_PRI_MOH_EVENT_HOLD_REJ:
/* Fall back to MOH */
if (chan) {
ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
}
next_state = SIG_PRI_MOH_STATE_MOH;
break;
case SIG_PRI_MOH_EVENT_HOLD_ACK:
next_state = SIG_PRI_MOH_STATE_HOLD;
break;
default:
break;
}
pvt->moh_state = next_state;
return next_state;
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
* \brief MOH FSM state hold requested with pending unhold.
Richard Mudgett
committed
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
*
* \param chan Channel to post event to (Usually pvt->owner)
* \param pvt Channel private control structure.
* \param event MOH event to process.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state
*/
static enum sig_pri_moh_state sig_pri_moh_fsm_pend_unhold(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
{
enum sig_pri_moh_state next_state;
next_state = pvt->moh_state;
switch (event) {
case SIG_PRI_MOH_EVENT_RESET:
next_state = SIG_PRI_MOH_STATE_IDLE;
break;
case SIG_PRI_MOH_EVENT_HOLD:
next_state = SIG_PRI_MOH_STATE_HOLD_REQ;
break;
case SIG_PRI_MOH_EVENT_HOLD_REJ:
next_state = SIG_PRI_MOH_STATE_IDLE;
break;
case SIG_PRI_MOH_EVENT_HOLD_ACK:
next_state = sig_pri_moh_retrieve_call(pvt);
break;
default:
break;
}
pvt->moh_state = next_state;
return next_state;
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
* \brief MOH FSM state hold.
Richard Mudgett
committed
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
*
* \param chan Channel to post event to (Usually pvt->owner)
* \param pvt Channel private control structure.
* \param event MOH event to process.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state
*/
static enum sig_pri_moh_state sig_pri_moh_fsm_hold(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
{
enum sig_pri_moh_state next_state;
next_state = pvt->moh_state;
switch (event) {
case SIG_PRI_MOH_EVENT_RESET:
next_state = SIG_PRI_MOH_STATE_IDLE;
break;
case SIG_PRI_MOH_EVENT_UNHOLD:
next_state = sig_pri_moh_retrieve_call(pvt);
break;
case SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK:
/* Fall back to MOH */
if (chan) {
ast_moh_start(chan, pvt->moh_suggested, pvt->mohinterpret);
}
next_state = SIG_PRI_MOH_STATE_MOH;
break;
default:
break;
}
pvt->moh_state = next_state;
return next_state;
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
* \brief MOH FSM state retrieve requested.
Richard Mudgett
committed
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
*
* \param chan Channel to post event to (Usually pvt->owner)
* \param pvt Channel private control structure.
* \param event MOH event to process.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state
*/
static enum sig_pri_moh_state sig_pri_moh_fsm_retrieve_req(struct ast_channel *chan, struct sig_pri_chan *pvt, enum sig_pri_moh_event event)
{
enum sig_pri_moh_state next_state;
next_state = pvt->moh_state;
switch (event) {
case SIG_PRI_MOH_EVENT_RESET:
next_state = SIG_PRI_MOH_STATE_IDLE;
break;
case SIG_PRI_MOH_EVENT_HOLD:
next_state = SIG_PRI_MOH_STATE_PEND_HOLD;
break;
case SIG_PRI_MOH_EVENT_RETRIEVE_ACK:
case SIG_PRI_MOH_EVENT_REMOTE_RETRIEVE_ACK:
next_state = SIG_PRI_MOH_STATE_IDLE;
break;
case SIG_PRI_MOH_EVENT_RETRIEVE_REJ:
next_state = SIG_PRI_MOH_STATE_RETRIEVE_FAIL;
break;
default:
break;
}
pvt->moh_state = next_state;
return next_state;
}
#endif /* defined(HAVE_PRI_CALL_HOLD) */
#if defined(HAVE_PRI_CALL_HOLD)
/*!
* \internal
* \brief MOH FSM state retrieve requested with pending hold.
Richard Mudgett
committed
*
* \param chan Channel to post event to (Usually pvt->owner)
* \param pvt Channel private control structure.
* \param event MOH event to process.
*
* \note Assumes the pvt->pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pvt) is already obtained.
*
* \return Next MOH state