X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=apppbx.cpp;h=8bcc36fa0065a6606923601269ab16eb860f607d;hp=a61d1085a5853ec1e110d855241322a60581cf87;hb=refs%2Fheads%2Fbackup2;hpb=f851ca0d9e22673b7cc0a7c2f539c9d51b9b77f8 diff --git a/apppbx.cpp b/apppbx.cpp index a61d108..8bcc36f 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -500,6 +500,7 @@ void EndpointAppPBX::notify_active(void) */ 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') { @@ -515,7 +516,25 @@ void EndpointAppPBX::keypad_function(char digit) 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; + + /* 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 @@ -537,7 +556,6 @@ void EndpointAppPBX::keypad_function(char digit) encrypt_off(); break; #endif - default: PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit); } @@ -584,306 +602,6 @@ void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone) } } -/* hunts for the given interface - * it does not need to have an mISDNport instance */ -struct interface *EndpointAppPBX::hunt_interface(char *ifname) -{ - struct interface *interface; - int there_is_an_external = 0; - - interface = interface_first; - - /* first find the given interface or, if not given, one with no extension */ - checknext: - if (!interface) { - if (!there_is_an_external && !(ifname && ifname[0])) { - trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE); - add_trace("info", NULL, "Add 'extern' parameter to interface.conf."); - end_trace(); - } - return(NULL); - } - - /* check for given interface */ - if (ifname && ifname[0]) { - if (!strcasecmp(interface->name, ifname)) { - /* found explicit interface */ - trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", ifname); - end_trace(); - goto foundif; - } - } else { - if (interface->external) { - there_is_an_external = 1; - /* found non extension */ - trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", interface->name); - end_trace(); - goto foundif; - } - } - - interface = interface->next; - goto checknext; -foundif: - - return interface; -} - - -#ifdef WITH_MISDN -/* - * hunts an mISDNport that is available for an outgoing call - * if no ifname was given, any interface that is not an extension - * will be searched. - */ -struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel) -{ - struct interface *interface; - struct interface_port *ifport, *ifport_start; - struct select_channel *selchannel; - struct mISDNport *mISDNport; - int index, i; - int there_is_an_external = 0; - - interface = interface_first; - - /* first find the given interface or, if not given, one with no extension */ - checknext: - if (!interface) { - if (!there_is_an_external && !(ifname && ifname[0])) { - trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE); - add_trace("info", NULL, "Add 'extern' parameter to interface.conf."); - end_trace(); - } - return(NULL); - } - - /* check for given interface */ - if (ifname && ifname[0]) { - if (!strcasecmp(interface->name, ifname)) { - /* found explicit interface */ - trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", ifname); - end_trace(); - goto foundif; - } - - } else { - if (interface->external) { - there_is_an_external = 1; - /* found non extension */ - trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", interface->name); - end_trace(); - goto foundif; - } - } - - interface = interface->next; - goto checknext; -foundif: - - /* see if interface has ports */ - if (!interface->ifport) { - /* no ports */ - trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", interface->name); - end_trace(); - interface = interface->next; - goto checknext; - } - - /* select port by algorithm */ - ifport_start = interface->ifport; - index = 0; - if (interface->hunt == HUNT_ROUNDROBIN) { - while(ifport_start->next && indexhunt_next) { - ifport_start = ifport_start->next; - index++; - } - trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport_start->portnum); - add_trace("position", NULL, "%d", index); - end_trace(); - } - - /* loop ports */ - ifport = ifport_start; - nextport: - - /* see if port is available */ - if (!ifport->mISDNport) { - trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - end_trace(); - goto portbusy; - } - mISDNport = ifport->mISDNport; - - /* see if port is administratively blocked */ - if (ifport->block) { - trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - end_trace(); - goto portbusy; - } - - /* see if link is up on PTP*/ - if (mISDNport->l2hold && mISDNport->l2link<1) { - trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - end_trace(); - goto portbusy; - } - - /* check for channel form selection list */ - *channel = 0; -#ifdef WITH_SS5 - if (mISDNport->ss5) { - class Pss5 *port; - port = ss5_hunt_line(mISDNport); - if (port) { - *channel = port->p_m_b_channel; - trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - add_trace("channel", NULL, "%d", *channel); - end_trace(); - } - } else -#endif - { - selchannel = ifport->out_channel; - while(selchannel) { - switch(selchannel->channel) { - case CHANNEL_FREE: /* free channel */ - if (mISDNport->b_reserved >= mISDNport->b_num) - break; /* all channel in use or reserverd */ - /* find channel */ - i = 0; - while(i < mISDNport->b_num) { - if (mISDNport->b_port[i] == NULL) { - *channel = i+1+(i>=15); - trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - add_trace("channel", NULL, "%d", *channel); - end_trace(); - break; - } - i++; - } - if (*channel) - break; - trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - end_trace(); - break; - - case CHANNEL_ANY: /* don't ask for channel */ - if (mISDNport->b_reserved >= mISDNport->b_num) { - trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - add_trace("total", NULL, "%d", mISDNport->b_num); - add_trace("reserved", NULL, "%d", mISDNport->b_reserved); - end_trace(); - break; /* all channel in use or reserverd */ - } - trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - end_trace(); - *channel = CHANNEL_ANY; - break; - - case CHANNEL_NO: /* call waiting */ - trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - end_trace(); - *channel = CHANNEL_NO; - break; - - default: - if (selchannel->channel<1 || selchannel->channel==16) { - trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - add_trace("channel", NULL, "%d", selchannel->channel); - end_trace(); - break; /* invalid channels */ - } - i = selchannel->channel-1-(selchannel->channel>=17); - if (i >= mISDNport->b_num) { - trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - add_trace("channel", NULL, "%d", selchannel->channel); - add_trace("channels", NULL, "%d", mISDNport->b_num); - end_trace(); - break; /* channel not in port */ - } - if (mISDNport->b_port[i] == NULL) { - *channel = selchannel->channel; - trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - add_trace("channel", NULL, "%d", *channel); - end_trace(); - break; - } - break; - } - if (*channel) - break; /* found channel */ - selchannel = selchannel->next; - } - } - - /* if channel was found, return mISDNport and channel */ - if (*channel) { - /* setting next port to start next time */ - if (interface->hunt == HUNT_ROUNDROBIN) { - index++; - if (!ifport->next) - index = 0; - interface->hunt_next = index; - } - - return(mISDNport); - } - - trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE); - add_trace("port", NULL, "%d", ifport->portnum); - add_trace("position", NULL, "%d", index); - end_trace(); - - portbusy: - /* go next port, until all ports are checked */ - index++; - ifport = ifport->next; - if (!ifport) { - index = 0; - ifport = interface->ifport; - } - if (ifport != ifport_start) - goto nextport; - - if (!ifname) { - interface = interface->next; - goto checknext; - } - - return(NULL); /* no port found */ -} -#endif /* outgoing setup to port(s) * ports will be created and a setup is sent if everything is ok. otherwhise @@ -909,12 +627,14 @@ void EndpointAppPBX::out_setup(int cfnr) // char allowed_ports[256]; // char exten[256]; char ifname[sizeof(e_ext.interfaces)], - number[256]; + *ifname_p, + number[256], + *number_p; struct port_settings port_settings; #ifdef WITH_MISDN int channel = 0; - struct admin_list *admin; #endif + struct admin_list *admin; int earlyb; int mode = B_MODE_TRANSPARENT; @@ -1039,6 +759,23 @@ void EndpointAppPBX::out_setup(int cfnr) } /* found interface */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname); + if (interface->remote) { + admin = admin_first; + while(admin) { + if (admin->remote_name[0] && !strcmp(admin->remote_name, interface->remote_app)) + break; + admin = admin->next; + } + if (!admin) { + trace_header("INTERFACE (remote not connected)", DIRECTION_NONE); + add_trace("application", NULL, "%s", interface->remote_app); + end_trace(); + continue; + } + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface, admin->sock); + earlyb = (interface->is_earlyb == IS_YES); + } else #ifdef WITH_GSM_BS if (interface->gsm_bs) { SPRINT(portname, "%s-%d-out", interface->name, 0); @@ -1053,7 +790,7 @@ void EndpointAppPBX::out_setup(int cfnr) earlyb = (interface->is_earlyb == IS_YES); } else #endif -#ifdef WITH_GSM_MS +#ifdef WITH_SIP if (interface->sip) { SPRINT(portname, "%s-%d-out", interface->name, 0); port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface); @@ -1077,22 +814,12 @@ void EndpointAppPBX::out_setup(int cfnr) port = ss5_hunt_line(mISDNport); else #endif - if (mISDNport->ifport->remote) { - admin = admin_first; - while(admin) { - if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app)) - break; - admin = admin->next; - } - if (!admin) { - trace_header("INTERFACE (remote not connected)", DIRECTION_NONE); - add_trace("application", NULL, "%s", mISDNport->ifport->remote_app); - end_trace(); - continue; - } - port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock); - } else - 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); @@ -1213,7 +940,12 @@ void EndpointAppPBX::out_setup(int cfnr) 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; @@ -1286,128 +1018,153 @@ void EndpointAppPBX::out_setup(int cfnr) PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad); /* call to extenal interfaces */ if (e_dialinginfo.keypad[0]) - p = e_dialinginfo.keypad; + number_p = e_dialinginfo.keypad; else - p = e_dialinginfo.id; + number_p = e_dialinginfo.id; do { - earlyb = 0; number[0] = '\0'; - while(*p!=',' && *p!='\0') - SCCAT(number, *p++); - if (*p == ',') - p++; + while(*number_p!=',' && *number_p!='\0') + SCCAT(number, *number_p++); + if (*number_p == ',') + number_p++; /* found number */ - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface"); - /* search interface */ - interface = hunt_interface(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL); - if (!interface) { - trace_header("INTERFACE (not found)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", ifname); - end_trace(); - goto check_anycall_extern; - } - /* found interface */ -#ifdef WITH_GSM_BS - if (interface->gsm_bs) { - SPRINT(portname, "%s-%d-out", interface->name, 0); - port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface); - earlyb = (interface->is_earlyb == IS_YES); - } else -#endif -#ifdef WITH_GSM_MS - if (interface->gsm_ms) { - SPRINT(portname, "%s-%d-out", interface->name, 0); - port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface); - earlyb = (interface->is_earlyb == IS_YES); - } else -#endif -#ifdef WITH_GSM_MS - if (interface->sip) { - SPRINT(portname, "%s-%d-out", interface->name, 0); - port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface); - earlyb = (interface->is_earlyb == IS_YES); - } else -#endif - { -#ifdef WITH_MISDN - /* hunt for mISDNport and create Port */ - mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel); - if (!mISDNport) { - trace_header("INTERFACE (too busy)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface"); + + ifname_p = e_dialinginfo.interfaces; + if (*ifname_p == '+') + ifname_p++; + do { + earlyb = 0; + ifname[0] = '\0'; + while(*ifname_p!=',' && *ifname_p!='\0') + SCCAT(ifname, *ifname_p++); + if (*ifname_p == ',') + ifname_p++; + /* found interface name */ + + /* search interface */ + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, ifname[0]?ifname:"any interface"); + interface = hunt_interface(ifname[0]?ifname:NULL); + if (!interface) { + trace_header("INTERFACE (not found)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", ifname); end_trace(); - goto check_anycall_extern; + continue; } - /* creating EXTERNAL port*/ - SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); -#ifdef WITH_SS5 - if (mISDNport->ss5) - port = ss5_hunt_line(mISDNport); - else -#endif - if (mISDNport->ifport->remote) { + /* found interface */ + if (interface->remote) { admin = admin_first; while(admin) { - if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app)) + if (admin->remote_name[0] && !strcmp(admin->remote_name, interface->remote_app)) break; admin = admin->next; } if (!admin) { trace_header("INTERFACE (remote not connected)", DIRECTION_NONE); - add_trace("application", NULL, "%s", mISDNport->ifport->remote_app); + add_trace("application", NULL, "%s", interface->remote_app); end_trace(); continue; } - port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock); + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface, admin->sock); + earlyb = (interface->is_earlyb == IS_YES); } else - 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); - earlyb = mISDNport->earlyb; +#ifdef WITH_GSM_BS + if (interface->gsm_bs) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface); + earlyb = (interface->is_earlyb == IS_YES); + } else +#endif +#ifdef WITH_GSM_MS + if (interface->gsm_ms) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface); + earlyb = (interface->is_earlyb == IS_YES); + } else +#endif +#ifdef WITH_SIP + if (interface->sip) { + SPRINT(portname, "%s-%d-out", interface->name, 0); + port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface); + earlyb = (interface->is_earlyb == IS_YES); + } else +#endif + { +#ifdef WITH_MISDN + /* hunt for mISDNport and create Port */ + mISDNport = hunt_port(ifname[0]?ifname:NULL, &channel); + if (!mISDNport) { + trace_header("INTERFACE (too busy)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", ifname[0]?ifname:"any interface"); + end_trace(); + continue; + } + /* creating EXTERNAL port*/ + SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); + +#ifdef WITH_SS5 + if (mISDNport->ss5) + port = ss5_hunt_line(mISDNport); + else +#endif +#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); - add_trace("interface", NULL, "%s", ifname); - end_trace(); - continue; + trace_header("INTERFACE (has no function)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", ifname); + end_trace(); + continue; #endif - } - if (!port) - FATAL("No memory for Port instance\n"); - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name); - memset(&dialinginfo, 0, sizeof(dialinginfo)); - if (e_dialinginfo.keypad[0]) - SCPY(dialinginfo.keypad, number); - else - SCPY(dialinginfo.id, number); - dialinginfo.itype = INFO_ITYPE_ISDN; - dialinginfo.ntype = e_dialinginfo.ntype; - dialinginfo.sending_complete = e_dialinginfo.sending_complete; - portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb); - if (!portlist) { - PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial); - delete port; - goto check_anycall_extern; - } -//printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id); - message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP); - memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info)); - memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info)); - memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info)); - memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info)); - memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info)); -//terminal SCPY(message->param.setup.from_terminal, e_ext.number); -//terminal if (e_dialinginfo.id) -//terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id); - /* handle restricted caller ids */ - apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name); - apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name); - apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL); - /* display callerid if desired for extension */ - SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name)); - message_put(message); - logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); - anycall = 1; - } while(*p); + } + if (!port) + FATAL("No memory for Port instance\n"); + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name); + memset(&dialinginfo, 0, sizeof(dialinginfo)); + if (e_dialinginfo.keypad[0]) + SCPY(dialinginfo.keypad, number); + else + SCPY(dialinginfo.id, number); + dialinginfo.itype = INFO_ITYPE_ISDN; + dialinginfo.ntype = e_dialinginfo.ntype; + dialinginfo.sending_complete = e_dialinginfo.sending_complete; + portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb); + if (!portlist) { + PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial); + delete port; + continue; + } + //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id); + message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP); + memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info)); + memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info)); + memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info)); + memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info)); + memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info)); + //terminal SCPY(message->param.setup.from_terminal, e_ext.number); + //terminal if (e_dialinginfo.id) + //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id); + /* handle restricted caller ids */ + apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name); + apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name); + apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL); + /* display callerid if desired for extension */ + SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name)); + message_put(message); + logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); + anycall = 1; + + /* found an interface + * continue only if + is given, so every interface is calles parallel */ + if (e_dialinginfo.interfaces[0] != '+') + break; + } while (*ifname_p); + } while(*number_p); - check_anycall_extern: /* now we have all ports created */ if (!anycall) { trace_header("INTERFACE (no free ports found)", DIRECTION_NONE); @@ -1521,7 +1278,7 @@ int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index) { class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr); + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr); ea->out_setup(1); return 0; @@ -1643,7 +1400,8 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un /* 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); + 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 */ @@ -1847,8 +1605,7 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty } if (e_action) if (e_action->index==ACTION_OUTDIAL - || e_action->index==ACTION_EXTERNAL - || e_action->index==ACTION_REMOTE) { + || e_action->index==ACTION_EXTERNAL) { if (!e_extdialing) set_tone(portlist, "dialing"); else if (!e_extdialing[0]) @@ -2213,6 +1970,16 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, 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); @@ -2505,8 +2272,6 @@ void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, u 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); @@ -2550,86 +2315,6 @@ void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, u 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); @@ -2670,6 +2355,50 @@ void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, message_put(message); } +/* port MESSAGE_3PTY */ +void EndpointAppPBX::port_3pty(struct port_list *portlist, int message_type, union parameter *param) +{ + logmessage(message_type, param, portlist->port_id, DIRECTION_IN); + + struct lcr_msg *message; + int rc; + + /* 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 = param->threepty.begin; + message->param.threepty.end = param->threepty.end; + if (rc < 0) + message->param.threepty.error = 1; + else + message->param.threepty.result = 1; + message->param.threepty.invoke_id = param->threepty.invoke_id; + logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); + 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) @@ -2709,6 +2438,49 @@ void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_t } +/* 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 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 */ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param) @@ -2772,6 +2544,16 @@ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, uni port_facility(portlist, message_type, param); break; + case MESSAGE_3PTY: + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming 3PTY facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id); + 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); @@ -2890,6 +2672,26 @@ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, uni 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; + + 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); @@ -3109,6 +2911,13 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int 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 */ @@ -3414,6 +3223,56 @@ void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, uni } } +/* 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 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) @@ -3585,6 +3444,30 @@ void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, uni 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; + + /* 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); } @@ -3636,10 +3519,8 @@ void EndpointAppPBX::pick_join(char *extensions) 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) { @@ -3650,7 +3531,6 @@ void EndpointAppPBX::pick_join(char *extensions) if (port->p_type == PORT_TYPE_VBOX_OUT) { if (match_list(extensions, eapp->e_ext.number)) { found = eapp; - vbox = 1; break; } } @@ -3811,49 +3691,50 @@ reject: /* join calls (look for a join that is on hold (same isdn interface/terminal)) */ -void 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); if (!our_join) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial); - return; + 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; + 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; + 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; + 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; + 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; + return -1; } 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) { @@ -3870,7 +3751,7 @@ void EndpointAppPBX::join_join(void) || 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 (other_pdss1->p_m_hold /* port is on hold */ + 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; @@ -3885,155 +3766,643 @@ void EndpointAppPBX::join_join(void) } if (!other_eapp) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial); - return; + 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; + 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; + 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; + 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; + 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(&our_joinpbx->j_updatebridge); + 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; +} -/* check if we have an external call - * this is used to check for encryption ability +/* join calls (look for a join that is on hold (same fxs interface/terminal)) */ -int EndpointAppPBX::check_external(const char **errstr, class Port **port) +int EndpointAppPBX::join_join_fxs(void) { - struct join_relation *relation; - class Join *join; - class JoinPBX *joinpbx; - class Endpoint *epoint; +#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; - /* some paranoia check */ + /* 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) error: we have no port.\n", ea_endpoint->ep_serial); - *errstr = "No Call"; - return(1); + 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) error: we are not internal extension.\n", ea_endpoint->ep_serial); - *errstr = "No Call"; - return(1); + 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; - /* check if we have a join with 2 parties */ - join = find_join_id(ea_endpoint->ep_join_id); - if (!join) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial); - *errstr = "No Call"; - return(1); + /* 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 (join->j_type != JOIN_TYPE_PBX) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial); - *errstr = "No PBX Call"; - return(1); + if (!other_eapp) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial); + return -1; } - joinpbx = (class JoinPBX *)join; - relation = joinpbx->j_relation; - if (!relation) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial); - *errstr = "No Call"; - 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; } - if (!relation->next) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial); - *errstr = "No Call"; - 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 (relation->next->next) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial); - *errstr = "Err: Conference"; - 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; } - if (relation->epoint_id == ea_endpoint->ep_serial) { - relation = relation->next; - if (relation->epoint_id == ea_endpoint->ep_serial) { - PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial); - *errstr = "Software Error"; - 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; } - /* check remote port for external call */ - epoint = find_epoint_id(relation->epoint_id); - if (!epoint) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial); + /* 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 +#else + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial); +#endif + + 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 + */ +int EndpointAppPBX::check_external(const char **errstr, class Port **port) +{ + struct join_relation *relation; + class Join *join; + class JoinPBX *joinpbx; + class Endpoint *epoint; + + /* some paranoia check */ + if (!ea_endpoint->ep_portlist) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial); + *errstr = "No Call"; + return(1); + } + if (!e_ext.number[0]) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial); + *errstr = "No Call"; + return(1); + } + + /* check if we have a join with 2 parties */ + join = find_join_id(ea_endpoint->ep_join_id); + if (!join) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial); + *errstr = "No Call"; + return(1); + } + if (join->j_type != JOIN_TYPE_PBX) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial); + *errstr = "No PBX Call"; + return(1); + } + joinpbx = (class JoinPBX *)join; + relation = joinpbx->j_relation; + if (!relation) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial); + *errstr = "No Call"; + return(1); + } + if (!relation->next) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial); + *errstr = "No Call"; + return(1); + } + if (relation->next->next) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial); + *errstr = "Err: Conference"; + return(1); + } + if (relation->epoint_id == ea_endpoint->ep_serial) { + relation = relation->next; + if (relation->epoint_id == ea_endpoint->ep_serial) { + PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial); + *errstr = "Software Error"; + return(1); + } + } + + /* check remote port for external call */ + epoint = find_epoint_id(relation->epoint_id); + if (!epoint) { + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial); *errstr = "No Call"; return(1); } @@ -4061,6 +4430,30 @@ int EndpointAppPBX::check_external(const char **errstr, class Port **port) 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"; @@ -4075,6 +4468,10 @@ void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsign 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: @@ -4460,6 +4857,50 @@ void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsign break; #endif + case MESSAGE_3PTY: + if (param->threepty.begin) + trace_header("Begin3PTY", dir); + if (param->threepty.end) + trace_header("End3PTY", dir); + if (param->threepty.invoke) + add_trace("action", NULL, "invoke"); + if (param->threepty.result) + add_trace("action", NULL, "result"); + if (param->threepty.error) + add_trace("action", NULL, "error"); + add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id); + 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; + + 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; + default: PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type); } @@ -4493,3 +4934,38 @@ void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cau 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); +} +