Initial import from FreeBSD RELENG_4:
[games.git] / usr.sbin / i4b / isdnmonitor / main.c
1 /*
2  *   Copyright (c) 1998,1999 Martin Husemann. All rights reserved.
3  *
4  *   Redistribution and use in source and binary forms, with or without
5  *   modification, are permitted provided that the following conditions
6  *   are met:
7  *
8  *   1. Redistributions of source code must retain the above copyright
9  *      notice, this list of conditions and the following disclaimer.
10  *   2. Redistributions in binary form must reproduce the above copyright
11  *      notice, this list of conditions and the following disclaimer in the
12  *      documentation and/or other materials provided with the distribution.
13  *   3. Neither the name of the author nor the names of any co-contributors
14  *      may be used to endorse or promote products derived from this software
15  *      without specific prior written permission.
16  *   4. Altered versions must be plainly marked as such, and must not be
17  *      misrepresented as being the original software and/or documentation.
18  *   
19  *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  *   SUCH DAMAGE.
30  *
31  *---------------------------------------------------------------------------
32  *
33  *      i4b daemon - network monitor client
34  *      -----------------------------------
35  *
36  *      $Id: main.c,v 1.35 2000/08/24 11:48:57 hm Exp $
37  *
38  * $FreeBSD: src/usr.sbin/i4b/isdnmonitor/main.c,v 1.7.2.1 2001/08/01 17:45:06 obrien Exp $
39  *
40  *      last edit-date: [Mon Dec 13 21:52:11 1999]
41  *
42  *---------------------------------------------------------------------------*/
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <string.h>
48 #include <signal.h>
49 #include <time.h>
50 #include <errno.h>
51 #ifndef WIN32
52 #include <unistd.h>
53 #include <netdb.h>
54 #endif
55 #include <sys/types.h>
56 #ifndef WIN32
57 #include <sys/socket.h>
58 #include <sys/ioctl.h>
59 #include <sys/un.h>
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #else
63 #include <stdarg.h>
64 #include <windows.h>
65 extern char     *optarg;
66 int getopt(int nargc, char * const nargv[], const char *ostr);
67 #define close(f)        closesocket(f)
68 #define sleep(s)        Sleep(s*1000)
69 #define vsnprintf       _vsnprintf
70 #define ssize_t long
71 #endif
72 #ifdef ERROR
73 #undef ERROR
74 #endif
75
76 #define MAIN
77 #include "monprivate.h"
78 #undef MAIN
79
80 #ifndef AF_LOCAL
81 #define AF_LOCAL AF_UNIX
82 #endif
83
84 #ifdef DEBUG
85 #include <ctype.h>
86 #endif
87
88 #include "monitor.h"
89
90 /*
91  * Local function prototypes
92  */
93 static int connect_local(char *sockpath);
94 static int connect_remote(char *host, int portno);
95 static void usage();
96 static void mloop();
97 static void handle_input();
98 static void print_menu();
99 static void print_logevent(time_t tstamp, int prio, char * what, char * msg);
100 static void print_charge(time_t tstamp, int controller, int channel, int units, int estimated);
101 static void print_connect(time_t tstamp, int dir, int controller, int channel, char * cfgname, char * devname, char * remphone, char * locphone);
102 static void print_disconnect(time_t tstamp, int controller, int channel);
103 static void print_updown(time_t tstamp, int contoller, int channel, int isup);
104 static void handle_event(u_int8_t *msg, int len);
105 #ifdef DEBUG
106 static void dump_event(u_int8_t *msg, int len, int readflag);
107 #endif
108
109 static ssize_t sock_read(int fd, void *buf, size_t nbytes);
110 static ssize_t sock_write(int fd, void *buf, size_t nbytes);
111
112 static void mprintf(char *fmt, ...);
113
114 /*
115  * Global variables
116  */
117 static int debug = 0;
118 #define DBG_DUMPALL     0x01
119 #define DBG_PSEND       0x02
120
121 static int monsock = -1;
122 static int state = ST_INIT;
123 static int sub_state = 0;
124 static int sub_state_count = 0;
125
126 static int isdn_major = 0;
127 static int isdn_minor = 0;
128 static u_int32_t rights = 0;
129
130 static char *logfilename = NULL;
131 static FILE *lfp = NULL;
132
133 /*---------------------------------------------------------------------------
134  *      Display usage and exit
135  *---------------------------------------------------------------------------*/
136 static void
137 usage()
138 {
139         fprintf(stderr, "\n");
140         fprintf(stderr, "isdnmonitor - version %02d.%02d.%d, %s %s (protocol %02d.%02d)\n", VERSION, REL, STEP, __DATE__, __TIME__, MPROT_VERSION, MPROT_REL);
141 #ifdef FOREIGN
142         fprintf(stderr, "  usage: isdnmonitor [-c] [-d val] [-f name] [-h host] [-p port]\n");
143 #else
144         fprintf(stderr, "  usage: isdnmonitor [-c] [-d val] [-f name] [-h host] [-l path] [-p port]\n");
145 #endif
146         fprintf(stderr, "    -c        switch to curses fullscreen output\n");        
147         fprintf(stderr, "    -d <val>  debug flags (see source ...)\n");
148         fprintf(stderr, "    -dn       no debug output on fullscreen display\n");
149         fprintf(stderr, "    -f <name> filename to log output to\n");
150         fprintf(stderr, "    -h <host> hostname/address to connect to\n");        
151 #ifndef FOREIGN
152         fprintf(stderr, "    -l <path> pathname to local domain socket to connect to\n");
153 #endif
154         fprintf(stderr, "    -p <port> portnumber to use to connect to remote host\n");
155         exit(1);
156 }
157
158 /*---------------------------------------------------------------------------
159  *      Parse command line, startup monitor client
160  *---------------------------------------------------------------------------*/
161 int main(int argc, char **argv)
162 {
163         int i;
164
165 #ifdef WIN32
166         WSADATA wsCaps;
167         WSAStartup(MAKEWORD(2, 0), &wsCaps);
168 #endif
169
170         portno = DEF_MONPORT;
171         devbuf[0] = '\0';
172
173 #ifndef FOREIGN 
174         while((i = getopt(argc, argv, "cd:f:h:p:l:")) != -1)
175 #else
176         while((i = getopt(argc, argv, "cd:f:h:p:")) != -1)
177 #endif
178         {
179                 switch(i)
180                 {
181                         case 'c':
182                                 fullscreen = 1;
183                                 break;
184                         case 'd':
185                                 if(*optarg == 'n')
186                                 {
187                                         debug_noscreen = 1;
188                                 }
189                                 else
190                                 {
191                                         if((sscanf(optarg, "%i", &debug)) != 1)
192                                                 usage();
193                                 }
194                                 break;
195                         case 'f':
196                                 logfilename = optarg;
197                                 break;
198                         case 'h':
199                                 hostname = optarg;
200                                 break;
201 #ifndef FOREIGN
202                         case 'l':
203                                 sockpath = optarg;
204                                 break;
205 #endif
206                         case 'p':
207                                 if((sscanf(optarg, "%i", &portno)) != 1)
208                                         usage();
209                                 break;
210                         default:
211                                 usage();
212                                 break;
213                 }
214         }
215
216 #ifndef FOREIGN
217         if(hostname && sockpath)
218         {
219                 fprintf(stderr, "Error: can not use local socket path on remote machine\n"
220                                 "conflicting options -h and -l!\n");
221                 return 1;
222         }
223
224         if(sockpath)
225         {
226                 monsock = connect_local(sockpath);
227         }
228         else if(hostname)
229 #else
230         if(hostname)
231 #endif
232
233         {
234                 monsock = connect_remote(hostname, portno);
235         }
236         else
237         {
238                 usage();
239         }
240
241         if(monsock == -1)
242         {
243                 fprintf(stderr, "Could not connect to i4b isdn daemon.\n");
244                 return 1;
245         }
246
247         if(logfilename != NULL)
248         {
249                 if((lfp = fopen(logfilename, "w")) == NULL)
250                 {
251                         fprintf(stderr, "could not open logfile [%s], %s\n", logfilename, strerror(errno));
252                         exit(1);
253                 }
254         }
255
256 #ifndef WIN32
257         signal(SIGPIPE, SIG_IGN);
258 #endif
259                 
260         mloop();
261
262         close(monsock);
263
264         return 0;
265 }
266
267 /*---------------------------------------------------------------------------
268  *      Connect via tcp/ip.
269  *      Return socket if successfull, -1 on error.
270  ---------------------------------------------------------------------------*/
271 static int
272 connect_remote(char *host, int portno)
273 {
274         struct sockaddr_in sa;
275         struct hostent *h;
276         int remotesockfd;
277
278         h = gethostbyname(host);
279
280         if(!h)
281         {
282                 fprintf(stderr, "could not resolve hostname '%s'\n", host);
283                 exit(1);
284         }
285
286         remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
287
288         if(remotesockfd == -1)
289         {
290                 fprintf(stderr, "could not create remote monitor socket: %s\n", strerror(errno));
291                 exit(1);
292         }
293
294         memset(&sa, 0, sizeof(sa));
295
296 #ifdef BSD4_4
297         sa.sin_len = sizeof(sa);
298 #endif
299         sa.sin_family = AF_INET;
300         sa.sin_port = htons(portno);
301
302         memcpy(&sa.sin_addr.s_addr, h->h_addr_list[0], sizeof(sa.sin_addr.s_addr));
303
304         if(connect(remotesockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
305         {
306                 fprintf(stderr, "could not connect remote monitor: %s\n", strerror(errno));
307                 exit(1);
308         }
309
310         return remotesockfd;
311 }
312
313 #ifndef FOREIGN
314 /*---------------------------------------------------------------------------
315  *      Connect local.
316  *      Return socket on success, -1 on failure.
317  *---------------------------------------------------------------------------*/
318 static int
319 connect_local(char *sockpath)
320 {
321         int s;
322         struct sockaddr_un sa;
323
324         /* check path length */
325         if(strlen(sockpath) >= sizeof(sa.sun_path))
326         {
327                 fprintf(stderr, "pathname to long for local socket: %s\n",
328                         sockpath);
329                 exit(1);
330         }
331
332         /* create and setup socket */
333         s = socket(AF_LOCAL, SOCK_STREAM, 0);
334
335         if(s == -1)
336         {
337                 fprintf(stderr, "could not create local monitor socket:%s\n", strerror(errno));
338                 exit(1);
339         }
340
341         memset(&sa, 0, sizeof(sa));
342
343         sa.sun_len = sizeof(sa);
344         sa.sun_family = AF_LOCAL;
345         strcpy(sa.sun_path, sockpath);
346
347         if(connect(s, (struct sockaddr *)&sa, sizeof(sa)))
348         {
349                 fprintf(stderr, "could not connect local monitor socket [%s]: %s\n", sockpath, strerror(errno));
350         }
351
352         return s;
353 }
354 #endif
355
356 /*---------------------------------------------------------------------------*
357  *      data from keyboard available, read and process it 
358  *---------------------------------------------------------------------------*/
359 #ifndef WIN32
360 static void
361 kbdrdhdl(void)
362 {
363         int ch = getch();
364                 
365         switch(ch)
366         {
367                 case 0x0c:      /* control L */
368                         wrefresh(curscr);
369                         break;
370                 
371                 case '\n':
372                 case '\r':
373                         do_menu();
374                         break;
375         }
376 }
377 #endif
378
379 /*---------------------------------------------------------------------------
380  *      main event loop
381  *---------------------------------------------------------------------------*/
382 static void
383 mloop()
384 {
385         for(;;)
386         {
387                 fd_set rd, wr, ex;
388
389                 FD_ZERO(&rd);
390                 FD_ZERO(&wr);
391                 FD_ZERO(&ex);
392                 FD_SET(fileno(stdin), &rd);
393                 FD_SET(monsock, &rd);
394
395                 select(monsock+1, &rd, &wr, &ex, NULL);
396
397                 if(FD_ISSET(fileno(stdin), &rd))
398                 {
399 #ifndef WIN32
400                         if(fullscreen && curses_ready)
401                                 kbdrdhdl();
402                         else
403 #endif
404                              if(!fullscreen)
405                                 handle_input();
406                         else
407                                 getchar();
408                 }
409
410                 if(FD_ISSET(monsock, &rd))
411                 {
412                         u_int8_t buf[8192];
413                         int bytes, ret;
414
415                         /* Network transfer may deliver two or more packets concatenated.
416                          * Peek at the header and read only one event at a time... */
417
418                         bytes = recv(monsock, buf, I4B_MON_EVNT_HDR, MSG_PEEK);
419
420                         if(bytes == 0)
421                         {
422                                 close(monsock);
423
424 #ifndef WIN32
425                                 if(curses_ready)
426                                 {
427                                         endwin();
428                                         curses_ready = 0;
429                                 }
430 #endif
431                                 
432                                 mprintf("remote isdnd has closed our connection\n");
433                                 exit(0);
434                         }
435                         else if(bytes < 0)
436                         {
437                                 fprintf(stderr, "recv error: %s\n", strerror(errno));
438                                 close(monsock);
439                                 exit(1);
440                         }
441
442                         if (bytes < I4B_MON_EVNT_HDR)
443                                 continue;       /* errh? something must be wrong... */
444
445                         bytes = I4B_GET_2B(buf, I4B_MON_EVNT_LEN);
446
447                         if(bytes >= sizeof(buf))
448                         {
449                                 fprintf(stderr, "mloop: socket recv buffer overflow %d!\n", bytes);
450                                 break;
451                         }
452
453                         /* now we know the size, it fits, so lets read it! */
454                         
455                         ret = sock_read(monsock, buf, bytes);
456
457                         if(ret == 0)
458                         {
459                                 close(monsock);
460 #ifndef WIN32
461                                 if(curses_ready)
462                                         endwin();
463 #endif
464                                 mprintf("remote isdnd has closed our connection\n");
465                                 exit(0);
466                         }
467                         else if(ret < 0)
468                         {
469                                 mprintf("error reading from isdnd: %s", strerror(errno));
470                                 break;
471                         }
472 #ifdef DEBUG
473                         if(debug & DBG_DUMPALL)
474                                 dump_event(buf, ret, 1);
475 #endif
476                         handle_event(buf, ret);
477                 }
478         }
479 }
480
481 #ifdef DEBUG
482 /*
483  * Dump a complete event packet.
484  */
485 static void dump_event(u_int8_t *msg, int len, int read)
486 {
487         int i;
488
489         if(read)
490                 mprintf("read from socket:");
491         else
492                 mprintf("write to socket:");
493
494         for(i = 0; i < len; i++)
495         {
496                 if(i % 8 == 0)
497                         mprintf("\n%02d: ", i);
498                 mprintf("0x%02x %c  ", msg[i], isprint(msg[i]) ? msg[i] : '.');
499         }
500         mprintf("\n");
501 }
502 #endif
503
504 static void
505 print_logevent(time_t tstamp, int prio, char * what, char * msg)
506 {
507         char buf[256];
508         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
509         mprintf("log: %s prio %d what=%s msg=%s\n", buf, prio, what, msg);
510
511 #ifndef WIN32
512         if(fullscreen)
513         {
514                 if((!debug_noscreen) || (debug_noscreen && (((strcmp(what, "DBG"))) != 0)))
515                 {
516 /*
517  * FreeBSD-current integrated ncurses. Since then it is no longer possible
518  * to write to the last column in the logfilewindow without causing an
519  * automatic newline to occur resulting in a blank line in that window.
520  */
521 #ifdef __FreeBSD__
522 #include <osreldate.h>
523 #endif
524 #if defined(__FreeBSD_version) && __FreeBSD_version >= 400009
525 #warning "FreeBSD ncurses is buggy: write to last column = auto newline!"
526                         wprintw(lower_w, "%s %s %-.*s\n", buf, what,
527                                 COLS-((strlen(buf))+(strlen(what))+3), msg);
528 #else
529                         wprintw(lower_w, "%s %s %-.*s\n", buf, what,
530                                 (int)(COLS-((strlen(buf))+(strlen(what))+2)), msg);
531 #endif
532                         wrefresh(lower_w);
533                 }
534         }
535 #endif
536 }
537
538 static void
539 print_charge(time_t tstamp, int controller, int channel, int units, int estimated)
540 {
541         char buf[256];
542         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
543         mprintf("%s: controller %d, channel %d, charge = %d%s\n",
544                 buf, controller, channel, units, estimated ? " (estimated)" : "");
545 #ifndef WIN32
546         if(fullscreen)
547         {
548                 if(estimated)
549                         display_ccharge(CHPOS(controller, channel), units);
550                 else
551                         display_charge(CHPOS(controller, channel), units);
552         }
553 #endif
554 }
555
556 /*
557  * Print a connect event.
558  * A real monitor would allocate state info for "channel" on this
559  * event.
560  */
561 static void print_connect(
562         time_t tstamp,  /* server time of event */
563         int outgoing,   /* 0 = incoming, 1 = outgoing */
564         int controller, /* controller number */
565         int channel,    /* channel no, used to identify this connection until disconnect */
566         char * cfgname,         /* name of config entry/connection */
567         char * devname,         /* device used (e.g. isp0) */
568         char * remphone,        /* phone no of remote side */
569         char * locphone)        /* local phone no */
570 {
571         char buf[256];
572
573         if(channel == 0)
574                 remstate[controller].ch1state = 1;
575         else
576                 remstate[controller].ch2state = 1;
577
578         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
579
580         if(outgoing)
581                 mprintf("%s: calling out to '%s' [from msn: '%s']",
582                         buf, remphone, locphone);
583         else
584                 mprintf("%s: incoming call from '%s' [to msn: '%s']",
585                         buf, remphone, locphone);
586         mprintf(", controller %d, channel %d, config '%s' on device '%s'\n",
587                 controller, channel, cfgname, devname);
588
589 #ifndef WIN32
590         if(fullscreen)
591                 display_connect(CHPOS(controller, channel), outgoing, cfgname, remphone, devname);
592 #endif
593 }
594
595 /*
596  * Print a disconnect event.
597  * A real monitor could free the "per connection" state
598  * for this channel now
599  */
600 static void
601 print_disconnect(time_t tstamp, int controller, int channel)
602 {
603         char buf[256];
604
605         if(channel == 0)
606                 remstate[controller].ch1state = 0;
607         else
608                 remstate[controller].ch2state = 0;
609
610         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
611
612         mprintf("%s: controller %d, channel %d disconnected\n",
613                 buf, controller, channel);
614
615 #ifndef WIN32
616         if(fullscreen)
617                 display_disconnect(CHPOS(controller, channel));
618 #endif
619 }
620
621 /*
622  * Print an up- or down event
623  */
624 static void
625 print_updown(time_t tstamp, int controller, int channel, int isup)
626 {
627         char buf[256];
628         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
629         mprintf("%s: channel %d is %s\n",
630                 buf, channel, isup ? "up" : "down");
631 }
632
633 /*
634  * Print l1 / l2 status
635  */
636 static void
637 print_l12stat(time_t tstamp, int controller, int layer, int state)
638 {
639         char buf[256];
640         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
641
642         mprintf("%s: layer %d change on controller %d: %s\n",
643                 buf, layer, controller, state ? "up" : "down");
644 #ifndef WIN32
645         if(fullscreen)
646                 display_l12stat(controller, layer, state);
647 #endif
648 }
649
650 /*
651  * Print TEI
652  */
653 static void
654 print_tei(time_t tstamp, int controller, int tei)
655 {
656         char buf[256];
657         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
658
659         mprintf("%s: controller %d, TEI is %d\n",
660                 buf, controller, tei);
661
662 #ifndef WIN32
663         if(fullscreen)
664                 display_tei(controller, tei);
665 #endif
666 }
667
668 /*
669  * Print accounting information
670  */
671 static void
672 print_acct(time_t tstamp, int controller, int channel, int obytes, int obps,
673                 int ibytes, int ibps)
674 {
675         char buf[256];
676         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
677
678         mprintf("%s: controller %d, channel %d: %d obytes, %d obps, %d ibytes, %d ibps\n",
679                 buf, controller, channel, obytes, obps, ibytes, ibps);
680 #ifndef WIN32
681         if(fullscreen)
682                 display_acct(CHPOS(controller, channel), obytes, obps, ibytes, ibps);
683 #endif
684 }
685
686 static void
687 print_initialization(void)
688 {
689 #ifndef WIN32
690         if(fullscreen)
691         {
692                 if(curses_ready == 0)
693                         init_screen();
694         }
695         else
696 #endif
697         {
698                 print_menu();
699         }
700 }
701
702 /*
703  * Dispatch one message received from the daemon.
704  */
705 static void
706 handle_event(u_int8_t *msg, int len)
707 {
708         u_int8_t cmd[I4B_MON_ICLIENT_SIZE];
709         int local;      
710         u_int32_t net;
711         u_int32_t mask;
712         u_int32_t who;
713         static int first = 1;
714         
715         switch(state)
716         {
717                 case ST_INIT:   /* initial data */
718
719                         isdn_major = I4B_GET_2B(msg, I4B_MON_IDATA_VERSMAJOR);
720                         isdn_minor = I4B_GET_2B(msg, I4B_MON_IDATA_VERSMINOR);
721                         nctrl = I4B_GET_2B(msg, I4B_MON_IDATA_NUMCTRL);
722                         nentries = I4B_GET_2B(msg, I4B_MON_IDATA_NUMENTR);
723                         rights = I4B_GET_4B(msg, I4B_MON_IDATA_CLACCESS);
724
725                         mprintf("remote protocol version is %02d.%02d\n", isdn_major, isdn_minor);
726
727                         if(isdn_major != MPROT_VERSION || isdn_minor != MPROT_REL)
728                         {
729                                 fprintf(stderr, "ERROR, remote protocol version mismatch:\n");
730                                 fprintf(stderr, "\tremote major version is %02d, local major version is %02d\n", isdn_major, MPROT_VERSION);
731                                 fprintf(stderr, "\tremote minor version is %02d, local minor version is %02d\n", isdn_minor, MPROT_REL);
732                                 exit(1);
733                         }
734
735                         mprintf("our rights = 0x%x\n", rights);
736
737                         sub_state = 0;                          
738                         first = 1;
739                         
740                         if(nctrl > 0)
741                         {
742                                 state = ST_ICTRL;
743                         }
744                         else if(nentries > 0)
745                         {
746                                 state = ST_IDEV;
747                         }
748                         else
749                         {
750                                 state = ST_ANYEV;
751                                 sleep(2);
752                                 print_initialization();
753                         }
754                         
755                         /* set maximum event mask */
756                         I4B_PREP_CMD(cmd, I4B_MON_CCMD_SETMASK);
757                         I4B_PUT_2B(cmd, I4B_MON_ICLIENT_VERMAJOR, MPROT_VERSION);
758                         I4B_PUT_2B(cmd, I4B_MON_ICLIENT_VERMINOR, MPROT_REL);
759                         I4B_PUT_4B(cmd, I4B_MON_ICLIENT_EVENTS, ~0U);
760
761 #ifdef DEBUG
762                         if(debug & DBG_DUMPALL)
763                                 dump_event(cmd, sizeof(cmd), 0);
764 #endif
765                         
766                         if((sock_write(monsock, cmd, sizeof(cmd))) == -1)
767                         {
768                                 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
769                                 exit(1);
770                         }
771                         break;
772
773                 case ST_ICTRL:  /* initial controller list */
774                         if(first)
775                         {
776                                 first = 0;
777                                 mprintf("%d controller(s) found:\n", nctrl);
778                         }
779                         mprintf("\tcontroller %d: %s\n", sub_state++, msg+I4B_MON_ICTRL_NAME);
780
781                         if(sub_state >= nctrl)
782                         {
783                                 sub_state = 0;
784                                 first = 1;
785                                 if(nentries > 0)
786                                 {
787                                         state = ST_IDEV; /* end of list reached */
788                                 }
789                                 else
790                                 {
791                                         state = ST_ANYEV;
792                                         sleep(2);
793                                         print_initialization();
794                                 }
795                         }
796                         break;
797
798                 case ST_IDEV:   /* initial entry devicename list */
799                         if(first)
800                         {
801                                 first = 0;
802                                 mprintf("%d entries found:\n", nentries);
803                         }
804                         
805                         mprintf("\tentry %d: device %s\n", sub_state++, msg+I4B_MON_IDEV_NAME);
806
807                         strcat(devbuf, msg+I4B_MON_IDEV_NAME);
808                         /* strcat(devbuf, " "); */
809                         
810                         if(sub_state >= nentries)
811                         {
812                                 first = 1;
813                                 state = ST_ANYEV; /* end of list reached */
814                                 sub_state = 0;
815                                 sleep(2);
816                                 print_initialization();
817                         }
818                         break;
819
820                 case ST_ANYEV: /* any event */
821                         switch(I4B_GET_2B(msg, I4B_MON_EVNT))
822                         {
823                                 case I4B_MON_DRINI_CODE:
824                                         state = ST_RIGHT;       /* list of rights entries will follow */
825                                         sub_state = 0;
826                                         sub_state_count = I4B_GET_2B(msg, I4B_MON_DRINI_COUNT);
827                                         mprintf("monitor rights:\n");
828                                         break;
829
830                                 case I4B_MON_DCINI_CODE:
831                                         state = ST_CONNS;
832                                         sub_state = 0;
833                                         sub_state_count = I4B_GET_2B(msg, I4B_MON_DCINI_COUNT);
834                                         mprintf("monitor connections:\n");
835                                         break;
836
837                                 case I4B_MON_LOGEVNT_CODE:
838                                         print_logevent(I4B_GET_4B(msg, I4B_MON_LOGEVNT_TSTAMP),
839                                                 I4B_GET_4B(msg, I4B_MON_LOGEVNT_PRIO),
840                                                 msg+I4B_MON_LOGEVNT_WHAT,
841                                                 msg+I4B_MON_LOGEVNT_MSG);
842                                         break;
843
844                                 case I4B_MON_CHRG_CODE:
845                                         print_charge(I4B_GET_4B(msg, I4B_MON_CHRG_TSTAMP),
846                                                 I4B_GET_4B(msg, I4B_MON_CHRG_CTRL),
847                                                 I4B_GET_4B(msg, I4B_MON_CHRG_CHANNEL),
848                                                 I4B_GET_4B(msg, I4B_MON_CHRG_UNITS),
849                                                 I4B_GET_4B(msg, I4B_MON_CHRG_ESTIMATED));
850                                         break;
851                                         
852                                 case I4B_MON_CONNECT_CODE:
853                                         print_connect(
854                                                 I4B_GET_4B(msg, I4B_MON_CONNECT_TSTAMP),
855                                                 I4B_GET_4B(msg, I4B_MON_CONNECT_DIR),
856                                                 I4B_GET_4B(msg, I4B_MON_CONNECT_CTRL),
857                                                 I4B_GET_4B(msg, I4B_MON_CONNECT_CHANNEL),
858                                                 msg+I4B_MON_CONNECT_CFGNAME,
859                                                 msg+I4B_MON_CONNECT_DEVNAME,
860                                                 msg+I4B_MON_CONNECT_REMPHONE,
861                                                 msg+I4B_MON_CONNECT_LOCPHONE);
862                                         break;
863                                         
864                                 case I4B_MON_DISCONNECT_CODE:
865                                         print_disconnect(
866                                                 I4B_GET_4B(msg, I4B_MON_DISCONNECT_TSTAMP),
867                                                 I4B_GET_4B(msg, I4B_MON_DISCONNECT_CTRL),
868                                                 I4B_GET_4B(msg, I4B_MON_DISCONNECT_CHANNEL));
869                                         break;
870                                         
871                                 case I4B_MON_UPDOWN_CODE:
872                                         print_updown(
873                                                 I4B_GET_4B(msg, I4B_MON_UPDOWN_TSTAMP),
874                                                 I4B_GET_4B(msg, I4B_MON_UPDOWN_CTRL),
875                                                 I4B_GET_4B(msg, I4B_MON_UPDOWN_CHANNEL),
876                                                 I4B_GET_4B(msg, I4B_MON_UPDOWN_ISUP));
877                                         break;
878                                 case I4B_MON_L12STAT_CODE:
879                                         print_l12stat(
880                                                 I4B_GET_4B(msg, I4B_MON_L12STAT_TSTAMP),
881                                                 I4B_GET_4B(msg, I4B_MON_L12STAT_CTRL),
882                                                 I4B_GET_4B(msg, I4B_MON_L12STAT_LAYER),
883                                                 I4B_GET_4B(msg, I4B_MON_L12STAT_STATE));
884                                         break;
885                                 case I4B_MON_TEI_CODE:
886                                         print_tei(
887                                                 I4B_GET_4B(msg, I4B_MON_TEI_TSTAMP),
888                                                 I4B_GET_4B(msg, I4B_MON_TEI_CTRL),
889                                                 I4B_GET_4B(msg, I4B_MON_TEI_TEI));
890                                         break;
891                                 case I4B_MON_ACCT_CODE:
892                                         print_acct(
893                                                 I4B_GET_4B(msg, I4B_MON_ACCT_TSTAMP),
894                                                 I4B_GET_4B(msg, I4B_MON_ACCT_CTRL),
895                                                 I4B_GET_4B(msg, I4B_MON_ACCT_CHAN),
896                                                 I4B_GET_4B(msg, I4B_MON_ACCT_OBYTES),
897                                                 I4B_GET_4B(msg, I4B_MON_ACCT_OBPS),
898                                                 I4B_GET_4B(msg, I4B_MON_ACCT_IBYTES),
899                                                 I4B_GET_4B(msg, I4B_MON_ACCT_IBPS));
900                                         break;
901                                 default:
902                                         mprintf("unknown event code: %d\n", I4B_GET_2B(msg, I4B_MON_EVNT));
903                         }
904                         break;
905
906                 case ST_RIGHT:  /* one record in a list of monitor rights */
907                         rights = I4B_GET_4B(msg, I4B_MON_DR_RIGHTS);
908                         net = I4B_GET_4B(msg, I4B_MON_DR_NET);
909                         mask = I4B_GET_4B(msg, I4B_MON_DR_MASK);
910                         local = I4B_GET_1B(msg, I4B_MON_DR_LOCAL);
911
912                         if(local)
913                         {
914                                 mprintf("\tlocal: rights = %x\n", rights);
915                         }
916                         else
917                         {
918                                 mprintf("\tfrom: %d.%d.%d.%d, mask %d.%d.%d.%d, rights = %x\n",
919                                         (net >> 24) & 0x00ff, (net >> 16) & 0x00ff, (net >> 8) & 0x00ff, net & 0x00ff,
920                                         (mask >> 24) & 0x00ff, (mask >> 16) & 0x00ff, (mask >> 8) & 0x00ff, mask & 0x00ff,
921                                         rights);
922                         }
923
924                         sub_state++;
925
926                         if(sub_state >= sub_state_count)
927                         {
928                                 state = ST_ANYEV;
929                                 print_initialization();
930                         }
931                         break;
932
933                 case ST_CONNS:
934                         who = I4B_GET_4B(msg, I4B_MON_DC_WHO);
935                         rights = I4B_GET_4B(msg, I4B_MON_DC_RIGHTS);
936
937                         mprintf("\tfrom: %d.%d.%d.%d, rights = %x\n",
938                                 (who >> 24) & 0x00ff, (who >> 16) & 0x00ff, (who >> 8) & 0x00ff, who & 0x00ff,
939                                 rights);
940
941                         sub_state++;
942
943                         if(sub_state >= sub_state_count)
944                         {
945                                 state = ST_ANYEV;
946                                 print_initialization();
947                         }
948                         break;
949
950                 default:
951                         mprintf("unknown event from remote: local state = %d, evnt = %x, len = %d\n",
952                                 state, I4B_GET_2B(msg, I4B_MON_EVNT), len);
953         }
954 }
955
956 /*
957  * Process input from user
958  */
959 static void
960 handle_input()
961 {
962         char buf[1024];
963         int channel, controller;
964         
965         fgets(buf, sizeof(buf), stdin);
966
967         switch(atoi(buf))
968         {
969                 case 1:
970                     {
971                         u_int8_t cmd[I4B_MON_DUMPRIGHTS_SIZE];
972                         I4B_PREP_CMD(cmd, I4B_MON_DUMPRIGHTS_CODE);
973 #ifdef DEBUG
974                         if(debug & DBG_DUMPALL)
975                                 dump_event(cmd, I4B_MON_DUMPRIGHTS_SIZE, 0);
976 #endif
977
978                         if((sock_write(monsock, cmd, I4B_MON_DUMPRIGHTS_SIZE)) == -1)
979                         {
980                                 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
981                                 exit(1);
982                         }
983                     }
984                     break;
985
986                 case 2:
987                     {
988                         u_int8_t cmd[I4B_MON_DUMPMCONS_SIZE];
989                         I4B_PREP_CMD(cmd, I4B_MON_DUMPMCONS_CODE);
990 #ifdef DEBUG
991                         if(debug & DBG_DUMPALL)
992                                 dump_event(cmd, I4B_MON_DUMPMCONS_CODE, 0);
993 #endif
994
995                         if((sock_write(monsock, cmd, I4B_MON_DUMPMCONS_SIZE)) == -1)
996                         {
997                                 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
998                                 exit(1);
999                         }                       
1000                     }
1001                     break;
1002
1003                 case 3:
1004                     {
1005                         u_int8_t cmd[I4B_MON_CFGREREAD_SIZE];
1006                         I4B_PREP_CMD(cmd, I4B_MON_CFGREREAD_CODE);
1007 #ifdef DEBUG
1008                         if(debug & DBG_DUMPALL)
1009                                 dump_event(cmd, I4B_MON_CFGREREAD_CODE, 0);
1010 #endif
1011
1012                         if((sock_write(monsock, cmd, I4B_MON_CFGREREAD_SIZE)) == -1)
1013                         {
1014                                 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1015                                 exit(1);
1016                         }
1017                     }
1018                     break;
1019                         
1020                 case 4:
1021                     {
1022                         u_int8_t cmd[I4B_MON_HANGUP_SIZE];
1023                         I4B_PREP_CMD(cmd, I4B_MON_HANGUP_CODE);
1024                         
1025                         printf("Which controller you wish to hangup? ");
1026                         fgets(buf, sizeof(buf), stdin);
1027                         controller = atoi(buf);
1028                         I4B_PUT_4B(cmd, I4B_MON_HANGUP_CTRL, controller);
1029
1030                         printf("Which channel do you wish to hangup? ");
1031                         fgets(buf, sizeof(buf), stdin);
1032                         channel = atoi(buf);
1033                         I4B_PUT_4B(cmd, I4B_MON_HANGUP_CHANNEL, channel);
1034                         
1035 #ifdef DEBUG
1036                         if(debug & DBG_DUMPALL)
1037                                 dump_event(cmd, I4B_MON_HANGUP_CHANNEL, 0);
1038 #endif
1039
1040                         if((sock_write(monsock, cmd, I4B_MON_HANGUP_SIZE)) == -1)
1041                         {
1042                                 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1043                                 exit(1);
1044                         }                       
1045                     }
1046                     break;
1047
1048                 case 9:
1049                         close(monsock);
1050                         exit(0);
1051                         break;
1052
1053                 default:
1054                         print_menu();
1055                         break;
1056         }
1057 }
1058
1059 void
1060 reread(void)
1061 {
1062         u_int8_t cmd[I4B_MON_CFGREREAD_SIZE];
1063         I4B_PREP_CMD(cmd, I4B_MON_CFGREREAD_CODE);
1064 #ifdef DEBUG
1065         if(debug & DBG_DUMPALL)
1066                 dump_event(cmd, I4B_MON_CFGREREAD_CODE, 0);
1067 #endif
1068         if((sock_write(monsock, cmd, I4B_MON_CFGREREAD_SIZE)) == -1)
1069         {
1070                 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1071                 exit(1);
1072         }
1073 }
1074
1075 void
1076 hangup(int ctrl, int chan)
1077 {
1078         u_int8_t cmd[I4B_MON_HANGUP_SIZE];
1079
1080         I4B_PREP_CMD(cmd, I4B_MON_HANGUP_CODE);
1081         I4B_PUT_4B(cmd, I4B_MON_HANGUP_CTRL, ctrl);
1082         I4B_PUT_4B(cmd, I4B_MON_HANGUP_CHANNEL, chan);
1083                         
1084 #ifdef DEBUG
1085         if(debug & DBG_DUMPALL)
1086                 dump_event(cmd, I4B_MON_HANGUP_CHANNEL, 0);
1087 #endif
1088
1089         if((sock_write(monsock, cmd, I4B_MON_HANGUP_SIZE)) == -1)
1090         {
1091                 fprintf(stderr, "sock_write failed: %s\n", strerror(errno));
1092                 exit(1);
1093         }                       
1094 }
1095
1096 /*
1097  * Display menu
1098  */
1099 static void
1100 print_menu()
1101 {
1102         if(!fullscreen)
1103         {
1104                 printf("Menu: <1> display rights,     <2> display monitor connections,\n");
1105                 printf("      <3> reread config file, <4> hangup \n");
1106                 printf("      <9> quit isdnmonitor\n");
1107                 fflush(stdout);
1108         }
1109 }
1110
1111 static ssize_t
1112 sock_read(int fd, void *buf, size_t nbytes)
1113 {
1114         size_t nleft;
1115         ssize_t nread;
1116         unsigned char *ptr;
1117
1118         ptr = buf;
1119         nleft = nbytes;
1120
1121         while(nleft > 0)
1122         {
1123                 if((nread = read(fd, ptr, nleft)) < 0)
1124                 {
1125                         if(errno == EINTR)
1126                         {
1127                                 nread = 0;
1128                         }
1129                         else
1130                         {
1131                                 return(-1);
1132                         }
1133                 }
1134                 else if(nread == 0)
1135                 {
1136                         break; /* EOF */
1137                 }
1138
1139                 nleft -= nread;
1140                 ptr += nread;
1141         }
1142         return(nbytes - nleft);
1143 }
1144
1145 static ssize_t
1146 sock_write(int fd, void *buf, size_t nbytes)
1147 {
1148         size_t nleft;
1149         ssize_t nwritten;
1150         unsigned char *ptr;
1151
1152         ptr = buf;
1153         nleft = nbytes;
1154
1155         while(nleft > 0)
1156         {
1157                 if((nwritten = write(fd, ptr, nleft)) <= 0)
1158                 {
1159                         if(errno == EINTR)
1160                         {
1161                                 nwritten = 0;
1162                         }
1163                         else
1164                         {
1165                                 return(-1);
1166                         }
1167                 }
1168
1169                 nleft -= nwritten;
1170                 ptr += nwritten;
1171         }
1172         return(nbytes);
1173 }
1174
1175 static void
1176 mprintf(char *fmt, ...)
1177 {
1178 #define PRBUFLEN 1024
1179         char buffer[PRBUFLEN];
1180         va_list ap;
1181
1182         va_start(ap, fmt);
1183         vsnprintf(buffer, PRBUFLEN-1, fmt, ap);
1184         va_end(ap);
1185
1186         if(!fullscreen || (fullscreen && (!curses_ready)))
1187                 printf("%s", buffer);
1188         
1189         if(logfilename != NULL)
1190         {
1191                 fprintf(lfp, "%s", buffer);
1192                 fflush(lfp);
1193         }
1194 }
1195
1196 /* EOF */