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