[svn-commits] rmudgett: branch rmudgett/bch_shift_v1.8 r311500 - /team/rmudgett/bch_shift_v...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Mar 22 10:42:41 CDT 2011


Author: rmudgett
Date: Tue Mar 22 10:42:37 2011
New Revision: 311500

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=311500
Log:
Fix deadlock and internal B channel allocation race between in/out going calls.

Modified:
    team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c
    team/rmudgett/bch_shift_v1.8/channels/sig_pri.c
    team/rmudgett/bch_shift_v1.8/channels/sig_pri.h

Modified: team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c?view=diff&rev=311500&r1=311499&r2=311500
==============================================================================
--- team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c (original)
+++ team/rmudgett/bch_shift_v1.8/channels/chan_dahdi.c Tue Mar 22 10:42:37 2011
@@ -3221,12 +3221,7 @@
 		if (pri->pvts[idx] && !pri->pvts[idx]->no_b_channel) {
 			/* This is a B channel interface. */
 			++num_b_chans;
-			if (pri->pvts[idx]->owner
-#if defined(HAVE_PRI_SERVICE_MESSAGES)
-				/* Out-of-service B channels are "in-use". */
-				|| pri->pvts[idx]->service_status
-#endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
-				) {
+			if (!sig_pri_is_chan_available(pri->pvts[idx])) {
 				++in_use;
 			}
 			if (!pri->pvts[idx]->inalarm) {
@@ -13436,18 +13431,23 @@
 			if (!tmp) {
 				p->outgoing = 0;
 #if defined(HAVE_PRI)
-#if defined(HAVE_PRI_CALL_WAITING)
 				switch (p->sig) {
 				case SIG_PRI_LIB_HANDLE_CASES:
+#if defined(HAVE_PRI_CALL_WAITING)
 					if (((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting) {
 						((struct sig_pri_chan *) p->sig_pvt)->is_call_waiting = 0;
 						ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
 					}
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+					/*
+					 * This should be the last thing to clear when we are done with
+					 * the channel.
+					 */
+					((struct sig_pri_chan *) p->sig_pvt)->allocated = 0;
 					break;
 				default:
 					break;
 				}
-#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 #endif	/* defined(HAVE_PRI) */
 			} else {
 				snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", (char *) data);

Modified: team/rmudgett/bch_shift_v1.8/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bch_shift_v1.8/channels/sig_pri.c?view=diff&rev=311500&r1=311499&r2=311500
==============================================================================
--- team/rmudgett/bch_shift_v1.8/channels/sig_pri.c (original)
+++ team/rmudgett/bch_shift_v1.8/channels/sig_pri.c Tue Mar 22 10:42:37 2011
@@ -1020,6 +1020,38 @@
 
 /*!
  * \internal
+ * \brief Determine if a private channel structure is in use.
+ * \since 1.8
+ *
+ * \param pvt Channel to determine if in use.
+ *
+ * \return TRUE if the channel is in use.
+ */
+static int sig_pri_is_chan_in_use(struct sig_pri_chan *pvt)
+{
+	return pvt->owner || pvt->call || pvt->allocated || pvt->resetting || pvt->inalarm;
+}
+
+/*!
+ * \brief Determine if a private channel structure is available.
+ * \since 1.8
+ *
+ * \param pvt Channel to determine if available.
+ *
+ * \return TRUE if the channel is available.
+ */
+int sig_pri_is_chan_available(struct sig_pri_chan *pvt)
+{
+	return !sig_pri_is_chan_in_use(pvt)
+#if defined(HAVE_PRI_SERVICE_MESSAGES)
+		/* And not out-of-service */
+		&& !pvt->service_status
+#endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
+		;
+}
+
+/*!
+ * \internal
  * \brief Obtain the sig_pri owner channel lock if the owner exists.
  * \since 1.8
  *
@@ -1156,6 +1188,7 @@
 		pri_hangup(pri->pri, call, cause);
 		pri->pvts[chanpos]->call = NULL;
 		sig_pri_unlock_private(pri->pvts[chanpos]);
+		sig_pri_span_devstate_changed(pri);
 		return;
 	}
 	pri->pvts[chanpos]->owner->hangupcause = cause;
@@ -1281,7 +1314,7 @@
 		ast_verb(3, "Moving call (%s) from channel %d to %d.\n",
 			old_chan->owner ? old_chan->owner->name : "",
 			old_chan->channel, new_chan->channel);
-		if (new_chan->owner) {
+		if (sig_pri_is_chan_available(new_chan)) {
 			ast_log(LOG_WARNING,
 				"Can't move call (%s) from channel %d to %d.  It is already in use.\n",
 				old_chan->owner ? old_chan->owner->name : "",
@@ -1312,6 +1345,7 @@
 		new_chan->alreadyhungup = old_chan->alreadyhungup;
 		new_chan->isidlecall = old_chan->isidlecall;
 		new_chan->progress = old_chan->progress;
+		new_chan->allocated = old_chan->allocated;
 		new_chan->outgoing = old_chan->outgoing;
 		new_chan->digital = old_chan->digital;
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1326,6 +1360,7 @@
 		old_chan->alreadyhungup = 0;
 		old_chan->isidlecall = 0;
 		old_chan->progress = 0;
+		old_chan->allocated = 0;
 		old_chan->outgoing = 0;
 		old_chan->digital = 0;
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1483,39 +1518,49 @@
 	}
 }
 
-/*! \note Assumes the pri->lock is already obtained. */
-static int pri_check_restart(struct sig_pri_span *pri)
+/*!
+ * \internal
+ * \brief Restart the next channel we think is idle on the span.
+ *
+ * \param pri PRI span control structure.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void pri_check_restart(struct sig_pri_span *pri)
 {
 #if defined(HAVE_PRI_SERVICE_MESSAGES)
-tryanotherpos:
+	unsigned why;
 #endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
-	do {
-		pri->resetpos++;
-	} while (pri->resetpos < pri->numchans
-		&& (!pri->pvts[pri->resetpos]
+
+	for (++pri->resetpos; pri->resetpos < pri->numchans; ++pri->resetpos) {
+		if (!pri->pvts[pri->resetpos]
 			|| pri->pvts[pri->resetpos]->no_b_channel
-			|| pri->pvts[pri->resetpos]->call
-			|| pri->pvts[pri->resetpos]->resetting));
-	if (pri->resetpos < pri->numchans) {
+			|| sig_pri_is_chan_in_use(pri->pvts[pri->resetpos])) {
+			continue;
+		}
 #if defined(HAVE_PRI_SERVICE_MESSAGES)
-		unsigned why;
-
 		why = pri->pvts[pri->resetpos]->service_status;
 		if (why) {
-			ast_log(LOG_NOTICE, "span '%d' channel '%d' out-of-service (reason: %s), not sending RESTART\n", pri->span,
-				pri->pvts[pri->resetpos]->channel, (why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
-			goto tryanotherpos;
+			ast_log(LOG_NOTICE,
+				"Span %d: channel %d out-of-service (reason: %s), not sending RESTART\n",
+				pri->span, pri->pvts[pri->resetpos]->channel,
+				(why & SRVST_FAREND) ? (why & SRVST_NEAREND) ? "both ends" : "far end" : "near end");
+			continue;
 		}
 #endif	/* defined(HAVE_PRI_SERVICE_MESSAGES) */
-
+		break;
+	}
+	if (pri->resetpos < pri->numchans) {
 		/* Mark the channel as resetting and restart it */
 		pri->pvts[pri->resetpos]->resetting = 1;
 		pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
 	} else {
 		pri->resetting = 0;
 		time(&pri->lastreset);
-	}
-	return 0;
+		sig_pri_span_devstate_changed(pri);
+	}
 }
 
 #if defined(HAVE_PRI_CALL_WAITING)
@@ -1550,6 +1595,18 @@
 }
 #endif	/* defined(HAVE_PRI_CALL_WAITING) */
 
+/*!
+ * \internal
+ * \brief Find an empty B-channel interface to use.
+ *
+ * \param pri PRI span control structure.
+ * \param backwards TRUE if the search starts from higher channels.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
 static int pri_find_empty_chan(struct sig_pri_span *pri, int backwards)
 {
 	int x;
@@ -1564,8 +1621,7 @@
 			break;
 		if (pri->pvts[x]
 			&& !pri->pvts[x]->no_b_channel
-			&& !pri->pvts[x]->inalarm
-			&& !pri->pvts[x]->owner) {
+			&& sig_pri_is_chan_available(pri->pvts[x])) {
 			ast_debug(1, "Found empty available channel %d/%d\n",
 				pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
 			return x;
@@ -1598,8 +1654,7 @@
 	for (idx = 0; idx < pri->numchans; ++idx) {
 		if (pri->pvts[idx]
 			&& pri->pvts[idx]->no_b_channel
-			&& !pri->pvts[idx]->inalarm
-			&& !pri->pvts[idx]->owner) {
+			&& sig_pri_is_chan_available(pri->pvts[idx])) {
 			ast_debug(1, "Found empty available no B channel interface\n");
 			return idx;
 		}
@@ -1785,6 +1840,9 @@
 		p->exten[0] = '\0';
 		/* Since we send release complete here, we won't get one */
 		p->call = NULL;
+		ast_mutex_lock(&p->pri->lock);
+		sig_pri_span_devstate_changed(p->pri);
+		ast_mutex_unlock(&p->pri->lock);
 	}
 	return NULL;
 }
@@ -4253,23 +4311,22 @@
 		return -1;
 	}
 
+	chanpos_new = -1;
+
 	sig_pri_lock_private(pri->pvts[chanpos_old]);
 	sig_pri_lock_owner(pri, chanpos_old);
 	owner = pri->pvts[chanpos_old]->owner;
 	if (!owner) {
-		retval = -1;
 		goto done_with_private;
 	}
 	bridged = ast_bridged_channel(owner);
 	if (!bridged) {
 		/* Cannot hold a call that is not bridged. */
-		retval = -1;
 		goto done_with_owner;
 	}
 	chanpos_new = pri_find_empty_nobch(pri);
 	if (chanpos_new < 0) {
 		/* No hold channel available. */
-		retval = -1;
 		goto done_with_owner;
 	}
 	sig_pri_handle_subcmds(pri, chanpos_old, ev->e, ev->hold.channel, ev->hold.subcmds,
@@ -4277,7 +4334,6 @@
 	chanpos_new = pri_fixup_principle(pri, chanpos_new, ev->hold.call);
 	if (chanpos_new < 0) {
 		/* Should never happen. */
-		retval = -1;
 	} else {
 		struct ast_frame f = { AST_FRAME_CONTROL, };
 
@@ -4287,15 +4343,19 @@
 		 */
 		f.subclass.integer = AST_CONTROL_HOLD;
 		ast_queue_frame(owner, &f);
-
-		sig_pri_span_devstate_changed(pri);
-		retval = 0;
 	}
 
 done_with_owner:;
 	ast_channel_unlock(owner);
 done_with_private:;
 	sig_pri_unlock_private(pri->pvts[chanpos_old]);
+
+	if (chanpos_new < 0) {
+		retval = -1;
+	} else {
+		sig_pri_span_devstate_changed(pri);
+		retval = 0;
+	}
 
 	return retval;
 }
@@ -4336,10 +4396,10 @@
 		chanpos = pri_find_principle(pri,
 			ev->retrieve.channel & ~PRI_HELD_CALL, ev->retrieve.call);
 		if (ev->retrieve.flexible
-			&& (chanpos < 0 || pri->pvts[chanpos]->owner || pri->pvts[chanpos]->call)) {
+			&& (chanpos < 0 || !sig_pri_is_chan_available(pri->pvts[chanpos]))) {
 			/*
 			 * Channel selection is flexible and the requested channel
-			 * is bad or already in use.  Pick another channel.
+			 * is bad or not available.  Pick another channel.
 			 */
 			chanpos = pri_find_empty_chan(pri, 1);
 		}
@@ -4362,9 +4422,9 @@
 		ev->retrieve.subcmds, ev->retrieve.call);
 	pri_queue_control(pri, chanpos, AST_CONTROL_UNHOLD);
 	sig_pri_unlock_private(pri->pvts[chanpos]);
-	sig_pri_span_devstate_changed(pri);
 	pri_retrieve_ack(pri->pri, ev->retrieve.call,
 		PVT_TO_CHANNEL(pri->pvts[chanpos]));
+	sig_pri_span_devstate_changed(pri);
 }
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
 
@@ -4430,8 +4490,12 @@
 		ast_mutex_lock(&pri->lock);
 		if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->sig != SIG_BRI_PTMP) && (pri->resetinterval > 0)) {
 			if (pri->resetting && pri_is_up(pri)) {
-				if (pri->resetpos < 0)
+				if (pri->resetpos < 0) {
 					pri_check_restart(pri);
+					if (pri->resetting) {
+						sig_pri_span_devstate_changed(pri);
+					}
+				}
 			} else {
 				if (!pri->resetting	&& (t - pri->lastreset) >= pri->resetinterval) {
 					pri->resetting = 1;
@@ -4445,32 +4509,41 @@
 			haveidles = 0;
 			activeidles = 0;
 			for (x = pri->numchans; x >= 0; x--) {
-				if (pri->pvts[x]
-					&& !pri->pvts[x]->owner
-					&& !pri->pvts[x]->call
-					&& !pri->pvts[x]->no_b_channel) {
-					if (haveidles < pri->minunused) {
-						haveidles++;
-					} else if (!pri->pvts[x]->resetting) {
-						nextidle = x;
-						break;
+				if (pri->pvts[x] && !pri->pvts[x]->no_b_channel) {
+					if (sig_pri_is_chan_available(pri->pvts[x])) {
+						if (haveidles < pri->minunused) {
+							haveidles++;
+						} else {
+							nextidle = x;
+							break;
+						}
+					} else if (pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
+						activeidles++;
 					}
-				} else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
-					activeidles++;
+				}
 			}
 			if (nextidle > -1) {
 				if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
 					/* Don't create a new idle call more than once per second */
 					snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
+					pri->pvts[nextidle]->allocated = 1;
+					/*
+					 * Release the PRI lock while we create the channel so other
+					 * threads can send D channel messages.
+					 */
+					ast_mutex_unlock(&pri->lock);
 					idle = sig_pri_request(pri->pvts[nextidle], AST_FORMAT_ULAW, NULL, 0);
+					ast_mutex_lock(&pri->lock);
 					if (idle) {
 						pri->pvts[nextidle]->isidlecall = 1;
 						if (ast_pthread_create_background(&p, NULL, do_idle_thread, pri->pvts[nextidle])) {
 							ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
 							ast_hangup(idle);
 						}
-					} else
+					} else {
+						pri->pvts[nextidle]->allocated = 0;
 						ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
+					}
 					gettimeofday(&lastidle, NULL);
 				}
 			} else if ((haveidles < pri->minunused) &&
@@ -4682,6 +4755,7 @@
 							sig_pri_unlock_private(pri->pvts[x]);
 						}
 				}
+				sig_pri_span_devstate_changed(pri);
 				break;
 			case PRI_EVENT_KEYPAD_DIGIT:
 				if (sig_pri_is_cis_call(e->digit.channel)) {
@@ -4841,6 +4915,27 @@
 				} else {
 					/* A channel is specified. */
 					chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
+					if (chanpos < 0) {
+						ast_log(LOG_WARNING,
+							"Span %d: SETUP on unconfigured channel %d/%d\n",
+							pri->span, PRI_SPAN(e->ring.channel),
+							PRI_CHANNEL(e->ring.channel));
+					} else if (!sig_pri_is_chan_available(pri->pvts[chanpos])) {
+						/* Libpri has already filtered out duplicate SETUPs anyway. */
+						if (pri->pvts[chanpos]->call == e->ring.call) {
+							ast_log(LOG_WARNING,
+								"Span %d: Ignoring duplicate SETUP on channel %d/%d\n",
+								pri->span, PRI_SPAN(e->ring.channel),
+								PRI_CHANNEL(e->ring.channel));
+							break;
+						}
+						/* This is where we handle initial glare */
+						ast_debug(1,
+							"Span %d: SETUP requested unavailable channel %d/%d.  Attempting to renegotiate.\n",
+							pri->span, PRI_SPAN(e->ring.channel),
+							PRI_CHANNEL(e->ring.channel));
+						chanpos = -1;
+					}
 /*!
  * Define to make always pick a channel if allowed.  Useful for
  * testing channel shifting.
@@ -4849,376 +4944,385 @@
 #define ALWAYS_PICK_CHANNEL	1	//BUGBUG
 #if defined(ALWAYS_PICK_CHANNEL)
 					if (e->ring.flexible) {
+						chanpos = -1;
+					}
+#endif	/* defined(ALWAYS_PICK_CHANNEL) */
+					if (chanpos < 0 && e->ring.flexible) {
+						/* We can try to pick another channel. */
 						chanpos = pri_find_empty_chan(pri, 1);
 					}
-#endif	/* defined(ALWAYS_PICK_CHANNEL) */
-				}
-				/* if no channel specified find one empty */
+				}
 				if (chanpos < 0) {
-					ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n",
-						PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
+					if (e->ring.flexible) {
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+					} else {
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+					}
+					break;
+				}
+
+				sig_pri_lock_private(pri->pvts[chanpos]);
+
+				/* Mark channel as in use so noone else will steal it. */
+				pri->pvts[chanpos]->call = e->ring.call;
+
+				/* Use plancallingnum as a scratch buffer since it is initialized next. */
+				apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri,
+					e->ring.redirectingnum, e->ring.callingplanrdnis);
+				sig_pri_set_rdnis(pri->pvts[chanpos], plancallingnum);
+
+				/* Setup caller-id info */
+				apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
+				pri->pvts[chanpos]->cid_ani2 = 0;
+				if (pri->pvts[chanpos]->use_callerid) {
+					ast_shrink_phone_number(plancallingnum);
+					ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
+#ifdef PRI_ANI
+					if (!ast_strlen_zero(e->ring.callingani)) {
+						apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
+						ast_shrink_phone_number(plancallingani);
+						ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
+					} else {
+						pri->pvts[chanpos]->cid_ani[0] = '\0';
+					}
+#endif
+					pri->pvts[chanpos]->cid_subaddr[0] = '\0';
+#if defined(HAVE_PRI_SUBADDR)
+					if (e->ring.calling.subaddress.valid) {
+						struct ast_party_subaddress calling_subaddress;
+
+						ast_party_subaddress_init(&calling_subaddress);
+						sig_pri_set_subaddress(&calling_subaddress,
+							&e->ring.calling.subaddress);
+						if (calling_subaddress.str) {
+							ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
+								calling_subaddress.str,
+								sizeof(pri->pvts[chanpos]->cid_subaddr));
+						}
+						ast_party_subaddress_free(&calling_subaddress);
+					}
+#endif /* defined(HAVE_PRI_SUBADDR) */
+					ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
+					pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
+					pri->pvts[chanpos]->callingpres = e->ring.callingpres;
+					if (e->ring.ani2 >= 0) {
+						pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
+					}
 				} else {
-					sig_pri_lock_private(pri->pvts[chanpos]);
-					if (pri->pvts[chanpos]->owner) {
-						if (pri->pvts[chanpos]->call == e->ring.call) {
-							ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n",
-								PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-							sig_pri_unlock_private(pri->pvts[chanpos]);
+					pri->pvts[chanpos]->cid_num[0] = '\0';
+					pri->pvts[chanpos]->cid_subaddr[0] = '\0';
+					pri->pvts[chanpos]->cid_ani[0] = '\0';
+					pri->pvts[chanpos]->cid_name[0] = '\0';
+					pri->pvts[chanpos]->cid_ton = 0;
+					pri->pvts[chanpos]->callingpres = 0;
+				}
+
+				/* Setup the user tag for party id's from this device for this call. */
+				if (pri->append_msn_to_user_tag) {
+					snprintf(pri->pvts[chanpos]->user_tag,
+						sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
+						pri->initial_user_tag,
+						pri->nodetype == PRI_NETWORK
+							? plancallingnum : e->ring.callednum);
+				} else {
+					ast_copy_string(pri->pvts[chanpos]->user_tag,
+						pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
+				}
+
+				sig_pri_set_caller_id(pri->pvts[chanpos]);
+
+				/* Set DNID on all incoming calls -- even immediate */
+				sig_pri_set_dnid(pri->pvts[chanpos], e->ring.callednum);
+
+				/* If immediate=yes go to s|1 */
+				if (pri->pvts[chanpos]->immediate) {
+					ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+				/* Get called number */
+				else if (!ast_strlen_zero(e->ring.callednum)) {
+					ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
+				} else if (pri->overlapdial)
+					pri->pvts[chanpos]->exten[0] = '\0';
+				else {
+					/* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+				/* No number yet, but received "sending complete"? */
+				if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
+					ast_verb(3, "Going to extension s|1 because of Complete received\n");
+					pri->pvts[chanpos]->exten[0] = 's';
+					pri->pvts[chanpos]->exten[1] = '\0';
+				}
+
+				/* Make sure extension exists (or in overlap dial mode, can exist) */
+				if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
+					ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+					/* Setup law */
+					if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
+						/* Just announce proceeding */
+						pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
+						pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
+					} else if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
+						pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
+						pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+					} else {
+						pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
+						pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+					}
+
+					/* Start PBX */
+					if (!e->ring.complete
+						&& (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
+						&& ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
+						/*
+						 * Release the PRI lock while we create the channel so other
+						 * threads can send D channel messages.  We must also release
+						 * the private lock to prevent deadlock while creating the
+						 * channel.
+						 */
+						sig_pri_unlock_private(pri->pvts[chanpos]);
+						ast_mutex_unlock(&pri->lock);
+						c = sig_pri_new_ast_channel(pri->pvts[chanpos],
+							AST_STATE_RESERVED,
+							(e->ring.layer1 == PRI_LAYER_1_ALAW)
+								? SIG_PRI_ALAW : SIG_PRI_ULAW,
+							e->ring.ctype, pri->pvts[chanpos]->exten, NULL);
+						ast_mutex_lock(&pri->lock);
+						sig_pri_lock_private(pri->pvts[chanpos]);
+						if (c) {
+#if defined(HAVE_PRI_SUBADDR)
+							if (e->ring.calling.subaddress.valid) {
+								/* Set Calling Subaddress */
+								sig_pri_lock_owner(pri, chanpos);
+								sig_pri_set_subaddress(
+									&pri->pvts[chanpos]->owner->caller.id.subaddress,
+									&e->ring.calling.subaddress);
+								if (!e->ring.calling.subaddress.type
+									&& !ast_strlen_zero(
+										(char *) e->ring.calling.subaddress.data)) {
+									/* NSAP */
+									pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
+										(char *) e->ring.calling.subaddress.data);
+								}
+								ast_channel_unlock(c);
+							}
+							if (e->ring.called_subaddress.valid) {
+								/* Set Called Subaddress */
+								sig_pri_lock_owner(pri, chanpos);
+								sig_pri_set_subaddress(
+									&pri->pvts[chanpos]->owner->dialed.subaddress,
+									&e->ring.called_subaddress);
+								if (!e->ring.called_subaddress.type
+									&& !ast_strlen_zero(
+										(char *) e->ring.called_subaddress.data)) {
+									/* NSAP */
+									pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
+										(char *) e->ring.called_subaddress.data);
+								}
+								ast_channel_unlock(c);
+							}
+#else
+							if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+								pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+							}
+#endif /* !defined(HAVE_PRI_SUBADDR) */
+							if (e->ring.ani2 >= 0) {
+								snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
+								pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+							}
+
+#ifdef SUPPORT_USERUSER
+							if (!ast_strlen_zero(e->ring.useruserinfo)) {
+								pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
+							}
+#endif
+
+							snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
+							pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+							if (e->ring.redirectingreason >= 0) {
+								/* This is now just a status variable.  Use REDIRECTING() dialplan function. */
+								pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
+							}
+#if defined(HAVE_PRI_REVERSE_CHARGE)
+							pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
+#endif
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+							ast_copy_string(pri->pvts[chanpos]->keypad_digits,
+								e->ring.keypad_digits,
+								sizeof(pri->pvts[chanpos]->keypad_digits));
+#endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
+
+							sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
+								e->ring.subcmds, e->ring.call);
+
+							if (!pri->pvts[chanpos]->digital
+								&& !pri->pvts[chanpos]->no_b_channel) {
+								/*
+								 * Call has a channel.
+								 * Indicate that we are providing dialtone.
+								 */
+								pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */
+#ifdef HAVE_PRI_PROG_W_CAUSE
+								pri_progress_with_cause(pri->pri, e->ring.call,
+									PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */
+#else
+								pri_progress(pri->pri, e->ring.call,
+									PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
+#endif
+							}
+						}
+						if (c && !ast_pthread_create_detached(&threadid, NULL, pri_ss_thread, pri->pvts[chanpos])) {
+							ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
+								plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
+								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+						} else {
+							ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+							if (c) {
+								/* Avoid deadlock while destroying channel */
+								sig_pri_unlock_private(pri->pvts[chanpos]);
+								ast_mutex_unlock(&pri->lock);
+								ast_hangup(c);
+								ast_mutex_lock(&pri->lock);
+							} else {
+								pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+								pri->pvts[chanpos]->call = NULL;
+								sig_pri_unlock_private(pri->pvts[chanpos]);
+								sig_pri_span_devstate_changed(pri);
+							}
 							break;
+						}
+					} else {
+						/*
+						 * Release the PRI lock while we create the channel so other
+						 * threads can send D channel messages.  We must also release
+						 * the private lock to prevent deadlock while creating the
+						 * channel.
+						 */
+						sig_pri_unlock_private(pri->pvts[chanpos]);
+						ast_mutex_unlock(&pri->lock);
+						c = sig_pri_new_ast_channel(pri->pvts[chanpos],
+							AST_STATE_RING,
+							(e->ring.layer1 == PRI_LAYER_1_ALAW)
+								? SIG_PRI_ALAW : SIG_PRI_ULAW, e->ring.ctype,
+							pri->pvts[chanpos]->exten, NULL);
+						ast_mutex_lock(&pri->lock);
+						sig_pri_lock_private(pri->pvts[chanpos]);
+						if (c) {
+							/*
+							 * It is reasonably safe to set the following
+							 * channel variables while the PRI and DAHDI private
+							 * structures are locked.  The PBX has not been
+							 * started yet and it is unlikely that any other task
+							 * will do anything with the channel we have just
+							 * created.
+							 */
+#if defined(HAVE_PRI_SUBADDR)
+							if (e->ring.calling.subaddress.valid) {
+								/* Set Calling Subaddress */
+								sig_pri_lock_owner(pri, chanpos);
+								sig_pri_set_subaddress(
+									&pri->pvts[chanpos]->owner->caller.id.subaddress,
+									&e->ring.calling.subaddress);
+								if (!e->ring.calling.subaddress.type
+									&& !ast_strlen_zero(
+										(char *) e->ring.calling.subaddress.data)) {
+									/* NSAP */
+									pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
+										(char *) e->ring.calling.subaddress.data);
+								}
+								ast_channel_unlock(c);
+							}
+							if (e->ring.called_subaddress.valid) {
+								/* Set Called Subaddress */
+								sig_pri_lock_owner(pri, chanpos);
+								sig_pri_set_subaddress(
+									&pri->pvts[chanpos]->owner->dialed.subaddress,
+									&e->ring.called_subaddress);
+								if (!e->ring.called_subaddress.type
+									&& !ast_strlen_zero(
+										(char *) e->ring.called_subaddress.data)) {
+									/* NSAP */
+									pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
+										(char *) e->ring.called_subaddress.data);
+								}
+								ast_channel_unlock(c);
+							}
+#else
+							if (!ast_strlen_zero(e->ring.callingsubaddr)) {
+								pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
+							}
+#endif /* !defined(HAVE_PRI_SUBADDR) */
+							if (e->ring.ani2 >= 0) {
+								snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
+								pbx_builtin_setvar_helper(c, "ANI2", ani2str);
+							}
+
+#ifdef SUPPORT_USERUSER
+							if (!ast_strlen_zero(e->ring.useruserinfo)) {
+								pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
+							}
+#endif
+
+							if (e->ring.redirectingreason >= 0) {
+								/* This is now just a status variable.  Use REDIRECTING() dialplan function. */
+								pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
+							}
+#if defined(HAVE_PRI_REVERSE_CHARGE)
+							pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
+#endif
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+							ast_copy_string(pri->pvts[chanpos]->keypad_digits,
+								e->ring.keypad_digits,
+								sizeof(pri->pvts[chanpos]->keypad_digits));
+#endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
+
+							snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
+							pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
+
+							sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
+								e->ring.subcmds, e->ring.call);
+
+						}
+						if (c && !ast_pbx_start(c)) {
+							ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
+								plancallingnum, pri->pvts[chanpos]->exten,
+								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+							sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
 						} else {
-							/* This is where we handle initial glare */
-							ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d.  Attempting to renegotiating channel.\n",
-							PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
-							sig_pri_unlock_private(pri->pvts[chanpos]);
-							chanpos = -1;
+							ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
+								pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
+							if (c) {
+								/* Avoid deadlock while destroying channel */
+								sig_pri_unlock_private(pri->pvts[chanpos]);
+								ast_mutex_unlock(&pri->lock);
+								ast_hangup(c);
+								ast_mutex_lock(&pri->lock);
+							} else {
+								pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
+								pri->pvts[chanpos]->call = NULL;
+								sig_pri_unlock_private(pri->pvts[chanpos]);
+								sig_pri_span_devstate_changed(pri);
+							}
+							break;
 						}
 					}
-					if (chanpos > -1)
-						sig_pri_unlock_private(pri->pvts[chanpos]);
-				}
-				if ((chanpos < 0) && (e->ring.flexible))
-					chanpos = pri_find_empty_chan(pri, 1);
-				if (chanpos > -1) {
-					sig_pri_lock_private(pri->pvts[chanpos]);
-					pri->pvts[chanpos]->call = e->ring.call;
-
-					/* Use plancallingnum as a scratch buffer since it is initialized next. */
-					apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri,
-						e->ring.redirectingnum, e->ring.callingplanrdnis);
-					sig_pri_set_rdnis(pri->pvts[chanpos], plancallingnum);
-
-					/* Setup caller-id info */
-					apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
-					pri->pvts[chanpos]->cid_ani2 = 0;
-					if (pri->pvts[chanpos]->use_callerid) {
-						ast_shrink_phone_number(plancallingnum);
-						ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
-#ifdef PRI_ANI
-						if (!ast_strlen_zero(e->ring.callingani)) {
-							apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
-							ast_shrink_phone_number(plancallingani);
-							ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
-						} else {
-							pri->pvts[chanpos]->cid_ani[0] = '\0';
-						}
-#endif
-						pri->pvts[chanpos]->cid_subaddr[0] = '\0';
-#if defined(HAVE_PRI_SUBADDR)
-						if (e->ring.calling.subaddress.valid) {
-							struct ast_party_subaddress calling_subaddress;
-
-							ast_party_subaddress_init(&calling_subaddress);
-							sig_pri_set_subaddress(&calling_subaddress,
-								&e->ring.calling.subaddress);
-							if (calling_subaddress.str) {
-								ast_copy_string(pri->pvts[chanpos]->cid_subaddr,
-									calling_subaddress.str,
-									sizeof(pri->pvts[chanpos]->cid_subaddr));
-							}
-							ast_party_subaddress_free(&calling_subaddress);
-						}
-#endif /* defined(HAVE_PRI_SUBADDR) */
-						ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
-						pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
-						pri->pvts[chanpos]->callingpres = e->ring.callingpres;
-						if (e->ring.ani2 >= 0) {
-							pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
-						}
-					} else {
-						pri->pvts[chanpos]->cid_num[0] = '\0';
-						pri->pvts[chanpos]->cid_subaddr[0] = '\0';
-						pri->pvts[chanpos]->cid_ani[0] = '\0';
-						pri->pvts[chanpos]->cid_name[0] = '\0';
-						pri->pvts[chanpos]->cid_ton = 0;
-						pri->pvts[chanpos]->callingpres = 0;
-					}
-
-					/* Setup the user tag for party id's from this device for this call. */
-					if (pri->append_msn_to_user_tag) {
-						snprintf(pri->pvts[chanpos]->user_tag,
-							sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
-							pri->initial_user_tag,
-							pri->nodetype == PRI_NETWORK
-								? plancallingnum : e->ring.callednum);
-					} else {
-						ast_copy_string(pri->pvts[chanpos]->user_tag,
-							pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
-					}
-
-					sig_pri_set_caller_id(pri->pvts[chanpos]);
-
-					/* Set DNID on all incoming calls -- even immediate */
-					sig_pri_set_dnid(pri->pvts[chanpos], e->ring.callednum);
-
-					/* If immediate=yes go to s|1 */
-					if (pri->pvts[chanpos]->immediate) {
-						ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
-						pri->pvts[chanpos]->exten[0] = 's';
-						pri->pvts[chanpos]->exten[1] = '\0';
-					}
-					/* Get called number */
-					else if (!ast_strlen_zero(e->ring.callednum)) {
-						ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
-					} else if (pri->overlapdial)
-						pri->pvts[chanpos]->exten[0] = '\0';
-					else {
-						/* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
-						pri->pvts[chanpos]->exten[0] = 's';
-						pri->pvts[chanpos]->exten[1] = '\0';
-					}
-					/* No number yet, but received "sending complete"? */
-					if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
-						ast_verb(3, "Going to extension s|1 because of Complete received\n");
-						pri->pvts[chanpos]->exten[0] = 's';
-						pri->pvts[chanpos]->exten[1] = '\0';
-					}
-
-					/* Make sure extension exists (or in overlap dial mode, can exist) */
-					if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
-						ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
-						/* Setup law */
-						if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
-							/* Just announce proceeding */
-							pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_PROCEEDING;
-							pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
-						} else if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
-							pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_CONNECT;
-							pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
-						} else {
-							pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_OVERLAP;
-							pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
-						}
-
-						/* Start PBX */
-						if (!e->ring.complete
-							&& (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
-							&& ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
-							/*
-							 * Release the PRI lock while we create the channel
-							 * so other threads can send D channel messages.
-							 */
-							ast_mutex_unlock(&pri->lock);
-							c = sig_pri_new_ast_channel(pri->pvts[chanpos],
-								AST_STATE_RESERVED,
-								(e->ring.layer1 == PRI_LAYER_1_ALAW)
-									? SIG_PRI_ALAW : SIG_PRI_ULAW,
-								e->ring.ctype, pri->pvts[chanpos]->exten, NULL);
-							ast_mutex_lock(&pri->lock);
-							if (c) {
-#if defined(HAVE_PRI_SUBADDR)
-								if (e->ring.calling.subaddress.valid) {
-									/* Set Calling Subaddress */
-									sig_pri_lock_owner(pri, chanpos);
-									sig_pri_set_subaddress(
-										&pri->pvts[chanpos]->owner->caller.id.subaddress,
-										&e->ring.calling.subaddress);
-									if (!e->ring.calling.subaddress.type
-										&& !ast_strlen_zero(
-											(char *) e->ring.calling.subaddress.data)) {
-										/* NSAP */
-										pbx_builtin_setvar_helper(c, "CALLINGSUBADDR",
-											(char *) e->ring.calling.subaddress.data);
-									}
-									ast_channel_unlock(c);
-								}
-								if (e->ring.called_subaddress.valid) {
-									/* Set Called Subaddress */
-									sig_pri_lock_owner(pri, chanpos);
-									sig_pri_set_subaddress(
-										&pri->pvts[chanpos]->owner->dialed.subaddress,
-										&e->ring.called_subaddress);
-									if (!e->ring.called_subaddress.type
-										&& !ast_strlen_zero(
-											(char *) e->ring.called_subaddress.data)) {
-										/* NSAP */
-										pbx_builtin_setvar_helper(c, "CALLEDSUBADDR",
-											(char *) e->ring.called_subaddress.data);
-									}
-									ast_channel_unlock(c);
-								}
-#else
-								if (!ast_strlen_zero(e->ring.callingsubaddr)) {
-									pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
-								}
-#endif /* !defined(HAVE_PRI_SUBADDR) */
-								if (e->ring.ani2 >= 0) {
-									snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
-									pbx_builtin_setvar_helper(c, "ANI2", ani2str);
-								}
-
-#ifdef SUPPORT_USERUSER
-								if (!ast_strlen_zero(e->ring.useruserinfo)) {
-									pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
-								}
-#endif
-
-								snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
-								pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
-								if (e->ring.redirectingreason >= 0) {
-									/* This is now just a status variable.  Use REDIRECTING() dialplan function. */
-									pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
-								}
-#if defined(HAVE_PRI_REVERSE_CHARGE)
-								pri->pvts[chanpos]->reverse_charging_indication = e->ring.reversecharge;
-#endif
-#if defined(HAVE_PRI_SETUP_KEYPAD)
-								ast_copy_string(pri->pvts[chanpos]->keypad_digits,
-									e->ring.keypad_digits,
-									sizeof(pri->pvts[chanpos]->keypad_digits));
-#endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
-
-								sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
-									e->ring.subcmds, e->ring.call);
-
-								if (!pri->pvts[chanpos]->digital
-									&& !pri->pvts[chanpos]->no_b_channel) {
-									/*
-									 * Call has a channel.
-									 * Indicate that we are providing dialtone.
-									 */
-									pri->pvts[chanpos]->progress = 1;/* No need to send plain PROGRESS again. */
-#ifdef HAVE_PRI_PROG_W_CAUSE
-									pri_progress_with_cause(pri->pri, e->ring.call,
-										PVT_TO_CHANNEL(pri->pvts[chanpos]), 1, -1);/* no cause at all */
-#else

[... 363 lines stripped ...]



More information about the svn-commits mailing list