Merge commit 'fsorig/master'
This commit is contained in:
commit
aa7c9b898a
|
@ -10,6 +10,8 @@
|
|||
<param name="moh-sound" value="$${hold_music}"/>
|
||||
<!--<param name="record-template" value="$${base_dir}/recordings/${strftime(%Y-%m-%d-%H-%M-%S)}.${destination_number}.${caller_id_number}.${uuid}.wav"/>-->
|
||||
<param name="time-base-score" value="system"/>
|
||||
<param name="max-wait-time" value="0"/>
|
||||
<param name="max-wait-time-with-no-agent" value="0"/>
|
||||
<param name="tier-rules-apply" value="false"/>
|
||||
<param name="tier-rule-wait-second" value="300"/>
|
||||
<param name="tier-rule-wait-multiply-level" value="true"/>
|
||||
|
|
|
@ -715,15 +715,6 @@
|
|||
-->
|
||||
<X-PRE-PROCESS cmd="include" data="default/*.xml"/>
|
||||
|
||||
<!--
|
||||
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
|
||||
Anything you put below this line will usually get ignored due to the file in
|
||||
default/99999_enum.xml as it will transfer the call to the enum dialplan.
|
||||
|
||||
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
-->
|
||||
|
||||
<!--
|
||||
<extension name="refer">
|
||||
<condition field="${sip_refer_to}">
|
||||
|
@ -758,7 +749,12 @@
|
|||
</extension>
|
||||
-->
|
||||
|
||||
<!-- SEE WARNING ABOVE IF YOU ARE TRYING TO ADD EXTENSIONS HERE! -->
|
||||
<extension name="enum">
|
||||
<condition field="${module_exists(mod_enum)}" expression="true"/>
|
||||
<condition field="destination_number" expression="^(.*)$">
|
||||
<action application="transfer" data="$1 enum"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
</context>
|
||||
</include>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<include>
|
||||
<extension name="enum">
|
||||
<condition field="${module_exists(mod_enum)}" expression="true"/>
|
||||
<condition field="destination_number" expression="^(.*)$">
|
||||
<action application="transfer" data="$1 enum"/>
|
||||
</condition>
|
||||
</extension>
|
||||
</include>
|
|
@ -3896,7 +3896,7 @@ SWITCH_STANDARD_API(ft_function)
|
|||
ftdm_channel_t *fchan = NULL;
|
||||
ftdm_span_t *span = NULL;
|
||||
if (argc < 2) {
|
||||
stream->write_function(stream, "-ERR Usage: oz notrace <span_id> [<chan_id>]\n");
|
||||
stream->write_function(stream, "-ERR Usage: ftdm notrace <span_id> [<chan_id>]\n");
|
||||
goto end;
|
||||
}
|
||||
ftdm_span_find_by_name(argv[1], &span);
|
||||
|
|
|
@ -1805,6 +1805,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id,
|
|||
status = FTDM_SUCCESS;
|
||||
}
|
||||
ftdm_set_flag(check, FTDM_CHANNEL_INUSE);
|
||||
ftdm_set_flag(check, FTDM_CHANNEL_OUTBOUND);
|
||||
*ftdmchan = check;
|
||||
}
|
||||
|
||||
|
|
|
@ -207,6 +207,13 @@ struct t30_state_s
|
|||
/*! \brief This is only used in full duplex (e.g. ISDN) modes. */
|
||||
int timer_t8;
|
||||
|
||||
/* These fields are guessed based on compiler error forensics, I added them to fix the build -anthm */
|
||||
int remote_interrupts_allowed;
|
||||
int rtp_events;
|
||||
int rtn_events;
|
||||
int retransmit_capable;
|
||||
/* end guessed fields */
|
||||
|
||||
/*! \brief TRUE once the far end FAX entity has been detected. */
|
||||
int far_end_detected;
|
||||
|
||||
|
|
|
@ -682,6 +682,8 @@ SPAN_DECLARE(void) t30_get_transfer_statistics(t30_state_t *s, t30_stats_t *t);
|
|||
\param state TRUE to enable interrupt request, else FALSE. */
|
||||
SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state);
|
||||
|
||||
SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2377,6 +2377,8 @@ static int send_response_to_pps(t30_state_t *s)
|
|||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#define VET_ALL_FCD_FRAMES
|
||||
|
||||
static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len)
|
||||
{
|
||||
int page;
|
||||
|
@ -2387,6 +2389,10 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len)
|
|||
int frame_no;
|
||||
int first_bad_frame;
|
||||
int image_ended;
|
||||
#if defined(VET_ALL_FCD_FRAMES)
|
||||
int first;
|
||||
int expected_len;
|
||||
#endif
|
||||
|
||||
if (len < 7)
|
||||
{
|
||||
|
@ -2469,12 +2475,35 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len)
|
|||
|
||||
/* Build a bit map of which frames we now have stored OK */
|
||||
first_bad_frame = 256;
|
||||
#if defined(VET_ALL_FCD_FRAMES)
|
||||
first = TRUE;
|
||||
expected_len = 256;
|
||||
#endif
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
s->ecm_frame_map[i + 3] = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
frame_no = (i << 3) + j;
|
||||
#if defined(VET_ALL_FCD_FRAMES)
|
||||
if (s->ecm_len[frame_no] >= 0)
|
||||
{
|
||||
if (frame_no < s->ecm_frames - 1)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
if (s->ecm_len[frame_no] == 64)
|
||||
expected_len = 64;
|
||||
first = FALSE;
|
||||
}
|
||||
if (s->ecm_len[frame_no] != expected_len)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length ECM frame - %d\n", s->ecm_len[frame_no]);
|
||||
s->ecm_len[frame_no] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (s->ecm_len[frame_no] < 0)
|
||||
{
|
||||
s->ecm_frame_map[i + 3] |= (1 << j);
|
||||
|
@ -2524,14 +2553,18 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len)
|
|||
|
||||
switch (s->last_pps_fcf2)
|
||||
{
|
||||
case T30_NULL:
|
||||
case T30_EOP:
|
||||
case T30_PRI_EOP:
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOS:
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_PRI_EOM:
|
||||
case T30_PRI_EOP:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
}
|
||||
/* Fall through */
|
||||
case T30_NULL:
|
||||
case T30_MPS:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
case T30_EOP:
|
||||
if (s->receiver_not_ready_count > 0)
|
||||
{
|
||||
s->receiver_not_ready_count--;
|
||||
|
@ -2635,7 +2668,13 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len)
|
|||
switch (s->state)
|
||||
{
|
||||
case T30_STATE_F_DOC_ECM:
|
||||
if (len <= 4 + 256)
|
||||
if (len > 4 + 256)
|
||||
{
|
||||
/* For other frame types we kill the call on an unexpected frame length. For FCD frames it is better to just ignore
|
||||
the frame, and let retries sort things out. */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected %s frame length - %d\n", t30_frametype(msg[0]), len);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_no = msg[3];
|
||||
/* Just store the actual image data, and record its length */
|
||||
|
@ -2645,10 +2684,6 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len)
|
|||
/* In case we are just after a CTC/CTR exchange, which kicked us back to long training */
|
||||
s->short_train = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
unexpected_frame_length(s, msg, len);
|
||||
}
|
||||
/* We have received something, so any missing carrier status is out of date */
|
||||
if (s->current_status == T30_ERR_RX_NOCARRIER)
|
||||
s->current_status = T30_ERR_OK;
|
||||
|
@ -2677,6 +2712,7 @@ static void process_rx_rcp(t30_state_t *s, const uint8_t *msg, int len)
|
|||
case T30_STATE_F_POST_DOC_ECM:
|
||||
/* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance
|
||||
of receiving a correct one. */
|
||||
timer_t2_start(s);
|
||||
break;
|
||||
default:
|
||||
unexpected_non_final_frame(s, msg, len);
|
||||
|
@ -3063,6 +3099,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int
|
|||
case T30_DCS:
|
||||
process_rx_dcs(s, msg, len);
|
||||
break;
|
||||
case T30_PRI_MPS:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
}
|
||||
/* Fall through */
|
||||
case T30_MPS:
|
||||
/* Treat this as a bad quality page. */
|
||||
if (s->phase_d_handler)
|
||||
|
@ -3072,16 +3113,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int
|
|||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
send_simple_frame(s, T30_RTN);
|
||||
break;
|
||||
case T30_PRI_MPS:
|
||||
/* Treat this as a bad quality page. */
|
||||
if (s->phase_d_handler)
|
||||
case T30_PRI_EOM:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
s->next_rx_step = msg[2] & 0xFE;
|
||||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
break;
|
||||
/* Fall through */
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
/* Treat this as a bad quality page. */
|
||||
|
@ -3093,16 +3129,11 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int
|
|||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
send_simple_frame(s, T30_RTN);
|
||||
break;
|
||||
case T30_PRI_EOM:
|
||||
/* Treat this as a bad quality page. */
|
||||
if (s->phase_d_handler)
|
||||
case T30_PRI_EOP:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
s->next_rx_step = T30_PRI_EOM;
|
||||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
break;
|
||||
/* Fall through */
|
||||
case T30_EOP:
|
||||
/* Treat this as a bad quality page. */
|
||||
if (s->phase_d_handler)
|
||||
|
@ -3112,16 +3143,6 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int
|
|||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
send_simple_frame(s, T30_RTN);
|
||||
break;
|
||||
case T30_PRI_EOP:
|
||||
/* Treat this as a bad quality page. */
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
s->next_rx_step = msg[2] & 0xFE;
|
||||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
break;
|
||||
case T30_DCN:
|
||||
s->current_status = T30_ERR_RX_DCNDATA;
|
||||
disconnect(s);
|
||||
|
@ -3148,6 +3169,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg,
|
|||
fcf = msg[2] & 0xFE;
|
||||
switch (fcf)
|
||||
{
|
||||
case T30_PRI_MPS:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
}
|
||||
/* Fall through */
|
||||
case T30_MPS:
|
||||
s->next_rx_step = fcf;
|
||||
queue_phase(s, T30_PHASE_D_TX);
|
||||
|
@ -3179,41 +3205,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg,
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case T30_PRI_MPS:
|
||||
s->next_rx_step = fcf;
|
||||
switch (copy_quality(s))
|
||||
case T30_PRI_EOM:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
case T30_COPY_QUALITY_PERFECT:
|
||||
case T30_COPY_QUALITY_GOOD:
|
||||
rx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
terminate_operation_in_progress(s);
|
||||
set_state(s, T30_STATE_III_Q_MCF);
|
||||
break;
|
||||
case T30_COPY_QUALITY_POOR:
|
||||
rx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
terminate_operation_in_progress(s);
|
||||
set_state(s, T30_STATE_III_Q_RTP);
|
||||
break;
|
||||
case T30_COPY_QUALITY_BAD:
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Fall through */
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
s->next_rx_step = fcf;
|
||||
|
@ -3247,41 +3243,11 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg,
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case T30_PRI_EOM:
|
||||
s->next_rx_step = fcf;
|
||||
switch (copy_quality(s))
|
||||
case T30_PRI_EOP:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
case T30_COPY_QUALITY_PERFECT:
|
||||
case T30_COPY_QUALITY_GOOD:
|
||||
rx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
terminate_operation_in_progress(s);
|
||||
set_state(s, T30_STATE_III_Q_MCF);
|
||||
break;
|
||||
case T30_COPY_QUALITY_POOR:
|
||||
rx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
terminate_operation_in_progress(s);
|
||||
set_state(s, T30_STATE_III_Q_RTP);
|
||||
break;
|
||||
case T30_COPY_QUALITY_BAD:
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Fall through */
|
||||
case T30_EOP:
|
||||
s->next_rx_step = fcf;
|
||||
queue_phase(s, T30_PHASE_D_TX);
|
||||
|
@ -3312,41 +3278,6 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg,
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case T30_PRI_EOP:
|
||||
s->next_rx_step = fcf;
|
||||
switch (copy_quality(s))
|
||||
{
|
||||
case T30_COPY_QUALITY_PERFECT:
|
||||
case T30_COPY_QUALITY_GOOD:
|
||||
rx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
terminate_operation_in_progress(s);
|
||||
set_state(s, T30_STATE_III_Q_MCF);
|
||||
break;
|
||||
case T30_COPY_QUALITY_POOR:
|
||||
rx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
terminate_operation_in_progress(s);
|
||||
set_state(s, T30_STATE_III_Q_RTP);
|
||||
break;
|
||||
case T30_COPY_QUALITY_BAD:
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
set_state(s, T30_STATE_III_Q_RTN);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case T30_DCN:
|
||||
s->current_status = T30_ERR_RX_DCNFAX;
|
||||
disconnect(s);
|
||||
|
@ -3384,21 +3315,7 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t *
|
|||
case T4_RCP:
|
||||
/* Return to control for partial page. These might come through with or without the final frame tag.
|
||||
Here we deal with the "final frame tag" case. */
|
||||
if (s->state == T30_STATE_F_DOC_ECM)
|
||||
{
|
||||
/* Return to control for partial page */
|
||||
set_state(s, T30_STATE_F_POST_DOC_ECM);
|
||||
queue_phase(s, T30_PHASE_D_RX);
|
||||
timer_t2_start(s);
|
||||
/* We have received something, so any missing carrier status is out of date */
|
||||
if (s->current_status == T30_ERR_RX_NOCARRIER)
|
||||
s->current_status = T30_ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance
|
||||
of receiving a correct one. */
|
||||
}
|
||||
process_rx_rcp(s, msg, len);
|
||||
break;
|
||||
case T30_EOR:
|
||||
if (len != 4)
|
||||
|
@ -3413,7 +3330,10 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t *
|
|||
case T30_PRI_EOP:
|
||||
case T30_PRI_EOM:
|
||||
case T30_PRI_MPS:
|
||||
/* TODO: Alert operator */
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
/* TODO: Alert operator */
|
||||
}
|
||||
/* Fall through */
|
||||
case T30_NULL:
|
||||
case T30_EOP:
|
||||
|
@ -3651,11 +3571,22 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
fcf = msg[2] & 0xFE;
|
||||
switch (fcf)
|
||||
{
|
||||
case T30_PIP:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
case T30_MCF:
|
||||
switch (s->next_tx_step)
|
||||
{
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_MPS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -3668,8 +3599,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
set_state(s, T30_STATE_I);
|
||||
queue_phase(s, T30_PHASE_C_NON_ECM_TX);
|
||||
break;
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
|
@ -3678,8 +3609,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
report_tx_result(s, TRUE);
|
||||
return_to_phase_b(s, FALSE);
|
||||
break;
|
||||
case T30_EOP:
|
||||
case T30_PRI_EOP:
|
||||
case T30_EOP:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -3690,13 +3621,11 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
}
|
||||
break;
|
||||
case T30_RTP:
|
||||
#if 0
|
||||
s->rtp_events++;
|
||||
#endif
|
||||
switch (s->next_tx_step)
|
||||
{
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_MPS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -3717,8 +3646,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
queue_phase(s, T30_PHASE_B_TX);
|
||||
restart_sending_document(s);
|
||||
break;
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
|
@ -3727,8 +3656,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
/* TODO: should go back to T, and resend */
|
||||
return_to_phase_b(s, TRUE);
|
||||
break;
|
||||
case T30_EOP:
|
||||
case T30_PRI_EOP:
|
||||
case T30_EOP:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -3737,20 +3666,27 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case T30_PIN:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
case T30_RTN:
|
||||
#if 0
|
||||
s->rtn_events++;
|
||||
#endif
|
||||
switch (s->next_tx_step)
|
||||
{
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_MPS:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
#if 0
|
||||
if (!s->retransmit_capable)
|
||||
#endif
|
||||
{
|
||||
/* Send the next page, regardless of the problem with the current one. */
|
||||
if (tx_start_page(s))
|
||||
|
@ -3771,29 +3707,26 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
queue_phase(s, T30_PHASE_B_TX);
|
||||
restart_sending_document(s);
|
||||
break;
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
#if 0
|
||||
if (s->retransmit_capable)
|
||||
{
|
||||
/* Wait for DIS */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return_to_phase_b(s, TRUE);
|
||||
}
|
||||
break;
|
||||
case T30_EOP:
|
||||
case T30_PRI_EOP:
|
||||
case T30_EOP:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
#if 0
|
||||
if (s->retransmit_capable)
|
||||
{
|
||||
/* Send fresh training, and then repeat the last page */
|
||||
|
@ -3809,36 +3742,19 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
restart_sending_document(s);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
send_dcn(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case T30_PIP:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
break;
|
||||
case T30_PIN:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
break;
|
||||
case T30_DCN:
|
||||
switch (s->next_tx_step)
|
||||
{
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_MPS:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
/* Unexpected DCN after EOM, EOS or MPS sequence */
|
||||
s->current_status = T30_ERR_RX_DCNPHD;
|
||||
|
@ -4019,8 +3935,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le
|
|||
span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n");
|
||||
switch (s->next_tx_step)
|
||||
{
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_MPS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -4036,8 +3952,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le
|
|||
send_first_ecm_frame(s);
|
||||
}
|
||||
break;
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
|
@ -4046,8 +3962,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le
|
|||
report_tx_result(s, TRUE);
|
||||
return_to_phase_b(s, FALSE);
|
||||
break;
|
||||
case T30_EOP:
|
||||
case T30_PRI_EOP:
|
||||
case T30_EOP:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -4094,6 +4010,17 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
fcf = msg[2] & 0xFE;
|
||||
switch (fcf)
|
||||
{
|
||||
case T30_PIP:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
case T30_MCF:
|
||||
s->retries = 0;
|
||||
s->timer_t5 = 0;
|
||||
|
@ -4112,8 +4039,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n");
|
||||
switch (s->next_tx_step)
|
||||
{
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_MPS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -4129,8 +4056,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
send_first_ecm_frame(s);
|
||||
}
|
||||
break;
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
|
@ -4139,8 +4066,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
report_tx_result(s, TRUE);
|
||||
return_to_phase_b(s, FALSE);
|
||||
break;
|
||||
case T30_EOP:
|
||||
case T30_PRI_EOP:
|
||||
case T30_EOP:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -4158,22 +4085,6 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
set_state(s, T30_STATE_IV_PPS_RNR);
|
||||
send_rr(s);
|
||||
break;
|
||||
case T30_PIP:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
break;
|
||||
case T30_PIN:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
break;
|
||||
case T30_PPR:
|
||||
process_rx_ppr(s, msg, len);
|
||||
break;
|
||||
|
@ -4187,6 +4098,17 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len)
|
|||
case T30_FNV:
|
||||
process_rx_fnv(s, msg, len);
|
||||
break;
|
||||
case T30_PIN:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
/* We don't know what to do with this. */
|
||||
unexpected_final_frame(s, msg, len);
|
||||
|
@ -4203,6 +4125,17 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len
|
|||
fcf = msg[2] & 0xFE;
|
||||
switch (fcf)
|
||||
{
|
||||
case T30_PIP:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
case T30_MCF:
|
||||
s->retries = 0;
|
||||
s->timer_t5 = 0;
|
||||
|
@ -4221,8 +4154,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len
|
|||
span_log(&s->logging, SPAN_LOG_FLOW, "Moving on to the next page\n");
|
||||
switch (s->next_tx_step)
|
||||
{
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_MPS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -4238,8 +4171,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len
|
|||
send_first_ecm_frame(s);
|
||||
}
|
||||
break;
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
|
@ -4248,8 +4181,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len
|
|||
report_tx_result(s, TRUE);
|
||||
return_to_phase_b(s, FALSE);
|
||||
break;
|
||||
case T30_EOP:
|
||||
case T30_PRI_EOP:
|
||||
case T30_EOP:
|
||||
tx_end_page(s);
|
||||
if (s->phase_d_handler)
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
|
@ -4267,22 +4200,6 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len
|
|||
set_state(s, T30_STATE_IV_PPS_RNR);
|
||||
send_rr(s);
|
||||
break;
|
||||
case T30_PIP:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
break;
|
||||
case T30_PIN:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
break;
|
||||
case T30_DCN:
|
||||
s->current_status = T30_ERR_RX_DCNRRD;
|
||||
disconnect(s);
|
||||
|
@ -4293,6 +4210,17 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len
|
|||
case T30_FNV:
|
||||
process_rx_fnv(s, msg, len);
|
||||
break;
|
||||
case T30_PIN:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
/* We don't know what to do with this. */
|
||||
unexpected_final_frame(s, msg, len);
|
||||
|
@ -4345,14 +4273,6 @@ static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len)
|
|||
set_state(s, T30_STATE_IV_EOR_RNR);
|
||||
send_rr(s);
|
||||
break;
|
||||
case T30_PIN:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
break;
|
||||
case T30_ERR:
|
||||
/* TODO: Continue with the next message if MPS or EOM? */
|
||||
s->timer_t5 = 0;
|
||||
|
@ -4364,6 +4284,17 @@ static void process_state_iv_eor(t30_state_t *s, const uint8_t *msg, int len)
|
|||
case T30_FNV:
|
||||
process_rx_fnv(s, msg, len);
|
||||
break;
|
||||
case T30_PIN:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
/* We don't know what to do with this. */
|
||||
unexpected_final_frame(s, msg, len);
|
||||
|
@ -4386,14 +4317,6 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len
|
|||
set_state(s, T30_STATE_IV_EOR_RNR);
|
||||
send_rr(s);
|
||||
break;
|
||||
case T30_PIN:
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
break;
|
||||
case T30_ERR:
|
||||
/* TODO: Continue with the next message if MPS or EOM? */
|
||||
s->timer_t5 = 0;
|
||||
|
@ -4409,6 +4332,17 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len
|
|||
case T30_FNV:
|
||||
process_rx_fnv(s, msg, len);
|
||||
break;
|
||||
case T30_PIN:
|
||||
if (s->remote_interrupts_allowed)
|
||||
{
|
||||
s->retries = 0;
|
||||
if (s->phase_d_handler)
|
||||
{
|
||||
s->phase_d_handler(s, s->phase_d_user_data, fcf);
|
||||
s->timer_t3 = ms_to_samples(DEFAULT_TIMER_T3);
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
/* We don't know what to do with this. */
|
||||
unexpected_final_frame(s, msg, len);
|
||||
|
@ -4596,7 +4530,7 @@ static void process_rx_control_msg(t30_state_t *s, const uint8_t *msg, int len)
|
|||
/* The following handles context sensitive message types, which should
|
||||
occur at the end of message sequences. They should, therefore have
|
||||
the final frame flag set. */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "In state %d\n", s->state);
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Rx final frame in state %d\n", s->state);
|
||||
|
||||
switch (s->state)
|
||||
{
|
||||
|
@ -5082,11 +5016,11 @@ static void timer_t2_expired(t30_state_t *s)
|
|||
case T30_STATE_F_POST_RCP_MCF:
|
||||
switch (s->next_rx_step)
|
||||
{
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
/* We didn't receive a response to our T30_MCF after T30_EOM, so we must be OK
|
||||
to proceed to phase B, and pretty act like its the beginning of a call. */
|
||||
to proceed to phase B, and pretty much act like its the beginning of a call. */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Returning to phase B after %s\n", t30_frametype(s->next_rx_step));
|
||||
set_phase(s, T30_PHASE_B_TX);
|
||||
timer_t2_start(s);
|
||||
|
@ -5109,6 +5043,8 @@ static void timer_t2_expired(t30_state_t *s)
|
|||
case T30_STATE_F_POST_DOC_ECM:
|
||||
case T30_STATE_F_POST_DOC_NON_ECM:
|
||||
/* While waiting for next FAX page */
|
||||
/* Figure 5-2b/T.30 and note 7 says we should allow 1 to 3 tries at this point.
|
||||
The way we work now is effectively hard coding a 1 try limit */
|
||||
s->current_status = T30_ERR_RX_T2EXPMPS;
|
||||
break;
|
||||
#if 0
|
||||
|
@ -5873,8 +5809,8 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
{
|
||||
switch (s->next_rx_step)
|
||||
{
|
||||
case T30_MPS:
|
||||
case T30_PRI_MPS:
|
||||
case T30_MPS:
|
||||
/* We should now start to get another page */
|
||||
if (s->error_correcting_mode)
|
||||
{
|
||||
|
@ -5888,15 +5824,15 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status)
|
|||
}
|
||||
timer_t2_start(s);
|
||||
break;
|
||||
case T30_EOM:
|
||||
case T30_PRI_EOM:
|
||||
case T30_EOM:
|
||||
case T30_EOS:
|
||||
/* See if we get something back, before moving to phase B. */
|
||||
timer_t2_start(s);
|
||||
set_phase(s, T30_PHASE_D_RX);
|
||||
break;
|
||||
case T30_EOP:
|
||||
case T30_PRI_EOP:
|
||||
case T30_EOP:
|
||||
/* Wait for a DCN. */
|
||||
set_phase(s, T30_PHASE_D_RX);
|
||||
timer_t4_start(s);
|
||||
|
@ -6256,6 +6192,12 @@ SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state)
|
|||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state)
|
||||
{
|
||||
s->remote_interrupts_allowed = state;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
SPAN_DECLARE(int) t30_restart(t30_state_t *s)
|
||||
{
|
||||
s->phase = T30_PHASE_IDLE;
|
||||
|
@ -6276,10 +6218,9 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s)
|
|||
/* The page number is only reset at call establishment */
|
||||
s->rx_page_number = 0;
|
||||
s->tx_page_number = 0;
|
||||
#if 0
|
||||
s->rtn_events = 0;
|
||||
s->rtp_events = 0;
|
||||
#endif
|
||||
s->local_interrupt_pending = FALSE;
|
||||
s->far_end_detected = FALSE;
|
||||
s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0);
|
||||
if (s->calling_party)
|
||||
|
|
|
@ -2602,7 +2602,9 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s,
|
|||
t38_tx_packet_handler_t *tx_t38_packet_handler,
|
||||
void *tx_t38_packet_user_data)
|
||||
{
|
||||
#if 0
|
||||
v8_parms_t v8_parms;
|
||||
#endif
|
||||
int alloced;
|
||||
|
||||
if (at_tx_handler == NULL || modem_control_handler == NULL)
|
||||
|
|
|
@ -426,7 +426,6 @@ static int set_next_tx_type(t38_gateway_state_t *s)
|
|||
t38_gateway_hdlc_state_t *u;
|
||||
|
||||
t = &s->audio.modems;
|
||||
u = &s->core.hdlc_to_modem;
|
||||
t38_non_ecm_buffer_report_output_status(&s->core.non_ecm_to_modem, &s->logging);
|
||||
if (t->next_tx_handler)
|
||||
{
|
||||
|
@ -447,6 +446,7 @@ static int set_next_tx_type(t38_gateway_state_t *s)
|
|||
return TRUE;
|
||||
}
|
||||
/*endif*/
|
||||
u = &s->core.hdlc_to_modem;
|
||||
if (u->in == u->out)
|
||||
return FALSE;
|
||||
/*endif*/
|
||||
|
@ -1057,7 +1057,9 @@ static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_n
|
|||
static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indicator)
|
||||
{
|
||||
t38_gateway_state_t *s;
|
||||
|
||||
t38_gateway_hdlc_state_t *u;
|
||||
int immediate;
|
||||
|
||||
s = (t38_gateway_state_t *) user_data;
|
||||
|
||||
t38_non_ecm_buffer_report_input_status(&s->core.non_ecm_to_modem, &s->logging);
|
||||
|
@ -1067,25 +1069,50 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
|
|||
return 0;
|
||||
}
|
||||
/*endif*/
|
||||
if (s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents)
|
||||
|
||||
u = &s->core.hdlc_to_modem;
|
||||
immediate = (u->in == u->out);
|
||||
if (u->buf[u->in].contents)
|
||||
{
|
||||
if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS)
|
||||
s->core.hdlc_to_modem.in = 0;
|
||||
if (++u->in >= T38_TX_HDLC_BUFS)
|
||||
u->in = 0;
|
||||
/*endif*/
|
||||
}
|
||||
/*endif*/
|
||||
s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents = (indicator | FLAG_INDICATOR);
|
||||
if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS)
|
||||
s->core.hdlc_to_modem.in = 0;
|
||||
u->buf[u->in].contents = (indicator | FLAG_INDICATOR);
|
||||
if (++u->in >= T38_TX_HDLC_BUFS)
|
||||
u->in = 0;
|
||||
/*endif*/
|
||||
t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits);
|
||||
|
||||
span_log(&s->logging,
|
||||
SPAN_LOG_FLOW,
|
||||
"Queued change - (%d) %s -> %s\n",
|
||||
silence_gen_remainder(&(s->audio.modems.silence_gen)),
|
||||
t38_indicator_to_str(t->current_rx_indicator),
|
||||
t38_indicator_to_str(indicator));
|
||||
if (immediate)
|
||||
{
|
||||
span_log(&s->logging,
|
||||
SPAN_LOG_FLOW,
|
||||
"Changing - (%d) %s -> %s\n",
|
||||
silence_gen_remainder(&(s->audio.modems.silence_gen)),
|
||||
t38_indicator_to_str(t->current_rx_indicator),
|
||||
t38_indicator_to_str(indicator));
|
||||
switch (s->t38x.current_rx_field_class)
|
||||
{
|
||||
case T38_FIELD_CLASS_NONE:
|
||||
break;
|
||||
case T38_FIELD_CLASS_HDLC:
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC shutdown\n");
|
||||
hdlc_tx_frame(&s->audio.modems.hdlc_tx, NULL, 0);
|
||||
break;
|
||||
case T38_FIELD_CLASS_NON_ECM:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
span_log(&s->logging,
|
||||
SPAN_LOG_FLOW,
|
||||
"Queued change - (%d) %s -> %s\n",
|
||||
silence_gen_remainder(&(s->audio.modems.silence_gen)),
|
||||
t38_indicator_to_str(t->current_rx_indicator),
|
||||
t38_indicator_to_str(indicator));
|
||||
}
|
||||
s->t38x.current_rx_field_class = T38_FIELD_CLASS_NONE;
|
||||
/* We need to set this here, since we might have been called as a fake
|
||||
indication when the real one was missing */
|
||||
|
@ -1440,6 +1467,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
|
|||
xx->corrupt_current_frame[0] = FALSE;
|
||||
break;
|
||||
case T38_FIELD_T4_NON_ECM_DATA:
|
||||
if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE)
|
||||
t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits);
|
||||
xx->current_rx_field_class = T38_FIELD_CLASS_NON_ECM;
|
||||
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
|
||||
if (hdlc_buf->contents != (data_type | FLAG_DATA))
|
||||
|
@ -1454,6 +1483,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
|
|||
xx->corrupt_current_frame[0] = FALSE;
|
||||
break;
|
||||
case T38_FIELD_T4_NON_ECM_SIG_END:
|
||||
if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE)
|
||||
t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits);
|
||||
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
|
||||
/* Some T.38 implementations send multiple T38_FIELD_T4_NON_ECM_SIG_END messages, in IFP packets with
|
||||
incrementing sequence numbers, which are actually repeats. They get through to this point because
|
||||
|
@ -2432,8 +2463,8 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s,
|
|||
|
||||
s->core.to_t38.octets_per_data_packet = 1;
|
||||
s->core.ecm_allowed = TRUE;
|
||||
t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0);
|
||||
//s->core.ms_per_tx_chunk = DEFAULT_MS_PER_TX_CHUNK;
|
||||
t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0);
|
||||
restart_rx_modem(s);
|
||||
s->core.timed_mode = TIMED_MODE_STARTUP;
|
||||
s->core.samples_to_timeout = 1;
|
||||
|
|
|
@ -111,7 +111,7 @@ static const struct dtmf_to_ascii_s dtmf_to_ascii[] =
|
|||
{"##8", 'W'},
|
||||
{"##9", 'Z'},
|
||||
{"##0", ' '},
|
||||
#if defined(WIN32) || ( defined(__SVR4) && defined (__sun))
|
||||
#if defined(WIN32) || ( defined(__SVR4) && defined (__sun))
|
||||
{"#*1", 'X'}, // (Note 1) 111 1011
|
||||
{"#*2", 'X'}, // (Note 1) 111 1100
|
||||
{"#*3", 'X'}, // (Note 1) 111 1101
|
||||
|
|
|
@ -103,6 +103,7 @@ SWITCH_BEGIN_EXTERN_C
|
|||
switch_caller_profile_flag_t flags;
|
||||
struct switch_caller_profile *originator_caller_profile;
|
||||
struct switch_caller_profile *originatee_caller_profile;
|
||||
struct switch_caller_profile *origination_caller_profile;
|
||||
struct switch_caller_profile *hunt_caller_profile;
|
||||
struct switch_channel_timetable *times;
|
||||
struct switch_caller_extension *caller_extension;
|
||||
|
|
|
@ -215,6 +215,20 @@ SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel
|
|||
*/
|
||||
SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originatee_caller_profile(switch_channel_t *channel);
|
||||
|
||||
/*!
|
||||
\brief Set the given channel's origination caller profile
|
||||
\param channel channel to assign the profile to
|
||||
\param caller_profile the profile to assign
|
||||
*/
|
||||
SWITCH_DECLARE(void) switch_channel_set_origination_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile);
|
||||
|
||||
/*!
|
||||
\brief Retrive the given channel's origination caller profile
|
||||
\param channel channel to retrive the profile from
|
||||
\return the requested profile
|
||||
*/
|
||||
SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_origination_caller_profile(switch_channel_t *channel);
|
||||
|
||||
|
||||
/*!
|
||||
\brief Retrive the given channel's unique id
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#define CC_AGENT_TYPE_UUID_STANDBY "uuid-standby"
|
||||
#define CC_SQLITE_DB_NAME "callcenter"
|
||||
|
||||
#define CC_MAX_TIME_DIFF_CHECK 5
|
||||
/* TODO
|
||||
drop caller if no agent login
|
||||
dont allow new caller
|
||||
|
@ -53,6 +54,16 @@ SWITCH_MODULE_DEFINITION(mod_callcenter, mod_callcenter_load, mod_callcenter_shu
|
|||
|
||||
static const char *global_cf = "callcenter.conf";
|
||||
|
||||
struct cc_status_table {
|
||||
const char *name;
|
||||
int status;
|
||||
};
|
||||
|
||||
struct cc_state_table {
|
||||
const char *name;
|
||||
int state;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CC_STATUS_SUCCESS,
|
||||
CC_STATUS_FALSE,
|
||||
|
@ -77,12 +88,7 @@ typedef enum {
|
|||
CC_TIER_STATE_STANDBY = 5
|
||||
} cc_tier_state_t;
|
||||
|
||||
struct cc_tier_state_table {
|
||||
const char *name;
|
||||
cc_tier_state_t state;
|
||||
};
|
||||
|
||||
static struct cc_tier_state_table STATE_CHART[] = {
|
||||
static struct cc_state_table STATE_CHART[] = {
|
||||
{"Unknown", CC_TIER_STATE_UNKNOWN},
|
||||
{"No Answer", CC_TIER_STATE_NO_ANSWER},
|
||||
{"Ready", CC_TIER_STATE_READY},
|
||||
|
@ -101,12 +107,7 @@ typedef enum {
|
|||
CC_AGENT_STATUS_ON_BREAK = 4
|
||||
} cc_agent_status_t;
|
||||
|
||||
struct cc_agent_status_table {
|
||||
const char *name;
|
||||
cc_agent_status_t status;
|
||||
};
|
||||
|
||||
static struct cc_agent_status_table AGENT_STATUS_CHART[] = {
|
||||
static struct cc_status_table AGENT_STATUS_CHART[] = {
|
||||
{"Unknown", CC_AGENT_STATUS_UNKNOWN},
|
||||
{"Logged Out", CC_AGENT_STATUS_LOGGED_OUT},
|
||||
{"Available", CC_AGENT_STATUS_AVAILABLE},
|
||||
|
@ -124,12 +125,7 @@ typedef enum {
|
|||
CC_AGENT_STATE_IDLE = 4
|
||||
} cc_agent_state_t;
|
||||
|
||||
struct cc_agent_state_table {
|
||||
const char *name;
|
||||
cc_agent_state_t state;
|
||||
};
|
||||
|
||||
static struct cc_agent_state_table AGENT_STATE_CHART[] = {
|
||||
static struct cc_state_table AGENT_STATE_CHART[] = {
|
||||
{"Unknown", CC_AGENT_STATE_UNKNOWN},
|
||||
{"Waiting", CC_AGENT_STATE_WAITING},
|
||||
{"Receiving", CC_AGENT_STATE_RECEIVING},
|
||||
|
@ -147,12 +143,7 @@ typedef enum {
|
|||
CC_MEMBER_STATE_ABANDONED = 4
|
||||
} cc_member_state_t;
|
||||
|
||||
struct cc_member_state_table {
|
||||
const char *name;
|
||||
cc_member_state_t state;
|
||||
};
|
||||
|
||||
static struct cc_member_state_table MEMBER_STATE_CHART[] = {
|
||||
static struct cc_state_table MEMBER_STATE_CHART[] = {
|
||||
{"Unknown", CC_MEMBER_STATE_UNKNOWN},
|
||||
{"Waiting", CC_MEMBER_STATE_WAITING},
|
||||
{"Trying", CC_MEMBER_STATE_TRYING},
|
||||
|
@ -162,10 +153,24 @@ static struct cc_member_state_table MEMBER_STATE_CHART[] = {
|
|||
|
||||
};
|
||||
|
||||
/*static char queues_sql[] =
|
||||
"CREATE TABLE queues (\n"
|
||||
" name VARCHAR(255)\n" ");\n";
|
||||
*/
|
||||
struct cc_member_cancel_reason_table {
|
||||
const char *name;
|
||||
int reason;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CC_MEMBER_CANCEL_REASON_NONE,
|
||||
CC_MEMBER_CANCEL_REASON_TIMEOUT,
|
||||
CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT
|
||||
} cc_member_cancel_reason_t;
|
||||
|
||||
static struct cc_member_cancel_reason_table MEMBER_CANCEL_REASON_CHART[] = {
|
||||
{"NONE", CC_MEMBER_CANCEL_REASON_NONE},
|
||||
{"TIMEOUT", CC_MEMBER_CANCEL_REASON_TIMEOUT},
|
||||
{"NO_AGENT_TIMEOUT", CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static char members_sql[] =
|
||||
"CREATE TABLE members (\n"
|
||||
" queue VARCHAR(255),\n"
|
||||
|
@ -222,7 +227,6 @@ static char agents_sql[] =
|
|||
" ready_time INTEGER NOT NULL DEFAULT 0\n"
|
||||
");\n";
|
||||
|
||||
|
||||
static char tiers_sql[] =
|
||||
"CREATE TABLE tiers (\n"
|
||||
" queue VARCHAR(255),\n"
|
||||
|
@ -247,7 +251,7 @@ const char * cc_tier_state2str(cc_tier_state_t state)
|
|||
uint8_t x;
|
||||
const char *str = "Unknown";
|
||||
|
||||
for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_tier_state_table)) - 1; x++) {
|
||||
for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) {
|
||||
if (STATE_CHART[x].state == state) {
|
||||
str = STATE_CHART[x].name;
|
||||
break;
|
||||
|
@ -262,7 +266,7 @@ cc_tier_state_t cc_tier_str2state(const char *str)
|
|||
uint8_t x;
|
||||
cc_tier_state_t state = CC_TIER_STATE_UNKNOWN;
|
||||
|
||||
for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_tier_state_table)) - 1 && STATE_CHART[x].name; x++) {
|
||||
for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct cc_state_table)) - 1 && STATE_CHART[x].name; x++) {
|
||||
if (!strcasecmp(STATE_CHART[x].name, str)) {
|
||||
state = STATE_CHART[x].state;
|
||||
break;
|
||||
|
@ -271,12 +275,41 @@ cc_tier_state_t cc_tier_str2state(const char *str)
|
|||
return state;
|
||||
}
|
||||
|
||||
const char * cc_member_cancel_reason2str(cc_member_cancel_reason_t reason)
|
||||
{
|
||||
uint8_t x;
|
||||
const char *str = "NONE";
|
||||
|
||||
for (x = 0; x < (sizeof(MEMBER_CANCEL_REASON_CHART) / sizeof(struct cc_member_cancel_reason_table)) - 1; x++) {
|
||||
if (MEMBER_CANCEL_REASON_CHART[x].reason == reason) {
|
||||
str = MEMBER_CANCEL_REASON_CHART[x].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
cc_member_cancel_reason_t cc_member_cancel_str2reason(const char *str)
|
||||
{
|
||||
uint8_t x;
|
||||
cc_member_cancel_reason_t reason = CC_MEMBER_CANCEL_REASON_NONE;
|
||||
|
||||
for (x = 0; x < (sizeof(MEMBER_CANCEL_REASON_CHART) / sizeof(struct cc_member_cancel_reason_table)) - 1 && MEMBER_CANCEL_REASON_CHART[x].name; x++) {
|
||||
if (!strcasecmp(MEMBER_CANCEL_REASON_CHART[x].name, str)) {
|
||||
reason = MEMBER_CANCEL_REASON_CHART[x].reason;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
|
||||
const char * cc_agent_status2str(cc_agent_status_t status)
|
||||
{
|
||||
uint8_t x;
|
||||
const char *str = "Unknown";
|
||||
|
||||
for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_agent_status_table)) - 1; x++) {
|
||||
for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_status_table)) - 1; x++) {
|
||||
if (AGENT_STATUS_CHART[x].status == status) {
|
||||
str = AGENT_STATUS_CHART[x].name;
|
||||
break;
|
||||
|
@ -291,7 +324,7 @@ cc_agent_status_t cc_agent_str2status(const char *str)
|
|||
uint8_t x;
|
||||
cc_agent_status_t status = CC_AGENT_STATUS_UNKNOWN;
|
||||
|
||||
for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_agent_status_table)) - 1 && AGENT_STATUS_CHART[x].name; x++) {
|
||||
for (x = 0; x < (sizeof(AGENT_STATUS_CHART) / sizeof(struct cc_status_table)) - 1 && AGENT_STATUS_CHART[x].name; x++) {
|
||||
if (!strcasecmp(AGENT_STATUS_CHART[x].name, str)) {
|
||||
status = AGENT_STATUS_CHART[x].status;
|
||||
break;
|
||||
|
@ -305,7 +338,7 @@ const char * cc_agent_state2str(cc_agent_state_t state)
|
|||
uint8_t x;
|
||||
const char *str = "Unknown";
|
||||
|
||||
for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_agent_state_table)) - 1; x++) {
|
||||
for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) {
|
||||
if (AGENT_STATE_CHART[x].state == state) {
|
||||
str = AGENT_STATE_CHART[x].name;
|
||||
break;
|
||||
|
@ -320,7 +353,7 @@ cc_agent_state_t cc_agent_str2state(const char *str)
|
|||
uint8_t x;
|
||||
cc_agent_state_t state = CC_AGENT_STATE_UNKNOWN;
|
||||
|
||||
for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_agent_state_table)) - 1 && AGENT_STATE_CHART[x].name; x++) {
|
||||
for (x = 0; x < (sizeof(AGENT_STATE_CHART) / sizeof(struct cc_state_table)) - 1 && AGENT_STATE_CHART[x].name; x++) {
|
||||
if (!strcasecmp(AGENT_STATE_CHART[x].name, str)) {
|
||||
state = AGENT_STATE_CHART[x].state;
|
||||
break;
|
||||
|
@ -334,7 +367,7 @@ const char * cc_member_state2str(cc_member_state_t state)
|
|||
uint8_t x;
|
||||
const char *str = "Unknown";
|
||||
|
||||
for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_member_state_table)) - 1; x++) {
|
||||
for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_state_table)) - 1; x++) {
|
||||
if (MEMBER_STATE_CHART[x].state == state) {
|
||||
str = MEMBER_STATE_CHART[x].name;
|
||||
break;
|
||||
|
@ -349,7 +382,7 @@ cc_member_state_t cc_member_str2state(const char *str)
|
|||
uint8_t x;
|
||||
cc_member_state_t state = CC_MEMBER_STATE_UNKNOWN;
|
||||
|
||||
for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_member_state_table)) - 1 && MEMBER_STATE_CHART[x].name; x++) {
|
||||
for (x = 0; x < (sizeof(MEMBER_STATE_CHART) / sizeof(struct cc_state_table)) - 1 && MEMBER_STATE_CHART[x].name; x++) {
|
||||
if (!strcasecmp(MEMBER_STATE_CHART[x].name, str)) {
|
||||
state = MEMBER_STATE_CHART[x].state;
|
||||
break;
|
||||
|
@ -384,19 +417,27 @@ struct cc_queue {
|
|||
char *moh;
|
||||
char *record_template;
|
||||
char *time_base_score;
|
||||
|
||||
switch_bool_t tier_rules_apply;
|
||||
uint32_t tier_rule_wait_second;
|
||||
switch_bool_t tier_rule_wait_multiply_level;
|
||||
switch_bool_t tier_rule_no_agent_no_wait;
|
||||
|
||||
uint32_t discard_abandoned_after;
|
||||
switch_bool_t abandoned_resume_allowed;
|
||||
|
||||
uint32_t max_wait_time;
|
||||
uint32_t max_wait_time_with_no_agent;
|
||||
|
||||
switch_mutex_t *mutex;
|
||||
|
||||
switch_thread_rwlock_t *rwlock;
|
||||
switch_memory_pool_t *pool;
|
||||
uint32_t flags;
|
||||
|
||||
switch_time_t last_agent_exist;
|
||||
switch_time_t last_agent_exist_check;
|
||||
|
||||
switch_xml_config_item_t config[CC_QUEUE_CONFIGITEM_COUNT];
|
||||
switch_xml_config_string_options_t config_str_pool;
|
||||
|
||||
|
@ -488,6 +529,7 @@ cc_queue_t *queue_set_config(cc_queue_t *queue)
|
|||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "moh-sound", SWITCH_CONFIG_STRING, 0, &queue->moh, NULL, &queue->config_str_pool, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "record-template", SWITCH_CONFIG_STRING, 0, &queue->record_template, NULL, &queue->config_str_pool, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "time-base-score", SWITCH_CONFIG_STRING, 0, &queue->time_base_score, "queue", &queue->config_str_pool, NULL, NULL);
|
||||
|
||||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rules-apply", SWITCH_CONFIG_BOOL, 0, &queue->tier_rules_apply, SWITCH_FALSE, NULL, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rule-wait-second", SWITCH_CONFIG_INT, 0, &queue->tier_rule_wait_second, 0, &config_int_0_86400, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "tier-rule-wait-multiply-level", SWITCH_CONFIG_BOOL, 0, &queue->tier_rule_wait_multiply_level, SWITCH_FALSE, NULL, NULL, NULL);
|
||||
|
@ -495,6 +537,9 @@ cc_queue_t *queue_set_config(cc_queue_t *queue)
|
|||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "discard-abandoned-after", SWITCH_CONFIG_INT, 0, &queue->discard_abandoned_after, 60, &config_int_0_86400, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "abandoned-resume-allowed", SWITCH_CONFIG_BOOL, 0, &queue->abandoned_resume_allowed, SWITCH_FALSE, NULL, NULL, NULL);
|
||||
|
||||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "max-wait-time", SWITCH_CONFIG_INT, 0, &queue->max_wait_time, 0, &config_int_0_86400, NULL, NULL);
|
||||
SWITCH_CONFIG_SET_ITEM(queue->config[i++], "max-wait-time-with-no-agent", SWITCH_CONFIG_INT, 0, &queue->max_wait_time_with_no_agent, 0, &config_int_0_86400, NULL, NULL);
|
||||
|
||||
switch_assert(i < CC_QUEUE_CONFIGITEM_COUNT);
|
||||
|
||||
return queue;
|
||||
|
@ -646,6 +691,9 @@ static cc_queue_t *load_queue(const char *queue_name)
|
|||
switch_thread_rwlock_create(&queue->rwlock, pool);
|
||||
queue->name = switch_core_strdup(pool, queue_name);
|
||||
|
||||
queue->last_agent_exist = 0;
|
||||
queue->last_agent_exist_check = 0;
|
||||
|
||||
if (!(dbh = cc_get_db_handle())) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n");
|
||||
goto end;
|
||||
|
@ -702,7 +750,7 @@ static cc_queue_t *get_queue(const char *queue_name)
|
|||
|
||||
struct call_helper {
|
||||
const char *member_uuid;
|
||||
const char *queue;
|
||||
const char *queue_name;
|
||||
const char *queue_strategy;
|
||||
const char *member_joined_epoch;
|
||||
const char *member_caller_name;
|
||||
|
@ -744,7 +792,7 @@ int cc_queue_count(const char *queue)
|
|||
count = atoi(res);
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Selection", event_name);
|
||||
|
@ -827,7 +875,7 @@ cc_agent_status_t cc_agent_get(const char *key, const char *agent, char *ret_res
|
|||
result = CC_STATUS_SUCCESS;
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-get");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", res);
|
||||
switch_event_fire(&event);
|
||||
|
@ -894,7 +942,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
|
|||
result = CC_STATUS_SUCCESS;
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-status-change");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Status", value);
|
||||
switch_event_fire(&event);
|
||||
|
@ -918,7 +966,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
|
|||
result = CC_STATUS_SUCCESS;
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", agent);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", agent);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-state-change");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-State", value);
|
||||
switch_event_fire(&event);
|
||||
|
@ -1118,13 +1166,13 @@ done:
|
|||
return result;
|
||||
}
|
||||
|
||||
cc_status_t cc_tier_del(const char *queue, const char *agent)
|
||||
cc_status_t cc_tier_del(const char *queue_name, const char *agent)
|
||||
{
|
||||
cc_status_t result = CC_STATUS_SUCCESS;
|
||||
char *sql;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted tier Agent %s in Queue %s\n", agent, queue);
|
||||
sql = switch_mprintf("DELETE FROM tiers WHERE queue = '%q' AND agent = '%q';", queue, agent);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted tier Agent %s in Queue %s\n", agent, queue_name);
|
||||
sql = switch_mprintf("DELETE FROM tiers WHERE queue = '%q' AND agent = '%q';", queue_name, agent);
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
|
||||
|
@ -1307,7 +1355,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
}
|
||||
if (!strcasecmp(h->agent_type, CC_AGENT_TYPE_CALLBACK)) {
|
||||
switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue_name);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_uuid", "%s", h->member_uuid);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_member_pre_answer_uuid", "%s", h->member_uuid);
|
||||
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent", "%s", h->agent_name);
|
||||
|
@ -1327,7 +1375,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
switch_event_t *event;
|
||||
const char *cc_warning_tone = switch_channel_get_variable(agent_channel, "cc_warning_tone");
|
||||
|
||||
switch_channel_set_variable(agent_channel, "cc_queue", h->queue);
|
||||
switch_channel_set_variable(agent_channel, "cc_queue", h->queue_name);
|
||||
switch_channel_set_variable(agent_channel, "cc_agent", h->agent_name);
|
||||
switch_channel_set_variable(agent_channel, "cc_agent_type", h->agent_type);
|
||||
switch_channel_set_variable(agent_channel, "cc_member_uuid", h->member_uuid);
|
||||
|
@ -1384,7 +1432,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_event_set_data(agent_channel, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-start");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
|
||||
|
@ -1407,11 +1455,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
switch_safe_free(sql);
|
||||
|
||||
/* Change the agents Status in the tiers */
|
||||
sql = switch_mprintf("UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q'",
|
||||
cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), h->agent_name, h->queue);
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
|
||||
cc_tier_update("state", cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), h->queue_name, h->agent_name);
|
||||
cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_IN_A_QUEUE_CALL), h->agent_name);
|
||||
|
||||
/* Record session if record-template is provided */
|
||||
|
@ -1424,10 +1468,13 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
}
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s answered \"%s\" (%s) from queue %s%s\n",
|
||||
h->agent_name, h->member_caller_name, h->member_caller_number, h->queue, (h->record_template?" (Recorded)":""));
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s answered \"%s\" <%s> from queue %s%s\n",
|
||||
h->agent_name, h->member_caller_name, h->member_caller_number, h->queue_name, (h->record_template?" (Recorded)":""));
|
||||
switch_ivr_uuid_bridge(h->member_uuid, switch_core_session_get_uuid(agent_session));
|
||||
|
||||
/* This is used for the waiting caller to quit waiting for a agent */
|
||||
switch_channel_set_variable(member_channel, "cc_agent_uuid", agent_uuid);
|
||||
|
||||
/* Wait until the member hangup or the agent hangup. This will quit also if the agent transfer the call */
|
||||
while(switch_channel_up(member_channel) && switch_channel_up(agent_channel) && globals.running) {
|
||||
switch_yield(100000);
|
||||
|
@ -1436,7 +1483,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_event_set_data(agent_channel, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-end");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
|
||||
|
@ -1452,7 +1499,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
/* Update Agents Items */
|
||||
/* Do not remove uuid of the agent if we are a standby agent */
|
||||
sql = switch_mprintf("UPDATE agents SET %q last_bridge_end = %ld, talk_time = talk_time + (%ld-last_bridge_start) WHERE name = '%q' AND system = '%q';"
|
||||
, (strcasecmp(h->agent_type, "uuid-standby")?"uuid = '',":""), (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system);
|
||||
, (strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)?"uuid = '',":""), (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system);
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
|
||||
|
@ -1464,7 +1511,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
/* Caller off event */
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_event_set_data(member_channel, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", h->queue);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Terminated");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answer-Time", "%ld", (long) (t_agent_answered - t_agent_called));
|
||||
|
@ -1472,8 +1519,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
|
|||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Talk-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_agent_answered));
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Total-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name",
|
||||
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number",
|
||||
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")));
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
|
@ -1538,8 +1587,8 @@ done:
|
|||
sql = switch_mprintf(
|
||||
"UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q' AND (state = '%q' OR state = '%q' OR state = '%q');"
|
||||
"UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q'"
|
||||
, cc_tier_state2str(tiers_state), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), cc_tier_state2str(CC_TIER_STATE_STANDBY), cc_tier_state2str(CC_TIER_STATE_OFFERING),
|
||||
cc_tier_state2str(CC_TIER_STATE_READY), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_STANDBY));
|
||||
, cc_tier_state2str(tiers_state), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_ACTIVE_INBOUND), cc_tier_state2str(CC_TIER_STATE_STANDBY), cc_tier_state2str(CC_TIER_STATE_OFFERING),
|
||||
cc_tier_state2str(CC_TIER_STATE_READY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_STANDBY));
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
|
||||
|
@ -1567,7 +1616,7 @@ done:
|
|||
}
|
||||
|
||||
struct agent_callback {
|
||||
const char *queue;
|
||||
const char *queue_name;
|
||||
const char *system;
|
||||
const char *uuid;
|
||||
const char *caller_number;
|
||||
|
@ -1579,6 +1628,7 @@ struct agent_callback {
|
|||
uint32_t tier_rule_wait_second;
|
||||
switch_bool_t tier_rule_wait_multiply_level;
|
||||
switch_bool_t tier_rule_no_agent_no_wait;
|
||||
switch_bool_t agent_found;
|
||||
|
||||
int tier;
|
||||
int tier_agent_available;
|
||||
|
@ -1602,6 +1652,8 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
|
|||
|
||||
switch_bool_t contact_agent = SWITCH_TRUE;
|
||||
|
||||
cbt->agent_found = SWITCH_TRUE;
|
||||
|
||||
/* Check if we switch to a different tier, if so, check if we should continue further for that member */
|
||||
|
||||
if (cbt->tier_rules_apply == SWITCH_TRUE && atoi(agent_tier_level) > cbt->tier) {
|
||||
|
@ -1700,7 +1752,7 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
|
|||
h->member_joined_epoch = switch_core_strdup(h->pool, cbt->joined_epoch);
|
||||
h->member_caller_name = switch_core_strdup(h->pool, cbt->caller_name);
|
||||
h->member_caller_number = switch_core_strdup(h->pool, cbt->caller_number);
|
||||
h->queue = switch_core_strdup(h->pool, cbt->queue);
|
||||
h->queue_name = switch_core_strdup(h->pool, cbt->queue_name);
|
||||
h->record_template = switch_core_strdup(h->pool, cbt->record_template);
|
||||
h->no_answer_count = atoi(argv[4]);
|
||||
h->max_no_answer = atoi(argv[5]);
|
||||
|
@ -1713,8 +1765,8 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
|
|||
sql = switch_mprintf(
|
||||
"UPDATE tiers SET state = '%q' WHERE agent = '%q' AND queue = '%q';"
|
||||
"UPDATE tiers SET state = '%q' WHERE agent = '%q' AND NOT queue = '%q' AND state = '%q';",
|
||||
cc_tier_state2str(CC_TIER_STATE_OFFERING), h->agent_name, h->queue,
|
||||
cc_tier_state2str(CC_TIER_STATE_STANDBY), h->agent_name, h->queue, cc_tier_state2str(CC_TIER_STATE_READY));
|
||||
cc_tier_state2str(CC_TIER_STATE_OFFERING), h->agent_name, h->queue_name,
|
||||
cc_tier_state2str(CC_TIER_STATE_STANDBY), h->agent_name, h->queue_name, cc_tier_state2str(CC_TIER_STATE_READY));
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
|
||||
|
@ -1796,9 +1848,10 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
|
|||
cbt.caller_number = argv[2];
|
||||
cbt.caller_name = argv[3];
|
||||
cbt.joined_epoch = argv[4];
|
||||
cbt.queue = argv[0];
|
||||
cbt.queue_name = argv[0];
|
||||
cbt.strategy = queue_strategy;
|
||||
cbt.record_template = queue_record_template;
|
||||
cbt.agent_found = SWITCH_FALSE;
|
||||
|
||||
if (!strcasecmp(queue->strategy, "longest-idle-agent")) {
|
||||
sql_order_by = switch_mprintf("level, agents.last_offered_call, position");
|
||||
|
@ -1832,6 +1885,18 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
|
|||
switch_safe_free(sql);
|
||||
switch_safe_free(sql_order_by);
|
||||
|
||||
/* We update a field in the queue struct so we can kick caller out if waiting for too long with no agent */
|
||||
if (!argv[0] || !(queue = get_queue(argv[0]))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found locally, skip this member\n", argv[0]);
|
||||
goto end;
|
||||
} else {
|
||||
queue->last_agent_exist_check = switch_epoch_time_now(NULL);
|
||||
if (cbt.agent_found) {
|
||||
queue->last_agent_exist = queue->last_agent_exist_check;
|
||||
}
|
||||
queue_rwunlock(queue);
|
||||
}
|
||||
|
||||
end:
|
||||
switch_safe_free(queue_name);
|
||||
switch_safe_free(queue_strategy);
|
||||
|
@ -1911,30 +1976,53 @@ void cc_agent_dispatch_thread_start(void)
|
|||
switch_thread_create(&thread, thd_attr, cc_agent_dispatch_thread_run, NULL, globals.pool);
|
||||
}
|
||||
|
||||
struct member_helper {
|
||||
const char *uuid;
|
||||
struct member_thread_helper {
|
||||
const char *member_uuid;
|
||||
const char *queue_name;
|
||||
switch_time_t t_member_called;
|
||||
cc_member_cancel_reason_t member_cancel_reason;
|
||||
|
||||
int running;
|
||||
switch_memory_pool_t *pool;
|
||||
};
|
||||
|
||||
void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
struct member_helper *m = (struct member_helper *) obj;
|
||||
switch_core_session_t *member_session = switch_core_session_locate(m->uuid);
|
||||
switch_channel_t *channel = NULL;
|
||||
struct member_thread_helper *m = (struct member_thread_helper *) obj;
|
||||
switch_core_session_t *member_session = switch_core_session_locate(m->member_uuid);
|
||||
switch_channel_t *member_channel = NULL;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
globals.threads++;
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
if (member_session) {
|
||||
channel = switch_core_session_get_channel(member_session);
|
||||
member_channel = switch_core_session_get_channel(member_session);
|
||||
} else {
|
||||
switch_core_destroy_memory_pool(&m->pool);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while(switch_channel_ready(channel) && m->running && globals.running) {
|
||||
while(switch_channel_ready(member_channel) && m->running && globals.running) {
|
||||
cc_queue_t *queue = NULL;
|
||||
|
||||
if (!m->queue_name || !(queue = get_queue(m->queue_name))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Queue %s not found\n", m->queue_name);
|
||||
break;
|
||||
}
|
||||
/* Make the Caller Leave if he went over his max wait time */
|
||||
if (queue->max_wait_time > 0 && queue->max_wait_time <= switch_epoch_time_now(NULL) - m->t_member_called) {
|
||||
m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_TIMEOUT;
|
||||
switch_channel_set_flag_value(member_channel, CF_BREAK, 2);
|
||||
}
|
||||
|
||||
/* Will drop the caller if no agent was found for more than X secondes */
|
||||
if (queue->max_wait_time_with_no_agent > 0 && m->t_member_called < queue->last_agent_exist_check - CC_MAX_TIME_DIFF_CHECK &&
|
||||
queue->last_agent_exist_check - queue->last_agent_exist >= queue->max_wait_time_with_no_agent) {
|
||||
m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT;
|
||||
switch_channel_set_flag_value(member_channel, CF_BREAK, 2);
|
||||
}
|
||||
|
||||
/* TODO Go thought the list of phrases */
|
||||
/* SAMPLE CODE to playback something over the MOH
|
||||
|
||||
|
@ -1949,8 +2037,12 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj
|
|||
|
||||
/* If Agent Logoff, we might need to recalculare score based on skill */
|
||||
/* Play Announcement in order */
|
||||
switch_yield(100000);
|
||||
|
||||
queue_rwunlock(queue);
|
||||
|
||||
switch_yield(500000);
|
||||
}
|
||||
|
||||
switch_core_session_rwunlock(member_session);
|
||||
switch_core_destroy_memory_pool(&m->pool);
|
||||
|
||||
|
@ -1971,26 +2063,27 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
char *mydata = NULL;
|
||||
cc_queue_t *queue = NULL;
|
||||
const char *queue_name = NULL;
|
||||
switch_channel_t *member_channel = switch_core_session_get_channel(session);
|
||||
switch_core_session_t *member_session = session;
|
||||
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
|
||||
char *sql = NULL;
|
||||
char *uuid = switch_core_session_get_uuid(session);
|
||||
switch_input_args_t args = { 0 };
|
||||
struct member_helper *h = NULL;
|
||||
char *member_uuid = switch_core_session_get_uuid(member_session);
|
||||
struct member_thread_helper *h = NULL;
|
||||
switch_thread_t *thread;
|
||||
switch_threadattr_t *thd_attr = NULL;
|
||||
switch_memory_pool_t *pool;
|
||||
int cc_base_score_int = 0;
|
||||
switch_channel_timetable_t *times = NULL;
|
||||
const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score");
|
||||
const char *cc_moh_override = switch_channel_get_variable(member_channel, "cc_moh_override");
|
||||
const char *cc_base_score = switch_channel_get_variable(member_channel, "cc_base_score");
|
||||
int cc_base_score_int = 0;
|
||||
const char *cur_moh = NULL;
|
||||
char start_epoch[64];
|
||||
switch_event_t *event;
|
||||
switch_time_t t_member_called = switch_epoch_time_now(NULL);
|
||||
long abandoned_epoch = 0;
|
||||
const char *agent_uuid = NULL;
|
||||
|
||||
if (!zstr(data)) {
|
||||
mydata = switch_core_session_strdup(session, data);
|
||||
mydata = switch_core_session_strdup(member_session, data);
|
||||
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No Queue name provided\n");
|
||||
|
@ -2013,7 +2106,7 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
times = switch_channel_get_timetable(member_channel);
|
||||
switch_snprintf(start_epoch, sizeof(start_epoch), "%" SWITCH_TIME_T_FMT, times->answered / 1000000);
|
||||
|
||||
/* Check of we have a queued abandoned member we can resume from */
|
||||
/* Check if we support and have a queued abandoned member we can resume from */
|
||||
if (queue->abandoned_resume_allowed == SWITCH_TRUE) {
|
||||
char res[256];
|
||||
|
||||
|
@ -2037,9 +2130,9 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_event_set_data(member_channel, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-%s", (abandoned_epoch==0?"start":"resume"));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", uuid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", member_uuid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")));
|
||||
switch_event_fire(&event);
|
||||
|
@ -2054,7 +2147,7 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
" (queue,system,uuid,system_epoch,joined_epoch,base_score,skill_score,caller_number,caller_name,serving_agent,serving_system,state)"
|
||||
" VALUES('%q','single_box','%q','%q','%ld','%d','%d','%q','%q','%q','','%q')",
|
||||
queue_name,
|
||||
uuid,
|
||||
member_uuid,
|
||||
start_epoch,
|
||||
(long) switch_epoch_time_now(NULL),
|
||||
cc_base_score_int,
|
||||
|
@ -2069,12 +2162,12 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
char res[256];
|
||||
/* Update abandoned member */
|
||||
sql = switch_mprintf("UPDATE members SET uuid = '%q', state = '%q', rejoined_epoch = '%ld' WHERE caller_number = '%q' AND abandoned_epoch = '%ld' AND state = '%q' AND queue = '%q'",
|
||||
uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), (long) switch_epoch_time_now(NULL), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), abandoned_epoch, cc_member_state2str(CC_MEMBER_STATE_ABANDONED), queue_name);
|
||||
member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), (long) switch_epoch_time_now(NULL), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), abandoned_epoch, cc_member_state2str(CC_MEMBER_STATE_ABANDONED), queue_name);
|
||||
cc_execute_sql(queue, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
|
||||
/* Confirm we took that member in */
|
||||
sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND state = '%q' AND queue = '%q'", uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name);
|
||||
sql = switch_mprintf("SELECT abandoned_epoch FROM members WHERE uuid = '%q' AND state = '%q' AND queue = '%q'", member_uuid, cc_member_state2str(CC_MEMBER_STATE_WAITING), queue_name);
|
||||
cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
|
||||
switch_safe_free(sql);
|
||||
|
||||
|
@ -2092,9 +2185,14 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
/* Start Thread that will playback different prompt to the channel */
|
||||
switch_core_new_memory_pool(&pool);
|
||||
h = switch_core_alloc(pool, sizeof(*h));
|
||||
|
||||
h->pool = pool;
|
||||
h->uuid = switch_core_strdup(h->pool, uuid);
|
||||
h->member_uuid = switch_core_strdup(h->pool, member_uuid);
|
||||
h->queue_name = switch_core_strdup(h->pool, queue_name);
|
||||
h->t_member_called = t_member_called;
|
||||
h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NONE;
|
||||
h->running = 1;
|
||||
|
||||
switch_threadattr_create(&thd_attr, h->pool);
|
||||
switch_threadattr_detach_set(thd_attr, 1);
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
|
@ -2104,16 +2202,37 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
/* TODO Add DTMF callback support */
|
||||
/* TODO add MOH infitite loop */
|
||||
if (cc_moh_override) {
|
||||
cur_moh = switch_core_session_strdup(session, cc_moh_override);
|
||||
cur_moh = switch_core_session_strdup(member_session, cc_moh_override);
|
||||
} else {
|
||||
cur_moh = switch_core_session_strdup(session, queue->moh);
|
||||
cur_moh = switch_core_session_strdup(member_session, queue->moh);
|
||||
}
|
||||
queue_rwunlock(queue);
|
||||
|
||||
if (cur_moh) {
|
||||
switch_ivr_play_file(session, NULL, cur_moh, &args);
|
||||
} else {
|
||||
switch_ivr_collect_digits_callback(session, &args, 0, 0);
|
||||
while (switch_channel_ready(member_channel)) {
|
||||
switch_input_args_t args = { 0 };
|
||||
|
||||
/* An agent was found, time to exit and let the bridge do it job */
|
||||
if ((agent_uuid = switch_channel_get_variable(member_channel, "cc_agent_uuid"))) {
|
||||
break;
|
||||
}
|
||||
/* If the member thread set a different reason, we monitor it so we can quit the wait */
|
||||
if (h->member_cancel_reason != CC_MEMBER_CANCEL_REASON_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch_core_session_flush_private_events(member_session);
|
||||
|
||||
if (cur_moh) {
|
||||
switch_status_t status = switch_ivr_play_file(member_session, NULL, cur_moh, &args);
|
||||
|
||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
switch_ivr_collect_digits_callback(session, &args, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Stop Member Thread */
|
||||
|
@ -2123,33 +2242,42 @@ SWITCH_STANDARD_APP(callcenter_function)
|
|||
|
||||
/* Hangup any agents been callback */
|
||||
if (!switch_channel_up(member_channel)) { /* If channel is still up, it mean that the member didn't hangup, so we should leave the agent alone */
|
||||
switch_core_session_hupall_matching_var("cc_member_uuid", uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL);
|
||||
switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL);
|
||||
sql = switch_mprintf("UPDATE members SET state = '%q', uuid = '', abandoned_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'",
|
||||
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), uuid);
|
||||
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), member_uuid);
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
|
||||
/* Generate an Event and update some channel variable */
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_event_set_data(member_channel, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Wait-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Abort");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", uuid);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n",
|
||||
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")),
|
||||
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")),
|
||||
queue_name, cc_member_cancel_reason2str(h->member_cancel_reason));
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", cc_member_cancel_reason2str(h->member_cancel_reason));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", member_uuid);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")));
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
/* for xml_cdr needs */
|
||||
switch_channel_set_variable_printf(member_channel, "cc_queue_canceled_epoch", "%ld", (long) switch_epoch_time_now(NULL));
|
||||
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", cc_member_cancel_reason2str(h->member_cancel_reason));
|
||||
|
||||
|
||||
/* Send Event with queue count */
|
||||
cc_queue_count(queue_name);
|
||||
|
||||
} else {
|
||||
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered");
|
||||
sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'",
|
||||
cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), uuid);
|
||||
cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), member_uuid);
|
||||
cc_execute_sql(NULL, sql, NULL);
|
||||
switch_safe_free(sql);
|
||||
|
||||
|
@ -2525,7 +2653,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
|
|||
stream->write_function(stream, "%d\n", atoi(res));
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Name", queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res);
|
||||
switch_event_fire(&event);
|
||||
|
|
|
@ -697,7 +697,11 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
|
|||
|
||||
if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
|
||||
char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX);
|
||||
char *cid = generate_pai_str(session);
|
||||
char *cid = NULL;
|
||||
|
||||
if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID)) {
|
||||
cid = generate_pai_str(session);
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) {
|
||||
/* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless
|
||||
|
@ -1761,7 +1765,14 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
|||
nua_update(tech_pvt->nh,
|
||||
TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)),
|
||||
TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END());
|
||||
}
|
||||
} else if ((ua && (switch_stristr("cisco", ua)))) {
|
||||
snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <sip:%s@%s>", name, number, tech_pvt->profile->sipip);
|
||||
|
||||
sofia_set_flag_locked(tech_pvt, TFLAG_UPDATING_DISPLAY);
|
||||
nua_update(tech_pvt->nh,
|
||||
TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)),
|
||||
TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END());
|
||||
}
|
||||
|
||||
tech_pvt->last_sent_callee_id_name = switch_core_session_strdup(tech_pvt->session, name);
|
||||
tech_pvt->last_sent_callee_id_number = switch_core_session_strdup(tech_pvt->session, number);
|
||||
|
@ -2158,7 +2169,11 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
|||
|
||||
if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
|
||||
char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX);
|
||||
char *cid = generate_pai_str(session);
|
||||
char *cid = NULL;
|
||||
|
||||
if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID)) {
|
||||
cid = generate_pai_str(session);
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) &&
|
||||
tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) {
|
||||
|
|
|
@ -4664,22 +4664,22 @@ void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *sess
|
|||
return;
|
||||
}
|
||||
|
||||
if (sofia_test_flag(tech_pvt, TFLAG_TRACKED)) {
|
||||
sofia_glue_tech_untrack(profile, session, SWITCH_TRUE);
|
||||
}
|
||||
|
||||
if (switch_ivr_generate_xml_cdr(session, &cdr) == SWITCH_STATUS_SUCCESS) {
|
||||
xml_cdr_text = switch_xml_toxml(cdr, SWITCH_FALSE);
|
||||
switch_xml_free(cdr);
|
||||
}
|
||||
|
||||
if (xml_cdr_text) {
|
||||
sql = switch_mprintf("insert into sip_recovery (runtime_uuid, profile_name, hostname, uuid, metadata) values ('%q','%q','%q','%q','%q')",
|
||||
switch_core_get_uuid(), profile->name, mod_sofia_globals.hostname, switch_core_session_get_uuid(session), xml_cdr_text);
|
||||
|
||||
if (sofia_test_flag(tech_pvt, TFLAG_TRACKED)) {
|
||||
sql = switch_mprintf("update sip_recovery set metadata='%q' where uuid='%q'", xml_cdr_text, switch_core_session_get_uuid(session));
|
||||
} else {
|
||||
|
||||
sql = switch_mprintf("insert into sip_recovery (runtime_uuid, profile_name, hostname, uuid, metadata) values ('%q','%q','%q','%q','%q')",
|
||||
switch_core_get_uuid(), profile->name, mod_sofia_globals.hostname, switch_core_session_get_uuid(session), xml_cdr_text);
|
||||
}
|
||||
|
||||
if (sofia_test_pflag(profile, PFLAG_TRACK_CALLS_EVENTS)) {
|
||||
switch_event_t *event = NULL;
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_RECOVERY_SEND) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "profile_name", profile->name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sql", sql);
|
||||
|
@ -4687,8 +4687,8 @@ void sofia_glue_tech_track(sofia_profile_t *profile, switch_core_session_t *sess
|
|||
}
|
||||
}
|
||||
|
||||
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
|
||||
|
||||
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
|
||||
free(xml_cdr_text);
|
||||
sofia_set_flag(tech_pvt, TFLAG_TRACKED);
|
||||
|
||||
|
|
|
@ -673,8 +673,8 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot)
|
|||
if (now && sofia_test_pflag(profile, PFLAG_NAT_OPTIONS_PING)) {
|
||||
switch_snprintf(sql, sizeof(sql), "select call_id,sip_user,sip_host,contact,status,rpid,"
|
||||
"expires,user_agent,server_user,server_host,profile_name"
|
||||
" from sip_registrations where (status like '%%AUTO-NAT%%' "
|
||||
"or status like '%%UDP-NAT%%') and hostname='%s'", mod_sofia_globals.hostname);
|
||||
" from sip_registrations where (status like '%%NAT%%' "
|
||||
"or contact like '%%fs_nat=true%%') and hostname='%s'", mod_sofia_globals.hostname);
|
||||
|
||||
sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_reg_nat_callback, profile);
|
||||
}
|
||||
|
|
|
@ -2035,6 +2035,36 @@ SWITCH_DECLARE(void) switch_channel_set_hunt_caller_profile(switch_channel_t *ch
|
|||
switch_mutex_unlock(channel->profile_mutex);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_set_origination_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile)
|
||||
{
|
||||
switch_assert(channel != NULL);
|
||||
switch_assert(channel->caller_profile != NULL);
|
||||
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
|
||||
if (channel->caller_profile) {
|
||||
caller_profile->next = channel->caller_profile->origination_caller_profile;
|
||||
channel->caller_profile->origination_caller_profile = caller_profile;
|
||||
}
|
||||
switch_assert(channel->caller_profile->origination_caller_profile->next != channel->caller_profile->origination_caller_profile);
|
||||
switch_mutex_unlock(channel->profile_mutex);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_origination_caller_profile(switch_channel_t *channel)
|
||||
{
|
||||
switch_caller_profile_t *profile = NULL;
|
||||
switch_assert(channel != NULL);
|
||||
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
if (channel->caller_profile) {
|
||||
profile = channel->caller_profile->origination_caller_profile;
|
||||
}
|
||||
switch_mutex_unlock(channel->profile_mutex);
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile)
|
||||
{
|
||||
switch_assert(channel != NULL);
|
||||
|
|
|
@ -524,6 +524,14 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_
|
|||
switch_channel_set_originator_caller_profile(peer_channel, cloned_profile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((profile = switch_channel_get_caller_profile(peer_channel))) {
|
||||
if ((cloned_profile = switch_caller_profile_clone(session, profile)) != 0) {
|
||||
switch_channel_set_origination_caller_profile(channel, cloned_profile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_OUTGOING) == SWITCH_STATUS_SUCCESS) {
|
||||
|
|
|
@ -2012,6 +2012,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_
|
|||
|
||||
cp_off += switch_ivr_set_xml_profile_data(x_main_cp, caller_profile, 0);
|
||||
|
||||
if (caller_profile->origination_caller_profile) {
|
||||
switch_caller_profile_t *cp = NULL;
|
||||
int off = 0;
|
||||
if (!(x_o = switch_xml_add_child_d(x_main_cp, "origination", cp_off++))) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (cp = caller_profile->origination_caller_profile; cp; cp = cp->next) {
|
||||
if (!(x_caller_profile = switch_xml_add_child_d(x_o, "origination_caller_profile", off++))) {
|
||||
goto error;
|
||||
}
|
||||
switch_ivr_set_xml_profile_data(x_caller_profile, cp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (caller_profile->originator_caller_profile) {
|
||||
switch_caller_profile_t *cp = NULL;
|
||||
int off = 0;
|
||||
|
|
|
@ -1683,16 +1683,20 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char *
|
|||
{
|
||||
switch_api_interface_t *api;
|
||||
switch_status_t status;
|
||||
char *arg_no_spaces;
|
||||
char *cmd_no_spaces;
|
||||
char *arg_used;
|
||||
char *cmd_used;
|
||||
|
||||
switch_assert(stream != NULL);
|
||||
switch_assert(stream->data != NULL);
|
||||
switch_assert(stream->write_function != NULL);
|
||||
|
||||
|
||||
cmd_no_spaces = switch_strip_whitespace(cmd);
|
||||
arg_no_spaces = switch_strip_whitespace(arg);
|
||||
if (strcasecmp(cmd, "console_complete")) {
|
||||
cmd_used = switch_strip_whitespace(cmd);
|
||||
arg_used = switch_strip_whitespace(arg);
|
||||
} else {
|
||||
cmd_used = (char *) cmd;
|
||||
arg_used = (char *) arg;
|
||||
}
|
||||
|
||||
|
||||
if (!stream->param_event) {
|
||||
|
@ -1700,17 +1704,17 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char *
|
|||
}
|
||||
|
||||
if (stream->param_event) {
|
||||
if (cmd_no_spaces) {
|
||||
switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command", cmd_no_spaces);
|
||||
if (cmd_used) {
|
||||
switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command", cmd_used);
|
||||
}
|
||||
if (arg_no_spaces) {
|
||||
switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command-Argument", arg_no_spaces);
|
||||
if (arg_used) {
|
||||
switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command-Argument", arg_used);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (cmd_no_spaces && (api = switch_loadable_module_get_api_interface(cmd_no_spaces)) != 0) {
|
||||
if ((status = api->function(arg_no_spaces, session, stream)) != SWITCH_STATUS_SUCCESS) {
|
||||
if (cmd_used && (api = switch_loadable_module_get_api_interface(cmd_used)) != 0) {
|
||||
if ((status = api->function(arg_used, session, stream)) != SWITCH_STATUS_SUCCESS) {
|
||||
stream->write_function(stream, "COMMAND RETURNED ERROR!\n");
|
||||
}
|
||||
UNPROTECT_INTERFACE(api);
|
||||
|
@ -1723,8 +1727,13 @@ SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char *
|
|||
switch_event_fire(&stream->param_event);
|
||||
}
|
||||
|
||||
switch_safe_free(cmd_no_spaces);
|
||||
switch_safe_free(arg_no_spaces);
|
||||
if (cmd_used != cmd) {
|
||||
switch_safe_free(cmd_used);
|
||||
}
|
||||
|
||||
if (arg_used != arg) {
|
||||
switch_safe_free(arg_used);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue