Restore the 'w' modifier support for ISDN spans. Dial(DAHDI/g0/1234w888)
authorRichard Mudgett <rmudgett@digium.com>
Thu, 2 Feb 2012 20:18:11 +0000 (20:18 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Thu, 2 Feb 2012 20:18:11 +0000 (20:18 +0000)
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
........

Merged revisions 353867 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 353868 from http://svn.asterisk.org/svn/asterisk/branches/10

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@353872 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_dahdi.c
channels/sig_pri.c
channels/sig_pri.h

index 6cfa81d..cde55d0 100644 (file)
@@ -2681,6 +2681,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)
@@ -3380,6 +3413,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,
 };
@@ -7975,6 +8009,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_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
index c9c96be..bfdcb10 100644 (file)
@@ -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.
@@ -1459,6 +1468,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);
                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;
@@ -6567,14 +6577,28 @@ static void *pri_dchannel(void *vpri)
 #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)) {
@@ -7331,7 +7355,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;
                }
@@ -7447,7 +7478,6 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
                }
                dialed_subaddress.str = s;
                dialed_subaddress.valid = 1;
-               s = NULL;
        }
 
        l = NULL;
@@ -7476,6 +7506,21 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
                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);
@@ -7483,7 +7528,8 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, const char *rd
                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);
@@ -8258,6 +8304,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
index e10e4c7..dc9f578 100644 (file)
@@ -156,6 +156,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,
 };
@@ -199,6 +201,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);
 
@@ -290,6 +293,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];
        /*! Music class suggested with AST_CONTROL_HOLD. */
        char moh_suggested[MAX_MUSICCLASS];
        enum sig_pri_moh_state moh_state;
@@ -605,6 +610,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);