From bed1db51a808a4cd3774c8367a790f7331198dcb Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Tue, 17 Sep 2013 12:48:23 +0200 Subject: [PATCH] Add ECT (Call Forwarding) facility message handling This allows to connect together two call via ISDN phone's menu. --- action.cpp | 66 +++++++++++++++--------------- action_vbox.cpp | 2 +- apppbx.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++++++---------- apppbx.h | 4 +- dss1.cpp | 52 ++++++++++++++++++++++++ dss1.h | 2 + message.h | 7 ++++ 7 files changed, 198 insertions(+), 58 deletions(-) diff --git a/action.cpp b/action.cpp index 5b332c9..b42e301 100644 --- a/action.cpp +++ b/action.cpp @@ -112,7 +112,7 @@ void EndpointAppPBX::action_dialing_internal(void) end_trace(); release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_86"); return; } @@ -123,7 +123,7 @@ void EndpointAppPBX::action_dialing_internal(void) end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0); - message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_81"); return; } @@ -257,7 +257,7 @@ void EndpointAppPBX::action_dialing_external(void) release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0); set_tone(portlist, "cause_82"); denied: - message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); return; } @@ -324,7 +324,7 @@ void EndpointAppPBX::action_dialing_vbox_record(void) end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); return; } @@ -335,7 +335,7 @@ void EndpointAppPBX::action_dialing_vbox_record(void) add_trace("extension", NULL, "%s", rparam->string_value); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_86"); return; } @@ -345,7 +345,7 @@ void EndpointAppPBX::action_dialing_vbox_record(void) trace_header("ACTION vbox-record (internal calls are denied)", DIRECTION_NONE); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_81"); return; } @@ -402,7 +402,7 @@ void EndpointAppPBX::action_init_partyline(void) end_trace(); noroom: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); return; } @@ -500,7 +500,7 @@ void EndpointAppPBX::action_dialing_login(void) end_trace(); /* extension doesn't exist */ new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_86"); return; } @@ -591,7 +591,7 @@ void EndpointAppPBX::action_init_change_callerid(void) /* service not available */ trace_header("ACTION change-callerid (denied for this caller)", DIRECTION_NONE); end_trace(); - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); set_tone(portlist,"cause_87"); return; @@ -681,7 +681,7 @@ void EndpointAppPBX::_action_callerid_calleridnext(int next) add_trace("new", "caller id", "%s", numberrize_callerinfo(new_id, new_type, options.national, options.international)); add_trace("new", "present", "%s", (new_present==INFO_PRESENT_RESTRICTED)?"restricted":"allowed"); end_trace(); - message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); set_tone(portlist,"activated"); } @@ -712,7 +712,7 @@ void EndpointAppPBX::action_init_change_forward(void) trace_header("ACTION change-forward (denied for this caller)", DIRECTION_NONE); end_trace(); /* service not available */ - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); set_tone(portlist,"cause_87"); return; @@ -776,7 +776,7 @@ void EndpointAppPBX::action_dialing_forward(void) write_extension(&e_ext, e_ext.number); } /* function (de)activated */ - message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); if (dest[0]) set_tone(portlist,"activated"); @@ -796,7 +796,7 @@ void EndpointAppPBX::action_init_redial_reply(void) trace_header("ACTION redial/reply (no last number stored)", DIRECTION_NONE); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); return; } @@ -910,7 +910,7 @@ void EndpointAppPBX::action_dialing_powerdial(void) trace_header("ACTION powerdial (no last number stored)", DIRECTION_NONE); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); return; } @@ -976,7 +976,7 @@ void EndpointAppPBX::action_dialing_callback(void) disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; e_cbcaller[0] = e_cbdialing[0] = '\0'; @@ -1076,7 +1076,7 @@ void EndpointAppPBX::action_dialing_abbrev(void) trace_header("ACTION abbreviation (only for extension)", DIRECTION_NONE); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); return; } @@ -1091,7 +1091,7 @@ void EndpointAppPBX::action_dialing_abbrev(void) add_trace("abbrev", NULL, "%s", abbrev); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_01"); return; } @@ -1246,7 +1246,7 @@ void EndpointAppPBX::action_dialing_test(void) end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); SPRINT(causestr,"cause_%02x",cause); - message_disconnect_port(portlist, cause, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, cause, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, causestr); break; @@ -1256,7 +1256,7 @@ void EndpointAppPBX::action_dialing_test(void) add_trace("cause", NULL, "16"); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "release"); break; @@ -1297,7 +1297,7 @@ void EndpointAppPBX::action_init_play(void) disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; return; @@ -1569,7 +1569,7 @@ void EndpointAppPBX::_action_goto_menu(int mode) disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; return; @@ -1682,7 +1682,7 @@ void EndpointAppPBX::action_dialing_disconnect(void) new_state(EPOINT_STATE_OUT_DISCONNECT); set_tone(portlist, cause_string); if (!(rparam = routeparam(e_action, PARAM_CONNECT))) { - message_disconnect_port(portlist, cause, location, display); + message_disconnect_port(portlist, cause, location, display, NULL); } else { message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY); SCPY(message->param.notifyinfo.display, display); @@ -2019,7 +2019,7 @@ void EndpointAppPBX::action_dialing_password(void) e_connectedmode = 0; e_dtmf = 0; new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_10"); return; } @@ -2069,7 +2069,7 @@ void EndpointAppPBX::action_init_pots_retrieve(void) disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; return; @@ -2138,7 +2138,7 @@ void EndpointAppPBX::action_init_pots_release(void) disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; return; @@ -2176,7 +2176,7 @@ void EndpointAppPBX::action_init_pots_release(void) #if 0 /* disconnect our call */ new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "hangup"); e_action = NULL; #endif @@ -2208,7 +2208,7 @@ void EndpointAppPBX::action_init_pots_reject(void) end_trace(); disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; return; @@ -2259,7 +2259,7 @@ void EndpointAppPBX::action_init_pots_answer(void) end_trace(); disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; return; @@ -2312,7 +2312,7 @@ void EndpointAppPBX::action_init_pots_3pty(void) end_trace(); disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; return; @@ -2390,7 +2390,7 @@ void EndpointAppPBX::action_init_pots_transfer(void) disconnect: new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); e_action = NULL; return; @@ -2474,7 +2474,7 @@ void EndpointAppPBX::process_dialing(int timeout) add_trace("max-levels", NULL, "%d", RULE_NESTING); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); unsched_timer(&e_action_timeout); unsched_timer(&e_match_timeout); @@ -2501,7 +2501,7 @@ void EndpointAppPBX::process_dialing(int timeout) /* nothing more, so we release */ PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, and we have no next action, so we disconnect.\n", ea_endpoint->ep_serial); new_state(EPOINT_STATE_OUT_DISCONNECT); - message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL); set_tone(portlist, "cause_3f"); goto end; } @@ -2530,7 +2530,7 @@ void EndpointAppPBX::process_dialing(int timeout) goto end; } /* invalid dialing */ - message_disconnect_port(portlist, CAUSE_INCALID, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_INCALID, LOCATION_PRIVATE_LOCAL, "", NULL); message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT); message->param.disconnectinfo.cause = CAUSE_INVALID; message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; diff --git a/action_vbox.cpp b/action_vbox.cpp index 120bfa6..3b222e2 100644 --- a/action_vbox.cpp +++ b/action_vbox.cpp @@ -82,7 +82,7 @@ void EndpointAppPBX::action_init_vbox_play(void) SCPY(e_vbox, rparam->string_value); if (e_vbox[0] == '\0') { /* facility rejected */ - message_disconnect_port(portlist, CAUSE_FACILITYREJECTED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_FACILITYREJECTED, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); set_tone(portlist,"cause_22"); return; diff --git a/apppbx.cpp b/apppbx.cpp index 9752b87..9f2b2e0 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -522,7 +522,7 @@ void EndpointAppPBX::keypad_function(char digit) if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS) join_join_fxs(); else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1) - join_join_dss1(); + join_join_dss1(-1); break; /* VOOTP on */ @@ -1317,7 +1317,7 @@ int password_timeout(struct lcr_timer *timer, void *instance, int index) ea->new_state(EPOINT_STATE_OUT_DISCONNECT); portlist = ea->ea_endpoint->ep_portlist; if (portlist) { - ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL); ea->set_tone(portlist, "cause_10"); } } @@ -1424,7 +1424,7 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un trace_header("EXTENSION (not created)", DIRECTION_IN); add_trace("extension", NULL, "%s", e_ext.number); end_trace(); - message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */ e_ext.number[0] = '\0'; /* no terminal */ @@ -1991,7 +1991,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, if (!read_extension(&e_ext, e_ext.number)) { /* extension doesn't exist */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number); - message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */ return; @@ -2260,7 +2260,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, SCPY(e_tone, cause); while(portlist) { set_tone(portlist, cause); - message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, ""); + message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "", NULL); portlist = portlist->next; } release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ @@ -2389,14 +2389,25 @@ void EndpointAppPBX::port_transfer(struct port_list *portlist, int message_type, logmessage(message_type, param, portlist->port_id, DIRECTION_IN); class Port *port; + struct lcr_msg *message; + int rc; /* bridge for real */ if (!(port = find_port_id(portlist->port_id))) return; if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS) join_join_fxs(); - else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1) - join_join_dss1(); + else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1) { + rc = join_join_dss1(param->transfer.invoke_id); + + if (rc < 0) { + message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TRANSFER); + message->param.transfer.error = 1; + message->param.transfer.invoke_id = param->transfer.invoke_id; + logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); + message_put(message); + } + } } /* port MESSAGE_SUSPEND */ @@ -3020,7 +3031,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter * portlist = ea_endpoint->ep_portlist; while(portlist) { set_tone(portlist, cause); - message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, ""); + message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "", ¶m->disconnectinfo.transfer); portlist = portlist->next; } } @@ -3338,7 +3349,9 @@ void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, uni case MESSAGE_ALERTING: PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received alerting\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id); if (e_state!=EPOINT_STATE_IN_OVERLAP - && e_state!=EPOINT_STATE_IN_PROCEEDING) { + && e_state!=EPOINT_STATE_IN_PROCEEDING + && e_state!=EPOINT_STATE_IN_ALERTING /* second alerting */ + && e_state!=EPOINT_STATE_CONNECT) { /* alerting after transfer */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial); break; } @@ -3553,7 +3566,7 @@ void EndpointAppPBX::pick_join(char *extensions) PDEBUG(DEBUG_EPOINT, "EPOINT(%d) nobody is ringing internally (or we don't have her in the access list), so we disconnect.\n", ea_endpoint->ep_serial); reject: set_tone(ea_endpoint->ep_portlist, "cause_10"); - message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL); new_state(EPOINT_STATE_OUT_DISCONNECT); return; } @@ -3691,7 +3704,7 @@ reject: /* join calls (look for a join that is on hold (same isdn interface/terminal)) */ -int EndpointAppPBX::join_join_dss1(void) +int EndpointAppPBX::join_join_dss1(int invoke_id) { #ifdef WITH_MISDN struct lcr_msg *message; @@ -3699,7 +3712,7 @@ int EndpointAppPBX::join_join_dss1(void) struct join_relation **add_relation_pointer, **remove_relation_pointer; class Join *our_join, *other_join, *add_join, *remove_join; class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx; - class EndpointAppPBX *other_eapp, *remove_eapp; + class EndpointAppPBX *other_eapp, *remove_eapp_hold, *remove_eapp_active; class Port *our_port, *other_port; class Pdss1 *our_pdss1, *other_pdss1; class Endpoint *temp_epoint; @@ -3793,14 +3806,16 @@ int EndpointAppPBX::join_join_dss1(void) /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */ if (our_pdss1->p_m_hold && !other_pdss1->p_m_hold) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) our relation is on hold and other is active, so we move our relations to other relations\n", ea_endpoint->ep_serial); - remove_eapp = this; + remove_eapp_hold = this; + remove_eapp_active = other_eapp; remove_join = our_join; remove_joinpbx = our_joinpbx; add_join = other_join; add_joinpbx = other_joinpbx; } else { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) our relation is active or other is on hold, so we move ohter relations to our relations\n", ea_endpoint->ep_serial); - remove_eapp = other_eapp; + remove_eapp_hold = other_eapp; + remove_eapp_active = this; remove_join = other_join; remove_joinpbx = other_joinpbx; add_join = our_join; @@ -3811,13 +3826,13 @@ int EndpointAppPBX::join_join_dss1(void) remove_relation = remove_joinpbx->j_relation; remove_relation_pointer = &remove_joinpbx->j_relation; while(remove_relation) { - if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) { - /* detach other endpoint */ + if (remove_relation->epoint_id == remove_eapp_hold->ea_endpoint->ep_serial) { + /* detach endpoint on hold */ *remove_relation_pointer = remove_relation->next; FREE(remove_relation, sizeof(struct join_relation)); cmemuse--; remove_relation = *remove_relation_pointer; - remove_eapp->ea_endpoint->ep_join_id = 0; + remove_eapp_hold->ea_endpoint->ep_join_id = 0; continue; } @@ -3831,9 +3846,43 @@ int EndpointAppPBX::join_join_dss1(void) remove_relation_pointer = &remove_relation->next; remove_relation = remove_relation->next; } - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial); + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint (hold) removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial); + + if (invoke_id >= 0) { + /* remove relation to endpoint for active join */ + remove_relation = add_joinpbx->j_relation; + remove_relation_pointer = &add_joinpbx->j_relation; + while(remove_relation) { + if (remove_relation->epoint_id == remove_eapp_active->ea_endpoint->ep_serial) { + /* detach active endpoint */ + *remove_relation_pointer = remove_relation->next; + FREE(remove_relation, sizeof(struct join_relation)); + cmemuse--; + remove_relation = *remove_relation_pointer; + remove_eapp_active->ea_endpoint->ep_join_id = 0; + continue; + } - /* join call relations */ + remove_relation_pointer = &remove_relation->next; + remove_relation = remove_relation->next; + } + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint (active) removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial); + + /* if active endpoint is in alerting state, send alerting message to join */ + if (remove_eapp_active->e_state == EPOINT_STATE_IN_ALERTING) { + if (add_joinpbx->j_relation && !add_joinpbx->j_relation->next) { + /* if channel state indicateds "audio" (1), we tell the other endpoint that patterns are available */ + if (add_joinpbx->j_relation->channel_state) { + message = message_create(add_joinpbx->j_relation->epoint_id, add_join->j_serial, EPOINT_TO_JOIN, MESSAGE_PATTERN); + message_put(message); + } + message = message_create(add_joinpbx->j_relation->epoint_id, add_join->j_serial, EPOINT_TO_JOIN, MESSAGE_ALERTING); + message_put(message); + } + } + } + + /* join call relations: we add the members of the join on hold to the active join */ add_relation = add_joinpbx->j_relation; add_relation_pointer = &add_joinpbx->j_relation; while(add_relation) { @@ -3844,12 +3893,32 @@ int EndpointAppPBX::join_join_dss1(void) remove_joinpbx->j_relation = NULL; PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial); - /* release endpoint */ - message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE); + /* release endpoint on hold */ + message = message_create(remove_joinpbx->j_serial, remove_eapp_hold->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE); message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + if (invoke_id >= 0) { + /* send the result with disconnect message to the invoking endpoint */ + if (remove_eapp_hold->ea_endpoint->ep_serial == ea_endpoint->ep_serial) { + message->param.disconnectinfo.transfer.result = 1; + message->param.disconnectinfo.transfer.invoke_id = invoke_id; + } + } message_put(message); + if (invoke_id >= 0) { + /* release active endpoint */ + message = message_create(add_joinpbx->j_serial, remove_eapp_active->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE); + message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */ + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + /* send the result with disconnect message to the invoking endpoint */ + if (remove_eapp_active->ea_endpoint->ep_serial == ea_endpoint->ep_serial) { + message->param.disconnectinfo.transfer.result = 1; + message->param.disconnectinfo.transfer.invoke_id = invoke_id; + } + message_put(message); + } + /* if we are not a partyline, we get partyline state from other join */ add_joinpbx->j_partyline += remove_joinpbx->j_partyline; @@ -4874,6 +4943,13 @@ void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsign case MESSAGE_TRANSFER: trace_header("TRANSFER", dir); + if (param->transfer.invoke) + add_trace("action", NULL, "invoke"); + if (param->transfer.result) + add_trace("action", NULL, "result"); + if (param->transfer.error) + add_trace("action", NULL, "error"); + add_trace("invoke-id", NULL, "%d", param->transfer.invoke_id); end_trace(); break; @@ -4906,7 +4982,7 @@ void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsign } } -void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display) +void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display, const struct param_transfer *transfer) { struct lcr_msg *message; @@ -4930,6 +5006,9 @@ void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cau else SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause)); } + if (transfer) { + memcpy(&message->param.disconnectinfo.transfer, transfer, sizeof(struct param_transfer)); + } message_put(message); logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); } diff --git a/apppbx.h b/apppbx.h index 618d9ac..068f2e5 100644 --- a/apppbx.h +++ b/apppbx.h @@ -323,7 +323,7 @@ class EndpointAppPBX : public EndpointApp /* facility function */ void pick_join(char *extension); - int join_join_dss1(void); + int join_join_dss1(int invoke_id); int join_join_fxs(void); int join_3pty_dss1(void); int join_3pty_fxs(void); @@ -373,7 +373,7 @@ class EndpointAppPBX : public EndpointApp void cryptman_timeout(int secs); int vootp_on(int enable); - void message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display); + void message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display, const struct param_transfer *transfer); void logmessage(int message_type, union parameter *param, unsigned int port_id, int dir); void trace_header(const char *name, int direction); diff --git a/dss1.cpp b/dss1.cpp index 43452bb..f2c2ba5 100644 --- a/dss1.cpp +++ b/dss1.cpp @@ -1675,6 +1675,13 @@ void Pdss1::facility_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m) message->param.threepty.invoke_id = fac.u.inv.invokeId; message_put(message); return; + + case Fac_EctExecute: + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TRANSFER); + message->param.transfer.invoke = 1; + message->param.transfer.invoke_id = fac.u.inv.invokeId; + message_put(message); + return; default: ; } @@ -2348,6 +2355,43 @@ void Pdss1::message_3pty(unsigned int epoint_id, int message_id, union parameter p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_FACILITY, p_m_d_l3id, l3m); } +void Pdss1::enc_ie_facility_ect(l3_msg *l3m, struct param_transfer *transfer) +{ + unsigned char fac_ie[256]; + struct asn1_parm fac; + + /* encode ECT facility */ + memset(&fac, 0, sizeof(fac)); + fac.Valid = 1; + if (transfer->result) { + fac.comp = CompReturnResult; + fac.u.retResult.invokeId = transfer->invoke_id; + fac.u.retResult.operationValuePresent = 1; + fac.u.retResult.operationValue = Fac_EctExecute; + } + if (transfer->error) { + fac.comp = CompReturnError; + fac.u.retError.invokeId = transfer->invoke_id; + fac.u.retError.errorValue = FacError_Gen_InvalidCallState; + } + encodeFac(fac_ie, &fac); + + enc_ie_facility(l3m, fac_ie + 2, fac_ie[1]); +} + +/* MESSAGE_TRANSFER */ +void Pdss1::message_transfer(unsigned int epoint_id, int message_id, union parameter *param) +{ + l3_msg *l3m; + + /* sending facility */ + l3m = create_l3msg(); + l1l2l3_trace_header(p_m_mISDNport, this, L3_FACILITY_REQ, DIRECTION_OUT); + enc_ie_facility_ect(l3m, ¶m->transfer); + end_trace(); + p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_FACILITY, p_m_d_l3id, l3m); +} + /* MESSAGE_NOTIFY */ void Pdss1::message_notify(unsigned int epoint_id, int message_id, union parameter *param) { @@ -2689,6 +2733,10 @@ if (/* ||*/ p_state==PORT_STATE_OUT_SETUP) { enc_ie_progress(l3m, 0, (p_m_d_ntmode)?1:5, 8); /* send cause */ enc_ie_cause(l3m, (!p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_REMOTE:param->disconnectinfo.location, param->disconnectinfo.cause); + /* send facility */ + if (param->disconnectinfo.transfer.result) { + enc_ie_facility_ect(l3m, ¶m->disconnectinfo.transfer); + } /* send display */ if (param->disconnectinfo.display[0]) p = param->disconnectinfo.display; @@ -2859,6 +2907,10 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete message_3pty(epoint_id, message_id, param); break; + case MESSAGE_TRANSFER: /* begin result message */ + message_transfer(epoint_id, message_id, param); + break; + case MESSAGE_OVERLAP: /* more information is needed */ if (p_state!=PORT_STATE_IN_SETUP) { break; diff --git a/dss1.h b/dss1.h index d9487b3..b6966b2 100644 --- a/dss1.h +++ b/dss1.h @@ -58,6 +58,7 @@ class Pdss1 : public PmISDN void message_notify(unsigned int epoint_id, int message_id, union parameter *param); void message_facility(unsigned int epoint_id, int message_id, union parameter *param); void message_3pty(unsigned int epoint_id, int message_id, union parameter *param); + void message_transfer(unsigned int epoint_id, int message_id, union parameter *param); void message_overlap(unsigned int epoint_id, int message_id, union parameter *param); void message_proceeding(unsigned int epoint_id, int message_id, union parameter *param); void message_alerting(unsigned int epoint_id, int message_id, union parameter *param); @@ -99,6 +100,7 @@ class Pdss1 : public PmISDN void dec_ie_redir_dn(struct l3_msg *l3m, int *type, int *plan, int *present, unsigned char *number, int number_len); void enc_ie_facility(struct l3_msg *l3m, unsigned char *facility, int facility_len); void dec_ie_facility(struct l3_msg *l3m, unsigned char *facility, int *facility_len); + void enc_ie_facility_ect(l3_msg *l3m, struct param_transfer *transfer); void dec_facility_centrex(struct l3_msg *l3m, unsigned char *cnip, int cnip_len); void enc_ie_useruser(struct l3_msg *l3m, int protocol, unsigned char *user, int user_len); void dec_ie_useruser(struct l3_msg *l3m, int *protocol, unsigned char *user, int *user_len); diff --git a/message.h b/message.h index 47952ac..fb11384 100644 --- a/message.h +++ b/message.h @@ -156,6 +156,11 @@ struct rtp_info { unsigned short port; /* peer's port */ }; +struct param_transfer { + int invoke, result, error; + unsigned char invoke_id; +}; + /* call-info structure CALLER */ struct caller_info { char id[32]; /* id of caller (user number) */ @@ -210,6 +215,7 @@ struct disconnect_info { int location; /* disconnect location */ char display[84]; /* optional display information */ int force; /* special flag to release imediately */ + struct param_transfer transfer; /* used to return result to the invoking endpoint */ }; /* call-info structure REDIR */ @@ -392,6 +398,7 @@ union parameter { struct param_traffic traffic; /* MESSAGE_TRAFFIC */ struct param_3pty threepty; /* MESSAGE_TRAFFIC */ struct param_dov dov; /* MESSAGE_DOV */ + struct param_transfer transfer; /* MESSAGE_TRANSFER (ECT in case of ISDN) */ unsigned int queue; /* MESSAGE_DISABLE_DEJITTER */ struct param_vootp vootp; /* MESSAGE_VOOTP */ }; -- 2.13.6