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