Adding bridge between protocol handlers (ports)
[lcr.git] / apppbx.cpp
index 46b1f62..1b119b2 100644 (file)
@@ -201,7 +201,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;
@@ -238,6 +238,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);
                        }
@@ -594,7 +595,7 @@ struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
        if (!interface) {
                if (!there_is_an_external && !(ifname && ifname[0])) {
                        trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
-                       add_trace("info", NULL, "Add 'external' parameter to interface.conf.");
+                       add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
                        end_trace();
                }
                return(NULL);
@@ -828,7 +829,7 @@ foundif:
  * 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;
@@ -850,6 +851,7 @@ void EndpointAppPBX::out_setup(void)
        int                     channel = 0;
        int                     earlyb;
        int                     mode = B_MODE_TRANSPARENT;
+       struct admin_list       *admin;
 
        /* set bchannel mode */
        mode = e_capainfo.source_mode;
@@ -879,7 +881,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 */
                        }
                }
@@ -892,9 +894,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);
@@ -936,7 +939,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_timeout.active) {
+                       if (cfnr) {
                                /* present to forwarded party */
                                if (e_ext.anon_ignore && e_callerinfo.id[0]) {
                                        e_callerinfo.present = INFO_PRESENT_ALLOWED;
@@ -977,16 +980,39 @@ void EndpointAppPBX::out_setup(void)
                                port = ss5_hunt_line(mISDNport);
                        else
 #endif
-                       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);
+#ifdef WITH_GSM_BS
+                       if (mISDNport->gsm_bs)
+                               port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                       else
+#endif
+#ifdef WITH_GSM_MS
+                       if (mISDNport->gsm_ms)
+                               port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                       else
+#endif
+#ifdef WITH_SIP
+                       if (mISDNport->ifport->interface->sip)
+                               port = new Psip(PORT_TYPE_SIP_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, mISDNport->ifport->interface);
                        else
-#ifdef WITH_GSM
-                               port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
-#else
-                               port = NULL;
 #endif
+                       if (mISDNport->ifport->remote) {
+                               admin = admin_first;
+                               while(admin) {
+                                       if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
+                                               break;
+                                       admin = admin->next;
+                               }
+                               if (!admin) {
+                                       trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
+                                       add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
+                                       end_trace();
+                                       continue;
+                               }
+                               port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
+                       } else
+                               port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
                        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);
@@ -1156,7 +1182,7 @@ 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;
@@ -1193,14 +1219,37 @@ void EndpointAppPBX::out_setup(void)
                                port = ss5_hunt_line(mISDNport);
                        else
 #endif
-                       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);
+#ifdef WITH_GSM_BS
+                       if (mISDNport->gsm_bs)
+                               port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                       else
+#endif
+#ifdef WITH_GSM_MS
+                       if (mISDNport->gsm_ms)
+                               port = new Pgsm_ms(PORT_TYPE_GSM_MS_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);
-#else
-                               port = NULL;
 #endif
+#ifdef WITH_SIP
+                       if (mISDNport->ifport->interface->sip)
+                               port = new Psip(PORT_TYPE_SIP_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, mISDNport->ifport->interface);
+                       else
+#endif
+                       if (mISDNport->ifport->remote) {
+                               admin = admin_first;
+                               while(admin) {
+                                       if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
+                                               break;
+                                       admin = admin->next;
+                               }
+                               if (!admin) {
+                                       trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
+                                       add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
+                                       end_trace();
+                                       continue;
+                               }
+                               port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
+                       } else
+                               port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
                        if (!port)
                                FATAL("No memory for Port instance\n");
                        earlyb = mISDNport->earlyb;
@@ -1212,6 +1261,7 @@ void EndpointAppPBX::out_setup(void)
                                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, mISDNport->earlyb);
                        if (!portlist) {
                                PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
@@ -1245,7 +1295,7 @@ void EndpointAppPBX::out_setup(void)
                        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;
@@ -1294,7 +1344,7 @@ int redial_timeout(struct lcr_timer *timer, void *instance, int index)
 
        ea->new_state(EPOINT_STATE_OUT_SETUP);
        /* call special setup routine */
-       ea->out_setup();
+       ea->out_setup(0);
 
        return 0;
 }
@@ -1353,7 +1403,7 @@ int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
        class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
 
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr);
-       ea->out_setup();
+       ea->out_setup(1);
 
        return 0;
 }
@@ -1366,7 +1416,7 @@ int callback_timeout(struct lcr_timer *timer, void *instance, int index)
                /* epoint is idle, check callback */
                PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
                ea->new_state(EPOINT_STATE_OUT_SETUP);
-               ea->out_setup();
+               ea->out_setup(0);
        }
 
        return 0;
@@ -1424,7 +1474,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)
@@ -1609,6 +1659,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 */
@@ -1645,7 +1697,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') {
@@ -1693,6 +1751,7 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty
 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
 {
        time_t now;
+       struct lcr_msg          *message;
 
        time(&now);
 
@@ -1723,6 +1782,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 == '*')
@@ -2024,7 +2089,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));
@@ -2237,7 +2303,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 */
 }
 
@@ -2254,7 +2320,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:
@@ -2269,7 +2335,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:
@@ -2283,7 +2349,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:
@@ -2291,7 +2357,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:
@@ -2305,7 +2371,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:
@@ -2323,7 +2389,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 */
@@ -2466,6 +2532,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, &param->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)
 {
@@ -2504,6 +2589,18 @@ void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, u
 
 }
 
+/* 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 sends message to the endpoint
  */
@@ -2524,17 +2621,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) {
@@ -2662,6 +2748,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);
@@ -2685,6 +2777,12 @@ 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;
+
 
                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);
@@ -2919,7 +3017,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *
 
        /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
        if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
-               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 */
 
                /* set time for power dialing */
                schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
@@ -2970,7 +3068,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *
          && e_state!=EPOINT_STATE_IN_ALERTING)
         || !ea_endpoint->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 */
@@ -2992,7 +3090,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);
@@ -3110,7 +3208,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 */
@@ -3126,6 +3224,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)
 {
@@ -3180,6 +3291,19 @@ 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 sends messages to the endpoint
  */
 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
@@ -3194,21 +3318,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 */
@@ -3298,23 +3407,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 */
@@ -3372,6 +3469,12 @@ 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;
+
                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);
        }
@@ -3391,7 +3494,7 @@ int match_list(char *list, char *item)
 
        while(42) {
                /* eliminate white spaces */
-               while (*list <= ' ')
+               while (*list > '\0' && *list <= ' ')
                        list++;
                if (*list == ',') {
                        list++;
@@ -3441,7 +3544,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;
@@ -3633,7 +3736,7 @@ void EndpointAppPBX::join_join(void)
                PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
                return;
        }
-       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;
        }
@@ -3831,7 +3934,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);
@@ -4105,6 +4208,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)