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 */
+ case '1':
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) enable VoOTP.\n", ea_endpoint->ep_serial);
+ vootp_on(1);
+ break;
+
+ /* VOOTP off */
+ case '2':
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) disable VoOTP.\n", ea_endpoint->ep_serial);
+ vootp_on(0);
break;
#ifdef WITH_CRYPT
encrypt_off();
break;
#endif
-
default:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
}
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");
}
}
/* screen incoming caller id */
if (e_callerinfo.interface[0]) {
do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface);
- do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
- do_screen(0, e_redirinfo.id, sizeof(e_redirinfo.id), &e_redirinfo.ntype, &e_redirinfo.present, e_callerinfo.interface);
+ if (e_callerinfo.id2[0]) do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
+ if (e_redirinfo.id[0]) do_screen(0, e_redirinfo.id, sizeof(e_redirinfo.id), &e_redirinfo.ntype, &e_redirinfo.present, e_callerinfo.interface);
}
/* process extension */
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 */
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
message->param.audiopath = 1;
message_put(message);
+ if (e_ext.dov_ident[0]) {
+ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_REQUEST);
+ SPRINT(message->param.dov.data, "%08x ", lcr_random);
+ SCAT(message->param.dov.data, e_ext.dov_ident);
+ message->param.dov.length = strlen((char *)message->param.dov.data);
+ message->param.dov.type = e_ext.dov_type;
+ message->param.dov.level = e_ext.dov_level;
+ dov_msg_write(&message->param, 1);
+ message_put(message);
+ }
} else if (!e_adminid) {
/* callback */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
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
+ || (port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) {
+ 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 */
message_put(message);
}
+/* port MESSAGE_DOV_INDICATION */
+void EndpointAppPBX::port_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
+{
+ struct lcr_msg *message;
+
+ logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
+
+ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_INDICATION);
+ memcpy(&message->param, param, sizeof(union parameter));
+ message_put(message);
+}
+
+
+/* port MESSAGE_UPDATEBRIDGE */
+void EndpointAppPBX::port_updatebridge(struct port_list *portlist, int message_type, union parameter *param)
+{
+ struct lcr_msg *message;
+
+ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_UPDATEBRIDGE);
+ message_put(message);
+}
+
+
+/* port MESSAGE_VOOTP */
+void EndpointAppPBX::port_vootp(struct port_list *portlist, int message_type, union parameter *param)
+{
+ if (param->vootp.failed)
+ set_tone(ea_endpoint->ep_portlist, "crypt_off");
+}
+
/* port sends message to the endpoint
*/
port_disable_dejitter(portlist, message_type, param);
break;
+ case MESSAGE_UPDATEBRIDGE:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming updatebridge message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ port_updatebridge(portlist, message_type, param);
+ break;
+
+ case MESSAGE_VOOTP:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming vootp message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ port_vootp(portlist, message_type, param);
+ break;
+
+ /* PORT indivated Data-Over-Voice */
+ case MESSAGE_DOV_INDICATION:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') indicates Data-Over-Voice.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ port_dov_indication(portlist, message_type, param);
+ break;
default:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: %d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
message_put(message);
time(&now);
e_start = now;
+
+ /* if the remote answered, we listen to DOV message */
+ if (e_ext.dov_log[0]) {
+ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_LISTEN);
+ message->param.dov.type = e_ext.dov_type;
+ message_put(message);
+ }
}
/* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
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;
}
}
}
}
+/* join MESSAGE_DOV_INDICATION */
+void EndpointAppPBX::join_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
+{
+ dov_msg_write(param, 0);
+}
+
+/* join MESSAGE_DOV_REQUEST */
+void EndpointAppPBX::join_dov_request(struct port_list *portlist, int message_type, union parameter *param)
+{
+ struct lcr_msg *message;
+
+ /* don't send DOV from estension to extension */
+ if (e_ext.number[0])
+ return;
+
+ while(portlist) {
+ message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_REQUEST);
+ memcpy(&message->param, param, sizeof(union parameter));
+ message_put(message);
+ logmessage(message_type, param, portlist->port_id, DIRECTION_OUT);
+ portlist = portlist->next;
+ }
+}
+
+/* join MESSAGE_DOV_LISTEN */
+void EndpointAppPBX::join_dov_listen(struct port_list *portlist, int message_type, union parameter *param)
+{
+ struct lcr_msg *message;
+
+ while(portlist) {
+ message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_LISTEN);
+ memcpy(&message->param, param, sizeof(union parameter));
+ message_put(message);
+ portlist = portlist->next;
+ }
+}
+
/* JOIN sends messages to the endpoint
*/
void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
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;
}
join_disable_dejitter(portlist, message_type, param);
break;
+ /* JOIN sends a Data-Over-Voice message indication */
+ case MESSAGE_DOV_INDICATION:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice indication.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ join_dov_indication(portlist, message_type, param);
+ break;
+
+ /* JOIN sends a Data-Over-Voice message request */
+ case MESSAGE_DOV_REQUEST:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ join_dov_request(portlist, message_type, param);
+ break;
+
+ /* JOIN sends a Data-Over-Voice listen order */
+ case MESSAGE_DOV_LISTEN:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice listen order.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ join_dov_listen(portlist, message_type, param);
+ break;
+
default:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: #%d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
}
class Join *join;
class JoinPBX *joinpbx;
struct join_relation *relation;
- int vbox;
/* find an endpoint that is ringing internally or vbox with higher priority */
- vbox = 0;
found = NULL;
eapp = apppbx_first;
while(eapp) {
if (port->p_type == PORT_TYPE_VBOX_OUT) {
if (match_list(extensions, eapp->e_ext.number)) {
found = eapp;
- vbox = 1;
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))
+/* join calls (look for a join that is on hold (same isdn/gsm 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, *remove_relation;
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;
+#ifdef WITH_MISDN
+ class Pdss1 *our_pdss1 = NULL, *other_pdss1;
+#endif
+#ifdef WITH_GSM_BS
+ class Pgsm_bs *our_gsm_bs = NULL, *other_gsm_bs;
+#endif
class Endpoint *temp_epoint;
/* are we a candidate to join a join? */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
return -1;
}
- if (!e_ext.number[0]) {
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
- return -1;
- }
our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
if (!our_port) {
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
return -1;
}
- if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
- return -1;
- }
- our_pdss1 = (class Pdss1 *)our_port;
+#ifdef WITH_MISDN
+ if ((our_port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1)
+ our_pdss1 = (class Pdss1 *)our_port;
+#endif
+#ifdef WITH_GSM_BS
+ if ((our_port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS)
+ our_gsm_bs = (class Pgsm_bs *)our_port;
+#endif
/* find an endpoint that has the same mISDNport/ces that we are on */
other_eapp = apppbx_first;
continue;
}
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint candiate: (ep%d) terminal='%s' port=%s join=%d.\n", ea_endpoint->ep_serial, other_eapp->ea_endpoint->ep_serial, other_eapp->e_ext.number, (other_eapp->ea_endpoint->ep_portlist)?"YES":"NO", other_eapp->ea_endpoint->ep_join_id);
- if (other_eapp->e_ext.number[0] /* has terminal */
- && other_eapp->ea_endpoint->ep_portlist /* has port */
+ if (other_eapp->ea_endpoint->ep_portlist /* has port */
&& other_eapp->ea_endpoint->ep_join_id) { /* has join */
other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
if (other_port) { /* port still exists */
- if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
- || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
+#ifdef WITH_MISDN
+ if (our_pdss1
+ && (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
+ || other_port->p_type==PORT_TYPE_DSS1_NT_IN)) { /* port is isdn nt-mode */
other_pdss1 = (class Pdss1 *)other_port;
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_m_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
- if (1 //other_pdss1->p_m_hold /* port is on hold */
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
+ if (1 //other_pdss1->p_hold /* port is on hold */
&& other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
&& other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
break;
- } else {
+ } else
+#endif
+#ifdef WITH_GSM_BS
+ if (our_gsm_bs
+ && (other_port->p_type==PORT_TYPE_GSM_BS_OUT
+ || other_port->p_type==PORT_TYPE_GSM_BS_IN)) { /* port is GSM bs-mode */
+ other_gsm_bs = (class Pgsm_bs *)other_port;
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type GSM! comparing our imsi with other imsi=%s\n", ea_endpoint->ep_serial, our_gsm_bs->p_g_imsi, other_gsm_bs->p_g_imsi);
+ if (!strcmp(other_gsm_bs->p_g_imsi, our_gsm_bs->p_g_imsi)) /* same tei+sapi */
+ break;
+ } else
+#endif
+ {
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
}
} else {
}
/* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
- if (our_pdss1->p_m_hold && !other_pdss1->p_m_hold) {
+ if (our_port->p_hold && !other_port->p_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;
/* we send a retrieve to that endpoint */
// mixer will update the hold-state of the join and send it to the endpoints is changes
-#else
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
-#endif
return 0;
}
if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
|| other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is FXS */
other_fxs = (class Pfxs *)other_port;
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s state=%d\n", ea_endpoint->ep_serial, our_fxs->p_m_mISDNport->portnum, other_fxs->p_m_mISDNport->portnum, (other_fxs->p_m_hold)?"YES":"NO", other_fxs->p_state);
- if (1 //other_fxs->p_m_hold /* port is on hold */
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s state=%d\n", ea_endpoint->ep_serial, our_fxs->p_m_mISDNport->portnum, other_fxs->p_m_mISDNport->portnum, (other_fxs->p_hold)?"YES":"NO", other_fxs->p_state);
+ if (1 //other_fxs->p_hold /* port is on hold */
&& other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
break;
} else {
}
/* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
- if (our_fxs->p_m_hold && !other_fxs->p_m_hold) {
+ if (our_port->p_hold && !other_port->p_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_join = our_join;
/* we send a retrieve to that endpoint */
// mixer will update the hold-state of the join and send it to the endpoints is changes
+
+ return 0;
#else
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
-#endif
- return 0;
+ return -1;
+#endif
}
+/* do audio bridge of endpoints on same isdn/gsm terminal */
int EndpointAppPBX::join_3pty_dss1(void)
{
-#ifdef WITH_MISDN
class Join *our_join, *other_join;
class JoinPBX *our_joinpbx, *other_joinpbx;
class EndpointAppPBX *other_eapp;
class Port *our_port, *other_port;
- class Pdss1 *our_pdss1, *other_pdss1;
+#ifdef WITH_MISDN
+ class Pdss1 *our_pdss1 = NULL, *other_pdss1;
+#endif
+#ifdef WITH_GSM_BS
+ class Pgsm_bs *our_gsm_bs = NULL, *other_gsm_bs;
+#endif
/* are we a candidate to join a join? */
our_join = find_join_id(ea_endpoint->ep_join_id);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
return -1;
}
- if (!e_ext.number[0]) {
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
- return -1;
- }
our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
if (!our_port) {
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
return -1;
}
- if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
- return -1;
- }
- our_pdss1 = (class Pdss1 *)our_port;
+#ifdef WITH_MISDN
+ if ((our_port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1)
+ our_pdss1 = (class Pdss1 *)our_port;
+#endif
+#ifdef WITH_GSM_BS
+ if ((our_port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS)
+ our_gsm_bs = (class Pgsm_bs *)our_port;
+#endif
/* find an endpoint that has the same mISDNport/ces that we are on */
other_eapp = apppbx_first;
continue;
}
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint candiate: (ep%d) terminal='%s' port=%s join=%d.\n", ea_endpoint->ep_serial, other_eapp->ea_endpoint->ep_serial, other_eapp->e_ext.number, (other_eapp->ea_endpoint->ep_portlist)?"YES":"NO", other_eapp->ea_endpoint->ep_join_id);
- if (other_eapp->e_ext.number[0] /* has terminal */
- && other_eapp->ea_endpoint->ep_portlist /* has port */
+ if (other_eapp->ea_endpoint->ep_portlist /* has port */
&& other_eapp->ea_endpoint->ep_join_id) { /* has join */
other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
if (other_port) { /* port still exists */
- if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
- || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
+#ifdef WITH_MISDN
+ if (our_pdss1
+ && (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
+ || other_port->p_type==PORT_TYPE_DSS1_NT_IN)) { /* port is isdn nt-mode */
other_pdss1 = (class Pdss1 *)other_port;
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_m_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
- if (1 //other_pdss1->p_m_hold /* port is on hold */
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
+ if (1 //other_pdss1->p_hold /* port is on hold */
&& other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
&& other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
break;
- } else {
+ } else
+#endif
+#ifdef WITH_GSM_BS
+ if (our_gsm_bs
+ && (other_port->p_type==PORT_TYPE_GSM_BS_OUT
+ || other_port->p_type==PORT_TYPE_GSM_BS_IN)) { /* port is GSM bs-mode */
+ other_gsm_bs = (class Pgsm_bs *)other_port;
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type GSM! comparing our imsi with other imsi=%s\n", ea_endpoint->ep_serial, our_gsm_bs->p_g_imsi, other_gsm_bs->p_g_imsi);
+ if (!strcmp(other_gsm_bs->p_g_imsi, our_gsm_bs->p_g_imsi)) /* same tei+sapi */
+ break;
+ } else
+#endif
+ {
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
}
} else {
other_eapp = other_eapp->next;
}
if (!other_eapp) {
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same terminal.\n", ea_endpoint->ep_serial);
return -1;
}
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
/* we send a retrieve to that endpoint */
// mixer will update the hold-state of the join and send it to the endpoints is changes
-#else
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
-#endif
return 0;
}
+/* do audio bridge of endpoints on same fxs terminal */
int EndpointAppPBX::join_3pty_fxs(void)
{
#ifdef WITH_MISDN
if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
|| other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is isdn nt-mode */
other_fxs = (class Pfxs *)other_port;
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type FXS! comparing our portnum=%d with other's portnum=%d hold=%s state=%d\n", ea_endpoint->ep_serial, our_fxs->p_m_mISDNport->portnum, other_fxs->p_m_mISDNport->portnum, (other_fxs->p_m_hold)?"YES":"NO", other_fxs->p_state);
- if (1 //other_fxs->p_m_hold /* port is on hold */
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type FXS! comparing our portnum=%d with other's portnum=%d hold=%s state=%d\n", ea_endpoint->ep_serial, our_fxs->p_m_mISDNport->portnum, other_fxs->p_m_mISDNport->portnum, (other_fxs->p_hold)?"YES":"NO", other_fxs->p_state);
+ if (1 //other_fxs->p_hold /* port is on hold */
&& other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
break;
} else {
/* we send a retrieve to that endpoint */
// mixer will update the hold-state of the join and send it to the endpoints is changes
+
+ return 0;
#else
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
-#endif
- return 0;
+ return -1;
+#endif
}
+/* split audio bridge */
int EndpointAppPBX::split_3pty(void)
{
-#ifdef WITH_MISDN
class Join *our_join, *other_join;
class JoinPBX *our_joinpbx, *other_joinpbx;
/* we send a retrieve to that endpoint */
// mixer will update the hold-state of the join and send it to the endpoints is changes
-#else
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial);
-#endif
return 0;
}
return(0);
}
+int EndpointAppPBX::vootp_on(int on)
+{
+#ifndef WITH_VOOTP
+ set_tone(ea_endpoint->ep_portlist, "crypt_off");
+#else
+ if (!e_ext.otp_ident[0]) {
+ set_tone(ea_endpoint->ep_portlist, "crypt_off");
+ return -EINVAL;
+ }
+ if(ea_endpoint->ep_portlist) {
+ struct lcr_msg *message;
+
+ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VOOTP);
+ message->param.vootp.enable = on;
+ SCPY(message->param.vootp.id, e_ext.otp_ident);
+ message_put(message);
+ }
+ if (!on)
+ set_tone(ea_endpoint->ep_portlist, "crypt_off");
+#endif
+
+ return 0;
+}
+
void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
{
const char *logtext = "unknown";
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;
end_trace();
break;
+ case MESSAGE_DOV_INDICATION:
+ case MESSAGE_DOV_REQUEST:
+ trace_header("Data-Over-Voice", dir);
+ if (dir == DIRECTION_OUT)
+ add_trace("to", NULL, "CH(%lu)", port_id);
+ if (dir == DIRECTION_IN)
+ add_trace("from", NULL, "CH(%lu)", port_id);
+ {
+ char dov_str[param->dov.length + 1];
+ memcpy(dov_str, param->dov.data, param->dov.length);
+ dov_str[param->dov.length] = '\0';
+ add_trace("string", NULL, "%s", dov_str);
+ }
+ add_trace("type", NULL, "%d", param->dov.type);
+ end_trace();
+ break;
+
+ case MESSAGE_ENABLEKEYPAD:
+ trace_header("ENABLEKEYPAD", dir);
+ end_trace();
+ break;
+
default:
PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
}
}
-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);
}
+void EndpointAppPBX::dov_msg_write(union parameter *param, int sent)
+{
+ FILE *fp;
+ struct tm *tm;
+ time_t ti;
+ int __attribute__((__unused__)) rc;
+
+ /* no write, if no log file given */
+ if (!e_ext.dov_log[0])
+ return;
+
+ fp = fopen(e_ext.dov_log, "a");
+ if (!fp) {
+ PERROR("EPOINT(%d) failed to open Data-Over-Voice log file '%s'\n", ea_endpoint->ep_serial, e_ext.dov_log);
+ return;
+ }
+
+ ti = time(NULL);
+ tm = localtime(&ti);
+ fprintf(fp, "%02d.%02d.%02d %02d:%02d:%02d ", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+
+ if (sent) {
+ fprintf(fp, "sent [%s] ", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
+ } else {
+ fprintf(fp, "received [%s] ", e_dialinginfo.id);
+ }
+
+ rc = fwrite(param->dov.data, param->dov.length, 1, fp);
+
+ fprintf(fp, "\n");
+
+ fclose(fp);
+}
+