aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authorrmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b>2009-07-14 18:17:15 +0000
committerrmudgett <rmudgett@f38db490-d61c-443f-a65b-d21fe96a405b>2009-07-14 18:17:15 +0000
commit761a24f453980947dc9b3a76465bb7522b56442e (patch)
tree9a2c3ad985d0a564a7fee85b5c2a567c66575b84 /channels
parentb55009c7d99a9ed775b2820506d6bc487bc43ba8 (diff)
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 ........ ................ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.0@206555 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_misdn.c720
-rw-r--r--channels/misdn/isdn_lib.c81
-rw-r--r--channels/misdn/isdn_lib.h3
3 files changed, 461 insertions, 343 deletions
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 45b1b631c..57d6ee421 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -126,30 +126,32 @@ enum misdn_chan_state {
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 chan_list {
struct misdn_bchannel *bc;
/*!
- * \brief HOLDED channel information
+ * \brief HELD channel call information
*/
- struct hold_info hold_info;
+ struct hold_info hold;
- /*!
- * \brief From associated B channel: Layer 3 process ID
- * \note Used to find the HOLDED channel call record when retrieving a call.
+ /*!
+ * \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 void chan_misdn_log(int level, int port, char *tmpl, ...)
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 struct chan_list *find_chan_by_pid(struct chan_list *list, int pid);
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 @@ static struct state_struct state_array[] = {
{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 @@ static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, st
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 @@ static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, st
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 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
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 @@ static int misdn_indication(struct ast_channel *ast, int cond, const void *data,
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_indication(struct ast_channel *ast, int cond, const void *data,
static int misdn_hangup(struct ast_channel *ast)
{
struct chan_list *p;
- struct misdn_bchannel *bc = NULL;
- const char *varcause = NULL;
-
- ast_debug(1, "misdn_hangup(%s)\n", ast->name);
-
- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) ) ) return -1;
+ struct misdn_bchannel *bc;
+ const char *var;
- if (!p) {
- chan_misdn_log(3, 0, "misdn_hangup called, without chan_list obj.\n");
- return 0 ;
+ if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
+ return -1;
}
+ MISDN_ASTERISK_TECH_PVT(ast) = NULL;
- bc = p->bc;
+ ast_debug(1, "misdn_hangup(%s)\n", ast->name);
- 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);
+ 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;
}
}
- 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 (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:
- 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
- * */
+ /*
+ * 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);
- misdn_lib_send_event( bc, EVENT_RELEASE_COMPLETE);
- break;
- case MISDN_HOLDED:
+ release_chan(p, bc);
+ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+ return 0;
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 (p->hold.state == MISDN_HOLD_IDLE) {
+ start_bc_tones(p);
+ hanguptone_indicate(p);
+ }
+
+ p->state = MISDN_CLEANING;
+ 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 = 8;
+ bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
+ }
+ if (bc->need_disconnect) {
+ misdn_lib_send_event(bc, EVENT_DISCONNECT);
}
- if (bc->need_disconnect)
- misdn_lib_send_event( bc, EVENT_DISCONNECT);
-
- /*p->state=MISDN_CLEANING;*/
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;
}
@@ -3004,7 +3001,7 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
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 @@ static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
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 @@ static int dialtone_indicate(struct chan_list *cl)
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)
@@ -3738,39 +3734,72 @@ static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid)
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)
{
chan_misdn_log(4, chan->bc ? chan->bc->port : 0, "* Queuing chan %p\n", chan);
@@ -3834,23 +3863,26 @@ static int pbx_start_chan(struct chan_list *ch)
return ret;
}
-static void hangup_chan(struct chan_list *ch)
+static void hangup_chan(struct chan_list *ch, struct misdn_bchannel *bc)
{
- int port = ch ? (ch->bc ? ch->bc->port : 0) : 0;
+ 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;
}
@@ -3860,97 +3892,185 @@ static void hangup_chan(struct chan_list *ch)
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;
- }
+ cl_dequeue_chan(&cl_te, ch);
- chan_misdn_log(5, bc->port, "release_chan: bc with l3id: %x\n", bc->l3_id);
+ 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");
+ /* 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->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->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);
}
+ }
- if (ch) {
- close(ch->pipe[0]);
- close(ch->pipe[1]);
+ ast_free(ch);
- 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;
+ ast_mutex_unlock(&release_lock);
+}
- if (ast->_state != AST_STATE_RESERVED) {
- chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
- ast_setstate(ast, AST_STATE_DOWN);
- }
- }
+/*!
+ * \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;
- cl_dequeue_chan(&cl_te, ch);
+ ch->state = MISDN_CLEANING;
- ast_free(ch);
+ 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 {
- /* chan is already cleaned, so exiting */
+ --misdn_in_calls[ch->hold.port];
}
+ }
+
+ close(ch->pipe[0]);
+ close(ch->pipe[1]);
- ast_mutex_unlock(&release_lock);
+ ast = ch->ast;
+ if (ast) {
+ MISDN_ASTERISK_TECH_PVT(ast) = NULL;
+ if (ast->_state != AST_STATE_RESERVED) {
+ ast_setstate(ast, AST_STATE_DOWN);
+ }
}
-/*** release end **/
+
+ ast_free(ch);
+
+ ast_mutex_unlock(&release_lock);
}
-static void misdn_transfer_bc(struct chan_list *tmp_ch, struct chan_list *holded_chan)
+/*!
+ * \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)
{
- chan_misdn_log(4, 0, "TRANSFERRING %s to %s\n", holded_chan->ast->name, tmp_ch->ast->name);
+ 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;
+ }
- tmp_ch->state = MISDN_HOLD_DISCONNECT;
+ 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;
- ast_moh_stop(ast_bridged_channel(holded_chan->ast));
+ 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;
+ }
- holded_chan->state=MISDN_CONNECTED;
- /* misdn_lib_transfer(holded_chan->bc); */
- ast_channel_masquerade(holded_chan->ast, ast_bridged_channel(tmp_ch->ast));
+ return retval;
}
@@ -3986,7 +4106,7 @@ static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch,
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)
@@ -4161,7 +4281,7 @@ int add_out_calls(int port)
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);
@@ -4185,6 +4305,7 @@ static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, str
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 */
@@ -4203,14 +4324,13 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
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:
case EVENT_BCHAN_DATA:
@@ -4268,7 +4388,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
case EVENT_NEW_BC:
if (!ch) {
- ch = find_holded(cl_te,bc);
+ ch = find_hold_call(cl_te,bc);
}
if (!ch) {
@@ -4326,12 +4446,12 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
/* 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;
}
@@ -4582,11 +4702,11 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
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;
}
@@ -4834,8 +4954,6 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
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
@@ -4857,23 +4975,34 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
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);
+ 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)
@@ -4881,29 +5010,41 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
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:
{
@@ -4917,8 +5058,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
break;
}
- hangup_chan(ch);
- release_chan(bc);
+ hangup_chan(ch, bc);
+ release_chan(ch, bc);
}
break;
@@ -5004,8 +5145,8 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
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");
@@ -5065,70 +5206,57 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
/** 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;
+ 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*/
+ /* remember the channel again */
ch->bc = bc;
- ch->state = MISDN_CONNECTED;
- ch->hold_info.port = 0;
- ch->hold_info.channel = 0;
+ ch->hold.state = MISDN_HOLD_IDLE;
+ ch->hold.port = 0;
+ ch->hold.channel = 0;
- hold_ast = ast_bridged_channel(ch->ast);
-
- if (hold_ast) {
- ast_moh_stop(hold_ast);
- }
+ 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;
-
- 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*/
+ /* forget the channel now */
ch->bc = NULL;
- ch->hold_info.port = bc->port;
- ch->hold_info.channel = bc->channel;
+ 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);
} else {
misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
@@ -5194,7 +5322,7 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
if (!bc->dummy) {
stop_bc_tones(ch);
- release_chan(bc);
+ release_chan(ch, bc);
}
break;
diff --git a/channels/misdn/isdn_lib.c b/channels/misdn/isdn_lib.c
index c833fc2ef..1f6bbd900 100644
--- a/channels/misdn/isdn_lib.c
+++ b/channels/misdn/isdn_lib.c
@@ -222,8 +222,6 @@ struct misdn_bchannel *find_bc_by_l3id(struct misdn_stack *stack, unsigned long
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);
int manager_isdn_handler(iframe_t *frm ,msg_t *msg);
@@ -3106,13 +3104,6 @@ void te_lib_destroy(int midev)
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 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
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 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
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);
+ /* 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 bchannel*/
+ /* 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 @@ int misdn_lib_send_event(struct misdn_bchannel *bc, enum event_e event )
bc->in_use=0;
}
-
- }
- break;
+ break;
/* finishing the channel eh ? */
case EVENT_DISCONNECT:
@@ -4382,28 +4373,6 @@ void stack_holder_remove(struct misdn_stack *stack, struct misdn_bchannel *holde
}
}
-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 @@ struct misdn_bchannel *stack_holder_find(struct misdn_stack *stack, unsigned lon
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)
{
diff --git a/channels/misdn/isdn_lib.h b/channels/misdn/isdn_lib.h
index 3ea5385d0..24c1b442a 100644
--- a/channels/misdn/isdn_lib.h
+++ b/channels/misdn/isdn_lib.h
@@ -405,8 +405,6 @@ void misdn_lib_log_ies(struct misdn_bchannel *bc);
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_get_port_up (int port) ;
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);