[asterisk-commits] rmudgett: branch rmudgett/misdn_facility r182399 - in /team/rmudgett/misdn_fa...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Mar 16 17:02:23 CDT 2009


Author: rmudgett
Date: Mon Mar 16 17:02:18 2009
New Revision: 182399

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=182399
Log:
Merged revisions 182398 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/team/group/issue8824

........
  r182398 | mmichelson | 2009-03-16 16:46:54 -0500 (Mon, 16 Mar 2009) | 3 lines
  
  Reset automerge, resolve conflicts, butt heads with a raging goat-demon
........

Modified:
    team/rmudgett/misdn_facility/   (props changed)
    team/rmudgett/misdn_facility/CHANGES
    team/rmudgett/misdn_facility/CREDITS
    team/rmudgett/misdn_facility/UPGRADE.txt
    team/rmudgett/misdn_facility/channels/chan_dahdi.c
    team/rmudgett/misdn_facility/configs/chan_dahdi.conf.sample
    team/rmudgett/misdn_facility/configure
    team/rmudgett/misdn_facility/configure.ac
    team/rmudgett/misdn_facility/include/asterisk/autoconfig.h.in
    team/rmudgett/misdn_facility/makeopts.in

Propchange: team/rmudgett/misdn_facility/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/rmudgett/misdn_facility/
------------------------------------------------------------------------------
--- misdn-facility (original)
+++ misdn-facility Mon Mar 16 17:02:18 2009
@@ -1,1 +1,1 @@
-/team/group/issue8824:1-182392
+/team/group/issue8824:1-182398

Propchange: team/rmudgett/misdn_facility/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Mar 16 17:02:18 2009
@@ -1,1 +1,1 @@
-/trunk:1-182299
+/trunk:1-182397

Modified: team/rmudgett/misdn_facility/CHANGES
URL: http://svn.digium.com/svn-view/asterisk/team/rmudgett/misdn_facility/CHANGES?view=diff&rev=182399&r1=182398&r2=182399
==============================================================================
--- team/rmudgett/misdn_facility/CHANGES (original)
+++ team/rmudgett/misdn_facility/CHANGES Mon Mar 16 17:02:18 2009
@@ -7,6 +7,9 @@
 === and the other UPGRADE files for older releases.
 ===
 ======================================================================
+------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 1.6.2 to Asterisk 1.6.3  -------------
+------------------------------------------------------------------------------
 
 ------------------------------------------------------------------------------
 --- Functionality changes for COLP feature -----------------------------------
@@ -134,6 +137,8 @@
 
 DAHDI Changes
 -------------
+ * chan_dahdi now supports MFC/R2 signaling when Asterisk is compiled with
+   support for LibOpenR2.  http://www.libopenr2.org/
  * The UK option waitfordialtone has been added for use with BT analog
    lines.
  * Added a 'faxbuffers' configuration option to chan_dahdi.conf.  This option

Modified: team/rmudgett/misdn_facility/CREDITS
URL: http://svn.digium.com/svn-view/asterisk/team/rmudgett/misdn_facility/CREDITS?view=diff&rev=182399&r1=182398&r2=182399
==============================================================================
--- team/rmudgett/misdn_facility/CREDITS (original)
+++ team/rmudgett/misdn_facility/CREDITS Mon Mar 16 17:02:18 2009
@@ -194,6 +194,9 @@
 
 Klaus Darillon - the SIPremoveHeader function in chan_sip
 
+Moises Silva (moy) - for writing LibOpenR2, and providing support for it in chan_dahdi
+     moises.silva(AT)gmail.com
+
 === OTHER CONTRIBUTIONS ===
 John Todd - Monkey sounds and associated teletorture prompt
 Michael Jerris - bug marshaling

Modified: team/rmudgett/misdn_facility/UPGRADE.txt
URL: http://svn.digium.com/svn-view/asterisk/team/rmudgett/misdn_facility/UPGRADE.txt?view=diff&rev=182399&r1=182398&r2=182399
==============================================================================
--- team/rmudgett/misdn_facility/UPGRADE.txt (original)
+++ team/rmudgett/misdn_facility/UPGRADE.txt Mon Mar 16 17:02:18 2009
@@ -17,6 +17,10 @@
 === UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
 ===
 ===========================================================
+
+From 1.6.2 to 1.6.3:
+
+* Nothing, yet!
 
 From 1.6.1 to 1.6.2:
 

Modified: team/rmudgett/misdn_facility/channels/chan_dahdi.c
URL: http://svn.digium.com/svn-view/asterisk/team/rmudgett/misdn_facility/channels/chan_dahdi.c?view=diff&rev=182399&r1=182398&r2=182399
==============================================================================
--- team/rmudgett/misdn_facility/channels/chan_dahdi.c (original)
+++ team/rmudgett/misdn_facility/channels/chan_dahdi.c Mon Mar 16 17:02:18 2009
@@ -43,6 +43,7 @@
 	<depend>tonezone</depend>
 	<use>pri</use>
 	<use>ss7</use>
+	<use>openr2</use>
  ***/
 
 #include "asterisk.h"
@@ -68,6 +69,10 @@
 
 #ifdef HAVE_SS7
 #include <libss7.h>
+#endif
+
+#ifdef HAVE_OPENR2
+#include <openr2.h>
 #endif
 
 #include "asterisk/lock.h"
@@ -100,6 +105,7 @@
 #include "asterisk/astobj.h"
 #include "asterisk/event.h"
 #include "asterisk/devicestate.h"
+#include "asterisk/paths.h"
 
 /*** DOCUMENTATION
 	<application name="DAHDISendKeypadFacility" language="en_US">
@@ -134,6 +140,23 @@
 			current channel.</para>
 		</description>
 	</application>
+	<application name="DAHDIAcceptR2Call" language="en_US">
+		<synopsis>
+			Accept an R2 call if its not already accepted (you still need to answer it)
+		</synopsis>
+		<syntax>
+			<parameter name="charge" required="true">
+				<para>Yes or No.</para>
+				<para>Whether you want to accept the call with charge or without charge.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>This application will Accept the R2 call either with charge or no charge.</para>
+		</description>
+		<description>
+			<para>This application will Accept the R2 call either with charge or no charge.</para>
+		</description>
+	</application>
  ***/
 
 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
@@ -192,11 +215,25 @@
 #define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB))
 
 static const char tdesc[] = "DAHDI Telephony Driver"
+#if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
+	" w/"
+#endif
 #ifdef HAVE_PRI
-	" w/PRI"
+	"PRI"
 #endif
 #ifdef HAVE_SS7
-	" w/SS7"
+	#ifdef HAVE_PRI
+	" & SS7"
+	#else
+	"SS7"
+	#endif
+#endif
+#ifdef HAVE_OPENR2
+	#if defined(HAVE_PRI) || defined(HAVE_SS7)
+	" & MFC/R2"
+	#else
+	"MFC/R2"
+	#endif
 #endif
 ;
 
@@ -221,6 +258,7 @@
 #define SIG_BRI		(0x2000000 | DAHDI_SIG_CLEAR)
 #define SIG_BRI_PTMP	(0X4000000 | DAHDI_SIG_CLEAR)
 #define SIG_SS7		(0x1000000 | DAHDI_SIG_CLEAR)
+#define SIG_MFCR2 	DAHDI_SIG_CAS
 #define	SIG_SF		DAHDI_SIG_SF
 #define SIG_SFWINK 	(0x0100000 | DAHDI_SIG_SF)
 #define SIG_SF_FEATD	(0x0200000 | DAHDI_SIG_SF)
@@ -421,6 +459,44 @@
 static int cur_networkindicator = -1;
 static int cur_defaultdpc = -1;
 #endif /* HAVE_SS7 */
+
+#ifdef HAVE_OPENR2
+struct dahdi_mfcr2 {
+	pthread_t r2master;		       /*!< Thread of master */
+	openr2_context_t *protocol_context;    /*!< OpenR2 context handle */
+	struct dahdi_pvt *pvts[MAX_CHANNELS];     /*!< Member channel pvt structs */
+	int numchans;                          /*!< Number of channels in this R2 block */
+	int monitored_count;                   /*!< Number of channels being monitored */
+	ast_mutex_t monitored_count_lock;      /*!< lock access to the counter */ 
+	ast_cond_t do_monitor;                 /*!< Condition to wake up the monitor thread when there's work to do */
+
+};
+struct dahdi_mfcr2_conf {
+	openr2_variant_t variant;
+	int mfback_timeout;
+	int metering_pulse_timeout;
+	int max_ani;
+	int max_dnis;
+	int get_ani_first:1;
+	int call_files:1;
+	int allow_collect_calls:1;
+	int charge_calls:1;
+	int accept_on_offer:1;
+	int forced_release:1;
+	int double_answer:1;
+	int immediate_accept:1;
+	char logdir[OR2_MAX_PATH];
+	char r2proto_file[OR2_MAX_PATH];
+	openr2_log_level_t loglevel;
+	openr2_calling_party_category_t category;
+};
+
+/* malloc'd array of malloc'd r2links */
+static struct dahdi_mfcr2 **r2links; 
+/* how many r2links have been malloc'd */
+static int r2links_count = 0; 
+
+#endif /* HAVE_OPENR2 */
 
 #ifdef HAVE_PRI
 
@@ -1132,6 +1208,22 @@
 	unsigned int dpc;						/*!< CIC's DPC */
 	unsigned int loopedback:1;
 #endif
+#ifdef HAVE_OPENR2
+	struct dahdi_mfcr2 *mfcr2;
+	openr2_chan_t *r2chan;
+	openr2_calling_party_category_t mfcr2_recvd_category;
+	openr2_calling_party_category_t mfcr2_category;
+	int mfcr2_dnis_index;
+	int mfcr2_ani_index;
+	int mfcr2call:1;
+	int mfcr2_answer_pending:1;
+	int mfcr2_charge_calls:1;
+	int mfcr2_allow_collect_calls:1;
+	int mfcr2_forced_release:1;
+	int mfcr2_dnis_matched:1;
+	int mfcr2_call_accepted:1;
+	int mfcr2_accept_on_offer:1;
+#endif
 	/*! \brief DTMF digit in progress.  0 when no digit in progress. */
 	char begindigit;
 	/*! \brief TRUE if confrence is muted. */
@@ -1157,6 +1249,10 @@
 #ifdef HAVE_SS7
 	struct dahdi_ss7 ss7;
 #endif
+
+#ifdef HAVE_OPENR2
+	struct dahdi_mfcr2_conf mfcr2;
+#endif
 	struct dahdi_params timing;
 	int is_sig_auto; /*!< Use channel signalling from DAHDI? */
 
@@ -1202,6 +1298,27 @@
 			.nationalprefix = "",
 			.subscriberprefix = "",
 			.unknownprefix = ""
+		},
+#endif
+#ifdef HAVE_OPENR2
+		.mfcr2 = {
+			.variant = OR2_VAR_ITU,
+			.mfback_timeout = -1,
+			.metering_pulse_timeout = -1,
+			.max_ani = 10,
+			.max_dnis = 4,
+			.get_ani_first = -1,
+			.call_files = 0,
+			.allow_collect_calls = 0,
+			.charge_calls = 1,
+			.accept_on_offer = 1,
+			.forced_release = 0,
+			.double_answer = 0,
+			.immediate_accept = -1,
+			.logdir = "",
+			.r2proto_file = "",
+			.loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING,
+			.category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER
 		},
 #endif
 		.chan = {
@@ -1484,6 +1601,462 @@
 	}
 #endif
 }
+
+static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
+#ifdef HAVE_OPENR2
+
+static int dahdi_r2_answer(struct dahdi_pvt *p)
+{
+	int res = 0;
+	/* openr2 1.1.0 and older does not even define OR2_LIB_INTERFACE
+	* and does not has support for openr2_chan_answer_call_with_mode
+	*  */
+#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
+	const char *double_answer = pbx_builtin_getvar_helper(p->owner, "MFCR2_DOUBLE_ANSWER");
+	int wants_double_answer = ast_true(double_answer) ? 1 : 0;
+	if (!double_answer) {
+		/* this still can result in double answer if the channel context 
+		* was configured that way */
+		res = openr2_chan_answer_call(p->r2chan);
+	} else if (wants_double_answer) {
+		res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_DOUBLE);
+	} else {
+		res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_SIMPLE);
+	} 
+#else
+	res = openr2_chan_answer_call(p->r2chan);
+#endif
+	return res;
+}
+
+
+
+/* should be called with the ast_channel locked */
+static openr2_calling_party_category_t dahdi_r2_get_channel_category(struct ast_channel *c)
+{
+	openr2_calling_party_category_t cat;
+	const char *catstr = pbx_builtin_getvar_helper(c, "MFCR2_CATEGORY");
+	struct dahdi_pvt *p = c->tech_pvt;
+	if (ast_strlen_zero(catstr)) {
+		ast_debug(1, "No MFC/R2 category specified for chan %s, using default %s\n",
+				c->name, openr2_proto_get_category_string(p->mfcr2_category));
+		return p->mfcr2_category;
+	}
+	if ((cat = openr2_proto_get_category(catstr)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
+		ast_log(LOG_WARNING, "Invalid category specified '%s' for chan %s, using default %s\n",
+				catstr, c->name, openr2_proto_get_category_string(p->mfcr2_category));
+		return p->mfcr2_category;
+	}
+	ast_debug(1, "Using category %s\n", catstr);
+	return cat;
+}
+
+static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	ast_mutex_lock(&p->lock);
+	if (p->mfcr2call) {
+		ast_mutex_unlock(&p->lock);
+		/* TODO: This can happen when some other thread just finished dahdi_request requesting this very same
+		   interface but has not yet seized the line (dahdi_call), and the far end wins and seize the line,
+		   can we avoid this somehow?, at this point when dahdi_call send the seize, it is likely that since
+		   the other end will see our seize as a forced release and drop the call, we will see an invalid
+		   pattern that will be seen and treated as protocol error. */
+		ast_log(LOG_ERROR, "Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan));
+		return;
+	}
+	p->mfcr2call = 1;
+	/* better safe than sorry ... */
+	p->cid_name[0] = '\0';
+	p->cid_num[0] = '\0';
+	p->rdnis[0] = '\0';
+	p->exten[0] = '\0';
+	p->mfcr2_ani_index = '\0';
+	p->mfcr2_dnis_index = '\0';
+	p->mfcr2_dnis_matched = 0;
+	p->mfcr2_answer_pending = 0;
+	p->mfcr2_call_accepted = 0;
+	ast_mutex_unlock(&p->lock);
+	ast_log(LOG_NOTICE, "New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
+}
+
+static int get_alarms(struct dahdi_pvt *p);
+static void handle_alarms(struct dahdi_pvt *p, int alms);
+static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
+{
+	int res;
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	ast_mutex_lock(&p->lock);
+	p->inalarm = alarm ? 1 : 0;
+	if (p->inalarm) {
+		res = get_alarms(p);
+		handle_alarms(p, res);
+	} else {
+		ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
+		manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
+	}
+	ast_mutex_unlock(&p->lock);
+}
+
+static void dahdi_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
+{
+	ast_log(LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
+}
+
+static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	ast_log(LOG_ERROR, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
+	if (p->owner) {
+		p->owner->hangupcause = AST_CAUSE_PROTOCOL_ERROR;
+		p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+	}
+	ast_mutex_lock(&p->lock);
+	p->mfcr2call = 0;
+	ast_mutex_unlock(&p->lock);
+}
+
+static void dahdi_r2_update_monitor_count(struct dahdi_mfcr2 *mfcr2, int increment)
+{
+	ast_mutex_lock(&mfcr2->monitored_count_lock);
+	if (increment) {
+		mfcr2->monitored_count++;
+		if (mfcr2->monitored_count == 1) {
+			ast_log(LOG_DEBUG, "At least one device needs monitoring, let's wake up the monitor thread.\n");
+			ast_cond_signal(&mfcr2->do_monitor);
+		}
+	} else {
+		mfcr2->monitored_count--;
+		if (mfcr2->monitored_count < 0) {
+			ast_log(LOG_ERROR, "we have a bug here!.\n");
+		}
+	}
+	ast_mutex_unlock(&mfcr2->monitored_count_lock);
+}
+
+static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
+{
+	struct dahdi_pvt *p;
+	struct ast_channel *c;
+	ast_log(LOG_NOTICE, "MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
+			openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis,
+			openr2_proto_get_category_string(category));
+	p = openr2_chan_get_client_data(r2chan);
+	/* if collect calls are not allowed and this is a collect call, reject it! */
+	if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
+		ast_log(LOG_NOTICE, "Rejecting MFC/R2 collect call\n");
+		openr2_chan_disconnect_call(r2chan, OR2_CAUSE_COLLECT_CALL_REJECTED);
+		return;
+	}
+	ast_mutex_lock(&p->lock);
+	p->mfcr2_recvd_category = category;
+	/* if we're not supposed to use CID, clear whatever we have */
+	if (!p->use_callerid) {
+		ast_log(LOG_DEBUG, "No CID allowed in configuration, CID is being cleared!\n");
+		p->cid_num[0] = 0;
+		p->cid_name[0] = 0;
+	}
+	/* if we're supposed to answer immediately, clear DNIS and set 's' exten */
+	if (p->immediate || !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan))) {
+		ast_log(LOG_DEBUG, "Setting exten => s because of immediate or 0 DNIS configured\n");
+		p->exten[0] = 's';
+		p->exten[1] = 0;
+	}
+	ast_mutex_unlock(&p->lock);
+	if (!ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
+		ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
+				p->channel, p->exten, p->context);
+		openr2_chan_disconnect_call(r2chan, OR2_CAUSE_UNALLOCATED_NUMBER);
+		return;
+	} 
+	if (!p->mfcr2_accept_on_offer) {
+		/* The user wants us to start the PBX thread right away without accepting the call first */
+		c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, 0);
+		if (c) {
+			dahdi_r2_update_monitor_count(p->mfcr2, 0);
+			/* Done here, don't disable reading now since we still need to generate MF tones to accept
+			   the call or reject it and detect the tone off condition of the other end, all of this
+			   will be done in the PBX thread now */
+			return;
+		} 
+		ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
+		openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+	} else if (p->mfcr2_charge_calls) {
+		ast_log(LOG_DEBUG, "Accepting MFC/R2 call with charge on chan %d\n", p->channel);
+		openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
+	} else {
+		ast_log(LOG_DEBUG, "Accepting MFC/R2 call with no charge on chan %d\n", p->channel);
+		openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
+	}
+}
+
+static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	ast_log(LOG_NOTICE, "MFC/R2 call end on chan %d\n", p->channel);
+	ast_mutex_lock(&p->lock);
+	p->mfcr2call = 0;
+	ast_mutex_unlock(&p->lock);
+}
+
+static void dahdi_enable_ec(struct dahdi_pvt *p);
+static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
+{
+	struct dahdi_pvt *p = NULL;
+	struct ast_channel *c = NULL;
+	ast_log(LOG_NOTICE, "MFC/R2 call has been accepted on chan %d\n", openr2_chan_get_number(r2chan));
+	p = openr2_chan_get_client_data(r2chan);
+	dahdi_enable_ec(p);
+	p->mfcr2_call_accepted = 1;
+	/* if it's an incoming call ... */
+	if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
+		/* If accept on offer is not set, it means at this point the PBX thread is already
+		   launched (was launched in the 'on call offered' handler) and therefore this callback
+		   is being executed already in the PBX thread rather than the monitor thread, don't launch
+		   any other thread, just disable the openr2 reading and answer the call if needed */
+		if (!p->mfcr2_accept_on_offer) {
+			openr2_chan_disable_read(r2chan);
+			if (p->mfcr2_answer_pending) {
+				ast_log(LOG_DEBUG, "Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
+				dahdi_r2_answer(p);
+			}	
+			return;
+		} 
+		c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, 0);
+		if (c) {
+			dahdi_r2_update_monitor_count(p->mfcr2, 0);
+			/* chan_dahdi will take care of reading from now on in the PBX thread, tell the 
+			   library to forget about it */
+			openr2_chan_disable_read(r2chan);
+			return;
+		}
+		ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
+		/* failed to create the channel, bail out and report it as an out of order line */
+		openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+		return;
+	} 
+	/* this is an outgoing call, no need to launch the PBX thread, most likely we're in one already */
+	ast_log(LOG_NOTICE, "Call accepted on forward channel %d\n", p->channel);
+	p->subs[SUB_REAL].needringing = 1;
+	p->dialing = 0;
+	/* chan_dahdi will take care of reading from now on in the PBX thread, tell the 
+	   library to forget about it */
+	openr2_chan_disable_read(r2chan);
+}
+
+static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	ast_log(LOG_DEBUG, "MFC/R2 call has been answered on chan %d\n", openr2_chan_get_number(r2chan));
+	p->subs[SUB_REAL].needanswer = 1;
+}
+
+static void dahdi_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
+{
+	/*ast_log(LOG_DEBUG, "Read data from dahdi channel %d\n", openr2_chan_get_number(r2chan));*/
+}
+
+static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
+{
+	switch (cause) {
+	case OR2_CAUSE_BUSY_NUMBER:
+		return AST_CAUSE_BUSY;
+	case OR2_CAUSE_NETWORK_CONGESTION:
+		return AST_CAUSE_CONGESTION;
+	case OR2_CAUSE_OUT_OF_ORDER:
+		return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
+	case OR2_CAUSE_UNALLOCATED_NUMBER:
+		return AST_CAUSE_UNREGISTERED;
+	case OR2_CAUSE_NO_ANSWER:
+		return AST_CAUSE_NO_ANSWER;
+	case OR2_CAUSE_NORMAL_CLEARING:
+		return AST_CAUSE_NORMAL_CLEARING;
+	case OR2_CAUSE_UNSPECIFIED:
+	default:
+		return AST_CAUSE_NOTDEFINED;
+	}
+}
+
+static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	ast_verb(3, "MFC/R2 call disconnected on chan %d\n", openr2_chan_get_number(r2chan));
+	ast_mutex_lock(&p->lock);
+	if (!p->owner) {
+		ast_mutex_unlock(&p->lock);
+		/* no owner, therefore we can't use dahdi_hangup to disconnect, do it right now */
+		openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+		return;
+	}
+	/* when we have an owner we don't call openr2_chan_disconnect_call here, that will
+	   be done in dahdi_hangup */
+	if (p->owner->_state == AST_STATE_UP) {
+		p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+		ast_mutex_unlock(&p->lock);
+	} else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
+		/* being the forward side we must report what happened to the call to whoever requested it */
+		switch (cause) {
+		case OR2_CAUSE_BUSY_NUMBER:
+			p->subs[SUB_REAL].needbusy = 1;
+			break;
+		case OR2_CAUSE_NETWORK_CONGESTION:
+		case OR2_CAUSE_OUT_OF_ORDER:
+		case OR2_CAUSE_UNALLOCATED_NUMBER:
+		case OR2_CAUSE_NO_ANSWER:
+		case OR2_CAUSE_UNSPECIFIED:
+		case OR2_CAUSE_NORMAL_CLEARING:
+			p->subs[SUB_REAL].needcongestion = 1;
+			break;
+		default:
+			p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+		}
+		ast_mutex_unlock(&p->lock);
+	} else {
+		ast_mutex_unlock(&p->lock);
+		/* being the backward side and not UP yet, we only need to request hangup */
+		/* TODO: what about doing this same thing when were AST_STATE_UP? */
+		ast_queue_hangup_with_cause(p->owner, dahdi_r2_cause_to_ast_cause(cause));
+	}
+}
+
+static void dahdi_r2_write_log(openr2_log_level_t level, char *logmessage)
+{
+	switch (level) {
+	case OR2_LOG_NOTICE:
+		ast_log(LOG_NOTICE, "%s", logmessage);
+		break;
+	case OR2_LOG_WARNING:
+		ast_log(LOG_WARNING, "%s", logmessage);
+		break;
+	case OR2_LOG_ERROR:
+		ast_log(LOG_ERROR, "%s", logmessage);
+		break;
+	case OR2_LOG_STACK_TRACE:
+	case OR2_LOG_MF_TRACE:
+	case OR2_LOG_CAS_TRACE:
+	case OR2_LOG_DEBUG:
+	case OR2_LOG_EX_DEBUG:
+		ast_log(LOG_DEBUG, "%s", logmessage);
+		break;
+	default:
+		ast_log(LOG_WARNING, "We should handle logging level %d here.\n", level);
+		ast_log(LOG_DEBUG, "%s", logmessage);
+		break;
+	}
+}
+
+static void dahdi_r2_on_line_blocked(openr2_chan_t *r2chan)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	ast_mutex_lock(&p->lock);
+	p->remotelyblocked = 1;
+	ast_mutex_unlock(&p->lock);
+	ast_log(LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void dahdi_r2_on_line_idle(openr2_chan_t *r2chan)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	ast_mutex_lock(&p->lock);
+	p->remotelyblocked = 0;
+	ast_mutex_unlock(&p->lock);
+	ast_log(LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
+}
+
+static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
+	__attribute__((format (printf, 3, 0)));
+static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CONTEXT_TAG "Context - "
+	char logmsg[256];
+	char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
+	vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+	snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
+	dahdi_r2_write_log(level, completemsg);
+#undef CONTEXT_TAG
+}
+
+static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
+	__attribute__((format (printf, 3, 0)));
+static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
+{
+#define CHAN_TAG "Chan "
+	char logmsg[256];
+	char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
+	vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
+	snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d - %s", openr2_chan_get_number(r2chan), logmsg);
+	dahdi_r2_write_log(level, completemsg);
+}
+
+static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	/* if 'immediate' is set, let's stop requesting DNIS */
+	if (p->immediate) {
+		return 0;
+	}
+	p->exten[p->mfcr2_dnis_index] = digit;
+	p->rdnis[p->mfcr2_dnis_index] = digit;
+	p->mfcr2_dnis_index++;
+	p->exten[p->mfcr2_dnis_index] = 0;
+	p->rdnis[p->mfcr2_dnis_index] = 0;
+	/* if the DNIS is a match and cannot match more, stop requesting DNIS */
+	if ((p->mfcr2_dnis_matched ||
+	    (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num) && (p->mfcr2_dnis_matched = 1))) &&
+	    !ast_matchmore_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
+		return 0;
+	}
+	/* otherwise keep going */
+	return 1;
+}
+
+static void dahdi_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
+{
+	struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
+	p->cid_num[p->mfcr2_ani_index] = digit;
+	p->cid_name[p->mfcr2_ani_index] = digit;
+	p->mfcr2_ani_index++;
+	p->cid_num[p->mfcr2_ani_index] = 0;
+	p->cid_name[p->mfcr2_ani_index] = 0;
+}
+
+static openr2_event_interface_t dahdi_r2_event_iface = {
+	.on_call_init = dahdi_r2_on_call_init,
+	.on_call_offered = dahdi_r2_on_call_offered,
+	.on_call_accepted = dahdi_r2_on_call_accepted,
+	.on_call_answered = dahdi_r2_on_call_answered,
+	.on_call_disconnect = dahdi_r2_on_call_disconnect,
+	.on_call_end = dahdi_r2_on_call_end,
+	.on_call_read = dahdi_r2_on_call_read,
+	.on_hardware_alarm = dahdi_r2_on_hardware_alarm,
+	.on_os_error = dahdi_r2_on_os_error,
+	.on_protocol_error = dahdi_r2_on_protocol_error,
+	.on_line_blocked = dahdi_r2_on_line_blocked,
+	.on_line_idle = dahdi_r2_on_line_idle,
+	/* cast seems to be needed to get rid of the annoying warning regarding format attribute  */
+	.on_context_log = (openr2_handle_context_logging_func)dahdi_r2_on_context_log,
+	.on_dnis_digit_received = dahdi_r2_on_dnis_digit_received,
+	.on_ani_digit_received = dahdi_r2_on_ani_digit_received,
+	/* so far we do nothing with billing pulses */
+	.on_billing_pulse_received = NULL
+};
+
+static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample)
+{
+	return AST_ALAW(sample);
+}
+
+static inline uint8_t dahdi_r2_linear_to_alaw(int sample)
+{
+	return AST_LIN2A(sample);
+}
+
+static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
+	dahdi_r2_alaw_to_linear,
+	dahdi_r2_linear_to_alaw
+};
+
+#endif /* HAVE_OPENR2 */
 
 static int restore_gains(struct dahdi_pvt *p);
 
@@ -1877,6 +2450,8 @@
 		return "ISDN BRI Point to MultiPoint";
 	case SIG_SS7:
 		return "SS7";
+	case SIG_MFCR2:
+		return "MFC/R2";
 	case SIG_SF:
 		return "SF (Tone) Immediate";
 	case SIG_SFWINK:
@@ -2816,6 +3391,7 @@
 	case SIG_BRI:
 	case SIG_BRI_PTMP:
 	case SIG_SS7:
+	case SIG_MFCR2:
 		/* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
 		p->dialdest[0] = '\0';
 		break;
@@ -2962,6 +3538,39 @@
 		ss7_rel(p->ss7);
 	}
 #endif /* HAVE_SS7 */
+#ifdef HAVE_OPENR2
+	if (p->mfcr2) {
+		openr2_calling_party_category_t chancat;
+		int strip = p->stripmsd;
+		int callres = 0;
+		c = strchr(dest, '/');
+		if (c) {
+			c++;
+		} else {
+			c = dest;
+		}
+		if (!p->hidecallerid) {
+			l = ast->cid.cid_num;
+		} else {
+			l = NULL;
+		}
+		if (strlen(c) < strip) {
+			ast_log(LOG_WARNING, "Destiny number '%s' is shorter than stripmsd(%d)? hum, you should fix that. Assuming stripmsd = 0\n", c, strip);
+			strip = 0;
+		}
+		p->dialing = 1;
+		ast_channel_lock(ast);
+		chancat = dahdi_r2_get_channel_category(ast);
+		ast_channel_unlock(ast);
+		callres = openr2_chan_make_call(p->r2chan, l, (c + strip), chancat);
+		if (-1 == callres) {
+			ast_mutex_unlock(&p->lock);
+			ast_log(LOG_ERROR, "unable to make new MFC/R2 call!\n");
+			return -1;
+		}
+		ast_setstate(ast, AST_STATE_DIALING);
+	}
+#endif /* HAVE_OPENR2 */
 #ifdef HAVE_PRI
 	if (p->pri) {
 		struct pri_sr *sr;
@@ -3555,6 +4164,149 @@
 }
 #endif	/* defined(HAVE_PRI) */
 
+#if defined(HAVE_OPENR2)
+static const char *dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
+
+static int dahdi_accept_r2_call_exec(struct ast_channel *chan, void *data)
+{
+	/* data is whether to accept with charge or no charge */
+	openr2_call_mode_t accept_mode;
+	int res, timeout, maxloops;
+	struct ast_frame *f;
+	struct dahdi_pvt *p;
+	char *parse;
+	AST_DECLARE_APP_ARGS(args,
+			AST_APP_ARG(charge);
+	);
+
+	if (ast_strlen_zero(data)) {
+		ast_log(LOG_DEBUG, "No data sent to application!\n");
+		return -1;
+	}
+
+	if (chan->tech != &dahdi_tech) {
+		ast_log(LOG_DEBUG, "Only DAHDI technology accepted!\n");
+		return -1;
+	}
+
+	p = (struct dahdi_pvt *)chan->tech_pvt;
+	if (!p) {
+		ast_log(LOG_DEBUG, "Unable to find technology private!\n");
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	if (ast_strlen_zero(args.charge)) {
+		ast_log(LOG_WARNING, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
+		return -1;
+	}
+
+	ast_mutex_lock(&p->lock);
+	if (!p->mfcr2 || !p->mfcr2call) {
+		ast_mutex_unlock(&p->lock);
+		ast_log(LOG_DEBUG, "Channel %s does not seems to be an R2 active channel!\n", chan->name);
+		return -1;
+	}
+
+	if (p->mfcr2_call_accepted) {
+		ast_mutex_unlock(&p->lock);
+		ast_log(LOG_DEBUG, "MFC/R2 call already accepted on channel %s!\n", chan->name);
+		return 0;
+	}
+	accept_mode = ast_true(args.charge) ? OR2_CALL_WITH_CHARGE : OR2_CALL_NO_CHARGE;
+	if (openr2_chan_accept_call(p->r2chan, accept_mode)) {
+		ast_mutex_unlock(&p->lock);
+		ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
+		return -1;
+	}
+	ast_mutex_unlock(&p->lock);
+
+	res = 0;
+	timeout = 100;
+	maxloops = 50; /* wait up to 5 seconds */
+	/* we need to read() until the call is accepted */
+	while (maxloops > 0) {
+		maxloops--;
+		if (ast_check_hangup(chan)) {
+			break;
+		}
+		res = ast_waitfor(chan, timeout);
+		if (res < 0) {
+			ast_log(LOG_DEBUG, "ast_waitfor failed on channel %s, going out ...\n", chan->name);
+			res = -1;
+			break;
+		}
+		if (res == 0) {
+			continue;
+		}
+		f = ast_read(chan);
+		if (!f) {
+			ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
+			res = -1;
+			break;
+		}
+		if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
+			ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
+			ast_frfree(f);
+			res = -1;
+			break;
+		}
+		ast_frfree(f);
+		ast_mutex_lock(&p->lock);
+		if (p->mfcr2_call_accepted) {
+			ast_mutex_unlock(&p->lock);
+			ast_log(LOG_DEBUG, "Accepted MFC/R2 call!\n");
+			break;
+		}
+		ast_mutex_unlock(&p->lock);
+	}
+	if (res == -1) {
+		ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
+	}
+	return res;
+}
+
+static openr2_call_disconnect_cause_t dahdi_ast_cause_to_r2_cause(int cause)
+{
+	openr2_call_disconnect_cause_t r2cause = OR2_CAUSE_NORMAL_CLEARING;
+	switch (cause) {
+	case AST_CAUSE_USER_BUSY:
+	case AST_CAUSE_CALL_REJECTED:
+	case AST_CAUSE_INTERWORKING: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
+		r2cause = OR2_CAUSE_BUSY_NUMBER;
+		break;
+
+	case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+	case AST_CAUSE_SWITCH_CONGESTION:
+		r2cause = OR2_CAUSE_NETWORK_CONGESTION;
+		break;
+
+	case AST_CAUSE_UNALLOCATED:
+		r2cause = OR2_CAUSE_UNALLOCATED_NUMBER;
+		break;
+
+	case AST_CAUSE_NETWORK_OUT_OF_ORDER:
+	case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
+		r2cause = OR2_CAUSE_OUT_OF_ORDER;
+		break;
+
+	case AST_CAUSE_NO_ANSWER:
+	case AST_CAUSE_NO_USER_RESPONSE:
+		r2cause = OR2_CAUSE_NO_ANSWER;
+		break;
+
+	default:
+		r2cause = OR2_CAUSE_NORMAL_CLEARING;
+		break;
+	}
+	ast_log(LOG_DEBUG, "dahdi_ast_cause_to_r2_cause returned %d/%s for ast cause %d\n", 
+			r2cause, openr2_proto_get_disconnect_string(r2cause), cause);
+	return r2cause;
+}
+#endif
+
 static int dahdi_hangup(struct ast_channel *ast)
 {
 	int res;
@@ -3770,6 +4522,22 @@
 			}
 		}
 #endif
+#ifdef HAVE_OPENR2
+		if (p->mfcr2) {
+			ast_log(LOG_DEBUG, "disconnecting MFC/R2 call on chan %d\n", p->channel);
+			/* If it's an incoming call, check the mfcr2_forced_release setting */
+			if (openr2_chan_get_direction(p->r2chan) == OR2_DIR_BACKWARD && p->mfcr2_forced_release) {
+				openr2_chan_disconnect_call(p->r2chan, OR2_CAUSE_FORCED_RELEASE);
+			} else {
+				const char *r2causestr = pbx_builtin_getvar_helper(ast, "MFCR2_CAUSE");
+				int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
+				openr2_call_disconnect_cause_t r2cause = r2cause_user ? dahdi_ast_cause_to_r2_cause(r2cause_user)
+					                                              : dahdi_ast_cause_to_r2_cause(ast->hangupcause);
+				openr2_chan_disconnect_call(p->r2chan, r2cause);
+			}
+			dahdi_r2_update_monitor_count(p->mfcr2, 1);
+		}
+#endif
 #ifdef HAVE_PRI
 		if (p->pri) {
 #ifdef SUPPORT_USERUSER
@@ -3823,7 +4591,10 @@
 			}
 		}
 #endif
-		if (p->sig && ((p->sig != SIG_PRI) && (p->sig != SIG_SS7) && (p->sig != SIG_BRI) && (p->sig != SIG_BRI_PTMP)))
+		if (p->sig && ((p->sig != SIG_PRI) && (p->sig != SIG_SS7)
+			&& (p->sig != SIG_BRI)
+			&& (p->sig != SIG_BRI_PTMP))
+			&& (p->sig != SIG_MFCR2))
 			res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
@@ -4017,6 +4788,25 @@
 		}
 		break;
 #endif
+#ifdef HAVE_OPENR2
+	case SIG_MFCR2:
+		if (!p->mfcr2_call_accepted) {
+			/* The call was not accepted on offer nor the user, so it must be accepted now before answering,
+			   openr2_chan_answer_call will be called when the callback on_call_accepted is executed */
+			p->mfcr2_answer_pending = 1;
+			if (p->mfcr2_charge_calls) {
+				ast_log(LOG_DEBUG, "Accepting MFC/R2 call with charge before answering on chan %d\n", p->channel);
+				openr2_chan_accept_call(p->r2chan, OR2_CALL_WITH_CHARGE);
+			} else {
+				ast_log(LOG_DEBUG, "Accepting MFC/R2 call with no charge before answering on chan %d\n", p->channel);
+				openr2_chan_accept_call(p->r2chan, OR2_CALL_NO_CHARGE);
+			}
+		} else {
+			ast_log(LOG_DEBUG, "Answering MFC/R2 call on chan %d\n", p->channel);
+			dahdi_r2_answer(p);
+		}
+		break;
+#endif
 	case 0:
 		ast_mutex_unlock(&p->lock);
 		return 0;
@@ -4693,8 +5483,6 @@
 
 static void *ss_thread(void *data);
 
-static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
-
 static int attempt_transfer(struct dahdi_pvt *p)
 {
 	/* In order to transfer, we need at least one of the channels to
@@ -4957,13 +5745,29 @@
 			p->echocanon = 0;
 			break;
 		case DAHDI_EVENT_BITSCHANGED:
+#ifdef HAVE_OPENR2
+			if (p->sig != SIG_MFCR2) {
+				ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
+			} else {
+				ast_log(LOG_DEBUG, "bits changed in chan %d\n", p->channel);
+				openr2_chan_handle_cas(p->r2chan);
+			}
+#else
 			ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
+#endif
 		case DAHDI_EVENT_PULSE_START:
 			/* Stop tone if there's a pulse start and the PBX isn't started */
 			if (!ast->pbx)
 				tone_zone_play_tone(p->subs[idx].dfd, -1);
 			break;
 		case DAHDI_EVENT_DIALCOMPLETE:
+#ifdef HAVE_OPENR2
+			if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
+				/* we don't need to do anything for this event for R2 signaling 
+				   if the call is being setup */
+				break;
+			}
+#endif
 			if (p->inalarm) break;
 			if ((p->radio || (p->oprmode < 0))) break;
 			if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
@@ -5056,6 +5860,10 @@
 #endif
 #ifdef HAVE_SS7
 			if (p->sig == SIG_SS7)
+				break;
+#endif
+#ifdef HAVE_OPENR2
+			if (p->sig == SIG_MFCR2)
 				break;
 #endif
 		case DAHDI_EVENT_ONHOOK:
@@ -5914,6 +6722,12 @@
 	else if (p->ringt > 0)
 		p->ringt--;
 
+#ifdef HAVE_OPENR2
+	if (p->mfcr2) {
+		openr2_chan_process_event(p->r2chan);
+	}
+#endif
+
 	if (p->subs[idx].needringing) {
 		/* Send ringing frame if requested */
 		p->subs[idx].needringing = 0;
@@ -5957,7 +6771,17 @@
 		p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
 		ast_mutex_unlock(&p->lock);
 		return &p->subs[idx].f;
-	}
+	}	
+#ifdef HAVE_OPENR2
+	if (p->mfcr2 && openr2_chan_get_read_enabled(p->r2chan)) {
+		/* openr2 took care of reading and handling any event 
+		  (needanswer, needbusy etc), if we continue we will read()
+		  twice, lets just return a null frame. This should only
+		  happen when openr2 is dialing out */
+		ast_mutex_unlock(&p->lock);
+		return &ast_null_frame;
+	}
+#endif
 
 	if (p->subs[idx].needflash) {
 		/* Send answer frame if requested */
@@ -6292,6 +7116,14 @@
 	ast_mutex_lock(&p->lock);
 	idx = dahdi_get_index(chan, p, 0);
 	ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name);
+#ifdef HAVE_OPENR2
+	if (p->mfcr2 && !p->mfcr2_call_accepted) {
+		ast_mutex_unlock(&p->lock);
+		/* if this is an R2 call and the call is not yet accepted, we don't want the
+		   tone indications to mess up with the MF tones */
+		return 0;
+	}	
+#endif
 	if (idx == SUB_REAL) {
 		switch (condition) {
 		case AST_CONTROL_BUSY:
@@ -6686,6 +7518,10 @@
 	/* Assume calls are not idle calls unless we're told differently */
 	i->isidlecall = 0;
 	i->alreadyhungup = 0;
+#endif
+#ifdef HAVE_OPENR2
+	if (i->mfcr2call)
+		pbx_builtin_setvar_helper(tmp, "MFCR2_CATEGORY", openr2_proto_get_category_string(i->mfcr2_recvd_category));
 #endif
 	/* clear the fake event in case we posted one before we had ast_channel */
 	i->fake_event = 0;
@@ -8621,7 +9457,7 @@
 		count = 0;
 		i = iflist;
 		while (i) {
-			if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
+			if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
 				if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive ) {
 					/* This needs to be watched, as it lacks an owner */
 					pfds[count].fd = i->subs[SUB_REAL].dfd;
@@ -8956,6 +9792,102 @@
 }
 #endif	/* defined(HAVE_SS7) */
 
+#ifdef HAVE_OPENR2
+static void dahdi_r2_destroy_links(void)
+{
+	int i = 0;
+	if (!r2links) {
+		return;
+	}
+	for (; i < r2links_count; i++) {
+		if (r2links[i]->r2master != AST_PTHREADT_NULL) {
+			pthread_cancel(r2links[i]->r2master);
+			pthread_join(r2links[i]->r2master, NULL);
+			openr2_context_delete(r2links[i]->protocol_context);
+		}
+		ast_free(r2links[i]);
+	}
+	ast_free(r2links);
+	r2links = NULL;
+	r2links_count = 0;
+}
+
+#define R2_LINK_CAPACITY 10
+static struct dahdi_mfcr2 *dahdi_r2_get_link(void)
+{
+	struct dahdi_mfcr2 *new_r2link = NULL;
+	struct dahdi_mfcr2 **new_r2links = NULL;
+	/* this function is called just when starting up and no monitor threads have been launched, 
+	   no need to lock monitored_count member */
+	if (!r2links_count || (r2links[r2links_count - 1]->monitored_count == R2_LINK_CAPACITY)) {
+		new_r2link = ast_calloc(1, sizeof(**r2links));
+		if (!new_r2link) {
+			ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
+			return NULL;
+		}
+		new_r2links = ast_realloc(r2links, ((r2links_count + 1) * sizeof(*r2links)));
+		if (!new_r2links) {
+			ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");

[... 1022 lines stripped ...]



More information about the asterisk-commits mailing list