only for backup, still in coding state - no compile!!!
[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);addch(ACS_HLINE);addch(ACS_HLINE);}
30 #define LLCORNER {addch(ACS_LLCORNER);addch(ACS_HLINE);addch(ACS_HLINE);}
31 #define VLINE {addch(ACS_VLINE);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 };
47
48 char *text_interfaces[] = {
49         "off",
50         "brief",
51         "active channels",
52         "all channels",
53 };
54
55 char *text_calls[] = {
56         "off",
57         "brief",
58         "structured",
59 };
60
61 char    red = 1,
62         green = 2,
63         yellow = 3,
64         blue = 4,
65         mangenta = 5,
66         cyan = 6,
67         white = 7;
68
69 #define LOGLINES 128
70 char logline[LOGLINES][256];
71 unsigned long logcur = 0;
72 int logfh = -1;
73 char logfile[128];
74
75 /*
76  * curses
77  */
78 void init_curses(void)
79 {
80         /* init curses */
81         initscr(); cbreak(); noecho();
82         start_color();
83         nodelay(stdscr, TRUE);
84         if (COLOR_PAIRS>=8 && COLORS>=8)
85         {
86                 init_pair(1,1,0);
87                 init_pair(2,2,0);
88                 init_pair(3,3,0);
89                 init_pair(4,4,0);
90                 init_pair(5,5,0);
91                 init_pair(6,6,0);
92                 init_pair(7,7,0);
93         }
94         lastlines = LINES;
95         lastcols = COLS;
96 }
97
98 void cleanup_curses(void)
99 {
100         endwin();
101 }
102
103 void color(int color)
104 {
105         if (COLOR_PAIRS>=8 && COLORS>=8)
106                 attrset(COLOR_PAIR(color));
107 }
108
109 /*
110  * permanently show current state using ncurses
111  */
112 int debug_port(struct admin_message *msg, struct admin_message *m, int line, int i, int vline)
113 {
114         char buffer[256];
115
116         color(white);
117         addstr("PORT:");
118         color(yellow);
119         SPRINT(buffer,"%s(%d)", m[i].u.p.name,m[i].u.p.serial);
120         addstr(buffer);
121         color(cyan);
122         addstr(" state=");
123         switch (m[i].u.p.state)
124         {
125                 case ADMIN_STATE_IDLE:
126                 color(red);
127                 addstr("'idle'");
128                 break;
129                 case ADMIN_STATE_IN_SETUP:
130                 color(red);
131                 addstr("'in << setup'");
132                 break;
133                 case ADMIN_STATE_OUT_SETUP:
134                 color(red);
135                 addstr("'out >> setup'");
136                 break;
137                 case ADMIN_STATE_IN_OVERLAP:
138                 color(yellow);
139                 addstr("'in << overlap'");
140                 break;
141                 case ADMIN_STATE_OUT_OVERLAP:
142                 color(yellow);
143                 addstr("'out >> overlap'");
144                 break;
145                 case ADMIN_STATE_IN_PROCEEDING:
146                 color(mangenta);
147                 addstr("'in << proc'");
148                 break;
149                 case ADMIN_STATE_OUT_PROCEEDING:
150                 color(mangenta);
151                 addstr("'out >> proc'");
152                 break;
153                 case ADMIN_STATE_IN_ALERTING:
154                 color(cyan);
155                 addstr("'in << alert'");
156                 break;
157                 case ADMIN_STATE_OUT_ALERTING:
158                 color(cyan);
159                 addstr("'out >> alert'");
160                 break;
161                 case ADMIN_STATE_CONNECT:
162                 color(white);
163                 addstr("'connect'");
164                 break;
165                 case ADMIN_STATE_IN_DISCONNECT:
166                 color(blue);
167                 addstr("'in  << disc'");
168                 break;
169                 case ADMIN_STATE_OUT_DISCONNECT:
170                 color(blue);
171                 addstr("'out >> disc'");
172                 break;
173                 default:
174                 color(blue);
175                 addstr("'--NONE--'");
176         }
177
178         if (m[i].u.p.isdn)
179         {       
180                 color(cyan);
181                 addstr(" bchannel=");
182                 color(white);
183                 SPRINT(buffer,"%d", m[i].u.p.isdn_chan);
184                 addstr(buffer);
185                 if (m[i].u.p.isdn_ces >= 0)
186                 {
187                         color(cyan);
188                         addstr(" ces=");
189                         color(yellow);
190                         SPRINT(buffer, "%d", m[i].u.p.isdn_ces);
191                         addstr(buffer);
192                 }
193                 if (m[i].u.p.isdn_hold)
194                 {
195                         color(red);
196                         addstr(" hold");
197                 }
198         }
199
200         return(line);
201 }
202 int debug_epoint(struct admin_message *msg, struct admin_message *m, int line, int i, int vline)
203 {
204         unsigned long epoint = m[i].u.e.serial;
205         char buffer[256];
206         unsigned char c;
207         int j, jj;
208         int ltee;
209
210         color(white);
211         SPRINT(buffer,"EPOINT(%d)", epoint);
212         addstr(buffer);
213         color(cyan);
214         addstr(" state=");
215         switch (m[i].u.e.state)
216         {
217                 case ADMIN_STATE_IDLE:
218                 color(red);
219                 addstr("'idle'");
220                 break;
221                 case ADMIN_STATE_IN_SETUP:
222                 color(red);
223                 addstr("'in << setup'");
224                 break;
225                 case ADMIN_STATE_OUT_SETUP:
226                 color(red);
227                 addstr("'out >> setup'");
228                 break;
229                 case ADMIN_STATE_IN_OVERLAP:
230                 color(yellow);
231                 addstr("'in << overlap'");
232                 break;
233                 case ADMIN_STATE_OUT_OVERLAP:
234                 color(yellow);
235                 addstr("'out >> overlap'");
236                 break;
237                 case ADMIN_STATE_IN_PROCEEDING:
238                 color(mangenta);
239                 addstr("'in << proc'");
240                 break;
241                 case ADMIN_STATE_OUT_PROCEEDING:
242                 color(mangenta);
243                 addstr("'out >> proc'");
244                 break;
245                 case ADMIN_STATE_IN_ALERTING:
246                 color(cyan);
247                 addstr("'in << alert'");
248                 break;
249                 case ADMIN_STATE_OUT_ALERTING:
250                 color(cyan);
251                 addstr("'out >> alert'");
252                 break;
253                 case ADMIN_STATE_CONNECT:
254                 color(white);
255                 addstr("'connect'");
256                 break;
257                 case ADMIN_STATE_IN_DISCONNECT:
258                 color(blue);
259                 addstr("'in  << disc'");
260                 break;
261                 case ADMIN_STATE_OUT_DISCONNECT:
262                 color(blue);
263                 addstr("'out >> disc'");
264                 break;
265                 default:
266                 color(blue);
267                 addstr("'--NONE--'");
268         }
269         if (m[i].u.e.terminal[0])
270         {
271                 color(cyan);
272                 addstr(" terminal=");
273                 color(green);
274                 addstr(m[i].u.e.terminal);
275         }
276         color(white);
277         SPRINT(buffer, " %s", m[i].u.e.callerid);
278         addstr(buffer);
279         color(cyan);
280         addstr("->");
281         color(white);
282         addstr(m[i].u.e.dialing);
283         if (m[i].u.e.action[0])
284         {
285                 color(cyan);
286                 addstr(" action=");
287                 color(yellow);
288                 addstr(m[i].u.e.action);
289         }
290         if (m[i].u.e.park)
291         {
292                 color(cyan);
293                 addstr(" park="); /* 9 digits */
294                 color(green);
295                 UCPY(buffer, "\""); /* 9 digits */
296                 j = 0;
297                 jj = m[i].u.e.park_len;
298                 while(j < jj)
299                 {
300                         c = m[i].u.e.park_callid[j];
301                         if (c >= 32 && c < 127 && c != '[')
302                         {
303                                 SCCAT(buffer, c);
304                         } else
305                                 UPRINT(buffer+strlen(buffer), "[%02x]", c);
306                         j++;
307                 }
308                 SCAT(buffer, "\"");
309                 addstr(buffer);
310         } else
311         {
312                 color(red);
313                 switch(m[i].u.e.rx_state)
314                 {
315                         case NOTIFY_STATE_SUSPEND:
316                         addstr(" in=suspend");
317                         break;
318                         case NOTIFY_STATE_HOLD:
319                         addstr(" in=hold");
320                         break;
321                         case NOTIFY_STATE_CONFERENCE:
322                         addstr(" in=conference");
323                         break;
324                 }
325                 switch(m[i].u.e.tx_state)
326                 {
327                         case NOTIFY_STATE_SUSPEND:
328                         addstr(" out=suspend");
329                         break;
330                         case NOTIFY_STATE_HOLD:
331                         addstr(" out=hold");
332                         break;
333                         case NOTIFY_STATE_CONFERENCE:
334                         addstr(" out=conference");
335                         break;
336                 }
337         }
338         if (m[i].u.e.crypt)
339         {
340                 color(cyan);
341                 addstr(" crypt=");
342                 if (m[i].u.e.crypt) /* crypt on */
343                 {
344                         color(green);
345                         addstr("active");
346                 } else
347                 {
348                         color(yellow);
349                         addstr("pending");
350                 }
351         }
352         /* loop all related ports */
353         ltee = 0;
354         j = msg->u.s.interfaces+msg->u.s.calls+msg->u.s.epoints;
355         jj = j + msg->u.s.ports;
356         while(j < jj)
357         {
358                 if (m[j].u.p.epoint == epoint)
359                 {
360                         color(cyan);
361                         move(++line>1?line:1, 1);
362                         if (vline)
363                                 VLINE
364                         else
365                                 EMPTY
366                         move(line>1?line:1, 5);
367                         LTEE
368                         ltee = line;
369                         move(line>1?line:1, 8);
370                         if (line+2 >= LINES) break;
371                         line = debug_port(msg, m, line, j, vline);
372                         if (line+2 >= LINES) break;
373                 }
374                 j++;
375         }
376         if (ltee)
377         {
378                 color(cyan);
379                 move(ltee>1?line:1, 5);
380                 LLCORNER
381         }
382
383         return(line);
384 }
385 int debug_call(struct admin_message *msg, struct admin_message *m, int line, int i)
386 {
387         unsigned long   call = m[i].u.c.serial;
388         char            buffer[256];
389         int             j, jj;
390
391         color(white);
392         SPRINT(buffer,"CALL(%d)", call);
393         addstr(buffer);
394         if (m[i].u.c.partyline)
395         {
396                 color(cyan);
397                 addstr(" partyline=");
398                 color(white);
399                 SPRINT(buffer, "%d\n", m[i].u.c.partyline);
400                 addstr(buffer);
401         }
402         /* find number of epoints */
403         j = msg->u.s.interfaces+msg->u.s.calls;
404         jj = j + msg->u.s.epoints;
405         i = 0;
406         while(j < jj)
407         {
408                 if (m[j].u.e.call == call)
409                         i++;
410                 j++;
411         }
412         /* loop all related endpoints */
413         j = msg->u.s.interfaces+msg->u.s.calls;
414         jj = j + msg->u.s.epoints;
415         while(j < jj)
416         {
417                 if (m[j].u.e.call == call)
418                 {
419                         i--;
420                         move(++line>1?line:1, 1);
421                         color(cyan);
422                         if (i)
423                                 LTEE
424                         else
425                                 LLCORNER
426                         move(line>1?line:1, 4);
427                         if (line+2 >= LINES) break;
428                         line = debug_epoint(msg, m, line, j, i?1:0);
429                         if (line+2 >= LINES) break;
430                 }
431                 j++;
432         }
433
434         return(line);
435 }
436 char *admin_state(int sock)
437 {
438         struct admin_message    msg,
439                                 *m;
440         char                    buffer[256],
441                                 *p;
442         int                     line, offset = 0;
443         int                     i, ii, j, jj, k;
444         unsigned long           l, ll;
445         int                     num;
446         int                     len;
447         int                     off;
448         int                     ltee;
449         int                     anything;
450
451         /* flush logfile name */
452         logfile[0] = '\0';
453
454         /* init curses */
455         init_curses();
456
457         again:
458         /* send reload command */
459         memset(&msg, 0, sizeof(msg));
460         msg.message = ADMIN_REQUEST_STATE;
461 //      printf("sizeof=%d\n",sizeof(msg));
462         if (write(sock, &msg, sizeof(msg)) != sizeof(msg))
463         {
464                 cleanup_curses();
465                 return("Broken pipe while sending command.");
466         }
467
468         /* receive response */
469         if (read(sock, &msg, sizeof(msg)) != sizeof(msg))
470         {
471                 cleanup_curses();
472                 return("Broken pipe while receiving response.");
473         }
474         if (msg.message != ADMIN_RESPONSE_STATE)
475         {
476                 cleanup_curses();
477                 return("Response not valid. Expecting state response.");
478         }
479         num = msg.u.s.interfaces + msg.u.s.calls + msg.u.s.epoints + msg.u.s.ports;
480         if (!(m = (struct admin_message *)malloc(num*sizeof(struct admin_message))))
481         {
482                 cleanup_curses();
483                 return("Not enough memory for messages.");
484         }
485         off=0;
486 readagain:
487         if ((len = read(sock, ((unsigned char *)(m))+off,
488                                         num*sizeof(struct admin_message)-off)) != num*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*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, 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, 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, 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  * main function
1206  */
1207 int main(int argc, char *argv[])
1208 {
1209         int mode;
1210         char *socket_name = SOCKET_NAME;
1211         int sock, conn;
1212         struct sockaddr_un sock_address;
1213         char *ret;
1214
1215
1216         /* show options */
1217         if (argc <= 1)
1218         {
1219                 usage:
1220                 printf("\n");
1221                 printf("Usage: %s state | interface | route | dial ...\n", argv[0]);
1222                 printf("state - View current states using graphical console output.\n");
1223                 printf("interface - Tell PBX to reload \"interface.conf\".\n");
1224                 printf("route - Tell PBX to reload \"route.conf\".\n");
1225                 printf("dial <extension> <number> - Tell PBX the next number to dial for extension.\n");
1226                 printf("release <number> - Tell PBX to release endpoint with given number.\n");
1227                 printf("testcall <interface> <callerid> <number> [present|restrict [<capability>]] - Testcall\n");
1228                 printf(" -> capability = <bc> <mode> <codec> <hlc> <exthlc> (Values must be numbers, -1 to omit.)\n");
1229                 printf("\n");
1230                 return(0);
1231         }
1232
1233         /* check mode */
1234         if (!(strcasecmp(argv[1],"state")))
1235         {
1236                 mode = MODE_STATE;
1237         } else
1238         if (!(strcasecmp(argv[1],"interface")))
1239         {
1240                 mode = MODE_INTERFACE;
1241         } else
1242         if (!(strcasecmp(argv[1],"route")))
1243         {
1244                 mode = MODE_ROUTE;
1245         } else
1246         if (!(strcasecmp(argv[1],"dial")))
1247         {
1248                 if (argc <= 3)
1249                         goto usage;
1250                 mode = MODE_DIAL;
1251         } else
1252         if (!(strcasecmp(argv[1],"release")))
1253         {
1254                 if (argc <= 2)
1255                         goto usage;
1256                 mode = MODE_RELEASE;
1257         } else
1258         if (!(strcasecmp(argv[1],"testcall")))
1259         {
1260                 if (argc <= 4)
1261                         goto usage;
1262                 mode = MODE_TESTCALL;
1263         } else
1264         {
1265                 goto usage;
1266         }
1267
1268 //pipeagain:
1269         /* open socket */
1270         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
1271         {
1272                 fprintf(stderr, "Failed to create socket.\n");
1273                 exit(EXIT_FAILURE);
1274         }
1275         memset(&sock_address, 0, sizeof(sock_address));
1276         sock_address.sun_family = PF_UNIX;
1277         UCPY(sock_address.sun_path, socket_name);
1278         if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
1279         {
1280                 close(sock);
1281                 fprintf(stderr, "Failed to connect to socket \"%s\".\nIs PBX4Linux running?\n", sock_address.sun_path);
1282                 exit(EXIT_FAILURE);
1283         }
1284
1285         /* process mode */
1286         switch(mode)
1287         {
1288                 case MODE_STATE:
1289                 ret = admin_state(sock);
1290                 break;
1291         
1292                 case MODE_INTERFACE:
1293                 case MODE_ROUTE:
1294                 ret = admin_cmd(sock, mode, NULL, NULL);
1295                 break;
1296
1297                 case MODE_DIAL:
1298                 ret = admin_cmd(sock, mode, argv[2], argv[3]);
1299                 break;
1300
1301                 case MODE_RELEASE:
1302                 ret = admin_cmd(sock, mode, NULL, argv[2]);
1303                 break;
1304
1305                 case MODE_TESTCALL:
1306                 ret = admin_testcall(sock, argc, argv);
1307         }
1308
1309         close(sock);
1310         /* now we say good bye */
1311         if (ret)
1312         {
1313 //              if (!strncasecmp(ret, "Broken Pipe", 11))
1314 //                      goto pipeagain;
1315                 printf("%s\n", ret);
1316                 exit(EXIT_FAILURE);
1317         }
1318 }
1319
1320
1321
1322
1323