*/
void EndpointAppPBX::keypad_function(char digit)
{
+ class Port *port;
/* we must be in a call, in order to send messages to the call */
if (e_ext.number[0] == '\0') {
break;
}
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
- join_join();
+ port = find_port_id(ea_endpoint->ep_portlist->port_id);
+ if (!port)
+ break;
+ 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();
break;
#ifdef WITH_CRYPT
port = ss5_hunt_line(mISDNport);
else
#endif
- port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+#ifdef ISDN_P_FXS_POTS
+ if (mISDNport->pots)
+ port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
+ else
+#endif
+ port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, channel, mISDNport->ifport->channel_force, mode);
earlyb = mISDNport->earlyb;
#else
trace_header("INTERFACE (has no function)", DIRECTION_NONE);
port = ss5_hunt_line(mISDNport);
else
#endif
- port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+#ifdef ISDN_P_FXS_POTS
+ if (mISDNport->pots)
+ port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
+ else
+#endif
+ port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, channel, mISDNport->ifport->channel_force, mode);
if (!port)
FATAL("No memory for Port instance\n");
earlyb = mISDNport->earlyb;
port = ss5_hunt_line(mISDNport);
else
#endif
- port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+#ifdef ISDN_P_FXS_POTS
+ if (mISDNport->pots)
+ port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
+ else
+#endif
+ port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, channel, mISDNport->ifport->channel_force, mode);
earlyb = mISDNport->earlyb;
#else
trace_header("INTERFACE (has no function)", DIRECTION_NONE);
logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
struct lcr_msg *message;
- const char *logtext = "";
- char buffer[64];
/* signal to call tool */
admin_call_response(e_adminid, ADMIN_CALL_NOTIFY, numberrize_callerinfo(param->notifyinfo.id,param->notifyinfo.ntype, options.national, options.international), 0, 0, param->notifyinfo.notify);
break;
}
- /* get name of notify */
- switch(param->notifyinfo.notify) {
- case 0x00:
- logtext = "NULL";
- break;
- case 0x80:
- logtext = "USER_SUSPENDED";
- break;
- case 0x82:
- logtext = "BEARER_SERVICE_CHANGED";
- break;
- case 0x81:
- logtext = "USER_RESUMED";
- break;
- case 0xc2:
- logtext = "CONFERENCE_ESTABLISHED";
- break;
- case 0xc3:
- logtext = "CONFERENCE_DISCONNECTED";
- break;
- case 0xc4:
- logtext = "OTHER_PARTY_ADDED";
- break;
- case 0xc5:
- logtext = "ISOLATED";
- break;
- case 0xc6:
- logtext = "REATTACHED";
- break;
- case 0xc7:
- logtext = "OTHER_PARTY_ISOLATED";
- break;
- case 0xc8:
- logtext = "OTHER_PARTY_REATTACHED";
- break;
- case 0xc9:
- logtext = "OTHER_PARTY_SPLIT";
- break;
- case 0xca:
- logtext = "OTHER_PARTY_DISCONNECTED";
- break;
- case 0xcb:
- logtext = "CONFERENCE_FLOATING";
- break;
- case 0xcc:
- logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
- break;
- case 0xcf:
- logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
- break;
- case 0xe0:
- logtext = "CALL_IS_A_WAITING_CALL";
- break;
- case 0xe8:
- logtext = "DIVERSION_ACTIVATED";
- break;
- case 0xe9:
- logtext = "RESERVED_CT_1";
- break;
- case 0xea:
- logtext = "RESERVED_CT_2";
- break;
- case 0xee:
- logtext = "REVERSE_CHARGING";
- break;
- case 0xf9:
- logtext = "REMOTE_HOLD";
- break;
- case 0xfa:
- logtext = "REMOTE_RETRIEVAL";
- break;
- case 0xfb:
- logtext = "CALL_IS_DIVERTING";
- break;
- default:
- SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
- logtext = buffer;
-
- }
-
/* notify call if available */
if (ea_endpoint->ep_join_id) {
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
struct lcr_msg *message;
int rc;
- rc = join_join();
+ /* 3PTY bridge */
+ if (param->threepty.begin)
+ rc = join_3pty_dss1();
+ else if (param->threepty.end)
+ rc = split_3pty();
+ else
+ return;
+
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_3PTY);
- message->param.threepty.begin = 1;
+ message->param.threepty.begin = param->threepty.begin;
+ message->param.threepty.end = param->threepty.end;
if (rc < 0)
message->param.threepty.error = 1;
else
message_put(message);
}
+/* port MESSAGE_TRANSFER */
+void EndpointAppPBX::port_transfer(struct port_list *portlist, int message_type, union parameter *param)
+{
+ logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
+
+ class Port *port;
+
+ /* 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();
+}
+
/* port MESSAGE_SUSPEND */
/* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
}
+/* port MESSAGE_DISABLE_DEJITTER */
+void EndpointAppPBX::port_disable_dejitter(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_DISABLE_DEJITTER);
+ memcpy(&message->param, param, sizeof(union parameter));
+ message_put(message);
+}
+
+
/* port sends message to the endpoint
*/
void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
port_3pty(portlist, message_type, param);
break;
+ case MESSAGE_TRANSFER:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming TRANSFER request (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ port_transfer(portlist, message_type, param);
+ break;
+
/* PORT sends DTMF message */
case MESSAGE_DTMF: /* dtmf digits received */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf digit=%c (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, param->dtmf, e_ext.number, e_callerinfo.id);
port_enablekeypad(portlist, message_type, param);
break;
+ case MESSAGE_DISABLE_DEJITTER:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming disable dejitter message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ port_disable_dejitter(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);
}
}
+/* join MESSAGE_DISABLE_DEJITTER */
+void EndpointAppPBX::join_disable_dejitter(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_DISABLE_DEJITTER);
+ 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)
join_dtmf(portlist, message_type, param);
break;
+ /* JOIN sends a DISABLE_DEJITTER message */
+ case MESSAGE_DISABLE_DEJITTER:
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received disable dejitter.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
+ join_disable_dejitter(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);
}
/* join calls (look for a join that is on hold (same isdn interface/terminal))
*/
-int EndpointAppPBX::join_join(void)
+int EndpointAppPBX::join_join_dss1(void)
{
#ifdef WITH_MISDN
struct lcr_msg *message;
- struct join_relation *our_relation, *other_relation;
- struct join_relation **our_relation_pointer, **other_relation_pointer;
- class Join *our_join, *other_join;
- class JoinPBX *our_joinpbx, *other_joinpbx;
- class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
+ 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 Port *our_port, *other_port;
class Pdss1 *our_pdss1, *other_pdss1;
+ class Endpoint *temp_epoint;
/* are we a candidate to join a join? */
our_join = find_join_id(ea_endpoint->ep_join_id);
}
our_pdss1 = (class Pdss1 *)our_port;
- /* find an endpoint that is on hold and has the same mISDNport that we are on */
+ /* find an endpoint that has the same mISDNport/ces that we are on */
other_eapp = apppbx_first;
while(other_eapp) {
if (other_eapp == this) {
return -1;
}
+ /* 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_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_join = other_join;
+ remove_joinpbx = other_joinpbx;
+ add_join = our_join;
+ add_joinpbx = our_joinpbx;
+ }
+
/* remove relation to endpoint for join on hold */
- other_relation = other_joinpbx->j_relation;
- other_relation_pointer = &other_joinpbx->j_relation;
- while(other_relation) {
- if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
- /* detach other endpoint on hold */
- *other_relation_pointer = other_relation->next;
- FREE(other_relation, sizeof(struct join_relation));
+ 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 */
+ *remove_relation_pointer = remove_relation->next;
+ FREE(remove_relation, sizeof(struct join_relation));
cmemuse--;
- other_relation = *other_relation_pointer;
- other_eapp->ea_endpoint->ep_join_id = 0;
+ remove_relation = *remove_relation_pointer;
+ remove_eapp->ea_endpoint->ep_join_id = 0;
continue;
}
/* change join/hold pointer of endpoint to the new join */
- temp_epoint = find_epoint_id(other_relation->epoint_id);
+ temp_epoint = find_epoint_id(remove_relation->epoint_id);
if (temp_epoint) {
- if (temp_epoint->ep_join_id == other_join->j_serial)
- temp_epoint->ep_join_id = our_join->j_serial;
+ if (temp_epoint->ep_join_id == remove_join->j_serial)
+ temp_epoint->ep_join_id = add_join->j_serial;
}
- other_relation_pointer = &other_relation->next;
- other_relation = other_relation->next;
+ remove_relation_pointer = &remove_relation->next;
+ remove_relation = remove_relation->next;
}
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
/* join call relations */
- our_relation = our_joinpbx->j_relation;
- our_relation_pointer = &our_joinpbx->j_relation;
- while(our_relation) {
- our_relation_pointer = &our_relation->next;
- our_relation = our_relation->next;
- }
- *our_relation_pointer = other_joinpbx->j_relation;
- other_joinpbx->j_relation = NULL;
+ add_relation = add_joinpbx->j_relation;
+ add_relation_pointer = &add_joinpbx->j_relation;
+ while(add_relation) {
+ add_relation_pointer = &add_relation->next;
+ add_relation = add_relation->next;
+ }
+ *add_relation_pointer = remove_joinpbx->j_relation;
+ remove_joinpbx->j_relation = NULL;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
- /* release endpoint on hold */
- message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
+ /* release endpoint */
+ message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
/* if we are not a partyline, we get partyline state from other join */
- our_joinpbx->j_partyline += other_joinpbx->j_partyline;
+ add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
/* remove empty join */
- delete other_join;
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
+ delete remove_join;
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
+
+ /* mixer must update */
+ trigger_work(&add_joinpbx->j_updatebridge);
+
+ /* 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;
+}
+
+/* join calls (look for a join that is on hold (same fxs interface/terminal))
+ */
+int EndpointAppPBX::join_join_fxs(void)
+{
+#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 Port *our_port, *other_port;
+ class Pfxs *our_fxs, *other_fxs;
+ class Endpoint *temp_epoint;
+
+ /* are we a candidate to join a join? */
+ our_join = find_join_id(ea_endpoint->ep_join_id);
+ if (!our_join) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (our_join->j_type != JOIN_TYPE_PBX) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ our_joinpbx = (class JoinPBX *)our_join;
+ if (!ea_endpoint->ep_portlist) {
+ 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_POTS_MASK) != PORT_CLASS_POTS_FXS) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not fxs.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ our_fxs = (class Pfxs *)our_port;
+
+ /* find an endpoint that has the same mISDNport that we are on */
+ other_eapp = apppbx_first;
+ while(other_eapp) {
+ if (other_eapp == this) {
+ other_eapp = other_eapp->next;
+ 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 */
+ && 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_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 */
+ && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
+ break;
+ } else {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
+ }
+ } else {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
+ }
+ }
+ other_eapp = other_eapp->next;
+ }
+ if (!other_eapp) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
+
+ /* if we have the same join */
+ if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
+ if (!other_join) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (other_join->j_type != JOIN_TYPE_PBX) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ other_joinpbx = (class JoinPBX *)other_join;
+ if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+
+ /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
+ if (our_fxs->p_m_hold && !other_fxs->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_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_join = other_join;
+ remove_joinpbx = other_joinpbx;
+ add_join = our_join;
+ add_joinpbx = our_joinpbx;
+ }
+
+ /* remove relation to endpoint for join on hold */
+ 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 */
+ *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;
+ continue;
+ }
+
+ /* change join/hold pointer of endpoint to the new join */
+ temp_epoint = find_epoint_id(remove_relation->epoint_id);
+ if (temp_epoint) {
+ if (temp_epoint->ep_join_id == remove_join->j_serial)
+ temp_epoint->ep_join_id = add_join->j_serial;
+ }
+
+ 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);
+
+ /* join call relations */
+ add_relation = add_joinpbx->j_relation;
+ add_relation_pointer = &add_joinpbx->j_relation;
+ while(add_relation) {
+ add_relation_pointer = &add_relation->next;
+ add_relation = add_relation->next;
+ }
+ *add_relation_pointer = remove_joinpbx->j_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);
+ message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+
+ /* if we are not a partyline, we get partyline state from other join */
+ add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
+
+ /* remove empty join */
+ delete remove_join;
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
+
+ /* mixer must update */
+ trigger_work(&add_joinpbx->j_updatebridge);
+
+ /* 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;
+}
+
+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;
+
+ /* are we a candidate to join a join? */
+ our_join = find_join_id(ea_endpoint->ep_join_id);
+ if (!our_join) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (our_join->j_type != JOIN_TYPE_PBX) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ our_joinpbx = (class JoinPBX *)our_join;
+ if (!ea_endpoint->ep_portlist) {
+ 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;
+
+ /* find an endpoint that has the same mISDNport/ces that we are on */
+ other_eapp = apppbx_first;
+ while(other_eapp) {
+ if (other_eapp == this) {
+ other_eapp = other_eapp->next;
+ 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 */
+ && 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 */
+ 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 */
+ && 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 {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
+ }
+ } else {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
+ }
+ }
+ 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);
+ return -1;
+ }
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
+
+ /* if we have the same join */
+ if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
+ if (!other_join) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (other_join->j_type != JOIN_TYPE_PBX) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ other_joinpbx = (class JoinPBX *)other_join;
+ if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+
+ if (our_joinpbx->j_3pty) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (other_joinpbx->j_3pty) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+
+ /* set 3PTY bridge */
+ other_joinpbx->j_3pty = our_joinpbx->j_serial;
+ our_joinpbx->j_3pty = other_joinpbx->j_serial;
+
+ /* mixer must update */
+ trigger_work(&our_joinpbx->j_updatebridge);
+ trigger_work(&other_joinpbx->j_updatebridge);
+
+ /* 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;
+}
+
+int EndpointAppPBX::join_3pty_fxs(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 Pfxs *our_fxs, *other_fxs;
+
+ /* are we a candidate to join a join? */
+ our_join = find_join_id(ea_endpoint->ep_join_id);
+ if (!our_join) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (our_join->j_type != JOIN_TYPE_PBX) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ our_joinpbx = (class JoinPBX *)our_join;
+ if (!ea_endpoint->ep_portlist) {
+ 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_POTS_MASK) != PORT_CLASS_POTS_FXS) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not FXS pots.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ our_fxs = (class Pfxs *)our_port;
+
+ /* find an endpoint that has the same mISDNport that we are on */
+ other_eapp = apppbx_first;
+ while(other_eapp) {
+ if (other_eapp == this) {
+ other_eapp = other_eapp->next;
+ 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 */
+ && 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_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 */
+ && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
+ break;
+ } else {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
+ }
+ } else {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
+ }
+ }
+ other_eapp = other_eapp->next;
+ }
+ if (!other_eapp) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
+
+ /* if we have the same join */
+ if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
+ if (!other_join) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (other_join->j_type != JOIN_TYPE_PBX) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ other_joinpbx = (class JoinPBX *)other_join;
+ if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+
+ if (our_joinpbx->j_3pty) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (other_joinpbx->j_3pty) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+
+ /* set 3PTY bridge */
+ other_joinpbx->j_3pty = our_joinpbx->j_serial;
+ our_joinpbx->j_3pty = other_joinpbx->j_serial;
/* mixer must update */
trigger_work(&our_joinpbx->j_updatebridge);
+ trigger_work(&other_joinpbx->j_updatebridge);
/* 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;
}
+int EndpointAppPBX::split_3pty(void)
+{
+#ifdef WITH_MISDN
+ class Join *our_join, *other_join;
+ class JoinPBX *our_joinpbx, *other_joinpbx;
+
+ /* are we a candidate to join a join? */
+ our_join = find_join_id(ea_endpoint->ep_join_id);
+ if (!our_join) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (our_join->j_type != JOIN_TYPE_PBX) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ our_joinpbx = (class JoinPBX *)our_join;
+
+ if (!our_joinpbx->j_3pty) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+
+ other_join = find_join_id(our_joinpbx->j_3pty);
+ if (!other_join) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ if (other_join->j_type != JOIN_TYPE_PBX) {
+ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
+ return -1;
+ }
+ other_joinpbx = (class JoinPBX *)other_join;
+
+ our_joinpbx->j_3pty = 0;
+ other_joinpbx->j_3pty = 0;
+
+ /* mixer must update */
+ trigger_work(&our_joinpbx->j_updatebridge);
+ trigger_work(&other_joinpbx->j_updatebridge);
+
+ /* 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;
+}
/* check if we have an external call
* this is used to check for encryption ability
add_trace("from", NULL, "CH(%lu)", port_id);
if (param->setup.callerinfo.extension[0])
add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
+ if (param->setup.callerinfo.interface[0])
+ add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
+ if (param->setup.dialinginfo.interfaces[0])
+ add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
switch(param->setup.callerinfo.present) {
case INFO_PRESENT_RESTRICTED:
end_trace();
break;
+ case MESSAGE_TRANSFER:
+ trace_header("TRANSFER", dir);
+ end_trace();
+ break;
+
+ case MESSAGE_DISABLE_DEJITTER:
+ trace_header("DISBALE_DEJITTER", dir);
+ if (param->queue)
+ add_trace("queue", NULL, "%d", param->queue);
+ end_trace();
+ break;
+
default:
PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
}