[asterisk-commits] rmudgett: trunk r267261 - in /trunk: ./ channels/ configs/ include/asterisk/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jun 2 16:05:35 CDT 2010


Author: rmudgett
Date: Wed Jun  2 16:05:32 2010
New Revision: 267261

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=267261
Log:
Add ETSI Call Waiting support.

Add the ability to announce a call to an endpoint when there are no B
channels available.  A call waiting call is a SETUP message with no B
channel selected.

Relevant specification: EN 300 056, EN 300 057, EN 300 058

For DAHDI/ISDN channels, the CHANNEL() dialplan function now supports the
"no_media_path" option.
* Returns "0" if there is a B channel associated with the call.
* Returns "1" if no B channel is associated with the call.  The call is
either on hold or is a call waiting call.

If you are going to allow incoming call waiting calls then you need to use
CHANNEL(no_media_path) do determine if you must drop a call to accept the
new call.

Review:	https://reviewboard.asterisk.org/r/568/

Modified:
    trunk/CHANGES
    trunk/channels/chan_dahdi.c
    trunk/channels/sig_pri.c
    trunk/channels/sig_pri.h
    trunk/configs/chan_dahdi.conf.sample
    trunk/configure
    trunk/configure.ac
    trunk/include/asterisk/autoconfig.h.in

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=267261&r1=267260&r2=267261
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Wed Jun  2 16:05:32 2010
@@ -205,6 +205,11 @@
    prefixing the name of the hash at assignment with the appropriate number of
    underscores, just like variables.
  * GROUP_MATCH_COUNT has been improved to allow regex matching on category
+ * For DAHDI/ISDN channels, the CHANNEL() dialplan function now supports the
+   "no_media_path" option.
+   Returns "0" if there is a B channel associated with the call.
+   Returns "1" if no B channel is associated with the call.  The call is either
+   on hold or is a call waiting call.
 
 Dialplan Variables
 ------------------
@@ -339,6 +344,8 @@
    back into the same interface.  Tromboned calls happen because of call routing,
    call deflection, call forwarding, and call transfer.
  * Added the ability to send and receive ETSI Advice-Of-Charge messages. 
+ * Added the ability to support call waiting calls.  (The SETUP has no B channel
+   assigned.)
 
 Asterisk Manager Interface
 --------------------------

Modified: trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=267261&r1=267260&r2=267261
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Wed Jun  2 16:05:32 2010
@@ -800,7 +800,10 @@
 	unsigned int didtdd:1;				/*!< flag to say its done it once */
 	/*! \brief TRUE if analog type line dialed no digits in Dial() */
 	unsigned int dialednone:1;
-	/*! \brief TRUE if in the process of dialing digits or sending something. */
+	/*!
+	 * \brief TRUE if in the process of dialing digits or sending something.
+	 * \note This is used as a receive squelch for ISDN until connected.
+	 */
 	unsigned int dialing:1;
 	/*! \brief TRUE if the transfer capability of the call is digital. */
 	unsigned int digital:1;
@@ -1075,6 +1078,8 @@
 	 * \note The "group" bitmapped group string read in from chan_dahdi.conf
 	 */
 	ast_group_t group;
+	/*! \brief Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW. */
+	int law_default;
 	/*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
 	int law;
 	int confno;					/*!< Our conference */
@@ -2232,7 +2237,8 @@
 		p->dsp = NULL;
 	}
 
-	law = DAHDI_LAW_DEFAULT;
+	p->law = p->law_default;
+	law = p->law_default;
 	res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
 	if (res < 0)
 		ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
@@ -2391,10 +2397,22 @@
 	int audio;
 	int newlaw = -1;
 
-	/* Set to audio mode at this point */
-	audio = 1;
-	if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1)
-		ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, audio, strerror(errno));
+	switch (p->sig) {
+	case SIG_PRI_LIB_HANDLE_CASES:
+		if (((struct sig_pri_chan *) p->sig_pvt)->no_b_channel) {
+			/* PRI nobch pseudo channel.  Does not handle ioctl(DAHDI_AUDIOMODE) */
+			break;
+		}
+		/* Fall through */
+	default:
+		/* Set to audio mode at this point */
+		audio = 1;
+		if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &audio) == -1) {
+			ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n",
+				p->channel, audio, strerror(errno));
+		}
+		break;
+	}
 
 	if (law != SIG_PRI_DEFLAW) {
 		dahdi_setlaw(p->subs[SUB_REAL].dfd, (law == SIG_PRI_ULAW) ? DAHDI_LAW_MULAW : DAHDI_LAW_ALAW);
@@ -2414,6 +2432,54 @@
 			break;
 	}
 	return dahdi_new(p, state, startpbx, SUB_REAL, newlaw, transfercapability, requestor ? requestor->linkedid : "");
+}
+#endif	/* defined(HAVE_PRI) */
+
+static int set_actual_gain(int fd, float rxgain, float txgain, float rxdrc, float txdrc, int law);
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Open the PRI channel media path.
+ * \since 1.8
+ *
+ * \param p Channel private control structure.
+ *
+ * \return Nothing
+ */
+static void my_pri_open_media(void *p)
+{
+	struct dahdi_pvt *pvt = p;
+	int res;
+	int dfd;
+	int set_val;
+
+	dfd = pvt->subs[SUB_REAL].dfd;
+
+	/* Open the media path. */
+	set_val = 1;
+	res = ioctl(dfd, DAHDI_AUDIOMODE, &set_val);
+	if (res < 0) {
+		ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n",
+			pvt->channel, strerror(errno));
+	}
+
+	/* Set correct companding law for this call. */
+	res = dahdi_setlaw(dfd, pvt->law);
+	if (res < 0) {
+		ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pvt->channel);
+	}
+
+	/* Set correct gain for this call. */
+	if (pvt->digital) {
+		res = set_actual_gain(dfd, 0, 0, pvt->rxdrc, pvt->txdrc, pvt->law);
+	} else {
+		res = set_actual_gain(dfd, pvt->rxgain, pvt->txgain, pvt->rxdrc, pvt->txdrc,
+			pvt->law);
+	}
+	if (res < 0) {
+		ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pvt->channel);
+	}
 }
 #endif	/* defined(HAVE_PRI) */
 
@@ -2734,6 +2800,17 @@
 	new_chan->dsp_features = old_chan->dsp_features;
 	old_chan->dsp = NULL;
 	old_chan->dsp_features = 0;
+
+	/* Transfer flags from the old channel. */
+	new_chan->dialing = old_chan->dialing;
+	new_chan->digital = old_chan->digital;
+	new_chan->outgoing = old_chan->outgoing;
+	old_chan->dialing = 0;
+	old_chan->digital = 0;
+	old_chan->outgoing = 0;
+
+	/* More stuff to transfer to the new channel. */
+	new_chan->law = old_chan->law;
 }
 
 static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
@@ -2997,6 +3074,9 @@
 	ast_module_unref(ast_module_info->self);
 }
 
+#if defined(HAVE_PRI_CALL_WAITING)
+static void my_pri_init_config(void *priv, struct sig_pri_pri *pri);
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 static int dahdi_new_pri_nobch_channel(struct sig_pri_pri *pri);
 
 static struct sig_pri_callback dahdi_pri_callbacks =
@@ -3016,11 +3096,15 @@
 	.set_dnid = my_pri_set_dnid,
 	.set_rdnis = my_pri_set_rdnis,
 	.new_nobch_intf = dahdi_new_pri_nobch_channel,
+#if defined(HAVE_PRI_CALL_WAITING)
+	.init_config = my_pri_init_config,
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 	.get_orig_dialstring = my_get_orig_dialstring,
 	.make_cc_dialstring = my_pri_make_cc_dialstring,
 	.update_span_devstate = dahdi_pri_update_span_devstate,
 	.module_ref = my_module_ref,
 	.module_unref = my_module_unref,
+	.open_media = my_pri_open_media,
 };
 #endif	/* defined(HAVE_PRI) */
 
@@ -3155,6 +3239,7 @@
 	.set_needringing = my_set_needringing,
 };
 
+/*! Round robin search locations. */
 static struct dahdi_pvt *round_robin[32];
 
 #if defined(HAVE_SS7)
@@ -4179,7 +4264,7 @@
 	if (slavechannel < 1) {
 		p->confno = zi.confno;
 	}
-	memcpy(&c->curconf, &zi, sizeof(c->curconf));
+	c->curconf = zi;
 	ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
 	return 0;
 }
@@ -4850,13 +4935,8 @@
 
 #ifdef HAVE_PRI
 	if (dahdi_sig_pri_lib_handles(p->sig)) {
-		struct dahdi_params ps;
-
-		memset(&ps, 0, sizeof(ps));
-		if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps)) {
-			ast_log(LOG_ERROR, "Could not get params\n");
-		}
-		res = sig_pri_call(p->sig_pvt, ast, rdest, timeout, (ps.curlaw == DAHDI_LAW_MULAW) ? PRI_LAYER_1_ULAW : PRI_LAYER_1_ALAW);
+		res = sig_pri_call(p->sig_pvt, ast, rdest, timeout,
+			(p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW);
 		ast_mutex_unlock(&p->lock);
 		return res;
 	}
@@ -5736,7 +5816,8 @@
 		}
 		revert_fax_buffers(p, ast);
 		dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
-		law = DAHDI_LAW_DEFAULT;
+		p->law = p->law_default;
+		law = p->law_default;
 		res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
 		dahdi_disable_ec(p);
 		update_conf(p);
@@ -5907,7 +5988,8 @@
 
 		revert_fax_buffers(p, ast);
 
-		law = DAHDI_LAW_DEFAULT;
+		p->law = p->law_default;
+		law = p->law_default;
 		res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
 		if (res < 0)
 			ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
@@ -6464,6 +6546,22 @@
 		}
 		ast_mutex_unlock(&p->lock);
 #endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
+	} else if (!strcasecmp(data, "no_media_path")) {
+		ast_mutex_lock(&p->lock);
+		switch (p->sig) {
+		case SIG_PRI_LIB_HANDLE_CASES:
+			/*
+			 * TRUE if the call is on hold or is call waiting because
+			 * there is no media path available.
+			 */
+			snprintf(buf, len, "%d", ((struct sig_pri_chan *) p->sig_pvt)->no_b_channel);
+			break;
+		default:
+			*buf = '\0';
+			res = -1;
+			break;
+		}
+		ast_mutex_unlock(&p->lock);
 #endif	/* defined(HAVE_PRI) */
 	} else {
 		*buf = '\0';
@@ -8871,12 +8969,10 @@
 {
 	struct ast_channel *tmp;
 	format_t deflaw;
-	int res;
 	int x;
 	int features;
 	struct ast_str *chan_name;
 	struct ast_variable *v;
-	struct dahdi_params ps;
 
 	if (i->subs[idx].owner) {
 		ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
@@ -8907,21 +9003,29 @@
 	}
 #endif	/* defined(HAVE_PRI) */
 	ast_channel_cc_params_init(tmp, i->cc_params);
-	memset(&ps, 0, sizeof(ps));
-	res = ioctl(i->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps);
-	if (res) {
-		ast_log(LOG_WARNING, "Unable to get parameters, assuming MULAW: %s\n", strerror(errno));
-		ps.curlaw = DAHDI_LAW_MULAW;
-	}
-	if (ps.curlaw == DAHDI_LAW_ALAW)
-		deflaw = AST_FORMAT_ALAW;
-	else
-		deflaw = AST_FORMAT_ULAW;
 	if (law) {
-		if (law == DAHDI_LAW_ALAW)
+		i->law = law;
+		if (law == DAHDI_LAW_ALAW) {
 			deflaw = AST_FORMAT_ALAW;
-		else
+		} else {
 			deflaw = AST_FORMAT_ULAW;
+		}
+	} else {
+		switch (i->sig) {
+		case SIG_PRI_LIB_HANDLE_CASES:
+			/* Make sure companding law is known. */
+			i->law = (i->law_default == DAHDI_LAW_ALAW)
+				? DAHDI_LAW_ALAW : DAHDI_LAW_MULAW;
+			break;
+		default:
+			i->law = i->law_default;
+			break;
+		}
+		if (i->law_default == DAHDI_LAW_ALAW) {
+			deflaw = AST_FORMAT_ALAW;
+		} else {
+			deflaw = AST_FORMAT_ULAW;
+		}
 	}
 	ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
 	tmp->nativeformats = deflaw;
@@ -11538,6 +11642,7 @@
 					destroy_dahdi_pvt(tmp);
 					return NULL;
 				}
+				tmp->law_default = p.curlaw;
 				tmp->law = p.curlaw;
 				tmp->span = p.spanno;
 				span = p.spanno - 1;
@@ -11777,6 +11882,12 @@
 						pris[span].pri.cc_qsig_signaling_link_rsp =
 							conf->pri.pri.cc_qsig_signaling_link_rsp;
 #endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CALL_WAITING)
+						pris[span].pri.max_call_waiting_calls =
+							conf->pri.pri.max_call_waiting_calls;
+						pris[span].pri.allow_call_waiting_calls =
+							conf->pri.pri.allow_call_waiting_calls;
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 						pris[span].pri.transfer = conf->chan.transfer;
 						pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
 #if defined(HAVE_PRI_AOC_EVENTS)
@@ -11796,6 +11907,20 @@
 						for (x = 0; x < PRI_MAX_TIMERS; x++) {
 							pris[span].pri.pritimers[x] = conf->pri.pri.pritimers[x];
 						}
+
+#if defined(HAVE_PRI_CALL_WAITING)
+						/* Channel initial config parameters. */
+						pris[span].pri.ch_cfg.stripmsd = conf->chan.stripmsd;
+						pris[span].pri.ch_cfg.hidecallerid = conf->chan.hidecallerid;
+						pris[span].pri.ch_cfg.hidecalleridname = conf->chan.hidecalleridname;
+						pris[span].pri.ch_cfg.immediate = conf->chan.immediate;
+						pris[span].pri.ch_cfg.priexclusive = conf->chan.priexclusive;
+						pris[span].pri.ch_cfg.priindication_oob = conf->chan.priindication_oob;
+						pris[span].pri.ch_cfg.use_callerid = conf->chan.use_callerid;
+						pris[span].pri.ch_cfg.use_callingpres = conf->chan.use_callingpres;
+						ast_copy_string(pris[span].pri.ch_cfg.context, conf->chan.context, sizeof(pris[span].pri.ch_cfg.context));
+						ast_copy_string(pris[span].pri.ch_cfg.mohinterpret, conf->chan.mohinterpret, sizeof(pris[span].pri.ch_cfg.mohinterpret));
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 					} else {
 						ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", p.chanpos);
 						destroy_dahdi_pvt(tmp);
@@ -12266,8 +12391,10 @@
 	return 1;
 }
 
-static int available(struct dahdi_pvt *p)
-{
+static int available(struct dahdi_pvt **pvt, int is_specific_channel)
+{
+	struct dahdi_pvt *p = *pvt;
+
 	if (p->inalarm)
 		return 0;
 
@@ -12277,7 +12404,15 @@
 #ifdef HAVE_PRI
 	switch (p->sig) {
 	case SIG_PRI_LIB_HANDLE_CASES:
-		return sig_pri_available(p->sig_pvt);
+		{
+			struct sig_pri_chan *pvt_chan;
+			int res;
+
+			pvt_chan = p->sig_pvt;
+			res = sig_pri_available(&pvt_chan, is_specific_channel);
+			*pvt = pvt_chan->chan_pvt;
+			return res;
+		}
 	default:
 		break;
 	}
@@ -12314,6 +12449,38 @@
 
 	return 0;
 }
+
+#if defined(HAVE_PRI)
+#if defined(HAVE_PRI_CALL_WAITING)
+/*!
+ * \internal
+ * \brief Init the private channel configuration using the span controller.
+ * \since 1.8
+ *
+ * \param priv Channel to init the configuration.
+ * \param pri sig_pri PRI control structure.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void my_pri_init_config(void *priv, struct sig_pri_pri *pri)
+{
+	struct dahdi_pvt *pvt = priv;
+
+	pvt->stripmsd = pri->ch_cfg.stripmsd;
+	pvt->hidecallerid = pri->ch_cfg.hidecallerid;
+	pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
+	pvt->immediate = pri->ch_cfg.immediate;
+	pvt->priexclusive = pri->ch_cfg.priexclusive;
+	pvt->priindication_oob = pri->ch_cfg.priindication_oob;
+	pvt->use_callerid = pri->ch_cfg.use_callerid;
+	pvt->use_callingpres = pri->ch_cfg.use_callingpres;
+	ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
+	ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
+}
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+#endif	/* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
 /*!
@@ -12381,7 +12548,15 @@
 	}
 	chan->no_b_channel = 1;
 
+	/*
+	 * Pseudo channel companding law.
+	 * Needed for outgoing call waiting calls.
+	 * XXX May need to make this determined by switchtype or user option.
+	 */
+	pvt->law_default = DAHDI_LAW_ALAW;
+
 	pvt->sig = pri->sig;
+	pvt->outsigmod = -1;
 	pvt->pri = pri;
 	pvt->sig_pvt = chan;
 	pri->pvts[pvt_idx] = chan;
@@ -12577,13 +12752,18 @@
 			} else
 				p = iflist;
 		} else {
+			if (ARRAY_LEN(round_robin) <= x) {
+				ast_log(LOG_WARNING, "Round robin index %d out of range for data %s\n",
+					x, data);
+				return NULL;
+			}
 			if (args.group[0] == 'R') {
 				param->backwards = 1;
-				p = round_robin[x]?round_robin[x]->prev:ifend;
+				p = round_robin[x] ? round_robin[x]->prev : ifend;
 				if (!p)
 					p = ifend;
 			} else {
-				p = round_robin[x]?round_robin[x]->next:iflist;
+				p = round_robin[x] ? round_robin[x]->next : iflist;
 				if (!p)
 					p = iflist;
 			}
@@ -12643,7 +12823,7 @@
 			round_robin[start.rr_starting_point] = p;
 
 		if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
-			&& available(p)) {
+			&& available(&p, channelmatched)) {
 			ast_debug(1, "Using channel %d\n", p->channel);
 
 			callwait = (p->owner != NULL);
@@ -12702,6 +12882,20 @@
 			}
 			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 (((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);
+					}
+					break;
+				default:
+					break;
+				}
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+#endif	/* defined(HAVE_PRI) */
 			} else {
 				snprintf(p->dialstring, sizeof(p->dialstring), "DAHDI/%s", (char *) data);
 			}
@@ -15090,7 +15284,7 @@
 			ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
 			ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
 			ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
-			ast_cli(a->fd, "Default law: %s\n", tmp->law == DAHDI_LAW_MULAW ? "ulaw" : tmp->law == DAHDI_LAW_ALAW ? "alaw" : "unknown");
+			ast_cli(a->fd, "Default law: %s\n", tmp->law_default == DAHDI_LAW_MULAW ? "ulaw" : tmp->law_default == DAHDI_LAW_ALAW ? "alaw" : "unknown");
 			ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
 			ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
 			ast_cli(a->fd, "Gains (RX/TX): %.2f/%.2f\n", tmp->rxgain, tmp->txgain);
@@ -17246,6 +17440,16 @@
 					confp->pri.pri.cc_qsig_signaling_link_rsp = 1;/* retain */
 				}
 #endif	/* defined(HAVE_PRI_CCSS) */
+#if defined(HAVE_PRI_CALL_WAITING)
+			} else if (!strcasecmp(v->name, "max_call_waiting_calls")) {
+				confp->pri.pri.max_call_waiting_calls = atoi(v->value);
+				if (confp->pri.pri.max_call_waiting_calls < 0) {
+					/* Negative values are not allowed. */
+					confp->pri.pri.max_call_waiting_calls = 0;
+				}
+			} else if (!strcasecmp(v->name, "allow_call_waiting_calls")) {
+				confp->pri.pri.allow_call_waiting_calls = ast_true(v->value);
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 #endif /* HAVE_PRI */
 #ifdef HAVE_SS7
 			} else if (!strcasecmp(v->name, "ss7type")) {

Modified: trunk/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_pri.c?view=diff&rev=267261&r1=267260&r2=267261
==============================================================================
--- trunk/channels/sig_pri.c (original)
+++ trunk/channels/sig_pri.c Wed Jun  2 16:05:32 2010
@@ -814,6 +814,26 @@
 	return c;
 }
 
+/*!
+ * \internal
+ * \brief Open the PRI channel media path.
+ * \since 1.8
+ *
+ * \param p Channel private control structure.
+ *
+ * \return Nothing
+ */
+static void sig_pri_open_media(struct sig_pri_chan *p)
+{
+	if (p->no_b_channel) {
+		return;
+	}
+
+	if (p->calls->open_media) {
+		p->calls->open_media(p->chan_pvt);
+	}
+}
+
 struct ast_channel *sig_pri_request(struct sig_pri_chan *p, enum sig_pri_law law, const struct ast_channel *requestor, int transfercapability)
 {
 	struct ast_channel *ast;
@@ -982,15 +1002,17 @@
 	int x;
 	int span;
 	int principle;
+	int prioffset;
 
 	if (channel < 0) {
 		/* Channel is not picked yet. */
 		return -1;
 	}
 
-	if (channel & PRI_HELD_CALL) {
+	prioffset = PRI_CHANNEL(channel);
+	if (!prioffset || (channel & PRI_HELD_CALL)) {
 		if (!call) {
-			/* Cannot find a held call without a call. */
+			/* Cannot find a call waiting call or held call without a call. */
 			return -1;
 		}
 		principle = -1;
@@ -1015,11 +1037,10 @@
 		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]->prioffset == prioffset
 			&& pri->pvts[x]->logicalspan == span
 			&& !pri->pvts[x]->no_b_channel) {
 			principle = x;
@@ -1079,6 +1100,11 @@
 		old_chan->call = NULL;
 
 		/* Transfer flags from the old channel. */
+#if defined(HAVE_PRI_AOC_EVENTS)
+		new_chan->aoc_s_request_invoke_id_valid = old_chan->aoc_s_request_invoke_id_valid;
+		new_chan->waiting_for_aoce = old_chan->waiting_for_aoce;
+		new_chan->holding_aoce = old_chan->holding_aoce;
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 		new_chan->alerting = old_chan->alerting;
 		new_chan->alreadyhungup = old_chan->alreadyhungup;
 		new_chan->isidlecall = old_chan->isidlecall;
@@ -1087,17 +1113,14 @@
 		new_chan->setup_ack = old_chan->setup_ack;
 		new_chan->outgoing = old_chan->outgoing;
 		new_chan->digital = old_chan->digital;
+#if defined(HAVE_PRI_CALL_WAITING)
+		new_chan->is_call_waiting = old_chan->is_call_waiting;
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+
 #if defined(HAVE_PRI_AOC_EVENTS)
-		new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
-		new_chan->aoc_s_request_invoke_id_valid = old_chan->aoc_s_request_invoke_id_valid;
-		new_chan->holding_aoce = old_chan->holding_aoce;
-		new_chan->waiting_for_aoce = old_chan->waiting_for_aoce;
-		new_chan->aoc_e = old_chan->aoc_e;
-
-		old_chan->holding_aoce = 0;
 		old_chan->aoc_s_request_invoke_id_valid = 0;
 		old_chan->waiting_for_aoce = 0;
-		memset(&old_chan->aoc_e, 0, sizeof(&old_chan->aoc_e));
+		old_chan->holding_aoce = 0;
 #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 		old_chan->alerting = 0;
 		old_chan->alreadyhungup = 0;
@@ -1107,6 +1130,9 @@
 		old_chan->setup_ack = 0;
 		old_chan->outgoing = 0;
 		old_chan->digital = 0;
+#if defined(HAVE_PRI_CALL_WAITING)
+		old_chan->is_call_waiting = 0;
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 
 		/* More stuff to transfer to the new channel. */
 #if defined(HAVE_PRI_REVERSE_CHARGE)
@@ -1115,6 +1141,10 @@
 #if defined(HAVE_PRI_SETUP_KEYPAD)
 		strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
 #endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
+#if defined(HAVE_PRI_AOC_EVENTS)
+		new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
+		new_chan->aoc_e = old_chan->aoc_e;
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 
 		if (new_chan->no_b_channel) {
 			/* Copy the real channel configuration to the no B channel interface. */
@@ -1222,6 +1252,38 @@
 	}
 	return 0;
 }
+
+#if defined(HAVE_PRI_CALL_WAITING)
+/*!
+ * \internal
+ * \brief Init the private channel configuration using the span controller.
+ * \since 1.8
+ *
+ * \param pvt Channel to init the configuration.
+ * \param pri sig_pri PRI control structure.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_init_config(struct sig_pri_chan *pvt, struct sig_pri_pri *pri)
+{
+	pvt->stripmsd = pri->ch_cfg.stripmsd;
+	pvt->hidecallerid = pri->ch_cfg.hidecallerid;
+	pvt->hidecalleridname = pri->ch_cfg.hidecalleridname;
+	pvt->immediate = pri->ch_cfg.immediate;
+	pvt->priexclusive = pri->ch_cfg.priexclusive;
+	pvt->priindication_oob = pri->ch_cfg.priindication_oob;
+	pvt->use_callerid = pri->ch_cfg.use_callerid;
+	pvt->use_callingpres = pri->ch_cfg.use_callingpres;
+	ast_copy_string(pvt->context, pri->ch_cfg.context, sizeof(pvt->context));
+	ast_copy_string(pvt->mohinterpret, pri->ch_cfg.mohinterpret, sizeof(pvt->mohinterpret));
+
+	if (pri->calls->init_config) {
+		pri->calls->init_config(pvt->chan_pvt, pri);
+	}
+}
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 
 static int pri_find_empty_chan(struct sig_pri_pri *pri, int backwards)
 {
@@ -3519,7 +3581,8 @@
 			sig_pri_lock_owner(pri, chanpos);
 			owner = pri->pvts[chanpos]->owner;
 			if (owner) {
-				sig_pri_aoc_s_from_pri(&subcmd->u.aoc_s, owner, (pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S));
+				sig_pri_aoc_s_from_pri(&subcmd->u.aoc_s, owner,
+					(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S));
 				ast_channel_unlock(owner);
 			}
 			break;
@@ -3530,7 +3593,8 @@
 			owner = pri->pvts[chanpos]->owner;
 			if (owner) {
 				/* Queue AST_CONTROL_AOC frame on channel */
-				sig_pri_aoc_d_from_pri(&subcmd->u.aoc_d, owner, (pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_D));
+				sig_pri_aoc_d_from_pri(&subcmd->u.aoc_d, owner,
+					(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_D));
 				ast_channel_unlock(owner);
 			}
 			break;
@@ -3540,7 +3604,8 @@
 			sig_pri_lock_owner(pri, chanpos);
 			owner = pri->pvts[chanpos]->owner;
 			/* Queue AST_CONTROL_AOC frame */
-			sig_pri_aoc_e_from_pri(&subcmd->u.aoc_e, owner, (pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E));
+			sig_pri_aoc_e_from_pri(&subcmd->u.aoc_e, owner,
+				(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_E));
 			if (owner) {
 				ast_channel_unlock(owner);
 			}
@@ -3551,20 +3616,25 @@
 			sig_pri_lock_owner(pri, chanpos);
 			owner = pri->pvts[chanpos]->owner;
 			if (owner) {
-				sig_pri_aoc_request_from_pri(&subcmd->u.aoc_request, pri->pvts[chanpos], call_rsp);
+				sig_pri_aoc_request_from_pri(&subcmd->u.aoc_request, pri->pvts[chanpos],
+					call_rsp);
 				ast_channel_unlock(owner);
 			}
 			break;
 #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 #if defined(HAVE_PRI_AOC_EVENTS)
 		case PRI_SUBCMD_AOC_CHARGING_REQ_RSP:
-			/* An AOC request response may contain an AOC-S rate list.  If this is the case handle this just like we
-			 * would an incoming AOC-S msg */
+			/*
+			 * An AOC request response may contain an AOC-S rate list.
+			 * If this is the case handle this just like we
+			 * would an incoming AOC-S msg.
+			 */
 			if (subcmd->u.aoc_request_response.valid_aoc_s) {
 				sig_pri_lock_owner(pri, chanpos);
 				owner = pri->pvts[chanpos]->owner;
 				if (owner) {
-					sig_pri_aoc_s_from_pri(&subcmd->u.aoc_request_response.aoc_s, owner, (pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S));
+					sig_pri_aoc_s_from_pri(&subcmd->u.aoc_request_response.aoc_s, owner,
+						(pri->aoc_passthrough_flag & SIG_PRI_AOC_GRANT_S));
 					ast_channel_unlock(owner);
 				}
 			}
@@ -4175,10 +4245,33 @@
 						e->ring.call);
 					break;
 				}
-				if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF)
+				if (e->ring.channel == -1 || PRI_CHANNEL(e->ring.channel) == 0xFF) {
+					/* Any channel requested. */
 					chanpos = pri_find_empty_chan(pri, 1);
-				else
+				} else if (PRI_CHANNEL(e->ring.channel) == 0x00) {
+					/* No channel specified. */
+#if defined(HAVE_PRI_CALL_WAITING)
+					if (!pri->allow_call_waiting_calls)
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+					{
+						/* We will not accept incoming call waiting calls. */
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INCOMPATIBLE_DESTINATION);
+						break;
+					}
+#if defined(HAVE_PRI_CALL_WAITING)
+					chanpos = pri_find_empty_nobch(pri);
+					if (chanpos < 0) {
+						/* We could not find/create a call interface. */
+						pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+						break;
+					}
+					/* Setup the call interface to use. */
+					sig_pri_init_config(pri->pvts[chanpos], pri);
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+				} else {
+					/* A channel is specified. */
 					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",
@@ -4571,43 +4664,33 @@
 					sig_pri_lock_private(pri->pvts[chanpos]);
 					sig_pri_handle_subcmds(pri, chanpos, e->e, e->proceeding.channel,
 						e->proceeding.subcmds, e->proceeding.call);
-					if ((!pri->pvts[chanpos]->progress)
+
+					if (e->proceeding.cause > -1) {
+						ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
+
+						/* Work around broken, out of spec USER_BUSY cause in a progress message */
+						if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
+							if (pri->pvts[chanpos]->owner) {
+								ast_verb(3, "PROGRESS with 'user busy' received, signaling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
+
+								pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
+								pri_queue_control(pri, chanpos, AST_CONTROL_BUSY);
+							}
+						}
+					}
+
+					if (!pri->pvts[chanpos]->progress
+						&& !pri->pvts[chanpos]->no_b_channel
 #ifdef PRI_PROGRESS_MASK
-						|| (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
+						&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
 #else
-						|| (e->proceeding.progress == 8)
+						&& e->proceeding.progress == 8
 #endif
 						) {
-						int subclass;
-
-						subclass = AST_CONTROL_PROGRESS;
-						if (e->proceeding.cause > -1) {
-							ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
-
-							/* Work around broken, out of spec USER_BUSY cause in a progress message */
-							if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
-								if (pri->pvts[chanpos]->owner) {
-									ast_verb(3, "PROGRESS with 'user busy' received, signaling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
-
-									pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
-									subclass = AST_CONTROL_BUSY;
-								}
-							}
-						}
-
+						/* Bring voice path up */
 						ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
 							pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
-						pri_queue_control(pri, chanpos, subclass);
-						if (
-#ifdef PRI_PROGRESS_MASK
-							e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE
-#else
-							e->proceeding.progress == 8
-#endif
-							) {
-							/* Bring voice path up */
-							pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
-						}
+						pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
 						pri->pvts[chanpos]->progress = 1;
 						sig_pri_set_dialing(pri->pvts[chanpos], 0);
 					}
@@ -4629,17 +4712,19 @@
 						ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
 							pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
 						pri_queue_control(pri, chanpos, AST_CONTROL_PROCEEDING);
-						if (
+						pri->pvts[chanpos]->proceeding = 1;
+					}
+					if (!pri->pvts[chanpos]->progress
+						&& !pri->pvts[chanpos]->no_b_channel
 #ifdef PRI_PROGRESS_MASK
-							e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE
+						&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
 #else
-							e->proceeding.progress == 8
+						&& e->proceeding.progress == 8
 #endif
-							) {
-							/* Bring voice path up */
-							pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
-						}
-						pri->pvts[chanpos]->proceeding = 1;
+						) {
+						/* Bring voice path up */
+						pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
+						pri->pvts[chanpos]->progress = 1;
 						sig_pri_set_dialing(pri->pvts[chanpos], 0);
 					}
 					sig_pri_unlock_private(pri->pvts[chanpos]);
@@ -4689,39 +4774,127 @@
 				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);
+					break;
+				}
+				chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n",
+						PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
+					break;
+				}
+#if defined(HAVE_PRI_CALL_WAITING)
+				if (pri->pvts[chanpos]->is_call_waiting) {
+					if (pri->pvts[chanpos]->no_b_channel) {
+						int new_chanpos;
+
+						/*
+						 * Need to find a free channel now or
+						 * kill the call with PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION.
+						 */
+						new_chanpos = pri_find_empty_chan(pri, 1);
+						if (new_chanpos < 0) {
+							sig_pri_lock_private(pri->pvts[chanpos]);
+							sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
+								e->answer.subcmds, e->answer.call);
+							sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCBS);
+							if (pri->pvts[chanpos]->owner) {
+								pri->pvts[chanpos]->owner->hangupcause = PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+								switch (pri->pvts[chanpos]->owner->_state) {
+								case AST_STATE_BUSY:
+								case AST_STATE_UP:
+									ast_softhangup_nolock(pri->pvts[chanpos]->owner, AST_SOFTHANGUP_DEV);
+									break;
+								default:
+									pri_queue_control(pri, chanpos, AST_CONTROL_CONGESTION);
+									break;
+								}
+							} else {
+								pri->pvts[chanpos]->is_call_waiting = 0;
+								ast_atomic_fetchadd_int(&pri->num_call_waiting_calls, -1);
+								pri_hangup(pri->pri, e->answer.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
+								pri->pvts[chanpos]->call = NULL;
+							}
+							sig_pri_unlock_private(pri->pvts[chanpos]);
+							break;
+						}
+						chanpos = pri_fixup_principle(pri, new_chanpos, e->answer.call);
+						if (chanpos < 0) {
+							ast_log(LOG_WARNING,
+								"Unable to move call waiting call channel on span %d\n",
+								pri->span);
+							break;
+						}
+					}
+					pri_connect_ack(pri->pri, e->answer.call, PVT_TO_CHANNEL(pri->pvts[chanpos]));
 				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
-					if (chanpos < 0) {
-						ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n",
-							PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
-					} else {
-						sig_pri_lock_private(pri->pvts[chanpos]);
-
-						sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
-							e->answer.subcmds, e->answer.call);
-						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);
+					/* Call is normal so do normal CONNECT_ACKNOWLEDGE. */
+					pri_connect_ack(pri->pri, e->answer.call, 0);
+				}
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+				sig_pri_lock_private(pri->pvts[chanpos]);
+
+#if defined(HAVE_PRI_CALL_WAITING)
+				if (pri->pvts[chanpos]->is_call_waiting) {
+					pri->pvts[chanpos]->is_call_waiting = 0;
+					ast_atomic_fetchadd_int(&pri->num_call_waiting_calls, -1);
+					sig_pri_span_devstate_changed(pri);
+				}
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->answer.channel,
+					e->answer.subcmds, e->answer.call);
+				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)) {
-							struct ast_channel *owner;
-
-							sig_pri_lock_owner(pri, chanpos);
-							owner = pri->pvts[chanpos]->owner;
-							if (owner) {
-								pbx_builtin_setvar_helper(owner, "USERUSERINFO",
-									e->answer.useruserinfo);
-								ast_channel_unlock(owner);
-							}
-						}
+				if (!ast_strlen_zero(e->answer.useruserinfo)) {
+					struct ast_channel *owner;
+
+					sig_pri_lock_owner(pri, chanpos);
+					owner = pri->pvts[chanpos]->owner;
+					if (owner) {
+						pbx_builtin_setvar_helper(owner, "USERUSERINFO",
+							e->answer.useruserinfo);
+						ast_channel_unlock(owner);
+					}
+				}
 #endif
 
-						sig_pri_unlock_private(pri->pvts[chanpos]);
-					}
-				}
+				sig_pri_unlock_private(pri->pvts[chanpos]);
 				break;
+#if defined(HAVE_PRI_CALL_WAITING)
+			case PRI_EVENT_CONNECT_ACK:
+				if (sig_pri_is_cis_call(e->connect_ack.channel)) {
+					sig_pri_handle_cis_subcmds(pri, e->e, e->connect_ack.subcmds,
+						e->connect_ack.call);
+					break;
+				}
+				chanpos = pri_find_principle(pri, e->connect_ack.channel,
+					e->connect_ack.call);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "Connect ACK on unconfigured channel %d/%d span %d\n",
+						PRI_SPAN(e->connect_ack.channel),
+						PRI_CHANNEL(e->connect_ack.channel), pri->span);
+					break;
+				}
+				chanpos = pri_fixup_principle(pri, chanpos, e->connect_ack.call);
+				if (chanpos < 0) {
+					ast_log(LOG_WARNING, "Connect ACK requested on channel %d/%d not in use on span %d\n",
+						PRI_SPAN(e->connect_ack.channel),
+						PRI_CHANNEL(e->connect_ack.channel), pri->span);
+					break;
+				}
+
+				sig_pri_lock_private(pri->pvts[chanpos]);
+				sig_pri_span_devstate_changed(pri);
+				sig_pri_handle_subcmds(pri, chanpos, e->e, e->connect_ack.channel,
+					e->connect_ack.subcmds, e->connect_ack.call);
+				sig_pri_open_media(pri->pvts[chanpos]);
+				sig_pri_unlock_private(pri->pvts[chanpos]);
+				break;
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 			case PRI_EVENT_HANGUP:
 				if (sig_pri_is_cis_call(e->hangup.channel)) {
 					sig_pri_handle_cis_subcmds(pri, e->e, e->hangup.subcmds,
@@ -4880,7 +5053,6 @@
 							sig_pri_lock_private(pri->pvts[chanpos]);
 						}
 #endif	/* defined(HAVE_PRI_CALL_HOLD) */
-
 						switch (e->hangup.cause) {
 						case PRI_CAUSE_USER_BUSY:
 						case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
@@ -5207,6 +5379,12 @@
 	p->owner = NULL;
 	p->outgoing = 0;
 	sig_pri_set_digital(p, 0);	/* push up to parent for EC*/
+#if defined(HAVE_PRI_CALL_WAITING)
+	if (p->is_call_waiting) {
+		p->is_call_waiting = 0;
+		ast_atomic_fetchadd_int(&p->pri->num_call_waiting_calls, -1);
+	}
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 	p->proceeding = 0;
 	p->progress = 0;
 	p->alerting = 0;
@@ -5248,13 +5426,11 @@
 					if (atoi(cause))
 						icause = atoi(cause);
 				}
-
 #if defined(HAVE_PRI_AOC_EVENTS)
 				if (p->holding_aoce) {
 					pri_aoc_e_send(p->pri->pri, p->call, &p->aoc_e);
 				}
 #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
-
 				pri_hangup(p->pri->pri, p->call, icause);
 			}
 		}
@@ -5271,7 +5447,6 @@
 	p->holding_aoce = 0;
 	p->waiting_for_aoce = 0;
 #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
-
 	ast->tech_pvt = NULL;
 	return res;
 }
@@ -5356,6 +5531,7 @@
 enum SIG_PRI_CALL_OPT_ARGS {
 	OPT_ARG_KEYPAD = 0,
 	OPT_ARG_AOC_REQUEST,
+
 	/* note: this entry _MUST_ be the last one in the enum */
 	OPT_ARG_ARRAY_SIZE,
 };
@@ -5482,14 +5658,25 @@
 
 	sig_pri_set_digital(p, IS_DIGITAL(ast->transfercapability));	/* push up to parent for EC */
 
-	/* Should the picked channel be used exclusively? */
-	if (p->priexclusive || p->pri->nodetype == PRI_NETWORK) {
-		exclusive = 1;
-	} else {
-		exclusive = 0;
-	}
-
-	pri_sr_set_channel(sr, PVT_TO_CHANNEL(p), exclusive, 1);
+#if defined(HAVE_PRI_CALL_WAITING)
+	if (p->is_call_waiting) {
+		/*
+		 * Indicate that this is a call waiting call.
+		 * i.e., Normal call but with no B channel.
+		 */
+		pri_sr_set_channel(sr, 0, 0, 1);
+	} else
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
+	{
+		/* Should the picked channel be used exclusively? */
+		if (p->priexclusive || p->pri->nodetype == PRI_NETWORK) {
+			exclusive = 1;
+		} else {
+			exclusive = 0;
+		}
+		pri_sr_set_channel(sr, PVT_TO_CHANNEL(p), exclusive, 1);
+	}
+
 	pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability,
 		(p->digital ? -1 : layer1));
 
@@ -5567,9 +5754,9 @@
 		}
 		c++;
 	}
-
 #if defined(HAVE_PRI_AOC_EVENTS)
-	if (ast_test_flag(&opts, OPT_AOC_REQUEST) && !ast_strlen_zero(opt_args[OPT_ARG_AOC_REQUEST])) {
+	if (ast_test_flag(&opts, OPT_AOC_REQUEST)
+		&& !ast_strlen_zero(opt_args[OPT_ARG_AOC_REQUEST])) {
 		if (strchr(opt_args[OPT_ARG_AOC_REQUEST], 's')) {
 			pri_sr_set_aoc_charging_request(sr, PRI_AOC_REQUEST_S);
 		}
@@ -5581,7 +5768,6 @@
 		}
 	}
 #endif	/* defined(HAVE_PRI_AOC_EVENTS) */
-
 #if defined(HAVE_PRI_SETUP_KEYPAD)
 	if (ast_test_flag(&opts, OPT_KEYPAD)
 		&& !ast_strlen_zero(opt_args[OPT_ARG_KEYPAD])) {
@@ -5762,7 +5948,7 @@
 
 	switch (condition) {
 	case AST_CONTROL_BUSY:
-		if (p->priindication_oob) {
+		if (p->priindication_oob || p->no_b_channel) {
 			chan->hangupcause = AST_CAUSE_USER_BUSY;
 			chan->_softhangup |= AST_SOFTHANGUP_DEV;
 			res = 0;

[... 458 lines stripped ...]



More information about the asterisk-commits mailing list