fixup
[lcr.git] / dss1.cpp
index c8adb27..43452bb 100644 (file)
--- a/dss1.cpp
+++ b/dss1.cpp
 //#include <sys/socket.h>
 extern "C" {
 }
-#include <q931.h>
+#include <mISDN/q931.h>
+#include <mISDN/suppserv.h>
+#ifdef OLD_MT_ASSIGN
 extern unsigned int mt_assign_pid;
+#endif
 
 #include "ie.cpp"
 
+static int delete_event(struct lcr_work *work, void *instance, int index);
+
 /*
  * constructor
  */
-Pdss1::Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode)
+Pdss1::Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, struct interface *interface, int channel, int exclusive, int mode) : PmISDN(type, mISDNport, portname, settings, interface, channel, exclusive, mode)
 {
        p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
        p_m_d_ntmode = mISDNport->ntmode;
        p_m_d_tespecial = mISDNport->tespecial;
        p_m_d_l3id = 0;
+       memset(&p_m_d_delete, 0, sizeof(p_m_d_delete));
+       add_work(&p_m_d_delete, delete_event, this, 0);
        p_m_d_ces = -1;
        p_m_d_queue[0] = '\0';
        p_m_d_notify_pending = NULL;
@@ -44,6 +51,8 @@ Pdss1::Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_
  */
 Pdss1::~Pdss1()
 {
+       del_work(&p_m_d_delete);
+
        /* remove queued message */
        if (p_m_d_notify_pending)
                message_free(p_m_d_notify_pending);
@@ -255,7 +264,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
        end_trace();
        p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
        new_state(PORT_STATE_RELEASE);
-       p_m_delete = 1;
+       trigger_work(&p_m_d_delete);
        return(-34); /* to epoint: no channel available */
 }
 
@@ -402,7 +411,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        int bearer_coding, bearer_capability, bearer_mode, bearer_rate, bearer_multi, bearer_user;
        int exclusive, channel;
        int ret;
-       unsigned char keypad[32] = "";
+       unsigned char keypad[33] = "";
        unsigned char useruser[128];
        int useruser_len = 0, useruser_protocol;
        class Endpoint *epoint;
@@ -422,7 +431,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, pid, l3m);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
        p_m_d_l3id = pid;
@@ -453,7 +462,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
 
@@ -473,6 +482,12 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                case 0:
                p_callerinfo.screen = INFO_SCREEN_USER;
                break;
+               case 1:
+               p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
+               break;
+               case 2:
+               p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
+               break;
                default:
                p_callerinfo.screen = INFO_SCREEN_NETWORK;
                break;
@@ -516,6 +531,12 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                case 0:
                p_callerinfo.screen2 = INFO_SCREEN_USER;
                break;
+               case 1:
+               p_callerinfo.screen2 = INFO_SCREEN_USER_VERIFIED_PASSED;
+               break;
+               case 2:
+               p_callerinfo.screen2 = INFO_SCREEN_USER_VERIFIED_FAILED;
+               break;
                default:
                p_callerinfo.screen2 = INFO_SCREEN_NETWORK;
                break;
@@ -574,6 +595,12 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                case 0:
                p_redirinfo.screen = INFO_SCREEN_USER;
                break;
+               case 1:
+               p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
+               break;
+               case 2:
+               p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
+               break;
                default:
                p_redirinfo.screen = INFO_SCREEN_NETWORK;
                break;
@@ -693,7 +720,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
        bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
@@ -703,8 +730,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                FATAL("Incoming call but already got an endpoint.\n");
        if (!(epoint = new Endpoint(p_serial, 0)))
                FATAL("No memory for Endpoint instance\n");
-       if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
-               FATAL("No memory for Endpoint Application instance\n");
+       epoint->ep_app = new_endpointapp(epoint, 0, p_m_mISDNport->ifport->interface->app); //incoming
        epointlist_new(epoint->ep_serial);
 
        /* send setup message to endpoit */
@@ -728,7 +754,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 void Pdss1::information_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 {
        int type, plan;
-       unsigned char keypad[32] = "", display[128] = "";
+       unsigned char keypad[33] = "", display[128] = "";
        struct lcr_msg *message;
 
        l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_IND, DIRECTION_IN);
@@ -753,7 +779,7 @@ void Pdss1::information_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l
                p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
                break;
        }
-       SCAT(p_dialinginfo.display, (char *)display);
+       SCPY(p_dialinginfo.display, (char *)display);
        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
        memcpy(&message->param.information, &p_dialinginfo, sizeof(struct dialing_info));
        message_put(message);
@@ -777,6 +803,13 @@ void Pdss1::setup_acknowledge_ind(unsigned int cmd, unsigned int pid, struct l3_
        dec_ie_progress(l3m, &coding, &location, &progress);
        end_trace();
 
+       if (progress >= 0) {
+               message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROGRESS);
+               message->param.progressinfo.progress = progress;
+               message->param.progressinfo.location = location;
+               message_put(message);
+       }
+
        /* process channel */
        ret = received_first_reply_to_setup(cmd, channel, exclusive);
        if (ret < 0) {
@@ -785,7 +818,7 @@ void Pdss1::setup_acknowledge_ind(unsigned int cmd, unsigned int pid, struct l3_
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                message_put(message);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
 
@@ -826,6 +859,13 @@ void Pdss1::proceeding_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
        dec_ie_redir_dn(l3m, &type, &plan, &present, (unsigned char *)redir, sizeof(redir));
        end_trace();
 
+       if (progress >= 0) {
+               message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROGRESS);
+               message->param.progressinfo.progress = progress;
+               message->param.progressinfo.location = location;
+               message_put(message);
+       }
+
        ret = received_first_reply_to_setup(cmd, channel, exclusive);
        if (ret < 0) {
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
@@ -833,7 +873,7 @@ void Pdss1::proceeding_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                message_put(message);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
@@ -902,6 +942,13 @@ void Pdss1::alerting_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        dec_ie_redir_dn(l3m, &type, &plan, &present, (unsigned char *)redir, sizeof(redir));
        end_trace();
 
+       if (progress >= 0) {
+               message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROGRESS);
+               message->param.progressinfo.progress = progress;
+               message->param.progressinfo.location = location;
+               message_put(message);
+       }
+
        /* process channel */
        ret = received_first_reply_to_setup(cmd, channel, exclusive);
        if (ret < 0) {
@@ -910,7 +957,7 @@ void Pdss1::alerting_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                message_put(message);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
@@ -987,7 +1034,7 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                message_put(message);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
 
@@ -1007,6 +1054,12 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                case 0:
                p_connectinfo.screen = INFO_SCREEN_USER;
                break;
+               case 1:
+               p_connectinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
+               break;
+               case 2:
+               p_connectinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
+               break;
                default:
                p_connectinfo.screen = INFO_SCREEN_NETWORK;
                break;
@@ -1064,8 +1117,17 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
        dec_ie_display(l3m, (unsigned char *)display, sizeof(display));
        end_trace();
 
-       if (cause < 0)
+       if (cause < 0) {
                cause = 16;
+               location = LOCATION_PRIVATE_LOCAL;
+       }
+
+       if (progress >= 0) {
+               message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROGRESS);
+               message->param.progressinfo.progress = progress;
+               message->param.progressinfo.location = proglocation;
+               message_put(message);
+       }
 
        /* release if remote sends us no tones */
        if (!p_m_mISDNport->earlyb) {
@@ -1091,7 +1153,7 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                        free_epointlist(p_epointlist);
                }
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
 
@@ -1152,8 +1214,10 @@ void Pdss1::release_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        dec_ie_display(l3m, (unsigned char *)display, sizeof(display));
        end_trace();
 
-       if (cause < 0)
+       if (cause < 0) {
                cause = 16;
+               location = LOCATION_PRIVATE_LOCAL;
+       }
 
        /* sending release to endpoint */
        if (location == LOCATION_PRIVATE_LOCAL)
@@ -1169,7 +1233,7 @@ void Pdss1::release_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        }
 
        new_state(PORT_STATE_RELEASE);
-       p_m_delete = 1;
+       trigger_work(&p_m_d_delete);
 }
 
 /* CC_RESTART INDICATION */
@@ -1203,8 +1267,10 @@ void Pdss1::release_complete_ind(unsigned int cmd, unsigned int pid, struct l3_m
        if (location == LOCATION_PRIVATE_LOCAL)
                location = LOCATION_PRIVATE_REMOTE;
 
-       if (cause < 0)
+       if (cause < 0) {
                cause = 16;
+               location = LOCATION_PRIVATE_LOCAL;
+       }
 
        /* sending release to endpoint */
        while(p_epointlist) {
@@ -1217,7 +1283,7 @@ void Pdss1::release_complete_ind(unsigned int cmd, unsigned int pid, struct l3_m
        }
 
        new_state(PORT_STATE_RELEASE);
-       p_m_delete = 1;
+       trigger_work(&p_m_d_delete);
 }
 
 /* T312 timeout  */
@@ -1321,8 +1387,8 @@ void Pdss1::hold_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 #if 0
        epoint = find_epoint_id(ACTIVE_EPOINT(p_epointlist));
        if (epoint && p_m_d_ntmode) {
-               p_m_timeout = p_settings.tout_hold;
-               time(&p_m_timer);
+               if (p_settings.tout_hold)
+                       schedule_timer(&p_m_timeout, p_settings.tout_hold, 0);
        }
 #endif
 
@@ -1380,7 +1446,7 @@ void Pdss1::retrieve_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 
        /* set hold state */
        p_m_hold = 0;
-       p_m_timeout = 0;
+       unsched_timer(&p_m_timeout);
 
        /* acknowledge retrieve */
        l3m = create_l3msg();
@@ -1458,7 +1524,7 @@ void Pdss1::suspend_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_SUSPEND_ACKNOWLEDGE, p_m_d_l3id, l3m);
 
        new_state(PORT_STATE_RELEASE);
-       p_m_delete = 1;
+       trigger_work(&p_m_d_delete);
 }
 
 /* CC_RESUME INDICATION */
@@ -1485,7 +1551,7 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RESUME_REJECT, pid, l3m);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
        p_m_d_l3id = pid;
@@ -1528,7 +1594,7 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RESUME_REJECT, p_m_d_l3id, l3m);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
        bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
@@ -1576,21 +1642,50 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 /* CC_FACILITY INDICATION */
 void Pdss1::facility_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 {
-       unsigned char facil[256];
-       int facil_len;
+       unsigned char fac_ie[256];
+       struct asn1_parm fac;
+       int fac_len;
        struct lcr_msg *message;
 
        l1l2l3_trace_header(p_m_mISDNport, this, L3_FACILITY_IND, DIRECTION_IN);
-       dec_ie_facility(l3m, facil, &facil_len);
+       dec_ie_facility(l3m, fac_ie + 1, &fac_len);
+       fac_ie[0] = fac_len;
        end_trace();
 
        /* facility */
-       if (facil_len<=0)
+       if (fac_len<=0)
                return;
 
+       decodeFac(fac_ie, &fac);
+       switch (fac.comp) {
+       case CompInvoke:
+               switch(fac.u.inv.operationValue) {
+                       case Fac_Begin3PTY:
+                       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_3PTY);
+                       message->param.threepty.begin = 1;
+                       message->param.threepty.invoke = 1;
+                       message->param.threepty.invoke_id = fac.u.inv.invokeId;
+                       message_put(message);
+                       return;
+
+                       case Fac_End3PTY:
+                       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_3PTY);
+                       message->param.threepty.end = 1;
+                       message->param.threepty.invoke = 1;
+                       message->param.threepty.invoke_id = fac.u.inv.invokeId;
+                       message_put(message);
+                       return;
+               default:
+                       ;
+               }
+               break;
+       default:
+               ;
+       }
+
        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_FACILITY);
-       message->param.facilityinfo.len = facil_len;
-       memcpy(message->param.facilityinfo.data, facil, facil_len);
+       message->param.facilityinfo.len = fac_len;
+       memcpy(message->param.facilityinfo.data, fac_ie + 1, fac_len);
        message_put(message);
 }
 
@@ -1603,6 +1698,13 @@ void Pdss1::progress_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        l1l2l3_trace_header(p_m_mISDNport, this, L3_PROGRESS_IND, DIRECTION_IN);
        dec_ie_progress(l3m, &coding, &location, &progress);
        end_trace();
+
+       if (progress >= 0) {
+               message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROGRESS);
+               message->param.progressinfo.progress = progress;
+               message->param.progressinfo.location = location;
+               message_put(message);
+       }
 }
 
 
@@ -1748,8 +1850,8 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                add_trace("callref", NULL, "0x%x", p_m_d_l3id);
                end_trace();
                p_m_d_l3id = 0;
+               trigger_work(&p_m_d_delete);
                p_m_d_ces = -1;
-               p_m_delete = 1;
                /* sending release to endpoint in case we still have an endpoint
                 * this is because we don't get any response if a release_complete is received (or a release in release state)
                 */
@@ -1784,35 +1886,39 @@ void Pdss1::new_state(int state)
 
        /* set timeout */
        if (state == PORT_STATE_IN_OVERLAP) {
-               p_m_timeout = p_m_mISDNport->ifport->tout_dialing;
-               time(&p_m_timer);
+               if (p_m_mISDNport->ifport->tout_dialing)
+                       schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_dialing, 0);
        }
        if (state != p_state) {
+               unsched_timer(&p_m_timeout);
                if (state == PORT_STATE_IN_SETUP
                 || state == PORT_STATE_OUT_SETUP
                 || state == PORT_STATE_IN_OVERLAP
                 || state == PORT_STATE_OUT_OVERLAP) {
-                       p_m_timeout = p_m_mISDNport->ifport->tout_setup;
-                       time(&p_m_timer);
+                       if (p_m_mISDNport->ifport->tout_setup)
+                               schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_setup, 0);
                }
                if (state == PORT_STATE_IN_PROCEEDING
                 || state == PORT_STATE_OUT_PROCEEDING) {
-                       p_m_timeout = p_m_mISDNport->ifport->tout_proceeding;
-                       time(&p_m_timer);
+                       if (p_m_mISDNport->ifport->tout_proceeding)
+                               schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_proceeding, 0);
                }
                if (state == PORT_STATE_IN_ALERTING
                 || state == PORT_STATE_OUT_ALERTING) {
-                       p_m_timeout = p_m_mISDNport->ifport->tout_alerting;
-                       time(&p_m_timer);
+                       if (p_m_mISDNport->ifport->tout_alerting)
+                               schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_alerting, 0);
                }
+#if 0
                if (state == PORT_STATE_CONNECT
                 || state == PORT_STATE_CONNECT_WAITING) {
-                       p_m_timeout = 0;
+                       if (p_m_mISDNport->ifport->tout_connect)
+                               schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_connect, 0);
                }
+#endif
                if (state == PORT_STATE_IN_DISCONNECT
                 || state == PORT_STATE_OUT_DISCONNECT) {
-                       p_m_timeout = p_m_mISDNport->ifport->tout_disconnect;
-                       time(&p_m_timer);
+                       if (p_m_mISDNport->ifport->tout_disconnect)
+                               schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_disconnect, 0);
                }
        }
        
@@ -1820,23 +1926,15 @@ void Pdss1::new_state(int state)
 }
 
 
-/*
- * handler
- */
-int Pdss1::handler(void)
+/* deletes only if l3id is release, otherwhise it will be triggered then */
+static int delete_event(struct lcr_work *work, void *instance, int index)
 {
-       int ret;
+       class Pdss1 *isdnport = (class Pdss1 *)instance;
 
-       if ((ret = PmISDN::handler()))
-               return(ret);
-
-       /* handle destruction */
-       if (p_m_delete && p_m_d_l3id==0) {
-               delete this;
-               return(-1);
-       }
+       if (!isdnport->p_m_d_l3id)
+               delete isdnport;
 
-       return(0);
+       return 0;
 }
 
 
@@ -1860,7 +1958,7 @@ void Pdss1::message_information(unsigned int epoint_id, int message_id, union pa
                enc_ie_called_pn(l3m, 0, 1, (unsigned char *)number, max);
                if ((p_m_d_ntmode || p_m_d_tespecial) && display[0]) {
                        enc_ie_display(l3m, (unsigned char *)display);
-                       display = "";
+                       display = (char *)"";
                }
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_INFORMATION, p_m_d_l3id, l3m);
@@ -1870,13 +1968,13 @@ void Pdss1::message_information(unsigned int epoint_id, int message_id, union pa
 }
 
 
-int newteid = 0;
-
 /* MESSAGE_SETUP */
 void Pdss1::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
 {
        l3_msg *l3m;
+#ifdef OLD_MT_ASSIGN
        int ret;
+#endif
        int plan, type, screen, present, reason;
        int plan2, type2, screen2, present2;
        int capability, mode, rate, coding, user, presentation, interpretation, hlc, exthlc;
@@ -1893,7 +1991,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                message_put(message);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
 
@@ -1902,10 +2000,10 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        memcpy(&p_dialinginfo, &param->setup.dialinginfo, sizeof(p_dialinginfo));
        memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
        memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
-//             SCPY(&p_m_tones_dir, param->setup.ext.tones_dir);
        /* screen outgoing caller id */
-       do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface);
-       do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface);
+       do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface->name);
+       do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface->name);
+       do_screen(1, p_redirinfo.id, sizeof(p_redirinfo.id), &p_redirinfo.ntype, &p_redirinfo.present, p_m_mISDNport->ifport->interface->name);
 
        /* only display at connect state: this case happens if endpoint is in connected mode */
        if (p_state==PORT_STATE_CONNECT) {
@@ -1947,10 +2045,18 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
 
        /* creating l3id */
        l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
+#ifdef OLD_MT_ASSIGN
        /* see MT_ASSIGN notes at do_layer3() */
        mt_assign_pid = 0;
        ret = p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_ASSIGN, 0, NULL);
-       if (mt_assign_pid == 0 || ret < 0) {
+       if (mt_assign_pid == 0 || ret < 0)
+       p_m_d_l3id = mt_assign_pid;
+       mt_assign_pid = ~0;
+#else
+       p_m_d_l3id = request_new_pid(p_m_mISDNport->ml3);
+       if (p_m_d_l3id == MISDN_PID_NONE)
+#endif
+       {
                struct lcr_msg *message;
 
                add_trace("callref", NULL, "no free id");
@@ -1960,11 +2066,13 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                message_put(message);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
+#ifdef OLD_MT_ASSIGN
        p_m_d_l3id = mt_assign_pid;
        mt_assign_pid = ~0;
+#endif
        add_trace("callref", "new", "0x%x", p_m_d_l3id);
        end_trace();
 
@@ -1972,7 +2080,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        l3m = create_l3msg();
        l1l2l3_trace_header(p_m_mISDNport, this, L3_SETUP_REQ, DIRECTION_OUT);
        /* channel information */
-       if (channel >= 0) /* it should */
+       if (p_m_d_ntmode || channel != CHANNEL_ANY) /* only omit channel id in te-mode/any channel */
                enc_ie_channel_id(l3m, exclusive, channel);
        /* caller information */
        plan = 1;
@@ -1997,6 +2105,12 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                case INFO_SCREEN_USER:
                screen = 0;
                break;
+               case INFO_SCREEN_USER_VERIFIED_PASSED:
+               screen = 1;
+               break;
+               case INFO_SCREEN_USER_VERIFIED_FAILED:
+               screen = 2;
+               break;
                default: /* INFO_SCREEN_NETWORK */
                screen = 3;
                break;
@@ -2035,6 +2149,12 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                case INFO_SCREEN_USER:
                screen2 = 0;
                break;
+               case INFO_SCREEN_USER_VERIFIED_PASSED:
+               screen2 = 1;
+               break;
+               case INFO_SCREEN_USER_VERIFIED_FAILED:
+               screen2 = 2;
+               break;
                default: /* INFO_SCREEN_NETWORK */
                screen2 = 3;
                break;
@@ -2059,6 +2179,9 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                enc_ie_called_pn(l3m, 0, 1, (unsigned char *)p_dialinginfo.id, max);
                SCPY(p_m_d_queue, p_dialinginfo.id + max);
        }
+       /* keypad */
+       if (p_dialinginfo.keypad[0])
+               enc_ie_keypad(l3m, (unsigned char *)p_dialinginfo.keypad);
        /* sending complete */
        if (p_dialinginfo.sending_complete)
                enc_ie_complete(l3m, 1);
@@ -2089,6 +2212,12 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                case INFO_SCREEN_USER:
                screen = 0;
                break;
+               case INFO_SCREEN_USER_VERIFIED_PASSED:
+               screen = 1;
+               break;
+               case INFO_SCREEN_USER_VERIFIED_FAILED:
+               screen = 2;
+               break;
                default: /* INFO_SCREE_NETWORK */
                screen = 3;
                break;
@@ -2185,6 +2314,40 @@ void Pdss1::message_facility(unsigned int epoint_id, int message_id, union param
        p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_FACILITY, p_m_d_l3id, l3m);
 }
 
+/* MESSAGE_3PTY */
+void Pdss1::message_3pty(unsigned int epoint_id, int message_id, union parameter *param)
+{
+       l3_msg *l3m;
+       unsigned char fac_ie[256];
+       struct asn1_parm fac;
+
+       /* encode 3PTY facility */
+       memset(&fac, 0, sizeof(fac));
+       fac.Valid = 1;
+       if (param->threepty.result) {
+               fac.comp = CompReturnResult;
+               fac.u.retResult.invokeId = param->threepty.invoke_id;
+               fac.u.retResult.operationValuePresent = 1;
+               if (param->threepty.begin)
+                       fac.u.retResult.operationValue = Fac_Begin3PTY;
+               if (param->threepty.end)
+                       fac.u.retResult.operationValue = Fac_End3PTY;
+       }
+       if (param->threepty.error) {
+               fac.comp = CompReturnError;
+               fac.u.retError.invokeId = param->threepty.invoke_id;
+               fac.u.retError.errorValue = FacError_Gen_InvalidCallState;
+       }
+       encodeFac(fac_ie, &fac);
+
+       /* sending facility */
+       l3m = create_l3msg();
+       l1l2l3_trace_header(p_m_mISDNport, this, L3_FACILITY_REQ, DIRECTION_OUT);
+       enc_ie_facility(l3m, fac_ie + 2, fac_ie[1]);
+       end_trace();
+       p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_FACILITY, p_m_d_l3id, l3m);
+}
+
 /* MESSAGE_NOTIFY */
 void Pdss1::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
 {
@@ -2192,7 +2355,14 @@ void Pdss1::message_notify(unsigned int epoint_id, int message_id, union paramet
        int notify;
        int plan = 0, type = -1, present = 0;
 
-       printf("if = %d\n", param->notifyinfo.notify);
+       if (p_m_mISDNport->ifport->nonotify) {
+               l1l2l3_trace_header(p_m_mISDNport, this, L3_NOTIFY_REQ, DIRECTION_OUT);
+               add_trace("info", NULL, "blocked by config");
+               end_trace();
+               return;
+       }
+
+//     printf("if = %d\n", param->notifyinfo.notify);
        if (param->notifyinfo.notify>INFO_NOTIFY_NONE)
                notify = param->notifyinfo.notify & 0x7f;
        else
@@ -2363,7 +2533,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
 {
        l3_msg *l3m;
        int type, plan, present, screen;
-       class Endpoint *epoint;
+       time_t current_time;
 
        /* NT-MODE in setup state we must send PROCEEDING first */
        if (p_m_d_ntmode && p_state==PORT_STATE_IN_SETUP) {
@@ -2380,20 +2550,9 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
        /* copy connected information */
        memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
        /* screen outgoing caller id */
-       do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface);
+       do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface->name);
 
-       /* only display at connect state */
-       if (p_state == PORT_STATE_CONNECT)
-       if (p_connectinfo.display[0]) {
-               /* sending information */
-               l3m = create_l3msg();
-               l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
-               if (p_m_d_ntmode || p_m_d_tespecial)
-                       enc_ie_display(l3m, (unsigned char *)p_connectinfo.display);
-               end_trace();
-               p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_INFORMATION, p_m_d_l3id, l3m);
-               return;
-       }
+       set_display(p_connectinfo.display);
 
        if (p_state!=PORT_STATE_IN_SETUP && p_state!=PORT_STATE_IN_OVERLAP && p_state!=PORT_STATE_IN_PROCEEDING && p_state!=PORT_STATE_IN_ALERTING) {
                /* connect command only possible in setup, proceeding or alerting state */
@@ -2426,6 +2585,12 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
                case INFO_SCREEN_USER:
                screen = 0;
                break;
+               case INFO_SCREEN_USER_VERIFIED_PASSED:
+               screen = 1;
+               break;
+               case INFO_SCREEN_USER_VERIFIED_FAILED:
+               screen = 2;
+               break;
                default: /* INFO_SCREE_NETWORK */
                screen = 3;
                break;
@@ -2451,8 +2616,8 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
 //             enc_facility_centrex(&connect->FACILITY, dmsg, (unsigned char *)p_connectinfo.name, 0);
        /* date & time */
        if (p_m_d_ntmode || p_m_d_tespecial) {
-               epoint = find_epoint_id(epoint_id);
-               enc_ie_date(l3m, now, p_settings.no_seconds);
+               time(&current_time);
+               enc_ie_date(l3m, current_time, p_settings.no_seconds);
        }
        end_trace();
        /* finally send message */
@@ -2491,7 +2656,7 @@ if (/*     ||*/ p_state==PORT_STATE_OUT_SETUP) {
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
 
@@ -2538,49 +2703,49 @@ if (/*   ||*/ p_state==PORT_STATE_OUT_SETUP) {
 void Pdss1::message_release(unsigned int epoint_id, int message_id, union parameter *param)
 {
        l3_msg *l3m;
-       class Endpoint *epoint;
        char *p = NULL;
 
        /*
-        * we may only release during incoming disconnect state.
-        * this means that the endpoint doesnt require audio anymore
+        * if we are on incoming call setup, we may reject by sending a release_complete
+        * also on outgoing call setup, we send a release complete, BUT this is not conform. (i don't know any other way)
         */
-       if (p_state == PORT_STATE_IN_DISCONNECT
-        || p_state == PORT_STATE_OUT_DISCONNECT) {
-               /* sending release */
+       if (p_state==PORT_STATE_IN_SETUP
+        || p_state==PORT_STATE_OUT_SETUP) {
+//#warning remove me
+//PDEBUG(DEBUG_LOG, "JOLLY sending release complete %d\n", p_serial);
+               /* sending release complete */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_REQ, DIRECTION_OUT);
                /* send cause */
                enc_ie_cause(l3m, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
                end_trace();
-               p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE, p_m_d_l3id, l3m);
+               p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
                new_state(PORT_STATE_RELEASE);
                /* remove epoint */
                free_epointid(epoint_id);
                // wait for callref to be released
                return;
-
        }
        /*
-        * if we are on incoming call setup, we may reject by sending a release_complete
-        * also on outgoing call setup, we send a release complete, BUT this is not conform. (i don't know any other way)
+        * we may only release during incoming disconnect state.
+        * this means that the endpoint doesnt require audio anymore
         */
-       if (p_state==PORT_STATE_IN_SETUP
-        || p_state==PORT_STATE_OUT_SETUP) {
-//#warning remove me
-//PDEBUG(DEBUG_LOG, "JOLLY sending release complete %d\n", p_serial);
-               /* sending release complete */
+       if (p_state == PORT_STATE_IN_DISCONNECT
+        || p_state == PORT_STATE_OUT_DISCONNECT
+        || param->disconnectinfo.force) {
+               /* sending release */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_REQ, DIRECTION_OUT);
                /* send cause */
                enc_ie_cause(l3m, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
                end_trace();
-               p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
+               p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE, p_m_d_l3id, l3m);
                new_state(PORT_STATE_RELEASE);
                /* remove epoint */
                free_epointid(epoint_id);
                // wait for callref to be released
                return;
+
        }
 
 #if 0
@@ -2617,7 +2782,6 @@ wirklich erst proceeding?:
        /* send cause */
        enc_ie_cause(l3m, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
        /* send display */
-       epoint = find_epoint_id(epoint_id);
        if (param->disconnectinfo.display[0])
                p = param->disconnectinfo.display;
        if (p) if (*p && (p_m_d_ntmode || p_m_d_tespecial))
@@ -2691,6 +2855,10 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
                message_facility(epoint_id, message_id, param);
                break;
 
+               case MESSAGE_3PTY: /* begin result message */
+               message_3pty(epoint_id, message_id, param);
+               break;
+
                case MESSAGE_OVERLAP: /* more information is needed */
                if (p_state!=PORT_STATE_IN_SETUP) {
                        break;
@@ -2796,7 +2964,7 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
        port = port_first;
        while(port) {
                /* are we ISDN ? */
-               if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1) {
+               if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1) {
                        pdss1 = (class Pdss1 *)port;
                        /* check out correct stack and id */
                        if (pdss1->p_m_mISDNport == mISDNport) {
@@ -2860,7 +3028,7 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
                case MT_SETUP:
                /* creating port object, transparent until setup with hdlc */
                SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
-               if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
+               if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, mISDNport->ifport->interface, 0, 0, B_MODE_TRANSPARENT)))
 
                        FATAL("Cannot create Port instance.\n");
                pdss1->message_isdn(cmd, pid, l3m);
@@ -2869,7 +3037,7 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
                case MT_RESUME:
                /* creating port object, transparent until setup with hdlc */
                SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
-               if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
+               if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, mISDNport->ifport->interface, 0, 0, B_MODE_TRANSPARENT)))
                        FATAL("Cannot create Port instance.\n");
                pdss1->message_isdn(cmd, pid, l3m);
                break;
@@ -2886,6 +3054,11 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
                // facility als broadcast
                break;
 
+               case MT_L2IDLE:
+               // L2 became idle - we could sent a MT_L2RELEASE if we are the L2 master
+               PDEBUG(DEBUG_ISDN, "Got L2 idle\n");
+               break;
+
                default:
                PERROR("unhandled message: cmd(0x%x) pid(0x%x)\n", cmd, pid);
                port = port_first;
@@ -2904,6 +3077,23 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
        return(0);
 }
 
+void Pdss1::set_display(const char *text)
+{
+       l3_msg *l3m;
+
+       /* only display at connect state */
+       if (p_state == PORT_STATE_CONNECT)
+       if (text[0]) {
+               /* sending information */
+               l3m = create_l3msg();
+               l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
+               if (p_m_d_ntmode || p_m_d_tespecial)
+                       enc_ie_display(l3m, (unsigned char *)text);
+               end_trace();
+               p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_INFORMATION, p_m_d_l3id, l3m);
+               return;
+       }
+}