82b21e92621b2d8b23d68c1696dd29cd9da4f814
[lcr.git] / admin_client.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
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 <curses.h>
23 #include "save.h"
24 #include "call.h"
25 #include "callpbx.h"
26 #include "admin.h"
27 #include "cause.h"
28
29 #define LTEE {addch(/*ACS_LTEE*/'t');addch(/*ACS_HLINE*/'q');addch(/*ACS_HLINE*/'q');}
30 #define LLCORNER {addch(/*ACS_LLCORNER*/'m');addch(/*ACS_HLINE*/'q');addch(/*ACS_HLINE*/'q');}
31 #define VLINE {addch(/*ACS_VLINE*/'x');addstr("  ");}
32 #define EMPTY {addstr("   ");}
33 //char rotator[] = {'-', '\\', '|', '/'};
34 int     lastlines, lastcols;
35 int     show_interfaces = 2,
36         show_calls = 1,
37         show_log = 1;
38
39 enum {
40         MODE_STATE,
41         MODE_INTERFACE,
42         MODE_ROUTE,
43         MODE_DIAL,
44         MODE_RELEASE,
45         MODE_TESTCALL,
46         MODE_TRACE,
47 };
48
49 char *text_interfaces[] = {
50         "off",
51         "brief",
52         "active channels",
53         "all channels",
54 };
55
56 char *text_calls[] = {
57         "off",
58         "brief",
59         "structured",
60 };
61
62 char    red = 1,
63         green = 2,
64         yellow = 3,
65         blue = 4,
66         mangenta = 5,
67         cyan = 6,
68         white = 7;
69
70 #define LOGLINES 128
71 char logline[LOGLINES][256];
72 unsigned long logcur = 0;
73 int logfh = -1;
74 char logfile[128];
75
76 /*
77  * curses
78  */
79 void init_curses(void)
80 {
81         /* init curses */
82         initscr(); cbreak(); noecho();
83         start_color();
84         nodelay(stdscr, TRUE);
85         if (COLOR_PAIRS>=8 && COLORS>=8)
86         {
87                 init_pair(1,1,0);
88                 init_pair(2,2,0);
89                 init_pair(3,3,0);
90                 init_pair(4,4,0);
91                 init_pair(5,5,0);
92                 init_pair(6,6,0);
93                 init_pair(7,7,0);
94         }
95         lastlines = LINES;
96         lastcols = COLS;
97 }
98
99 void cleanup_curses(void)
100 {
101         endwin();
102 }
103
104 void color(int color)
105 {
106         if (COLOR_PAIRS>=8 && COLORS>=8)
107                 attrset(COLOR_PAIR(color));
108 }
109
110 /*
111  * permanently show current state using ncurses
112  */
113 int debug_port(struct admin_message *msg, struct admin_message *m, int line, int i, int vline)
114 {
115         char buffer[256];
116
117         color(white);
118         addstr("PORT:");
119         color(yellow);
120         SPRINT(buffer,"%s(%d)", m[i].u.p.name,m[i].u.p.serial);
121         addstr(buffer);
122         color(cyan);
123         addstr(" state=");
124         switch (m[i].u.p.state)
125         {
126                 case ADMIN_STATE_IDLE:
127                 color(red);
128                 addstr("'idle'");
129                 break;
130                 case ADMIN_STATE_IN_SETUP:
131                 color(red);
132                 addstr("'in << setup'");
133                 break;
134                 case ADMIN_STATE_OUT_SETUP:
135                 color(red);
136                 addstr("'out >> setup'");
137                 break;
138                 case ADMIN_STATE_IN_OVERLAP:
139                 color(yellow);
140                 addstr("'in << overlap'");
141                 break;
142                 case ADMIN_STATE_OUT_OVERLAP:
143                 color(yellow);
144                 addstr("'out >> overlap'");
145                 break;
146                 case ADMIN_STATE_IN_PROCEEDING:
147                 color(mangenta);
148                 addstr("'in << proc'");
149                 break;
150                 case ADMIN_STATE_OUT_PROCEEDING:
151                 color(mangenta);
152                 addstr("'out >> proc'");
153                 break;
154                 case ADMIN_STATE_IN_ALERTING:
155                 color(cyan);
156                 addstr("'in << alert'");
157                 break;
158                 case ADMIN_STATE_OUT_ALERTING:
159                 color(cyan);
160                 addstr("'out >> alert'");
161                 break;
162                 case ADMIN_STATE_CONNECT:
163                 color(white);
164                 addstr("'connect'");
165                 break;
166                 case ADMIN_STATE_IN_DISCONNECT:
167                 color(blue);
168                 addstr("'in  << disc'");
169                 break;
170                 case ADMIN_STATE_OUT_DISCONNECT:
171                 color(blue);
172                 addstr("'out >> disc'");
173                 break;
174                 default:
175                 color(blue);
176                 addstr("'--NONE--'");
177         }
178
179         if (m[i].u.p.isdn)
180         {       
181                 color(cyan);
182                 addstr(" bchannel=");
183                 color(white);
184                 SPRINT(buffer,"%d", m[i].u.p.isdn_chan);
185                 addstr(buffer);
186                 if (m[i].u.p.isdn_ces >= 0)
187                 {
188                         color(cyan);
189                         addstr(" ces=");
190                         color(yellow);
191                         SPRINT(buffer, "%d", m[i].u.p.isdn_ces);
192                         addstr(buffer);
193                 }
194                 if (m[i].u.p.isdn_hold)
195                 {
196                         color(red);
197                         addstr(" hold");
198                 }
199         }
200
201         return(line);
202 }
203 int debug_epoint(struct admin_message *msg, struct admin_message *m, int line, int i, int vline)
204 {
205         unsigned long epoint = m[i].u.e.serial;
206         char buffer[256];
207         unsigned char c;
208         int j, jj;
209         int ltee;
210
211         color(white);
212         SPRINT(buffer,"EPOINT(%d)", epoint);
213         addstr(buffer);
214         color(cyan);
215         addstr(" state=");
216         switch (m[i].u.e.state)
217         {
218                 case ADMIN_STATE_IDLE:
219                 color(red);
220                 addstr("'idle'");
221                 break;
222                 case ADMIN_STATE_IN_SETUP:
223                 color(red);
224                 addstr("'in << setup'");
225                 break;
226                 case ADMIN_STATE_OUT_SETUP:
227                 color(red);
228                 addstr("'out >> setup'");
229                 break;
230                 case ADMIN_STATE_IN_OVERLAP:
231                 color(yellow);
232                 addstr("'in << overlap'");
233                 break;
234                 case ADMIN_STATE_OUT_OVERLAP:
235                 color(yellow);
236                 addstr("'out >> overlap'");
237                 break;
238                 case ADMIN_STATE_IN_PROCEEDING:
239                 color(mangenta);
240                 addstr("'in << proc'");
241                 break;
242                 case ADMIN_STATE_OUT_PROCEEDING:
243                 color(mangenta);
244                 addstr("'out >> proc'");
245                 break;
246                 case ADMIN_STATE_IN_ALERTING:
247                 color(cyan);
248                 addstr("'in << alert'");
249                 break;
250                 case ADMIN_STATE_OUT_ALERTING:
251                 color(cyan);
252                 addstr("'out >> alert'");
253                 break;
254                 case ADMIN_STATE_CONNECT:
255                 color(white);
256                 addstr("'connect'");
257                 break;
258                 case ADMIN_STATE_IN_DISCONNECT:
259                 color(blue);
260                 addstr("'in  << disc'");
261                 break;
262                 case ADMIN_STATE_OUT_DISCONNECT:
263                 color(blue);
264                 addstr("'out >> disc'");
265                 break;
266                 default:
267                 color(blue);
268                 addstr("'--NONE--'");
269         }
270         if (m[i].u.e.terminal[0])
271         {
272                 color(cyan);
273                 addstr(" terminal=");
274                 color(green);
275                 addstr(m[i].u.e.terminal);
276         }
277         color(white);
278         SPRINT(buffer, " %s", m[i].u.e.callerid);
279         addstr(buffer);
280         color(cyan);
281         addstr("->");
282         color(white);
283         addstr(m[i].u.e.dialing);
284         if (m[i].u.e.action[0])
285         {
286                 color(cyan);
287                 addstr(" action=");
288                 color(yellow);
289                 addstr(m[i].u.e.action);
290         }
291         if (m[i].u.e.park)
292         {
293                 color(cyan);
294                 addstr(" park="); /* 9 digits */
295                 color(green);
296                 UCPY(buffer, "\""); /* 9 digits */
297                 j = 0;
298                 jj = m[i].u.e.park_len;
299                 while(j < jj)
300                 {
301                         c = m[i].u.e.park_callid[j];
302                         if (c >= 32 && c < 127 && c != '[')
303                         {
304                                 SCCAT(buffer, c);
305                         } else
306                                 UPRINT(buffer+strlen(buffer), "[%02x]", c);
307                         j++;
308                 }
309                 SCAT(buffer, "\"");
310                 addstr(buffer);
311         } else
312         {
313                 color(red);
314                 switch(m[i].u.e.rx_state)
315                 {
316                         case NOTIFY_STATE_SUSPEND:
317                         addstr(" in=suspend");
318                         break;
319                         case NOTIFY_STATE_HOLD:
320                         addstr(" in=hold");
321                         break;
322                         case NOTIFY_STATE_CONFERENCE:
323                         addstr(" in=conference");
324                         break;
325                 }
326                 switch(m[i].u.e.tx_state)
327                 {
328                         case NOTIFY_STATE_SUSPEND:
329                         addstr(" out=suspend");
330                         break;
331                         case NOTIFY_STATE_HOLD:
332                         addstr(" out=hold");
333                         break;
334                         case NOTIFY_STATE_CONFERENCE:
335                         addstr(" out=conference");
336                         break;
337                 }
338         }
339         if (m[i].u.e.crypt)
340         {
341                 color(cyan);
342                 addstr(" crypt=");
343                 if (m[i].u.e.crypt) /* crypt on */
344                 {
345                         color(green);
346                         addstr("active");
347                 } else
348                 {
349                         color(yellow);
350                         addstr("pending");
351                 }
352         }
353         /* loop all related ports */
354         ltee = 0;
355         j = msg->u.s.interfaces+msg->u.s.calls+msg->u.s.epoints;
356         jj = j + msg->u.s.ports;
357         while(j < jj)
358         {
359                 if (m[j].u.p.epoint == epoint)
360                 {
361                         color(cyan);
362                         move(++line>1?line:1, 1);
363                         if (vline)
364                                 VLINE
365                         else
366                                 EMPTY
367                         move(line>1?line:1, 5);
368                         LTEE
369                         ltee = line;
370                         move(line>1?line:1, 8);
371                         if (line+2 >= LINES) break;
372                         line = debug_port(msg, m, line, j, vline);
373                         if (line+2 >= LINES) break;
374                 }
375                 j++;
376         }
377         if (ltee)
378         {
379                 color(cyan);
380                 move(ltee>1?line:1, 5);
381                 LLCORNER
382         }
383
384         return(line);
385 }
386 int debug_call(struct admin_message *msg, struct admin_message *m, int line, int i)
387 {
388         unsigned long   call = m[i].u.c.serial;
389         char            buffer[256];
390         int             j, jj;
391
392         color(white);
393         SPRINT(buffer,"CALL(%d)", call);
394         addstr(buffer);
395         if (m[i].u.c.partyline)
396         {
397                 color(cyan);
398                 addstr(" partyline=");
399                 color(white);
400                 SPRINT(buffer, "%d\n", m[i].u.c.partyline);
401                 addstr(buffer);
402         }
403         /* find number of epoints */
404         j = msg->u.s.interfaces+msg->u.s.calls;
405         jj = j + msg->u.s.epoints;
406         i = 0;
407         while(j < jj)
408         {
409                 if (m[j].u.e.call == call)
410                         i++;
411                 j++;
412         }
413         /* loop all related endpoints */
414         j = msg->u.s.interfaces+msg->u.s.calls;
415         jj = j + msg->u.s.epoints;
416         while(j < jj)
417         {
418                 if (m[j].u.e.call == call)
419                 {
420                         i--;
421                         move(++line>1?line:1, 1);
422                         color(cyan);
423                         if (i)
424                                 LTEE
425                         else
426                                 LLCORNER
427                         move(line>1?line:1, 4);
428                         if (line+2 >= LINES) break;
429                         line = debug_epoint(msg, m, line, j, i?1:0);
430                         if (line+2 >= LINES) break;
431                 }
432                 j++;
433         }
434
435         return(line);
436 }
437 char *admin_state(int sock)
438 {
439         struct admin_message    msg,
440                                 *m;
441         char                    buffer[256],
442                                 *p;
443         int                     line, offset = 0;
444         int                     i, ii, j, jj, k;
445         unsigned long           l, ll;
446         int                     num;
447         int                     len;
448         int                     off;
449         int                     ltee;
450         int                     anything;
451
452         /* flush logfile name */
453         logfile[0] = '\0';
454
455         /* init curses */
456         init_curses();
457
458         again:
459         /* send reload command */
460         memset(&msg, 0, sizeof(msg));
461         msg.message = ADMIN_REQUEST_STATE;
462 //      printf("sizeof=%d\n",sizeof(msg));
463         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
464         {
465                 cleanup_curses();
466                 return("Broken pipe while sending command.");
467         }
468
469         /* receive response */
470         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
471         {
472                 cleanup_curses();
473                 return("Broken pipe while receiving response.");
474         }
475         if (msg.message != ADMIN_RESPONSE_STATE)
476         {
477                 cleanup_curses();
478                 return("Response not valid. Expecting state response.");
479         }
480         num = msg.u.s.interfaces + msg.u.s.calls + msg.u.s.epoints + msg.u.s.ports;
481         if (!(m = (struct admin_message *)malloc(num*sizeof(struct admin_message))))
482         {
483                 cleanup_curses();
484                 return("Not enough memory for messages.");
485         }
486         off=0;
487 readagain:
488         if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off)
489         {
490                 if (len <= 0) {
491                         free(m);
492 //                      fprintf(stderr, "got=%d expected=%d\n", i, num*sizeof(struct admin_message));
493                         cleanup_curses();
494                         return("Broken pipe while receiving state infos.");
495                 }
496                 if (len < num*(int)sizeof(struct admin_message))
497                 {
498                         off+=len;
499                         goto readagain;
500                 }
501         }
502         j = 0;
503         i = 0;
504 //      fprintf("getting =%d interfaces\n", msg.u.s.interfaces);
505         while(i < msg.u.s.interfaces)
506         {
507 //              fprintf(stderr, "j=%d message=%d\n", j, m[j].message);
508                 if (m[j].message != ADMIN_RESPONSE_S_INTERFACE)
509                 {
510                         free(m);
511                         cleanup_curses();
512                         return("Response not valid. Expecting interface information.");
513                 }
514                 i++;
515                 j++;
516         }
517         i = 0;
518         while(i < msg.u.s.calls)
519         {
520                 if (m[j].message != ADMIN_RESPONSE_S_CALL)
521                 {
522                         free(m);
523                         cleanup_curses();
524                         return("Response not valid. Expecting call information.");
525                 }
526                 i++;
527                 j++;
528         }
529         i = 0;
530         while(i < msg.u.s.epoints)
531         {
532                 if (m[j].message != ADMIN_RESPONSE_S_EPOINT)
533                 {
534                         free(m);
535                         cleanup_curses();
536                         return("Response not valid. Expecting endpoint information.");
537                 }
538                 i++;
539                 j++;
540         }
541         i = 0;
542         while(i < msg.u.s.ports)
543         {
544                 if (m[j].message != ADMIN_RESPONSE_S_PORT)
545                 {
546                         free(m);
547                         cleanup_curses();
548                         return("Response not valid. Expecting port information.");
549                 }
550                 i++;
551                 j++;
552         }
553         // now j is the number of message blocks
554
555         /* display start */
556         erase();
557
558         line = 1-offset; 
559
560         /* change log */
561         if (!!strcmp(logfile, msg.u.s.logfile))
562         {
563                 SCPY(logfile, msg.u.s.logfile);
564                 if (logfh >= 0)
565                         close(logfh);
566                 i = 0;
567                 ii = LOGLINES;
568                 while(i < ii)
569                 {
570                         logline[i][0] = '~';
571                         logline[i][1] = '\0';
572                         i++;
573                 }
574                 logcur = 0;
575                 logfh = open(logfile, O_RDONLY|O_NONBLOCK);
576                 if (logfh >= 0)
577                 {
578                         /* seek at the end -8000 chars */
579                         lseek(logfh, -8000, SEEK_END);
580                         /* if not at the beginning, read until endofline */
581                         logline[logcur % LOGLINES][0] = '\0';
582                         l = read(logfh, logline[logcur % LOGLINES], sizeof(logline[logcur % LOGLINES])-1);
583                         if (l > 0)
584                         {
585                                 /* read first line and skip junk */
586                                 logline[logcur % LOGLINES][l] = '\0';
587                                 if ((p = strchr(logline[logcur % LOGLINES],'\n')))
588                                 {
589                                         logcur++;
590                                         SCPY(logline[logcur % LOGLINES], p+1);
591                                         SCPY(logline[(logcur-1) % LOGLINES], "...");
592                                 }
593                                 goto finish_line;
594                         }
595                 }
596         }
597
598         /* read log */
599         if (logfh >= 0)
600         {
601                 while(42)
602                 {
603                         ll = strlen(logline[logcur % LOGLINES]);
604                         l = read(logfh, logline[logcur % LOGLINES]+ll, sizeof(logline[logcur % LOGLINES])-ll-1);
605                         if (l<=0)
606                                 break;
607                         logline[logcur % LOGLINES][ll+l] = '\0';
608                         finish_line:
609                         /* put data to lines */
610                         while ((p = strchr(logline[logcur % LOGLINES],'\n')))
611                         {
612                                 *p = '\0';
613                                 logcur++;
614                                 SCPY(logline[logcur % LOGLINES], p+1);
615                         }
616                         /* if line is full without return, go next line */
617                         if (strlen(logline[logcur % LOGLINES]) == sizeof(logline[logcur % LOGLINES])-1)
618                         {
619                                 logcur++;
620                                 logline[logcur % LOGLINES][0] = '\0';
621                         }
622                 }
623         }
624
625         /* display interfaces */
626         if (show_interfaces > 0)
627         {
628                 anything = 0;
629                 i = 0;
630                 ii = i + msg.u.s.interfaces;
631                 while(i < ii)
632                 {
633                         /* show interface summary */
634                         move(++line>1?line:1, 0);
635                         color(white);
636
637                         SPRINT(buffer, "%s(%d) '%s' %s use:%d ", (m[i].u.i.ntmode)?"NT":"TE", m[i].u.i.portnum, m[i].u.i.interface_name, (m[i].u.i.ptp)?"ptp ":"ptmp", m[i].u.i.use);
638                         addstr(buffer);
639                         if (m[i].u.i.ptp || !m[i].u.i.ntmode)
640                         {
641                                 color((m[i].u.i.l2link)?green:red);
642                                 addstr((m[i].u.i.l2link)?"  L2 UP":"  L2 down");
643                         }
644                         color((m[i].u.i.l1link)?green:blue);
645                         addstr((m[i].u.i.l1link)?"  L1 ACTIVE":"  L1 inactive");
646                         if (line+2 >= LINES) goto end;
647                         /* show channels */
648                         if (show_interfaces > 1)
649                         {
650                                 ltee = 0;
651                                 j = k =0;
652                                 jj = m[i].u.i.channels;
653                                 while(j < jj)
654                                 {
655                                         /* show all channels */
656                                         if (show_interfaces>2 || m[i].u.i.busy[j]>0)
657                                         {
658                                                 color(cyan);
659                                                 /* show left side / right side */
660                                                 if ((k & 1) && (COLS > 70))
661                                                 {
662                                                         move(line>1?line:1,4+((COLS-4)/2));
663                                                 } else
664                                                 {
665                                                         move(++line>1?line:1, 1);
666                                                         LTEE
667                                                         ltee = 1;
668                                                 }
669                                                 k++;
670                                                 color(white);
671                                                 if (m[i].u.i.pri)
672                                                         SPRINT(buffer,"S%2d: ", j+1+(j>=15));
673                                                 else
674                                                         SPRINT(buffer,"B%2d: ", j+1);
675                                                 addstr(buffer);
676                                                 if (!m[i].u.i.ptp)
677                                                         goto ptmp;
678                                                 if (m[i].u.i.l2link)
679                                                 {
680                                                         ptmp:
681                                                         color((m[i].u.i.busy[j])?yellow:blue);
682                                                         addstr((m[i].u.i.busy[j])?"busy":"idle");
683                                                 } else
684                                                 {
685                                                         color(red);
686                                                         addstr("blk ");
687                                                 }
688                                                 if (m[i].u.i.port[j])
689                                                 {
690                                                         /* search for port */
691                                                         l = msg.u.s.interfaces+msg.u.s.calls+msg.u.s.epoints;
692                                                         ll = l+msg.u.s.ports;
693                                                         while(l < ll)
694                                                         {
695                                                                 if (m[l].u.p.serial == m[i].u.i.port[j])
696                                                                 {
697                                                                         SPRINT(buffer, " %s(%ld)", m[l].u.p.name, m[l].u.p.serial);
698                                                                         addstr(buffer);
699                                                                 }
700                                                                 l++;
701                                                         }
702                                                 }
703                                                 if (line+2 >= LINES)
704                                                 {
705                                                         if (ltee)
706                                                         {
707                                                                 color(cyan);
708                                                                 move(line>1?line:1, 1);
709                                                                 LLCORNER
710                                                         }
711                                                         goto end;
712                                                 }
713                                         }
714                                         j++;
715                                 }
716                                 if (ltee)
717                                 {
718                                         color(cyan);
719                                         move(line>1?line:1, 1);
720                                         LLCORNER
721                                 }
722                                 if (line+2 >= LINES) goto end;
723                                 /* show summary if no channels were shown */
724                                 if (show_interfaces<2 && ltee==0)
725                                 {
726                                         color(cyan);
727                                         move(++line>1?line:1, 1);
728                                         LLCORNER
729                                                 
730                                         if (m[i].u.i.l2link)
731                                         {
732                                                 color(green);
733                                                 SPRINT(buffer,"all %d channels free", m[i].u.i.channels);
734                                         } else
735                                         {
736                                                 color(red);
737                                                 SPRINT(buffer,"all %d channels blocked", m[i].u.i.channels);
738                                         }
739                                         addstr(buffer);
740                                 }
741                                 if (line+2 >= LINES) goto end;
742                         }
743                         i++;
744                         anything = 1;
745                 }
746                 if (anything)
747                         line++;
748                 if (line+2 >= LINES) goto end;
749         }               
750         /* display calls (brief) */
751         if (show_calls == 1)
752         {
753                 anything = 0;
754                 i = msg.u.s.interfaces+msg.u.s.calls;
755                 ii = i+msg.u.s.epoints;
756                 while(i < ii)
757                 {
758                         /* for each endpoint... */
759                         if (!m[i].u.e.call)
760                         {
761                                 move(++line>1?line:1, 0);
762                                 color(white);
763                                 SPRINT(buffer, "(%d): ", m[i].u.e.serial);
764                                 addstr(buffer);
765                                 color(cyan);
766                                 if (m[i].u.e.terminal[0])
767                                 {
768                                         addstr("intern=");
769                                         color(green);
770                                         addstr(m[i].u.e.terminal);
771                                 } else
772                                         addstr("extern");
773                                 color(white);
774                                 SPRINT(buffer, " %s", m[i].u.e.callerid);
775                                 addstr(buffer);
776                                 color(cyan);
777                                 addstr("->");
778                                 color(white);
779                                 SPRINT(buffer, "%s", m[i].u.e.dialing);
780                                 addstr(buffer);
781                                 if (m[i].u.e.action[0])
782                                 {
783                                         color(cyan);
784                                         addstr(" action=");
785                                         color(yellow);
786                                         addstr(m[i].u.e.action);
787                                 }
788                                 if (line+2 >= LINES) goto end;
789                         }
790                         i++;
791                         anything = 1;
792                 }
793                 j = msg.u.s.interfaces;
794                 jj = j+msg.u.s.calls;
795                 while(j < jj)
796                 {
797                         /* for each call... */
798                         move(++line>1?line:1, 0);
799                         color(white);
800                         SPRINT(buffer, "(%d):", m[j].u.c.serial);
801                         addstr(buffer);
802                         i = msg.u.s.interfaces+msg.u.s.calls;
803                         ii = i+msg.u.s.epoints;
804                         while(i < ii)
805                         {
806                                 /* for each endpoint... */
807                                 if (m[i].u.e.call == m[j].u.c.serial)
808                                 {
809                                         color(white);
810                                         SPRINT(buffer, " (%d)", m[i].u.e.serial);
811                                         addstr(buffer);
812                                         color(cyan);
813                                         if (m[i].u.e.terminal[0])
814                                         {
815                                                 addstr("int=");
816                                                 color(green);
817                                                 addstr(m[i].u.e.terminal);
818                                         } else
819                                                 addstr("ext");
820                                         color(white);
821                                         SPRINT(buffer, "-%s", m[i].u.e.callerid);
822                                         addstr(buffer);
823                                         color(cyan);
824                                         addstr(">");
825                                         color(white);
826                                         SPRINT(buffer, "%s", m[i].u.e.dialing);
827                                         addstr(buffer);
828                                 }
829                                 i++;
830                                 anything = 1;
831                         }
832                         if (line+2 >= LINES) goto end;
833                         j++;
834                 }
835                 if (anything)
836                         line++;
837                 if (line+2 >= LINES) goto end;
838         }
839         /* display calls (structurd) */
840         if (show_calls == 2)
841         {
842                 /* show all ports with no epoint */
843                 anything = 0;
844                 i = msg.u.s.interfaces+msg.u.s.calls+msg.u.s.epoints;
845                 ii = i+msg.u.s.ports;
846                 while(i < ii)
847                 {
848                         if (!m[i].u.p.epoint)
849                         {
850                                 move(++line>1?line:1, 8);
851                                 if (line+2 >= LINES) goto end;
852                                 line = debug_port(&msg, m, line, i, 0);
853                                 if (line+2 >= LINES) goto end;
854                                 anything = 1;
855                         }
856                         i++;
857                 }
858                 if (anything)
859                         line++;
860                 if (line+2 >= LINES) goto end;
861
862                 /* show all epoints with no call */
863                 anything = 0;
864                 i = msg.u.s.interfaces+msg.u.s.calls;
865                 ii = i+msg.u.s.epoints;
866                 while(i < ii)
867                 {
868                         if (!m[i].u.e.call)
869                         {
870                                 move(++line>1?line:1, 4);
871                                 if (line+2 >= LINES) goto end;
872                                 line = debug_epoint(&msg, m, line, i, 0);
873                                 if (line+2 >= LINES) goto end;
874                                 anything = 1;
875                         }
876                         i++;
877                 }
878                 if (anything)
879                         line++;
880                 if (line+2 >= LINES) goto end;
881
882                 /* show all calls */
883                 anything = 0;
884                 i = msg.u.s.interfaces;
885                 ii = i+msg.u.s.calls;
886                 while(i < ii)
887                 {
888                         move(++line>1?line:1, 0);
889                         if (line+2 >= LINES) goto end;
890                         line = debug_call(&msg, m, line, i);
891                         if (line+2 >= LINES) goto end;
892                         i++;
893                         anything = 1;
894                 }
895                 if (anything)
896                         line++;
897                 if (line+2 >= LINES) goto end;
898
899         }
900
901         /* show log */
902         if (show_log)
903         {
904                 if (line+2 < LINES)
905                 {
906                         move(line++>1?line-1:1, 0);
907                         color(blue);
908                         hline(/*ACS_HLINE*/'q', COLS);
909                         color(white);
910                         
911                         l = logcur-(LINES-line-2);
912                         ll = logcur;
913                         if (ll-l >= LOGLINES)
914                                 l = ll-LOGLINES+1;
915                         while(l!=ll)
916                         {
917                                 move(line++>1?line-1:1, 0);
918                                 SCPY(buffer, logline[l % LOGLINES]);
919                                 if (COLS < (int)sizeof(buffer))
920                                         buffer[COLS] = '\0';
921                                 addstr(buffer);
922                                 l++;
923                         }
924                 }
925         }
926
927         end:
928         /* free memory */
929         free(m);
930         /* display name/time */
931 //      move(0, 0);
932 //      hline(' ', COLS);
933         move(0, 0);
934         color(white);
935         msg.u.s.version_string[sizeof(msg.u.s.version_string)-1] = '\0';
936         SPRINT(buffer, "PBX4Linux %s", msg.u.s.version_string);
937         addstr(buffer);
938         if (COLS>50)
939         {
940                 move(0, COLS-19);
941                 SPRINT(buffer, "%04d-%02d-%02d %02d:%02d:%02d",
942                         msg.u.s.tm.tm_year+1900, msg.u.s.tm.tm_mon+1, msg.u.s.tm.tm_mday,
943                         msg.u.s.tm.tm_hour, msg.u.s.tm.tm_min, msg.u.s.tm.tm_sec);
944                 addstr(buffer);
945         }
946         /* displeay head line */
947         move(1, 0);
948         color(blue);
949         hline(/*ACS_HLINE*/'q', COLS);
950         if (offset)
951         {
952                 move(1, 1);
953                 SPRINT(buffer, "Offset +%d", offset);
954                 color(red);
955                 addstr(buffer);
956         }
957         /* display end */
958         move(LINES-2, 0);
959         color(white);
960         hline(/*ACS_HLINE*/'q', COLS);
961         move(LINES-1, 0);
962         color(white);
963         SPRINT(buffer, "i = interfaces '%s'  c = calls '%s'  l = log  q = quit  +/- = scroll", text_interfaces[show_interfaces], text_calls[show_calls]);
964         addstr(buffer);
965         refresh();
966
967         /* resize */
968         if (lastlines!=LINES || lastcols!=COLS)
969         {
970                 cleanup_curses();
971                 init_curses();
972                 goto again;
973         }
974
975         /* user input */
976         switch(getch())
977         {
978                 case 12: /* refresh */
979                 cleanup_curses();
980                 init_curses();
981                 goto again;
982                 break;
983
984                 case 3: /* abort */
985                 case 'q':
986                 case 'Q':
987                 break;
988
989                 case 'i': /* toggle interface */
990                 show_interfaces++;
991                 if (show_interfaces > 3) show_interfaces = 0;
992                 goto again;
993
994                 case 'c': /* toggle calls */
995                 show_calls++;
996                 if (show_calls > 2) show_calls = 0;
997                 goto again;
998
999                 case 'l': /* toggle log */
1000                 show_log++;
1001                 if (show_log > 1) show_log = 0;
1002                 goto again;
1003
1004                 case '+': /* scroll down */
1005                 offset++;
1006                 goto again;
1007                 
1008                 case '-': /* scroll up */
1009                 if (offset)
1010                         offset--;
1011                 goto again;
1012
1013                 default:
1014                 usleep(250000);
1015                 goto again;
1016         }
1017
1018         /* check for logfh */
1019         if (logfh >= 0)
1020                 close(logfh);
1021         logfh = -1;
1022
1023         /* cleanup curses and exit */
1024         cleanup_curses();
1025
1026         return(NULL);
1027 }
1028
1029
1030 /*
1031  * Send command and show error message.
1032  */
1033 char *admin_cmd(int sock, int mode, char *extension, char *number)
1034 {
1035         static struct admin_message msg;
1036
1037         /* send reload command */
1038         memset(&msg, 0, sizeof(msg));
1039         switch(mode)
1040         {
1041                 case MODE_INTERFACE:
1042                 msg.message = ADMIN_REQUEST_CMD_INTERFACE;
1043                 break;
1044                 case MODE_ROUTE:
1045                 msg.message = ADMIN_REQUEST_CMD_ROUTE;
1046                 break;
1047                 case MODE_DIAL:
1048                 msg.message = ADMIN_REQUEST_CMD_DIAL;
1049                 SPRINT(msg.u.x.message, "%s:%s", extension?:"", number?:"");
1050                 break;
1051                 case MODE_RELEASE:
1052                 msg.message = ADMIN_REQUEST_CMD_RELEASE;
1053                 SCPY(msg.u.x.message, number);
1054                 break;
1055         }
1056
1057         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1058                 return("Broken pipe while sending command.");
1059
1060         /* receive response */
1061         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
1062                 return("Broken pipe while receiving response.");
1063         switch(mode)
1064         {
1065                 case MODE_INTERFACE:
1066                 if (msg.message != ADMIN_RESPONSE_CMD_INTERFACE)
1067                         return("Response not valid.");
1068                 break;
1069                 case MODE_ROUTE:
1070                 if (msg.message != ADMIN_RESPONSE_CMD_ROUTE)
1071                         return("Response not valid.");
1072                 break;
1073                 case MODE_DIAL:
1074                 if (msg.message != ADMIN_RESPONSE_CMD_DIAL)
1075                         return("Response not valid.");
1076                 break;
1077                 case MODE_RELEASE:
1078                 if (msg.message != ADMIN_RESPONSE_CMD_RELEASE)
1079                         return("Response not valid.");
1080                 break;
1081         }
1082
1083         /* process response */
1084         if (msg.u.x.error)
1085         {
1086                 return(msg.u.x.message);
1087         }
1088         printf("Command successfull.\n");
1089         return(NULL);
1090 }
1091
1092
1093 /*
1094  * makes a testcall
1095  */
1096 char *admin_testcall(int sock, int argc, char *argv[])
1097 {
1098         static struct admin_message msg;
1099
1100         printf("pid=%d\n", getpid()); fflush(stdout);
1101
1102         /* send reload command */
1103         memset(&msg, 0, sizeof(msg));
1104         msg.message = ADMIN_CALL_SETUP;
1105         if (argc > 2)
1106         {
1107                 SCPY(msg.u.call.interface, argv[2]);
1108         }
1109         if (argc > 3)
1110         {
1111                 SCPY(msg.u.call.callerid, argv[3]);
1112         }
1113         if (argc > 4)
1114         {
1115                 SCPY(msg.u.call.dialing, argv[4]);
1116         }
1117         if (argc > 5)
1118         {
1119                 if (argv[5][0] == 'p')
1120                         msg.u.call.present = 1;
1121         }
1122         msg.u.call.bc_capa = 0x00; /*INFO_BC_SPEECH*/
1123         msg.u.call.bc_mode = 0x00; /*INFO_BMODE_CIRCUIT*/
1124         msg.u.call.bc_info1 = 0;
1125         msg.u.call.hlc = 0;
1126         msg.u.call.exthlc = 0;
1127         if (argc > 6)
1128                 msg.u.call.bc_capa = strtol(argv[6],NULL,0);
1129         else
1130                 msg.u.call.bc_info1 = 3 | 0x80; /* alaw, if no capability is given at all */
1131         if (argc > 7) {
1132                 msg.u.call.bc_mode = strtol(argv[7],NULL,0);
1133                 if (msg.u.call.bc_mode) msg.u.call.bc_mode = 2;
1134         }
1135         if (argc > 8) {
1136                 msg.u.call.bc_info1 = strtol(argv[8],NULL,0);
1137                 if (msg.u.call.bc_info1 < 0)
1138                         msg.u.call.bc_info1 = 0;
1139                 else
1140                         msg.u.call.bc_info1 |= 0x80;
1141         }
1142         if (argc > 9) {
1143                 msg.u.call.hlc = strtol(argv[9],NULL,0);
1144                 if (msg.u.call.hlc < 0)
1145                         msg.u.call.hlc = 0;
1146                 else
1147                         msg.u.call.hlc |= 0x80;
1148         }
1149 //              printf("hlc=%d\n",  msg.u.call.hlc);
1150         if (argc > 10) {
1151                 msg.u.call.exthlc = strtol(argv[10],NULL,0);
1152                 if (msg.u.call.exthlc < 0)
1153                         msg.u.call.exthlc = 0;
1154                 else
1155                         msg.u.call.exthlc |= 0x80;
1156         }
1157
1158         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1159                 return("Broken pipe while sending command.");
1160
1161         /* receive response */
1162 next:
1163         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
1164                 return("Broken pipe while receiving response.");
1165         switch(msg.message)
1166         {
1167                 case ADMIN_CALL_SETUP_ACK:
1168                 printf("SETUP ACKNOWLEDGE\n"); fflush(stdout);
1169                 goto next;
1170
1171                 case ADMIN_CALL_PROCEEDING:
1172                 printf("PROCEEDING\n"); fflush(stdout);
1173                 goto next;
1174
1175                 case ADMIN_CALL_ALERTING:
1176                 printf("ALERTING\n"); fflush(stdout);
1177                 goto next;
1178
1179                 case ADMIN_CALL_CONNECT:
1180                 printf("CONNECT\n number=%s\n", msg.u.call.callerid); fflush(stdout);
1181                 goto next;
1182
1183                 case ADMIN_CALL_NOTIFY:
1184                 printf("NOTIFY\n notify=%d\n number=%s\n", msg.u.call.notify, msg.u.call.callerid); fflush(stdout);
1185                 goto next;
1186
1187                 case ADMIN_CALL_DISCONNECT:
1188                 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);
1189                 goto next;
1190
1191                 case ADMIN_CALL_RELEASE:
1192                 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);
1193                 break;
1194
1195                 default:
1196                 return("Response not valid.");
1197         }
1198         
1199         printf("Command successfull.\n");
1200         return(NULL);
1201 }
1202
1203
1204 /*
1205  * makes a trace
1206  */
1207 char *admin_trace(int sock, int argc, char *argv[])
1208 {
1209         static struct admin_message msg;
1210         int i;
1211
1212         /* show help */
1213         if (!strcasecmp(argv[2], "help"))
1214         {
1215                 printf("Trace Help\n----------\n");
1216                 printf("%s trace [brief|short] [<filter>=<value> [...]]\n\n", argv[0]);
1217                 printf("By default a complete trace is shown in detailed format.\n");
1218                 printf("To show a more compact format, use 'brief' or 'short' keyword.\n");
1219                 printf("Use filter values to select specific trace messages.\n");
1220                 printf("All given filter values must match. If no filter is given, anything matches.\n\n");
1221                 printf("Filters:\n");
1222                 printf(" category=<mask bits>\n");
1223                 printf("  0x01 = CH: channel object trace\n");
1224                 printf("  0x02 = EP: endpoint object trace\n");
1225                 printf(" port=<mISDN port>  select only given port for trace\n");
1226                 printf(" interface=<interface name>  select only given interface for trace\n");
1227                 printf(" caller=<caller id>  select only given caller id for trace\n");
1228                 printf(" dialing=<number>  select only given dialed number for trace\n");
1229                 return(NULL);
1230         }
1231
1232         /* init trace request */        
1233         memset(&msg, 0, sizeof(msg));
1234         msg.message = ADMIN_TRACE_REQUEST;
1235         msg.u.trace_req.detail = 3;
1236
1237         /* parse args */
1238         i = 2;
1239         while(i < argc)
1240         {
1241                 if (!strcasecmp(argv[i], "brief"))
1242                         msg.u.trace_req.detail = 1;
1243                 else if (!strcasecmp(argv[i], "short"))
1244                         msg.u.trace_req.detail = 2;
1245                 else if (!strncasecmp(argv[i], "category=", 9))
1246                         SCPY(msg.u.trace_req.category, argv[i]+9);
1247                 else if (!strncasecmp(argv[i], "port=", 5))
1248                         msg.u.trace_req.port = atoi(argv[i]+5);
1249                 else if (!strncasecmp(argv[i], "interface=", 10))
1250                         SCPY(msg.u.trace_req.interface, argv[i]+10);
1251                 else if (!strncasecmp(argv[i], "caller=", 7))
1252                         SCPY(msg.u.trace_req.caller, argv[i]+7);
1253                 else if (!strncasecmp(argv[i], "dialing=", 8))
1254                         SCPY(msg.u.trace_req.dialing, argv[i]+8);
1255                 else return("Invalid trace option, try 'trace help'.");
1256
1257                 i++;
1258         }
1259
1260         /* send trace request */
1261         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
1262                 return("Broken pipe while sending trace request.");
1263
1264         /* receive response */
1265 next:
1266         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
1267                 return("Broken pipe while receiving response.");
1268
1269         if (msg.message != ADMIN_TRACE_RESPONSE)
1270                 return("Response not valid.");
1271
1272         printf("%s", msg.u.trace_rsp.text);
1273         goto next;
1274 }
1275
1276
1277 /*
1278  * main function
1279  */
1280 int main(int argc, char *argv[])
1281 {
1282         int mode;
1283         char *socket_name = SOCKET_NAME;
1284         int sock, conn;
1285         struct sockaddr_un sock_address;
1286         char *ret;
1287
1288
1289         /* show options */
1290         if (argc <= 1)
1291         {
1292                 usage:
1293                 printf("\n");
1294                 printf("Usage: %s state | interface | route | dial ...\n", argv[0]);
1295                 printf("state - View current states using graphical console output.\n");
1296                 printf("interface - Tell PBX to reload \"interface.conf\".\n");
1297                 printf("route - Tell PBX to reload \"route.conf\".\n");
1298                 printf("dial <extension> <number> - Tell PBX the next number to dial for extension.\n");
1299                 printf("release <number> - Tell PBX to release endpoint with given number.\n");
1300                 printf("testcall <interface> <callerid> <number> [present|restrict [<capability>]] - Testcall\n");
1301                 printf(" -> capability = <bc> <mode> <codec> <hlc> <exthlc> (Values must be numbers, -1 to omit.)\n");
1302                 printf("trace [brief|short] [<filter> [...]] - Shows call trace. Use filter to reduce output.\n");
1303                 printf(" -> Use 'trace help' to see filter description.\n");
1304                 printf("\n");
1305                 return(0);
1306         }
1307
1308         /* check mode */
1309         if (!(strcasecmp(argv[1],"state")))
1310         {
1311                 mode = MODE_STATE;
1312         } else
1313         if (!(strcasecmp(argv[1],"interface")))
1314         {
1315                 mode = MODE_INTERFACE;
1316         } else
1317         if (!(strcasecmp(argv[1],"route")))
1318         {
1319                 mode = MODE_ROUTE;
1320         } else
1321         if (!(strcasecmp(argv[1],"dial")))
1322         {
1323                 if (argc <= 3)
1324                         goto usage;
1325                 mode = MODE_DIAL;
1326         } else
1327         if (!(strcasecmp(argv[1],"release")))
1328         {
1329                 if (argc <= 2)
1330                         goto usage;
1331                 mode = MODE_RELEASE;
1332         } else
1333         if (!(strcasecmp(argv[1],"testcall")))
1334         {
1335                 if (argc <= 4)
1336                         goto usage;
1337                 mode = MODE_TESTCALL;
1338         } else
1339         if (!(strcasecmp(argv[1],"trace")))
1340         {
1341                 mode = MODE_TRACE;
1342         } else
1343         {
1344                 goto usage;
1345         }
1346
1347 //pipeagain:
1348         /* open socket */
1349         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1350         {
1351                 fprintf(stderr, "Failed to create socket.\n");
1352                 exit(EXIT_FAILURE);
1353         }
1354         memset(&sock_address, 0, sizeof(sock_address));
1355         sock_address.sun_family = PF_UNIX;
1356         UCPY(sock_address.sun_path, socket_name);
1357         if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
1358         {
1359                 close(sock);
1360                 fprintf(stderr, "Failed to connect to socket \"%s\".\nIs PBX4Linux running?\n", sock_address.sun_path);
1361                 exit(EXIT_FAILURE);
1362         }
1363
1364         /* process mode */
1365         switch(mode)
1366         {
1367                 case MODE_STATE:
1368                 ret = admin_state(sock);
1369                 break;
1370         
1371                 case MODE_INTERFACE:
1372                 case MODE_ROUTE:
1373                 ret = admin_cmd(sock, mode, NULL, NULL);
1374                 break;
1375
1376                 case MODE_DIAL:
1377                 ret = admin_cmd(sock, mode, argv[2], argv[3]);
1378                 break;
1379
1380                 case MODE_RELEASE:
1381                 ret = admin_cmd(sock, mode, NULL, argv[2]);
1382                 break;
1383
1384                 case MODE_TESTCALL:
1385                 ret = admin_testcall(sock, argc, argv);
1386
1387                 case MODE_TRACE:
1388                 ret = admin_trace(sock, argc, argv);
1389         }
1390
1391         close(sock);
1392         /* now we say good bye */
1393         if (ret)
1394         {
1395 //              if (!strncasecmp(ret, "Broken Pipe", 11))
1396 //                      goto pipeagain;
1397                 printf("%s\n", ret);
1398                 exit(EXIT_FAILURE);
1399         }
1400 }
1401
1402
1403
1404
1405