aboutsummaryrefslogtreecommitdiffstats
path: root/channels/sig_pri.c
diff options
context:
space:
mode:
authorrmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b>2009-10-23 16:57:33 +0000
committerrmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b>2009-10-23 16:57:33 +0000
commit4ad439617df9b05fb34022086ffcd6bd57567000 (patch)
treea618eefafd5d7b1e69344a4efc8fb303fa89fcb6 /channels/sig_pri.c
parent588db98f088eee512d95b6a08024d56ac5757dbb (diff)
Add to chan_dahdi ISDN HOLD, Call deflection, and keypad facility support.
* Added handling of received HOLD/RETRIEVE messages and the optional ability to transfer a held call on disconnect similar to an analog phone. * Added CallRerouting/CallDeflection support for Q.SIG, ETSI PTP, ETSI PTMP. Will reroute/deflect an outgoing call when receive the message. Can use the DAHDISendCallreroutingFacility to send the message for the supported switches. * Added ability to send/receive keypad digits in the SETUP message. Send keypad digits in SETUP message: Dial(DAHDI/g1[/K<keypad_digits>][/extension]) Access any received keypad digits in SETUP message by: ${CHANNEL(keypad_digits)} * Added support for BRI PTMP NT mode. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@225692 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/sig_pri.c')
-rw-r--r--channels/sig_pri.c747
1 files changed, 644 insertions, 103 deletions
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index 92b5d0c62..5db73c204 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -67,9 +67,12 @@ static int pri_gendigittimeout = 8000;
#define DCHAN_NOTINALARM (1 << 0)
#define DCHAN_UP (1 << 1)
-#define PRI_CHANNEL(p) ((p) & 0xff)
-#define PRI_SPAN(p) (((p) >> 8) & 0xff)
-#define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
+/* Defines to help decode the encoded event channel id. */
+#define PRI_CHANNEL(p) ((p) & 0xff)
+#define PRI_SPAN(p) (((p) >> 8) & 0xff)
+#define PRI_EXPLICIT (1 << 16)
+#define PRI_CIS_CALL (1 << 17) /* Call is using the D channel only. */
+#define PRI_HELD_CALL (1 << 18)
#define DCHAN_AVAILABLE (DCHAN_NOTINALARM | DCHAN_UP)
@@ -90,7 +93,7 @@ static inline void pri_rel(struct sig_pri_pri *pri)
static unsigned int PVT_TO_CHANNEL(struct sig_pri_chan *p)
{
- int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? 0x10000 : 0));
+ int res = (((p)->prioffset) | ((p)->logicalspan << 8) | (p->mastertrunkgroup ? PRI_EXPLICIT : 0));
ast_debug(5, "prioffset: %d mastertrunkgroup: %d logicalspan: %d result: %d\n",
p->prioffset, p->mastertrunkgroup, p->logicalspan, res);
@@ -828,23 +831,51 @@ static void pri_queue_control(struct sig_pri_chan *p, int subclass, struct sig_p
pri_queue_frame(p, &f, pri);
}
-static int pri_find_principle(struct sig_pri_pri *pri, int channel)
+static int pri_find_principle(struct sig_pri_pri *pri, int channel, q931_call *call)
{
int x;
- int span = PRI_SPAN(channel);
- int principle = -1;
- int explicit_ds1 = PRI_EXPLICIT(channel);
- channel = PRI_CHANNEL(channel);
+ int span;
+ int principle;
+
+ if (channel < 0) {
+ /* Channel is not picked yet. */
+ return -1;
+ }
+
+ if (channel & PRI_HELD_CALL) {
+ if (!call) {
+ /* Cannot find a held call without a call. */
+ return -1;
+ }
+ principle = -1;
+ for (x = 0; x < pri->numchans; ++x) {
+ if (pri->pvts[x]
+ && pri->pvts[x]->call == call) {
+ principle = x;
+ break;
+ }
+ }
+ return principle;
+ }
- if (!explicit_ds1) {
- int index = pri_active_dchan_index(pri);
- if (index == -1)
+ span = PRI_SPAN(channel);
+ if (!(channel & PRI_EXPLICIT)) {
+ int index;
+
+ index = pri_active_dchan_index(pri);
+ if (index == -1) {
return -1;
+ }
span = pri->dchan_logical_span[index];
}
+ channel = PRI_CHANNEL(channel);
+ principle = -1;
for (x = 0; x < pri->numchans; x++) {
- if (pri->pvts[x] && (pri->pvts[x]->prioffset == channel) && (pri->pvts[x]->logicalspan == span)) {
+ if (pri->pvts[x]
+ && pri->pvts[x]->prioffset == channel
+ && pri->pvts[x]->logicalspan == span
+ && !pri->pvts[x]->no_b_channel) {
principle = x;
break;
}
@@ -853,49 +884,99 @@ static int pri_find_principle(struct sig_pri_pri *pri, int channel)
return principle;
}
-static int pri_fixup_principle(struct sig_pri_pri *pri, int principle, q931_call *c)
+static int pri_fixup_principle(struct sig_pri_pri *pri, int principle, q931_call *call)
{
int x;
- if (!c) {
- if (principle < 0)
- return -1;
+ if (principle < 0 || pri->numchans <= principle) {
+ /* Out of rannge */
+ return -1;
+ }
+ if (!call) {
+ /* No call */
return principle;
}
- if ((principle > -1) &&
- (principle < pri->numchans) &&
- (pri->pvts[principle]) &&
- (pri->pvts[principle]->call == c))
+ if (pri->pvts[principle] && pri->pvts[principle]->call == call) {
+ /* Call is already on the specified principle. */
return principle;
- /* First, check for other bearers */
+ }
+
+ /* Find the old principle location. */
for (x = 0; x < pri->numchans; x++) {
- if (!pri->pvts[x])
+ struct sig_pri_chan *new_chan;
+ struct sig_pri_chan *old_chan;
+
+ if (!pri->pvts[x] || pri->pvts[x]->call != call) {
continue;
- if (pri->pvts[x]->call == c) {
- /* Found our call */
- if (principle != x) {
- struct sig_pri_chan *new_chan = pri->pvts[principle];
- struct sig_pri_chan *old_chan = pri->pvts[x];
-
- ast_verb(3, "Moving call from channel %d to channel %d\n",
- old_chan->channel, new_chan->channel);
- if (new_chan->owner) {
- ast_log(LOG_WARNING, "Can't fix up channel from %d to %d because %d is already in use\n",
- old_chan->channel, new_chan->channel, new_chan->channel);
- return -1;
- }
+ }
- sig_pri_fixup_chans(old_chan, new_chan);
- /* Fix it all up now */
- new_chan->owner = old_chan->owner;
- old_chan->owner = NULL;
+ /* Found our call */
+ new_chan = pri->pvts[principle];
+ old_chan = pri->pvts[x];
- new_chan->call = old_chan->call;
- old_chan->call = NULL;
+ ast_verb(3, "Moving call from channel %d to channel %d\n",
+ old_chan->channel, new_chan->channel);
+ if (new_chan->owner) {
+ ast_log(LOG_WARNING,
+ "Can't fix up channel from %d to %d because %d is already in use\n",
+ old_chan->channel, new_chan->channel, new_chan->channel);
+ return -1;
+ }
- }
- return principle;
+ sig_pri_fixup_chans(old_chan, new_chan);
+
+ /* Fix it all up now */
+ new_chan->owner = old_chan->owner;
+ old_chan->owner = NULL;
+
+ new_chan->call = old_chan->call;
+ old_chan->call = NULL;
+
+ /* Transfer flags from the old channel. */
+ new_chan->alerting = old_chan->alerting;
+ new_chan->alreadyhungup = old_chan->alreadyhungup;
+ new_chan->isidlecall = old_chan->isidlecall;
+ new_chan->proceeding = old_chan->proceeding;
+ new_chan->progress = old_chan->progress;
+ new_chan->setup_ack = old_chan->setup_ack;
+ new_chan->outgoing = old_chan->outgoing;
+ new_chan->digital = old_chan->digital;
+ old_chan->alerting = 0;
+ old_chan->alreadyhungup = 0;
+ old_chan->isidlecall = 0;
+ old_chan->proceeding = 0;
+ old_chan->progress = 0;
+ old_chan->setup_ack = 0;
+ old_chan->outgoing = 0;
+ old_chan->digital = 0;
+
+ /* More stuff to transfer to the new channel. */
+#if defined(HAVE_PRI_REVERSE_CHARGE)
+ new_chan->reverse_charging_indication = old_chan->reverse_charging_indication;
+#endif /* defined(HAVE_PRI_REVERSE_CHARGE) */
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+ strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
+#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
+
+ if (new_chan->no_b_channel) {
+ /* Copy the real channel configuration to the no B channel interface. */
+ new_chan->hidecallerid = old_chan->hidecallerid;
+ new_chan->hidecalleridname = old_chan->hidecalleridname;
+ new_chan->immediate = old_chan->immediate;
+ new_chan->priexclusive = old_chan->priexclusive;
+ new_chan->priindication_oob = old_chan->priindication_oob;
+ new_chan->use_callerid = old_chan->use_callerid;
+ new_chan->use_callingpres = old_chan->use_callingpres;
+ new_chan->stripmsd = old_chan->stripmsd;
+ strcpy(new_chan->context, old_chan->context);
+ strcpy(new_chan->mohinterpret, old_chan->mohinterpret);
+
+ /* Become a member of the old channel span/trunk-group. */
+ new_chan->logicalspan = old_chan->logicalspan;
+ new_chan->mastertrunkgroup = old_chan->mastertrunkgroup;
}
+
+ return principle;
}
ast_log(LOG_WARNING, "Call specified, but not found?\n");
return -1;
@@ -957,10 +1038,11 @@ tryanotherpos:
#endif
do {
pri->resetpos++;
- } while ((pri->resetpos < pri->numchans) &&
- (!pri->pvts[pri->resetpos] ||
- pri->pvts[pri->resetpos]->call ||
- pri->pvts[pri->resetpos]->resetting));
+ } while (pri->resetpos < pri->numchans
+ && (!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) {
#ifdef HAVE_PRI_SERVICE_MESSAGES
char db_chan_name[20], db_answer[5], state;
@@ -1002,7 +1084,10 @@ static int pri_find_empty_chan(struct sig_pri_pri *pri, int backwards)
break;
if (!backwards && (x >= pri->numchans))
break;
- if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
+ if (pri->pvts[x]
+ && !pri->pvts[x]->no_b_channel
+ && !pri->pvts[x]->inalarm
+ && !pri->pvts[x]->owner) {
ast_debug(1, "Found empty available channel %d/%d\n",
pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
return x;
@@ -1015,6 +1100,71 @@ static int pri_find_empty_chan(struct sig_pri_pri *pri, int backwards)
return -1;
}
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Find or create an empty no-B-channel interface to use.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri span controller to find interface.
+ *
+ * \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_nobch(struct sig_pri_pri *pri)
+{
+ int idx;
+
+ 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) {
+ ast_debug(1, "Found empty available no B channel interface\n");
+ return idx;
+ }
+ }
+
+ /* Need to create a new interface. */
+ if (pri->calls->new_nobch_intf) {
+ idx = pri->calls->new_nobch_intf(pri);
+ } else {
+ idx = -1;
+ }
+ return idx;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Find the channel associated with the libpri call.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri span controller to find interface.
+ * \param call LibPRI opaque call pointer to find.
+ *
+ * \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_pri_call(struct sig_pri_pri *pri, q931_call *call)
+{
+ int idx;
+
+ for (idx = 0; idx < pri->numchans; ++idx) {
+ if (pri->pvts[idx] && pri->pvts[idx]->call == call) {
+ /* Found the channel */
+ return idx;
+ }
+ }
+ return -1;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
static void *do_idle_thread(void *vchan)
{
struct ast_channel *chan = vchan;
@@ -1309,6 +1459,10 @@ static void sig_pri_lock_owner(struct sig_pri_pri *pri, int chanpos)
* \param event_id PRI event id
* \param channel PRI encoded span/channel
* \param subcmds Subcommands to process if any. (Could be NULL).
+ * \param call_rsp libpri opaque call structure to send any responses toward.
+ * Could be NULL either because it is not available or the call is for the
+ * dummy call reference. However, this should not be NULL in the cases that
+ * need to use the pointer to send a response message back.
*
* \note Assumes the pri->lock is already obtained.
* \note Assumes the sig_pri_lock_private(pri->pvts[chanpos]) is already obtained.
@@ -1316,7 +1470,7 @@ static void sig_pri_lock_owner(struct sig_pri_pri *pri, int chanpos)
* \return Nothing
*/
static void sig_pri_handle_subcmds(struct sig_pri_pri *pri, int chanpos, int event_id,
- int channel, const struct pri_subcommands *subcmds)
+ int channel, const struct pri_subcommands *subcmds, q931_call *call_rsp)
{
int index;
struct ast_channel *owner;
@@ -1403,6 +1557,63 @@ static void sig_pri_handle_subcmds(struct sig_pri_pri *pri, int chanpos, int eve
ast_channel_unlock(owner);
}
break;
+#if defined(HAVE_PRI_CALL_REROUTING)
+ case PRI_SUBCMD_REROUTING:
+ sig_pri_lock_owner(pri, chanpos);
+ owner = pri->pvts[chanpos]->owner;
+ if (owner) {
+ struct pri_party_redirecting pri_deflection;
+
+ if (!call_rsp) {
+ ast_channel_unlock(owner);
+ ast_log(LOG_WARNING,
+ "CallRerouting/CallDeflection to '%s' without call!\n",
+ subcmd->u.rerouting.deflection.to.number.str);
+ break;
+ }
+
+ pri_deflection = subcmd->u.rerouting.deflection;
+
+ ast_string_field_set(owner, call_forward, pri_deflection.to.number.str);
+
+ /* Adjust the deflecting to number based upon the subscription option. */
+ switch (subcmd->u.rerouting.subscription_option) {
+ case 0: /* noNotification */
+ case 1: /* notificationWithoutDivertedToNr */
+ /* Delete the number because the far end is not supposed to see it. */
+ pri_deflection.to.number.presentation =
+ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
+ pri_deflection.to.number.plan =
+ (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
+ pri_deflection.to.number.str[0] = '\0';
+ break;
+ case 2: /* notificationWithDivertedToNr */
+ break;
+ case 3: /* notApplicable */
+ default:
+ break;
+ }
+ sig_pri_redirecting_convert(&ast_redirecting, &pri_deflection,
+ &owner->redirecting, pri);
+ ast_channel_set_redirecting(owner, &ast_redirecting);
+ ast_party_redirecting_free(&ast_redirecting);
+
+ /*
+ * Send back positive ACK to CallRerouting/CallDeflection.
+ *
+ * Note: This call will be hungup by the dial application when
+ * it processes the call_forward string set above.
+ */
+ pri_rerouting_rsp(pri->pri, call_rsp, subcmd->u.rerouting.invoke_id,
+ PRI_REROUTING_RSP_OK_CLEAR);
+
+ /* This line is BUSY to further attempts by this dialing attempt. */
+ ast_queue_control(owner, AST_CONTROL_BUSY);
+
+ ast_channel_unlock(owner);
+ }
+ break;
+#endif /* defined(HAVE_PRI_CALL_REROUTING) */
default:
ast_debug(2,
"Unknown call subcommand(%d) in %s event on channel %d/%d on span %d.\n",
@@ -1413,6 +1624,220 @@ static void sig_pri_handle_subcmds(struct sig_pri_pri *pri, int chanpos, int eve
}
}
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Attempt to transfer the active call to the held call.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param active_call Active call to transfer.
+ * \param held_call Held call to transfer.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int sig_pri_attempt_transfer(struct sig_pri_pri *pri, q931_call *active_call, q931_call *held_call)
+{
+ int retval;
+ int active_chanpos;
+ int held_chanpos;
+ struct ast_channel *active_ast;
+ struct ast_channel *held_ast;
+ struct ast_channel *bridged;
+
+ active_chanpos = pri_find_pri_call(pri, active_call);
+ held_chanpos = pri_find_pri_call(pri, held_call);
+ if (active_chanpos < 0 || held_chanpos < 0) {
+ return -1;
+ }
+
+ sig_pri_lock_private(pri->pvts[active_chanpos]);
+ sig_pri_lock_private(pri->pvts[held_chanpos]);
+ sig_pri_lock_owner(pri, active_chanpos);
+ sig_pri_lock_owner(pri, held_chanpos);
+
+ active_ast = pri->pvts[active_chanpos]->owner;
+ held_ast = pri->pvts[held_chanpos]->owner;
+ if (!active_ast || !held_ast) {
+ if (active_ast) {
+ ast_channel_unlock(active_ast);
+ }
+ if (held_ast) {
+ ast_channel_unlock(held_ast);
+ }
+ sig_pri_unlock_private(pri->pvts[active_chanpos]);
+ sig_pri_unlock_private(pri->pvts[held_chanpos]);
+ return -1;
+ }
+
+ bridged = ast_bridged_channel(held_ast);
+ if (bridged) {
+ ast_queue_control(held_ast, AST_CONTROL_UNHOLD);
+
+ ast_verb(3, "TRANSFERRING %s to %s\n", held_ast->name, active_ast->name);
+ retval = ast_channel_masquerade(active_ast, bridged);
+ } else {
+ /*
+ * Could not transfer. Held channel is not bridged anymore.
+ * Held party probably got tired of waiting and hung up.
+ */
+ retval = -1;
+ }
+
+ ast_channel_unlock(active_ast);
+ ast_channel_unlock(held_ast);
+ sig_pri_unlock_private(pri->pvts[active_chanpos]);
+ sig_pri_unlock_private(pri->pvts[held_chanpos]);
+
+ return retval;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Handle the hold event from libpri.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param ev Hold event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int sig_pri_handle_hold(struct sig_pri_pri *pri, pri_event *ev)
+{
+ int retval;
+ int chanpos_old;
+ int chanpos_new;
+ struct ast_channel *bridged;
+ struct ast_channel *owner;
+
+ chanpos_old = pri_find_principle(pri, ev->hold.channel, ev->hold.call);
+ if (chanpos_old < 0) {
+ ast_log(LOG_WARNING,
+ "Received HOLD on unconfigured channel %d/%d span %d\n",
+ PRI_SPAN(ev->hold.channel), PRI_CHANNEL(ev->hold.channel), pri->span);
+ return -1;
+ }
+ if (pri->pvts[chanpos_old]->no_b_channel) {
+ /* Call is already on hold or is call waiting call. */
+ return -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,
+ ev->hold.call);
+ 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, };
+
+ f.subclass = AST_CONTROL_HOLD;
+ ast_queue_frame(owner, &f);
+ retval = 0;
+ }
+
+done_with_owner:;
+ ast_channel_unlock(owner);
+done_with_private:;
+ sig_pri_unlock_private(pri->pvts[chanpos_old]);
+
+ return retval;
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
+#if defined(HAVE_PRI_CALL_HOLD)
+/*!
+ * \internal
+ * \brief Handle the retrieve event from libpri.
+ * \since 1.6.3
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param ev Retrieve event received.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_handle_retrieve(struct sig_pri_pri *pri, pri_event *ev)
+{
+ int chanpos;
+
+ if (!(ev->retrieve.channel & PRI_HELD_CALL)
+ || pri_find_principle(pri, ev->retrieve.channel, ev->retrieve.call) < 0) {
+ /* The call is not currently held. */
+ pri_retrieve_rej(pri->pri, ev->retrieve.call,
+ PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+ return;
+ }
+ if (PRI_CHANNEL(ev->retrieve.channel) == 0xFF) {
+ chanpos = pri_find_empty_chan(pri, 1);
+ } else {
+ chanpos = pri_find_principle(pri,
+ ev->retrieve.channel & ~PRI_HELD_CALL, ev->retrieve.call);
+ if (ev->retrieve.flexible
+ && (chanpos < 0 || pri->pvts[chanpos]->owner)) {
+ /*
+ * Channel selection is flexible and the requested channel
+ * is bad or already in use. Pick another channel.
+ */
+ chanpos = pri_find_empty_chan(pri, 1);
+ }
+ }
+ if (chanpos < 0) {
+ pri_retrieve_rej(pri->pri, ev->retrieve.call,
+ ev->retrieve.flexible ? PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION
+ : PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+ return;
+ }
+ chanpos = pri_fixup_principle(pri, chanpos, ev->retrieve.call);
+ if (chanpos < 0) {
+ /* Channel is already in use. */
+ pri_retrieve_rej(pri->pri, ev->retrieve.call,
+ PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
+ return;
+ }
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ sig_pri_handle_subcmds(pri, chanpos, ev->e, ev->retrieve.channel,
+ ev->retrieve.subcmds, ev->retrieve.call);
+ {
+ struct ast_frame f = { AST_FRAME_CONTROL, };
+
+ f.subclass = AST_CONTROL_UNHOLD;
+ pri_queue_frame(pri->pvts[chanpos], &f, pri);
+ }
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ pri_retrieve_ack(pri->pri, ev->retrieve.call,
+ PVT_TO_CHANNEL(pri->pvts[chanpos]));
+}
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+
static void *pri_dchannel(void *vpri)
{
struct sig_pri_pri *pri = vpri;
@@ -1489,8 +1914,10 @@ static void *pri_dchannel(void *vpri)
haveidles = 0;
activeidles = 0;
for (x = pri->numchans; x >= 0; x--) {
- if (pri->pvts[x] && !pri->pvts[x]->owner &&
- !pri->pvts[x]->call) {
+ 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) {
@@ -1643,6 +2070,11 @@ static void *pri_dchannel(void *vpri)
pri_find_dchan(pri);
if (!pri_is_up(pri)) {
pri->resetting = 0;
+ if (pri->sig == SIG_BRI_PTMP) {
+ /* For PTMP connections with non persistent layer 2 we want
+ * to *not* declare inalarm unless there actually is an alarm */
+ break;
+ }
/* Hangup active channels and put them in alarm mode */
for (i = 0; i < pri->numchans; i++) {
struct sig_pri_chan *p = pri->pvts[i];
@@ -1660,18 +2092,14 @@ static void *pri_dchannel(void *vpri)
if (p->owner)
ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
}
- /* For PTMP connections with non persistent layer 2 we want
- * to *not* declare inalarm unless there actually is an alarm */
- if (p->pri->sig != SIG_BRI_PTMP) {
- p->inalarm = 1;
- }
+ p->inalarm = 1;
}
}
}
break;
case PRI_EVENT_RESTART:
if (e->restart.channel > -1) {
- chanpos = pri_find_principle(pri, e->restart.channel);
+ chanpos = pri_find_principle(pri, e->restart.channel, NULL);
if (chanpos < 0)
ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n",
PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
@@ -1726,7 +2154,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_KEYPAD_DIGIT:
- chanpos = pri_find_principle(pri, e->digit.channel);
+ chanpos = pri_find_principle(pri, e->digit.channel, e->digit.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
@@ -1735,7 +2163,7 @@ static void *pri_dchannel(void *vpri)
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->digit.channel,
- e->digit.subcmds);
+ e->digit.subcmds, e->digit.call);
/* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
&& pri->pvts[chanpos]->call == e->digit.call
@@ -1756,7 +2184,7 @@ static void *pri_dchannel(void *vpri)
break;
case PRI_EVENT_INFO_RECEIVED:
- chanpos = pri_find_principle(pri, e->ring.channel);
+ chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
@@ -1765,7 +2193,7 @@ static void *pri_dchannel(void *vpri)
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->ring.channel,
- e->ring.subcmds);
+ e->ring.subcmds, e->ring.call);
/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
&& pri->pvts[chanpos]->call == e->ring.call
@@ -1786,7 +2214,7 @@ static void *pri_dchannel(void *vpri)
break;
#ifdef HAVE_PRI_SERVICE_MESSAGES
case PRI_EVENT_SERVICE:
- chanpos = pri_find_principle(pri, e->service.channel);
+ chanpos = pri_find_principle(pri, e->service.channel, NULL);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Received service change status %d on unconfigured channel %d/%d span %d\n",
e->service_ack.changestatus, PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span);
@@ -1827,7 +2255,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_SERVICE_ACK:
- chanpos = pri_find_principle(pri, e->service_ack.channel);
+ chanpos = pri_find_principle(pri, e->service_ack.channel, NULL);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Received service acknowledge change status '%d' on unconfigured channel %d/%d span %d\n",
e->service_ack.changestatus, PRI_SPAN(e->service_ack.channel), PRI_CHANNEL(e->service_ack.channel), pri->span);
@@ -1850,7 +2278,7 @@ static void *pri_dchannel(void *vpri)
if (e->ring.channel == -1)
chanpos = pri_find_empty_chan(pri, 1);
else
- chanpos = pri_find_principle(pri, e->ring.channel);
+ chanpos = pri_find_principle(pri, e->ring.channel, e->ring.call);
/* if no channel specified find one empty */
if (chanpos < 0) {
ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n",
@@ -2028,9 +2456,14 @@ static void *pri_dchannel(void *vpri)
#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.subcmds, e->ring.call);
}
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",
@@ -2121,12 +2554,17 @@ static void *pri_dchannel(void *vpri)
#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.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",
@@ -2161,7 +2599,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_RINGING:
- chanpos = pri_find_principle(pri, e->ringing.channel);
+ chanpos = pri_find_principle(pri, e->ringing.channel, e->ringing.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
@@ -2174,7 +2612,7 @@ static void *pri_dchannel(void *vpri)
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->ringing.channel,
- e->ringing.subcmds);
+ e->ringing.subcmds, e->ringing.call);
sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
pri_queue_control(pri->pvts[chanpos], AST_CONTROL_RINGING, pri);
pri->pvts[chanpos]->alerting = 1;
@@ -2199,11 +2637,11 @@ static void *pri_dchannel(void *vpri)
break;
case PRI_EVENT_PROGRESS:
/* Get chan value if e->e is not PRI_EVNT_RINGING */
- chanpos = pri_find_principle(pri, e->proceeding.channel);
+ chanpos = pri_find_principle(pri, e->proceeding.channel, e->proceeding.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
- e->proceeding.subcmds);
+ e->proceeding.subcmds, e->proceeding.call);
if ((!pri->pvts[chanpos]->progress)
#ifdef PRI_PROGRESS_MASK
|| (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
@@ -2248,11 +2686,11 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_PROCEEDING:
- chanpos = pri_find_principle(pri, e->proceeding.channel);
+ chanpos = pri_find_principle(pri, e->proceeding.channel, e->proceeding.call);
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
- e->proceeding.subcmds);
+ e->proceeding.subcmds, e->proceeding.call);
if (!pri->pvts[chanpos]->proceeding) {
struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
@@ -2277,7 +2715,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_FACILITY:
- chanpos = pri_find_principle(pri, e->facility.channel);
+ chanpos = pri_find_principle(pri, e->facility.channel, e->facility.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Facility requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span);
@@ -2288,14 +2726,19 @@ static void *pri_dchannel(void *vpri)
PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span);
} else {
sig_pri_lock_private(pri->pvts[chanpos]);
+#if defined(HAVE_PRI_CALL_REROUTING)
+ sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.channel,
+ e->facility.subcmds, e->facility.subcall);
+#else
sig_pri_handle_subcmds(pri, chanpos, e->e, e->facility.channel,
- e->facility.subcmds);
+ e->facility.subcmds, e->facility.call);
+#endif /* !defined(HAVE_PRI_CALL_REROUTING) */
sig_pri_unlock_private(pri->pvts[chanpos]);
}
}
break;
case PRI_EVENT_ANSWER:
- chanpos = pri_find_principle(pri, e->answer.channel);
+ chanpos = pri_find_principle(pri, e->answer.channel, e->answer.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
@@ -2308,7 +2751,7 @@ static void *pri_dchannel(void *vpri)
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
- e->answer.subcmds);
+ e->answer.subcmds, e->answer.call);
pri_queue_control(pri->pvts[chanpos], AST_CONTROL_ANSWER, pri);
/* Enable echo cancellation if it's not on already */
sig_pri_set_dialing(pri->pvts[chanpos], 0);
@@ -2333,7 +2776,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_HANGUP:
- chanpos = pri_find_principle(pri, e->hangup.channel);
+ chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
@@ -2342,7 +2785,7 @@ static void *pri_dchannel(void *vpri)
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.channel,
- e->hangup.subcmds);
+ e->hangup.subcmds, e->hangup.call);
if (!pri->pvts[chanpos]->alreadyhungup) {
/* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
pri->pvts[chanpos]->alreadyhungup = 1;
@@ -2412,7 +2855,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_HANGUP_REQ:
- chanpos = pri_find_principle(pri, e->hangup.channel);
+ chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
@@ -2421,7 +2864,19 @@ static void *pri_dchannel(void *vpri)
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->hangup.channel,
- e->hangup.subcmds);
+ e->hangup.subcmds, e->hangup.call);
+#if defined(HAVE_PRI_CALL_HOLD)
+ if (e->hangup.call_active && e->hangup.call_held
+ && pri->hold_disconnect_transfer) {
+ /* We are to transfer the call instead of simply hanging up. */
+ sig_pri_unlock_private(pri->pvts[chanpos]);
+ if (!sig_pri_attempt_transfer(pri, e->hangup.call_active,
+ e->hangup.call_held)) {
+ break;
+ }
+ sig_pri_lock_private(pri->pvts[chanpos]);
+ }
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
if (pri->pvts[chanpos]->owner) {
pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
switch (pri->pvts[chanpos]->owner->_state) {
@@ -2484,7 +2939,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_HANGUP_ACK:
- chanpos = pri_find_principle(pri, e->hangup.channel);
+ chanpos = pri_find_principle(pri, e->hangup.channel, e->hangup.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n",
PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
@@ -2520,7 +2975,7 @@ static void *pri_dchannel(void *vpri)
ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err);
break;
case PRI_EVENT_RESTART_ACK:
- chanpos = pri_find_principle(pri, e->restartack.channel);
+ chanpos = pri_find_principle(pri, e->restartack.channel, NULL);
if (chanpos < 0) {
/* Sometime switches (e.g. I421 / British Telecom) don't give us the
channel number, so we have to figure it out... This must be why
@@ -2567,7 +3022,7 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_SETUP_ACK:
- chanpos = pri_find_principle(pri, e->setup_ack.channel);
+ chanpos = pri_find_principle(pri, e->setup_ack.channel, e->setup_ack.call);
if (chanpos < 0) {
ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
@@ -2576,7 +3031,7 @@ static void *pri_dchannel(void *vpri)
if (chanpos > -1) {
sig_pri_lock_private(pri->pvts[chanpos]);
sig_pri_handle_subcmds(pri, chanpos, e->e, e->setup_ack.channel,
- e->setup_ack.subcmds);
+ e->setup_ack.subcmds, e->setup_ack.call);
pri->pvts[chanpos]->setup_ack = 1;
/* Send any queued digits */
for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) {
@@ -2590,14 +3045,23 @@ static void *pri_dchannel(void *vpri)
}
break;
case PRI_EVENT_NOTIFY:
- chanpos = pri_find_principle(pri, e->notify.channel);
+#if defined(HAVE_PRI_CALL_HOLD)
+ chanpos = pri_find_principle(pri, e->notify.channel, e->notify.call);
+#else
+ chanpos = pri_find_principle(pri, e->notify.channel, NULL);
+#endif /* !defined(HAVE_PRI_CALL_HOLD) */
if (chanpos < 0) {
ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n",
PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span);
} else {
sig_pri_lock_private(pri->pvts[chanpos]);
+#if defined(HAVE_PRI_CALL_HOLD)
sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.channel,
- e->notify.subcmds);
+ e->notify.subcmds, e->notify.call);
+#else
+ sig_pri_handle_subcmds(pri, chanpos, e->e, e->notify.channel,
+ e->notify.subcmds, NULL);
+#endif /* !defined(HAVE_PRI_CALL_HOLD) */
switch (e->notify.info) {
case PRI_NOTIFY_REMOTE_HOLD:
if (!pri->discardremoteholdretrieval) {
@@ -2619,6 +3083,41 @@ static void *pri_dchannel(void *vpri)
sig_pri_unlock_private(pri->pvts[chanpos]);
}
break;
+#if defined(HAVE_PRI_CALL_HOLD)
+ case PRI_EVENT_HOLD:
+ if (sig_pri_handle_hold(pri, e)) {
+ pri_hold_rej(pri->pri, e->hold.call,
+ PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED);
+ } else {
+ pri_hold_ack(pri->pri, e->hold.call);
+ }
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CALL_HOLD)
+ case PRI_EVENT_HOLD_ACK:
+ ast_debug(1, "Event: HOLD_ACK\n");
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CALL_HOLD)
+ case PRI_EVENT_HOLD_REJ:
+ ast_debug(1, "Event: HOLD_REJ\n");
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CALL_HOLD)
+ case PRI_EVENT_RETRIEVE:
+ sig_pri_handle_retrieve(pri, e);
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CALL_HOLD)
+ case PRI_EVENT_RETRIEVE_ACK:
+ ast_debug(1, "Event: RETRIEVE_ACK\n");
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CALL_HOLD)
+ case PRI_EVENT_RETRIEVE_REJ:
+ ast_debug(1, "Event: RETRIEVE_REJ\n");
+ break;
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
default:
ast_debug(1, "Event: %d\n", e->e);
break;
@@ -2727,6 +3226,9 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i
int prilocaldialplan;
int ldp_strip;
int exclusive;
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+ const char *keypad;
+#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
ast_log(LOG_DEBUG, "CALLING CID_NAME: %s CID_NUM:: %s\n", ast->cid.cid_name, ast->cid.cid_num);
@@ -2752,6 +3254,34 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i
c = "";
}
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+ /*
+ * v--- c points here
+ * /[K<keypad-digits>/]extension
+ */
+ if (c[0] == 'K') {
+ /* Extract the keypad facility digits. */
+ keypad = c + 1;
+ c = strchr(keypad, '/');
+ if (c) {
+ /* Terminate the keypad facility digits. */
+ *c++ = '\0';
+ } else {
+ c = "";
+ }
+ if (ast_strlen_zero(keypad)) {
+ /* What no keypad digits? */
+ keypad = NULL;
+ }
+ } else {
+ keypad = NULL;
+ }
+ /*
+ * v--- c points here
+ * /extension
+ */
+#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
+
/* setup dialed_subaddress if found */
ast_party_subaddress_init(&dialed_subaddress);
s = strchr(c, ':');
@@ -2894,6 +3424,11 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i
pri_sr_set_reversecharge(sr, PRI_REVERSECHARGE_REQUESTED);
break;
#endif
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+ case 'K':
+ /* Reserve this letter for keypad facility digits. */
+ break;
+#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
default:
if (isalpha(c[p->stripmsd])) {
ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n",
@@ -2903,7 +3438,15 @@ int sig_pri_call(struct sig_pri_chan *p, struct ast_channel *ast, char *rdest, i
}
c++;
}
- pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
+#if defined(HAVE_PRI_SETUP_KEYPAD)
+ if (keypad) {
+ pri_sr_set_keypad_digits(sr, keypad);
+ }
+ if (!keypad || !ast_strlen_zero(c + p->stripmsd + dp_strip))
+#endif /* defined(HAVE_PRI_SETUP_KEYPAD) */
+ {
+ pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
+ }
#if defined(HAVE_PRI_SUBADDR)
if (dialed_subaddress.valid) {
@@ -3198,8 +3741,8 @@ int sig_pri_answer(struct sig_pri_chan *p, struct ast_channel *ast)
int sig_pri_available(struct sig_pri_chan *p, int channelmatch, ast_group_t groupmatch, int *reason, int *channelmatched, int *groupmatched)
{
- /* If no owner definitely available */
- if (!p->owner && p->pri) {
+ /* If no owner and interface has a B channel then likely available */
+ if (!p->owner && !p->no_b_channel && p->pri) {
#ifdef HAVE_PRI_SERVICE_MESSAGES
char db_chan_name[20], db_answer[5], state;
int why = 0;
@@ -3285,6 +3828,12 @@ int sig_pri_start_pri(struct sig_pri_pri *pri)
#ifdef HAVE_PRI_INBANDDISCONNECT
pri_set_inbanddisconnect(pri->dchans[i], pri->inbanddisconnect);
#endif
+#if defined(HAVE_PRI_CALL_HOLD)
+ pri_hold_enable(pri->dchans[i], 1);
+#endif /* defined(HAVE_PRI_CALL_HOLD) */
+#if defined(HAVE_PRI_CALL_REROUTING)
+ pri_reroute_enable(pri->dchans[i], 1);
+#endif /* defined(HAVE_PRI_CALL_REROUTING) */
/* Enslave to master if appropriate */
if (i)
pri_enslave(pri->dchans[0], pri->dchans[i]);
@@ -3475,19 +4024,11 @@ int pri_send_callrerouting_facility_exec(struct sig_pri_chan *p, enum ast_channe
return -1;
}
- switch (p->pri->sig) {
- case SIG_PRI:
- if (!pri_grab(p, p->pri)) {
- if (chanstate == AST_STATE_RING) {
- res = pri_callrerouting_facility(p->pri->pri, p->call, destination, original, reason);
- }
- pri_rel(p->pri);
- } else {
- ast_log(LOG_DEBUG, "Unable to grab pri to send callrerouting facility on span %d!\n", p->pri->span);
- sig_pri_unlock_private(p);
- return -1;
- }
- break;
+ if (!pri_grab(p, p->pri)) {
+ res = pri_callrerouting_facility(p->pri->pri, p->call, destination, original, reason);
+ pri_rel(p->pri);
+ } else {
+ ast_log(LOG_DEBUG, "Unable to grab pri to send callrerouting facility on span %d!\n", p->pri->span);
}
sig_pri_unlock_private(p);