From: Richard Mudgett Date: Thu, 2 Feb 2012 20:01:00 +0000 (+0000) Subject: Restore the 'w' modifier support for ISDN spans. Dial(DAHDI/g0/1234w888) X-Git-Tag: 1.8.11.0-rc1~65 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c5fc58c3a0b1f4a6b034f6bafbeab041ab544f54;p=thirdparty%2Fasterisk.git Restore the 'w' modifier support for ISDN spans. Dial(DAHDI/g0/1234w888) This feature also causes the sending complete ie to be sent for switch types that do not automatically send the ie. (EuroISDN/ETSI) The main difference between dialing Dial(DAHDI/g0/1234w888) and Dial(DAHDI/g0/1234,,D(888)) is the sending of the sending complete ie. (closes issue ASTERISK-19176) Reported by: rmudgett Tested by: rmudgett git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@353867 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 4545430108..5d9600db6f 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -2644,6 +2644,39 @@ static void my_pri_open_media(void *p) } #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) @@ -3342,6 +3375,7 @@ static struct sig_pri_callback dahdi_pri_callbacks = .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, }; @@ -7892,6 +7926,29 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast) 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_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n", ast->name, + 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 diff --git a/channels/sig_pri.c b/channels/sig_pri.c index a54c232dc2..bc875ecffe 100644 --- a/channels/sig_pri.c +++ b/channels/sig_pri.c @@ -137,6 +137,8 @@ static const char *sig_pri_call_level2str(enum sig_pri_call_level level) 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"; } @@ -214,6 +216,13 @@ static void sig_pri_make_cc_dialstring(struct sig_pri_chan *p, char *buf, size_t } #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. @@ -1460,6 +1469,7 @@ static int pri_fixup_principle(struct sig_pri_span *pri, int principle, q931_cal #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); #if defined(HAVE_PRI_AOC_EVENTS) new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id; new_chan->aoc_e = old_chan->aoc_e; @@ -5719,14 +5729,28 @@ static void *pri_dchannel(void *vpri) #endif /* defined(HAVE_PRI_CALL_WAITING) */ sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel, 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)) { @@ -6432,7 +6456,14 @@ void sig_pri_extract_called_num_subaddr(struct sig_pri_chan *p, const char *rdes 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; } @@ -6548,7 +6579,6 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i } dialed_subaddress.str = s; dialed_subaddress.valid = 1; - s = NULL; } l = NULL; @@ -6577,6 +6607,21 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i 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); @@ -6584,7 +6629,8 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i 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); @@ -7306,6 +7352,40 @@ int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char 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 diff --git a/channels/sig_pri.h b/channels/sig_pri.h index acd3251842..67342be119 100644 --- a/channels/sig_pri.h +++ b/channels/sig_pri.h @@ -95,6 +95,8 @@ enum sig_pri_call_level { 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, }; @@ -136,6 +138,7 @@ struct sig_pri_callback { 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); @@ -227,6 +230,8 @@ struct sig_pri_chan { /*! \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]; #if defined(HAVE_PRI_AOC_EVENTS) struct pri_subcmd_aoc_e aoc_e; @@ -507,6 +512,7 @@ void sig_pri_init_pri(struct sig_pri_span *pri); /* 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);