8cd40dae4bafbbd26300d35007c9af93a882cd0f
[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                                 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":"");
672                                 addstr(buffer);
673                                 color(red);
674                                 addstr("  not loaded");
675                         } else
676                         {
677                                 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);
678                                 addstr(buffer);
679                                 if (m[i].u.i.ptp || !m[i].u.i.ntmode)
680                                 {
681                                         color((m[i].u.i.l2link)?green:red);
682                                         addstr((m[i].u.i.l2link)?"  L2 UP":"  L2 down");
683                                 }
684                                 color((m[i].u.i.l1link > 0)?green:blue);
685                                 if (m[i].u.i.l1link < 0)
686                                         addstr("  L1 unknown");
687                                 else
688                                         addstr((m[i].u.i.l1link)?"  L1 ACTIVE":"  L1 inactive");
689                                 if (m[i].u.i.los)
690                                 {
691                                         color(red);
692                                         addstr(" LOS");
693                                 }
694                                 if (m[i].u.i.ais)
695                                 {
696                                         color(red);
697                                         addstr(" AIS");
698                                 }
699                                 if (m[i].u.i.rdi)
700                                 {
701                                         color(red);
702                                         addstr(" RDI");
703                                 }
704                                 if (m[i].u.i.slip_tx || m[i].u.i.slip_rx)
705                                 {
706                                         color(red);
707                                         SPRINT(buffer, " SLIP(tx:%d rx:%d)", m[i].u.i.slip_tx, m[i].u.i.slip_rx);
708                                         addstr(buffer);
709                                 }
710                                 if (m[i].u.i.block)
711                                 {
712                                         color(red);
713                                         addstr("  blocked");
714                                 }
715                                 if (line+2 >= LINES) goto end;
716                                 /* show channels */
717                                 if (show_interfaces > 1)
718                                 {
719                                         ltee = 0;
720                                         j = k =0;
721                                         jj = m[i].u.i.channels;
722                                         while(j < jj)
723                                         {
724                                                 /* show all channels */
725                                                 if (show_interfaces>2 || m[i].u.i.busy[j]>0)
726                                                 {
727                                                         color(cyan);
728                                                         /* show left side / right side */
729                                                         if ((k & 1) && (COLS > 70))
730                                                         {
731                                                                 move(line>1?line:1,4+((COLS-4)/2));
732                                                         } else
733                                                         {
734                                                                 move(++line>1?line:1, 1);
735                                                                 LTEE
736                                                                 ltee = 1;
737                                                         }
738                                                         k++;
739                                                         color(white);
740                                                         if (m[i].u.i.pri)
741                                                                 SPRINT(buffer,"S%2d: ", j+1+(j>=15));
742                                                         else
743                                                                 SPRINT(buffer,"B%2d: ", j+1);
744                                                         if (m[i].u.i.mode[j] == B_MODE_HDLC)
745                                                                 SCAT(buffer,"HDLC ");
746                                                         addstr(buffer);
747                                                         switch(m[i].u.i.busy[j])
748                                                         {
749                                                                 case B_STATE_IDLE:
750                                                                 if ((!m[i].u.i.l2link && m[i].u.i.ptp) || m[i].u.i.block)
751                                                                 {
752                                                                         color(red);
753                                                                         addstr("blocked ");
754                                                                 } else
755                                                                 {
756                                                                         color(blue);
757                                                                         addstr("idle    ");
758                                                                 }
759                                                                 break;
760                                                                 case B_STATE_ACTIVATING:
761                                                                 color(yellow);
762                                                                 addstr("act'ing ");
763                                                                 break;
764                                                                 case B_STATE_ACTIVE:
765                                                                 color(green);
766                                                                 addstr("busy    ");
767                                                                 break;
768                                                                 case B_STATE_DEACTIVATING:
769                                                                 color(yellow);
770                                                                 addstr("dact'ing");
771                                                                 break;
772                                                                 case B_STATE_EXPORTING:
773                                                                 color(yellow);
774                                                                 addstr("exp'ing ");
775                                                                 break;
776                                                                 case B_STATE_REMOTE:
777                                                                 color(green);
778                                                                 addstr("remote  ");
779                                                                 break;
780                                                                 case B_STATE_IMPORTING:
781                                                                 color(yellow);
782                                                                 addstr("imp'ing ");
783                                                                 break;
784                                                         }
785                                                         if (m[i].u.i.port[j])
786                                                         {
787                                                                 /* search for port */
788                                                                 l = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins+msg.u.s.epoints;
789                                                                 ll = l+msg.u.s.ports;
790                                                                 while(l < ll)
791                                                                 {
792                                                                         if (m[l].u.p.serial == m[i].u.i.port[j])
793                                                                         {
794                                                                                 SPRINT(buffer, " %s(%ld)", m[l].u.p.name, m[l].u.p.serial);
795                                                                                 addstr(buffer);
796                                                                         }
797                                                                         l++;
798                                                                 }
799                                                         }
800                                                         if (line+2 >= LINES)
801                                                         {
802                                                                 if (ltee)
803                                                                 {
804                                                                         color(cyan);
805                                                                         move(line>1?line:1, 1);
806                                                                         LLCORNER
807                                                                 }
808                                                                 goto end;
809                                                         }
810                                                 }
811                                                 j++;
812                                         }
813                                         if (ltee)
814                                         {
815                                                 color(cyan);
816                                                 move(line>1?line:1, 1);
817                                                 LLCORNER
818                                         }
819                                         if (line+2 >= LINES) goto end;
820                                         /* show summary if no channels were shown */
821                                         if (show_interfaces<2 && ltee==0)
822                                         {
823                                                 color(cyan);
824                                                 move(++line>1?line:1, 1);
825                                                 LLCORNER
826                                                         
827                                                 if (m[i].u.i.l2link && m[i].u.i.block==0)
828                                                 {
829                                                         color(green);
830                                                         SPRINT(buffer,"all %d channels free", m[i].u.i.channels);
831                                                 } else
832                                                 {
833                                                         color(red);
834                                                         SPRINT(buffer,"all %d channels blocked", m[i].u.i.channels);
835                                                 }
836                                                 addstr(buffer);
837                                         }
838                                         if (line+2 >= LINES) goto end;
839                                 }
840                         }
841                         i++;
842                         anything = 1;
843                 }
844                 i = msg.u.s.interfaces;
845                 ii = i + msg.u.s.remotes;
846                 while(i < ii)
847                 {
848                         /* show remote summary */
849                         move(++line>1?line:1, 0);
850                         color(white);
851                         SPRINT(buffer, "Remote: %s", m[i].u.r.name);
852                         addstr(buffer);
853                         i++;
854                 }
855                 if (anything)
856                         line++;
857                 if (line+2 >= LINES) goto end;
858         }               
859         /* display calls (brief) */
860         if (show_calls == 1)
861         {
862                 anything = 0;
863                 i = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins;
864                 ii = i+msg.u.s.epoints;
865                 while(i < ii)
866                 {
867                         /* for each endpoint... */
868                         if (!m[i].u.e.join)
869                         {
870                                 move(++line>1?line:1, 0);
871                                 color(white);
872                                 SPRINT(buffer, "(%d): ", m[i].u.e.serial);
873                                 addstr(buffer);
874                                 color(cyan);
875                                 if (m[i].u.e.terminal[0])
876                                 {
877                                         addstr("intern=");
878                                         color(green);
879                                         addstr(m[i].u.e.terminal);
880                                 } else
881                                         addstr("extern");
882                                 color(white);
883                                 SPRINT(buffer, " %s", m[i].u.e.callerid);
884                                 addstr(buffer);
885                                 color(cyan);
886                                 addstr("->");
887                                 color(white);
888                                 SPRINT(buffer, "%s", m[i].u.e.dialing);
889                                 addstr(buffer);
890                                 if (m[i].u.e.action[0])
891                                 {
892                                         color(cyan);
893                                         addstr(" action=");
894                                         color(yellow);
895                                         addstr(m[i].u.e.action);
896                                 }
897                                 if (line+2 >= LINES) goto end;
898                         }
899                         i++;
900                         anything = 1;
901                 }
902                 j = msg.u.s.interfaces+msg.u.s.remotes;
903                 jj = j+msg.u.s.joins;
904                 while(j < jj)
905                 {
906                         /* for each call... */
907                         move(++line>1?line:1, 0);
908                         color(white);
909                         SPRINT(buffer, "(%d):", m[j].u.j.serial);
910                         addstr(buffer);
911                         i = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins;
912                         ii = i+msg.u.s.epoints;
913                         while(i < ii)
914                         {
915                                 /* for each endpoint... */
916                                 if (m[i].u.e.join == m[j].u.j.serial)
917                                 {
918                                         color(white);
919                                         SPRINT(buffer, " (%d)", m[i].u.e.serial);
920                                         addstr(buffer);
921                                         color(cyan);
922                                         if (m[i].u.e.terminal[0])
923                                         {
924                                                 addstr("int=");
925                                                 color(green);
926                                                 addstr(m[i].u.e.terminal);
927                                         } else
928                                                 addstr("ext");
929                                         color(white);
930                                         SPRINT(buffer, "-%s", m[i].u.e.callerid);
931                                         addstr(buffer);
932                                         color(cyan);
933                                         addstr(">");
934                                         color(white);
935                                         SPRINT(buffer, "%s", m[i].u.e.dialing);
936                                         addstr(buffer);
937                                 }
938                                 i++;
939                                 anything = 1;
940                         }
941                         if (line+2 >= LINES) goto end;
942                         j++;
943                 }
944                 if (anything)
945                         line++;
946                 if (line+2 >= LINES) goto end;
947         }
948         /* display calls (structurd) */
949         if (show_calls == 2)
950         {
951                 /* show all ports with no epoint */
952                 anything = 0;
953                 i = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins+msg.u.s.epoints;
954                 ii = i+msg.u.s.ports;
955                 while(i < ii)
956                 {
957                         if (!m[i].u.p.epoint)
958                         {
959                                 move(++line>1?line:1, 8);
960                                 if (line+2 >= LINES) goto end;
961                                 line = debug_port(&msg, m, line, i, 0);
962                                 if (line+2 >= LINES) goto end;
963                                 anything = 1;
964                         }
965                         i++;
966                 }
967                 if (anything)
968                         line++;
969                 if (line+2 >= LINES) goto end;
970
971                 /* show all epoints with no call */
972                 anything = 0;
973                 i = msg.u.s.interfaces+msg.u.s.remotes+msg.u.s.joins;
974                 ii = i+msg.u.s.epoints;
975                 while(i < ii)
976                 {
977                         if (!m[i].u.e.join)
978                         {
979                                 move(++line>1?line:1, 4);
980                                 if (line+2 >= LINES) goto end;
981                                 line = debug_epoint(&msg, m, line, i, 0);
982                                 if (line+2 >= LINES) goto end;
983                                 anything = 1;
984                         }
985                         i++;
986                 }
987                 if (anything)
988                         line++;
989                 if (line+2 >= LINES) goto end;
990
991                 /* show all joins */
992                 anything = 0;
993                 i = msg.u.s.interfaces+msg.u.s.remotes;
994                 ii = i+msg.u.s.joins;
995                 while(i < ii)
996                 {
997                         move(++line>1?line:1, 0);
998                         if (line+2 >= LINES) goto end;
999                         line = debug_join(&msg, m, line, i);
1000                         if (line+2 >= LINES) goto end;
1001                         i++;
1002                         anything = 1;
1003                 }
1004                 if (anything)
1005                         line++;
1006                 if (line+2 >= LINES) goto end;
1007
1008         }
1009
1010         /* show log */
1011         if (show_log)
1012         {
1013                 if (line+2 < LINES)
1014                 {
1015                         move(line++>1?line-1:1, 0);
1016                         color(blue);
1017                         hline(ACS_HLINE, COLS);
1018                         color(white);
1019                         
1020                         l = logcur-(LINES-line-2);
1021                         ll = logcur;
1022                         if (ll-l >= LOGLINES)
1023                                 l = ll-LOGLINES+1;
1024                         while(l!=ll)
1025                         {
1026                                 move(line++>1?line-1:1, 0);
1027                                 if ((int)strlen(logline[l % LOGLINES]) > hoffset)
1028                                         SCPY(buffer, logline[l % LOGLINES] + hoffset);
1029                                 else
1030                                         buffer[0] = '\0';
1031                                 if (COLS < (int)strlen(buffer))
1032                                 {
1033                                         buffer[COLS-1] = '\0';
1034                                         addstr(buffer);
1035                                         color(mangenta);
1036                                         addch('*');
1037                                         color(white);
1038                                 } else
1039                                         addstr(buffer);
1040                                 l++;
1041                         }
1042                 }
1043         }
1044
1045         end:
1046         /* free memory */
1047         FREE(m, 0);
1048         /* display name/time */
1049 //      move(0, 0);
1050 //      hline(' ', COLS);
1051         move(0, 0);
1052         color(cyan);
1053         msg.u.s.version_string[sizeof(msg.u.s.version_string)-1] = '\0';
1054         SPRINT(buffer, "LCR %s", msg.u.s.version_string);
1055         addstr(buffer);
1056         if (COLS>50)
1057         {
1058                 move(0, COLS-19);
1059                 SPRINT(buffer, "%04d-%02d-%02d %02d:%02d:%02d",
1060                         msg.u.s.tm.tm_year+1900, msg.u.s.tm.tm_mon+1, msg.u.s.tm.tm_mday,
1061                         msg.u.s.tm.tm_hour, msg.u.s.tm.tm_min, msg.u.s.tm.tm_sec);
1062                 addstr(buffer);
1063         }
1064         /* displeay head line */
1065         move(1, 0);
1066         color(blue);
1067         hline(ACS_HLINE, COLS);
1068         if (offset)
1069         {
1070                 move(1, 1);
1071                 SPRINT(buffer, "Offset +%d", offset);
1072                 color(red);
1073                 addstr(buffer);
1074         }
1075         if (hoffset)
1076         {
1077                 move(1, 13);
1078                 SPRINT(buffer, "H-Offset +%d", hoffset);
1079                 color(red);
1080                 addstr(buffer);
1081         }
1082         /* display end */
1083         move(LINES-2, 0);
1084         color(blue);
1085         hline(ACS_HLINE, COLS);
1086         move(LINES-1, 0);
1087         if (enter)
1088         {
1089                 color(white);
1090                 SPRINT(buffer, "-> %s", enter_string);
1091         } else
1092         {
1093                 color(cyan);
1094                 SPRINT(buffer, "i=interfaces '%s'  c=calls '%s'  l=log  q=quit  +-*/=scroll  enter", text_interfaces[show_interfaces], text_calls[show_calls]);
1095         }
1096         addstr(buffer);
1097         refresh();
1098
1099         /* resize */
1100         if (lastlines!=LINES || lastcols!=COLS)
1101         {
1102                 cleanup_curses();
1103                 init_curses();
1104                 goto again;
1105         }
1106
1107         if (enter)
1108         {
1109                 /* user input in enter mode */
1110                 ch = getch();
1111                 enter_again:
1112                 if (ch == 10)
1113                 {
1114                         FILE *fp;
1115
1116                         enter = 0;
1117                         if (!enter_string[0])
1118                                 goto again;
1119
1120                         SPRINT(logline[logcur++ % LOGLINES], "> %s", enter_string);
1121                         if (!!strncmp(enter_string, "interface", 10) &&
1122                             !!strncmp(enter_string, "route", 6) &&
1123                             !!strncmp(enter_string, "release ", 8) &&
1124                             !!strncmp(enter_string, "block ", 6) &&
1125                             !!strncmp(enter_string, "unblock ", 8) &&
1126                             !!strncmp(enter_string, "unload ", 7))
1127                         {
1128                                 SPRINT(logline[logcur++ % LOGLINES], "usage:");
1129                                 SPRINT(logline[logcur++ % LOGLINES], "interface (reload interface.conf)");
1130                                 SPRINT(logline[logcur++ % LOGLINES], "route (reload routing.conf)");
1131                                 SPRINT(logline[logcur++ % LOGLINES], "release <EP> (release endpoint with given ID)");
1132                                 SPRINT(logline[logcur++ % LOGLINES], "block <port> (block port for further calls)");
1133                                 SPRINT(logline[logcur++ % LOGLINES], "unblock <port> (unblock port for further calls, load if not loaded)");
1134                                 SPRINT(logline[logcur++ % LOGLINES], "unload <port> (unload mISDN stack, release call calls)");
1135                         } else
1136                         {
1137                                 /* applend output to log window */
1138                                 SPRINT(buffer, "%s %s", argv[0], enter_string);
1139                                 fp = popen(buffer, "r");
1140                                 if (fp)
1141                                 {
1142                                         while(fgets(logline[logcur % LOGLINES], sizeof(logline[0]), fp))
1143                                                 logline[logcur++ % LOGLINES][sizeof(logline[0])-1] = '\0';
1144                                         pclose(fp);
1145                                 } else
1146                                 {
1147                                         SPRINT(logline[logcur++ % LOGLINES], "failed to execute '%s'", buffer);
1148                                 }
1149                         }
1150                         logline[logcur % LOGLINES][0] = '\0';
1151                         enter_string[0] = '\0';
1152                         goto again;
1153                 }
1154                 if (ch>=32 && ch<=126)
1155                 {
1156                         SCCAT(enter_string, ch);
1157                         ch = getch();
1158                         if (ch > 0)
1159                                 goto enter_again;
1160                         goto again;
1161                 } else
1162                 if (ch==8 || ch==127)
1163                 {
1164                         if (enter_string[0])
1165                                 enter_string[strlen(enter_string)-1] = '\0';
1166                         ch = getch();
1167                         if (ch > 0)
1168                                 goto enter_again;
1169                         goto again;
1170                 } else
1171                 if (ch != 3)
1172                 {
1173                         ch = getch();
1174                         if (ch > 0)
1175                                 goto enter_again;
1176                         FD_ZERO(&select_rfds);
1177                         FD_SET(0, &select_rfds);
1178                         select_tv.tv_sec = 0;
1179                         select_tv.tv_usec = 250000;
1180                         select(1, &select_rfds, NULL, NULL, &select_tv);
1181                         goto again;
1182                 }
1183         } else
1184         {
1185                 /* user input in normal mode */
1186                 switch(getch())
1187                 {
1188                         case 12: /* refresh */
1189                         cleanup_curses();
1190                         init_curses();
1191                         goto again;
1192                         break;
1193
1194                         case 3: /* abort */
1195                         case 'q':
1196                         case 'Q':
1197                         break;
1198
1199                         case 'i': /* toggle interface */
1200                         show_interfaces++;
1201                         if (show_interfaces > 3) show_interfaces = 0;
1202                         goto again;
1203
1204                         case 'c': /* toggle calls */
1205                         show_calls++;
1206                         if (show_calls > 2) show_calls = 0;
1207                         goto again;
1208
1209                         case 'l': /* toggle log */
1210                         show_log++;
1211                         if (show_log > 1) show_log = 0;
1212                         goto again;
1213
1214                         case '+': /* scroll down */
1215                         offset++;
1216                         goto again;
1217                         
1218                         case '-': /* scroll up */
1219                         if (offset)
1220                                 offset--;
1221                         goto again;
1222
1223                         case '*': /* scroll right */
1224                         hoffset += 2;
1225                         goto again;
1226                         
1227                         case '/': /* scroll left */
1228                         if (hoffset)
1229                                 hoffset -= 2;
1230                         goto again;
1231
1232                         case 10: /* entermode */
1233                         enter = 1;
1234                         goto again;
1235
1236                         default:
1237                         FD_ZERO(&select_rfds);
1238                         FD_SET(0, &select_rfds);
1239                         select_tv.tv_sec = 0;
1240                         select_tv.tv_usec = 250000;
1241                         select(1, &select_rfds, NULL, NULL, &select_tv);
1242                         goto again;
1243                 }
1244         }
1245
1246         /* check for logfh */
1247         if (logfh >= 0)
1248                 close(logfh);
1249         logfh = -1;
1250
1251         /* cleanup curses and exit */
1252         cleanup_curses();
1253
1254         return(NULL);
1255 }
1256
1257
1258 /*
1259  * Send command and show error message.
1260  */
1261 const char *admin_cmd(int sock, int mode, char *extension, char *number)
1262 {
1263         static struct admin_message msg;
1264
1265         /* send reload command */
1266         memset(&msg, 0, sizeof(msg));
1267         switch(mode)
1268         {
1269                 case MODE_INTERFACE:
1270                 msg.message = ADMIN_REQUEST_CMD_INTERFACE;
1271                 break;
1272                 case MODE_ROUTE:
1273                 msg.message = ADMIN_REQUEST_CMD_ROUTE;
1274                 break;
1275                 case MODE_DIAL:
1276                 msg.message = ADMIN_REQUEST_CMD_DIAL;
1277                 SPRINT(msg.u.x.message, "%s:%s", extension?:"", number?:"");
1278                 break;
1279                 case MODE_RELEASE:
1280                 msg.message = ADMIN_REQUEST_CMD_RELEASE;
1281                 SCPY(msg.u.x.message, number);
1282                 break;
1283                 case MODE_UNBLOCK:
1284                 msg.message = ADMIN_REQUEST_CMD_BLOCK;
1285                 msg.u.x.portnum = atoi(number);
1286                 msg.u.x.block = 0;
1287                 break;
1288                 case MODE_BLOCK:
1289                 msg.message = ADMIN_REQUEST_CMD_BLOCK;
1290                 msg.u.x.portnum = atoi(number);
1291                 msg.u.x.block = 1;
1292                 break;
1293                 case MODE_UNLOAD:
1294                 msg.message = ADMIN_REQUEST_CMD_BLOCK;
1295                 msg.u.x.portnum = atoi(number);
1296                 msg.u.x.block = 2;
1297                 break;
1298         }
1299
1300         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1301                 return("Broken pipe while sending command.");
1302
1303         /* receive response */
1304         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
1305                 return("Broken pipe while receiving response.");
1306         switch(mode)
1307         {
1308                 case MODE_INTERFACE:
1309                 if (msg.message != ADMIN_RESPONSE_CMD_INTERFACE)
1310                         return("Response not valid.");
1311                 break;
1312                 case MODE_ROUTE:
1313                 if (msg.message != ADMIN_RESPONSE_CMD_ROUTE)
1314                         return("Response not valid.");
1315                 break;
1316                 case MODE_DIAL:
1317                 if (msg.message != ADMIN_RESPONSE_CMD_DIAL)
1318                         return("Response not valid.");
1319                 break;
1320                 case MODE_RELEASE:
1321                 if (msg.message != ADMIN_RESPONSE_CMD_RELEASE)
1322                         return("Response not valid.");
1323                 break;
1324                 case MODE_UNBLOCK:
1325                 case MODE_BLOCK:
1326                 case MODE_UNLOAD:
1327                 if (msg.message != ADMIN_RESPONSE_CMD_BLOCK)
1328                         return("Response not valid.");
1329                 break;
1330         }
1331
1332         /* process response */
1333         if (msg.u.x.error)
1334         {
1335                 return(msg.u.x.message);
1336         }
1337         printf("Command successfull.\n");
1338         return(NULL);
1339 }
1340
1341
1342 /*
1343  * makes a testcall
1344  */
1345 #define GET_NOW() { \
1346         gettimeofday(&now_tv, &now_tz); \
1347         now_d = ((double)(now_tv.tv_usec))/1000000 + now_tv.tv_sec; \
1348         }
1349 const char *admin_testcall(int sock, int argc, char *argv[])
1350 {
1351         static struct admin_message msg;
1352         int ar = 2;
1353         int stimeout = 0, ptimeout = 0, atimeout = 0, ctimeout = 0;
1354         int l;
1355         double timer = 0, now_d;
1356         unsigned int on = 1;
1357         struct timeval now_tv;
1358         struct timezone now_tz;
1359
1360         printf("pid=%d\n", getpid()); fflush(stdout);
1361
1362         while (argc > ar)
1363         {
1364                 if (!strcmp(argv[ar], "--setup-timeout"))
1365                 {
1366                         ar++;
1367                         if (argc == ar)
1368                                 return("Missing setup timeout value.\n");
1369                         stimeout = atoi(argv[ar]);
1370                         ar++;
1371                 } else
1372                 if (!strcmp(argv[ar], "--proceeding-timeout"))
1373                 {
1374                         ar++;
1375                         if (argc == ar)
1376                                 return("Missing proceeding timeout value.\n");
1377                         ptimeout = atoi(argv[ar]);
1378                         ar++;
1379                 } else
1380                 if (!strcmp(argv[ar], "--alerting-timeout"))
1381                 {
1382                         ar++;
1383                         if (argc == ar)
1384                                 return("Missing alerting timeout value.\n");
1385                         atimeout = atoi(argv[ar]);
1386                         ar++;
1387                 } else
1388                 if (!strcmp(argv[ar], "--connect-timeout"))
1389                 {
1390                         ar++;
1391                         if (argc == ar)
1392                                 return("Missing connect timeout value.\n");
1393                         ctimeout = atoi(argv[ar]);
1394                         ar++;
1395                 } else
1396                 {
1397                         break;
1398                 }
1399         }
1400
1401         /* send reload command */
1402         memset(&msg, 0, sizeof(msg));
1403         msg.message = ADMIN_CALL_SETUP;
1404         msg.u.call.present = 1;
1405
1406         if (argc > ar)
1407         {
1408                 SCPY(msg.u.call.interface, argv[ar]);
1409         }
1410         ar++;
1411         if (argc > ar)
1412         {
1413                 SCPY(msg.u.call.callerid, argv[ar]);
1414         }
1415         ar++;
1416         if (argc > ar)
1417         {
1418                 SCPY(msg.u.call.dialing, argv[ar]);
1419         }
1420         ar++;
1421         if (argc > ar)
1422         {
1423                 if (argv[ar][0] == 'r')
1424                         msg.u.call.present = 0;
1425         }
1426         ar++;
1427         msg.u.call.bc_capa = 0x00; /*INFO_BC_SPEECH*/
1428         msg.u.call.bc_mode = 0x00; /*INFO_BMODE_CIRCUIT*/
1429         msg.u.call.bc_info1 = 0;
1430         msg.u.call.hlc = 0;
1431         msg.u.call.exthlc = 0;
1432         if (argc > ar)
1433                 msg.u.call.bc_capa = strtol(argv[ar],NULL,0);
1434         else
1435                 msg.u.call.bc_info1 = 3 | 0x80; /* alaw, if no capability is given at all */
1436         ar++;
1437         if (argc > ar) {
1438                 msg.u.call.bc_mode = strtol(argv[ar],NULL,0);
1439                 if (msg.u.call.bc_mode) msg.u.call.bc_mode = 2;
1440         }
1441         ar++;
1442         if (argc > ar) {
1443                 msg.u.call.bc_info1 = strtol(argv[ar],NULL,0);
1444                 if (msg.u.call.bc_info1 < 0)
1445                         msg.u.call.bc_info1 = 0;
1446                 else
1447                         msg.u.call.bc_info1 |= 0x80;
1448         }
1449         ar++;
1450         if (argc > ar) {
1451                 msg.u.call.hlc = strtol(argv[ar],NULL,0);
1452                 if (msg.u.call.hlc < 0)
1453                         msg.u.call.hlc = 0;
1454                 else
1455                         msg.u.call.hlc |= 0x80;
1456         }
1457         ar++;
1458         if (argc > ar) {
1459                 msg.u.call.exthlc = strtol(argv[ar],NULL,0);
1460                 if (msg.u.call.exthlc < 0)
1461                         msg.u.call.exthlc = 0;
1462                 else
1463                         msg.u.call.exthlc |= 0x80;
1464         }
1465         ar++;
1466
1467         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1468                 return("Broken pipe while sending command.");
1469
1470         if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0)
1471                 return("Failed to set socket into non-blocking IO.");
1472
1473         if (stimeout)
1474         {
1475                 GET_NOW();
1476                 timer = now_d + (double)stimeout;
1477         }
1478         
1479         /* receive response */
1480 next:
1481         l = read(sock, &msg, sizeof(msg));
1482         if (l < 0)
1483         {
1484                 if (errno == EWOULDBLOCK)
1485                 {
1486                         if (timer)
1487                         {
1488                                 GET_NOW();
1489                                 if (timer <= now_d)
1490                                 {
1491                                         printf("Timeout\n"); fflush(stdout);
1492                                         return(NULL);
1493                                 }
1494                         }
1495                         usleep(30000);
1496                         goto next;
1497                 }
1498                 return("Broken pipe while receiving response.");
1499         }
1500         if (l != sizeof(msg))
1501                 return("Response has unexpected message size.");
1502         switch(msg.message)
1503         {
1504                 case ADMIN_CALL_SETUP_ACK:
1505                 printf("SETUP ACKNOWLEDGE\n"); fflush(stdout);
1506                 goto next;
1507
1508                 case ADMIN_CALL_PROCEEDING:
1509                 printf("PROCEEDING\n"); fflush(stdout);
1510                 if (ptimeout)
1511                 {
1512                         GET_NOW();
1513                         timer = now_d + (double)ptimeout;
1514                 }
1515                 goto next;
1516
1517                 case ADMIN_CALL_ALERTING:
1518                 printf("ALERTING\n"); fflush(stdout);
1519                 if (atimeout)
1520                 {
1521                         GET_NOW();
1522                         timer = now_d + (double)atimeout;
1523                 }
1524                 goto next;
1525
1526                 case ADMIN_CALL_CONNECT:
1527                 printf("CONNECT\n number=%s\n", msg.u.call.callerid); fflush(stdout);
1528                 if (ctimeout)
1529                 {
1530                         GET_NOW();
1531                         timer = now_d + (double)ctimeout;
1532                 }
1533                 goto next;
1534
1535                 case ADMIN_CALL_NOTIFY:
1536                 printf("NOTIFY\n notify=%d\n number=%s\n", msg.u.call.notify, msg.u.call.callerid); fflush(stdout);
1537                 goto next;
1538
1539                 case ADMIN_CALL_DISCONNECT:
1540                 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);
1541                 break;
1542
1543                 case ADMIN_CALL_RELEASE:
1544                 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);
1545                 break;
1546
1547                 default:
1548                 return("Response not valid.");
1549         }
1550
1551         printf("Call released.\n"); fflush(stdout);
1552         return(NULL);
1553 }
1554
1555
1556 /*
1557  * makes a trace
1558  */
1559 const char *admin_trace(int sock, int argc, char *argv[])
1560 {
1561         static struct admin_message msg;
1562         int i;
1563
1564         /* show help */
1565         if (argc > 2) if (!strcasecmp(argv[2], "help"))
1566         {
1567                 printf("Trace Help\n----------\n");
1568                 printf("%s trace [brief|short] [<filter>=<value> [...]]\n\n", argv[0]);
1569                 printf("By default a complete trace is shown in detailed format.\n");
1570                 printf("To show a more compact format, use 'brief' or 'short' keyword.\n");
1571                 printf("Use filter values to select specific trace messages.\n");
1572                 printf("All given filter values must match. If no filter is given, anything matches.\n\n");
1573                 printf("Filters:\n");
1574                 printf(" category=<mask bits>\n");
1575                 printf("  0x01 = CH: channel object trace\n");
1576                 printf("  0x02 = EP: endpoint object trace\n");
1577                 printf(" port=<mISDN port>  select only given port for trace\n");
1578                 printf(" interface=<interface name>  select only given interface for trace\n");
1579                 printf(" caller=<caller id>  select only given caller id for trace\n");
1580                 printf(" dialing=<number>  select only given dialed number for trace\n");
1581                 return(NULL);
1582         }
1583
1584         /* init trace request */        
1585         memset(&msg, 0, sizeof(msg));
1586         msg.message = ADMIN_TRACE_REQUEST;
1587         msg.u.trace_req.detail = 3;
1588
1589         /* parse args */
1590         i = 2;
1591         while(i < argc)
1592         {
1593                 if (!strcasecmp(argv[i], "brief"))
1594                         msg.u.trace_req.detail = 1;
1595                 else if (!strcasecmp(argv[i], "short"))
1596                         msg.u.trace_req.detail = 2;
1597                 else if (!strncasecmp(argv[i], "category=", 9))
1598                         msg.u.trace_req.category = atoi(argv[i]+9);
1599                 else if (!strncasecmp(argv[i], "port=", 5))
1600                         msg.u.trace_req.port = atoi(argv[i]+5);
1601                 else if (!strncasecmp(argv[i], "interface=", 10))
1602                         SCPY(msg.u.trace_req.interface, argv[i]+10);
1603                 else if (!strncasecmp(argv[i], "caller=", 7))
1604                         SCPY(msg.u.trace_req.caller, argv[i]+7);
1605                 else if (!strncasecmp(argv[i], "dialing=", 8))
1606                         SCPY(msg.u.trace_req.dialing, argv[i]+8);
1607                 else return("Invalid trace option, try 'trace help'.");
1608
1609                 i++;
1610         }
1611
1612         /* send trace request */
1613         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1614                 return("Broken pipe while sending trace request.");
1615
1616         /* receive response */
1617 next:
1618         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
1619                 return("Broken pipe while receiving response.");
1620
1621         if (msg.message != ADMIN_TRACE_RESPONSE)
1622                 return("Response not valid.");
1623
1624         printf("%s", msg.u.trace_rsp.text);
1625         goto next;
1626 }
1627
1628
1629 /*
1630  * main function
1631  */
1632 int main(int argc, char *argv[])
1633 {
1634         int mode;
1635         int sock, conn;
1636         struct sockaddr_un sock_address;
1637         const char *ret;
1638
1639
1640         /* show options */
1641         if (argc <= 1)
1642         {
1643                 usage:
1644                 printf("\n");
1645                 printf("Usage: %s state | interface | route | dial ...\n", argv[0]);
1646                 printf("state - View current states using graphical console output.\n");
1647                 printf("interface - Tell LCR to reload \"interface.conf\".\n");
1648                 printf("route - Tell LCR to reload \"route.conf\".\n");
1649                 printf("dial <extension> <number> - Tell LCR the next number to dial for extension.\n");
1650                 printf("release <number> - Tell LCR to release endpoint with given number.\n");
1651                 printf("block <port> - Block given port.\n");
1652                 printf("unblock <port> - Unblock given port.\n");
1653                 printf("unload <port> - Unload port. To load port use 'block' or 'unblock'.\n");
1654                 printf("testcall [options] <interface> <callerid> <number> [present|restrict [<capability>]] - Testcall\n");
1655                 printf(" -> options = --setup-timeout <seconds> --proceeding-timeout <seconds>\n");
1656                 printf("              --alerting-timeout <seconds> --connect-timeout <seconds>\n");
1657                 printf(" -> capability = <bc> <mode> <codec> <hlc> <exthlc> (Values must be numbers, -1 to omit.)\n");
1658                 printf("trace [brief|short] [<filter> [...]] - Shows call trace. Use filter to reduce output.\n");
1659                 printf(" -> Use 'trace help' to see filter description.\n");
1660                 printf("\n");
1661                 return(0);
1662         }
1663
1664         /* check mode */
1665         if (!(strcasecmp(argv[1],"state")))
1666         {
1667                 mode = MODE_STATE;
1668         } else
1669         if (!(strcasecmp(argv[1],"interface")))
1670         {
1671                 mode = MODE_INTERFACE;
1672         } else
1673         if (!(strcasecmp(argv[1],"route")))
1674         {
1675                 mode = MODE_ROUTE;
1676         } else
1677         if (!(strcasecmp(argv[1],"dial")))
1678         {
1679                 if (argc <= 3)
1680                         goto usage;
1681                 mode = MODE_DIAL;
1682         } else
1683         if (!(strcasecmp(argv[1],"release")))
1684         {
1685                 if (argc <= 2)
1686                         goto usage;
1687                 mode = MODE_RELEASE;
1688         } else
1689         if (!(strcasecmp(argv[1],"unblock")))
1690         {
1691                 if (argc <= 2)
1692                         goto usage;
1693                 mode = MODE_UNBLOCK;
1694         } else
1695         if (!(strcasecmp(argv[1],"block")))
1696         {
1697                 if (argc <= 2)
1698                         goto usage;
1699                 mode = MODE_BLOCK;
1700         } else
1701         if (!(strcasecmp(argv[1],"unload")))
1702         {
1703                 if (argc <= 2)
1704                         goto usage;
1705                 mode = MODE_UNLOAD;
1706         } else
1707         if (!(strcasecmp(argv[1],"testcall")))
1708         {
1709                 if (argc <= 4)
1710                         goto usage;
1711                 mode = MODE_TESTCALL;
1712         } else
1713         if (!(strcasecmp(argv[1],"trace")))
1714         {
1715                 mode = MODE_TRACE;
1716         } else
1717         {
1718                 goto usage;
1719         }
1720
1721         if (read_options() == 0) {
1722                 exit(EXIT_FAILURE);
1723         }
1724
1725 //pipeagain:
1726         /* open socket */
1727         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1728         {
1729                 fprintf(stderr, "Failed to create socket.\n");
1730                 exit(EXIT_FAILURE);
1731         }
1732         memset(&sock_address, 0, sizeof(sock_address));
1733         SPRINT(sock_address.sun_path, SOCKET_NAME, options.lock);
1734         sock_address.sun_family = PF_UNIX;
1735         if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
1736         {
1737                 close(sock);
1738                 fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path);
1739                 exit(EXIT_FAILURE);
1740         }
1741
1742         /* process mode */
1743         switch(mode)
1744         {
1745                 case MODE_STATE:
1746                 ret = admin_state(sock, argv);
1747                 break;
1748         
1749                 case MODE_INTERFACE:
1750                 case MODE_ROUTE:
1751                 ret = admin_cmd(sock, mode, NULL, NULL);
1752                 break;
1753
1754                 case MODE_DIAL:
1755                 ret = admin_cmd(sock, mode, argv[2], argv[3]);
1756                 break;
1757
1758                 case MODE_RELEASE:
1759                 case MODE_UNBLOCK:
1760                 case MODE_BLOCK:
1761                 case MODE_UNLOAD:
1762                 ret = admin_cmd(sock, mode, NULL, argv[2]);
1763                 break;
1764
1765                 case MODE_TESTCALL:
1766                 ret = admin_testcall(sock, argc, argv);
1767                 break;
1768
1769                 case MODE_TRACE:
1770                 ret = admin_trace(sock, argc, argv);
1771                 break;
1772         }
1773
1774         close(sock);
1775         /* now we say good bye */
1776         if (ret)
1777         {
1778 //              if (!strncasecmp(ret, "Broken Pipe", 11))
1779 //                      goto pipeagain;
1780                 printf("%s\n", ret);
1781                 exit(EXIT_FAILURE);
1782         }
1783 }
1784
1785
1786
1787
1788