[svn-commits] rmudgett: branch 1.6.1 r206558 - in /branches/1.6.1: ./ channels/ channels/mi...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 14 13:32:25 CDT 2009


Author: rmudgett
Date: Tue Jul 14 13:32:20 2009
New Revision: 206558

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=206558
Log:
Merged revisions 206489 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

................
  r206489 | rmudgett | 2009-07-14 12:01:48 -0500 (Tue, 14 Jul 2009) | 35 lines
  
  Merged revisions 206487 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r206487 | rmudgett | 2009-07-14 11:44:47 -0500 (Tue, 14 Jul 2009) | 28 lines
    
    Fixes several call transfer issues with chan_misdn.
    
    *  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.
    
    *  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.
    
    *  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.
    
    *  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.
    
    (closes issue #14355)
    (closes issue #14692)
    Reported by: sodom
    Patches:
          misdn_xfer_v14_r205839.patch uploaded by rmudgett (license 664)
    Tested by: rmudgett
  ........
................

Modified:
    branches/1.6.1/   (props changed)
    branches/1.6.1/channels/chan_misdn.c
    branches/1.6.1/channels/misdn/isdn_lib.c
    branches/1.6.1/channels/misdn/isdn_lib.h

Propchange: branches/1.6.1/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.1/channels/chan_misdn.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/channels/chan_misdn.c?view=diff&rev=206558&r1=206557&r2=206558
==============================================================================
--- branches/1.6.1/channels/chan_misdn.c (original)
+++ branches/1.6.1/channels/chan_misdn.c Tue Jul 14 13:32:20 2009
@@ -126,30 +126,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;
@@ -313,13 +315,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;
 
@@ -482,7 +484,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
@@ -528,12 +529,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);
@@ -1294,15 +1296,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) 
@@ -1461,8 +1456,8 @@
 		if (bc) {
 			print_bc_info(a->fd, help, bc);
 		} else {
-			if (help->state == MISDN_HOLDED) {
-				ast_cli(a->fd, "ITS A HOLDED BC:\n");
+			if (help->hold.state != MISDN_HOLD_IDLE) {
+				ast_cli(a->fd, "ITS A HELD CALL BC:\n");
 				ast_cli(a->fd, " --> l3_id: %x\n"
 						" --> dad:%s oad:%s\n"
 						" --> hold_port: %d\n"
@@ -1470,8 +1465,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(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num);
@@ -2631,13 +2626,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:
@@ -2738,6 +2739,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;
@@ -2746,173 +2748,168 @@
 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_debug(1, "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_debug(1, "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]);
-		ast_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 a lot of trouble.
+		 */
+		ast_log(LOG_NOTICE, "release channel, in INCOMING_SETUP state.. no other events happened\n");
+		release_chan(p, bc);
+		misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+		return 0;
+	case MISDN_DIALING:
+		if (p->hold.state == MISDN_HOLD_IDLE) {
+			start_bc_tones(p);
+			hanguptone_indicate(p);
+		}
+
 		p->state = MISDN_CLEANING;
-		/* This is the only place in misdn_hangup, where we 
-		 * can call release_chan, else it might create lot's of trouble
-		 * */
-		ast_log(LOG_NOTICE, "release channel, in INCOMING_SETUP state.. no other events happened\n");
-		release_chan(bc);
-		misdn_lib_send_event( bc, EVENT_RELEASE_COMPLETE);
-		break;
-	case MISDN_HOLDED:
-	case MISDN_DIALING:
-		start_bc_tones(p);
-		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_CALLING_ACKNOWLEDGE:
-		start_bc_tones(p);
-		hanguptone_indicate(p);
-		
-		if (bc->need_disconnect)
-			misdn_lib_send_event( bc, EVENT_DISCONNECT);
-		break;
-      
+		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 = 8;
-		}
-		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; */
-		break;
-
-	case MISDN_RELEASED:
+		if (bc->need_release) {
+			misdn_lib_send_event(bc, EVENT_RELEASE);
+		}
+		break;
+
 	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;
 }
@@ -3004,7 +3001,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;
 	}
@@ -3088,8 +3085,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;
 	}
 	
@@ -3320,10 +3317,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)
@@ -3742,38 +3738,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)
 {
@@ -3838,23 +3867,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;
 	}
 
@@ -3864,97 +3896,185 @@
 
 	ch->need_queue_hangup = 0;
 	if (ch->ast) {
-		send_cause2ast(ch->ast, ch->bc, ch);
-
-		if (ch->ast)
-			ast_queue_hangup_with_cause(ch->ast, ch->bc->cause);
+		send_cause2ast(ch->ast, bc, ch);
+		ast_queue_hangup_with_cause(ch->ast, bc->cause);
 		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);
+		}
+	}
+
+	ast_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);
-
-			ast_free(ch);
-		} else {
-			/* chan is already cleaned, so exiting  */
-		}
-
-		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));
+			--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);
+		}
+	}
+
+	ast_free(ch);
+
+	ast_mutex_unlock(&release_lock);
+}
+
+/*!
+ * \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;
 }
 
 
@@ -3990,7 +4110,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)
@@ -4165,7 +4285,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);
@@ -4189,6 +4309,7 @@
 static enum event_response_e
 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
 {
+	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 */
@@ -4207,13 +4328,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:
@@ -4272,7 +4392,7 @@
 
 	case EVENT_NEW_BC:
 		if (!ch) {
-			ch = find_holded(cl_te,bc);
+			ch = find_hold_call(cl_te,bc);
 		}
 		
 		if (!ch) {
@@ -4330,12 +4450,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;
 				}
@@ -4586,11 +4706,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;
 			}
@@ -4838,8 +4958,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
@@ -4861,23 +4979,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);
+
+			/* 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);
 			}
-
-			bc->need_disconnect = 0;
-
-			stop_bc_tones(ch);
-			hangup_chan(ch);
-#if 0
 		} else {
-			ch = find_holded_l3(cl_te, bc->l3_id,1);
-			if (ch) {
-				hangup_chan(ch);
+			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) */
 			}
-#endif
 		}
 		bc->out_cause = -1;
 		if (bc->need_release)
@@ -4885,29 +5014,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:
 	{
@@ -4921,8 +5062,8 @@
 			break;
 		}
 		
-		hangup_chan(ch);
-		release_chan(bc);
+		hangup_chan(ch, bc);
+		release_chan(ch, bc);
 	}
 	break;
 
@@ -5008,8 +5149,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");
@@ -5069,70 +5210,57 @@
 	/** 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:
 	{
 		int hold_allowed;
-		struct ast_channel *bridged = ast_bridged_channel(ch->ast);
+		struct ast_channel *bridged;
 
 		misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(hold_allowed));
-
 		if (!hold_allowed) {
-
 			chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n");
 			misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
 			break;
 		}
 
+		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");
@@ -5198,7 +5326,7 @@
 
 		if (!bc->dummy) {
 			stop_bc_tones(ch);
-			release_chan(bc);
+			release_chan(ch, bc);
 		}
 		break;
 

Modified: branches/1.6.1/channels/misdn/isdn_lib.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/channels/misdn/isdn_lib.c?view=diff&rev=206558&r1=206557&r2=206558
==============================================================================
--- branches/1.6.1/channels/misdn/isdn_lib.c (original)
+++ branches/1.6.1/channels/misdn/isdn_lib.c Tue Jul 14 13:32:20 2009
@@ -221,8 +221,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);
 
@@ -3106,13 +3104,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;
@@ -3331,6 +3322,7 @@
 	msg_t *msg; 
 	int retval=0;
 	struct misdn_stack *stack;
+	struct misdn_bchannel *held_bc;
   
 	if (!bc) RETURN(-1,OUT_POST_UNLOCK);
 	
@@ -3417,21 +3409,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) {
@@ -3456,9 +3449,7 @@
 
 			bc->in_use=0;	
 		}
-		
-	}
-	break;
+		break;
 
 	/* finishing the channel eh ? */
 	case EVENT_DISCONNECT:
@@ -4382,28 +4373,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;
@@ -4425,7 +4394,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: branches/1.6.1/channels/misdn/isdn_lib.h
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/channels/misdn/isdn_lib.h?view=diff&rev=206558&r1=206557&r2=206558
==============================================================================
--- branches/1.6.1/channels/misdn/isdn_lib.h (original)
+++ branches/1.6.1/channels/misdn/isdn_lib.h Tue Jul 14 13:32:20 2009
@@ -405,8 +405,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);
@@ -442,6 +440,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