}
#endif /* defined(HAVE_PRI) */
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Ask DAHDI to dial the given dial string.
+ * \since 1.8.11
+ *
+ * \param p Channel private control structure.
+ * \param dial_string String to pass to DAHDI to dial.
+ *
+ * \note The channel private lock needs to be held when calling.
+ *
+ * \return Nothing
+ */
+static void my_pri_dial_digits(void *p, const char *dial_string)
+{
+ struct dahdi_dialoperation zo = {
+ .op = DAHDI_DIAL_OP_APPEND,
+ };
+ struct dahdi_pvt *pvt = p;
+ int res;
+
+ snprintf(zo.dialstr, sizeof(zo.dialstr), "T%s", dial_string);
+ ast_debug(1, "Channel %d: Sending '%s' to DAHDI_DIAL.\n", pvt->channel, zo.dialstr);
+ res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo);
+ if (res) {
+ ast_log(LOG_WARNING, "Channel %d: Couldn't dial '%s': %s\n",
+ pvt->channel, dial_string, strerror(errno));
+ } else {
+ pvt->dialing = 1;
+ }
+}
+#endif /* defined(HAVE_PRI) */
+
static int unalloc_sub(struct dahdi_pvt *p, int x);
static int my_unallocate_sub(void *pvt, enum analog_sub analogsub)
.update_span_devstate = dahdi_pri_update_span_devstate,
.module_ref = my_module_ref,
.module_unref = my_module_unref,
+ .dial_digits = my_pri_dial_digits,
.open_media = my_pri_open_media,
.ami_channel_event = my_ami_channel_event,
};
tone_zone_play_tone(p->subs[idx].dfd, -1);
break;
case DAHDI_EVENT_DIALCOMPLETE:
+ /* DAHDI has completed dialing all digits sent using DAHDI_DIAL. */
+#if defined(HAVE_PRI)
+ if (dahdi_sig_pri_lib_handles(p->sig)) {
+ if (p->inalarm) {
+ break;
+ }
+ if (ioctl(p->subs[idx].dfd, DAHDI_DIALING, &x) == -1) {
+ ast_debug(1, "DAHDI_DIALING ioctl failed on %s: %s\n",
+ ast_channel_name(ast), strerror(errno));
+ return NULL;
+ }
+ if (x) {
+ /* Still dialing in DAHDI driver */
+ break;
+ }
+ /*
+ * The ast channel is locked and the private may be locked more
+ * than once.
+ */
+ sig_pri_dial_complete(p->sig_pvt, ast);
+ break;
+ }
+#endif /* defined(HAVE_PRI) */
#ifdef HAVE_OPENR2
if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
/* we don't need to do anything for this event for R2 signaling
return "Proceeding";
case SIG_PRI_CALL_LEVEL_ALERTING:
return "Alerting";
+ case SIG_PRI_CALL_LEVEL_DEFER_DIAL:
+ return "DeferDial";
case SIG_PRI_CALL_LEVEL_CONNECT:
return "Connect";
}
}
#endif /* defined(HAVE_PRI_CCSS) */
+static void sig_pri_dial_digits(struct sig_pri_chan *p, const char *dial_string)
+{
+ if (p->calls->dial_digits) {
+ p->calls->dial_digits(p->chan_pvt, dial_string);
+ }
+}
+
/*!
* \internal
* \brief Reevaluate the PRI span device state.
#if defined(HAVE_PRI_SETUP_KEYPAD)
strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
+ strcpy(new_chan->deferred_digits, old_chan->deferred_digits);
strcpy(new_chan->moh_suggested, old_chan->moh_suggested);
new_chan->moh_state = old_chan->moh_state;
old_chan->moh_state = SIG_PRI_MOH_STATE_IDLE;
#endif /* defined(HAVE_PRI_CALL_WAITING) */
sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.subcmds,
e->answer.call);
- if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_CONNECT) {
- pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
+ if (!ast_strlen_zero(pri->pvts[chanpos]->deferred_digits)) {
+ /* We have some 'w' deferred digits to dial now. */
+ ast_verb(3,
+ "Span %d: Channel %d/%d dialing deferred digit string: %s\n",
+ pri->span, pri->pvts[chanpos]->logicalspan,
+ pri->pvts[chanpos]->prioffset,
+ pri->pvts[chanpos]->deferred_digits);
+ if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_DEFER_DIAL) {
+ pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_DEFER_DIAL;
+ }
+ sig_pri_dial_digits(pri->pvts[chanpos],
+ pri->pvts[chanpos]->deferred_digits);
+ } else {
+ if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_CONNECT) {
+ pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
+ }
+ sig_pri_open_media(pri->pvts[chanpos]);
+ pri_queue_control(pri, chanpos, AST_CONTROL_ANSWER);
+ sig_pri_set_dialing(pri->pvts[chanpos], 0);
+ /* Enable echo cancellation if it's not on already */
+ sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
}
- sig_pri_open_media(pri->pvts[chanpos]);
- pri_queue_control(pri, chanpos, AST_CONTROL_ANSWER);
- /* Enable echo cancellation if it's not on already */
- sig_pri_set_dialing(pri->pvts[chanpos], 0);
- sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
#ifdef SUPPORT_USERUSER
if (!ast_strlen_zero(e->answer.useruserinfo)) {
if (strlen(number) < p->stripmsd) {
number = "";
} else {
+ char *deferred;
+
number += p->stripmsd;
+ deferred = strchr(number, 'w');
+ if (deferred) {
+ /* Remove any 'w' deferred digits. */
+ *deferred = '\0';
+ }
while (isalpha(*number)) {
++number;
}
}
dialed_subaddress.str = s;
dialed_subaddress.valid = 1;
- s = NULL;
}
l = NULL;
ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
return -1;
}
+
+ /* Extract any 'w' deferred digits. */
+ s = strchr(c + p->stripmsd, 'w');
+ if (s) {
+ *s++ = '\0';
+ ast_copy_string(p->deferred_digits, s, sizeof(p->deferred_digits));
+ /*
+ * Since we have a 'w', this means that there will not be any
+ * more normal dialed digits. Therefore, the sending complete
+ * ie needs to be sent with any normal digits.
+ */
+ } else {
+ p->deferred_digits[0] = '\0';
+ }
+
pri_grab(p, p->pri);
if (!(p->call = pri_new_call(p->pri->pri))) {
ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
return -1;
}
if (!(sr = pri_sr_new())) {
- ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
+ ast_log(LOG_WARNING, "Failed to allocate setup request on channel %d\n",
+ p->channel);
pri_destroycall(p->pri->pri, p->call);
p->call = NULL;
pri_rel(p->pri);
return 1;
}
+/*!
+ * \brief DTMF dial string complete.
+ * \since 1.8.11
+ *
+ * \param pvt sig_pri private channel structure.
+ * \param ast Asterisk channel
+ *
+ * \note Channel and private lock are already held.
+ *
+ * \return Nothing
+ */
+void sig_pri_dial_complete(struct sig_pri_chan *pvt, struct ast_channel *ast)
+{
+ /* If we just completed 'w' deferred dialing digits, we need to answer now. */
+ if (pvt->call_level == SIG_PRI_CALL_LEVEL_DEFER_DIAL) {
+ pvt->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
+
+ sig_pri_open_media(pvt);
+ {
+ struct ast_frame f = {AST_FRAME_CONTROL, };
+
+ if (pvt->calls->queue_control) {
+ pvt->calls->queue_control(pvt->chan_pvt, AST_CONTROL_ANSWER);
+ }
+
+ f.subclass.integer = AST_CONTROL_ANSWER;
+ ast_queue_frame(ast, &f);
+ }
+ sig_pri_set_dialing(pvt, 0);
+ /* Enable echo cancellation if it's not on already */
+ sig_pri_set_echocanceller(pvt, 1);
+ }
+}
+
#if defined(HAVE_PRI_MWI)
/*!
* \internal
SIG_PRI_CALL_LEVEL_PROCEEDING,
/*! Called party is being alerted of the call. (ALERTING) */
SIG_PRI_CALL_LEVEL_ALERTING,
+ /*! Call is dialing 'w' deferred digits. (CONNECT) */
+ SIG_PRI_CALL_LEVEL_DEFER_DIAL,
/*! Call is connected/answered. (CONNECT) */
SIG_PRI_CALL_LEVEL_CONNECT,
};
const char *(* const get_orig_dialstring)(void *pvt);
void (* const make_cc_dialstring)(void *pvt, char *buf, size_t buf_size);
void (* const update_span_devstate)(struct sig_pri_span *pri);
+ void (* const dial_digits)(void *pvt, const char *dial_string);
void (* const open_media)(void *pvt);
/*! \brief Keypad digits that came in with the SETUP message. */
char keypad_digits[AST_MAX_EXTENSION];
#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
+ /*! 'w' deferred dialing digits. */
+ char deferred_digits[AST_MAX_EXTENSION];
/*! Music class suggested with AST_CONTROL_HOLD. */
char moh_suggested[MAX_MUSICCLASS];
enum sig_pri_moh_state moh_state;
/* If return 0, it means this function was able to handle it (pre setup digits). If non zero, the user of this
* functions should handle it normally (generate inband DTMF) */
int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char digit);
+void sig_pri_dial_complete(struct sig_pri_chan *pvt, struct ast_channel *ast);
void sig_pri_stop_pri(struct sig_pri_span *pri);
int sig_pri_start_pri(struct sig_pri_span *pri);