unified socket application interface (for asterisk and maybe other apps)
[lcr.git] / admin_client.c
index 82b21e9..02624a0 100644 (file)
@@ -1,6 +1,6 @@
 /*****************************************************************************\
 **                                                                           **
-** PBX4Linux                                                                 **
+** Linux Call Router                                                         **
 **                                                                           **
 **---------------------------------------------------------------------------**
 ** Copyright: Andreas Eversberg                                              **
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <curses.h>
-#include "save.h"
-#include "call.h"
-#include "callpbx.h"
+#include "macro.h"
+#include "join.h"
+#include "joinpbx.h"
+#include "extension.h"
+#include "message.h"
 #include "admin.h"
 #include "cause.h"
 
-#define LTEE {addch(/*ACS_LTEE*/'t');addch(/*ACS_HLINE*/'q');addch(/*ACS_HLINE*/'q');}
-#define LLCORNER {addch(/*ACS_LLCORNER*/'m');addch(/*ACS_HLINE*/'q');addch(/*ACS_HLINE*/'q');}
-#define VLINE {addch(/*ACS_VLINE*/'x');addstr("  ");}
+#define LTEE {addch(ACS_LTEE);addch(ACS_HLINE);addch(ACS_HLINE);}
+#define LLCORNER {addch(ACS_LLCORNER);addch(ACS_HLINE);addch(ACS_HLINE);}
+#define VLINE {addch(ACS_VLINE);addstr("  ");}
 #define EMPTY {addstr("   ");}
 //char rotator[] = {'-', '\\', '|', '/'};
 int    lastlines, lastcols;
@@ -42,6 +44,9 @@ enum {
        MODE_ROUTE,
        MODE_DIAL,
        MODE_RELEASE,
+       MODE_UNBLOCK,
+       MODE_BLOCK,
+       MODE_UNLOAD,
        MODE_TESTCALL,
        MODE_TRACE,
 };
@@ -68,7 +73,7 @@ char  red = 1,
        white = 7;
 
 #define LOGLINES 128
-char logline[LOGLINES][256];
+char logline[LOGLINES][512];
 unsigned long logcur = 0;
 int logfh = -1;
 char logfile[128];
@@ -352,7 +357,7 @@ int debug_epoint(struct admin_message *msg, struct admin_message *m, int line, i
        }
        /* loop all related ports */
        ltee = 0;
-       j = msg->u.s.interfaces+msg->u.s.calls+msg->u.s.epoints;
+       j = msg->u.s.interfaces+msg->u.s.joins+msg->u.s.epoints;
        jj = j + msg->u.s.ports;
        while(j < jj)
        {
@@ -383,39 +388,47 @@ int debug_epoint(struct admin_message *msg, struct admin_message *m, int line, i
 
        return(line);
 }
-int debug_call(struct admin_message *msg, struct admin_message *m, int line, int i)
+int debug_join(struct admin_message *msg, struct admin_message *m, int line, int i)
 {
-       unsigned long   call = m[i].u.c.serial;
+       unsigned long   join = m[i].u.j.serial;
        char            buffer[256];
        int             j, jj;
 
        color(white);
-       SPRINT(buffer,"CALL(%d)", call);
+       SPRINT(buffer,"JOIN(%d)", join);
        addstr(buffer);
-       if (m[i].u.c.partyline)
+       if (m[i].u.j.partyline)
        {
                color(cyan);
                addstr(" partyline=");
                color(white);
-               SPRINT(buffer, "%d\n", m[i].u.c.partyline);
+               SPRINT(buffer, "%d\n", m[i].u.j.partyline);
+               addstr(buffer);
+       }
+       if (m[i].u.j.remote[0])
+       {
+               color(cyan);
+               addstr(" remote=");
+               color(white);
+               SPRINT(buffer, "%s\n", m[i].u.j.remote);
                addstr(buffer);
        }
        /* find number of epoints */
-       j = msg->u.s.interfaces+msg->u.s.calls;
+       j = msg->u.s.interfaces+msg->u.s.joins;
        jj = j + msg->u.s.epoints;
        i = 0;
        while(j < jj)
        {
-               if (m[j].u.e.call == call)
+               if (m[j].u.e.join == join)
                        i++;
                j++;
        }
        /* loop all related endpoints */
-       j = msg->u.s.interfaces+msg->u.s.calls;
+       j = msg->u.s.interfaces+msg->u.s.joins;
        jj = j + msg->u.s.epoints;
        while(j < jj)
        {
-               if (m[j].u.e.call == call)
+               if (m[j].u.e.join == join)
                {
                        i--;
                        move(++line>1?line:1, 1);
@@ -434,13 +447,13 @@ int debug_call(struct admin_message *msg, struct admin_message *m, int line, int
 
        return(line);
 }
-char *admin_state(int sock)
+char *admin_state(int sock, char *argv[])
 {
        struct admin_message    msg,
                                *m;
-       char                    buffer[256],
+       char                    buffer[512],
                                *p;
-       int                     line, offset = 0;
+       int                     line, offset = 0, hoffset = 0;
        int                     i, ii, j, jj, k;
        unsigned long           l, ll;
        int                     num;
@@ -448,6 +461,8 @@ char *admin_state(int sock)
        int                     off;
        int                     ltee;
        int                     anything;
+       int                     enter = 0;
+       char                    enter_string[128] = "", ch;
 
        /* flush logfile name */
        logfile[0] = '\0';
@@ -459,7 +474,7 @@ char *admin_state(int sock)
        /* send reload command */
        memset(&msg, 0, sizeof(msg));
        msg.message = ADMIN_REQUEST_STATE;
-//     printf("sizeof=%d\n",sizeof(msg));
+//     printf("sizeof=%d\n",sizeof(msg));fflush(stdout);
        if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
        {
                cleanup_curses();
@@ -472,31 +487,31 @@ char *admin_state(int sock)
                cleanup_curses();
                return("Broken pipe while receiving response.");
        }
+
        if (msg.message != ADMIN_RESPONSE_STATE)
        {
                cleanup_curses();
                return("Response not valid. Expecting state response.");
        }
-       num = msg.u.s.interfaces + msg.u.s.calls + msg.u.s.epoints + msg.u.s.ports;
-       if (!(m = (struct admin_message *)malloc(num*sizeof(struct admin_message))))
-       {
-               cleanup_curses();
-               return("Not enough memory for messages.");
-       }
+       num = msg.u.s.interfaces + msg.u.s.remotes + msg.u.s.joins + msg.u.s.epoints + msg.u.s.ports;
+       m = (struct admin_message *)MALLOC(num*sizeof(struct admin_message));
        off=0;
-readagain:
-       if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off)
+       if (num)
        {
-               if (len <= 0) {
-                       free(m);
-//                     fprintf(stderr, "got=%d expected=%d\n", i, num*sizeof(struct admin_message));
-                       cleanup_curses();
-                       return("Broken pipe while receiving state infos.");
-               }
-               if (len < num*(int)sizeof(struct admin_message))
+               readagain:
+               if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off)
                {
-                       off+=len;
-                       goto readagain;
+                       if (len <= 0) {
+                               FREE(m, 0);
+       //                      fprintf(stderr, "got=%d expected=%d\n", i, num*sizeof(struct admin_message));
+                               cleanup_curses();
+                               return("Broken pipe while receiving state infos.");
+                       }
+                       if (len < num*(int)sizeof(struct admin_message))
+                       {
+                               off+=len;
+                               goto readagain;
+                       }
                }
        }
        j = 0;
@@ -507,7 +522,7 @@ readagain:
 //             fprintf(stderr, "j=%d message=%d\n", j, m[j].message);
                if (m[j].message != ADMIN_RESPONSE_S_INTERFACE)
                {
-                       free(m);
+                       FREE(m, 0);
                        cleanup_curses();
                        return("Response not valid. Expecting interface information.");
                }
@@ -515,13 +530,25 @@ readagain:
                j++;
        }
        i = 0;
-       while(i < msg.u.s.calls)
+       while(i < msg.u.s.remotes)
+       {
+               if (m[j].message != ADMIN_RESPONSE_S_REMOTE)
+               {
+                       FREE(m, 0);
+                       cleanup_curses();
+                       return("Response not valid. Expecting remote application information.");
+               }
+               i++;
+               j++;
+       }
+       i = 0;
+       while(i < msg.u.s.joins)
        {
-               if (m[j].message != ADMIN_RESPONSE_S_CALL)
+               if (m[j].message != ADMIN_RESPONSE_S_JOIN)
                {
-                       free(m);
+                       FREE(m, 0);
                        cleanup_curses();
-                       return("Response not valid. Expecting call information.");
+                       return("Response not valid. Expecting join information.");
                }
                i++;
                j++;
@@ -531,7 +558,7 @@ readagain:
        {
                if (m[j].message != ADMIN_RESPONSE_S_EPOINT)
                {
-                       free(m);
+                       FREE(m, 0);
                        cleanup_curses();
                        return("Response not valid. Expecting endpoint information.");
                }
@@ -543,7 +570,7 @@ readagain:
        {
                if (m[j].message != ADMIN_RESPONSE_S_PORT)
                {
-                       free(m);
+                       FREE(m, 0);
                        cleanup_curses();
                        return("Response not valid. Expecting port information.");
                }
@@ -633,116 +660,140 @@ readagain:
                        /* show interface summary */
                        move(++line>1?line:1, 0);
                        color(white);
-
-                       SPRINT(buffer, "%s(%d) '%s' %s use:%d ", (m[i].u.i.ntmode)?"NT":"TE", m[i].u.i.portnum, m[i].u.i.interface_name, (m[i].u.i.ptp)?"ptp ":"ptmp", m[i].u.i.use);
-                       addstr(buffer);
-                       if (m[i].u.i.ptp || !m[i].u.i.ntmode)
+                       if (m[i].u.i.block >= 2)
                        {
-                               color((m[i].u.i.l2link)?green:red);
-                               addstr((m[i].u.i.l2link)?"  L2 UP":"  L2 down");
-                       }
-                       color((m[i].u.i.l1link)?green:blue);
-                       addstr((m[i].u.i.l1link)?"  L1 ACTIVE":"  L1 inactive");
-                       if (line+2 >= LINES) goto end;
-                       /* show channels */
-                       if (show_interfaces > 1)
+                               SPRINT(buffer, "%s (%d)%s", m[i].u.i.interface_name, m[i].u.i.portnum, (m[i].u.i.extension)?" (extension)":"");
+                               addstr(buffer);
+                               color(red);
+                               addstr("  not loaded");
+                       } else
                        {
-                               ltee = 0;
-                               j = k =0;
-                               jj = m[i].u.i.channels;
-                               while(j < jj)
+                               SPRINT(buffer, "%s (%d) %s %s%s use:%d", m[i].u.i.interface_name, m[i].u.i.portnum, (m[i].u.i.ntmode)?"NT-mode":"TE-mode", (m[i].u.i.ptp)?"ptp ":"ptmp", (m[i].u.i.extension)?" extension":"", m[i].u.i.use);
+                               addstr(buffer);
+                               if (m[i].u.i.ptp || !m[i].u.i.ntmode)
                                {
-                                       /* show all channels */
-                                       if (show_interfaces>2 || m[i].u.i.busy[j]>0)
+                                       color((m[i].u.i.l2link)?green:red);
+                                       addstr((m[i].u.i.l2link)?"  L2 UP":"  L2 down");
+                               }
+                               color((m[i].u.i.l1link)?green:blue);
+                               addstr((m[i].u.i.l1link)?"  L1 ACTIVE":"  L1 inactive");
+                               if (m[i].u.i.block)
+                               {
+                                       color(red);
+                                       addstr("  blocked");
+                               }
+                               if (line+2 >= LINES) goto end;
+                               /* show channels */
+                               if (show_interfaces > 1)
+                               {
+                                       ltee = 0;
+                                       j = k =0;
+                                       jj = m[i].u.i.channels;
+                                       while(j < jj)
                                        {
-                                               color(cyan);
-                                               /* show left side / right side */
-                                               if ((k & 1) && (COLS > 70))
-                                               {
-                                                       move(line>1?line:1,4+((COLS-4)/2));
-                                               } else
+                                               /* show all channels */
+                                               if (show_interfaces>2 || m[i].u.i.busy[j]>0)
                                                {
-                                                       move(++line>1?line:1, 1);
-                                                       LTEE
-                                                       ltee = 1;
-                                               }
-                                               k++;
-                                               color(white);
-                                               if (m[i].u.i.pri)
-                                                       SPRINT(buffer,"S%2d: ", j+1+(j>=15));
-                                               else
-                                                       SPRINT(buffer,"B%2d: ", j+1);
-                                               addstr(buffer);
-                                               if (!m[i].u.i.ptp)
-                                                       goto ptmp;
-                                               if (m[i].u.i.l2link)
-                                               {
-                                                       ptmp:
-                                                       color((m[i].u.i.busy[j])?yellow:blue);
-                                                       addstr((m[i].u.i.busy[j])?"busy":"idle");
-                                               } else
-                                               {
-                                                       color(red);
-                                                       addstr("blk ");
-                                               }
-                                               if (m[i].u.i.port[j])
-                                               {
-                                                       /* search for port */
-                                                       l = msg.u.s.interfaces+msg.u.s.calls+msg.u.s.epoints;
-                                                       ll = l+msg.u.s.ports;
-                                                       while(l < ll)
+                                                       color(cyan);
+                                                       /* show left side / right side */
+                                                       if ((k & 1) && (COLS > 70))
+                                                       {
+                                                               move(line>1?line:1,4+((COLS-4)/2));
+                                                       } else
+                                                       {
+                                                               move(++line>1?line:1, 1);
+                                                               LTEE
+                                                               ltee = 1;
+                                                       }
+                                                       k++;
+                                                       color(white);
+                                                       if (m[i].u.i.pri)
+                                                               SPRINT(buffer,"S%2d: ", j+1+(j>=15));
+                                                       else
+                                                               SPRINT(buffer,"B%2d: ", j+1);
+                                                       addstr(buffer);
+                                                       if (!m[i].u.i.ptp)
+                                                               goto ptmp;
+                                                       if (m[i].u.i.l2link && m[i].u.i.block==0)
                                                        {
-                                                               if (m[l].u.p.serial == m[i].u.i.port[j])
+                                                               ptmp:
+                                                               color((m[i].u.i.busy[j])?yellow:blue);
+                                                               addstr((m[i].u.i.busy[j])?"busy":"idle");
+                                                       } else
+                                                       {
+                                                               color(red);
+                                                               addstr("blk ");
+                                                       }
+                                                       if (m[i].u.i.port[j])
+                                                       {
+                                                               /* search for port */
+                                                               l = msg.u.s.interfaces+msg.u.s.joins+msg.u.s.epoints;
+                                                               ll = l+msg.u.s.ports;
+                                                               while(l < ll)
                                                                {
-                                                                       SPRINT(buffer, " %s(%ld)", m[l].u.p.name, m[l].u.p.serial);
-                                                                       addstr(buffer);
+                                                                       if (m[l].u.p.serial == m[i].u.i.port[j])
+                                                                       {
+                                                                               SPRINT(buffer, " %s(%ld)", m[l].u.p.name, m[l].u.p.serial);
+                                                                               addstr(buffer);
+                                                                       }
+                                                                       l++;
                                                                }
-                                                               l++;
                                                        }
-                                               }
-                                               if (line+2 >= LINES)
-                                               {
-                                                       if (ltee)
+                                                       if (line+2 >= LINES)
                                                        {
-                                                               color(cyan);
-                                                               move(line>1?line:1, 1);
-                                                               LLCORNER
+                                                               if (ltee)
+                                                               {
+                                                                       color(cyan);
+                                                                       move(line>1?line:1, 1);
+                                                                       LLCORNER
+                                                               }
+                                                               goto end;
                                                        }
-                                                       goto end;
                                                }
+                                               j++;
                                        }
-                                       j++;
-                               }
-                               if (ltee)
-                               {
-                                       color(cyan);
-                                       move(line>1?line:1, 1);
-                                       LLCORNER
-                               }
-                               if (line+2 >= LINES) goto end;
-                               /* show summary if no channels were shown */
-                               if (show_interfaces<2 && ltee==0)
-                               {
-                                       color(cyan);
-                                       move(++line>1?line:1, 1);
-                                       LLCORNER
-                                               
-                                       if (m[i].u.i.l2link)
+                                       if (ltee)
                                        {
-                                               color(green);
-                                               SPRINT(buffer,"all %d channels free", m[i].u.i.channels);
-                                       } else
+                                               color(cyan);
+                                               move(line>1?line:1, 1);
+                                               LLCORNER
+                                       }
+                                       if (line+2 >= LINES) goto end;
+                                       /* show summary if no channels were shown */
+                                       if (show_interfaces<2 && ltee==0)
                                        {
-                                               color(red);
-                                               SPRINT(buffer,"all %d channels blocked", m[i].u.i.channels);
+                                               color(cyan);
+                                               move(++line>1?line:1, 1);
+                                               LLCORNER
+                                                       
+                                               if (m[i].u.i.l2link && m[i].u.i.block==0)
+                                               {
+                                                       color(green);
+                                                       SPRINT(buffer,"all %d channels free", m[i].u.i.channels);
+                                               } else
+                                               {
+                                                       color(red);
+                                                       SPRINT(buffer,"all %d channels blocked", m[i].u.i.channels);
+                                               }
+                                               addstr(buffer);
                                        }
-                                       addstr(buffer);
+                                       if (line+2 >= LINES) goto end;
                                }
-                               if (line+2 >= LINES) goto end;
                        }
                        i++;
                        anything = 1;
                }
+               i = 0;
+               ii = i + msg.u.s.remotes;
+               while(i < ii)
+               {
+                       /* show remote summary */
+                       move(++line>1?line:1, 0);
+                       color(white);
+                       SPRINT(buffer, "Remote: %s", m[i].u.r.name);
+                       addstr(buffer);
+                       i++;
+               }
                if (anything)
                        line++;
                if (line+2 >= LINES) goto end;
@@ -751,12 +802,12 @@ readagain:
        if (show_calls == 1)
        {
                anything = 0;
-               i = msg.u.s.interfaces+msg.u.s.calls;
+               i = msg.u.s.interfaces+msg.u.s.joins;
                ii = i+msg.u.s.epoints;
                while(i < ii)
                {
                        /* for each endpoint... */
-                       if (!m[i].u.e.call)
+                       if (!m[i].u.e.join)
                        {
                                move(++line>1?line:1, 0);
                                color(white);
@@ -791,20 +842,20 @@ readagain:
                        anything = 1;
                }
                j = msg.u.s.interfaces;
-               jj = j+msg.u.s.calls;
+               jj = j+msg.u.s.joins;
                while(j < jj)
                {
                        /* for each call... */
                        move(++line>1?line:1, 0);
                        color(white);
-                       SPRINT(buffer, "(%d):", m[j].u.c.serial);
+                       SPRINT(buffer, "(%d):", m[j].u.j.serial);
                        addstr(buffer);
-                       i = msg.u.s.interfaces+msg.u.s.calls;
+                       i = msg.u.s.interfaces+msg.u.s.joins;
                        ii = i+msg.u.s.epoints;
                        while(i < ii)
                        {
                                /* for each endpoint... */
-                               if (m[i].u.e.call == m[j].u.c.serial)
+                               if (m[i].u.e.join == m[j].u.j.serial)
                                {
                                        color(white);
                                        SPRINT(buffer, " (%d)", m[i].u.e.serial);
@@ -841,7 +892,7 @@ readagain:
        {
                /* show all ports with no epoint */
                anything = 0;
-               i = msg.u.s.interfaces+msg.u.s.calls+msg.u.s.epoints;
+               i = msg.u.s.interfaces+msg.u.s.joins+msg.u.s.epoints;
                ii = i+msg.u.s.ports;
                while(i < ii)
                {
@@ -861,11 +912,11 @@ readagain:
 
                /* show all epoints with no call */
                anything = 0;
-               i = msg.u.s.interfaces+msg.u.s.calls;
+               i = msg.u.s.interfaces+msg.u.s.joins;
                ii = i+msg.u.s.epoints;
                while(i < ii)
                {
-                       if (!m[i].u.e.call)
+                       if (!m[i].u.e.join)
                        {
                                move(++line>1?line:1, 4);
                                if (line+2 >= LINES) goto end;
@@ -879,15 +930,15 @@ readagain:
                        line++;
                if (line+2 >= LINES) goto end;
 
-               /* show all calls */
+               /* show all joins */
                anything = 0;
                i = msg.u.s.interfaces;
-               ii = i+msg.u.s.calls;
+               ii = i+msg.u.s.joins;
                while(i < ii)
                {
                        move(++line>1?line:1, 0);
                        if (line+2 >= LINES) goto end;
-                       line = debug_call(&msg, m, line, i);
+                       line = debug_join(&msg, m, line, i);
                        if (line+2 >= LINES) goto end;
                        i++;
                        anything = 1;
@@ -905,7 +956,7 @@ readagain:
                {
                        move(line++>1?line-1:1, 0);
                        color(blue);
-                       hline(/*ACS_HLINE*/'q', COLS);
+                       hline(ACS_HLINE, COLS);
                        color(white);
                        
                        l = logcur-(LINES-line-2);
@@ -915,10 +966,19 @@ readagain:
                        while(l!=ll)
                        {
                                move(line++>1?line-1:1, 0);
-                               SCPY(buffer, logline[l % LOGLINES]);
-                               if (COLS < (int)sizeof(buffer))
-                                       buffer[COLS] = '\0';
-                               addstr(buffer);
+                               if (strlen(logline[l % LOGLINES]) > hoffset)
+                                       SCPY(buffer, logline[l % LOGLINES] + hoffset);
+                               else
+                                       buffer[0] = '\0';
+                               if (COLS < (int)strlen(buffer))
+                               {
+                                       buffer[COLS-1] = '\0';
+                                       addstr(buffer);
+                                       color(red);
+                                       addch('*');
+                                       color(white);
+                               } else
+                                       addstr(buffer);
                                l++;
                        }
                }
@@ -926,14 +986,14 @@ readagain:
 
        end:
        /* free memory */
-       free(m);
+       FREE(m, 0);
        /* display name/time */
 //     move(0, 0);
 //     hline(' ', COLS);
        move(0, 0);
        color(white);
        msg.u.s.version_string[sizeof(msg.u.s.version_string)-1] = '\0';
-       SPRINT(buffer, "PBX4Linux %s", msg.u.s.version_string);
+       SPRINT(buffer, "LCR %s", msg.u.s.version_string);
        addstr(buffer);
        if (COLS>50)
        {
@@ -946,7 +1006,7 @@ readagain:
        /* displeay head line */
        move(1, 0);
        color(blue);
-       hline(/*ACS_HLINE*/'q', COLS);
+       hline(ACS_HLINE, COLS);
        if (offset)
        {
                move(1, 1);
@@ -954,13 +1014,23 @@ readagain:
                color(red);
                addstr(buffer);
        }
+       if (hoffset)
+       {
+               move(1, 13);
+               SPRINT(buffer, "H-Offset +%d", hoffset);
+               color(red);
+               addstr(buffer);
+       }
        /* display end */
        move(LINES-2, 0);
        color(white);
-       hline(/*ACS_HLINE*/'q', COLS);
+       hline(ACS_HLINE, COLS);
        move(LINES-1, 0);
        color(white);
-       SPRINT(buffer, "i = interfaces '%s'  c = calls '%s'  l = log  q = quit  +/- = scroll", text_interfaces[show_interfaces], text_calls[show_calls]);
+       if (enter)
+               SPRINT(buffer, "-> %s", enter_string);
+       else
+               SPRINT(buffer, "i=interfaces '%s'  c=calls '%s'  l=log  q=quit  +-*/=scroll  enter", text_interfaces[show_interfaces], text_calls[show_calls]);
        addstr(buffer);
        refresh();
 
@@ -972,47 +1042,125 @@ readagain:
                goto again;
        }
 
-       /* user input */
-       switch(getch())
+       if (enter)
        {
-               case 12: /* refresh */
-               cleanup_curses();
-               init_curses();
-               goto again;
-               break;
-
-               case 3: /* abort */
-               case 'q':
-               case 'Q':
-               break;
+               /* user input in enter mode */
+               ch = getch();
+               if (ch == 10)
+               {
+                       FILE *fp;
+
+                       enter = 0;
+                       if (!enter_string[0])
+                               goto again;
+
+                       SPRINT(logline[logcur++ % LOGLINES], "> %s", enter_string);
+                       if (!!strncmp(enter_string, "interface", 10) &&
+                           !!strncmp(enter_string, "route", 6) &&
+                           !!strncmp(enter_string, "release ", 8) &&
+                           !!strncmp(enter_string, "block ", 6) &&
+                           !!strncmp(enter_string, "unblock ", 8) &&
+                           !!strncmp(enter_string, "unload ", 7))
+                       {
+                               SPRINT(logline[logcur++ % LOGLINES], "usage:");
+                               SPRINT(logline[logcur++ % LOGLINES], "interface (reload interface.conf)");
+                               SPRINT(logline[logcur++ % LOGLINES], "route (reload routing.conf)");
+                               SPRINT(logline[logcur++ % LOGLINES], "release <EP> (release endpoint with given ID)");
+                               SPRINT(logline[logcur++ % LOGLINES], "block <port> (block port for further calls)");
+                               SPRINT(logline[logcur++ % LOGLINES], "unblock <port> (unblock port for further calls, load if not loaded)");
+                               SPRINT(logline[logcur++ % LOGLINES], "unload <port> (unload mISDN stack, release call calls)");
+                       } else
+                       {
+                               /* applend output to log window */
+                               SPRINT(buffer, "%s %s", argv[0], enter_string);
+                               fp = popen(buffer, "r");
+                               if (fp)
+                               {
+                                       while(fgets(logline[logcur % LOGLINES], sizeof(logline[0]), fp))
+                                               logline[logcur++ % LOGLINES][sizeof(logline[0])-1] = '\0';
+                                       pclose(fp);
+                               } else
+                               {
+                                       SPRINT(logline[logcur++ % LOGLINES], "failed to execute '%s'", buffer);
+                               }
+                       }
+                       logline[logcur % LOGLINES][0] = '\0';
+                       enter_string[0] = '\0';
+                       goto again;
+               }
+               if (ch>=32 && ch<=126)
+               {
+                       SCCAT(enter_string, ch);
+                       goto again;
+               } else
+               if (ch==8 || ch==127)
+               {
+                       if (enter_string[0])
+                               enter_string[strlen(enter_string)-1] = '\0';
+                       goto again;
+               } else
+               if (ch != 3)
+               {
+                       usleep(250000);
+                       goto again;
+               }
+       } else
+       {
+               /* user input in normal mode */
+               switch(getch())
+               {
+                       case 12: /* refresh */
+                       cleanup_curses();
+                       init_curses();
+                       goto again;
+                       break;
 
-               case 'i': /* toggle interface */
-               show_interfaces++;
-               if (show_interfaces > 3) show_interfaces = 0;
-               goto again;
+                       case 3: /* abort */
+                       case 'q':
+                       case 'Q':
+                       break;
 
-               case 'c': /* toggle calls */
-               show_calls++;
-               if (show_calls > 2) show_calls = 0;
-               goto again;
+                       case 'i': /* toggle interface */
+                       show_interfaces++;
+                       if (show_interfaces > 3) show_interfaces = 0;
+                       goto again;
 
-               case 'l': /* toggle log */
-               show_log++;
-               if (show_log > 1) show_log = 0;
-               goto again;
+                       case 'c': /* toggle calls */
+                       show_calls++;
+                       if (show_calls > 2) show_calls = 0;
+                       goto again;
 
-               case '+': /* scroll down */
-               offset++;
-               goto again;
-               
-               case '-': /* scroll up */
-               if (offset)
-                       offset--;
-               goto again;
+                       case 'l': /* toggle log */
+                       show_log++;
+                       if (show_log > 1) show_log = 0;
+                       goto again;
 
-               default:
-               usleep(250000);
-               goto again;
+                       case '+': /* scroll down */
+                       offset++;
+                       goto again;
+                       
+                       case '-': /* scroll up */
+                       if (offset)
+                               offset--;
+                       goto again;
+
+                       case '*': /* scroll right */
+                       hoffset += 2;
+                       goto again;
+                       
+                       case '/': /* scroll left */
+                       if (hoffset)
+                               hoffset -= 2;
+                       goto again;
+
+                       case 10: /* entermode */
+                       enter = 1;
+                       goto again;
+
+                       default:
+                       usleep(250000);
+                       goto again;
+               }
        }
 
        /* check for logfh */
@@ -1052,6 +1200,21 @@ char *admin_cmd(int sock, int mode, char *extension, char *number)
                msg.message = ADMIN_REQUEST_CMD_RELEASE;
                SCPY(msg.u.x.message, number);
                break;
+               case MODE_UNBLOCK:
+               msg.message = ADMIN_REQUEST_CMD_BLOCK;
+               msg.u.x.portnum = atoi(number);
+               msg.u.x.block = 0;
+               break;
+               case MODE_BLOCK:
+               msg.message = ADMIN_REQUEST_CMD_BLOCK;
+               msg.u.x.portnum = atoi(number);
+               msg.u.x.block = 1;
+               break;
+               case MODE_UNLOAD:
+               msg.message = ADMIN_REQUEST_CMD_BLOCK;
+               msg.u.x.portnum = atoi(number);
+               msg.u.x.block = 2;
+               break;
        }
 
        if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
@@ -1078,6 +1241,12 @@ char *admin_cmd(int sock, int mode, char *extension, char *number)
                if (msg.message != ADMIN_RESPONSE_CMD_RELEASE)
                        return("Response not valid.");
                break;
+               case MODE_UNBLOCK:
+               case MODE_BLOCK:
+               case MODE_UNLOAD:
+               if (msg.message != ADMIN_RESPONSE_CMD_BLOCK)
+                       return("Response not valid.");
+               break;
        }
 
        /* process response */
@@ -1210,7 +1379,7 @@ char *admin_trace(int sock, int argc, char *argv[])
        int i;
 
        /* show help */
-       if (!strcasecmp(argv[2], "help"))
+       if (argc > 2) if (!strcasecmp(argv[2], "help"))
        {
                printf("Trace Help\n----------\n");
                printf("%s trace [brief|short] [<filter>=<value> [...]]\n\n", argv[0]);
@@ -1243,7 +1412,7 @@ char *admin_trace(int sock, int argc, char *argv[])
                else if (!strcasecmp(argv[i], "short"))
                        msg.u.trace_req.detail = 2;
                else if (!strncasecmp(argv[i], "category=", 9))
-                       SCPY(msg.u.trace_req.category, argv[i]+9);
+                       msg.u.trace_req.category = atoi(argv[i]+9);
                else if (!strncasecmp(argv[i], "port=", 5))
                        msg.u.trace_req.port = atoi(argv[i]+5);
                else if (!strncasecmp(argv[i], "interface=", 10))
@@ -1293,10 +1462,13 @@ int main(int argc, char *argv[])
                printf("\n");
                printf("Usage: %s state | interface | route | dial ...\n", argv[0]);
                printf("state - View current states using graphical console output.\n");
-               printf("interface - Tell PBX to reload \"interface.conf\".\n");
-               printf("route - Tell PBX to reload \"route.conf\".\n");
-               printf("dial <extension> <number> - Tell PBX the next number to dial for extension.\n");
-               printf("release <number> - Tell PBX to release endpoint with given number.\n");
+               printf("interface - Tell LCR to reload \"interface.conf\".\n");
+               printf("route - Tell LCR to reload \"route.conf\".\n");
+               printf("dial <extension> <number> - Tell LCR the next number to dial for extension.\n");
+               printf("release <number> - Tell LCR to release endpoint with given number.\n");
+               printf("block <port> - Block given port.\n");
+               printf("unblock <port> - Unblock given port.\n");
+               printf("unload <port> - Unload port. To load port use 'block' or 'unblock'.\n");
                printf("testcall <interface> <callerid> <number> [present|restrict [<capability>]] - Testcall\n");
                printf(" -> capability = <bc> <mode> <codec> <hlc> <exthlc> (Values must be numbers, -1 to omit.)\n");
                printf("trace [brief|short] [<filter> [...]] - Shows call trace. Use filter to reduce output.\n");
@@ -1330,6 +1502,24 @@ int main(int argc, char *argv[])
                        goto usage;
                mode = MODE_RELEASE;
        } else
+       if (!(strcasecmp(argv[1],"unblock")))
+       {
+               if (argc <= 2)
+                       goto usage;
+               mode = MODE_UNBLOCK;
+       } else
+       if (!(strcasecmp(argv[1],"block")))
+       {
+               if (argc <= 2)
+                       goto usage;
+               mode = MODE_BLOCK;
+       } else
+       if (!(strcasecmp(argv[1],"unload")))
+       {
+               if (argc <= 2)
+                       goto usage;
+               mode = MODE_UNLOAD;
+       } else
        if (!(strcasecmp(argv[1],"testcall")))
        {
                if (argc <= 4)
@@ -1357,7 +1547,7 @@ int main(int argc, char *argv[])
        if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
        {
                close(sock);
-               fprintf(stderr, "Failed to connect to socket \"%s\".\nIs PBX4Linux running?\n", sock_address.sun_path);
+               fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path);
                exit(EXIT_FAILURE);
        }
 
@@ -1365,7 +1555,7 @@ int main(int argc, char *argv[])
        switch(mode)
        {
                case MODE_STATE:
-               ret = admin_state(sock);
+               ret = admin_state(sock, argv);
                break;
        
                case MODE_INTERFACE:
@@ -1378,6 +1568,9 @@ int main(int argc, char *argv[])
                break;
 
                case MODE_RELEASE:
+               case MODE_UNBLOCK:
+               case MODE_BLOCK:
+               case MODE_UNLOAD:
                ret = admin_cmd(sock, mode, NULL, argv[2]);
                break;