[asterisk-commits] rmudgett: branch group/issue14292 r169783 - /team/group/issue14292/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jan 21 15:30:40 CST 2009


Author: rmudgett
Date: Wed Jan 21 15:30:40 2009
New Revision: 169783

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=169783
Log:
Applied the asterisk-issue8824-2008-12-10-ccbsccnr-0.1.0.patch
to the new team/group/issue14292 branched from the team/group/issue14068 branch.
(issue 0014292)

Modified:
    team/group/issue14292/channels/chan_dahdi.c

Modified: team/group/issue14292/channels/chan_dahdi.c
URL: http://svn.digium.com/svn-view/asterisk/team/group/issue14292/channels/chan_dahdi.c?view=diff&rev=169783&r1=169782&r2=169783
==============================================================================
--- team/group/issue14292/channels/chan_dahdi.c (original)
+++ team/group/issue14292/channels/chan_dahdi.c Wed Jan 21 15:30:40 2009
@@ -335,6 +335,296 @@
 	 * knows that we care about it.  Then, chan_dahdi will get the MWI from the
 	 * event cache instead of checking the mailbox directly. */
 }
+
+#ifdef HAVE_PRI
+#define CC_TIMEOUT_PEERLINKCHANNELS  60
+#define CC_MAX_PEERLINKCHANNELS  20*CC_TIMEOUT_PEERLINKCHANNELS
+AST_MUTEX_DEFINE_STATIC(peerlink_lock);
+static struct peerlink_s {
+	struct ast_channel *channel;
+	time_t age;
+} peerlinkchannel[CC_MAX_PEERLINKCHANNELS+1];
+
+
+#define CC_IDLE                  1
+#define CC_WAIT_ACK              2
+#define CC_INVOKED_A_RET         3
+#define CC_WAIT_USER_A_ANSWER_N  4
+
+#define CCBS_SPAN(h) ((h) & 0xff)
+#define CCBS_CR(h) (((h) >> 16) & 0xffff)
+#define CCBS_HANDLE(s,r) ((s & 0xff) | ((r & 0xffff) << 16))
+
+struct ccbsnr_link {
+	unsigned int handle;
+	char type;
+	unsigned int state;
+	char callingnum[AST_MAX_EXTENSION];
+	char callernum[AST_MAX_EXTENSION];
+	char callername[AST_MAX_EXTENSION];
+	char context[AST_MAX_CONTEXT];
+	int priority;
+	q931_call *call;
+	struct ast_channel *peer;
+	time_t age;
+	struct ccbsnr_link *next;
+};
+
+static struct ccbsnr_link *ccbsnr_list = NULL;
+AST_MUTEX_DEFINE_STATIC(ccbsnr_lock);
+
+/*
+ * remove too old CCBS/CCNR entries
+ * (must be called with ccbsnr_lock held)
+ */
+static void del_old_ccbsnr(void)
+{
+	struct ccbsnr_link *ccbsnr;
+	struct ccbsnr_link *tmp = NULL;
+
+	ccbsnr = ccbsnr_list;
+	while (ccbsnr) {
+		if ((ccbsnr->age + 86400) < time(NULL)) {
+			ast_verbose(VERBOSE_PREFIX_3 "DAHDI: CCBS/CCNR handle=%d timeout.\n", ccbsnr->handle);
+			if (!tmp) {
+				ccbsnr_list = ccbsnr->next;
+			} else {
+				tmp->next = ccbsnr->next;
+			}
+			ast_free(ccbsnr);
+			break;
+		}
+		tmp = ccbsnr;
+		ccbsnr = ccbsnr->next;
+	}
+}
+
+
+/*
+ * return the pointer to ccbsnr structure by handle
+ */
+static struct ccbsnr_link *ccbsnr_get_link(unsigned int handle, unsigned int *state)
+{
+	struct ccbsnr_link *ret;
+
+	if (state) {
+		*state = CC_IDLE;
+	}
+
+	if (handle)
+		ast_verbose(VERBOSE_PREFIX_3 "DAHDI: ccbsnr_get_link: handle=%x\n", handle);
+
+	ast_mutex_lock(&ccbsnr_lock);
+
+	ret = ccbsnr_list;
+	while (ret) {
+		if ((handle) && (ret->handle == handle)) {
+			if (state) {
+				*state = ret->state;
+			}
+			break;
+		}
+		ret = ret->next;
+	}
+	ast_mutex_unlock(&ccbsnr_lock);
+
+	return ret;
+}
+
+
+static struct ccbsnr_link *ccbsnr_get_link_by_number(const char *callingnum, const char *callernum, unsigned int *state)
+{
+	struct ccbsnr_link *ret;
+
+	if (state) {
+		*state = CC_IDLE;
+	}
+
+	if (callingnum && callernum) {
+		if (strlen(callingnum) && strlen(callernum))
+			ast_verbose(VERBOSE_PREFIX_3 "DAHDI: ccbsnr_get_link_by_number: callingnum=%s callernum=%s\n", callingnum, callernum);
+	} else {
+		return NULL;
+	}
+
+	ast_mutex_lock(&ccbsnr_lock);
+
+	ret = ccbsnr_list;
+	while (ret) {
+		if (!strcmp(ret->callingnum, callingnum) && !strcmp(ret->callernum, callernum)) {
+			if (state) {
+				*state = ret->state;
+			}
+			break;
+		}
+		ret = ret->next;
+	}
+	ast_mutex_unlock(&ccbsnr_lock);
+
+	return ret;
+}
+
+
+/*
+ * select CCBS/CCNR id
+ */
+static struct ccbsnr_link *ccbsnr_select_link(unsigned int handle) {
+
+	struct ccbsnr_link *ccbsnr;
+	struct ccbsnr_link * ret = NULL;
+	int ccbsnronprispan;
+	int cr;
+	
+	ast_verbose(VERBOSE_PREFIX_3 "DAHDI: ccbsnr_select_link: handle=%x\n", handle);
+
+	ast_mutex_lock(&ccbsnr_lock);
+
+	ccbsnr = ccbsnr_list;
+	while (ccbsnr) {
+		if ((ccbsnr->handle == handle) && (ccbsnr->state == CC_WAIT_ACK)) {
+			ccbsnr->state = CC_INVOKED_A_RET;
+			ret = ccbsnr;
+
+			ccbsnronprispan = CCBS_SPAN(handle);
+			cr = CCBS_CR(handle);
+			ast_verbose(VERBOSE_PREFIX_3 "DAHDI: request CCBS/NR span=%d type=%d cr =%x handle=%x state=%d (%s, %s, %s, %s, %d)\n",
+				ccbsnronprispan, ccbsnr->type, cr, handle, ccbsnr->state, ccbsnr->callingnum, ccbsnr->callernum, ccbsnr->callername, ccbsnr->context, ccbsnr->priority);
+			break;
+		}
+		ccbsnr = ccbsnr->next;
+	}
+	ast_mutex_unlock(&ccbsnr_lock);
+	
+	return ret;
+}
+
+
+/*
+ * a CCBS/CCNR link was removed 
+ */
+static void ccbsnr_del_link(unsigned int handle)
+{
+	struct ccbsnr_link *ccbsnr;
+	struct ccbsnr_link *tmp = NULL;
+	int ccbsnronprispan;
+	int cr;
+
+	ast_verbose(VERBOSE_PREFIX_3 "DAHDI: ccbsnr_del_link: handle=%x\n", handle);
+
+	ast_mutex_lock(&ccbsnr_lock);
+
+	ccbsnr = ccbsnr_list;
+	while (ccbsnr) {
+		if (ccbsnr->handle == handle) {
+			if (!tmp) {
+				ccbsnr_list = ccbsnr->next;
+			} else {
+				tmp->next = ccbsnr->next;
+			}
+			ccbsnronprispan = CCBS_SPAN(handle);
+			cr = CCBS_CR(handle);
+
+			ast_verbose(VERBOSE_PREFIX_3 "DAHDI: destroy CCBS/NR span=%d type=%d cr=%x handle=%x state=%d (%s, %s, %s, %s, %d)\n",
+				ccbsnronprispan, ccbsnr->type, cr, handle, ccbsnr->state, ccbsnr->callingnum, ccbsnr->callernum, ccbsnr->callername, ccbsnr->context, ccbsnr->priority);
+
+			if (ccbsnr->call )
+				ast_log(LOG_NOTICE, "call(%x) must be 'NULL'. Memory leak!\n", (int)ccbsnr->call);
+
+			ast_free(ccbsnr);
+			break;
+		}
+		tmp = ccbsnr;
+		ccbsnr = ccbsnr->next;
+	}
+	ast_mutex_unlock(&ccbsnr_lock);
+}
+
+
+/*
+ * return the counter of ccbsnrlinks to callingnumber
+ */
+static int ccbsnr_count_callingnum(const char *callingnum)
+{
+	int count = 0;
+	struct ccbsnr_link *ccbsnr;
+
+	ast_mutex_lock(&ccbsnr_lock);
+	ccbsnr = ccbsnr_list;
+	while (ccbsnr) {
+		if (!strcmp(ccbsnr->callingnum, callingnum)) {
+			count++;
+		}
+		ccbsnr = ccbsnr->next;
+	}
+	ast_mutex_unlock(&ccbsnr_lock);
+
+	return count;
+}
+
+
+/*
+ * Add a new peer link id
+ */
+static int cc_add_peer_link_id(struct ast_channel *ast)
+{
+	int i;
+
+	ast_mutex_lock(&peerlink_lock);
+	for (i = 1; i <= CC_MAX_PEERLINKCHANNELS; i++) {
+		if (peerlinkchannel[i].channel == NULL) {
+			peerlinkchannel[i].channel = ast;
+			peerlinkchannel[i].age = time(NULL);
+			break;
+		} else {
+			/* remove too old entries */
+			if ((peerlinkchannel[i].age + CC_TIMEOUT_PEERLINKCHANNELS) < time(NULL)) {
+				peerlinkchannel[i].channel = NULL;
+				ast_verbose(VERBOSE_PREFIX_4 "DAHDI: peerlink %d timeout-erase\n", i);
+			}
+		}
+	}
+	ast_mutex_unlock(&peerlink_lock);
+	if (i > CC_MAX_PEERLINKCHANNELS) {
+		return -1;
+	}
+	return i;
+}
+
+/*
+ * Get and remove peer link id
+ */
+static struct ast_channel *cc_get_peer_link_id(const char *p)
+{
+	int id = -1;
+	struct ast_channel *ast = NULL;
+
+	if (p) {
+		id = (int)strtol(p, NULL, 0);
+	}
+
+	ast_mutex_lock(&peerlink_lock);
+	if ((id >= 1) && (id <= CC_MAX_PEERLINKCHANNELS)) {
+		ast = peerlinkchannel[id].channel;
+		peerlinkchannel[id].channel = NULL;
+	}
+	ast_verbose(VERBOSE_PREFIX_4 "DAHDI: peerlink %d allocated, peer is %s\n", id, (ast)?ast->name:"unlinked");
+	ast_mutex_unlock(&peerlink_lock);
+	return ast;
+}
+
+static void cc_destroy_all_peer_link_id(void)
+{
+	int i;
+
+	ast_mutex_lock(&peerlink_lock);
+	for (i = 1; i <= CC_MAX_PEERLINKCHANNELS; i++) {
+		/* remove entries */
+		peerlinkchannel[i].channel = NULL;
+	}
+	ast_mutex_unlock(&peerlink_lock);
+}
+#endif
+
 
 /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
 static inline int dahdi_get_event(int fd)
@@ -467,6 +757,7 @@
 	time_t lastreset;						/*!< time when unused channels were last reset */
 	long resetinterval;						/*!< Interval (in seconds) for resetting unused channels */
 	int sig;
+	unsigned int use_callingpres:1;					/*!< used for no channel call */
 	struct dahdi_pvt *pvts[MAX_CHANNELS];				/*!< Member channel pvt structs */
 	struct dahdi_pvt *crvs;						/*!< Member CRV structs */
 	struct dahdi_pvt *crvend;						/*!< Pointer to end of CRV structs */
@@ -564,6 +855,9 @@
 	ast_mutex_t lock;
 	struct ast_channel *owner;			/*!< Our current active owner (if applicable) */
 							/*!< Up to three channels can be associated with this call */
+#ifdef HAVE_PRI
+	int dummychannel;				/*!< Flag for dummy Channel. used for ccbsnr (shellscript) */
+#endif		
 		
 	struct dahdi_subchannel sub_unused;		/*!< Just a safety precaution */
 	struct dahdi_subchannel subs[3];			/*!< Sub-channels */
@@ -652,6 +946,9 @@
 	unsigned int resetting:1;
 	unsigned int setup_ack:1;
 #endif
+#ifdef HAVE_PRI
+	unsigned int ccringout:1;		/*!< Append CC-Ringout facility */
+#endif		
 	unsigned int use_smdi:1;		/* Whether to use SMDI on this channel */
 	struct mwisend_info mwisend_data;
 	struct ast_smdi_interface *smdi_iface;	/* The serial port to listen for SMDI data on */
@@ -942,6 +1239,282 @@
 #define GET_CHANNEL(p) ((p)->channel)
 #endif
 
+#ifdef HAVE_PRI
+static inline int pri_nochannel_grab(struct dahdi_pri *pri)
+{
+	int res;
+	/* Grab the lock first */
+	do {
+		res = ast_mutex_trylock(&pri->lock);
+		if (res) {
+			/* Release the lock and try again */
+			usleep(1);
+		}
+	} while (res);
+	/* Then break the poll */
+	pthread_kill(pri->master, SIGURG);
+	return 0;
+}
+
+
+/*
+ * a new CCBS/CCNR id was received
+ */
+static struct ccbsnr_link *ccbsnr_new_id(int callreference, int ccbsnronprispan, q931_call *call, int type, char* callingnum, char *callernum,
+					char *callername, char *context, int priority, struct ast_channel *peer) {
+	struct ccbsnr_link *ccbsnr;
+
+	ccbsnr = ast_calloc(1, sizeof(*ccbsnr));
+	if (!ccbsnr) {
+		ast_log(LOG_ERROR, "Unable to allocate CCBS/CCNR struct.\n");
+		return NULL;
+	}
+
+	ccbsnr->age = time(NULL);
+	ccbsnr->type = type;
+	ccbsnr->call = call;
+	ccbsnr->handle = CCBS_HANDLE(ccbsnronprispan,callreference);
+	ccbsnr->peer = peer;
+	ccbsnr->priority = priority;
+	ccbsnr->state = CC_WAIT_ACK;
+	ast_copy_string(ccbsnr->callingnum, callingnum, sizeof(ccbsnr->callingnum));
+	ast_copy_string(ccbsnr->callernum, callernum, sizeof(ccbsnr->callernum));
+	ast_copy_string(ccbsnr->callername, callername, sizeof(ccbsnr->callername));
+	ast_copy_string(ccbsnr->context, context, sizeof(ccbsnr->context));
+
+	ast_mutex_lock(&ccbsnr_lock);
+	del_old_ccbsnr();
+	ccbsnr->next = ccbsnr_list;
+	ccbsnr_list = ccbsnr;
+	ast_mutex_unlock(&ccbsnr_lock);
+
+	return ccbsnr;
+}
+
+
+/*
+ * Clear CCBS/CCNR links
+ */
+static void ccbsnr_clear_all(void)
+{
+	struct ccbsnr_link *ccbsnr;
+	struct ccbsnr_link *tmp = NULL;
+	unsigned int span;
+	int cr;
+
+	ast_mutex_lock(&ccbsnr_lock);
+	ccbsnr = ccbsnr_list;
+	while (ccbsnr) {
+		tmp = ccbsnr;
+		ccbsnr = ccbsnr->next;
+		span = CCBS_SPAN(tmp->handle);
+		cr = CCBS_CR(tmp->handle);
+		ast_log(LOG_NOTICE, "ccbsnr_clear_all: ccbsnr found(%x) span %d\n", (int)tmp, span);
+		ast_free(tmp);
+	}
+
+	ccbsnr_list = NULL;
+	ast_mutex_unlock(&ccbsnr_lock);
+}
+
+
+static void ccbsnr_destroy_all_of_span(struct dahdi_pri *pri)
+{
+	int span = pri->span;
+	struct ccbsnr_link *ccbsnr;
+	struct ccbsnr_link *prev = NULL;
+	struct ccbsnr_link *tmp = NULL;
+	q931_call *call;
+	unsigned int ccbs_span;
+	int cr;
+
+	ast_mutex_lock(&ccbsnr_lock);
+	ccbsnr = ccbsnr_list;
+	while (ccbsnr) {
+		ccbs_span = CCBS_SPAN(ccbsnr->handle);
+		cr = CCBS_CR(ccbsnr->handle);
+		if (ccbs_span == span) {
+			ast_log(LOG_NOTICE, "ccbsnr found(%x) ccbs_span %d\n", (int)ccbsnr, ccbs_span);
+
+			tmp = ccbsnr;
+			if (!prev) {
+				ccbsnr_list = ccbsnr->next;
+			} else {
+				prev->next = ccbsnr->next;
+			}
+			ccbsnr = ccbsnr->next;
+
+			if (tmp->call) {
+				call = pri_find_call(pri->pri, cr);
+				ast_log(LOG_NOTICE, "call found(%x)\n", (int)call);
+
+				if (call == tmp->call) {
+					ast_log(LOG_WARNING, "Q931Call(%x) cr(%x) found, hang it up it.\n", (int)call, cr);
+
+					pri_call_set_cc_operation(call, PRI_CC_CANCEL);
+					pri_hangup(pri->pri, call, -1);
+					pri_destroycall(pri->pri, call);
+				}
+			}
+			ast_free(tmp);
+			ast_log(LOG_WARNING, "Free ccbsnr-link (%x) ccbs_span %d\n", (int)tmp, ccbs_span);
+		} else {
+			prev = ccbsnr;
+			ccbsnr = ccbsnr->next;
+		}
+	}
+
+	ast_mutex_unlock(&ccbsnr_lock);
+}
+
+
+/*
+ * Destroy CCBS/CCNR links
+ */
+static void ccbsnr_destroy_all(void)
+{
+	struct ccbsnr_link *ccbsnr;
+	struct ccbsnr_link *tmp = NULL;
+	q931_call *call;
+	struct dahdi_pri *pri;
+	unsigned int span;
+	int cr;
+
+	ast_mutex_lock(&ccbsnr_lock);
+	ccbsnr = ccbsnr_list;
+	while (ccbsnr) {
+		tmp = ccbsnr;
+		ccbsnr = ccbsnr->next;
+		span = CCBS_SPAN(tmp->handle);
+		cr = CCBS_CR(tmp->handle);
+		ast_log(LOG_NOTICE, "ccbsnr_destroy_all: ccbsnr found(%x) span %d\n", (int)tmp, span);
+
+		if (tmp->call) {
+			pri = &pris[span - 1];
+
+			if (pri_nochannel_grab(pri)) {
+				ast_log(LOG_ERROR, "Failed to grab PRI!\n");
+				return;
+			}
+
+			call = pri_find_call(pri->pri, cr);
+			ast_log(LOG_NOTICE, "ccbsnr_destroy_all: call found(%x)\n", (int)call);
+
+			if (call == tmp->call) {
+				ast_log(LOG_WARNING, "ccbsnr_destroy_all(%x) cr(%x):Q931_call found, hang it up it.\n", (int)call, cr);
+
+				pri_call_set_cc_operation(call, PRI_CC_CANCEL);
+				pri_hangup(pri->pri, call, -1);
+			}
+
+			pri_rel(pri);
+		}
+		ast_free(tmp);
+	}
+
+	ccbsnr_list = NULL;
+	ast_mutex_unlock(&ccbsnr_lock);
+}
+
+
+/*
+ * on an activated CCBS, the remote party is now free
+ */
+static void	ccbsnr_remote_user_free(unsigned int handle)
+{
+
+	struct ast_channel *ast;
+	struct ccbsnr_link *ccbsnr;
+	int state = AST_STATE_DOWN;
+	struct dahdi_pvt *dummy;
+
+	ast_verbose(VERBOSE_PREFIX_3 "ccbsnr_remote_user_free: handle %x\n", handle);
+
+	ast_mutex_lock(&ccbsnr_lock);
+
+	ccbsnr = ccbsnr_list;
+	while (ccbsnr) {
+		if (ccbsnr->handle == handle) {
+			break;
+		}
+		ccbsnr = ccbsnr->next;
+	}
+	ast_mutex_unlock(&ccbsnr_lock);
+
+	if (!(ccbsnr)) {
+		ast_log(LOG_ERROR, "DAHDI: CCBS/CCBR reference not found!\n");
+		return;
+	}
+
+	ast = ast_channel_alloc(0, state, 0, 0, "", "", "", 0, 0);
+	if (!ast) {
+		ast_log(LOG_ERROR, "Unable to allocate channel!\n");
+		return;
+	}
+
+	ast->tech = &dahdi_tech;
+	dummy = ast_calloc(1,sizeof(*dummy));
+	if (!dummy) {
+		ast_log(LOG_ERROR, "Unable to allocate dummy:struct dahdi_pvt!\n");
+		return;
+	}
+	ast_mutex_init(&dummy->lock);
+	dummy->dummychannel = 1;
+	ast->tech_pvt = dummy;
+	ast_string_field_build(ast, name, "CCBSNR/%x", ccbsnr->handle);
+
+	ast_verbose(VERBOSE_PREFIX_3 "ccbsnr_remote_user_free: ast=%x name=%s ast->_softhangup=%x ast->tech%x\n",
+					(int)ast, ast->name, ast->_softhangup, (int)ast->tech);
+
+	ast->_softhangup = 0;
+	memset(&ast->whentohangup, 0, sizeof(ast->whentohangup));
+
+	ast->priority = ccbsnr->priority;
+
+	if (ast->cid.cid_num) {
+		ast_free(ast->cid.cid_num);
+	}
+	ast->cid.cid_num = ast_strdup(ccbsnr->callernum);
+
+	if (ast->cid.cid_dnid) {
+		ast_free(ast->cid.cid_dnid);
+	}
+	ast->cid.cid_name = ast_strdup(ccbsnr->callername);
+
+	ast_copy_string(ast->context, ccbsnr->context, sizeof(ast->context));
+	ast_copy_string(ast->exten, ccbsnr->callingnum, sizeof(ast->exten));
+
+	ast_setstate(ast, state);
+	ast_verbose(VERBOSE_PREFIX_3 "ccbsnr_remote_user_free: ast_pbx_start:ast %x cc-req(%d)\n", (int)ast, ccbsnr->type);
+
+	if (ast_pbx_start(ast)) {
+		pri_call_set_cc_operation(ccbsnr->call, PRI_CC_CANCEL);
+
+		int ccbs_span = CCBS_SPAN(ccbsnr->handle);
+		struct dahdi_pri *ccbs_pri = &pris[ccbs_span - 1];
+
+		if (pri_nochannel_grab(ccbs_pri)) {
+			ast_log(LOG_WARNING, "Failed to grab PRI!\n");
+			return;
+		}
+		pri_hangup(ccbs_pri->pri, ccbsnr->call, -1);
+		pri_rel(ccbs_pri);
+		ccbsnr->call = NULL;
+		ccbsnr_del_link(ccbsnr->handle);
+
+		ast_log(LOG_ERROR, "DAHDI: CCBS/CCNR: Unable to start pbx!\n");
+
+		return;
+	} else {
+		ast_verbose(VERBOSE_PREFIX_3 "DAHDI-span%d: started PBX for CCBS/CCNR callback (context:%s/callingnum:%s/prio:%d)callernum:%s callername:%s peer=%x\n",
+			CCBS_SPAN(ccbsnr->handle), ccbsnr->context, ccbsnr->callingnum, ccbsnr->priority, ccbsnr->callernum, ccbsnr->callername, (int)ccbsnr->peer);
+		ccbsnr->state = CC_WAIT_USER_A_ANSWER_N;
+	}
+
+	ast_module_ref(ast_module_info->self);
+}
+#endif
+
 struct dahdi_pvt *round_robin[32];
 
 #ifdef HAVE_PRI
@@ -2755,6 +3328,11 @@
 #ifdef HAVE_PRI
 	if (p->pri) {
 		struct pri_sr *sr;
+		struct ast_channel *peer;
+		struct ccbsnr_link *cclink;
+		unsigned int state = 0;
+		char *callingnum;
+		char *callernum;
 #ifdef SUPPORT_USERUSER
 		const char *useruser;
 #endif
@@ -3008,6 +3586,57 @@
 		if (useruser)
 			pri_sr_set_useruser(sr, useruser);
 #endif
+		callingnum = c + p->stripmsd + dp_strip;
+		callernum = l ? (l + ldp_strip) : NULL;
+
+		/* search ccbs-list */
+		cclink = ccbsnr_get_link_by_number(callingnum, callernum, &state);
+
+		if (p->ccringout) {
+			if (cclink) {
+				pri_sr_set_ccringout(sr, p->ccringout);
+			} else {
+				ast_verbose(VERBOSE_PREFIX_3 "DAHDI-Call: ccbsnr-link found. state(%d). Change to Dial without CC-Ringout\n", state);
+				p->ccringout = 0;
+			}
+		} else {
+			/* Normal Call */
+			if (cclink) {
+				int span = CCBS_SPAN(cclink->handle);
+				struct dahdi_pri *ccbs_pri;
+
+				switch (state) {
+				case CC_WAIT_ACK:
+				case CC_WAIT_USER_A_ANSWER_N:
+				case CC_INVOKED_A_RET:
+					ast_verbose(VERBOSE_PREFIX_4 "DAHDI-Call: CCBS-List-Obj 0x%x: handle %x span(%d) peer=%x\n", \
+									(int)cclink, cclink->handle, span, (int)cclink->peer);
+
+					if (cclink->call) {
+						pri_call_set_cc_operation(cclink->call, PRI_CC_CANCEL);
+
+						ccbs_pri = &pris[span - 1];
+						if (ccbs_pri != p->pri) {
+							if (pri_nochannel_grab(ccbs_pri)) {
+								ast_log(LOG_WARNING, "Failed to grab PRI!\n");
+								return -1;
+							}
+
+							pri_hangup(ccbs_pri->pri, cclink->call, -1);
+
+							pri_rel(ccbs_pri);
+						} else {
+							pri_hangup(p->pri->pri, cclink->call, -1);
+						}
+					}
+					cclink->call = NULL;
+					ccbsnr_del_link(cclink->handle);
+					break;
+				default:
+					ast_verbose(VERBOSE_PREFIX_3 "DAHDI-Call:wrong ccbsnr-link-state '%d'\n", state);
+				}
+			}
+		}
 
 		if (pri_setup(p->pri->pri, p->call, sr)) {
  			ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", 
@@ -3020,6 +3649,17 @@
 		pri_sr_free(sr);
 		ast_setstate(ast, AST_STATE_DIALING);
 		pri_rel(p->pri);
+		peer = cc_get_peer_link_id(pbx_builtin_getvar_helper(ast, "CCPEERLINKID"));
+		if (peer) {
+			char tmp[32];
+
+			pbx_builtin_setvar_helper(peer, "CCPEERLINKID", "0");
+
+			ast_verbose(VERBOSE_PREFIX_3 "DAHDI peer link is %x %s.\n", (int)peer, peer->name);
+
+			snprintf(tmp, sizeof(tmp) - 1, "%d", p->pri->span);
+			pbx_builtin_setvar_helper(peer, "CCBSNRONPRISPAN", tmp);
+		}
 	}
 #endif		
 	ast_mutex_unlock(&p->lock);
@@ -3129,6 +3769,509 @@
 }
 
 #ifdef HAVE_PRI
+static char *dahdi_qsig_ccbsnr_initialize_app = "DAHDIQsigCcbsnrInitialize";
+
+/*
+ * store the peer for future actions 
+ */
+static int dahdi_qsig_ccbsnr_initialize_exec(struct ast_channel *ast, void *param)
+{
+	char buffer[32];
+	int id;
+
+	id = cc_add_peer_link_id(ast);
+
+	if (id >= 0) {
+		snprintf(buffer, sizeof(buffer) - 1, "%d", id);
+		pbx_builtin_setvar_helper(ast, "_CCPEERLINKID", buffer);
+		pbx_builtin_setvar_helper(ast, "_CCBSNRREQSTATE", "AVAILABLE");
+		pbx_builtin_setvar_helper(ast, "_CCBSNRONPRISPAN", "0");
+	}
+
+	ast_verbose(VERBOSE_PREFIX_3 "Added %s as DAHDI peer link.\n",
+		ast->name);
+
+	return 0;
+}
+
+#define CC_MAX_NOCHANNELS 256
+
+static char *dahdi_qsic_check_ccbsnr_app = "DAHDIQsigCheckCcbsnr";
+
+static int dahdi_qsig_check_ccbsnr_exec(struct ast_channel *ast, void *param)
+{
+
+#define MAX_DISSALOWED 4
+
+	char *data = (char *) param;
+	char *parse, *tok, *tokb;
+	int   maxcount = 0;
+	char *dissalowed_callernum[MAX_DISSALOWED] = {NULL, NULL, NULL, NULL};
+	char *maxcounter = NULL;
+	char *callingnum = NULL;
+	char *callernum = NULL;
+	int count = 0;
+	int flag = 0;
+	char *c;
+	int cnt;
+
+	if (ast_strlen_zero(param)) {
+		ast_debug(1, "Check command requires arguments!\n");
+		return -1;
+	}
+
+	parse = ast_strdupa(data);
+	tok = strtok_r(parse, "|", &tokb);
+	if (!tok) {
+		ast_log(LOG_WARNING, "DAHDIQsigCheckCcbsnr requires at least maxcounter argument\n");
+		return -1;
+	}
+	maxcounter = tok;	
+	if (*tokb != '|') {
+		tok = strtok_r(NULL, "|", &tokb);
+		if (!tok) {
+			ast_log(LOG_WARNING, "DAHDIQsigCheckCcbsnr without callingnum argument\n");
+			return -1;
+		}
+		callingnum = tok;
+	} else {
+		callingnum = "";
+		tokb++;
+	}
+
+	if (*tokb != '|') {
+		tok = strtok_r(NULL, "|", &tokb);
+		if (!tok) {
+			ast_log(LOG_NOTICE, "DAHDIQsigCheckCcbsnr without callernum argument\n");
+			return -1;
+		}
+		callernum = tok;
+	} else {
+		callernum = "";
+		tokb++;
+	}
+
+
+	/* Optional args 'dissalowed_callernum'*/
+	for (cnt = 0; cnt < MAX_DISSALOWED; cnt++) {
+		tok = strtok_r(NULL, "|", &tokb);
+		if (!tok) {
+			ast_verbose(VERBOSE_PREFIX_3 "DAHDIQsigCheckCcbsnr without dissalowed-callernum argument\n");
+		} else {
+			dissalowed_callernum[cnt] = tok;
+		}
+	}
+
+	ast_verbose(VERBOSE_PREFIX_3 "DAHDI ccbsnr: '%s' '%s' '%s'\n", maxcounter, callingnum, callernum);
+	for (cnt = 0; cnt < MAX_DISSALOWED; cnt++) {
+		if (dissalowed_callernum[cnt])
+			ast_verbose(VERBOSE_PREFIX_3 "DAHDI ccbsnr: '%s'\n", dissalowed_callernum[cnt]);
+	}
+
+	maxcount = (int)strtol(maxcounter, NULL, 0);
+	if (maxcount > CC_MAX_NOCHANNELS) {
+		ast_debug(1, "DAHDIQsigCheckCcbsnr <maxcount> range:(%d - %d)\n", 0, CC_MAX_NOCHANNELS);
+		return -1;
+	} else if (!maxcount) {
+		maxcount = CC_MAX_NOCHANNELS;
+	}
+
+	if (ast_strlen_zero(callernum)) {
+		flag = 1;
+		ast_verbose(VERBOSE_PREFIX_3 "DAHDIQsigCheckCcbsnr: no caller number - <callingnum>|<callernum>\n");
+	} else if (ast_strlen_zero(callingnum)) {
+		flag = 1;
+		ast_verbose(VERBOSE_PREFIX_3 "DAHDIQsigCheckCcbsnr: no caller number - <callingnum>|<callernum>\n");
+	} else if (!strcmp(callernum, callingnum)) {
+		flag = 1;
+		ast_verbose(VERBOSE_PREFIX_3 "DAHDIQsigCheckCcbsnr: caller number(%s) and calling number are equal\n", callernum);
+	} else {
+		for (c = callernum; *c; c++)
+			*c = tolower(*c);
+		for (cnt = 0; cnt < MAX_DISSALOWED; cnt++) {
+			if (dissalowed_callernum[cnt]) {
+				if (!strcmp(callernum, dissalowed_callernum[cnt])) {
+					flag = 1;
+					ast_verbose(VERBOSE_PREFIX_4 "DAHDIQsigCheckCcbsnr: dissalowed_callernum - %s\n", dissalowed_callernum[cnt]);
+					break;
+				}
+			}
+		}
+		count = ccbsnr_count_callingnum(callingnum);
+		ast_verbose(VERBOSE_PREFIX_4 "DAHDIQsigCheckCcbsnr: maxcount(%d) count(%d)\n", maxcount, count);
+		if (count >= maxcount) {
+			flag = 1;
+			ast_verbose(VERBOSE_PREFIX_3 "DAHDIQsigCheckCcbsnr: count(%d) <callingnum>|<callernum>\n", count);
+		}
+	}
+
+	if (flag) {
+		ast_verbose(VERBOSE_PREFIX_3 "Set CCBSNRREQSTATE to NOTAVAILABLE\n");
+		pbx_builtin_setvar_helper(ast, "CCBSNRREQSTATE", "NOTAVAILABLE");
+	}
+
+	return 0;
+}
+
+
+static char *dahdi_qsic_clear_nochannel_app = "DAHDIQsigClearNoChannel";
+
+static int dahdi_qsig_clear_nochannel_exec(struct ast_channel *ast, void *param)
+{
+	char *callingnum, *callernum;
+	char *data = (char *) param;
+
+	struct ccbsnr_link *cclink;
+	unsigned int state = 0;
+	struct dahdi_pri *pri;
+	unsigned int span;
+	int cr;
+	q931_call *call;
+
+	if (ast_strlen_zero(data)) {
+		ast_debug(1, "Clear command requires arguments!\n");
+		return -1;
+	}
+
+	callingnum = strsep(&data, "|");
+	callernum = data;
+
+	if ((!callingnum) || (!callernum)) {
+		ast_debug(1, "DAHDIQsigClearNoChannel requires <callingnum>|<callernum>\n");
+		return -1;
+	}
+
+	ast_verbose(VERBOSE_PREFIX_3 "DAHDI ccbsnr: '%s' '%s'\n", callingnum, callernum);
+
+	cclink = ccbsnr_get_link_by_number(callingnum, callernum, &state);
+	if (cclink) {
+		ast_verbose(VERBOSE_PREFIX_3 "DAHDI ccbsnr: state(%d)\n", state);
+
+		switch (state) {
+		case CC_WAIT_ACK:
+		case CC_WAIT_USER_A_ANSWER_N:
+		case CC_INVOKED_A_RET:
+			if (cclink->call) {
+				span = CCBS_SPAN(cclink->handle);
+				pri = &pris[span - 1];
+
+				if (pri_nochannel_grab(pri)) {
+					ast_log(LOG_WARNING, "Failed to grab PRI!\n");
+					return -1;
+				}
+				cr = CCBS_CR(cclink->handle);
+				call = pri_find_call(pri->pri, cr);
+
+				ast_log(LOG_NOTICE, "destroy cclink: call found(%x)\n", (int)call);
+
+				if (call == cclink->call) {
+					ast_log(LOG_NOTICE, "destroy call(%x) cr(%x):Q931_call found, hang it up it.\n", (int)call, cr);
+
+					pri_call_set_cc_operation(call, PRI_CC_CANCEL);
+					pri_hangup(pri->pri, call, -1);
+				}
+				pri_rel(pri);
+			}
+			ast_mutex_lock(&ccbsnr_lock);
+			cclink->call = NULL;
+			ast_mutex_unlock(&ccbsnr_lock);
+			ccbsnr_del_link(cclink->handle);
+			break;
+		default:
+			ast_verbose(VERBOSE_PREFIX_2 "PRI_EVENT_HANGUP:wrong state '%d'\n", state);
+		}
+	} else {
+		ast_verbose(VERBOSE_PREFIX_2 "dahdi_qsig_clear_nochannel: CCBS-List-Obj for callingnum(%s) callernum(%s) not found\n", callingnum, callernum);
+		return 0;
+	}
+	return 0;
+
+}
+
+
+static char *dahdi_qsic_ccbsnr_request_app = "DAHDIQsigCcbsnrRequest";
+
+static int dahdi_qsig_ccbsnr_request_exec(struct ast_channel *ast, void *param)
+{
+	int type;
+	char *ccbsnrtype, *callingnum, *callernum, *callername, *context, *priority;
+	char *data = (char *) param;
+
+	const char *ccbsnronprispan;
+	unsigned int prispan;
+	char *c, *l, *n;
+	char *s = NULL;
+	int dp_strip;
+	int ldp_strip;
+	struct pri_sr *sr;
+	int pridialplan;
+	int prilocaldialplan;
+	l = NULL;
+	n = NULL;
+
+	struct dahdi_pri *pri;
+	struct ccbsnr_link *cclink;
+	q931_call *call;
+
+	/* sets for no channel call */
+	int channel = 0;
+	int exclusive = 1;
+	int nonisdn = 0;
+	int transmode = -1;
+	int userl1 = ast->transfercapability;
+	int cref = 0;
+
+	if (ast_strlen_zero(data)) {
+		ast_debug(1, "CCBScommand requires arguments!\n");
+		return -1;
+	}
+
+	ccbsnrtype = strsep(&data, "|");
+	callingnum = strsep(&data, "|");
+	callernum = strsep(&data, "|");
+	callername = strsep(&data, "|");
+	context = strsep(&data, "|");
+	priority = data;
+
+	if ((!ccbsnrtype) || (!callingnum) || (!callernum) || (!callername) || (!context) || (!priority)) {
+		ast_debug(1, "DAHDIQsigCcbsnrRequest requires <CCBR/CCNR>|<callingnum>|<callernum>|<callername>|<context>|<priority>\n");
+		return -1;
+	}
+
+	ast_verbose(VERBOSE_PREFIX_3 "DAHDI ccbsnr: '%s' '%s' '%s' '%s' '%s' '%s'\n",
+		ccbsnrtype, callingnum, callernum, callername, context, priority);
+
+	 if (!strcmp(callernum, callingnum)) {
+		ast_debug(1, "DAHDIQsigCcbsnrRequest: caller number(%s) and calling number are equal\n", callernum);
+		return -1;
+	}
+
+	if (!strcmp(ccbsnrtype, "CCBS"))
+		type = PRI_CC_CCBSREQUEST;
+	else if (!strcmp(ccbsnrtype, "CCNR"))
+		type = PRI_CC_CCNRREQUEST;
+	else {
+		ast_verbose(VERBOSE_PREFIX_2 "DAHDIQsigCcbsnrRequest requires <CCBS/CCNR>|<callingnum>|<callernum>|<callername>|<context>|<priority>\n");
+		return -1;
+	}
+
+	ccbsnronprispan = pbx_builtin_getvar_helper(ast, "CCBSNRONPRISPAN");
+	ast_verbose(VERBOSE_PREFIX_3 "DAHDI ccbsnronprispan: '%s'\n", ccbsnronprispan);
+
+	if (ast_strlen_zero(ccbsnronprispan)) {
+		ast_debug(1, "DAHDIQsigCcbsnrRequest: Use initialize befor use this funktion\n");
+		return -1;
+	}
+
+	prispan = (int)strtol(ccbsnronprispan, NULL, 0);
+
+	if ((prispan < 1) || (prispan > NUM_SPANS)) {
+		ast_verbose(VERBOSE_PREFIX_2 "DAHDI:Invalid span %d.  Should be a number %d to %d\n", prispan, 1, NUM_SPANS);
+		return -1;
+	}
+
+	pri = &pris[prispan-1];
+	if (pri_nochannel_grab(pri)) {
+		ast_log(LOG_WARNING, "Failed to grab PRI!\n");
+		return -1;
+	}
+
+	if (!(call = pri_new_nochannel_call(pri->pri, &cref))) {
+		ast_log(LOG_WARNING, "Unable to create no channel call on span %d\n", prispan);
+		pri_rel(pri);
+		return -1;
+	}
+
+	if (!(sr = pri_sr_new())) {
+		ast_log(LOG_WARNING, "Failed to allocate setup request for no channel on span %d\n", prispan);
+		pri_rel(pri);
+	}
+	pri_sr_set_no_channel_call(sr);
+	pri_sr_set_ccbsnr(sr, type);
+
+	channel |= prispan << 8 | exclusive << 16;
+	pri_sr_set_channel(sr, channel, exclusive, nonisdn);
+	pri_sr_set_bearer(sr, transmode, userl1);
+	if (pri->facilityenable)
+		pri_facility_enable(pri->pri);
+
+	ast_verbose(VERBOSE_PREFIX_4 "DAHDI:Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability));
+	dp_strip = 0;
+	pridialplan = pri->dialplan - 1;
+	c = callingnum;
+	if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
+		if (strncmp(c, pri->internationalprefix, strlen(pri->internationalprefix)) == 0) {
+			if (pridialplan == -2) {
+				dp_strip = strlen(pri->internationalprefix);
+			}
+			pridialplan = PRI_INTERNATIONAL_ISDN;
+		} else if (strncmp(c, pri->nationalprefix, strlen(pri->nationalprefix)) == 0) {
+			if (pridialplan == -2) {
+				dp_strip = strlen(pri->nationalprefix);
+			}
+			pridialplan = PRI_NATIONAL_ISDN;
+		} else {
+		pridialplan = PRI_LOCAL_ISDN;
+		}
+	}
+	while (c[0] > '9' && c[0] != '*' && c[0] != '#') {
+		switch (c[0]) {
+		case 'U':
+			pridialplan = (PRI_TON_UNKNOWN << 4) | (pridialplan & 0xf);
+			break;
+		case 'I':
+			pridialplan = (PRI_TON_INTERNATIONAL << 4) | (pridialplan & 0xf);
+			break;
+		case 'N':
+			pridialplan = (PRI_TON_NATIONAL << 4) | (pridialplan & 0xf);
+			break;
+		case 'L':
+			pridialplan = (PRI_TON_NET_SPECIFIC << 4) | (pridialplan & 0xf);
+			break;
+		case 'S':
+			pridialplan = (PRI_TON_SUBSCRIBER << 4) | (pridialplan & 0xf);
+			break;
+		case 'V':
+			pridialplan = (PRI_TON_ABBREVIATED << 4) | (pridialplan & 0xf);
+			break;
+		case 'R':
+			pridialplan = (PRI_TON_RESERVED << 4) | (pridialplan & 0xf);
+			break;
+		case 'u':
+			pridialplan = PRI_NPI_UNKNOWN | (pridialplan & 0xf0);
+			break;
+		case 'e':
+			pridialplan = PRI_NPI_E163_E164 | (pridialplan & 0xf0);
+			break;
+		case 'x':
+			pridialplan = PRI_NPI_X121 | (pridialplan & 0xf0);
+			break;
+		case 'f':
+			pridialplan = PRI_NPI_F69 | (pridialplan & 0xf0);
+			break;
+		case 'n':
+			pridialplan = PRI_NPI_NATIONAL | (pridialplan & 0xf0);
+			break;
+		case 'p':
+			pridialplan = PRI_NPI_PRIVATE | (pridialplan & 0xf0);
+			break;
+		case 'r':
+			pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0);
+			break;
+		default:
+			if (isalpha(*c))
+				ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c);
+		}
+		c++;
+	}
+	pri_sr_set_called(sr, c + dp_strip, pridialplan, s ? 1 : 0);
+
+	l = callernum;
+	n = callername;
+	ldp_strip = 0;
+	prilocaldialplan = pri->localdialplan - 1;
+	if ((l != NULL) && (prilocaldialplan == -2 || prilocaldialplan == -3)) { /* compute dynamically */
+		if (strncmp(l, pri->internationalprefix, strlen(pri->internationalprefix)) == 0) {
+			if (prilocaldialplan == -2) {
+				ldp_strip = strlen(pri->internationalprefix);
+			}
+			prilocaldialplan = PRI_INTERNATIONAL_ISDN;
+		} else if (strncmp(l, pri->nationalprefix, strlen(pri->nationalprefix)) == 0) {
+			if (prilocaldialplan == -2) {
+				ldp_strip = strlen(pri->nationalprefix);
+			}
+			prilocaldialplan = PRI_NATIONAL_ISDN;
+		} else {
+			prilocaldialplan = PRI_LOCAL_ISDN;
+		}
+	}
+	if (l != NULL) {
+		while (*l > '9' && *l != '*' && *l != '#') {
+			switch (*l) {
+			case 'U':
+				prilocaldialplan = (PRI_TON_UNKNOWN << 4) | (prilocaldialplan & 0xf);
+				break;
+			case 'I':
+				prilocaldialplan = (PRI_TON_INTERNATIONAL << 4) | (prilocaldialplan & 0xf);
+				break;
+			case 'N':
+				prilocaldialplan = (PRI_TON_NATIONAL << 4) | (prilocaldialplan & 0xf);
+				break;
+			case 'L':
+				prilocaldialplan = (PRI_TON_NET_SPECIFIC << 4) | (prilocaldialplan & 0xf);
+				break;
+			case 'S':
+				prilocaldialplan = (PRI_TON_SUBSCRIBER << 4) | (prilocaldialplan & 0xf);
+				break;
+			case 'V':
+				prilocaldialplan = (PRI_TON_ABBREVIATED << 4) | (prilocaldialplan & 0xf);
+				break;
+			case 'R':
+				prilocaldialplan = (PRI_TON_RESERVED << 4) | (prilocaldialplan & 0xf);
+				break;
+			case 'u':
+				prilocaldialplan = PRI_NPI_UNKNOWN | (prilocaldialplan & 0xf0);
+				break;
+			case 'e':
+				prilocaldialplan = PRI_NPI_E163_E164 | (prilocaldialplan & 0xf0);
+				break;
+			case 'x':
+				prilocaldialplan = PRI_NPI_X121 | (prilocaldialplan & 0xf0);
+				break;
+			case 'f':
+				prilocaldialplan = PRI_NPI_F69 | (prilocaldialplan & 0xf0);
+				break;
+			case 'n':
+				prilocaldialplan = PRI_NPI_NATIONAL | (prilocaldialplan & 0xf0);
+				break;
+			case 'p':
+				prilocaldialplan = PRI_NPI_PRIVATE | (prilocaldialplan & 0xf0);
+				break;
+			case 'r':
+				prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0);
+				break;
+			default:
+				if (isalpha(*l))
+					ast_log(LOG_WARNING, "Unrecognized prilocaldialplan %s modifier: %c\n", *c > 'Z' ? "NPI" : "TON", *c);
+			}
+			l++;
+		}
+	}
+
+	pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
+		pri->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
+
+	cclink = ccbsnr_new_id(cref, prispan, call, type, callingnum, callernum,
+					callername, context, (int)strtol(priority, NULL, 0), ast);
+	if (!cclink) {
+		ast_log(LOG_WARNING, "Unable to allocate ccbsnr list object. Aborting!\n");
+		pri_rel(pri);
+		pri_sr_free(sr);
+		return -1;
+	}
+
+	if (pri_setup(pri->pri, cclink->call, sr)) {
+		unsigned int handle = CCBS_HANDLE(prispan, cref);
+		ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", 
+			c + dp_strip, dialplan2str(pri->dialplan));
+
+		pri_hangup(pri->pri, cclink->call, -1);
+		cclink->call = NULL;
+		ccbsnr_del_link(handle);
+		pri_rel(pri);
+		pri_sr_free(sr);
+
+		return -1;
+	}
+
+	pri_sr_free(sr);
+	ast_setstate(ast, AST_STATE_DIALING);
+	pri_rel(pri);
+
+	return 0;
+}
+
+
 static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
 
 static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, void *data)
@@ -3344,6 +4487,21 @@
 	
 	ast_mutex_lock(&p->lock);
 	
+#ifdef HAVE_PRI
+	if (p->dummychannel == 1) {
+		ast_verb(3, "Hangup: dummy-channel(%s)\n", ast->name);
+		ast_verb(3, "Hangup:tech_pvt=%x q931_call=%x\n", (int)p, (int)p->call);
+
+		ast->tech_pvt = NULL;
+		ast_mutex_unlock(&p->lock);
+		ast_module_unref(ast_module_info->self);
+		ast_mutex_destroy(&p->lock);
+		ast_free(p);
+		return 0;
+	}
+	p->ccringout = 0;
+#endif	
+
 	idx = dahdi_get_index(ast, p, 1);
 
 	if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
@@ -9041,6 +10199,9 @@
 						ast_copy_string(pris[span].privateprefix, conf->pri.privateprefix, sizeof(pris[span].privateprefix));
 						ast_copy_string(pris[span].unknownprefix, conf->pri.unknownprefix, sizeof(pris[span].unknownprefix));
 						pris[span].resetinterval = conf->pri.resetinterval;
+						if (chan_sig == SIG_PRI) {
+							pris[span].use_callingpres = conf->chan.use_callingpres;
+						}
 						
 						tmp->pri = &pris[span];
 						tmp->prioffset = offset;
@@ -9722,6 +10883,11 @@
 					p->digital = 1;
 					if (tmp)
 						tmp->transfercapability = AST_TRANS_CAP_DIGITAL;
+#ifdef HAVE_PRI
+				} else if (opt == 'q') {
+					/* Append CC-Ringout facility */
+					p->ccringout = 1;
+#endif		
 				} else {
 					ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
 				}
@@ -11215,6 +12381,7 @@
 							p->inalarm = 1;
 						}
 					}
+					ccbsnr_destroy_all_of_span(pri);
 				}
 				break;
 			case PRI_EVENT_RESTART:
@@ -11755,215 +12922,426 @@
 				}
 				break;				
 			case PRI_EVENT_FACILITY:
-				chanpos = pri_find_principle(pri, e->facility.channel);
-				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);
-				} else {
-					chanpos = pri_fixup_principle(pri, chanpos, e->facility.call);
-					if (chanpos < 0) {
-						ast_log(LOG_WARNING, "Facility requested on channel %d/%d not in use on span %d\n", 
-							PRI_SPAN(e->facility.channel), PRI_CHANNEL(e->facility.channel), pri->span);
-					} else {
-						int i;
-
-						ast_mutex_lock(&pri->pvts[chanpos]->lock);
+				{
+					unsigned int handle;
+					int channel = e->facility.channel;
+					int ccbsnronprispan = PRI_SPAN(channel);
+					int explicit = PRI_EXPLICIT(channel);
+					int i;
+
+					channel = PRI_CHANNEL(channel);
+
+					ast_verbose(VERBOSE_PREFIX_4 "PRI_EVENT_CC_FACILITY e->facility.channel(0x%x) span(%d) explicit(%d) channel(%d)\n", \
+								e->facility.channel, ccbsnronprispan, explicit, channel);
+					if (channel == 0) {
 						for (i = 0; i < e->facility.subcmds.counter_subcmd; i++) {
 							subcommand *subcmd = &e->facility.subcmds.subcmd[i];
-
 							switch (subcmd->cmd) {
-							case CMD_CONNECTEDLINE:
+							case CMD_CC_EXECPOSIBLE_INV:
 								{
-									struct ast_party_connected_line connected;
-									cmd_connectedline *cmdcl;
-									struct ast_channel *owner = pri->pvts[chanpos]->owner;
-
-									/* Update the connected line information on the other channel */
-									ast_party_connected_line_init(&connected);
-									cmdcl = &subcmd->connectedline;
-									connected.id.number = cmdcl->connected.id.number;
-									connected.id.name = cmdcl->connected.id.name;
-									connected.id.number_type = cmdcl->connected.id.number_type;
-									connected.id.number_presentation = pri_to_ast_presentation(cmdcl->connected.id.number_presentation);
-									connected.source = pri_to_ast_connected_line_update_source(cmdcl->connected.source);
-									ast_queue_connected_line_update(owner, &connected);
-
-									ast_copy_string(pri->pvts[chanpos]->lastcid_num, cmdcl->connected.id.number, sizeof(pri->pvts[chanpos]->lastcid_num));
-									ast_copy_string(pri->pvts[chanpos]->lastcid_name, cmdcl->connected.id.name, sizeof(pri->pvts[chanpos]->lastcid_name));
-
-									pri->pvts[chanpos]->subs[SUB_REAL].needcallerid =1;
-								}
-								break;
-							case CMD_REDIRECTING:
-								{
-									struct ast_party_redirecting redirecting = {{0,},};
-									cmd_redirecting *cmdr;
-									struct ast_channel *owner = pri->pvts[chanpos]->owner;
-
-									cmdr = &subcmd->redirecting;
-									redirecting.from.number = cmdr->redirecting.from.number;
-									redirecting.from.name = cmdr->redirecting.from.name;
-									redirecting.from.number_type = cmdr->redirecting.from.number_type;
-									redirecting.from.number_presentation = pri_to_ast_presentation(cmdr->redirecting.from.number_presentation);
-									redirecting.to.number = cmdr->redirecting.to.number;
-									redirecting.to.name = cmdr->redirecting.to.name;
-									redirecting.to.number_type = cmdr->redirecting.to.number_type;
-									redirecting.to.number_presentation = pri_to_ast_presentation(cmdr->redirecting.to.number_presentation);
-									redirecting.count = 0;
-									redirecting.reason = pri_to_ast_reason(cmdr->redirecting.reason);
-									ast_queue_redirecting_update(owner, &redirecting);
+									int cr = e->facility.cref;
+									ast_verbose(VERBOSE_PREFIX_4 "Facility cc-execposible INV cr %d channel %d/%d, span %d\n",
+												cr, ccbsnronprispan, channel, pri->span);
+
+									handle = CCBS_HANDLE(ccbsnronprispan,cr);
+									unsigned int state = 0;
+									ast_verbose(VERBOSE_PREFIX_4 "Facility cc-execposible: handle=%x\n", handle);
+									if (ccbsnr_get_link(handle, &state) != NULL) {
+										if (state == CC_INVOKED_A_RET) {
+											ast_verbose(VERBOSE_PREFIX_4 "DAHDI ccbsnr_remote_user_free: state '%d'\n", state);
+											ccbsnr_remote_user_free(handle);
+										}
+									} else {
+										ast_verbose(VERBOSE_PREFIX_3 "Facility cc-execposible: List-obj not found - handle=%x state=%d\n", handle, state);

[... 693 lines stripped ...]



More information about the asterisk-commits mailing list