X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=apppbx.cpp;h=2a76c899697659fe3cacc3919645d874c398755a;hp=2a91364c3c03b22cc749fe0352c0ef339cd70ed9;hb=948b837669d36fc4aeea37cc7a6a674b127313f1;hpb=2188efe2cc9dfb473bf41540960382d7c43b892e diff --git a/apppbx.cpp b/apppbx.cpp index 2a91364..2a76c89 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -14,13 +14,46 @@ class EndpointAppPBX *apppbx_first = NULL; +int action_timeout(struct lcr_timer *timer, void *instance, int index); +int match_timeout(struct lcr_timer *timer, void *instance, int index); +int redial_timeout(struct lcr_timer *timer, void *instance, int index); +int powerdial_timeout(struct lcr_timer *timer, void *instance, int index); +int cfnr_timeout(struct lcr_timer *timer, void *instance, int index); +int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index); +int password_timeout(struct lcr_timer *timer, void *instance, int index); +int callback_timeout(struct lcr_timer *timer, void *instance, int index); + /* * EndpointAppPBX constructor */ -EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin) +EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin, EAPP_TYPE_PBX) { class EndpointAppPBX **apppointer; +#ifdef WITH_CRYPT + memset(&e_crypt_handler, 0, sizeof(e_crypt_handler)); + add_timer(&e_crypt_handler, crypt_handler, this, 0); +#endif + memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh)); + add_timer(&e_vbox_refresh, vbox_refresh, this, 0); + memset(&e_action_timeout, 0, sizeof(e_action_timeout)); + add_timer(&e_action_timeout, action_timeout, this, 0); + memset(&e_match_timeout, 0, sizeof(e_match_timeout)); + add_timer(&e_match_timeout, match_timeout, this, 0); + memset(&e_redial_timeout, 0, sizeof(e_redial_timeout)); + add_timer(&e_redial_timeout, redial_timeout, this, 0); + memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout)); + add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0); + memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout)); + add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0); + memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout)); + add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0); + memset(&e_callback_timeout, 0, sizeof(e_callback_timeout)); + add_timer(&e_callback_timeout, callback_timeout, this, 0); + memset(&e_password_timeout, 0, sizeof(e_password_timeout)); + add_timer(&e_password_timeout, password_timeout, this, 0); + e_powerdial_on = 0; + /* add application to chain */ next = NULL; apppointer = &apppbx_first; @@ -41,6 +74,7 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp memset(&e_connectinfo, 0, sizeof(struct connect_info)); memset(&e_redirinfo, 0, sizeof(struct redir_info)); memset(&e_capainfo, 0, sizeof(struct capa_info)); + memset(&e_rtpinfo, 0, sizeof(struct rtp_info)); e_start = e_stop = 0; e_origin = origin; e_ruleset = ruleset_main; @@ -48,8 +82,6 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp e_rule = e_ruleset->rule_first; e_rule_nesting = 0; e_action = NULL; - e_action_timeout = 0; - e_match_timeout = 0; e_match_to_action = NULL; e_select = 0; e_extdialing = e_dialinginfo.id; @@ -58,13 +90,10 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp e_hold = 0; // e_join_tone[0] = e_hold_tone[0] = '\0'; e_join_pattern /*= e_hold_pattern*/ = 0; - e_redial = 0; e_tone[0] = '\0'; e_adminid = 0; // will be set, if call was initiated via admin socket - e_powerdialing = 0; e_powerdelay = 0; e_powerlimit = 0; - e_callback = 0; e_cbdialing[0] = '\0'; e_cbcaller[0] = '\0'; e_cbto[0] = '\0'; @@ -74,16 +103,15 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp e_dtmf_time = 0; e_dtmf_last = 0; e_enablekeypad = 0; - e_cfnr_release = 0; - e_cfnr_call = 0; - e_password_timeout = 0; e_multipoint_cause = 0; e_multipoint_location = 0; e_dialing_queue[0] = '\0'; +#ifdef WITH_CRYPT e_crypt = CRYPT_OFF; e_crypt_state = CM_ST_NULL; e_crypt_keyengine_busy = 0; - e_crypt_info[0] = '\0'; + e_crypt_info[0] = '\0'; +#endif e_overlap = 0; e_vbox[0] = '\0'; e_tx_state = NOTIFY_STATE_ACTIVE; @@ -107,6 +135,19 @@ EndpointAppPBX::~EndpointAppPBX(void) { class EndpointAppPBX *temp, **tempp; +#ifdef WITH_CRYPT + del_timer(&e_crypt_handler); +#endif + del_timer(&e_vbox_refresh); + del_timer(&e_action_timeout); + del_timer(&e_match_timeout); + del_timer(&e_redial_timeout); + del_timer(&e_powerdial_timeout); + del_timer(&e_cfnr_timeout); + del_timer(&e_cfnr_call_timeout); + del_timer(&e_callback_timeout); + del_timer(&e_password_timeout); + /* detach */ temp =apppbx_first; tempp = &apppbx_first; @@ -136,7 +177,7 @@ void EndpointAppPBX::trace_header(const char *name, int direction) SCPY(msgtext, name); /* init trace with given values */ - start_trace(0, + start_trace(-1, NULL, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international), e_dialinginfo.id, @@ -167,7 +208,7 @@ void EndpointAppPBX::new_state(int state) /* release join and port (as specified) */ -void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause) +void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force) { struct port_list *portlist; struct lcr_msg *message; @@ -204,6 +245,7 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE); message->param.disconnectinfo.cause = portcause; message->param.disconnectinfo.location = portlocation; + message->param.disconnectinfo.force = force; // set, if port should release imediately message_put(message); logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); } @@ -211,7 +253,7 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p } /* if callback is enabled, call back with the given caller id */ - if (e_callback) { + if (e_callback_timeout.active) { /* reset some stuff */ new_state(EPOINT_STATE_IDLE); memset(&e_connectinfo, 0, sizeof(struct connect_info)); @@ -221,8 +263,10 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p if (e_ruleset) e_rule = e_ruleset->rule_first; e_action = NULL; - e_action_timeout = 0; - e_match_timeout = 0; + unsched_timer(&e_action_timeout); + unsched_timer(&e_match_timeout); + unsched_timer(&e_cfnr_timeout); + unsched_timer(&e_cfnr_call_timeout); e_match_to_action = NULL; //e_select = 0; e_extdialing = e_dialinginfo.id; @@ -231,15 +275,15 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p e_dtmf_time = 0; e_dtmf_last = 0; e_enablekeypad = 0; - e_cfnr_release = 0; - e_cfnr_call = 0; e_multipoint_cause = 0; e_multipoint_location = 0; e_dialing_queue[0] = '\0'; +#ifdef WITH_CRYPT e_crypt = 0; e_crypt_state = CM_ST_NULL; e_crypt_keyengine_busy = 0; e_crypt_info[0] = '\0'; +#endif e_tone[0] = '\0'; e_overlap = 0; e_vbox[0] = '\0'; @@ -273,7 +317,8 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p } PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial); - ea_endpoint->ep_use--; /* when e_lock is 0, the endpoint will be deleted */ + if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */ + trigger_work(&ea_endpoint->ep_delete); return; } } @@ -473,6 +518,7 @@ void EndpointAppPBX::keypad_function(char digit) join_join(); break; +#ifdef WITH_CRYPT /* crypt shared */ case '7': PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial); @@ -490,6 +536,7 @@ void EndpointAppPBX::keypad_function(char digit) PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial); encrypt_off(); break; +#endif default: PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit); @@ -538,238 +585,11 @@ void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone) } -/* - * 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; - - interface = interface_first; - - /* first find the given interface or, if not given, one with no extension */ - checknext: - if (!interface) - return(NULL); - - /* check for given interface */ - if (ifname) { - if (!strcasecmp(interface->name, ifname)) { - /* found explicit interface */ - trace_header("CHANNEL SELECTION (found interface)", DIRECTION_NONE); - add_trace("interface", NULL, "%s", ifname); - end_trace(); - goto foundif; - } - - } else { - if (!interface->extension) { - /* found non extension */ - trace_header("CHANNEL SELECTION (found non extension 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; - 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 */ -} - /* outgoing setup to port(s) * ports will be created and a setup is sent if everything is ok. otherwhise * the endpoint is destroyed. */ -void EndpointAppPBX::out_setup(void) +void EndpointAppPBX::out_setup(int cfnr) { struct dialing_info dialinginfo; class Port *port; @@ -779,16 +599,24 @@ void EndpointAppPBX::out_setup(void) int cause = CAUSE_RESSOURCEUNAVAIL; const char *p; char cfp[64]; + struct interface *interface; +#ifdef WITH_MISDN struct mISDNport *mISDNport; +#endif char portname[32]; char *dirname; class EndpointAppPBX *atemp; // 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; +#endif + struct admin_list *admin; int earlyb; int mode = B_MODE_TRANSPARENT; @@ -820,7 +648,7 @@ void EndpointAppPBX::out_setup(void) } if (atemp) { PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial); - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYSPE_ join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */ return; /* must exit here */ } } @@ -833,9 +661,10 @@ void EndpointAppPBX::out_setup(void) // if (!read_extension(&e_ext, exten)) if (!read_extension(&e_ext, e_dialinginfo.id)) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id); - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ return; /* must exit here */ } + e_dialinginfo.sending_complete = 1; if (e_dialinginfo.itype == INFO_ITYPE_VBOX) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial); @@ -877,7 +706,7 @@ void EndpointAppPBX::out_setup(void) p = e_ext.cfnr; if (*p) { /* when cfnr is done, out_setup() will setup the call */ - if (e_cfnr_call) { + if (cfnr) { /* present to forwarded party */ if (e_ext.anon_ignore && e_callerinfo.id[0]) { e_callerinfo.present = INFO_PRESENT_ALLOWED; @@ -885,8 +714,8 @@ void EndpointAppPBX::out_setup(void) goto cfnr_only; } if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) { - e_cfnr_release = now + e_ext.cfnr_delay; - e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */ + schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0); + schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) setting time for call-forward-busy to %s with delay %ld.\n", ea_endpoint->ep_serial, e_ext.cfnr, e_ext.cfnr_delay); } } @@ -895,41 +724,96 @@ void EndpointAppPBX::out_setup(void) p = e_ext.interfaces; PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p); while(*p) { + earlyb = 0; ifname[0] = '\0'; while(*p!=',' && *p!='\0') if (*p > ' ') SCCAT(ifname, *p++); if (*p == ',') p++; - /* found interface */ - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname); - /* hunt for mISDNport and create Port */ - mISDNport = hunt_port(ifname, &channel); - if (!mISDNport) { - trace_header("INTERFACE (not found or busy)", DIRECTION_NONE); + /* search interface */ + interface = hunt_interface(ifname); + if (!interface) { + trace_header("INTERFACE (not found)", DIRECTION_NONE); add_trace("interface", NULL, "%s", ifname); end_trace(); continue; } - /* creating INTERNAL port */ - SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); - if (!mISDNport->gsm) + /* 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); + 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, &channel); + if (!mISDNport) { + trace_header("INTERFACE (busy)", DIRECTION_NONE); + add_trace("interface", NULL, "%s", ifname); + end_trace(); + continue; + } + + SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); +#ifdef WITH_SS5 + if (mISDNport->ss5) + 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); - else -#ifdef WITH_GSM - port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); + earlyb = mISDNport->earlyb; #else - port = NULL; + 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"); + FATAL("Failed to create Port instance\n"); PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name); memset(&dialinginfo, 0, sizeof(dialinginfo)); SCPY(dialinginfo.id, e_dialinginfo.id); dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION; dialinginfo.ntype = e_dialinginfo.ntype; /* create port_list relation */ - portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb); + 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; @@ -949,6 +833,7 @@ void EndpointAppPBX::out_setup(void) 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); @@ -1021,16 +906,24 @@ void EndpointAppPBX::out_setup(void) p++; /* external call */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp); +#ifdef WITH_MISDN /* hunt for mISDNport and create Port */ mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel); if (mISDNport) { /* 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 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); if (!port) FATAL("No memory for Port instance\n"); earlyb = mISDNport->earlyb; - } else { + } else +#endif + { port = NULL; trace_header("INTERFACE (too busy)", DIRECTION_NONE); add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface"); @@ -1087,86 +980,165 @@ void EndpointAppPBX::out_setup(void) end_trace(); if (!ea_endpoint->ep_join_id) break; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ return; /* must exit here */ } break; /* *********************** external call */ default: - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id); + 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 */ - p = e_dialinginfo.id; + if (e_dialinginfo.keypad[0]) + number_p = e_dialinginfo.keypad; + else + number_p = e_dialinginfo.id; do { 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"); - /* hunt for mISDNport and create Port */ - /* 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"); - end_trace(); - goto check_anycall_extern; - } - /* creating EXTERNAL port*/ - SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum); - if (!mISDNport->gsm) - 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); - else -#ifdef WITH_GSM - port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode); + + 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(); + continue; + } + /* found interface */ + 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); + 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 + 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; #else - port = NULL; + 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"); - earlyb = mISDNport->earlyb; - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name); - memset(&dialinginfo, 0, sizeof(dialinginfo)); - SCPY(dialinginfo.id, number); - dialinginfo.itype = INFO_ITYPE_ISDN; - dialinginfo.ntype = e_dialinginfo.ntype; - portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->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)); - SCPY(message->param.setup.dialinginfo.id, number); - 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)); -//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); end_trace(); if (!ea_endpoint->ep_join_id) break; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ return; /* must exit here */ } break; @@ -1174,163 +1146,157 @@ void EndpointAppPBX::out_setup(void) } +int action_timeout(struct lcr_timer *timer, void *instance, int index) +{ + class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; + + if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT) + return 0; -/* handler for endpoint - */ + unsched_timer(&ea->e_redial_timeout); + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial); + ea->e_multipoint_cause = 0; + ea->e_multipoint_location = 0; + ea->new_state(EPOINT_STATE_IN_OVERLAP); + ea->e_join_pattern = 0; + ea->process_dialing(1); + /* we must exit, because our endpoint might be gone */ -extern int quit; -int EndpointAppPBX::handler(void) + return 0; +} + +int match_timeout(struct lcr_timer *timer, void *instance, int index) { - if (e_crypt_state!=CM_ST_NULL) { - cryptman_handler(); - } - - /* process answering machine (play) handling */ - if (e_action) { - if (e_action->index == ACTION_VBOX_PLAY) - vbox_handler(); - - /* process action timeout */ - if (e_action_timeout) - if (now_d >= e_action_timeout) { - if (e_state!=EPOINT_STATE_CONNECT) { - e_redial = 0; - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea_endpoint->ep_serial); - e_multipoint_cause = 0; - e_multipoint_location = 0; - new_state(EPOINT_STATE_IN_OVERLAP); - e_join_pattern = 0; - process_dialing(); - return(1); /* we must exit, because our endpoint might be gone */ - } else - e_action_timeout = 0; - } - } else { - /* process action timeout */ - if (e_match_timeout) - if (now_d >= e_match_timeout) { - e_redial = 0; - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea_endpoint->ep_serial); - process_dialing(); - return(1); /* we must exit, because our endpoint might be gone */ - } + class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; + + if (!ea->e_action) { + unsched_timer(&ea->e_redial_timeout); + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial); + ea->process_dialing(0); + /* we must exit, because our endpoint might be gone */ } + return 0; +} - /* process redialing (epoint redials to port) */ - if (e_redial) { - if (now_d >= e_redial) { - e_redial = 0; - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea_endpoint->ep_serial); +int redial_timeout(struct lcr_timer *timer, void *instance, int index) +{ + class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; - new_state(EPOINT_STATE_OUT_SETUP); - /* call special setup routine */ - out_setup(); + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial); - return(1); - } - } + ea->new_state(EPOINT_STATE_OUT_SETUP); + /* call special setup routine */ + ea->out_setup(0); - /* process powerdialing (epoint redials to epoint) */ - if (e_powerdialing > 0) { - if (now_d >= e_powerdialing) { - e_powerdialing = -1; /* leave power dialing on */ - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea_endpoint->ep_serial); + return 0; +} - /* redial */ - e_ruleset = ruleset_main; - if (e_ruleset) - e_rule = e_ruleset->rule_first; - e_action = NULL; - new_state(EPOINT_STATE_IN_OVERLAP); - process_dialing(); - return(1); - } - } +int powerdial_timeout(struct lcr_timer *timer, void *instance, int index) +{ + class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; - /* process call forward no response */ - if (e_cfnr_release) { - struct port_list *portlist; - struct lcr_msg *message; + /* leave power dialing on */ + ea->e_powerdial_on = 1; + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial); - if (now >= e_cfnr_release) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea_endpoint->ep_serial); - e_cfnr_release = 0; + /* redial */ + ea->e_ruleset = ruleset_main; + if (ea->e_ruleset) + ea->e_rule = ea->e_ruleset->rule_first; + ea->e_action = NULL; + ea->new_state(EPOINT_STATE_IN_OVERLAP); + ea->process_dialing(0); - /* release all ports */ - while((portlist = ea_endpoint->ep_portlist)) { - message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */ - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); - ea_endpoint->free_portlist(portlist); - } - /* put on hold */ - message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH); - message->param.audiopath = 0; - message_put(message); - /* indicate no patterns */ - message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN); - message_put(message); - /* set setup state, since we have no response from the new join */ - new_state(EPOINT_STATE_OUT_SETUP); - } - } else - if (e_cfnr_call) { - if (now >= e_cfnr_call) { - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea_endpoint->ep_serial, e_ext.cfnr); - out_setup(); - e_cfnr_call = 0; - } + return 0; +} + +int cfnr_timeout(struct lcr_timer *timer, void *instance, int index) +{ + class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; + struct port_list *portlist; + struct lcr_msg *message; + + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial); + + /* release all ports */ + while((portlist = ea->ea_endpoint->ep_portlist)) { + message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE); + message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */ + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + message_put(message); + ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); + ea->ea_endpoint->free_portlist(portlist); } + /* put on hold */ + message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH); + message->param.audiopath = 0; + message_put(message); + /* indicate no patterns */ + message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN); + message_put(message); + /* set setup state, since we have no response from the new join */ + ea->new_state(EPOINT_STATE_OUT_SETUP); + + return 0; +} + +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); + ea->out_setup(1); - /* handle connection to user */ - if (e_state == EPOINT_STATE_IDLE) { + return 0; +} + +int callback_timeout(struct lcr_timer *timer, void *instance, int index) +{ + class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; + + if (ea->e_state == EPOINT_STATE_IDLE) { /* epoint is idle, check callback */ - if (e_callback) - if (now_d >= e_callback) { - e_callback = 0; /* done with callback */ - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea_endpoint->ep_serial); - new_state(EPOINT_STATE_OUT_SETUP); - out_setup(); - return(1); - } + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial); + ea->new_state(EPOINT_STATE_OUT_SETUP); + ea->out_setup(0); } - /* check for password timeout */ - if (e_action) - if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE) { + return 0; +} + +int password_timeout(struct lcr_timer *timer, void *instance, int index) +{ + class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; + + if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) { struct port_list *portlist; - if (now >= e_password_timeout) { - e_ruleset = ruleset_main; - if (e_ruleset) - e_rule = e_ruleset->rule_first; - e_action = NULL; - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea_endpoint->ep_serial, e_extdialing); - trace_header("PASSWORD timeout", DIRECTION_NONE); - end_trace(); - e_connectedmode = 0; - e_dtmf = 0; - new_state(EPOINT_STATE_OUT_DISCONNECT); - portlist = ea_endpoint->ep_portlist; - if (portlist) { - message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); - set_tone(portlist, "cause_10"); - } - return(1); + ea->e_ruleset = ruleset_main; + if (ea->e_ruleset) + ea->e_rule = ea->e_ruleset->rule_first; + ea->e_action = NULL; + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing); + ea->trace_header("PASSWORD timeout", DIRECTION_NONE); + end_trace(); + ea->e_connectedmode = 0; + ea->e_dtmf = 0; + ea->new_state(EPOINT_STATE_OUT_DISCONNECT); + portlist = ea->ea_endpoint->ep_portlist; + if (portlist) { + ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, ""); + ea->set_tone(portlist, "cause_10"); } } - - return(0); -} + return 0; +} /* doing a hookflash */ void EndpointAppPBX::hookflash(void) { class Port *port; + time_t now; /* be sure that we are active */ notify_active(); @@ -1351,7 +1317,7 @@ void EndpointAppPBX::hookflash(void) port->set_echotest(0); } if (ea_endpoint->ep_join_id) { - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ } e_ruleset = ruleset_main; if (e_ruleset) @@ -1364,10 +1330,11 @@ void EndpointAppPBX::hookflash(void) e_join_pattern = 0; if (e_dialinginfo.id[0]) { set_tone(ea_endpoint->ep_portlist, "dialing"); - process_dialing(); + process_dialing(0); } else { set_tone(ea_endpoint->ep_portlist, "dialpbx"); } + time(&now); e_dtmf_time = now; e_dtmf_last = '\0'; } @@ -1382,7 +1349,6 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un char buffer[256]; int writeext; /* flags need to write extension after modification */ class Port *port; - struct interface *interface; logmessage(message_type, param, portlist->port_id, DIRECTION_IN); @@ -1391,18 +1357,18 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo)); memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo)); memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo)); + memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo)); + + /* convert (inter-)national number type */ + SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international)); + e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN; + // e_dtmf = param->setup.dtmf; /* screen incoming caller id */ - interface = interface_first; - while(interface) { - if (!strcmp(e_callerinfo.interface, interface->name)) { - break; - } - interface = interface->next; - } - if (interface) { - do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface); - do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface); + if (e_callerinfo.interface[0]) { + do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface); + do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface); + do_screen(0, e_redirinfo.id, sizeof(e_redirinfo.id), &e_redirinfo.ntype, &e_redirinfo.present, e_callerinfo.interface); } /* process extension */ @@ -1517,7 +1483,7 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un else set_tone(portlist, "dialtone"); } - process_dialing(); + process_dialing(0); if (e_state == EPOINT_STATE_IN_SETUP) { /* request MORE info, if not already at higher state */ new_state(EPOINT_STATE_IN_OVERLAP); @@ -1530,6 +1496,8 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un /* port MESSAGE_INFORMATION */ void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param) { + struct lcr_msg *message; + logmessage(message_type, param, portlist->port_id, DIRECTION_IN); /* ignore information message without digit information */ @@ -1550,7 +1518,7 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty if (e_action->index == ACTION_VBOX_PLAY) { /* concat dialing string */ SCAT(e_dialinginfo.id, param->information.id); - process_dialing(); + process_dialing(0); return; } @@ -1566,7 +1534,13 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty /* keypad when connected */ if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) { - if (e_ext.keypad || e_enablekeypad) { + if (e_enablekeypad) { + message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type); + memcpy(&message->param, param, sizeof(union parameter)); + message_put(message); + return; + } + if (e_ext.keypad) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id); /* processing keypad function */ if (param->information.id[0] == '0') { @@ -1598,8 +1572,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]) @@ -1607,12 +1580,17 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty } /* concat dialing string */ SCAT(e_dialinginfo.id, param->information.id); - process_dialing(); + process_dialing(0); } /* port MESSAGE_DTMF */ void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param) { + time_t now; + struct lcr_msg *message; + + time(&now); + /* only if dtmf detection is enabled */ if (!e_dtmf) { trace_header("DTMF (disabled)", DIRECTION_IN); @@ -1632,7 +1610,7 @@ NOTE: vbox is now handled due to overlap state if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) { e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0'; e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf; - process_dialing(); + process_dialing(0); } /* continue to process *X# sequences */ } @@ -1640,6 +1618,12 @@ NOTE: vbox is now handled due to overlap state /* check for *X# sequence */ if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) { + if (e_enablekeypad) { + message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type); + memcpy(&message->param, param, sizeof(union parameter)); + message_put(message); + return; + } if (e_dtmf_time+3 < now) { /* the last digit was too far in the past to be a sequence */ if (param->dtmf == '*') @@ -1706,7 +1690,7 @@ NOTE: vbox is now handled due to overlap state if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) { e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0'; e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf; - process_dialing(); + process_dialing(0); } } } @@ -1714,11 +1698,13 @@ NOTE: vbox is now handled due to overlap state /* port MESSAGE_CRYPT */ void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param) { +#ifdef WITH_CRYPT /* send crypt response to cryptman */ if (param->crypt.type == CR_MESSAGE_IND) cryptman_msg2man(param->crypt.data, param->crypt.len); else cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len); +#endif } /* port MESSAGE_OVERLAP */ @@ -1859,7 +1845,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, unsigned int port_id = portlist->port_id; struct port_list *tportlist; class Port *port; - struct interface *interface; + time_t now; logmessage(message_type, param, portlist->port_id, DIRECTION_IN); @@ -1883,18 +1869,11 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, } PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial); + time(&now); e_start = now; - /* screen incoming connected id */ - interface = interface_first; - while(interface) { - if (!strcmp(e_connectinfo.interface, interface->name)) { - break; - } - interface = interface->next; - } - if (interface) - do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface); + if (e_callerinfo.interface[0]) + do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface); /* screen connected name */ if (e_ext.name[0]) @@ -1930,7 +1909,8 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, message_put(message); } - e_cfnr_call = e_cfnr_release = 0; + unsched_timer(&e_cfnr_timeout); + unsched_timer(&e_cfnr_call_timeout); if (e_ext.number[0]) e_dtmf = 1; /* allow dtmf */ @@ -1938,7 +1918,8 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, /* other calls with no caller id (or not available for the extension) and force colp */ if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) { e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT; - if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT || portlist->port_type==PORT_TYPE_GSM_OUT) { /* external extension answered */ + if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) { + /* external extension answered */ port = find_port_id(portlist->port_id); if (port) { SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international)); @@ -2004,12 +1985,12 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, /* make call state to enter password */ new_state(EPOINT_STATE_IN_OVERLAP); e_action = &action_password_write; - e_match_timeout = 0; + unsched_timer(&e_match_timeout); e_match_to_action = NULL; e_dialinginfo.id[0] = '\0'; e_extdialing = strchr(e_dialinginfo.id, '\0'); - e_password_timeout = now+20; - process_dialing(); + schedule_timer(&e_password_timeout, 20, 0); + process_dialing(0); } else { /* incoming call (callback) */ e_ruleset = ruleset_main; @@ -2019,7 +2000,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, e_extdialing = e_dialinginfo.id; if (e_dialinginfo.id[0]) { set_tone(portlist, "dialing"); - process_dialing(); + process_dialing(0); } else { set_tone(portlist, "dialpbx"); } @@ -2102,7 +2083,8 @@ void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int mes } } - e_cfnr_call = e_cfnr_release = 0; + unsched_timer(&e_cfnr_timeout); + unsched_timer(&e_cfnr_call_timeout); /* process hangup */ process_hangup(e_join_cause, e_join_location); @@ -2141,8 +2123,10 @@ void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int mes message_put(message); /* disable encryption if disconnected */ //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt); +#ifdef WITH_CRYPT if (e_crypt_state) cryptman_message(CI_DISCONNECT_IND, NULL, 0); +#endif return; } else { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial); @@ -2150,7 +2134,7 @@ void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int mes } if (message_type == MESSAGE_RELEASE) ea_endpoint->free_portlist(portlist); - release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */ + release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */ return; /* must exit here */ } @@ -2167,7 +2151,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, add_trace("state", NULL, "outgoing setup/dialing"); end_trace(); /* no user responding */ - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ case PORT_STATE_IN_SETUP: @@ -2182,7 +2166,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, end_trace(); param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */ param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ case PORT_STATE_IN_PROCEEDING: @@ -2196,7 +2180,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, end_trace(); param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */ param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ case PORT_STATE_CONNECT: @@ -2204,7 +2188,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, end_trace(); param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */ param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ case PORT_STATE_IN_ALERTING: @@ -2218,7 +2202,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, add_trace("state", NULL, "disconnect"); end_trace(); PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial); - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ default: @@ -2236,7 +2220,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, ""); portlist = portlist->next; } - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ } /* port MESSAGE_NOTIFY */ @@ -2379,6 +2363,25 @@ void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, u } +/* port MESSAGE_PROGRESS */ +void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param) +{ + logmessage(message_type, param, portlist->port_id, DIRECTION_IN); + + struct lcr_msg *message; + + /* signal to call tool */ + admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress); + + /* send progress to 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_PROGRESS); + memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info)); + message_put(message); + } + +} + /* port MESSAGE_FACILITY */ void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param) { @@ -2391,6 +2394,44 @@ 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; + +#if 0 + /* bridge for real */ + if (param->threepty.begin) + rc = join_join(); + else if (param->threepty.end) + rc = -ENOTSUP; + else + return; +#else + /* 3PTY bridge */ + if (param->threepty.begin) + rc = join_3pty(); + else if (param->threepty.end) + rc = split_3pty(); + else + return; +#endif + + 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_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) @@ -2406,15 +2447,40 @@ void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, ea_endpoint->free_portlist(portlist); } -/* port MESSAGE_RESUME */ -/* NOTE: before resume, the active-notification must be done in order to set call mixer */ -void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param) +/* port MESSAGE_RESUME */ +/* NOTE: before resume, the active-notification must be done in order to set call mixer */ +void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param) +{ + logmessage(message_type, param, portlist->port_id, DIRECTION_IN); + + /* epoint is now resumed */ + ea_endpoint->ep_park = 0; + +} + +/* port MESSAGE_ENABLEKEYPAD */ +void EndpointAppPBX::port_enablekeypad(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_ENABLEKEYPAD); + memcpy(&message->param, param, sizeof(union parameter)); + message_put(message); +} + + +/* port MESSAGE_DISABLE_DEJITTER */ +void EndpointAppPBX::port_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param) { - logmessage(message_type, param, portlist->port_id, DIRECTION_IN); + struct lcr_msg *message; - /* epoint is now resumed */ - ea_endpoint->ep_park = 0; + 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); } @@ -2437,17 +2503,6 @@ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, uni // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id); switch(message_type) { - case MESSAGE_DATA: /* data from port */ - /* check if there is a call */ - if (!ea_endpoint->ep_join_id) - break; - /* continue if only one portlist */ - if (ea_endpoint->ep_portlist->next != NULL) - break; - /* forward message */ - message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param); - break; - case MESSAGE_TONE_EOF: /* tone is end of file */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial); if (e_action) { @@ -2492,6 +2547,11 @@ 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; + /* 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); @@ -2575,6 +2635,12 @@ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, uni port_notify(portlist, message_type, param); break; + /* PORT sends a PROGRESS message */ + case MESSAGE_PROGRESS: + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received progress.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id); + port_progress(portlist, message_type, param); + break; + /* PORT sends a SUSPEND message */ case MESSAGE_SUSPEND: PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received suspend.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id); @@ -2598,6 +2664,17 @@ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, uni break; #endif + /* PORT requests DTMF */ + case MESSAGE_ENABLEKEYPAD: + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') requests DTMF/KEYPAD.\n", ea_endpoint->ep_serial, 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); @@ -2612,6 +2689,7 @@ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, uni /* join MESSAGE_CRYPT */ void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param) { +#ifdef WITH_CRYPT switch(param->crypt.type) { /* message from remote port to "crypt manager" */ case CU_ACTK_REQ: /* activate key-exchange */ @@ -2635,6 +2713,7 @@ void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, un default: PERROR("EPOINT(%d) epoint with terminal '%s' (caller id '%s') unknown crypt message: '%d'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->crypt.type); } +#endif } /* join MESSAGE_INFORMATION */ @@ -2767,6 +2846,7 @@ void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param) { struct lcr_msg *message; + time_t now; new_state(EPOINT_STATE_CONNECT); // UCPY(e_join_tone, ""); @@ -2774,7 +2854,8 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, if (e_ext.number[0]) e_dtmf = 1; /* allow dtmf */ - e_powerdialing = 0; + e_powerdial_on = 0; + unsched_timer(&e_powerdial_timeout); memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo)); if(portlist) { message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT); @@ -2811,6 +2892,7 @@ void EndpointAppPBX::join_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); + time(&now); e_start = now; } @@ -2820,18 +2902,19 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter * char cause[16]; struct lcr_msg *message; struct port_list *portlist = NULL; + time_t now; /* be sure that we are active */ notify_active(); e_tx_state = NOTIFY_STATE_ACTIVE; - /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */ - if (e_powerdialing && ((e_powercount+1)ep_portlist) { /* or no port */ process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location); - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */ return; /* must exit here */ } /* save cause */ @@ -2900,7 +2984,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter * || !e_join_pattern) { /* no patterns */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have own cause or we have no patterns. (own_cause=%d pattern=%d)\n", ea_endpoint->ep_serial, e_ext.own_cause, e_join_pattern); if (message_type != MESSAGE_RELEASE) - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ e_join_pattern = 0; } else { /* else we enable audio */ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH); @@ -2953,11 +3037,11 @@ void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, un new_state(EPOINT_STATE_OUT_OVERLAP); /* get time */ - e_redial = now_d + 1; /* set redial one second in the future */ + schedule_timer(&e_redial_timeout, 1, 0); return; } /* if we have a pending redial, so we just adjust the dialing number */ - if (e_redial) { + if (e_redial_timeout.active) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) redial in progress, so we update the dialing number to %s.\n", ea_endpoint->ep_serial, param->setup.dialinginfo.id); memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo)); return; @@ -3006,6 +3090,7 @@ void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, un memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo)); memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo)); memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo)); + memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo)); /* process (voice over) data calls */ if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) { @@ -3018,7 +3103,7 @@ void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, un new_state(EPOINT_STATE_OUT_SETUP); /* call special setup routine */ - out_setup(); + out_setup(0); } /* join MESSAGE_mISDNSIGNAL */ @@ -3034,6 +3119,19 @@ void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_ty } } +/* join MESSAGE_BRIDE */ +void EndpointAppPBX::join_bridge(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_BRIDGE); + memcpy(&message->param, param, sizeof(union parameter)); + message_put(message); + portlist = portlist->next; + } +} + /* join MESSAGE_NOTIFY */ void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param) { @@ -3088,6 +3186,32 @@ void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, u } } +/* join MESSAGE_DTMF */ +void EndpointAppPBX::join_dtmf(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_DTMF); + memcpy(&message->param, param, sizeof(union parameter)); + message_put(message); + portlist = portlist->next; + } +} + +/* 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) @@ -3102,21 +3226,6 @@ void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, uni portlist = ea_endpoint->ep_portlist; - /* send MESSAGE_DATA to port */ - if (message_type == MESSAGE_DATA) { - if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN - /* skip if no port relation */ - if (!portlist) - return; - /* skip if more than one port relation */ - if (portlist->next) - return; - /* forward audio data to port */ - message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param); - return; - } - } - // PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received message %d for active JOIN (terminal %s, caller id %s state=%d)\n", ea_endpoint->ep_serial, message, e_ext.number, e_callerinfo.id, e_state); switch(message_type) { /* JOIN SENDS TONE message */ @@ -3206,23 +3315,11 @@ void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, uni join_mISDNsignal(portlist, message_type, param); break; -#if 0 - kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert - /* JOIN requests bchannel */ - case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */ - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel assignment %d from join.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type); - /* only one port is expected to be connected to bchannel */ - if (!portlist) - break; - if (portlist->next) - break; - e_join_pattern = 1; - SCPY(e_tone, ""); - set_tone(portlist, NULL); - message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param); - logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); + /* JOIN sends bridge message */ + case MESSAGE_BRIDGE: /* bride message to port */ + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bridge message.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id); + join_bridge(portlist, message_type, param); break; -#endif /* JOIN has pattern available */ case MESSAGE_PATTERN: /* indicating pattern available */ @@ -3280,6 +3377,18 @@ void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, uni end_trace(); break; + /* JOIN sends a DTMF message */ + case MESSAGE_DTMF: + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received dtmf.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id); + 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); } @@ -3299,7 +3408,7 @@ int match_list(char *list, char *item) while(42) { /* eliminate white spaces */ - while (*list <= ' ') + while (*list > '\0' && *list <= ' ') list++; if (*list == ',') { list++; @@ -3349,7 +3458,7 @@ void EndpointAppPBX::pick_join(char *extensions) break; } } - if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT) + if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT && port->p_state==PORT_STATE_OUT_ALERTING) if (match_list(extensions, eapp->e_ext.number)) { found = eapp; @@ -3476,7 +3585,7 @@ reject: message_put(message); /* beeing paranoid, we make call update */ - joinpbx->j_updatebridge = 1; + trigger_work(&joinpbx->j_updatebridge); if (options.deb & DEBUG_EPOINT) { class Join *debug_c = join_first; @@ -3506,48 +3615,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(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_mISDN_DSS1) { + 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) { @@ -3564,7 +3675,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; @@ -3579,87 +3690,279 @@ 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(&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(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 */ - our_joinpbx->j_updatebridge = 1; /* update mixer flag */ + 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 @@ -3739,7 +4042,7 @@ int EndpointAppPBX::check_external(const char **errstr, class Port **port) *errstr = "No Call"; return(1); } - if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */ + if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial); *errstr = "No Ext Call"; return(1); @@ -3766,6 +4069,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: @@ -3805,6 +4112,8 @@ void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsign } if (param->setup.dialinginfo.id[0]) add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id); + if (param->setup.dialinginfo.keypad[0]) + add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad); if (param->setup.dialinginfo.display[0]) add_trace("display", NULL, "%s", param->setup.dialinginfo.display); if (param->setup.dialinginfo.sending_complete) @@ -4011,6 +4320,65 @@ void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsign end_trace(); break; + case MESSAGE_PROGRESS: + switch(param->progressinfo.progress) { + case 0x01: + logtext = "Call is not end to end ISDN"; + break; + case 0x02: + logtext = "Destination address is non-ISDN"; + break; + case 0x03: + logtext = "Origination address is non-ISDN"; + break; + case 0x04: + logtext = "Call has returned to the ISDN"; + break; + case 0x08: + logtext = "In-band info or pattern available"; + break; + default: + SPRINT(buffer, "%d", param->progressinfo.progress); + logtext = buffer; + + } + trace_header("PROGRESS", 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); + add_trace("indicator", NULL, "%s", logtext); + switch(param->progressinfo.location) { + case LOCATION_USER: + add_trace("cause", "location", "0-User"); + break; + case LOCATION_PRIVATE_LOCAL: + add_trace("cause", "location", "1-Local-PBX"); + break; + case LOCATION_PUBLIC_LOCAL: + add_trace("cause", "location", "2-Local-Exchange"); + break; + case LOCATION_TRANSIT: + add_trace("cause", "location", "3-Transit"); + break; + case LOCATION_PUBLIC_REMOTE: + add_trace("cause", "location", "4-Remote-Exchange"); + break; + case LOCATION_PRIVATE_REMOTE: + add_trace("cause", "location", "5-Remote-PBX"); + break; + case LOCATION_INTERNATIONAL: + add_trace("cause", "location", "7-International-Exchange"); + break; + case LOCATION_BEYOND: + add_trace("cause", "location", "10-Beyond-Interworking"); + break; + default: + add_trace("cause", "location", "%d", param->progressinfo.location); + } + end_trace(); + break; + case MESSAGE_INFORMATION: trace_header("INFORMATION", dir); if (dir == DIRECTION_OUT) @@ -4090,6 +4458,28 @@ 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_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); }