struct message -> struct lcr_msg
[lcr.git] / action.cpp
index b77d937..67c8396 100644 (file)
@@ -67,44 +67,96 @@ char *numberrize_callerinfo(char *string, int ntype)
 
 
 /*
- * process init 'internal' / 'external' / 'chan' / 'vbox-record' / 'partyline'...
+ * process init 'internal' / 'external' / 'remote' / 'vbox-record' / 'partyline'...
  */
-void EndpointAppPBX::_action_init_call(int chan)
+void EndpointAppPBX::_action_init_call(char *remote)
 {
-       class Call              *call;
+       class Join              *join;
        struct port_list        *portlist = ea_endpoint->ep_portlist;
+       struct admin_list       *admin;
 
        /* a created call, this should never happen */
-       if (ea_endpoint->ep_call_id)
+       if (ea_endpoint->ep_join_id)
        {
                if (options.deb & DEBUG_EPOINT)
                        PERROR("EPOINT(%d): We already have a call instance, this should never happen!\n", ea_endpoint->ep_serial);
                return;
        }
 
-       /* create call */
-       PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new call instance.\n", ea_endpoint->ep_serial);
-       if (chan)
-               call = new CallChan(ea_endpoint);
-       else
-               call = new CallPBX(ea_endpoint);
-       if (!call)
+       /* create join */
+       PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new join instance.\n", ea_endpoint->ep_serial);
+       if (remote)
        {
-               /* resource not available */
-               message_disconnect_port(portlist, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
-               new_state(EPOINT_STATE_OUT_DISCONNECT);
-               set_tone(portlist,"cause_22");
-               return;
+               admin = admin_first;
+               while(admin)
+               {
+                       if (admin->remote_name[0] && !strcmp(admin->remote_name, remote))
+                               break;
+                       admin = admin->next;
+               }
+               if (!admin)
+               {
+                       /* resource not available */
+                       trace_header("ACTION remote (not available)", DIRECTION_NONE);
+                       add_trace("application", NULL, "%s", remote);
+                       end_trace();
+                       message_disconnect_port(portlist, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
+                       new_state(EPOINT_STATE_OUT_DISCONNECT);
+                       set_tone(portlist,"cause_22");
+                       return;
+               }
+               join = new JoinRemote(ea_endpoint->ep_serial, remote, admin->sock);
        }
-       ea_endpoint->ep_call_id = call->c_serial;
+       else
+               join = new JoinPBX(ea_endpoint);
+       if (!join)
+               FATAL("No memoy for Join instance.\n");
+       ea_endpoint->ep_join_id = join->j_serial;
 }
 void EndpointAppPBX::action_init_call(void)
 {
-       _action_init_call(0);
+       _action_init_call(NULL);
 }
-void EndpointAppPBX::action_init_chan(void)
+void EndpointAppPBX::action_init_remote(void)
 {
-       _action_init_call(1);
+       struct route_param      *rparam;
+       struct port_list        *portlist = ea_endpoint->ep_portlist;
+       struct lcr_msg          *message;
+       struct capa_info        capainfo;
+       struct caller_info      callerinfo;
+       struct redir_info       redirinfo;
+       struct dialing_info     dialinginfo;
+       char remote[32];
+
+       if (!(rparam = routeparam(e_action, PARAM_APPLICATION)))
+       {
+               trace_header("ACTION remote (no application given)", DIRECTION_NONE);
+               end_trace();
+               new_state(EPOINT_STATE_OUT_DISCONNECT);
+               message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
+               set_tone(portlist, "cause_3f");
+               return;
+       }
+       SCPY(remote, rparam->string_value);
+       _action_init_call(remote);
+
+       /* create bearer/caller/dialinginfo */
+       memcpy(&capainfo, &e_capainfo, sizeof(capainfo));
+       memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo));
+       memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo));
+       memset(&dialinginfo, 0, sizeof(dialinginfo));
+
+       /* send setup to remote */
+       trace_header("ACTION remote (setup)", DIRECTION_NONE);
+       add_trace("number", NULL, dialinginfo.id);
+       add_trace("remote", NULL, remote);
+       end_trace();
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
+       memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
+       memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
+       memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
+       memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info));
+       message_put(message);
 }
 
 /*
@@ -117,7 +169,7 @@ void EndpointAppPBX::action_dialing_internal(void)
        struct redir_info       redirinfo;
        struct dialing_info     dialinginfo;
        struct port_list        *portlist = ea_endpoint->ep_portlist;
-       struct message          *message;
+       struct lcr_msg          *message;
        struct extension        ext;
        struct route_param      *rparam;
 
@@ -125,7 +177,7 @@ void EndpointAppPBX::action_dialing_internal(void)
        set_tone(portlist, "proceeding");
        message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
        message_put(message);
-       logmessage(message);
+       logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
        new_state(EPOINT_STATE_IN_PROCEEDING);
 
        /* create bearer/caller/dialinginfo */
@@ -184,6 +236,7 @@ void EndpointAppPBX::action_dialing_internal(void)
                trace_header("ACTION extension (extension doesn't exist)", DIRECTION_NONE);
                add_trace("extension", NULL, dialinginfo.id);
                end_trace();
+               release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0);
                new_state(EPOINT_STATE_OUT_DISCONNECT);
                message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
                set_tone(portlist, "cause_86");
@@ -196,6 +249,7 @@ void EndpointAppPBX::action_dialing_internal(void)
                add_trace("extension", NULL, dialinginfo.id);
                end_trace();
                new_state(EPOINT_STATE_OUT_DISCONNECT);
+               release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0);
                message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
                set_tone(portlist, "cause_81");
                return;
@@ -205,7 +259,7 @@ void EndpointAppPBX::action_dialing_internal(void)
        trace_header("ACTION extension (calling)", DIRECTION_NONE);
        add_trace("extension", NULL, dialinginfo.id);
        end_trace();
-       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_SETUP);
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
        memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
        memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
        memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
@@ -223,7 +277,7 @@ void EndpointAppPBX::action_dialing_external(void)
        struct dialing_info dialinginfo;
        char *p;
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        struct route_param *rparam;
 
        /* special processing of delete characters '*' and '#' */
@@ -330,7 +384,7 @@ void EndpointAppPBX::action_dialing_external(void)
        {
                trace_header("ACTION extern (calling denied)", DIRECTION_NONE);
                end_trace();
-               release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, 0);
+               release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0);
                set_tone(portlist, "cause_82");
                denied:
                message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
@@ -347,7 +401,7 @@ void EndpointAppPBX::action_dialing_external(void)
                {
                        trace_header("ACTION extern (national calls denied)", DIRECTION_NONE);
                        end_trace();
-                       release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, 0);
+                       release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0);
                        set_tone(portlist, "cause_83");
                        goto denied;
                }
@@ -361,7 +415,7 @@ void EndpointAppPBX::action_dialing_external(void)
                {
                        trace_header("ACTION extern (international calls denied)", DIRECTION_NONE);
                        end_trace();
-                       release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, 0);
+                       release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0);
                        set_tone(portlist, "cause_84");
                        goto denied;
                }
@@ -373,7 +427,7 @@ void EndpointAppPBX::action_dialing_external(void)
        if (dialinginfo.interfaces[0])
                add_trace("interfaces", NULL, dialinginfo.interfaces);
        end_trace();
-       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_SETUP);
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
        memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
        memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
        memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
@@ -382,15 +436,25 @@ void EndpointAppPBX::action_dialing_external(void)
 }
 
 
-void EndpointAppPBX::action_dialing_chan(void)
+void EndpointAppPBX::action_dialing_remote(void)
 {
-       struct port_list *portlist = ea_endpoint->ep_portlist;
+       struct lcr_msg *message;
+       struct dialing_info dialinginfo;
+//     struct route_param *rparam;
 
-       trace_header("ACTION channel (not implemented)", DIRECTION_NONE);
-       end_trace();
-       message_disconnect_port(portlist, CAUSE_UNIMPLEMENTED, LOCATION_PRIVATE_LOCAL, "");
-       new_state(EPOINT_STATE_OUT_DISCONNECT);
-       set_tone(portlist,"cause_4f");
+       /* create bearer/caller/dialinginfo */
+       memset(&dialinginfo, 0, sizeof(dialinginfo));
+
+       if (dialinginfo.id[0])
+       {
+               /* add or update outgoing call */
+               trace_header("ACTION remote (dialing)", DIRECTION_NONE);
+               add_trace("number", NULL, dialinginfo.id);
+               end_trace();
+               message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_INFORMATION);
+               memcpy(&message->param.information, &dialinginfo, sizeof(struct dialing_info));
+               message_put(message);
+       }
 }
 
 
@@ -401,7 +465,7 @@ void EndpointAppPBX::action_dialing_vbox_record(void)
 {
        struct dialing_info dialinginfo;
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        struct extension ext;
        struct route_param *rparam;
 
@@ -445,7 +509,7 @@ void EndpointAppPBX::action_dialing_vbox_record(void)
        set_tone(portlist, "proceeding");
        message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
        message_put(message);
-       logmessage(message);
+       logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
        new_state(EPOINT_STATE_IN_PROCEEDING);
 
        memset(&dialinginfo, 0, sizeof(dialinginfo));
@@ -465,7 +529,7 @@ void EndpointAppPBX::action_dialing_vbox_record(void)
        trace_header("ACTION vbox-record (calling)", DIRECTION_NONE);
        add_trace("extension", NULL, "%s", dialinginfo.id);
        end_trace();
-       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_SETUP);
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, 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));
@@ -479,13 +543,13 @@ void EndpointAppPBX::action_dialing_vbox_record(void)
  */
 void EndpointAppPBX::action_init_partyline(void)
 {
-       class Call *call;
-       class CallPBX *callpbx;
+       class Join *join;
+       class JoinPBX *joinpbx;
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        struct route_param *rparam;
-       int partyline;
-       struct call_relation *relation;
+       int partyline, jingle = 0;
+       struct join_relation *relation;
 
        portlist = ea_endpoint->ep_portlist;
 
@@ -509,37 +573,33 @@ void EndpointAppPBX::action_init_partyline(void)
                goto noroom;
        }
        partyline = rparam->integer_value;
+       if ((rparam = routeparam(e_action, PARAM_JINGLE)))
+               jingle = 1;
 
-       /* don't create call if partyline exists */
-       call = call_first;
-       while(call)
+       /* don't create join if partyline exists */
+       join = join_first;
+       while(join)
        {
-               if (call->c_type == CALL_TYPE_PBX)
+               if (join->j_type == JOIN_TYPE_PBX)
                {
-                       callpbx = (class CallPBX *)call;
-                       if (callpbx->c_partyline == rparam->integer_value)
+                       joinpbx = (class JoinPBX *)join;
+                       if (joinpbx->j_partyline == partyline)
                                break;
                }
-               call = call->next;
+               join = join->next;
        }
-       if (!call)
+       if (!join)
        {
-               /* create call */
-               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new call instance.\n", ea_endpoint->ep_serial);
-               if (!(call = new CallPBX(ea_endpoint)))
-               {
-                       PERROR("no memory for call, exitting");
-                       exit(-1);
-               }
+               /* create join */
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new join instance.\n", ea_endpoint->ep_serial);
+               if (!(join = new JoinPBX(ea_endpoint)))
+                       FATAL("No memory for join object\n");
        } else
        {
-//NOTE: callpbx must be set here
-               /* add relation to existing call */
-               if (!(relation=callpbx->add_relation()))
-               {
-                       PERROR("no memory for call relation, exitting");
-                       exit(-1);
-               }
+//NOTE: joinpbx must be set here
+               /* add relation to existing join */
+               if (!(relation=joinpbx->add_relation()))
+                       FATAL("No memory for join relation\n");
                relation->type = RELATION_TYPE_SETUP;
                relation->channel_state = CHANNEL_STATE_CONNECT;
                relation->rx_state = NOTIFY_STATE_ACTIVE;
@@ -547,20 +607,22 @@ void EndpointAppPBX::action_init_partyline(void)
                relation->epoint_id = ea_endpoint->ep_serial;
 
        }
-       ea_endpoint->ep_call_id = call->c_serial;
+       ea_endpoint->ep_join_id = join->j_serial;
 
        set_tone(portlist, "proceeding");
        message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
        message_put(message);
-       logmessage(message);
+       logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
        new_state(EPOINT_STATE_IN_PROCEEDING);
 
-       /* send setup to call */
+       /* send setup to join */
        trace_header("ACTION partyline (calling)", DIRECTION_NONE);
        add_trace("room", NULL, "%d", partyline);
+       add_trace("jingle", NULL, (jingle)?"on":"off");
        end_trace();
-       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_SETUP);
+       message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
        message->param.setup.partyline = partyline;
+       message->param.setup.partyline_jingle = jingle;
        memcpy(&message->param.setup.dialinginfo, &e_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));
@@ -574,44 +636,8 @@ void EndpointAppPBX::action_init_partyline(void)
  */
 void EndpointAppPBX::action_hangup_call(void)
 {
-       int i;
-
        trace_header("ACTION hangup", DIRECTION_NONE);
        end_trace();
-       /* check */
-       if (e_ext.number[0] == '\0')
-       {
-               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last dialed number '%s' because caller is unknown (not internal).\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
-               return;
-       }
-       if (!(read_extension(&e_ext, e_ext.number)))
-       {
-               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last dialed number '%s' because cannot read settings.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
-               return;
-       }
-       if (e_dialinginfo.id[0] == '\0')
-       {
-               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last dialed number because nothing was dialed.\n", ea_endpoint->ep_serial, e_ext.number);
-               return;
-       }
-       if (!strcmp(e_dialinginfo.id, e_ext.last_out[0]))
-       {
-               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last dialed number '%s' because it is identical with the last one.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
-               return;
-       }
-
-       /* insert */
-       PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing last number '%s'.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
-       i = MAX_REMEMBER-1;
-       while(i)
-       {
-               UCPY(e_ext.last_out[i], e_ext.last_out[i-1]);
-               i--;
-       }
-       SCPY(e_ext.last_out[0], e_dialinginfo.id);
-
-       /* write extension */
-       write_extension(&e_ext, e_ext.number);
 }
 
 
@@ -621,7 +647,7 @@ void EndpointAppPBX::action_hangup_call(void)
 void EndpointAppPBX::action_dialing_login(void)
 {
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        char *extension;
        struct route_param *rparam;
 
@@ -672,12 +698,12 @@ void EndpointAppPBX::action_dialing_login(void)
                message->param.connectinfo.present = INFO_PRESENT_RESTRICTED;
        else    message->param.connectinfo.present = e_ext.callerid_present;
        /* handle restricted caller ids */
-       apply_callerid_restriction(e_ext.anon_ignore, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
+       apply_callerid_restriction(&e_ext, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
        /* display callerid if desired for extension */
        SCPY(message->param.connectinfo.display, apply_callerid_display(message->param.connectinfo.id, message->param.connectinfo.itype, message->param.connectinfo.ntype, message->param.connectinfo.present, message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name));
        message->param.connectinfo.ntype = e_ext.callerid_type;
        message_put(message);
-       logmessage(message);
+       logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
 
        /* set our caller id */
        SCPY(e_callerinfo.id, e_ext.callerid);
@@ -965,7 +991,7 @@ void EndpointAppPBX::action_init_redial_reply(void)
 */
 void EndpointAppPBX::_action_redial_reply(int in)
 {
-       struct message *message;
+       struct lcr_msg *message;
        char *last;
        struct route_param *rparam;
 
@@ -1041,7 +1067,7 @@ void EndpointAppPBX::_action_redial_reply(int in)
                SPRINT(message->param.notifyinfo.display, "(%d) %s", e_select+1, (last[0])?last:"- empty -");
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s sending display:%s\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
        message_put(message);
-       logmessage(message);
+       logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
 }
 
 /* process dialing redial
@@ -1064,7 +1090,7 @@ void EndpointAppPBX::action_dialing_reply(void)
 void EndpointAppPBX::action_dialing_powerdial(void)
 {
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        struct route_param *rparam;
 
        /* power dialing only possible if we have a last dialed number */
@@ -1114,7 +1140,7 @@ void EndpointAppPBX::action_dialing_powerdial(void)
        memset(&e_connectinfo, 0, sizeof(e_connectinfo));
        message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
        message_put(message);
-       logmessage(message);
+       logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
 
        /* do dialing */
        SCPY(e_dialinginfo.id, e_ext.last_out[0]);
@@ -1295,7 +1321,7 @@ void EndpointAppPBX::action_dialing_test(void)
        unsigned int cause;
        char causestr[16];
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        class Port *port;
        char testcode[32] = "";
        struct route_param *rparam;
@@ -1315,7 +1341,7 @@ void EndpointAppPBX::action_dialing_test(void)
                set_tone(portlist, "proceeding");
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                break;
                
                case '2':
@@ -1326,7 +1352,7 @@ void EndpointAppPBX::action_dialing_test(void)
                set_tone(portlist, "ringpbx");
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                break;
                
                case '3':
@@ -1347,11 +1373,11 @@ void EndpointAppPBX::action_dialing_test(void)
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
                memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
                /* handle restricted caller ids */
-               apply_callerid_restriction(e_ext.anon_ignore, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
+               apply_callerid_restriction(&e_ext, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
                /* display callerid if desired for extension */
                SCPY(message->param.connectinfo.display, apply_callerid_display(message->param.connectinfo.id, message->param.connectinfo.itype, message->param.connectinfo.ntype, message->param.connectinfo.present, message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name));
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
 
                port = find_port_id(portlist->port_id);
                if (port)
@@ -1370,7 +1396,7 @@ void EndpointAppPBX::action_dialing_test(void)
                memset(&e_connectinfo, 0, sizeof(e_connectinfo));
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                set_tone(portlist, "test");
                break;
                
@@ -1384,7 +1410,7 @@ void EndpointAppPBX::action_dialing_test(void)
                memset(&e_connectinfo, 0, sizeof(e_connectinfo));
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                set_tone(portlist, "hold");
                break;
                
@@ -1406,7 +1432,7 @@ void EndpointAppPBX::action_dialing_test(void)
                memset(&e_connectinfo, 0, sizeof(e_connectinfo));
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                set_tone(portlist, causestr);
                break;
                
@@ -1453,7 +1479,7 @@ void EndpointAppPBX::action_dialing_test(void)
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
                memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(message->param.connectinfo));
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                set_tone(portlist, "hold");
                break;
        }
@@ -1507,7 +1533,7 @@ void EndpointAppPBX::action_init_play(void)
 void EndpointAppPBX::action_dialing_calculator(void)
 {
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        double value1, value2, v, sign1;
        int komma1, komma2, k, state, mode, first;
        char *p;
@@ -1746,7 +1772,7 @@ void EndpointAppPBX::action_dialing_calculator(void)
        SPRINT(message->param.notifyinfo.display, ">%s", e_extdialing);
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s displaying interpreted dialing '%s' internal values: %f %f\n", ea_endpoint->ep_serial, e_ext.number, e_extdialing, value1, value2);
        message_put(message);
-       logmessage(message);
+       logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
 
 }
 
@@ -1799,7 +1825,7 @@ void EndpointAppPBX::_action_goto_menu(int mode)
        } else
        {
                /* remove digits that are required to match the rule */
-               if (!(rparam = routeparam(e_action, PARAM_STRIP)))
+               if ((rparam = routeparam(e_action, PARAM_STRIP)))
                {
                        if (e_extdialing)
                                SCPY(e_dialinginfo.id, e_extdialing);
@@ -1811,13 +1837,18 @@ void EndpointAppPBX::_action_goto_menu(int mode)
        trace_header("ACTION goto/menu (change to)", DIRECTION_NONE);
        add_trace("ruleset", NULL, "%s", e_ruleset->name);
        if (e_dialinginfo.id[0])
+       {
                add_trace("dialing", NULL, "%s", e_dialinginfo.id);
+       }
        if ((rparam = routeparam(e_action, PARAM_SAMPLE)))
        {
                add_trace("sample", NULL, "%s", rparam->string_value);
+               end_trace();
                set_tone(ea_endpoint->ep_portlist, rparam->string_value);
+       } else
+       {
+               end_trace();
        }
-       end_trace();
 
        /* do dialing with new ruleset */
        e_action = NULL;
@@ -1846,7 +1877,7 @@ void EndpointAppPBX::action_dialing_disconnect(void)
 {
        struct route_param *rparam;
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        int cause = CAUSE_NORMAL; /* normal call clearing */
        int location = LOCATION_PRIVATE_LOCAL;
        char cause_string[256] = "", display[84] = "";
@@ -1900,7 +1931,7 @@ void EndpointAppPBX::action_dialing_disconnect(void)
                message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
                SCPY(message->param.notifyinfo.display, display);
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
        }
        e_action = NULL;
 }
@@ -1916,7 +1947,7 @@ void EndpointAppPBX::action_dialing_help(void)
        struct numbering *numbering = numbering_int;
        char dialing[sizeof(e_dialinginfo.id)];
        int i;
-       struct message *message;
+       struct lcr_msg *message;
        struct route_param *rparam;
 
        /* in case we have no menu (this should never happen) */
@@ -1982,7 +2013,7 @@ nesting?:
        SPRINT(message->param.notifyinfo.display, ">%s %s%s%s", numbering->prefix, numb_actions[numbering->action], (numbering->param[0])?" ":"", numbering->param);
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' sending display:%s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], message->param.notifyinfo.display);
        message_put(message);
-       logmessage(message);
+       logmessage(message->type, message->paramea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
 #endif
 }
 
@@ -2009,8 +2040,9 @@ void EndpointAppPBX::action_dialing_setforward(void)
 void EndpointAppPBX::action_hangup_execute(void)
 {
        struct route_param *rparam;
+       pid_t pid;
        char *command = "", isdn_port[10];
-       char *argv[7+1]; /* check also number of args below */
+       char *argv[11]; /* check also number of args below */
        int i = 0;
 
        /* get script / command */
@@ -2022,26 +2054,35 @@ void EndpointAppPBX::action_hangup_execute(void)
                end_trace();
                return;
        }
-       trace_header("ACTION execute", DIRECTION_NONE);
-       add_trace("command", NULL, "%s", command);
-       end_trace();
-
-       argv[0] = command;
-       while(strchr(argv[0], '/'))
-               argv[0] = strchr(argv[0], '/')+1;
+       argv[i++] = "/bin/sh";
+       argv[i++] = "-c";
+       argv[i++] = command;
+       argv[i++] = command;
        if ((rparam = routeparam(e_action, PARAM_PARAM)))
        {
-               argv[1] = rparam->string_value;
-               i++;
+               argv[i++] = rparam->string_value;
        }
-       argv[1+i] = e_extdialing;
-       argv[2+i] = numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype);
-       argv[3+i] = e_callerinfo.extension;
-       argv[4+i] = e_callerinfo.name;
+       argv[i++] = e_extdialing;
+       argv[i++] = numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype);
+       argv[i++] = e_callerinfo.extension;
+       argv[i++] = e_callerinfo.name;
        SPRINT(isdn_port, "%d", e_callerinfo.isdn_port);
-       argv[5+i] = isdn_port;
-       argv[6+i] = NULL; /* check also number of args above */
-       execve("/bin/sh", argv, environ);
+       argv[i++] = isdn_port;
+       argv[i++] = NULL; /* check also number of args above */
+       switch (pid = fork ()) {
+               case -1:
+                       trace_header("ACTION execute (fork failed)", DIRECTION_NONE);
+                       end_trace();
+                       break;
+               case 0:
+                       execve("/bin/sh", argv, environ);
+                       break;
+               default:
+                       trace_header("ACTION execute", DIRECTION_NONE);
+                       add_trace("command", NULL, "%s", command);
+                       end_trace();
+                       break;
+       }
 }
 
 
@@ -2106,7 +2147,7 @@ void EndpointAppPBX::action_init_pick(void)
        if (extensions) if (extensions[0])
                add_trace("extensions", NULL, "%s", extensions);
        end_trace();
-       pick_call(extensions);
+       pick_join(extensions);
 }
 
 
@@ -2181,7 +2222,7 @@ void EndpointAppPBX::action_dialing_password_wr(void)
 void EndpointAppPBX::process_dialing(void)
 {
        struct port_list *portlist = ea_endpoint->ep_portlist;
-       struct message *message;
+       struct lcr_msg *message;
        struct route_param *rparam;
 
 //#warning Due to HANG-BUG somewhere here, I added some HANG-BUG-DEBUGGING output that cannot be disabled. after bug has been found, this will be removed.
@@ -2232,7 +2273,7 @@ void EndpointAppPBX::process_dialing(void)
                        release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
                        goto end;
                }
-               release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, 0);
+               release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0);
                e_action = e_action->next;
                if (!e_action)
                {
@@ -2250,7 +2291,7 @@ void EndpointAppPBX::process_dialing(void)
        if (e_state!=EPOINT_STATE_IN_SETUP
         && e_state!=EPOINT_STATE_IN_OVERLAP)
        {
-               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): we are not in incomming setup/overlap state, so we ignore init/dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): we are not in incoming setup/overlap state, so we ignore init/dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
                e_match_timeout = 0;
                goto end;
        }
@@ -2281,7 +2322,7 @@ void EndpointAppPBX::process_dialing(void)
                                        SCPY(message->param.notifyinfo.display,get_isdn_cause(LOCATION_PRIVATE_LOCAL, epoint->e_ext.display_cause, param->disconnectinfo.location, param->disconnectinfo.cause));
                                }
                        message_put(message);
-                       logmessage(message);
+                       logmessage(message->type, message->param, portlist->port_id, DIRECTION_OUT);
                }
                new_state(EPOINT_STATE_OUT_DISCONNECT);
                set_tone(portlist,"cause_1c");
@@ -2312,10 +2353,10 @@ void EndpointAppPBX::process_dialing(void)
                        goto process_action;
                }
                /* check for chan call */
-               if (!strncmp(e_dialinginfo.id, "chan:", 5))
+               if (!strncmp(e_dialinginfo.id, "remote:", 7))
                {
-                       e_extdialing = e_dialinginfo.id+4;
-                       e_action = &action_chan;
+                       e_extdialing = e_dialinginfo.id+7;
+                       e_action = &action_remote;
                        goto process_action;
                }
                /* check for vbox call */
@@ -2391,7 +2432,7 @@ void EndpointAppPBX::process_dialing(void)
                        memset(&e_connectinfo, 0, sizeof(e_connectinfo));
                        message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
                        message_put(message);
-                       logmessage(message);
+                       logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                } else
                if ((rparam = routeparam(e_action, PARAM_ALERTING)))
                {
@@ -2399,7 +2440,7 @@ void EndpointAppPBX::process_dialing(void)
                        memset(&e_connectinfo, 0, sizeof(e_connectinfo));
                        message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
                        message_put(message);
-                       logmessage(message);
+                       logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                } else
                if ((rparam = routeparam(e_action, PARAM_PROCEEDING)))
                {
@@ -2407,7 +2448,7 @@ void EndpointAppPBX::process_dialing(void)
                        memset(&e_connectinfo, 0, sizeof(e_connectinfo));
                        message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
                        message_put(message);
-                       logmessage(message);
+                       logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
                }
 
                if (action_defs[e_action->index].init_func)
@@ -2418,7 +2459,7 @@ void EndpointAppPBX::process_dialing(void)
                if (e_state!=EPOINT_STATE_IN_SETUP
                 && e_state!=EPOINT_STATE_IN_OVERLAP)
                {
-                       PDEBUG(DEBUG_EPOINT, "EPOINT(%d): AFTER init process: we are not in incomming setup/overlap state anymore, so we ignore further dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
+                       PDEBUG(DEBUG_EPOINT, "EPOINT(%d): AFTER init process: we are not in incoming setup/overlap state anymore, so we ignore further dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
                        goto display_action;
                }
        }
@@ -2462,7 +2503,7 @@ void EndpointAppPBX::process_dialing(void)
 
                PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s displaying interpreted dialing '%s'\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
                message_put(message);
-               logmessage(message);
+               logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
        }
 
 end:
@@ -2518,6 +2559,7 @@ void EndpointAppPBX::process_hangup(int cause, int location)
                write_log(e_ext.number, callertext, dialingtext, e_start, e_stop, 0, cause, location);
 
                /* store last received call for reply-list */
+               if (e_origin == 1) // outgoing to phone is incoming for user
                if (e_callerinfo.id[0] || e_callerinfo.extension[0])
                if (e_ext.anon_ignore || e_callerinfo.present!=INFO_PRESENT_RESTRICTED)
                {
@@ -2539,8 +2581,26 @@ void EndpointAppPBX::process_hangup(int cause, int location)
                        } else
                                PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last received id '%s' because it is identical with the last one.\n", ea_endpoint->ep_serial, e_ext.number, callertext);
                }
-       }
 
+               /* store last made call for reply-list */
+               if (e_origin == 0) // incoming from phone is outgoing for user
+               if (e_dialinginfo.id[0])
+               {
+                       if (!!strcmp(e_dialinginfo.id, e_ext.last_out[0]))
+                       {
+                               i = MAX_REMEMBER-1;
+                               while(i)
+                               {
+                                       UCPY(e_ext.last_out[i], e_ext.last_out[i-1]);
+                                       i--;
+                               }
+                               SCPY(e_ext.last_out[0], e_dialinginfo.id);
+                               writeext |= 1; /* store extension later */
+                               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing last number '%s'.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
+                       } else
+                               PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last number '%s' because it is identical with the last one.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
+               }
+       }
        /* write extension if needed */
        if (writeext == 0x11)
                write_extension(&e_ext, e_ext.number);