This allows to connect together two call via ISDN phone's menu.
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
/* 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;
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");
}
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;
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");
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;
}
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;
}
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';
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;
}
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;
}
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;
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;
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;
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;
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);
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;
}
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;
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;
#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
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;
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;
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;
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;
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);
/* 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;
}
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;
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;
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 */
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");
}
}
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 */
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;
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 */
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 */
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;
}
}
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;
}
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;
}
/* 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;
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;
/* 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;
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;
}
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) {
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;
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;
}
}
-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;
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);
}
/* 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);
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);
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:
;
}
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)
{
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;
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;
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);
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);
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) */
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 */
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 */
};