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