Allow calls to multiple interfaces simultaniosuly
[lcr.git] / apppbx.cpp
index 06e3d92..2c926f6 100644 (file)
 
 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;
@@ -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,262 +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;
-       int there_is_an_external = 0;
-
-       interface = interface_first;
-
-       /* first find the given interface or, if not given, one with no extension */
-       checknext:
-       if (!interface) {
-               if (!there_is_an_external && !(ifname && ifname[0])) {
-                       trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
-                       add_trace("info", NULL, "Add 'external' parameter to interface.conf.");
-                       end_trace();
-               }
-               return(NULL);
-       }
-
-       /* check for given interface */
-       if (ifname && ifname[0]) {
-               if (!strcasecmp(interface->name, ifname)) {
-                       /* found explicit interface */
-                       trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
-                       add_trace("interface", NULL, "%s", ifname);
-                       end_trace();
-                       goto foundif;
-               }
-
-       } else {
-               if (interface->external) {
-                       there_is_an_external = 1;
-                       /* found non extension */
-                       trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
-                       add_trace("interface", NULL, "%s", interface->name);
-                       end_trace();
-                       goto foundif;
-               }
-       }
-
-       interface = interface->next;
-       goto checknext;
-foundif:
-
-       /* see if interface has ports */
-       if (!interface->ifport) {
-               /* no ports */
-               trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
-               add_trace("interface", NULL, "%s", interface->name);
-               end_trace();
-               interface = interface->next;
-               goto checknext;
-       }
-
-       /* select port by algorithm */
-       ifport_start = interface->ifport;
-       index = 0;
-       if (interface->hunt == HUNT_ROUNDROBIN) {
-               while(ifport_start->next && index<interface->hunt_next) {
-                       ifport_start = ifport_start->next;
-                       index++;
-               }
-               trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
-               add_trace("port", NULL, "%d", ifport_start->portnum);
-               add_trace("position", NULL, "%d", index);
-               end_trace();
-       }
-
-       /* loop ports */
-       ifport = ifport_start;
-       nextport:
-
-       /* see if port is available */
-       if (!ifport->mISDNport) {
-               trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
-               add_trace("port", NULL, "%d", ifport->portnum);
-               add_trace("position", NULL, "%d", index);
-               end_trace();
-               goto portbusy;
-       }
-       mISDNport = ifport->mISDNport;
-
-       /* see if port is administratively blocked */
-       if (ifport->block) {
-               trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
-               add_trace("port", NULL, "%d", ifport->portnum);
-               add_trace("position", NULL, "%d", index);
-               end_trace();
-               goto portbusy;
-       }
-
-       /* see if link is up on PTP*/
-       if (mISDNport->l2hold && mISDNport->l2link<1) {
-               trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
-               add_trace("port", NULL, "%d", ifport->portnum);
-               add_trace("position", NULL, "%d", index);
-               end_trace();
-               goto portbusy;
-       }
-
-       /* check for channel form selection list */
-       *channel = 0;
-#ifdef WITH_SS5
-       if (mISDNport->ss5) {
-               class Pss5 *port;
-               port = ss5_hunt_line(mISDNport);
-               if (port) {
-                       *channel = port->p_m_b_channel;
-                       trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
-                       add_trace("port", NULL, "%d", ifport->portnum);
-                       add_trace("position", NULL, "%d", index);
-                       add_trace("channel", NULL, "%d", *channel);
-                       end_trace();
-               }
-       } else
-#endif
-       {
-               selchannel = ifport->out_channel;
-               while(selchannel) {
-                       switch(selchannel->channel) {
-                               case CHANNEL_FREE: /* free channel */
-                               if (mISDNport->b_reserved >= mISDNport->b_num)
-                                       break; /* all channel in use or reserverd */
-                               /* find channel */
-                               i = 0;
-                               while(i < mISDNport->b_num) {
-                                       if (mISDNport->b_port[i] == NULL) {
-                                               *channel = i+1+(i>=15);
-                                               trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
-                                               add_trace("port", NULL, "%d", ifport->portnum);
-                                               add_trace("position", NULL, "%d", index);
-                                               add_trace("channel", NULL, "%d", *channel);
-                                               end_trace();
-                                               break;
-                                       }
-                                       i++;
-                               }
-                               if (*channel)
-                                       break;
-                               trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
-                               add_trace("port", NULL, "%d", ifport->portnum);
-                               add_trace("position", NULL, "%d", index);
-                               end_trace();
-                               break;
-
-                               case CHANNEL_ANY: /* don't ask for channel */
-                               if (mISDNport->b_reserved >= mISDNport->b_num) {
-                                       trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
-                                       add_trace("port", NULL, "%d", ifport->portnum);
-                                       add_trace("position", NULL, "%d", index);
-                                       add_trace("total", NULL, "%d", mISDNport->b_num);
-                                       add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
-                                       end_trace();
-                                       break; /* all channel in use or reserverd */
-                               }
-                               trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
-                               add_trace("port", NULL, "%d", ifport->portnum);
-                               add_trace("position", NULL, "%d", index);
-                               end_trace();
-                               *channel = CHANNEL_ANY;
-                               break;
-
-                               case CHANNEL_NO: /* call waiting */
-                               trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
-                               add_trace("port", NULL, "%d", ifport->portnum);
-                               add_trace("position", NULL, "%d", index);
-                               end_trace();
-                               *channel = CHANNEL_NO;
-                               break;
-
-                               default:
-                               if (selchannel->channel<1 || selchannel->channel==16) {
-                                       trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
-                                       add_trace("port", NULL, "%d", ifport->portnum);
-                                       add_trace("position", NULL, "%d", index);
-                                       add_trace("channel", NULL, "%d", selchannel->channel);
-                                       end_trace();
-                                       break; /* invalid channels */
-                               }
-                               i = selchannel->channel-1-(selchannel->channel>=17);
-                               if (i >= mISDNport->b_num) {
-                                       trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
-                                       add_trace("port", NULL, "%d", ifport->portnum);
-                                       add_trace("position", NULL, "%d", index);
-                                       add_trace("channel", NULL, "%d", selchannel->channel);
-                                       add_trace("channels", NULL, "%d", mISDNport->b_num);
-                                       end_trace();
-                                       break; /* channel not in port */
-                               }
-                               if (mISDNport->b_port[i] == NULL) {
-                                       *channel = selchannel->channel;
-                                       trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
-                                       add_trace("port", NULL, "%d", ifport->portnum);
-                                       add_trace("position", NULL, "%d", index);
-                                       add_trace("channel", NULL, "%d", *channel);
-                                       end_trace();
-                                       break;
-                               }
-                               break;
-                       }
-                       if (*channel)
-                               break; /* found channel */
-                       selchannel = selchannel->next;
-               }
-       }
-
-       /* if channel was found, return mISDNport and channel */
-       if (*channel) {
-               /* setting next port to start next time */
-               if (interface->hunt == HUNT_ROUNDROBIN) {
-                       index++;
-                       if (!ifport->next)
-                               index = 0;
-                       interface->hunt_next = index;
-               }
-               
-               return(mISDNport);
-       }
-
-       trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
-       add_trace("port", NULL, "%d", ifport->portnum);
-       add_trace("position", NULL, "%d", index);
-       end_trace();
-
-       portbusy:
-       /* go next port, until all ports are checked */
-       index++;
-       ifport = ifport->next;
-       if (!ifport) {
-               index = 0;
-               ifport = interface->ifport;
-       }
-       if (ifport != ifport_start)
-               goto nextport;
-
-       if (!ifname) {
-               interface = interface->next;
-               goto checknext;
-       }
-
-       return(NULL); /* no port found */
-}
-
 /* 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;
@@ -803,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;
+       struct admin_list       *admin;
+#endif
        int                     earlyb;
        int                     mode = B_MODE_TRANSPARENT;
 
@@ -844,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 */
                        }
                }
@@ -857,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);
@@ -901,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;
@@ -909,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);
                        }
                }
@@ -919,46 +724,94 @@ 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);
+                       /* found interface */
+                       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
+#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
+                               if (mISDNport->ss5)
+                                       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);
-                       else
-#ifdef WITH_GSM
-                               port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                               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);
+                               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;
@@ -978,6 +831,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);
@@ -1050,6 +904,7 @@ 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) {
@@ -1064,7 +919,9 @@ void EndpointAppPBX::out_setup(void)
                                        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");
@@ -1121,91 +978,163 @@ 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);
+
+                       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 */
+#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
+                                       if (mISDNport->ss5)
+                                               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);
-                       else
-#ifdef WITH_GSM
-                               port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                                       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);
+                                       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;
@@ -1213,163 +1142,157 @@ void EndpointAppPBX::out_setup(void)
 
 }
 
+int action_timeout(struct lcr_timer *timer, void *instance, int index)
+{
+       class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
 
-/* handler for endpoint
- */
+       if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
+               return 0;
 
-extern int quit;
-int EndpointAppPBX::handler(void)
+       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 */
+
+       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);
 
-       /* handle connection to user */
-       if (e_state == EPOINT_STATE_IDLE) {
+       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);
+
+       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();
@@ -1390,7 +1313,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)
@@ -1403,10 +1326,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';
 }
@@ -1421,7 +1345,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);
        
@@ -1430,18 +1353,18 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un
        memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
        memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
        memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
+       memcpy(&e_rtpinfo, &param->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 */
@@ -1556,7 +1479,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);
@@ -1569,6 +1492,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 */
@@ -1589,7 +1514,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;
        }
 
@@ -1605,7 +1530,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') {
@@ -1646,12 +1577,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);
@@ -1671,7 +1607,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 */
        }
@@ -1679,6 +1615,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 == '*')
@@ -1745,7 +1687,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);
                }
        }
 }
@@ -1753,11 +1695,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 */
@@ -1898,7 +1842,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);
 
@@ -1922,18 +1866,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])
@@ -1969,7 +1906,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 */
 
@@ -1977,7 +1915,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));
@@ -2043,12 +1982,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;
@@ -2058,7 +1997,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");
                        }
@@ -2141,7 +2080,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);
@@ -2180,8 +2120,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);
@@ -2189,7 +2131,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 */
 }
 
@@ -2206,7 +2148,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:
@@ -2221,7 +2163,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:
@@ -2235,7 +2177,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:
@@ -2243,7 +2185,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:
@@ -2257,7 +2199,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:
@@ -2275,7 +2217,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 */
@@ -2418,6 +2360,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)
 {
@@ -2456,6 +2417,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
  */
@@ -2476,17 +2449,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) {
@@ -2614,6 +2576,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);
@@ -2637,6 +2605,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);
@@ -2651,6 +2625,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 */
@@ -2674,6 +2649,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 */
@@ -2806,6 +2782,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, "");
@@ -2813,7 +2790,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, &param->connectinfo, sizeof(e_callerinfo));
        if(portlist) {
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
@@ -2850,6 +2828,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;
 }
 
@@ -2859,18 +2838,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)<e_powerlimit || e_powerlimit<1)) {
-               release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
+       /* 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,0 ); /* RELEASE_TYPE, join, port */
 
                /* set time for power dialing */
-               e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
+               schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
                e_powercount++;
 
                /* set redial tone */
@@ -2908,6 +2888,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *
        }
 
        /* set stop time */
+       time(&now);
        e_stop = now;
 
        if ((e_state!=EPOINT_STATE_CONNECT
@@ -2917,7 +2898,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 */
@@ -2939,7 +2920,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);
@@ -2992,11 +2973,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, &param->setup.dialinginfo, sizeof(e_dialinginfo));
                        return;
@@ -3045,6 +3026,7 @@ void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, un
        memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
        memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
        memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
+       memcpy(&e_rtpinfo, &param->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) {
@@ -3057,7 +3039,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 */
@@ -3073,6 +3055,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)
 {
@@ -3127,6 +3122,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)
@@ -3141,21 +3149,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 */
@@ -3245,23 +3238,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 */
@@ -3319,6 +3300,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);
        }
@@ -3338,7 +3325,7 @@ int match_list(char *list, char *item)
 
        while(42) {
                /* eliminate white spaces */
-               while (*list <= ' ')
+               while (*list > '\0' && *list <= ' ')
                        list++;
                if (*list == ',') {
                        list++;
@@ -3388,7 +3375,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;
@@ -3515,7 +3502,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;
@@ -3547,6 +3534,7 @@ reject:
  */
 void 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;
@@ -3580,7 +3568,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;
        }
@@ -3693,10 +3681,13 @@ void EndpointAppPBX::join_join(void)
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
 
        /* mixer must update */
-       our_joinpbx->j_updatebridge = 1; /* update mixer flag */
+       trigger_work(&our_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
 }
 
 
@@ -3778,7 +3769,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);
@@ -3844,6 +3835,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)
@@ -4050,6 +4043,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)