OPENZAP-238: [freetdm] Enable GSM immediate forwarding logic
Use the new parameter immediate-forwarding-numbers to configure immediate forwarding logic that emulates hunt groups The parameter syntax is: [<span-name>:]<number> Multiple elements can be specified separated by commas If the <span-name> is specified, the span will be checked for availability, if available, its number will be selected for forwarding, otherwise next number will be checked Forwarding is enabled as soon as a channel is answered and its disabled when the channel is hung up
This commit is contained in:
parent
54005bfead
commit
7b4838035a
|
@ -571,5 +571,59 @@ with the signaling protocols that you can run on top of your I/O interfaces.
|
|||
<param name="context" value="default"/>
|
||||
</span>
|
||||
</pritap_spans>
|
||||
|
||||
<!--
|
||||
GSM spans (libwat must be installed when configuring the freetdm build)
|
||||
-->
|
||||
<gsm_spans>
|
||||
<span name="gsm01">
|
||||
<!-- where to send inbound calls to -->
|
||||
<param name="dialplan" value="XML" />
|
||||
<param name="context" value="module1" />
|
||||
|
||||
<!--
|
||||
GSM module type
|
||||
Accepted values: "telit", "telit-gc864", "telit-he910", "telit-cc864", "telit-de910", "motorola"
|
||||
-->
|
||||
<param name="moduletype" value="telit-gc864" />
|
||||
|
||||
<!--
|
||||
Debug mask (accepted values: all, uart_raw, uart_raw, call_state, span_state, at_parse, at_handle, sms_encode, sms_decode, none)
|
||||
comma-separated values are accepted to combine those levels
|
||||
-->
|
||||
<param name="debug" value="all" />
|
||||
|
||||
<!--
|
||||
Whether to enable HW DTMF in the hardware module
|
||||
Accepted values: true, generate, detect, false
|
||||
-->
|
||||
<param name="hwdtmf" value="true" />
|
||||
|
||||
<!--
|
||||
This enables conditional forwarding on module startup
|
||||
-->
|
||||
<!-- <param name="conditional-forwarding-prefix" value="*71" /> -->
|
||||
<!-- <param name="conditional-forwarding-number" value="123456789" /> -->
|
||||
|
||||
<!--
|
||||
This enables immediate forwarding logic to simulate hunt groups
|
||||
The syntax for immediate-forwarding-numbers ia a comma-separated
|
||||
list of elements in the form [<span-name>:]<number>
|
||||
|
||||
if span-name is specified, the span will be checked for availability
|
||||
before enabling forwarding to that span number
|
||||
|
||||
The span-name must be a defined freetdm span name
|
||||
|
||||
If the span-name is not specified then only first number specified is used for
|
||||
forwarding whenever this span is busy
|
||||
-->
|
||||
<!-- <param name="immediate-forwarding-prefix" value="*72" /> -->
|
||||
<!-- <param name="immediate-forwarding-numbers" value="gsm02:123456789" /> -->
|
||||
|
||||
<!-- Number to dial to disable forwarding when the call ends (if immediate forwarding was enabled) -->
|
||||
<!-- <param name="disable-forwarding-number" value="*73" /> -->
|
||||
</span>
|
||||
</gsm_spans>
|
||||
</configuration>
|
||||
|
||||
|
|
|
@ -106,10 +106,19 @@ typedef struct ftdm_gsm_span_data_s {
|
|||
ftdm_channel_t *bchan;
|
||||
int32_t call_id;
|
||||
uint32_t sms_id;
|
||||
char conditional_forward_number[255];
|
||||
char conditional_forward_prefix[10];
|
||||
char conditional_forward_number[50];
|
||||
char immediate_forward_prefix[10];
|
||||
struct {
|
||||
char number[50];
|
||||
char span[50];
|
||||
} immediate_forward_numbers[10];
|
||||
char disable_forward_number[50];
|
||||
ftdm_sched_t *sched;
|
||||
ftdm_timer_id_t conditional_forwarding_timer;
|
||||
ftdm_bool_t init_forwarding;
|
||||
ftdm_timer_id_t immediate_forwarding_timer;
|
||||
ftdm_bool_t init_conditional_forwarding;
|
||||
ftdm_bool_t startup_forwarding_disabled;
|
||||
} ftdm_gsm_span_data_t;
|
||||
|
||||
// command handler function type.
|
||||
|
@ -230,9 +239,11 @@ done:
|
|||
|
||||
static void ftdm_gsm_enable_conditional_forwarding(void *data)
|
||||
{
|
||||
char number[255];
|
||||
ftdm_gsm_span_data_t *gsm_data = data;
|
||||
ftdm_log_chan(gsm_data->bchan, FTDM_LOG_NOTICE, "Enabling conditional forwarding to %s\n", gsm_data->conditional_forward_number);
|
||||
ftdm_gsm_make_raw_call(data, gsm_data->conditional_forward_number);
|
||||
snprintf(number, sizeof(number), "%s%s", gsm_data->conditional_forward_prefix, gsm_data->conditional_forward_number);
|
||||
ftdm_log_chan(gsm_data->bchan, FTDM_LOG_INFO, "Enabling conditional forwarding to %s\n", number);
|
||||
ftdm_gsm_make_raw_call(data, number);
|
||||
}
|
||||
|
||||
static void on_wat_span_status(unsigned char span_id, wat_span_status_t *status)
|
||||
|
@ -258,12 +269,12 @@ static void on_wat_span_status(unsigned char span_id, wat_span_status_t *status)
|
|||
} else {
|
||||
ftdm_log_chan_msg(gsm_data->bchan, FTDM_LOG_INFO, "Signaling is now down\n");
|
||||
}
|
||||
if (gsm_data->init_forwarding == FTDM_TRUE && !ftdm_strlen_zero_buf(gsm_data->conditional_forward_number)) {
|
||||
ftdm_sched_timer(gsm_data->sched, "conditional_forwarding_delay", 500,
|
||||
if (gsm_data->init_conditional_forwarding == FTDM_TRUE && !ftdm_strlen_zero_buf(gsm_data->conditional_forward_number)) {
|
||||
ftdm_sched_timer(gsm_data->sched, "conditional_forwarding_delay", 1000,
|
||||
ftdm_gsm_enable_conditional_forwarding,
|
||||
gsm_data,
|
||||
&gsm_data->conditional_forwarding_timer);
|
||||
gsm_data->init_forwarding = FTDM_FALSE;
|
||||
gsm_data->init_conditional_forwarding = FTDM_FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -754,136 +765,164 @@ static ftdm_state_map_t gsm_state_map = {
|
|||
}
|
||||
};
|
||||
|
||||
static ftdm_status_t ftdm_gsm_state_advance(ftdm_channel_t *ftdmchan)
|
||||
#define immediate_forward_enabled(gsm_data) !ftdm_strlen_zero_buf(gsm_data->immediate_forward_numbers[0].number)
|
||||
|
||||
static void perform_enable_immediate_forward(void *data)
|
||||
{
|
||||
ftdm_span_t *fwd_span = NULL;
|
||||
ftdm_gsm_span_data_t *fwd_gsm_data = NULL;
|
||||
char *fwd_span_name = NULL;
|
||||
char *number = NULL;
|
||||
char cmd[100];
|
||||
int i = 0;
|
||||
ftdm_channel_t *ftdmchan = data;
|
||||
ftdm_gsm_span_data_t *gsm_data = ftdmchan->span->signal_data;
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
|
||||
switch (ftdmchan->state) {
|
||||
|
||||
/* starting an incoming call */
|
||||
case FTDM_CHANNEL_STATE_COLLECT:
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
/* starting an outgoing call */
|
||||
case FTDM_CHANNEL_STATE_DIALING:
|
||||
{
|
||||
uint32_t interval = 0;
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting outgoing call with interval %d\n", interval);
|
||||
|
||||
{
|
||||
|
||||
ftdm_gsm_span_data_t *gsm_data;
|
||||
wat_con_event_t con_event;
|
||||
gsm_data = ftdmchan->span->signal_data;
|
||||
gsm_data->call_id = GSM_OUTBOUND_CALL_ID;
|
||||
memset(&con_event, 0, sizeof(con_event));
|
||||
ftdm_set_string(con_event.called_num.digits, ftdmchan->caller_data.dnis.digits);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s\n", con_event.called_num.digits);
|
||||
wat_con_req(ftdmchan->span->span_id, gsm_data->call_id , &con_event);
|
||||
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_DIALING);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
/* incoming call was offered */
|
||||
case FTDM_CHANNEL_STATE_RING:
|
||||
|
||||
/* notify the user about the new call */
|
||||
|
||||
ftdm_log(FTDM_LOG_INFO, "Answering Incomming Call\r\n");
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_START);
|
||||
|
||||
break;
|
||||
|
||||
/* the call is making progress */
|
||||
case FTDM_CHANNEL_STATE_PROGRESS:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
||||
{
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_PROGRESS_MEDIA);
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
}
|
||||
break;
|
||||
|
||||
/* the call was answered */
|
||||
case FTDM_CHANNEL_STATE_UP:
|
||||
{
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_UP);
|
||||
}
|
||||
else {
|
||||
ftdm_gsm_span_data_t *gsm_data;
|
||||
gsm_data = ftdmchan->span->signal_data;
|
||||
wat_con_cfm(ftdmchan->span->span_id, gsm_data->call_id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
/* just got hangup */
|
||||
case FTDM_CHANNEL_STATE_HANGUP:
|
||||
{
|
||||
ftdm_gsm_span_data_t *gsm_data;
|
||||
gsm_data = ftdmchan->span->signal_data;
|
||||
wat_rel_req(ftdmchan->span->span_id, gsm_data->call_id);
|
||||
gsm_data->call_id = 0;
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
|
||||
}
|
||||
break;
|
||||
|
||||
case FTDM_CHANNEL_STATE_TERMINATING:
|
||||
{
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
|
||||
}
|
||||
break;
|
||||
|
||||
/* finished call for good */
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
ftdm_channel_t *closed_chan;
|
||||
closed_chan = ftdmchan;
|
||||
ftdm_channel_close(&closed_chan);
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "State processing ended.\n");
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
|
||||
}
|
||||
break;
|
||||
|
||||
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
|
||||
case FTDM_CHANNEL_STATE_RINGING:
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_RINGING);
|
||||
|
||||
break;
|
||||
|
||||
/* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */
|
||||
case FTDM_CHANNEL_STATE_RESET:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n");
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
}
|
||||
break;
|
||||
for (i = 0; i < ftdm_array_len(gsm_data->immediate_forward_numbers); i++) {
|
||||
fwd_span_name = gsm_data->immediate_forward_numbers[i].span;
|
||||
fwd_span = NULL;
|
||||
if (!ftdm_strlen_zero_buf(fwd_span_name) &&
|
||||
ftdm_span_find_by_name(fwd_span_name, &fwd_span) != FTDM_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
fwd_gsm_data = fwd_span ? fwd_span->signal_data : NULL;
|
||||
if (fwd_gsm_data && fwd_gsm_data->call_id) {
|
||||
/* span busy, do not forward here */
|
||||
continue;
|
||||
}
|
||||
number = gsm_data->immediate_forward_numbers[i].number;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!number) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "No numbers available to enable immediate forwarding\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Enabling immediate forwarding to %s\n", number);
|
||||
snprintf(cmd, sizeof(cmd), "ATD%s%s", gsm_data->immediate_forward_prefix, number);
|
||||
wat_cmd_req(ftdmchan->span->span_id, cmd, NULL, NULL);
|
||||
}
|
||||
|
||||
static __inline__ void enable_immediate_forward(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
ftdm_gsm_span_data_t *gsm_data = ftdmchan->span->signal_data;
|
||||
ftdm_sched_timer(gsm_data->sched, "immediate_forwarding_delay", 1000,
|
||||
perform_enable_immediate_forward,
|
||||
ftdmchan,
|
||||
&gsm_data->immediate_forwarding_timer);
|
||||
}
|
||||
|
||||
static __inline__ void disable_all_forwarding(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
char cmd[100];
|
||||
ftdm_gsm_span_data_t *gsm_data = ftdmchan->span->signal_data;
|
||||
|
||||
if (ftdm_strlen_zero_buf(gsm_data->disable_forward_number)) {
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "ATD%s", gsm_data->disable_forward_number);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Disabling GSM immediate forward dialing %s\n", gsm_data->disable_forward_number);
|
||||
wat_cmd_req(ftdmchan->span->span_id, cmd, NULL, NULL);
|
||||
}
|
||||
|
||||
static ftdm_status_t ftdm_gsm_state_advance(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
ftdm_gsm_span_data_t *gsm_data = ftdmchan->span->signal_data;
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing GSM state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
|
||||
switch (ftdmchan->state) {
|
||||
|
||||
/* starting an outgoing call */
|
||||
case FTDM_CHANNEL_STATE_DIALING:
|
||||
{
|
||||
uint32_t interval = 0;
|
||||
wat_con_event_t con_event;
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting outgoing call with interval %d\n", interval);
|
||||
|
||||
gsm_data->call_id = GSM_OUTBOUND_CALL_ID;
|
||||
memset(&con_event, 0, sizeof(con_event));
|
||||
ftdm_set_string(con_event.called_num.digits, ftdmchan->caller_data.dnis.digits);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Dialing number %s\n", con_event.called_num.digits);
|
||||
wat_con_req(ftdmchan->span->span_id, gsm_data->call_id , &con_event);
|
||||
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_DIALING);
|
||||
}
|
||||
break;
|
||||
|
||||
/* incoming call was offered */
|
||||
case FTDM_CHANNEL_STATE_RING:
|
||||
{
|
||||
/* notify the user about the new call */
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Inbound call detected\n");
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_START);
|
||||
}
|
||||
break;
|
||||
|
||||
/* the call is making progress */
|
||||
case FTDM_CHANNEL_STATE_PROGRESS:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
||||
{
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_PROGRESS_MEDIA);
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
}
|
||||
break;
|
||||
|
||||
/* the call was answered */
|
||||
case FTDM_CHANNEL_STATE_UP:
|
||||
{
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_UP);
|
||||
} else {
|
||||
wat_con_cfm(ftdmchan->span->span_id, gsm_data->call_id);
|
||||
}
|
||||
if (immediate_forward_enabled(gsm_data)) {
|
||||
enable_immediate_forward(ftdmchan);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* just got hangup */
|
||||
case FTDM_CHANNEL_STATE_HANGUP:
|
||||
{
|
||||
wat_rel_req(ftdmchan->span->span_id, gsm_data->call_id);
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
|
||||
}
|
||||
break;
|
||||
|
||||
/* finished call for good */
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
ftdm_channel_t *closed_chan;
|
||||
gsm_data->call_id = 0;
|
||||
closed_chan = ftdmchan;
|
||||
ftdm_channel_close(&closed_chan);
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "State processing ended.\n");
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_STOP);
|
||||
if (immediate_forward_enabled(gsm_data)) {
|
||||
disable_all_forwarding(ftdmchan);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Outbound call is ringing */
|
||||
case FTDM_CHANNEL_STATE_RINGING:
|
||||
{
|
||||
SEND_STATE_SIGNAL(FTDM_SIGEVENT_RINGING);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state: %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
@ -1067,7 +1106,50 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_gsm_configure_span_signaling)
|
|||
ftdm_log(FTDM_LOG_DEBUG, "Configuring GSM span %s with hardware dtmf %s\n", span->name, val);
|
||||
} else if (!strcasecmp(var, "conditional-forwarding-number")) {
|
||||
ftdm_set_string(gsm_data->conditional_forward_number, val);
|
||||
gsm_data->init_forwarding = FTDM_TRUE;
|
||||
gsm_data->init_conditional_forwarding = FTDM_TRUE;
|
||||
} else if (!strcasecmp(var, "conditional-forwarding-prefix")) {
|
||||
ftdm_set_string(gsm_data->conditional_forward_prefix, val);
|
||||
} else if (!strcasecmp(var, "immediate-forwarding-numbers")) {
|
||||
char *state = NULL;
|
||||
char *span_end = NULL;
|
||||
char *number = NULL;
|
||||
char *span_name = NULL;
|
||||
int f = 0;
|
||||
char *valdup = ftdm_strdup(val);
|
||||
char *s = valdup;
|
||||
|
||||
if (!ftdm_strlen_zero_buf(gsm_data->immediate_forward_numbers[0].number)) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "immediate-forwarding-numbers already parsed! failed to parse: %s\n", val);
|
||||
goto ifn_parse_done;
|
||||
}
|
||||
|
||||
/* The string must be in the form [<span>:]<number>, optionally multiple elements separated by comma */
|
||||
while ((number = strtok_r(s, ",", &state))) {
|
||||
if (f == ftdm_array_len(gsm_data->immediate_forward_numbers)) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Max number (%d) of immediate forwarding numbers reached!\n", f);
|
||||
break;
|
||||
}
|
||||
|
||||
s = NULL;
|
||||
span_end = strchr(number, ':');
|
||||
if (span_end) {
|
||||
*span_end = '\0';
|
||||
span_name = number;
|
||||
number = (span_end + 1);
|
||||
ftdm_set_string(gsm_data->immediate_forward_numbers[f].span, span_name);
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Parsed immediate forwarding to span %s number %s\n", span_name, number);
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "Parsed immediate forwarding to number %s\n", number);
|
||||
}
|
||||
ftdm_set_string(gsm_data->immediate_forward_numbers[f].number, number);
|
||||
f++;
|
||||
}
|
||||
ifn_parse_done:
|
||||
ftdm_safe_free(valdup);
|
||||
} else if (!strcasecmp(var, "immediate-forwarding-prefix")) {
|
||||
ftdm_set_string(gsm_data->immediate_forward_prefix, val);
|
||||
} else if (!strcasecmp(var, "disable-forwarding-number")) {
|
||||
ftdm_set_string(gsm_data->disable_forward_number, val);
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Ignoring unknown GSM parameter '%s'", var);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue