Added 'extern' flag to interface.conf.
[lcr.git] / lcradmin.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** Administration tool                                                       **
9 **                                                                           **
10 \*****************************************************************************/
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <time.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <sys/ioctl.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <sys/time.h>
23 #include <errno.h>
24 #include <curses.h>
25 #include "macro.h"
26 #include "options.h"
27 #include "join.h"
28 #include "joinpbx.h"
29 #include "extension.h"
30 #include "message.h"
31 #include "lcrsocket.h"
32 #include "cause.h"
33
34 #define LTEE {addch(ACS_LTEE);addch(ACS_HLINE);addch(ACS_HLINE);}
35 #define LLCORNER {addch(ACS_LLCORNER);addch(ACS_HLINE);addch(ACS_HLINE);}
36 #define VLINE {addch(ACS_VLINE);addstr("  ");}
37 #define EMPTY {addstr("   ");}
38 //char rotator[] = {'-', '\\', '|', '/'};
39 int     lastlines, lastcols;
40 int     show_interfaces = 2,
41         show_calls = 1,
42         show_log = 1;
43
44 enum {
45         MODE_STATE,
46         MODE_PORTINFO,
47         MODE_INTERFACE,
48         MODE_ROUTE,
49         MODE_DIAL,
50         MODE_RELEASE,
51         MODE_UNBLOCK,
52         MODE_BLOCK,
53         MODE_UNLOAD,
54         MODE_TESTCALL,
55         MODE_TRACE,
56 };
57
58 const char *text_interfaces[] = {
59         "off",
60         "brief",
61         "active channels",
62         "all channels",
63 };
64
65 const char *text_calls[] = {
66         "off",
67         "brief",
68         "structured",
69 };
70
71 char    red = 1,
72         green = 2,
73         yellow = 3,
74         blue = 4,
75         mangenta = 5,
76         cyan = 6,
77         white = 7;
78
79 #define LOGLINES 128
80 char logline[LOGLINES][512];
81 unsigned int logcur = 0;
82 int logfh = -1;
83 char logfile[128];
84
85 /*
86  * curses
87  */
88 void init_curses(void)
89 {
90         /* init curses */
91         initscr(); cbreak(); noecho();
92         start_color();
93         nodelay(stdscr, TRUE);
94         if (COLOR_PAIRS>=8 && COLORS>=8)
95         {
96                 init_pair(1,1,0);
97                 init_pair(2,2,0);
98                 init_pair(3,3,0);
99                 init_pair(4,4,0);
100                 init_pair(5,5,0);
101                 init_pair(6,6,0);
102                 init_pair(7,7,0);
103         }
104         lastlines = LINES;
105         lastcols = COLS;
106 }
107
108 void cleanup_curses(void)
109 {
110         endwin();
111 }
112
113 void color(int color)
114 {
115         if (COLOR_PAIRS>=8 && COLORS>=8)
116                 attrset(COLOR_PAIR(color));
117 }
118
119 /*
120  * permanently show current state using ncurses
121  */
122 int debug_port(struct admin_message *msg, struct admin_message *m, int line, int i, int vline)
123 {
124         char buffer[256];
125
126         color(white);
127         addstr("PORT:");
128         color(yellow);
129         SPRINT(buffer,"%s(%d)", m[i].u.p.name,m[i].u.p.serial);
130         addstr(buffer);
131         color(cyan);
132         addstr(" state=");
133         switch (m[i].u.p.state) {
134                 case ADMIN_STATE_IDLE:
135                 color(red);
136                 addstr("'idle'");
137                 break;
138                 case ADMIN_STATE_IN_SETUP:
139                 color(red);
140                 addstr("'in << setup'");
141                 break;
142                 case ADMIN_STATE_OUT_SETUP:
143                 color(red);
144                 addstr("'out >> setup'");
145                 break;
146                 case ADMIN_STATE_IN_OVERLAP:
147                 color(yellow);
148                 addstr("'in << overlap'");
149                 break;
150                 case ADMIN_STATE_OUT_OVERLAP:
151                 color(yellow);
152                 addstr("'out >> overlap'");
153                 break;
154                 case ADMIN_STATE_IN_PROCEEDING:
155                 color(mangenta);
156                 addstr("'in << proc'");
157                 break;
158                 case ADMIN_STATE_OUT_PROCEEDING:
159                 color(mangenta);
160                 addstr("'out >> proc'");
161                 break;
162                 case ADMIN_STATE_IN_ALERTING:
163                 color(cyan);
164                 addstr("'in << alert'");
165                 break;
166                 case ADMIN_STATE_OUT_ALERTING:
167                 color(cyan);
168                 addstr("'out >> alert'");
169                 break;
170                 case ADMIN_STATE_CONNECT:
171                 color(white);
172                 addstr("'connect'");
173                 break;
174                 case ADMIN_STATE_IN_DISCONNECT:
175                 color(blue);
176                 addstr("'in  << disc'");
177                 break;
178                 case ADMIN_STATE_OUT_DISCONNECT:
179                 color(blue);
180                 addstr("'out >> disc'");
181                 break;
182                 default:
183                 color(blue);
184                 addstr("'--NONE--'");
185         }
186
187         if (m[i].u.p.isdn) {    
188                 color(cyan);
189                 addstr(" bchannel=");
190                 color(white);
191                 SPRINT(buffer,"%d", m[i].u.p.isdn_chan);
192                 addstr(buffer);
193                 if (m[i].u.p.isdn_ces >= 0) {
194                         color(cyan);
195                         addstr(" ces=");
196                         color(yellow);
197                         SPRINT(buffer, "%d", m[i].u.p.isdn_ces);
198                         addstr(buffer);
199                 }
200                 if (m[i].u.p.isdn_hold) {
201                         color(red);
202                         addstr(" hold");
203                 }
204         }
205
206         return(line);
207 }
208 int debug_epoint(struct admin_message *msg, struct admin_message *m, int line, int i, int vline)
209 {
210         unsigned int epoint = m[i].u.e.serial;
211         char buffer[256];
212         unsigned char c;
213         int j, jj;
214         int ltee;
215
216         color(white);
217         SPRINT(buffer,"EPOINT(%d)", epoint);
218         addstr(buffer);
219         color(cyan);
220         addstr(" state=");
221         switch (m[i].u.e.state) {
222                 case ADMIN_STATE_IDLE:
223                 color(red);
224                 addstr("'idle'");
225                 break;
226                 case ADMIN_STATE_IN_SETUP:
227                 color(red);
228                 addstr("'in << setup'");
229                 break;
230                 case ADMIN_STATE_OUT_SETUP:
231                 color(red);
232                 addstr("'out >> setup'");
233                 break;
234                 case ADMIN_STATE_IN_OVERLAP:
235                 color(yellow);
236                 addstr("'in << overlap'");
237                 break;
238                 case ADMIN_STATE_OUT_OVERLAP:
239                 color(yellow);
240                 addstr("'out >> overlap'");
241                 break;
242                 case ADMIN_STATE_IN_PROCEEDING:
243                 color(mangenta);
244                 addstr("'in << proc'");
245                 break;
246                 case ADMIN_STATE_OUT_PROCEEDING:
247                 color(mangenta);
248                 addstr("'out >> proc'");
249                 break;
250                 case ADMIN_STATE_IN_ALERTING:
251                 color(cyan);
252                 addstr("'in << alert'");
253                 break;
254                 case ADMIN_STATE_OUT_ALERTING:
255                 color(cyan);
256                 addstr("'out >> alert'");
257                 break;
258                 case ADMIN_STATE_CONNECT:
259                 color(white);
260                 addstr("'connect'");
261                 break;
262                 case ADMIN_STATE_IN_DISCONNECT:
263                 color(blue);
264                 addstr("'in  << disc'");
265                 break;
266                 case ADMIN_STATE_OUT_DISCONNECT:
267                 color(blue);
268                 addstr("'out >> disc'");
269                 break;
270                 default:
271                 color(blue);
272                 addstr("'--NONE--'");
273         }
274         if (m[i].u.e.terminal[0]) {
275                 color(cyan);
276                 addstr(" terminal=");
277                 color(green);
278                 addstr(m[i].u.e.terminal);
279         }
280         color(white);
281         SPRINT(buffer, " %s", m[i].u.e.callerid);
282         addstr(buffer);
283         color(cyan);
284         addstr("->");
285         color(white);
286         addstr(m[i].u.e.dialing);
287         if (m[i].u.e.action[0]) {
288                 color(cyan);
289                 addstr(" action=");
290                 color(yellow);
291                 addstr(m[i].u.e.action);
292         }
293         if (m[i].u.e.park) {
294                 color(cyan);
295                 addstr(" park="); /* 9 digits */
296                 color(green);
297                 UCPY(buffer, "\""); /* 9 digits */
298                 j = 0;
299                 jj = m[i].u.e.park_len;
300                 while(j < jj) {
301                         c = m[i].u.e.park_callid[j];
302                         if (c >= 32 && c < 127 && c != '[') {
303                                 SCCAT(buffer, c);
304                         } else
305                                 UPRINT(buffer+strlen(buffer), "[%02x]", c);
306                         j++;
307                 }
308                 SCAT(buffer, "\"");
309                 addstr(buffer);
310         } else {
311                 color(red);
312                 switch(m[i].u.e.rx_state) {
313                         case NOTIFY_STATE_SUSPEND:
314                         addstr(" in=suspend");
315                         break;
316                         case NOTIFY_STATE_HOLD:
317                         addstr(" in=hold");
318                         break;
319                         case NOTIFY_STATE_CONFERENCE:
320                         addstr(" in=conference");
321                         break;
322                 }
323                 switch(m[i].u.e.tx_state) {
324                         case NOTIFY_STATE_SUSPEND:
325                         addstr(" out=suspend");
326                         break;
327                         case NOTIFY_STATE_HOLD:
328                         addstr(" out=hold");
329                         break;
330                         case NOTIFY_STATE_CONFERENCE:
331                         addstr(" out=conference");
332                         break;
333                 }
334         }
335         if (m[i].u.e.crypt) {
336                 color(cyan);
337                 addstr(" crypt=");
338                 if (m[i].u.e.crypt) { /* crypt on */
339                         color(green);
340                         addstr("active");
341                 } else {
342                         color(yellow);
343                         addstr("pending");
344                 }
345         }
346         /* loop all related ports */
347         ltee = 0;
348         j = msg->u.s.interfaces+msg->u.s.remotes+msg->u.s.joins+msg->u.s.epoints;
349         jj = j + msg->u.s.ports;
350         while(j < jj) {
351                 if (m[j].u.p.epoint == epoint) {
352                         color(cyan);
353                         move(++line>1?line:1, 1);
354                         if (vline)
355                                 VLINE
356                         else
357                                 EMPTY
358                         move(line>1?line:1, 5);
359                         LTEE
360                         ltee = line;
361                         move(line>1?line:1, 8);
362                         if (line+2 >= LINES) break;
363                         line = debug_port(msg, m, line, j, vline);
364                         if (line+2 >= LINES) break;
365                 }
366                 j++;
367         }
368         if (ltee) {
369                 color(cyan);
370                 move(ltee>1?line:1, 5);
371                 LLCORNER
372         }
373
374         return(line);
375 }
376 int debug_join(struct admin_message *msg, struct admin_message *m, int line, int i)
377 {
378         unsigned int    join = m[i].u.j.serial;
379         char            buffer[256];
380         int             j, jj;
381
382         color(white);
383         SPRINT(buffer,"JOIN(%d)", join);
384         addstr(buffer);
385         if (m[i].u.j.partyline) {
386                 color(cyan);
387                 addstr(" partyline=");
388                 color(white);
389                 SPRINT(buffer, "%d\n", m[i].u.j.partyline);
390                 addstr(buffer);
391         }
392         if (m[i].u.j.remote[0]) {
393                 color(cyan);
394                 addstr(" remote=");
395                 color(white);
396                 SPRINT(buffer, "%s\n", m[i].u.j.remote);
397                 addstr(buffer);
398         }
399         /* find number of epoints */
400         j = msg->u.s.interfaces+msg->u.s.remotes+msg->u.s.joins;
401         jj = j + msg->u.s.epoints;
402         i = 0;
403         while(j < jj) {
404                 if (m[j].u.e.join == join)
405                         i++;
406                 j++;
407         }
408         /* loop all related endpoints */
409         j = msg->u.s.interfaces+msg->u.s.remotes+msg->u.s.joins;
410         jj = j + msg->u.s.epoints;
411         while(j < jj) {
412                 if (m[j].u.e.join == join) {
413                         i--;
414                         move(++line>1?line:1, 1);
415                         color(cyan);
416                         if (i)
417                                 LTEE
418                         else
419                                 LLCORNER
420                         move(line>1?line:1, 4);
421                         if (line+2 >= LINES) break;
422                         line = debug_epoint(msg, m, line, j, i?1:0);
423                         if (line+2 >= LINES) break;
424                 }
425                 j++;
426         }
427
428         return(line);
429 }
430
431 const char *admin_state(int sock, char *argv[])
432 {
433         struct admin_message    msg,
434                                 *m;
435         char                    buffer[512],
436                                 *p;
437         int                     line, offset = 0, hoffset = 0;
438         int                     i, ii, j, jj, k;
439         unsigned int            l, ll;
440         int                     num;
441         int                     len;
442         int                     off;
443         int                     ltee;
444         int                     anything;
445         int                     enter = 0;
446         char                    enter_string[128] = "", ch;
447         fd_set                  select_rfds;
448         struct timeval          select_tv;
449
450         /* flush logfile name */
451         logfile[0] = '\0';
452
453         /* init curses */
454         init_curses();
455
456         again:
457         /* send reload command */
458         memset(&msg, 0, sizeof(msg));
459         msg.message = ADMIN_REQUEST_STATE;
460 //      printf("sizeof=%d\n",sizeof(msg));fflush(stdout);
461         if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) {
462                 cleanup_curses();
463                 return("Broken pipe while sending command.");
464         }
465
466         /* receive response */
467         if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) {
468                 cleanup_curses();
469                 return("Broken pipe while receiving response.");
470         }
471
472         if (msg.message != ADMIN_RESPONSE_STATE) {
473                 cleanup_curses();
474                 return("Response not valid. Expecting state response.");
475         }
476         num = msg.u.s.interfaces + msg.u.s.remotes + msg.u.s.joins + msg.u.s.epoints + msg.u.s.ports;
477         m = (struct admin_message *)MALLOC(num*sizeof(struct admin_message));
478         off=0;
479         if (num) {
480                 readagain:
481                 if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off) {
482                         if (len <= 0) {
483                                 FREE(m, 0);
484         //                      fprintf(stderr, "got=%d expected=%d\n", i, num*sizeof(struct admin_message));
485                                 cleanup_curses();
486                                 return("Broken pipe while receiving state infos.");
487                         }
488                         if (len < num*(int)sizeof(struct admin_message)) {
489                                 off+=len;
490                                 goto readagain;
491                         }
492                 }
493         }
494         j = 0;
495         i = 0;
496 //      fprintf("getting =%d interfaces\n", msg.u.s.interfaces);
497         while(i < msg.u.s.interfaces) {
498 //              fprintf(stderr, "j=%d message=%d\n", j, m[j].message);
499                 if (m[j].message != ADMIN_RESPONSE_S_INTERFACE) {
500                         FREE(m, 0);
501                         cleanup_curses();
502                         return("Response not valid. Expecting interface information.");
503                 }
504                 i++;
505                 j++;
506         }
507         i = 0;
508         while(i < msg.u.s.remotes) {
509                 if (m[j].message != ADMIN_RESPONSE_S_REMOTE) {
510                         FREE(m, 0);
511                         cleanup_curses();
512                         return("Response not valid. Expecting remote application information.");
513                 }
514                 i++;
515                 j++;
516         }
517         i = 0;
518         while(i < msg.u.s.joins) {
519                 if (m[j].message != ADMIN_RESPONSE_S_JOIN) {
520                         FREE(m, 0);
521                         cleanup_curses();
522                         return("Response not valid. Expecting join information.");
523                 }
524                 i++;
525                 j++;
526         }
527         i = 0;
528         while(i < msg.u.s.epoints) {
529                 if (m[j].message != ADMIN_RESPONSE_S_EPOINT) {
530                         FREE(m, 0);
531                         cleanup_curses();
532                         return("Response not valid. Expecting endpoint information.");
533                 }
534                 i++;
535                 j++;
536         }
537         i = 0;
538         while(i < msg.u.s.ports) {
539                 if (m[j].message != ADMIN_RESPONSE_S_PORT) {
540                         FREE(m, 0);
541                         cleanup_curses();
542                         return("Response not valid. Expecting port information.");
543                 }
544                 i++;
545                 j++;
546         }
547         // now j is the number of message blocks
548
549         /* display start */
550         erase();
551
552         line = 1-offset; 
553
554         /* change log */
555         if (!!strcmp(logfile, msg.u.s.logfile)) {
556                 SCPY(logfile, msg.u.s.logfile);
557                 if (logfh >= 0)
558                         close(logfh);
559                 i = 0;
560                 ii = LOGLINES;
561                 while(i < ii) {
562                         logline[i][0] = '~';
563                         logline[i][1] = '\0';
564                         i++;
565                 }
566                 logcur = 0;
567                 logfh = open(logfile, O_RDONLY|O_NONBLOCK);
568                 if (logfh >= 0) {
569                         /* seek at the end -8000 chars */
570                         lseek(logfh, -8000, SEEK_END);
571                         /* if not at the beginning, read until endofline */
572                         logline[logcur % LOGLINES][0] = '\0';
573                         l = read(logfh, logline[logcur % LOGLINES], sizeof(logline[logcur % LOGLINES])-1);
574                         if (l > 0) {
575                                 /* read first line and skip junk */
576                                 logline[logcur % LOGLINES][l] = '\0';
577                                 if ((p = strchr(logline[logcur % LOGLINES],'\n'))) {
578                                         logcur++;
579                                         SCPY(logline[logcur % LOGLINES], p+1);
580                                         SCPY(logline[(logcur-1) % LOGLINES], "...");
581                                 }
582                                 goto finish_line;
583                         }
584                 }
585         }
586
587         /* read log */
588         if (logfh >= 0) {
589                 while(42) {
590                         ll = strlen(logline[logcur % LOGLINES]);
591                         l = read(logfh, logline[logcur % LOGLINES]+ll, sizeof(logline[logcur % LOGLINES])-ll-1);
592                         if (l<=0)
593                                 break;
594                         logline[logcur % LOGLINES][ll+l] = '\0';
595                         finish_line:
596                         /* put data to lines */
597                         while ((p = strchr(logline[logcur % LOGLINES],'\n'))) {
598                                 *p = '\0';
599                                 logcur++;
600                                 SCPY(logline[logcur % LOGLINES], p+1);
601                         }
602                         /* if line is full without return, go next line */
603                         if (strlen(logline[logcur % LOGLINES]) == sizeof(logline[logcur % LOGLINES])-1) {
604                                 logcur++;
605                                 logline[logcur % LOGLINES][0] = '\0';
606                         }
607                 }
608         }
609
610         /* display interfaces */
611         if (show_interfaces > 0) {
612                 anything = 0;
613                 i = 0;
614                 ii = i + msg.u.s.interfaces;
615                 while(i < ii) {
616                         /* show interface summary */
617                         move(++line>1?line:1, 0);
618                         color(white);
619                         if (m[i].u.i.block >= 2) {
620                                 if (m[i].u.i.portnum < 0)
621                                         SPRINT(buffer, "%s (port ?: %s)%s", m[i].u.i.interface_name, m[i].u.i.portname, (m[i].u.i.extension)?" exten":"");
622                                 else
623                                         SPRINT(buffer, "%s (port %d: %s)%s", m[i].u.i.interface_name, m[i].u.i.portnum, m[i].u.i.portname, (m[i].u.i.extension)?" extension":"");
624                                 addstr(buffer);
625                                 color(red);
626                                 addstr("  not loaded");
627                         } else {
628                                 SPRINT(buffer, "%s", m[i].u.i.interface_name);
629                                 addstr(buffer);
630                                 color(yellow);
631                                 SPRINT(buffer, "(port %d: %s)", m[i].u.i.portnum, m[i].u.i.portname);
632                                 addstr(buffer);
633                                 color(cyan);
634                                 SPRINT(buffer, " %s %s%s%s%s", (m[i].u.i.ntmode)?"NT":"TE", (m[i].u.i.ptp)?"ptp":"ptmp", (m[i].u.i.l1hold)?" l1hold":"", (m[i].u.i.l2hold)?" l2hold":"", (m[i].u.i.extension)?" extension":"");
635                                 addstr(buffer);
636                                 if (m[i].u.i.use)
637                                         color(green);
638                                 else
639                                         color(blue);
640                                 SPRINT(buffer, " use:%d", m[i].u.i.use);
641                                 addstr(buffer);
642                                 if (m[i].u.i.ptp || !m[i].u.i.ntmode) {
643                                         color((m[i].u.i.l2link > 0)?green:red);
644                                         if (m[i].u.i.l2link < 0)
645                                                 addstr("  L2 unkn");
646                                         else
647                                                 addstr((m[i].u.i.l2link)?"  L2 UP":"  L2 down");
648                                 } else {
649                                         k = 0;
650                                         color(green);
651                                         j = 0;
652                                         while(j < 128) {
653                                                 if (m[i].u.i.l2mask[j>>3] & (1 << (j&7))) {
654                                                         SPRINT(buffer, "%s%d", k?",":"  TEI(", j);
655                                                         addstr(buffer);
656                                                         k = 1;
657                                                 }
658                                                 j++;
659                                         }
660                                         if (k)
661                                                 addstr(")");
662                                 }
663                                 color((m[i].u.i.l1link > 0)?green:blue);
664                                 if (m[i].u.i.l1link < 0)
665                                         addstr("  L1 unkn");
666                                 else
667                                         addstr((m[i].u.i.l1link)?"  L1 UP":"  L1 down");
668                                 if (m[i].u.i.los) {
669                                         color(red);
670                                         addstr(" LOS");
671                                 }
672                                 if (m[i].u.i.ais) {
673                                         color(red);
674                                         addstr(" AIS");
675                                 }
676                                 if (m[i].u.i.rdi) {
677                                         color(red);
678                                         addstr(" RDI");
679                                 }
680                                 if (m[i].u.i.slip_tx || m[i].u.i.slip_rx) {
681                                         color(red);
682                                         SPRINT(buffer, " SLIP(tx:%d rx:%d)", m[i].u.i.slip_tx, m[i].u.i.slip_rx);
683                                         addstr(buffer);
684                                 }
685                                 if (m[i].u.i.block) {
686                                         color(red);
687                                         addstr("  blocked");
688                                 }
689                                 if (line+2 >= LINES) goto end;
690                                 /* show channels */
691                                 if (show_interfaces > 1) {
692                                         ltee = 0;
693                                         j = k =0;
694                                         jj = m[i].u.i.channels;
695                                         while(j < jj) {
696                                                 /* show all channels */
697                                                 if (show_interfaces>2 || m[i].u.i.busy[j]>0) {
698                                                         color(cyan);
699                                                         /* show left side / right side */
700                                                         if ((k & 1) && (COLS > 70)) {
701                                                                 move(line>1?line:1,4+((COLS-4)/2));
702                                                         } else {
703                                                                 move(++line>1?line:1, 1);
704                                                                 LTEE
705                                                                 ltee = 1;
706                                                         }
707                                                         k++;
708                                                         color(white);
709                                                         if (m[i].u.i.pri)
710                                                                 SPRINT(buffer,"S%2d: ", j+1+(j>=15));
711                                                         else
712                                                                 SPRINT(buffer,"B%2d: ", j+1);
713                                                         if (m[i].u.i.mode[j] == B_MODE_HDLC)
714                                                                 SCAT(buffer,"HDLC ");
715                                                         addstr(buffer);
716                                                         switch(m[i].u.i.busy[j]) {
717                                                                 case B_STATE_IDLE:
718                                                                 if ((!m[i].u.i.l2link && m[i].u.i.ptp) || m[i].u.i.block) {
719                                                                         color(red);
720                                                                         addstr("blocked ");
721                                                                 } else {
722                                                                         color(blue);
723                                                                         addstr("idle    ");
724                                                                 }
725                                                                 break;
726                                                                 case B_STATE_ACTIVATING:
727                                                                 color(yellow);
728                                                                 addstr("act'ing ");
729                                                                 break;
730                                                                 case B_STATE_ACTIVE:
731                                                                 color(green);
732                                                                 addstr("busy    ");
733                                                                 break;
734                                                                 case B_STATE_DEACTIVATING:
735                                                                 color(yellow);
736                                                                 addstr("dact'ing");
737                                                                 break;
738                                                                 case B_STATE_EXPORTING:
739                                                                 color(yellow);
740                                                                 addstr("exp'ing ");
741                                                                 break;
742                                                                 case B_STATE_REMOTE:
743                                                                 color(green);
744                                                                 addstr("remote  ");
745                                                                 break;
746                                                                 case B_STATE_IMPORTING:
747                                                                 color(yellow);
748                                                                 addstr("imp'ing ");
749                                                                 break;
750                                                         }
751                                                         if (m[i].u.i.port[j]) {
752                                                                 /* search for port */
753                                                                 l = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins+msg.u.s.epoints;
754                                                                 ll = l+msg.u.s.ports;
755                                                                 while(l < ll) {
756                                                                         if (m[l].u.p.serial == m[i].u.i.port[j]) {
757                                                                                 SPRINT(buffer, " %s(%ld)", m[l].u.p.name, m[l].u.p.serial);
758                                                                                 addstr(buffer);
759                                                                         }
760                                                                         l++;
761                                                                 }
762                                                         }
763                                                         if (line+2 >= LINES) {
764                                                                 if (ltee) {
765                                                                         color(cyan);
766                                                                         move(line>1?line:1, 1);
767                                                                         LLCORNER
768                                                                 }
769                                                                 goto end;
770                                                         }
771                                                 }
772                                                 j++;
773                                         }
774                                         if (ltee) {
775                                                 color(cyan);
776                                                 move(line>1?line:1, 1);
777                                                 LLCORNER
778                                         }
779                                         if (line+2 >= LINES) goto end;
780                                         /* show summary if no channels were shown */
781                                         if (show_interfaces<2 && ltee==0) {
782                                                 color(cyan);
783                                                 move(++line>1?line:1, 1);
784                                                 LLCORNER
785                                                         
786                                                 if (m[i].u.i.l2link && m[i].u.i.block==0) {
787                                                         color(green);
788                                                         SPRINT(buffer,"all %d channels free", m[i].u.i.channels);
789                                                 } else {
790                                                         color(red);
791                                                         SPRINT(buffer,"all %d channels blocked", m[i].u.i.channels);
792                                                 }
793                                                 addstr(buffer);
794                                         }
795                                         if (line+2 >= LINES) goto end;
796                                 }
797                         }
798                         i++;
799                         anything = 1;
800                 }
801                 i = msg.u.s.interfaces;
802                 ii = i + msg.u.s.remotes;
803                 while(i < ii) {
804                         /* show remote summary */
805                         move(++line>1?line:1, 0);
806                         color(white);
807                         SPRINT(buffer, "Remote: %s", m[i].u.r.name);
808                         addstr(buffer);
809                         i++;
810                 }
811                 if (anything)
812                         line++;
813                 if (line+2 >= LINES) goto end;
814         }               
815         /* display calls (brief) */
816         if (show_calls == 1) {
817                 anything = 0;
818                 i = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins;
819                 ii = i+msg.u.s.epoints;
820                 while(i < ii) {
821                         /* for each endpoint... */
822                         if (!m[i].u.e.join) {
823                                 move(++line>1?line:1, 0);
824                                 color(white);
825                                 SPRINT(buffer, "(%d): ", m[i].u.e.serial);
826                                 addstr(buffer);
827                                 color(cyan);
828                                 if (m[i].u.e.terminal[0]) {
829                                         addstr("intern=");
830                                         color(green);
831                                         addstr(m[i].u.e.terminal);
832                                 } else
833                                         addstr("extern");
834                                 color(white);
835                                 SPRINT(buffer, " %s", m[i].u.e.callerid);
836                                 addstr(buffer);
837                                 color(cyan);
838                                 addstr("->");
839                                 color(white);
840                                 SPRINT(buffer, "%s", m[i].u.e.dialing);
841                                 addstr(buffer);
842                                 if (m[i].u.e.action[0]) {
843                                         color(cyan);
844                                         addstr(" action=");
845                                         color(yellow);
846                                         addstr(m[i].u.e.action);
847                                 }
848                                 if (line+2 >= LINES) goto end;
849                         }
850                         i++;
851                         anything = 1;
852                 }
853                 j = msg.u.s.interfaces+msg.u.s.remotes;
854                 jj = j+msg.u.s.joins;
855                 while(j < jj) {
856                         /* for each call... */
857                         move(++line>1?line:1, 0);
858                         color(white);
859                         SPRINT(buffer, "(%d):", m[j].u.j.serial);
860                         addstr(buffer);
861                         i = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins;
862                         ii = i+msg.u.s.epoints;
863                         while(i < ii) {
864                                 /* for each endpoint... */
865                                 if (m[i].u.e.join == m[j].u.j.serial) {
866                                         color(white);
867                                         SPRINT(buffer, " (%d)", m[i].u.e.serial);
868                                         addstr(buffer);
869                                         color(cyan);
870                                         if (m[i].u.e.terminal[0]) {
871                                                 addstr("int=");
872                                                 color(green);
873                                                 addstr(m[i].u.e.terminal);
874                                         } else
875                                                 addstr("ext");
876                                         color(white);
877                                         SPRINT(buffer, "-%s", m[i].u.e.callerid);
878                                         addstr(buffer);
879                                         color(cyan);
880                                         addstr(">");
881                                         color(white);
882                                         SPRINT(buffer, "%s", m[i].u.e.dialing);
883                                         addstr(buffer);
884                                 }
885                                 i++;
886                                 anything = 1;
887                         }
888                         if (line+2 >= LINES) goto end;
889                         j++;
890                 }
891                 if (anything)
892                         line++;
893                 if (line+2 >= LINES) goto end;
894         }
895         /* display calls (structurd) */
896         if (show_calls == 2) {
897                 /* show all ports with no epoint */
898                 anything = 0;
899                 i = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins+msg.u.s.epoints;
900                 ii = i+msg.u.s.ports;
901                 while(i < ii) {
902                         if (!m[i].u.p.epoint) {
903                                 move(++line>1?line:1, 8);
904                                 if (line+2 >= LINES) goto end;
905                                 line = debug_port(&msg, m, line, i, 0);
906                                 if (line+2 >= LINES) goto end;
907                                 anything = 1;
908                         }
909                         i++;
910                 }
911                 if (anything)
912                         line++;
913                 if (line+2 >= LINES) goto end;
914
915                 /* show all epoints with no call */
916                 anything = 0;
917                 i = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins;
918                 ii = i+msg.u.s.epoints;
919                 while(i < ii) {
920                         if (!m[i].u.e.join) {
921                                 move(++line>1?line:1, 4);
922                                 if (line+2 >= LINES) goto end;
923                                 line = debug_epoint(&msg, m, line, i, 0);
924                                 if (line+2 >= LINES) goto end;
925                                 anything = 1;
926                         }
927                         i++;
928                 }
929                 if (anything)
930                         line++;
931                 if (line+2 >= LINES) goto end;
932
933                 /* show all joins */
934                 anything = 0;
935                 i = msg.u.s.interfaces+msg.u.s.remotes;
936                 ii = i+msg.u.s.joins;
937                 while(i < ii) {
938                         move(++line>1?line:1, 0);
939                         if (line+2 >= LINES) goto end;
940                         line = debug_join(&msg, m, line, i);
941                         if (line+2 >= LINES) goto end;
942                         i++;
943                         anything = 1;
944                 }
945                 if (anything)
946                         line++;
947                 if (line+2 >= LINES) goto end;
948
949         }
950
951         /* show log */
952         if (show_log) {
953                 if (line+2 < LINES) {
954                         move(line++>1?line-1:1, 0);
955                         color(blue);
956                         hline(ACS_HLINE, COLS);
957                         color(white);
958                         
959                         l = logcur-(LINES-line-2);
960                         ll = logcur;
961                         if (ll-l >= LOGLINES)
962                                 l = ll-LOGLINES+1;
963                         while(l!=ll) {
964                                 move(line++>1?line-1:1, 0);
965                                 if ((int)strlen(logline[l % LOGLINES]) > hoffset)
966                                         SCPY(buffer, logline[l % LOGLINES] + hoffset);
967                                 else
968                                         buffer[0] = '\0';
969                                 if (COLS < (int)strlen(buffer)) {
970                                         buffer[COLS-1] = '\0';
971                                         addstr(buffer);
972                                         color(mangenta);
973                                         addch('*');
974                                         color(white);
975                                 } else
976                                         addstr(buffer);
977                                 l++;
978                         }
979                 }
980         }
981
982         end:
983         /* free memory */
984         FREE(m, 0);
985         /* display name/time */
986 //      move(0, 0);
987 //      hline(' ', COLS);
988         move(0, 0);
989         color(cyan);
990         msg.u.s.version_string[sizeof(msg.u.s.version_string)-1] = '\0';
991         SPRINT(buffer, "LCR %s", msg.u.s.version_string);
992         addstr(buffer);
993         if (COLS>50) {
994                 move(0, COLS-19);
995                 SPRINT(buffer, "%04d-%02d-%02d %02d:%02d:%02d",
996                         msg.u.s.tm.tm_year+1900, msg.u.s.tm.tm_mon+1, msg.u.s.tm.tm_mday,
997                         msg.u.s.tm.tm_hour, msg.u.s.tm.tm_min, msg.u.s.tm.tm_sec);
998                 addstr(buffer);
999         }
1000         /* displeay head line */
1001         move(1, 0);
1002         color(blue);
1003         hline(ACS_HLINE, COLS);
1004         if (offset) {
1005                 move(1, 1);
1006                 SPRINT(buffer, "Offset +%d", offset);
1007                 color(red);
1008                 addstr(buffer);
1009         }
1010         if (hoffset) {
1011                 move(1, 13);
1012                 SPRINT(buffer, "H-Offset +%d", hoffset);
1013                 color(red);
1014                 addstr(buffer);
1015         }
1016         /* display end */
1017         move(LINES-2, 0);
1018         color(blue);
1019         hline(ACS_HLINE, COLS);
1020         move(LINES-1, 0);
1021         if (enter) {
1022                 color(white);
1023                 SPRINT(buffer, "-> %s", enter_string);
1024         } else {
1025                 color(cyan);
1026                 SPRINT(buffer, "i=interfaces '%s'  c=calls '%s'  l=log  q=quit  +-*/=scroll  enter", text_interfaces[show_interfaces], text_calls[show_calls]);
1027         }
1028         addstr(buffer);
1029         refresh();
1030
1031         /* resize */
1032         if (lastlines!=LINES || lastcols!=COLS) {
1033                 cleanup_curses();
1034                 init_curses();
1035                 goto again;
1036         }
1037
1038         if (enter) {
1039                 /* user input in enter mode */
1040                 ch = getch();
1041                 enter_again:
1042                 if (ch == 10) {
1043                         FILE *fp;
1044
1045                         enter = 0;
1046                         if (!enter_string[0])
1047                                 goto again;
1048
1049                         SPRINT(logline[logcur++ % LOGLINES], "> %s", enter_string);
1050                         if (!!strncmp(enter_string, "interface", 10) &&
1051                             !!strncmp(enter_string, "route", 6) &&
1052                             !!strncmp(enter_string, "release ", 8) &&
1053                             !!strncmp(enter_string, "block ", 6) &&
1054                             !!strncmp(enter_string, "unblock ", 8) &&
1055                             !!strncmp(enter_string, "load ", 5) &&
1056                             !!strncmp(enter_string, "unload ", 7)) {
1057                                 SPRINT(logline[logcur++ % LOGLINES], "usage:");
1058                                 SPRINT(logline[logcur++ % LOGLINES], "interface (reload interface.conf)");
1059                                 SPRINT(logline[logcur++ % LOGLINES], "route (reload routing.conf)");
1060                                 SPRINT(logline[logcur++ % LOGLINES], "release <EP> (release endpoint with given ID)");
1061                                 SPRINT(logline[logcur++ % LOGLINES], "block <port> (block port for further calls)");
1062                                 SPRINT(logline[logcur++ % LOGLINES], "unblock/load <port> (unblock port for further calls, load if not loaded)");
1063                                 SPRINT(logline[logcur++ % LOGLINES], "unload <port> (unload mISDN stack, release call calls)");
1064                         } else {
1065                                 /* applend output to log window */
1066                                 SPRINT(buffer, "%s %s", argv[0], enter_string);
1067                                 fp = popen(buffer, "r");
1068                                 if (fp) {
1069                                         while(fgets(logline[logcur % LOGLINES], sizeof(logline[0]), fp))
1070                                                 logline[logcur++ % LOGLINES][sizeof(logline[0])-1] = '\0';
1071                                         pclose(fp);
1072                                 } else {
1073                                         SPRINT(logline[logcur++ % LOGLINES], "failed to execute '%s'", buffer);
1074                                 }
1075                         }
1076                         logline[logcur % LOGLINES][0] = '\0';
1077                         enter_string[0] = '\0';
1078                         goto again;
1079                 }
1080                 if (ch>=32 && ch<=126) {
1081                         SCCAT(enter_string, ch);
1082                         ch = getch();
1083                         if (ch > 0)
1084                                 goto enter_again;
1085                         goto again;
1086                 } else
1087                 if (ch==8 || ch==127) {
1088                         if (enter_string[0])
1089                                 enter_string[strlen(enter_string)-1] = '\0';
1090                         ch = getch();
1091                         if (ch > 0)
1092                                 goto enter_again;
1093                         goto again;
1094                 } else
1095                 if (ch != 3) {
1096                         ch = getch();
1097                         if (ch > 0)
1098                                 goto enter_again;
1099                         FD_ZERO(&select_rfds);
1100                         FD_SET(0, &select_rfds);
1101                         select_tv.tv_sec = 0;
1102                         select_tv.tv_usec = 250000;
1103                         select(1, &select_rfds, NULL, NULL, &select_tv);
1104                         goto again;
1105                 }
1106         } else {
1107                 /* user input in normal mode */
1108                 switch(getch()) {
1109                         case 12: /* refresh */
1110                         cleanup_curses();
1111                         init_curses();
1112                         goto again;
1113                         break;
1114
1115                         case 3: /* abort */
1116                         case 'q':
1117                         case 'Q':
1118                         break;
1119
1120                         case 'i': /* toggle interface */
1121                         show_interfaces++;
1122                         if (show_interfaces > 3) show_interfaces = 0;
1123                         goto again;
1124
1125                         case 'c': /* toggle calls */
1126                         show_calls++;
1127                         if (show_calls > 2) show_calls = 0;
1128                         goto again;
1129
1130                         case 'l': /* toggle log */
1131                         show_log++;
1132                         if (show_log > 1) show_log = 0;
1133                         goto again;
1134
1135                         case '+': /* scroll down */
1136                         offset++;
1137                         goto again;
1138                         
1139                         case '-': /* scroll up */
1140                         if (offset)
1141                                 offset--;
1142                         goto again;
1143
1144                         case '*': /* scroll right */
1145                         hoffset += 2;
1146                         goto again;
1147                         
1148                         case '/': /* scroll left */
1149                         if (hoffset)
1150                                 hoffset -= 2;
1151                         goto again;
1152
1153                         case 10: /* entermode */
1154                         enter = 1;
1155                         goto again;
1156
1157                         default:
1158                         FD_ZERO(&select_rfds);
1159                         FD_SET(0, &select_rfds);
1160                         select_tv.tv_sec = 0;
1161                         select_tv.tv_usec = 250000;
1162                         select(1, &select_rfds, NULL, NULL, &select_tv);
1163                         goto again;
1164                 }
1165         }
1166
1167         /* check for logfh */
1168         if (logfh >= 0)
1169                 close(logfh);
1170         logfh = -1;
1171
1172         /* cleanup curses and exit */
1173         cleanup_curses();
1174
1175         return(NULL);
1176 }
1177
1178 const char *admin_portinfo(int sock, int argc, char *argv[])
1179 {
1180         struct admin_message    msg,
1181                                 *m;
1182         int                     i, ii, j;
1183         int                     num;
1184         int                     len;
1185         int                     off;
1186
1187         /* send state request command */
1188         memset(&msg, 0, sizeof(msg));
1189         msg.message = ADMIN_REQUEST_STATE;
1190         if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) {
1191                 cleanup_curses();
1192                 return("Broken pipe while sending command.");
1193         }
1194
1195         /* receive response */
1196         if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) {
1197                 cleanup_curses();
1198                 return("Broken pipe while receiving response.");
1199         }
1200
1201         if (msg.message != ADMIN_RESPONSE_STATE) {
1202                 cleanup_curses();
1203                 return("Response not valid. Expecting state response.");
1204         }
1205         num = msg.u.s.interfaces + msg.u.s.remotes + msg.u.s.joins + msg.u.s.epoints + msg.u.s.ports;
1206         m = (struct admin_message *)MALLOC(num*sizeof(struct admin_message));
1207         off=0;
1208         if (num) {
1209                 readagain:
1210                 if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off) {
1211                         if (len <= 0) {
1212                                 FREE(m, 0);
1213                                 cleanup_curses();
1214                                 return("Broken pipe while receiving state infos.");
1215                         }
1216                         if (len < num*(int)sizeof(struct admin_message)) {
1217                                 off+=len;
1218                                 goto readagain;
1219                         }
1220                 }
1221         }
1222         j = 0;
1223         i = 0;
1224         while(i < msg.u.s.interfaces) {
1225                 if (m[j].message != ADMIN_RESPONSE_S_INTERFACE) {
1226                         FREE(m, 0);
1227                         cleanup_curses();
1228                         return("Response not valid. Expecting interface information.");
1229                 }
1230                 i++;
1231                 j++;
1232         }
1233         i = 0;
1234         while(i < msg.u.s.remotes) {
1235                 if (m[j].message != ADMIN_RESPONSE_S_REMOTE) {
1236                         FREE(m, 0);
1237                         cleanup_curses();
1238                         return("Response not valid. Expecting remote application information.");
1239                 }
1240                 i++;
1241                 j++;
1242         }
1243         i = 0;
1244         while(i < msg.u.s.joins) {
1245                 if (m[j].message != ADMIN_RESPONSE_S_JOIN) {
1246                         FREE(m, 0);
1247                         cleanup_curses();
1248                         return("Response not valid. Expecting join information.");
1249                 }
1250                 i++;
1251                 j++;
1252         }
1253         i = 0;
1254         while(i < msg.u.s.epoints) {
1255                 if (m[j].message != ADMIN_RESPONSE_S_EPOINT) {
1256                         FREE(m, 0);
1257                         cleanup_curses();
1258                         return("Response not valid. Expecting endpoint information.");
1259                 }
1260                 i++;
1261                 j++;
1262         }
1263         i = 0;
1264         while(i < msg.u.s.ports) {
1265                 if (m[j].message != ADMIN_RESPONSE_S_PORT) {
1266                         FREE(m, 0);
1267                         cleanup_curses();
1268                         return("Response not valid. Expecting port information.");
1269                 }
1270                 i++;
1271                 j++;
1272         }
1273         // now j is the number of message blocks
1274
1275         /* output interfaces */
1276         i = 0;
1277         ii = i + msg.u.s.interfaces;
1278         while(i < ii) {
1279                 if (argc > 2) {
1280                         if (!!strcmp(argv[2], m[i].u.i.interface_name)) {
1281                                 i++;
1282                                 continue;
1283                         }
1284                 }
1285                 printf("%s:\n", m[i].u.i.interface_name);
1286                 if (m[i].u.i.portnum < 0)
1287                         printf("\t port = unknown\n");
1288                 else
1289                         printf("\t port = %d \"%s\"\n",m[i].u.i.portnum, m[i].u.i.portname);
1290                 printf("\t extension = %s\n", (m[i].u.i.extension)?"yes":"no");
1291                 if (m[i].u.i.block >= 2) {
1292                         printf("\t status = not loaded\n");
1293                 } else {
1294                         if (m[i].u.i.block)
1295                                 printf("\t status = blocked\n");
1296                         else
1297                                 printf("\t status = unblocked\n");
1298                         printf("\t mode = %s %s%s%s\n", (m[i].u.i.ntmode)?"NT-mode":"TE-mode", (m[i].u.i.ptp)?"ptp":"ptmp", (m[i].u.i.l1hold)?" l1hold":"", (m[i].u.i.l2hold)?" l2hold":"");
1299                         if (m[i].u.i.l1link < 0)
1300                                 printf("\t l1 link = unknown\n");
1301                         else
1302                                 printf("\t l1 link = %s\n", (m[i].u.i.l1link)?"up":"down");
1303                         if (m[i].u.i.ptp || !m[i].u.i.ntmode) {
1304                                 if (m[i].u.i.l2link < 0)
1305                                         printf("\t l2 link = unknown\n");
1306                                 else
1307                                         printf("\t l2 link = %s\n", (m[i].u.i.l2link)?"up":"down");
1308                         }
1309                         printf("\t usage = %d\n", m[i].u.i.use);
1310                 }
1311                 i++;
1312         }
1313
1314         /* free memory */
1315         FREE(m, 0);
1316
1317         return(NULL);
1318 }
1319
1320
1321 /*
1322  * Send command and show error message.
1323  */
1324 const char *admin_cmd(int sock, int mode, char *extension, char *number)
1325 {
1326         static struct admin_message msg;
1327
1328         /* send reload command */
1329         memset(&msg, 0, sizeof(msg));
1330         switch(mode) {
1331                 case MODE_INTERFACE:
1332                 msg.message = ADMIN_REQUEST_CMD_INTERFACE;
1333                 break;
1334                 case MODE_ROUTE:
1335                 msg.message = ADMIN_REQUEST_CMD_ROUTE;
1336                 break;
1337                 case MODE_DIAL:
1338                 msg.message = ADMIN_REQUEST_CMD_DIAL;
1339                 SPRINT(msg.u.x.message, "%s:%s", extension?:"", number?:"");
1340                 break;
1341                 case MODE_RELEASE:
1342                 msg.message = ADMIN_REQUEST_CMD_RELEASE;
1343                 SCPY(msg.u.x.message, number);
1344                 break;
1345                 case MODE_UNBLOCK:
1346                 msg.message = ADMIN_REQUEST_CMD_BLOCK;
1347                 msg.u.x.portnum = atoi(number);
1348                 msg.u.x.block = 0;
1349                 break;
1350                 case MODE_BLOCK:
1351                 msg.message = ADMIN_REQUEST_CMD_BLOCK;
1352                 msg.u.x.portnum = atoi(number);
1353                 msg.u.x.block = 1;
1354                 break;
1355                 case MODE_UNLOAD:
1356                 msg.message = ADMIN_REQUEST_CMD_BLOCK;
1357                 msg.u.x.portnum = atoi(number);
1358                 msg.u.x.block = 2;
1359                 break;
1360         }
1361
1362         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1363                 return("Broken pipe while sending command.");
1364
1365         /* receive response */
1366         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
1367                 return("Broken pipe while receiving response.");
1368         switch(mode) {
1369                 case MODE_INTERFACE:
1370                 if (msg.message != ADMIN_RESPONSE_CMD_INTERFACE)
1371                         return("Response not valid.");
1372                 break;
1373                 case MODE_ROUTE:
1374                 if (msg.message != ADMIN_RESPONSE_CMD_ROUTE)
1375                         return("Response not valid.");
1376                 break;
1377                 case MODE_DIAL:
1378                 if (msg.message != ADMIN_RESPONSE_CMD_DIAL)
1379                         return("Response not valid.");
1380                 break;
1381                 case MODE_RELEASE:
1382                 if (msg.message != ADMIN_RESPONSE_CMD_RELEASE)
1383                         return("Response not valid.");
1384                 break;
1385                 case MODE_UNBLOCK:
1386                 case MODE_BLOCK:
1387                 case MODE_UNLOAD:
1388                 if (msg.message != ADMIN_RESPONSE_CMD_BLOCK)
1389                         return("Response not valid.");
1390                 break;
1391         }
1392
1393         /* process response */
1394         if (msg.u.x.error) {
1395                 return(msg.u.x.message);
1396         }
1397         printf("Command successfull.\n");
1398         return(NULL);
1399 }
1400
1401
1402 /*
1403  * makes a testcall
1404  */
1405 #define GET_NOW() { \
1406         gettimeofday(&now_tv, &now_tz); \
1407         now_d = ((double)(now_tv.tv_usec))/1000000 + now_tv.tv_sec; \
1408         }
1409 const char *admin_testcall(int sock, int argc, char *argv[])
1410 {
1411         static struct admin_message msg;
1412         int ar = 2;
1413         int stimeout = 0, ptimeout = 0, atimeout = 0, ctimeout = 0;
1414         int l;
1415         double timer = 0, now_d;
1416         unsigned int on = 1;
1417         struct timeval now_tv;
1418         struct timezone now_tz;
1419
1420         printf("pid=%d\n", getpid()); fflush(stdout);
1421
1422         while (argc > ar) {
1423                 if (!strcmp(argv[ar], "--setup-timeout")) {
1424                         ar++;
1425                         if (argc == ar)
1426                                 return("Missing setup timeout value.\n");
1427                         stimeout = atoi(argv[ar]);
1428                         ar++;
1429                 } else
1430                 if (!strcmp(argv[ar], "--proceeding-timeout")) {
1431                         ar++;
1432                         if (argc == ar)
1433                                 return("Missing proceeding timeout value.\n");
1434                         ptimeout = atoi(argv[ar]);
1435                         ar++;
1436                 } else
1437                 if (!strcmp(argv[ar], "--alerting-timeout")) {
1438                         ar++;
1439                         if (argc == ar)
1440                                 return("Missing alerting timeout value.\n");
1441                         atimeout = atoi(argv[ar]);
1442                         ar++;
1443                 } else
1444                 if (!strcmp(argv[ar], "--connect-timeout")) {
1445                         ar++;
1446                         if (argc == ar)
1447                                 return("Missing connect timeout value.\n");
1448                         ctimeout = atoi(argv[ar]);
1449                         ar++;
1450                 } else {
1451                         break;
1452                 }
1453         }
1454
1455         /* send reload command */
1456         memset(&msg, 0, sizeof(msg));
1457         msg.message = ADMIN_CALL_SETUP;
1458         msg.u.call.present = 1;
1459
1460         if (argc > ar) {
1461                 SCPY(msg.u.call.interface, argv[ar]);
1462         }
1463         ar++;
1464         if (argc > ar) {
1465                 SCPY(msg.u.call.callerid, argv[ar]);
1466         }
1467         ar++;
1468         if (argc > ar) {
1469                 SCPY(msg.u.call.dialing, argv[ar]);
1470         }
1471         ar++;
1472         if (argc > ar) {
1473                 if (argv[ar][0] == 'r')
1474                         msg.u.call.present = 0;
1475         }
1476         ar++;
1477         msg.u.call.bc_capa = 0x00; /*INFO_BC_SPEECH*/
1478         msg.u.call.bc_mode = 0x00; /*INFO_BMODE_CIRCUIT*/
1479         msg.u.call.bc_info1 = 0;
1480         msg.u.call.hlc = 0;
1481         msg.u.call.exthlc = 0;
1482         if (argc > ar)
1483                 msg.u.call.bc_capa = strtol(argv[ar],NULL,0);
1484         else
1485                 msg.u.call.bc_info1 = 3 | 0x80; /* alaw, if no capability is given at all */
1486         ar++;
1487         if (argc > ar) {
1488                 msg.u.call.bc_mode = strtol(argv[ar],NULL,0);
1489                 if (msg.u.call.bc_mode) msg.u.call.bc_mode = 2;
1490         }
1491         ar++;
1492         if (argc > ar) {
1493                 msg.u.call.bc_info1 = strtol(argv[ar],NULL,0);
1494                 if (msg.u.call.bc_info1 < 0)
1495                         msg.u.call.bc_info1 = 0;
1496                 else
1497                         msg.u.call.bc_info1 |= 0x80;
1498         }
1499         ar++;
1500         if (argc > ar) {
1501                 msg.u.call.hlc = strtol(argv[ar],NULL,0);
1502                 if (msg.u.call.hlc < 0)
1503                         msg.u.call.hlc = 0;
1504                 else
1505                         msg.u.call.hlc |= 0x80;
1506         }
1507         ar++;
1508         if (argc > ar) {
1509                 msg.u.call.exthlc = strtol(argv[ar],NULL,0);
1510                 if (msg.u.call.exthlc < 0)
1511                         msg.u.call.exthlc = 0;
1512                 else
1513                         msg.u.call.exthlc |= 0x80;
1514         }
1515         ar++;
1516
1517         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1518                 return("Broken pipe while sending command.");
1519
1520         if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0)
1521                 return("Failed to set socket into non-blocking IO.");
1522
1523         if (stimeout) {
1524                 GET_NOW();
1525                 timer = now_d + (double)stimeout;
1526         }
1527         
1528         /* receive response */
1529 next:
1530         l = read(sock, &msg, sizeof(msg));
1531         if (l < 0) {
1532                 if (errno == EWOULDBLOCK) {
1533                         if (timer) {
1534                                 GET_NOW();
1535                                 if (timer <= now_d) {
1536                                         printf("Timeout\n"); fflush(stdout);
1537                                         return(NULL);
1538                                 }
1539                         }
1540                         usleep(30000);
1541                         goto next;
1542                 }
1543                 return("Broken pipe while receiving response.");
1544         }
1545         if (l != sizeof(msg))
1546                 return("Response has unexpected message size.");
1547         switch(msg.message) {
1548                 case ADMIN_CALL_SETUP_ACK:
1549                 printf("SETUP ACKNOWLEDGE\n"); fflush(stdout);
1550                 goto next;
1551
1552                 case ADMIN_CALL_PROCEEDING:
1553                 printf("PROCEEDING\n"); fflush(stdout);
1554                 if (ptimeout) {
1555                         GET_NOW();
1556                         timer = now_d + (double)ptimeout;
1557                 }
1558                 goto next;
1559
1560                 case ADMIN_CALL_ALERTING:
1561                 printf("ALERTING\n"); fflush(stdout);
1562                 if (atimeout) {
1563                         GET_NOW();
1564                         timer = now_d + (double)atimeout;
1565                 }
1566                 goto next;
1567
1568                 case ADMIN_CALL_CONNECT:
1569                 printf("CONNECT\n number=%s\n", msg.u.call.callerid); fflush(stdout);
1570                 if (ctimeout) {
1571                         GET_NOW();
1572                         timer = now_d + (double)ctimeout;
1573                 }
1574                 goto next;
1575
1576                 case ADMIN_CALL_NOTIFY:
1577                 printf("NOTIFY\n notify=%d\n number=%s\n", msg.u.call.notify, msg.u.call.callerid); fflush(stdout);
1578                 goto next;
1579
1580                 case ADMIN_CALL_DISCONNECT:
1581                 printf("DISCONNECT\n cause=%d %s\n location=%d %s\n", msg.u.call.cause, (msg.u.call.cause>0 && msg.u.call.cause<128)?isdn_cause[msg.u.call.cause].german:"", msg.u.call.location, (msg.u.call.location>=0 && msg.u.call.location<128)?isdn_location[msg.u.call.location].german:""); fflush(stdout);
1582                 break;
1583
1584                 case ADMIN_CALL_RELEASE:
1585                 printf("RELEASE\n cause=%d %s\n location=%d %s\n", msg.u.call.cause, (msg.u.call.cause>0 && msg.u.call.cause<128)?isdn_cause[msg.u.call.cause].german:"", msg.u.call.location, (msg.u.call.location>=0 && msg.u.call.location<128)?isdn_location[msg.u.call.location].german:""); fflush(stdout);
1586                 break;
1587
1588                 default:
1589                 return("Response not valid.");
1590         }
1591
1592         printf("Call released.\n"); fflush(stdout);
1593         return(NULL);
1594 }
1595
1596
1597 /*
1598  * makes a trace
1599  */
1600 const char *admin_trace(int sock, int argc, char *argv[])
1601 {
1602         static struct admin_message msg;
1603         int i;
1604
1605         /* show help */
1606         if (argc > 2) if (!strcasecmp(argv[2], "help")) {
1607                 printf("Trace Help\n----------\n");
1608                 printf("%s trace [brief|short] [<filter>=<value> [...]]\n\n", argv[0]);
1609                 printf("By default a complete trace is shown in detailed format.\n");
1610                 printf("To show a more compact format, use 'brief' or 'short' keyword.\n");
1611                 printf("Use filter values to select specific trace messages.\n");
1612                 printf("All given filter values must match. If no filter is given, anything matches.\n\n");
1613                 printf("Filters:\n");
1614                 printf(" category=<mask bits>\n");
1615                 printf("  0x01 = CH: channel object trace\n");
1616                 printf("  0x02 = EP: endpoint object trace\n");
1617                 printf(" port=<mISDN port>  select only given port for trace\n");
1618                 printf(" interface=<interface name>  select only given interface for trace\n");
1619                 printf(" caller=<caller id>  select only given caller id for trace\n");
1620                 printf(" dialing=<number>  select only given dialed number for trace\n");
1621                 return(NULL);
1622         }
1623
1624         /* init trace request */        
1625         memset(&msg, 0, sizeof(msg));
1626         msg.message = ADMIN_TRACE_REQUEST;
1627         msg.u.trace_req.detail = 3;
1628         msg.u.trace_req.port = -1;
1629
1630         /* parse args */
1631         i = 2;
1632         while(i < argc) {
1633                 if (!strcasecmp(argv[i], "brief"))
1634                         msg.u.trace_req.detail = 1;
1635                 else if (!strcasecmp(argv[i], "short"))
1636                         msg.u.trace_req.detail = 2;
1637                 else if (!strncasecmp(argv[i], "category=", 9))
1638                         msg.u.trace_req.category = atoi(argv[i]+9);
1639                 else if (!strncasecmp(argv[i], "port=", 5))
1640                         msg.u.trace_req.port = atoi(argv[i]+5);
1641                 else if (!strncasecmp(argv[i], "interface=", 10))
1642                         SCPY(msg.u.trace_req.interface, argv[i]+10);
1643                 else if (!strncasecmp(argv[i], "caller=", 7))
1644                         SCPY(msg.u.trace_req.caller, argv[i]+7);
1645                 else if (!strncasecmp(argv[i], "dialing=", 8))
1646                         SCPY(msg.u.trace_req.dialing, argv[i]+8);
1647                 else return("Invalid trace option, try 'trace help'.");
1648
1649                 i++;
1650         }
1651
1652         /* send trace request */
1653         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1654                 return("Broken pipe while sending trace request.");
1655
1656         /* receive response */
1657 next:
1658         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
1659                 return("Broken pipe while receiving response.");
1660
1661         if (msg.message != ADMIN_TRACE_RESPONSE)
1662                 return("Response not valid.");
1663
1664         printf("%s", msg.u.trace_rsp.text);
1665         goto next;
1666 }
1667
1668
1669 /*
1670  * main function
1671  */
1672 int main(int argc, char *argv[])
1673 {
1674         int mode;
1675         int sock, conn;
1676         struct sockaddr_un sock_address;
1677         const char *ret = "invalid mode";
1678
1679
1680         /* show options */
1681         if (argc <= 1) {
1682                 usage:
1683                 printf("\n");
1684                 printf("Usage: %s state | interface | route | dial ...\n", argv[0]);
1685                 printf("state - View current states using graphical console output.\n");
1686                 printf("portinfo - Get info of current ports.\n");
1687                 printf("interface [<portname>] - Tell LCR to reload \"interface.conf\".\n");
1688                 printf("route - Tell LCR to reload \"route.conf\".\n");
1689                 printf("dial <extension> <number> - Tell LCR the next number to dial for extension.\n");
1690                 printf("release <number> - Tell LCR to release endpoint with given number.\n");
1691                 printf("block <port> - Block given port.\n");
1692                 printf("unblock/load <port> - Unblock given port.\n");
1693                 printf("unload <port> - Unload port. To load port use 'block' or 'unblock'.\n");
1694                 printf("testcall [options] <interface> <callerid> <number> [present|restrict [<capability>]] - Testcall\n");
1695                 printf(" -> options = --setup-timeout <seconds> --proceeding-timeout <seconds>\n");
1696                 printf("              --alerting-timeout <seconds> --connect-timeout <seconds>\n");
1697                 printf(" -> capability = <bc> <mode> <codec> <hlc> <exthlc> (Values must be numbers, -1 to omit.)\n");
1698                 printf("trace [brief|short] [<filter> [...]] - Shows call trace. Use filter to reduce output.\n");
1699                 printf(" -> Use 'trace help' to see filter description.\n");
1700                 printf("\n");
1701                 return(0);
1702         }
1703
1704         /* check mode */
1705         if (!(strcasecmp(argv[1],"state"))) {
1706                 mode = MODE_STATE;
1707         } else
1708         if (!(strcasecmp(argv[1],"portinfo"))) {
1709                 mode = MODE_PORTINFO;
1710         } else
1711         if (!(strcasecmp(argv[1],"interface"))) {
1712                 mode = MODE_INTERFACE;
1713         } else
1714         if (!(strcasecmp(argv[1],"route"))) {
1715                 mode = MODE_ROUTE;
1716         } else
1717         if (!(strcasecmp(argv[1],"dial"))) {
1718                 if (argc <= 3)
1719                         goto usage;
1720                 mode = MODE_DIAL;
1721         } else
1722         if (!(strcasecmp(argv[1],"release"))) {
1723                 if (argc <= 2)
1724                         goto usage;
1725                 mode = MODE_RELEASE;
1726         } else
1727         if (!(strcasecmp(argv[1],"unblock"))
1728          || !(strcasecmp(argv[1],"load"))) {
1729                 if (argc <= 2)
1730                         goto usage;
1731                 mode = MODE_UNBLOCK;
1732         } else
1733         if (!(strcasecmp(argv[1],"block"))) {
1734                 if (argc <= 2)
1735                         goto usage;
1736                 mode = MODE_BLOCK;
1737         } else
1738         if (!(strcasecmp(argv[1],"unload"))) {
1739                 if (argc <= 2)
1740                         goto usage;
1741                 mode = MODE_UNLOAD;
1742         } else
1743         if (!(strcasecmp(argv[1],"testcall"))) {
1744                 if (argc <= 4)
1745                         goto usage;
1746                 mode = MODE_TESTCALL;
1747         } else
1748         if (!(strcasecmp(argv[1],"trace"))) {
1749                 mode = MODE_TRACE;
1750         } else {
1751                 goto usage;
1752         }
1753
1754         if (read_options() == 0) {
1755                 exit(EXIT_FAILURE);
1756         }
1757
1758 //pipeagain:
1759         /* open socket */
1760         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
1761                 fprintf(stderr, "Failed to create socket.\n");
1762                 exit(EXIT_FAILURE);
1763         }
1764         memset(&sock_address, 0, sizeof(sock_address));
1765         SPRINT(sock_address.sun_path, SOCKET_NAME, options.lock);
1766         sock_address.sun_family = PF_UNIX;
1767         if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0) {
1768                 close(sock);
1769                 fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path);
1770                 exit(EXIT_FAILURE);
1771         }
1772
1773         /* process mode */
1774         switch(mode) {
1775                 case MODE_STATE:
1776                 ret = admin_state(sock, argv);
1777                 break;
1778         
1779                 case MODE_PORTINFO:
1780                 ret = admin_portinfo(sock, argc, argv);
1781                 break;
1782         
1783                 case MODE_INTERFACE:
1784                 case MODE_ROUTE:
1785                 ret = admin_cmd(sock, mode, NULL, NULL);
1786                 break;
1787
1788                 case MODE_DIAL:
1789                 ret = admin_cmd(sock, mode, argv[2], argv[3]);
1790                 break;
1791
1792                 case MODE_RELEASE:
1793                 case MODE_UNBLOCK:
1794                 case MODE_BLOCK:
1795                 case MODE_UNLOAD:
1796                 ret = admin_cmd(sock, mode, NULL, argv[2]);
1797                 break;
1798
1799                 case MODE_TESTCALL:
1800                 ret = admin_testcall(sock, argc, argv);
1801                 break;
1802
1803                 case MODE_TRACE:
1804                 ret = admin_trace(sock, argc, argv);
1805                 break;
1806         }
1807
1808         close(sock);
1809         /* now we say good bye */
1810         if (ret) {
1811 //              if (!strncasecmp(ret, "Broken Pipe", 11))
1812 //                      goto pipeagain;
1813                 printf("%s\n", ret);
1814                 exit(EXIT_FAILURE);
1815         }
1816 }
1817
1818
1819
1820
1821