[svn-commits] rmudgett: branch rmudgett/misdn_xfer_v14 r205976 - in /team/rmudgett/misdn_xf...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Jul 10 15:11:31 CDT 2009


Author: rmudgett
Date: Fri Jul 10 15:11:28 2009
New Revision: 205976

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=205976
Log:
Fixes several call transfer issues with chan_misdn.

JIRA ABE-1903 - Orphaned held calls left in music-on-hold.

Do not simply block passing the hangup event on held calls to asterisk
core.

issue #14692 - Held calls are not automatically cleared after transfer.

Allow the core to initate disconnect of held calls to the ISDN port.  This
also fixes a similar case where the party on hold hangs up before being
transferred or taken off hold.

issue #14355 - Crash if attempt to transfer a call to an application.

Masquerade the other pair of the four asterisk channels involved in the
two calls.  The held call already must be a bridged call (not an
applicaton) or it would have been rejected.

Fixed to allow held calls to be transferred to ringing calls.  Previously,
held calls could only be transferred to connected calls.

*  Eliminated unused call states to simplify hangup code.
*  Eliminated most uses of "holded" because it is not a word.

Modified:
    team/rmudgett/misdn_xfer_v14/channels/chan_misdn.c
    team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.c
    team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.h

Modified: team/rmudgett/misdn_xfer_v14/channels/chan_misdn.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/rmudgett/misdn_xfer_v14/channels/chan_misdn.c?view=diff&rev=205976&r1=205975&r2=205976
==============================================================================
--- team/rmudgett/misdn_xfer_v14/channels/chan_misdn.c (original)
+++ team/rmudgett/misdn_xfer_v14/channels/chan_misdn.c Fri Jul 10 15:11:28 2009
@@ -131,30 +131,32 @@
 	MISDN_ALERTING, /*!<  when Alerting */
 	MISDN_BUSY, /*!<  when BUSY */
 	MISDN_CONNECTED, /*!<  when connected */
-	MISDN_PRECONNECTED, /*!<  when connected */
 	MISDN_DISCONNECTED, /*!<  when connected */
-	MISDN_RELEASED, /*!<  when connected */
-	MISDN_BRIDGED, /*!<  when bridged */
 	MISDN_CLEANING, /*!< when hangup from * but we were connected before */
-	MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP  came from misdn */
-	MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */
-	MISDN_HOLDED, /*!< if this chan is holded */
-	MISDN_HOLD_DISCONNECT, /*!< if this chan is holded */
-  
 };
 
 #define ORG_AST 1
 #define ORG_MISDN 2
 
+enum misdn_hold_state {
+	MISDN_HOLD_IDLE,		/*!< HOLD not active */
+	MISDN_HOLD_ACTIVE,		/*!< Call is held */
+	MISDN_HOLD_TRANSFER,	/*!< Held call is being transferred */
+	MISDN_HOLD_DISCONNECT,	/*!< Held call is being disconnected */
+};
 struct hold_info {
 	/*!
-	 * \brief Logical port the channel call record is HOLDED on 
-	 * because the B channel is no longer associated. 
+	 * \brief Call HOLD state.
+	 */
+	enum misdn_hold_state state;
+	/*!
+	 * \brief Logical port the channel call record is HELD on
+	 * because the B channel is no longer associated.
 	 */
 	int port;
 
 	/*!
-	 * \brief Original B channel number the HOLDED call was using. 
+	 * \brief Original B channel number the HELD call was using.
 	 * \note Used only for debug display messages.
 	 */
 	int channel;
@@ -318,13 +320,13 @@
 	struct misdn_bchannel *bc;
 
 	/*!
-	 * \brief HOLDED channel information
+	 * \brief HELD channel call information
 	 */
-	struct hold_info hold_info;
-
-	/*! 
-	 * \brief From associated B channel: Layer 3 process ID 
-	 * \note Used to find the HOLDED channel call record when retrieving a call. 
+	struct hold_info hold;
+
+	/*!
+	 * \brief From associated B channel: Layer 3 process ID
+	 * \note Used to find the HELD channel call record when retrieving a call.
 	 */
 	unsigned int l3id;
 
@@ -485,7 +487,6 @@
 static struct ast_channel *misdn_new(struct chan_list *cl, int state,  char *exten, char *callerid, int format, int port, int c);
 static void send_digit_to_chan(struct chan_list *cl, char digit );
 
-static void hangup_chan(struct chan_list *ch);
 static int pbx_start_chan(struct chan_list *ch);
 
 #define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
@@ -531,12 +532,13 @@
 
 
 static int dialtone_indicate(struct chan_list *cl);
-static int hanguptone_indicate(struct chan_list *cl);
+static void hanguptone_indicate(struct chan_list *cl);
 static int stop_indicate(struct chan_list *cl);
 
 static int start_bc_tones(struct chan_list *cl);
 static int stop_bc_tones(struct chan_list *cl);
-static void release_chan(struct misdn_bchannel *bc);
+static void release_chan_early(struct chan_list *ch);
+static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc);
 
 static int misdn_check_l2l1(struct ast_channel *chan, void *data);
 static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
@@ -1191,15 +1193,8 @@
 	{MISDN_ALERTING,"ALERTING"}, /*  when Alerting */
 	{MISDN_BUSY,"BUSY"}, /*  when BUSY */
 	{MISDN_CONNECTED,"CONNECTED"}, /*  when connected */
-	{MISDN_PRECONNECTED,"PRECONNECTED"}, /*  when connected */
 	{MISDN_DISCONNECTED,"DISCONNECTED"}, /*  when connected */
-	{MISDN_RELEASED,"RELEASED"}, /*  when connected */
-	{MISDN_BRIDGED,"BRIDGED"}, /*  when bridged */
 	{MISDN_CLEANING,"CLEANING"}, /* when hangup from * but we were connected before */
-	{MISDN_HUNGUP_FROM_MISDN,"HUNGUP_FROM_MISDN"}, /* when DISCONNECT/RELEASE/REL_COMP  came from misdn */
-	{MISDN_HOLDED,"HOLDED"}, /* when DISCONNECT/RELEASE/REL_COMP  came from misdn */
-	{MISDN_HOLD_DISCONNECT,"HOLD_DISCONNECT"}, /* when DISCONNECT/RELEASE/REL_COMP  came from misdn */
-	{MISDN_HUNGUP_FROM_AST,"HUNGUP_FROM_AST"} /* when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */
 };
 
 static const char *misdn_get_ch_state(struct chan_list *p) 
@@ -1329,8 +1324,8 @@
 		if (bc) {
 			print_bc_info(fd, help, bc);
 		} else {
-			if (help->state == MISDN_HOLDED) {
-				ast_cli(fd, "ITS A HOLDED BC:\n");
+			if (help->hold.state != MISDN_HOLD_IDLE) {
+				ast_cli(fd, "ITS A HELD CALL BC:\n");
 				ast_cli(fd, " --> l3_id: %x\n"
 						" --> dad:%s oad:%s\n"
 						" --> hold_port: %d\n"
@@ -1338,8 +1333,8 @@
 						help->l3id,
 						ast->exten,
 						ast->cid.cid_num,
-						help->hold_info.port,
-						help->hold_info.channel
+						help->hold.port,
+						help->hold.channel
 						);
 			} else {
 				ast_cli(fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num);
@@ -2414,13 +2409,19 @@
 		return -1;
 	}
 	
-	if (!p->bc ) {
-		chan_misdn_log(1, 0, "* IND : Indication from %s\n", ast->exten);
-		ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
+	if (!p->bc) {
+		if (p->hold.state == MISDN_HOLD_IDLE) {
+			chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on %s\n", cond,
+				ast->name);
+			ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
+		} else {
+			chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on hold %s\n",
+				cond, ast->name);
+		}
 		return -1;
 	}
 	
-	chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] from %s\n", cond, ast->exten);
+	chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] on %s\n\n", cond, ast->name);
 	
 	switch (cond) {
 	case AST_CONTROL_BUSY:
@@ -2521,6 +2522,7 @@
 		break;
 	default:
 		chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc ? p->bc->pid : -1);
+		return -1;
 	}
   
 	return 0;
@@ -2529,174 +2531,170 @@
 static int misdn_hangup(struct ast_channel *ast)
 {
 	struct chan_list *p;
-	struct misdn_bchannel *bc = NULL;
-	const char *varcause = NULL;
+	struct misdn_bchannel *bc;
+	const char *var;
+
+	if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
+		return -1;
+	}
+	MISDN_ASTERISK_TECH_PVT(ast) = NULL;
 
 	ast_log(LOG_DEBUG, "misdn_hangup(%s)\n", ast->name);
 
-	if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) ) ) return -1;
-
-	if (!p) {
-		chan_misdn_log(3, 0, "misdn_hangup called, without chan_list obj.\n");
-		return 0 ;
-	}
-
-	bc = p->bc;
-
-	if (bc) {
-		const char *tmp=pbx_builtin_getvar_helper(ast,"MISDN_USERUSER");
-		if (tmp) {
-			ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
-			strcpy(bc->uu, tmp);
-			bc->uulen=strlen(bc->uu);
-		}
-	}
-
-	MISDN_ASTERISK_TECH_PVT(ast) = NULL;
-	p->ast = NULL;
-
-	if (ast->_state == AST_STATE_RESERVED || 
-		p->state == MISDN_NOTHING || 
-		p->state == MISDN_HOLDED || 
-		p->state == MISDN_HOLD_DISCONNECT ) {
-
-		CLEAN_CH:
+	if (p->hold.state == MISDN_HOLD_IDLE) {
+		bc = p->bc;
+	} else {
+		p->hold.state = MISDN_HOLD_DISCONNECT;
+		bc = misdn_lib_find_held_bc(p->hold.port, p->l3id);
+		if (!bc) {
+			chan_misdn_log(4, p->hold.port,
+				"misdn_hangup: Could not find held bc for (%s)\n", ast->name);
+			release_chan_early(p);
+			return 0;
+		}
+	}
+
+	if (ast->_state == AST_STATE_RESERVED || p->state == MISDN_NOTHING) {
 		/* between request and call */
 		ast_log(LOG_DEBUG, "State Reserved (or nothing) => chanIsAvail\n");
-		MISDN_ASTERISK_TECH_PVT(ast) = NULL;
-	
-		ast_mutex_lock(&release_lock);
-		cl_dequeue_chan(&cl_te, p);
-		close(p->pipe[0]);
-		close(p->pipe[1]);
-		free(p);
-		ast_mutex_unlock(&release_lock);
-		
-		if (bc)
+		release_chan_early(p);
+		if (bc) {
 			misdn_lib_release(bc);
-		
+		}
 		return 0;
 	}
-
 	if (!bc) {
-		ast_log(LOG_WARNING, "Hangup with private but no bc ? state:%s l3id:%x\n", misdn_get_ch_state(p), p->l3id);
-		goto CLEAN_CH;
-	}
-
-
+		ast_log(LOG_WARNING, "Hangup with private but no bc ? state:%s l3id:%x\n",
+			misdn_get_ch_state(p), p->l3id);
+		release_chan_early(p);
+		return 0;
+	}
+
+	p->ast = NULL;
 	p->need_hangup = 0;
 	p->need_queue_hangup = 0;
 	p->need_busy = 0;
 
-
-	if (!p->bc->nt) 
+	if (!bc->nt) {
 		stop_bc_tones(p);
+	}
 
 	bc->out_cause = ast->hangupcause ? ast->hangupcause : AST_CAUSE_NORMAL_CLEARING;
 
-	if ((varcause = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE")) ||
-		(varcause = pbx_builtin_getvar_helper(ast, "PRI_CAUSE"))) {
-		int tmpcause = atoi(varcause);
+	var = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE");
+	if (!var) {
+		var = pbx_builtin_getvar_helper(ast, "PRI_CAUSE");
+	}
+	if (var) {
+		int tmpcause;
+
+		tmpcause = atoi(var);
 		bc->out_cause = tmpcause ? tmpcause : AST_CAUSE_NORMAL_CLEARING;
 	}
 
-	chan_misdn_log(1, bc->port, "* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n", p->bc ? p->bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(p));
+	var = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER");
+	if (var) {
+		ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", var);
+		ast_copy_string(bc->uu, var, sizeof(bc->uu));
+		bc->uulen = strlen(bc->uu);
+	}
+
+	chan_misdn_log(1, bc->port,
+		"* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n",
+		bc->pid,
+		ast->context,
+		ast->exten,
+		ast->cid.cid_num,
+		misdn_get_ch_state(p));
 	chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
 	chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
 	chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);
-	chan_misdn_log(2, bc->port, " --> state:%s\n", misdn_get_ch_state(p));
 
 	switch (p->state) {
 	case MISDN_INCOMING_SETUP:
-		/* This is the only place in misdn_hangup, where we 
-		 * can call release_chan, else it might create lot's of trouble
-		 * */
+		/*
+		 * This is the only place in misdn_hangup, where we
+		 * can call release_chan, else it might create a lot of trouble.
+		 */
 		ast_log(LOG_NOTICE, "release channel, in INCOMING_SETUP state.. no other events happened\n");
-		release_chan(bc);
-
-		p->state = MISDN_CLEANING;
-		if (bc->need_release_complete)
-			misdn_lib_send_event( bc, EVENT_RELEASE_COMPLETE);
-		break;
-	case MISDN_HOLDED:
+		release_chan(p, bc);
+
+		if (bc->need_release_complete) {
+			misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+		}
+		return 0;
 	case MISDN_DIALING:
-		start_bc_tones(p);
-		hanguptone_indicate(p);
-
-		if (bc->need_disconnect)
-			misdn_lib_send_event( bc, EVENT_DISCONNECT);
+		if (p->hold.state == MISDN_HOLD_IDLE) {
+			start_bc_tones(p);
+			hanguptone_indicate(p);
+		}
+
+		if (bc->need_disconnect) {
+			misdn_lib_send_event(bc, EVENT_DISCONNECT);
+		}
 		break;
 	case MISDN_CALLING_ACKNOWLEDGE:
-		start_bc_tones(p);
-		hanguptone_indicate(p);
-
-		if (bc->need_disconnect)
-			misdn_lib_send_event( bc, EVENT_DISCONNECT);
+		if (p->hold.state == MISDN_HOLD_IDLE) {
+			start_bc_tones(p);
+			hanguptone_indicate(p);
+		}
+
+		if (bc->need_disconnect) {
+			misdn_lib_send_event(bc, EVENT_DISCONNECT);
+		}
 		break;
 
 	case MISDN_CALLING:
 	case MISDN_ALERTING:
 	case MISDN_PROGRESS:
 	case MISDN_PROCEEDING:
-		if (p->originator != ORG_AST) 
+		if (p->originator != ORG_AST && p->hold.state == MISDN_HOLD_IDLE) {
 			hanguptone_indicate(p);
-
-		/*p->state=MISDN_CLEANING;*/
-		if (bc->need_disconnect)
-			misdn_lib_send_event( bc, EVENT_DISCONNECT);
+		}
+
+		if (bc->need_disconnect) {
+			misdn_lib_send_event(bc, EVENT_DISCONNECT);
+		}
 		break;
 	case MISDN_CONNECTED:
-	case MISDN_PRECONNECTED:
 		/*  Alerting or Disconnect */
-		if (p->bc->nt) {
+		if (bc->nt && p->hold.state == MISDN_HOLD_IDLE) {
 			start_bc_tones(p);
 			hanguptone_indicate(p);
-			p->bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
-		}
-		if (bc->need_disconnect)
-			misdn_lib_send_event( bc, EVENT_DISCONNECT);
-
-		/*p->state=MISDN_CLEANING;*/
+			bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
+		}
+		if (bc->need_disconnect) {
+			misdn_lib_send_event(bc, EVENT_DISCONNECT);
+		}
 		break;
 	case MISDN_DISCONNECTED:
-		if (bc->need_release)
-			misdn_lib_send_event( bc, EVENT_RELEASE);
-		p->state = MISDN_CLEANING; /* MISDN_HUNGUP_FROM_AST; */
+		if (bc->need_release) {
+			misdn_lib_send_event(bc, EVENT_RELEASE);
+		}
 		break;
 
-	case MISDN_RELEASED:
 	case MISDN_CLEANING:
-		p->state = MISDN_CLEANING;
-		break;
+		return 0;
 
 	case MISDN_BUSY:
-		break;
-
-	case MISDN_HOLD_DISCONNECT:
-		/* need to send release here */
-		chan_misdn_log(1, bc->port, " --> cause %d\n", bc->cause);
-		chan_misdn_log(1, bc->port, " --> out_cause %d\n", bc->out_cause);
-
-		bc->out_cause = -1;
-		if (bc->need_release)
-			misdn_lib_send_event(bc, EVENT_RELEASE);
-		p->state = MISDN_CLEANING;
 		break;
 	default:
 		if (bc->nt) {
 			bc->out_cause = -1;
-			if (bc->need_release)
+			if (bc->need_release) {
 				misdn_lib_send_event(bc, EVENT_RELEASE);
-			p->state = MISDN_CLEANING; 
+			}
 		} else {
-			if (bc->need_disconnect)
+			if (bc->need_disconnect) {
 				misdn_lib_send_event(bc, EVENT_DISCONNECT);
-		}
+			}
+		}
+		break;
 	}
 
 	p->state = MISDN_CLEANING;
-
-	chan_misdn_log(3, bc->port, " --> Channel: %s hanguped new state:%s\n", ast->name, misdn_get_ch_state(p));
+	chan_misdn_log(3, bc->port, " --> Channel: %s hungup new state:%s\n", ast->name,
+		misdn_get_ch_state(p));
 
 	return 0;
 }
@@ -2789,7 +2787,7 @@
 		return NULL;
 	}
 
-	if (!tmp->bc && !(tmp->state == MISDN_HOLDED)) {
+	if (!tmp->bc && tmp->hold.state == MISDN_HOLD_IDLE) {
 		chan_misdn_log(1, 0, "misdn_read called without bc\n");
 		return NULL;
 	}
@@ -2873,8 +2871,8 @@
 	
 	if (!ast || ! (ch = MISDN_ASTERISK_TECH_PVT(ast)) ) return -1;
 
-	if (ch->state == MISDN_HOLDED) {
-		chan_misdn_log(7, 0, "misdn_write: Returning because holded\n");
+	if (ch->hold.state != MISDN_HOLD_IDLE) {
+		chan_misdn_log(7, 0, "misdn_write: Returning because hold active\n");
 		return 0;
 	}
 	
@@ -3107,10 +3105,9 @@
 	return 0;
 }
 
-static int hanguptone_indicate(struct chan_list *cl)
+static void hanguptone_indicate(struct chan_list *cl)
 {
 	misdn_lib_send_tone(cl->bc, TONE_HANGUP);
-	return 0;
 }
 
 static int stop_indicate(struct chan_list *cl)
@@ -3538,38 +3535,71 @@
 	return NULL;
 }
 
-static struct chan_list *find_holded(struct chan_list *list, struct misdn_bchannel *bc)
+static struct chan_list *find_hold_call(struct chan_list *list, struct misdn_bchannel *bc)
 {
 	struct chan_list *help = list;
 
 	if (bc->pri) return NULL;
 
-	chan_misdn_log(6, bc->port, "$$$ find_holded: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad);
+	chan_misdn_log(6, bc->port, "$$$ find_hold_call: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad);
 	for (;help; help = help->next) {
-		chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n", help->state == MISDN_HOLDED, help->hold_info.channel);
-		if ((help->state == MISDN_HOLDED) && 
-			(help->hold_info.port == bc->port))
+		chan_misdn_log(4, bc->port, "$$$ find_hold_call: --> hold:%d channel:%d\n", help->hold.state, help->hold.channel);
+		if (help->hold.state == MISDN_HOLD_ACTIVE && help->hold.port == bc->port)
 			return help;
 	}
-	chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
+	chan_misdn_log(6, bc->port, "$$$ find_hold_call: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
 
 	return NULL;
 }
 
 
-static struct chan_list *find_holded_l3(struct chan_list *list, unsigned long l3_id, int w) 
+static struct chan_list *find_hold_call_l3(struct chan_list *list, unsigned long l3_id)
 {
 	struct chan_list *help = list;
 
 	for (; help; help = help->next) {
-		if ( (help->state == MISDN_HOLDED) &&
-			 (help->l3id == l3_id)   
-			) 
+		if (help->hold.state != MISDN_HOLD_IDLE && help->l3id == l3_id)
 			return help;
 	}
 
 	return NULL;
 }
+
+#define TRANSFER_ON_HELD_CALL_HANGUP 1
+#if defined(TRANSFER_ON_HELD_CALL_HANGUP)
+/*!
+ * \internal
+ * \brief Find a suitable active call to go with a held call so we could try a transfer.
+ *
+ * \param list Channel list.
+ * \param bc B channel record.
+ *
+ * \return Found call record or NULL.
+ *
+ * \note There could be a possibility where we find the wrong active call to transfer.
+ * This concern is mitigated by the fact that there could be at most one other call
+ * on a PTMP BRI link to another device.  Maybe the l3_id could help in locating an
+ * active call on the same TEI?
+ */
+static struct chan_list *find_hold_active_call(struct chan_list *list, struct misdn_bchannel *bc)
+{
+	for (; list; list = list->next) {
+		if (list->hold.state == MISDN_HOLD_IDLE && list->bc && list->bc->port == bc->port
+			&& list->ast) {
+			switch (list->state) {
+			case MISDN_PROCEEDING:
+			case MISDN_PROGRESS:
+			case MISDN_ALERTING:
+			case MISDN_CONNECTED:
+				return list;
+			default:
+				break;
+			}
+		}
+	}
+	return NULL;
+}
+#endif	/* defined(TRANSFER_ON_HELD_CALL_HANGUP) */
 
 static void cl_queue_chan(struct chan_list **list, struct chan_list *chan)
 {
@@ -3634,23 +3664,26 @@
 	return ret;
 }
 
-static void hangup_chan(struct chan_list *ch)
-{
-	int port = ch ? (ch->bc ? ch->bc->port : 0) : 0;
+static void hangup_chan(struct chan_list *ch, struct misdn_bchannel *bc)
+{
+	int port;
+
 	if (!ch) {
 		cb_log(1, 0, "Cannot hangup chan, no ch\n");
 		return;
 	}
 
+	port = bc->port;
 	cb_log(5, port, "hangup_chan called\n");
 
 	if (ch->need_hangup) {
 		cb_log(2, port, " --> hangup\n");
-		send_cause2ast(ch->ast, ch->bc, ch);
 		ch->need_hangup = 0;
 		ch->need_queue_hangup = 0;
-		if (ch->ast)
+		if (ch->ast) {
+			send_cause2ast(ch->ast, bc, ch);
 			ast_hangup(ch->ast);
+		}
 		return;
 	}
 
@@ -3660,96 +3693,185 @@
 
 	ch->need_queue_hangup = 0;
 	if (ch->ast) {
-		send_cause2ast(ch->ast, ch->bc, ch);
-
-		if (ch->ast)
-			ast_queue_hangup(ch->ast);
+		send_cause2ast(ch->ast, bc, ch);
+		ast_queue_hangup(ch->ast);
 		cb_log(2, port, " --> queue_hangup\n");
 	} else {
 		cb_log(1, port, "Cannot hangup chan, no ast\n");
 	}
 }
 
-/** Isdn asks us to release channel, pendant to misdn_hangup **/
-static void release_chan(struct misdn_bchannel *bc) {
-	struct ast_channel *ast = NULL;
+/*!
+ * \internal
+ * \brief ISDN asked us to release channel, pendant to misdn_hangup.
+ *
+ * \param ch Call channel record to release.
+ * \param bc Current B channel record associated with ch.
+ *
+ * \return Nothing
+ *
+ * \note ch must not be referenced after calling.
+ */
+static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc)
+{
+	struct ast_channel *ast;
+
+	ch->state = MISDN_CLEANING;
 
 	ast_mutex_lock(&release_lock);
-	{
-		struct chan_list *ch=find_chan_by_bc(cl_te, bc);
-		if (!ch)  {
-			chan_misdn_log(1, bc->port, "release_chan: Ch not found!\n");
-			ast_mutex_unlock(&release_lock);
-			return;
-		}
-
-		if (ch->ast) {
-			ast = ch->ast;
-		} 
-
-		chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id);
-
-		/*releasing jitterbuffer*/
-		if (ch->jb ) {
-			misdn_jb_destroy(ch->jb);
-			ch->jb = NULL;
+
+	cl_dequeue_chan(&cl_te, ch);
+
+	chan_misdn_log(5, bc->port, "release_chan: bc with pid:%d l3id: %x\n", bc->pid, bc->l3_id);
+
+	/* releasing jitterbuffer */
+	if (ch->jb) {
+		misdn_jb_destroy(ch->jb);
+		ch->jb = NULL;
+	} else {
+		if (!bc->nojitter) {
+			chan_misdn_log(5, bc->port, "Jitterbuffer already destroyed.\n");
+		}
+	}
+
+	if (ch->overlap_dial) {
+		if (ch->overlap_dial_task != -1) {
+			misdn_tasks_remove(ch->overlap_dial_task);
+			ch->overlap_dial_task = -1;
+		}
+		ast_mutex_destroy(&ch->overlap_tv_lock);
+	}
+
+	if (ch->originator == ORG_AST) {
+		--misdn_out_calls[bc->port];
+	} else {
+		--misdn_in_calls[bc->port];
+	}
+
+	close(ch->pipe[0]);
+	close(ch->pipe[1]);
+
+	ast = ch->ast;
+	if (ast) {
+		MISDN_ASTERISK_TECH_PVT(ast) = NULL;
+		chan_misdn_log(1, bc->port,
+			"* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s\n",
+			bc->pid,
+			ast->context,
+			ast->exten,
+			ast->cid.cid_num);
+
+		if (ast->_state != AST_STATE_RESERVED) {
+			chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
+			ast_setstate(ast, AST_STATE_DOWN);
+		}
+	}
+
+	free(ch);
+
+	ast_mutex_unlock(&release_lock);
+}
+
+/*!
+ * \internal
+ * \brief Do everything in release_chan() that makes sense without a bc.
+ *
+ * \param ch Call channel record to release.
+ *
+ * \return Nothing
+ *
+ * \note ch must not be referenced after calling.
+ */
+static void release_chan_early(struct chan_list *ch)
+{
+	struct ast_channel *ast;
+
+	ch->state = MISDN_CLEANING;
+
+	ast_mutex_lock(&release_lock);
+
+	cl_dequeue_chan(&cl_te, ch);
+
+	/* releasing jitterbuffer */
+	if (ch->jb) {
+		misdn_jb_destroy(ch->jb);
+		ch->jb = NULL;
+	}
+
+	if (ch->overlap_dial) {
+		if (ch->overlap_dial_task != -1) {
+			misdn_tasks_remove(ch->overlap_dial_task);
+			ch->overlap_dial_task = -1;
+		}
+		ast_mutex_destroy(&ch->overlap_tv_lock);
+	}
+
+	if (ch->hold.state != MISDN_HOLD_IDLE) {
+		if (ch->originator == ORG_AST) {
+			--misdn_out_calls[ch->hold.port];
 		} else {
-			if (!bc->nojitter)
-				chan_misdn_log(5, bc->port, "Jitterbuffer already destroyed.\n");
-		}
-
-		if (ch->overlap_dial) {
-			if (ch->overlap_dial_task != -1) {
-				misdn_tasks_remove(ch->overlap_dial_task);
-				ch->overlap_dial_task = -1;
-			}
-			ast_mutex_destroy(&ch->overlap_tv_lock);
-		}
-
-		if (ch->originator == ORG_AST) {
-			misdn_out_calls[bc->port]--;
-		} else {
-			misdn_in_calls[bc->port]--;
-		}
-
-		if (ch) {
-			close(ch->pipe[0]);
-			close(ch->pipe[1]);
-
-			if (ast && MISDN_ASTERISK_TECH_PVT(ast)) {
-				chan_misdn_log(1, bc->port, "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s\n", bc ? bc->pid : -1, ast->context, ast->exten, ast->cid.cid_num, misdn_get_ch_state(ch));
-				chan_misdn_log(3, bc->port, " --> * State Down\n");
-				MISDN_ASTERISK_TECH_PVT(ast) = NULL;
-
-				if (ast->_state != AST_STATE_RESERVED) {
-					chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
-					ast_setstate(ast, AST_STATE_DOWN);
-				}
-			}
-
-			ch->state = MISDN_CLEANING;
-			cl_dequeue_chan(&cl_te, ch);
-
-			free(ch);
-		} else {
-			/* chan is already cleaned, so exiting  */
-		}
-	}
+			--misdn_in_calls[ch->hold.port];
+		}
+	}
+
+	close(ch->pipe[0]);
+	close(ch->pipe[1]);
+
+	ast = ch->ast;
+	if (ast) {
+		MISDN_ASTERISK_TECH_PVT(ast) = NULL;
+		if (ast->_state != AST_STATE_RESERVED) {
+			ast_setstate(ast, AST_STATE_DOWN);
+		}
+	}
+
+	free(ch);
+
 	ast_mutex_unlock(&release_lock);
-/*** release end **/
-}
-
-static void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan)
-{
-	chan_misdn_log(4, 0, "TRANSFERRING %s to %s\n", holded_chan->ast->name, tmp_ch->ast->name);
-
-	tmp_ch->state = MISDN_HOLD_DISCONNECT;
-
-	ast_moh_stop(ast_bridged_channel(holded_chan->ast));
-
-	holded_chan->state=MISDN_CONNECTED;
-	/* misdn_lib_transfer(holded_chan->bc); */
-	ast_channel_masquerade(holded_chan->ast, ast_bridged_channel(tmp_ch->ast));
+}
+
+/*!
+ * \internal
+ * \brief Attempt to transfer the active channel party to the held channel party.
+ *
+ * \param active_ch Channel currently connected.
+ * \param held_ch Channel currently on hold.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int misdn_attempt_transfer(struct chan_list *active_ch, struct chan_list *held_ch)
+{
+	int retval;
+	struct ast_channel *bridged;
+
+	switch (active_ch->state) {
+	case MISDN_PROCEEDING:
+	case MISDN_PROGRESS:
+	case MISDN_ALERTING:
+	case MISDN_CONNECTED:
+		break;
+	default:
+		return -1;
+	}
+
+	bridged = ast_bridged_channel(held_ch->ast);
+	if (bridged) {
+		ast_queue_control(held_ch->ast, AST_CONTROL_UNHOLD);
+		held_ch->hold.state = MISDN_HOLD_TRANSFER;
+
+		chan_misdn_log(1, held_ch->hold.port, "TRANSFERRING %s to %s\n",
+			held_ch->ast->name, active_ch->ast->name);
+		retval = ast_channel_masquerade(active_ch->ast, bridged);
+	} else {
+		/*
+		 * Could not transfer.  Held channel is not bridged anymore.
+		 * Held party probably got tired of waiting and hung up.
+		 */
+		retval = -1;
+	}
+
+	return retval;
 }
 
 
@@ -3787,7 +3909,7 @@
 	if (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, bc->oad) || pbx_start_chan(ch) < 0) {
 		ast = NULL;
 		bc->out_cause = AST_CAUSE_UNALLOCATED;
-		hangup_chan(ch);
+		hangup_chan(ch, bc);
 		hanguptone_indicate(ch);
 
 		if (bc->nt)
@@ -3967,7 +4089,7 @@
 
 static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
 	if (pbx_start_chan(ch) < 0) {
-		hangup_chan(ch);
+		hangup_chan(ch, bc);
 		chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
 		if (bc->nt) {
 			hanguptone_indicate(ch);
@@ -3992,6 +4114,7 @@
 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 {
 	int msn_valid;
+	struct chan_list *held_ch;
 	struct chan_list *ch = find_chan_by_bc(cl_te, bc);
 	
 	if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /*  Debug Only Non-Bchan */
@@ -4010,13 +4133,12 @@
 		switch(event) {
 		case EVENT_SETUP:
 		case EVENT_DISCONNECT:
+		case EVENT_RELEASE:
+		case EVENT_RELEASE_COMPLETE:
 		case EVENT_PORT_ALARM:
 		case EVENT_RETRIEVE:
 		case EVENT_NEW_BC:
 		case EVENT_FACILITY:
-			break;
-		case EVENT_RELEASE_COMPLETE:
-			chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n");
 			break;
 		case EVENT_CLEANUP:
 		case EVENT_TONE_GENERATE:
@@ -4075,7 +4197,7 @@
 
 	case EVENT_NEW_BC:
 		if (!ch) {
-			ch = find_holded(cl_te,bc);
+			ch = find_hold_call(cl_te,bc);
 		}
 		
 		if (!ch) {
@@ -4135,12 +4257,12 @@
 			/* Check for Pickup Request first */
 			if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
 				if (ast_pickup_call(ch->ast)) {
-					hangup_chan(ch);
+					hangup_chan(ch, bc);
 				} else {
 					struct ast_channel *chan = ch->ast;
 					ch->state = MISDN_CALLING_ACKNOWLEDGE;
 					ast_setstate(chan, AST_STATE_DOWN);
-					hangup_chan(ch);
+					hangup_chan(ch, bc);
 					ch->ast = NULL;
 					break;
 				}
@@ -4374,11 +4496,11 @@
 				ch->state = MISDN_INCOMING_SETUP;
 			}
 			if (ast_pickup_call(chan)) {
-				hangup_chan(ch);
+				hangup_chan(ch, bc);
 			} else {
 				ch->state = MISDN_CALLING_ACKNOWLEDGE;
 				ast_setstate(chan, AST_STATE_DOWN);
-				hangup_chan(ch);
+				hangup_chan(ch, bc);
 				ch->ast = NULL;
 				break;
 			}
@@ -4630,8 +4752,6 @@
 	case EVENT_DISCONNECT:
 		/*we might not have an ch->ast ptr here anymore*/
 		if (ch) {
-			struct chan_list *holded_ch = find_holded(cl_te, bc);
-
 			chan_misdn_log(3, bc->port, " --> org:%d nt:%d, inbandavail:%d state:%d\n", ch->originator, bc->nt, misdn_inband_avail(bc), ch->state);
 			if (ch->originator == ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
 				/* If there's inband information available (e.g. a
@@ -4653,23 +4773,34 @@
 				break;
 			}
 
-			/*Check for holded channel, to implement transfer*/
-			if (holded_ch && holded_ch != ch && ch->ast && ch->state == MISDN_CONNECTED) {
-				cb_log(1, bc->port, " --> found holded ch\n");
-				misdn_transfer_bc(ch, holded_ch) ;
-			}
-
 			bc->need_disconnect = 0;
-
 			stop_bc_tones(ch);
-			hangup_chan(ch);
-#if 0
+
+			/* Check for held channel, to implement transfer */
+			held_ch = find_hold_call(cl_te, bc);
+			if (!held_ch || !ch->ast || misdn_attempt_transfer(ch, held_ch)) {
+				hangup_chan(ch, bc);
+			}
 		} else {
-			ch = find_holded_l3(cl_te, bc->l3_id,1);
-			if (ch) {
-				hangup_chan(ch);
-			}
-#endif
+			held_ch = find_hold_call_l3(cl_te, bc->l3_id);
+			if (held_ch && held_ch->hold.state == MISDN_HOLD_ACTIVE) {
+				bc->need_disconnect = 0;
+
+#if defined(TRANSFER_ON_HELD_CALL_HANGUP)
+				/*
+				 * Some phones disconnect the held call and the active call at the
+				 * same time to do the transfer.  Unfortunately, either call could
+				 * be disconnected first.
+				 */
+				ch = find_hold_active_call(cl_te, bc);
+				if (!ch || misdn_attempt_transfer(ch, held_ch)) {
+					held_ch->hold.state = MISDN_HOLD_DISCONNECT;
+					hangup_chan(held_ch, bc);
+				}
+#else
+				hangup_chan(held_ch, bc);
+#endif	/* defined(TRANSFER_ON_HELD_CALL_HANGUP) */
+			}
 		}
 		bc->out_cause = -1;
 		if (bc->need_release)
@@ -4677,29 +4808,41 @@
 		break;
 	
 	case EVENT_RELEASE:
-		{
-			bc->need_disconnect = 0;
-			bc->need_release = 0;
-
-			hangup_chan(ch);
-			release_chan(bc);
-		}
+		if (!ch) {
+			ch = find_hold_call_l3(cl_te, bc->l3_id);
+			if (!ch) {
+				chan_misdn_log(1, bc->port,
+					" --> no Ch, so we've already released. (%s)\n",
+					manager_isdn_get_info(event));
+				return -1;
+			}
+		}
+
+		bc->need_disconnect = 0;
+		bc->need_release = 0;
+
+		hangup_chan(ch, bc);
+		release_chan(ch, bc);
 		break;
 	case EVENT_RELEASE_COMPLETE:
-	{
+		if (!ch) {
+			ch = find_hold_call_l3(cl_te, bc->l3_id);
+			if (!ch) {
+				chan_misdn_log(1, bc->port,
+					" --> no Ch, so we've already released. (%s)\n",
+					manager_isdn_get_info(event));
+				break;
+			}
+		}
+
 		bc->need_disconnect = 0;
 		bc->need_release = 0;
 		bc->need_release_complete = 0;
 
 		stop_bc_tones(ch);
-		hangup_chan(ch);
-
-		if (ch)
-			ch->state = MISDN_CLEANING;
-
-		release_chan(bc);
-	}
-	break;
+		hangup_chan(ch, bc);
+		release_chan(ch, bc);
+		break;
 	case EVENT_BCHAN_ERROR:
 	case EVENT_CLEANUP:
 	{
@@ -4713,8 +4856,8 @@
 			break;
 		}
 		
-		hangup_chan(ch);
-		release_chan(bc);
+		hangup_chan(ch, bc);
+		release_chan(ch, bc);
 	}
 	break;
 
@@ -4798,8 +4941,8 @@
 					chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
 
 					stop_bc_tones(ch);
-					hangup_chan(ch);
-					release_chan(bc);
+					hangup_chan(ch, bc);
+					release_chan(ch, bc);
 				}
 			} else {
 				chan_misdn_log(1, bc->port, "Write Pipe full!\n");
@@ -4859,39 +5002,30 @@
 	/** Supplementary Services **/
 	/****************************/
 	case EVENT_RETRIEVE:
-	{
-		struct ast_channel *hold_ast;
-
 		if (!ch) {
-			chan_misdn_log(4, bc->port, " --> no CH, searching in holded\n");
-			ch = find_holded_l3(cl_te, bc->l3_id, 1);
-		}
-
-		if (!ch) {
-			ast_log(LOG_WARNING, "Found no Holded channel, cannot Retrieve\n");
-			misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
-			break;
-		}
-
-		/*remember the channel again*/
+			chan_misdn_log(4, bc->port, " --> no CH, searching for held call\n");
+			ch = find_hold_call_l3(cl_te, bc->l3_id);
+			if (!ch || ch->hold.state != MISDN_HOLD_ACTIVE) {
+				ast_log(LOG_WARNING, "No held call found, cannot Retrieve\n");
+				misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
+				break;
+			}
+		}
+
+		/* remember the channel again */
 		ch->bc = bc;
-		ch->state = MISDN_CONNECTED;
-
-		ch->hold_info.port = 0;
-		ch->hold_info.channel = 0;
-
-		hold_ast = ast_bridged_channel(ch->ast);
-
-		if (hold_ast) {
-			ast_moh_stop(hold_ast);
-		}
+
+		ch->hold.state = MISDN_HOLD_IDLE;
+		ch->hold.port = 0;
+		ch->hold.channel = 0;
+
+		ast_queue_control(ch->ast, AST_CONTROL_UNHOLD);
 	
 		if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
 			chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
 			misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
 		}
-	}
-	break;
+		break;
     
 	case EVENT_HOLD:
 	{
@@ -4910,20 +5044,17 @@
 		bridged = ast_bridged_channel(ch->ast);
 		if (bridged) {
 			chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", bridged->tech->type);
-			ch->state = MISDN_HOLDED;
 			ch->l3id = bc->l3_id;
+
+			/* forget the channel now */
+			ch->bc = NULL;
+			ch->hold.state = MISDN_HOLD_ACTIVE;
+			ch->hold.port = bc->port;
+			ch->hold.channel = bc->channel;
+
+			ast_queue_control(ch->ast, AST_CONTROL_HOLD);
 			
 			misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
-
-			/* XXX This should queue an AST_CONTROL_HOLD frame on this channel
-			 * instead of starting moh on the bridged channel directly */
-			ast_moh_start(bridged, NULL, NULL);
-
-			/*forget the channel now*/
-			ch->bc = NULL;
-			ch->hold_info.port = bc->port;
-			ch->hold_info.channel = bc->channel;
-
 		} else {
 			misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
 			chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
@@ -4984,7 +5115,7 @@
 
 		if (!bc->dummy) {
 			stop_bc_tones(ch);
-			release_chan(bc);
+			release_chan(ch, bc);
 		}
 		break;
 

Modified: team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.c?view=diff&rev=205976&r1=205975&r2=205976
==============================================================================
--- team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.c (original)
+++ team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.c Fri Jul 10 15:11:28 2009
@@ -214,8 +214,6 @@
 struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long l3id);
 
 struct misdn_bchannel *find_bc_by_confid(unsigned long confid);
-
-struct misdn_bchannel *stack_holder_find_bychan(struct misdn_stack *stack, int chan);
 
 int setup_bc(struct misdn_bchannel *bc);
 
@@ -3099,13 +3097,6 @@
 	cb_log(4, 0, "midev closed\n");
 }
 
-
-
-void misdn_lib_transfer(struct misdn_bchannel* holded_bc)
-{
-	holded_bc->holded=0;
-}
-
 struct misdn_bchannel *manager_find_bc_by_pid(int pid)
 {
 	struct misdn_stack *stack;
@@ -3346,6 +3337,7 @@
 	msg_t *msg; 
 	int retval=0;
 	struct misdn_stack *stack;
+	struct misdn_bchannel *held_bc;
   
 	if (!bc) RETURN(-1,OUT_POST_UNLOCK);
 	
@@ -3432,21 +3424,22 @@
 		break;
 
 	case EVENT_HOLD_ACKNOWLEDGE:
-	{
-		struct misdn_bchannel *holded_bc=malloc(sizeof(struct misdn_bchannel));
-		if (!holded_bc) {
-			cb_log(0,bc->port, "Could not allocate holded_bc!!!\n");
+		held_bc = malloc(sizeof(struct misdn_bchannel));
+		if (!held_bc) {
+			cb_log(0, bc->port, "Could not allocate held_bc!!!\n");
 			RETURN(-1,OUT);
 		}
 
-		/*backup the bc*/
-		memcpy(holded_bc,bc,sizeof(struct misdn_bchannel));
-		holded_bc->holded=1;
-		bc_state_change(holded_bc,BCHAN_CLEANED);
-
-		stack_holder_add(stack,holded_bc);
-	
-		/*kill the bridge and clean the bchannel*/
+		/* backup the bc and put it in storage */
+		*held_bc = *bc;
+		held_bc->holded = 1;
+		held_bc->channel = 0;/* A held call does not have a channel anymore. */
+		held_bc->channel_preselected = 0;
+		held_bc->channel_found = 0;
+		bc_state_change(held_bc, BCHAN_CLEANED);
+		stack_holder_add(stack, held_bc);
+	
+		/* kill the bridge and clean the real b-channel record */
 		if (stack->nt) {
 			int channel;
 			if (bc->bc_state == BCHAN_BRIDGED) {
@@ -3471,9 +3464,7 @@
 
 			bc->in_use=0;	
 		}
-		
-	}
-	break;
+		break;
 
 	/* finishing the channel eh ? */
 	case EVENT_DISCONNECT:
@@ -4393,28 +4384,6 @@
 	}
 }
 
-struct misdn_bchannel *stack_holder_find_bychan(struct misdn_stack *stack, int chan)
-{
-	struct misdn_bchannel *help;
-
-	cb_log(4,stack?stack->port:0, "*HOLDER: find_bychan %c\n", chan);
-	
-	if (!stack) return NULL;
-	
-	for (help=stack->holding;
-	     help;
-	     help=help->next) {
-		if (help->channel == chan) {
-			cb_log(4,stack->port, "*HOLDER: found_bychan bc\n");
-			return help;
-		}
-	}
-
-	cb_log(4,stack->port, "*HOLDER: find_bychan nothing\n");
-	return NULL;
-
-}
-
 struct misdn_bchannel *stack_holder_find(struct misdn_stack *stack, unsigned long l3id)
 {
 	struct misdn_bchannel *help;
@@ -4436,7 +4405,29 @@
 	return NULL;
 }
 
-
+/*!
+ * \brief Find a held call's B channel record.
+ *
+ * \param port Port the call is on.
+ * \param l3_id mISDN Layer 3 ID of held call.
+ *
+ * \return Found bc-record or NULL.
+ */
+struct misdn_bchannel *misdn_lib_find_held_bc(int port, int l3_id)
+{
+	struct misdn_bchannel *bc;
+	struct misdn_stack *stack;
+
+	bc = NULL;
+	for (stack = get_misdn_stack(); stack; stack = stack->next) {
+		if (stack->port == port) {
+			bc = stack_holder_find(stack, l3_id);
+			break;
+		}
+	}
+
+	return bc;
+}
 
 void misdn_lib_send_tone(struct misdn_bchannel *bc, enum tone_e tone) 
 {

Modified: team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.h
URL: http://svn.asterisk.org/svn-view/asterisk/team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.h?view=diff&rev=205976&r1=205975&r2=205976
==============================================================================
--- team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.h (original)
+++ team/rmudgett/misdn_xfer_v14/channels/misdn/isdn_lib.h Fri Jul 10 15:11:28 2009
@@ -593,8 +593,6 @@
 
 char *manager_isdn_get_info(enum event_e event);
 
-void misdn_lib_transfer(struct misdn_bchannel* holded_bc);
-
 struct misdn_bchannel* misdn_lib_get_free_bc(int port, int channel, int inout, int dec);
 
 void manager_bchannel_activate(struct misdn_bchannel *bc);
@@ -629,6 +627,7 @@
 
 int misdn_lib_maxports_get(void) ;
 
+struct misdn_bchannel *misdn_lib_find_held_bc(int port, int l3_id);
 void misdn_lib_release(struct misdn_bchannel *bc);
 
 int misdn_cap_is_speech(int cap);




More information about the svn-commits mailing list