]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/i4b/isdnmonitor/main.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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$
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 #ifdef __FreeBSD__
76 #include <osreldate.h>
77 #endif
78
79 #define MAIN
80 #include "monprivate.h"
81 #undef MAIN
82
83 #ifndef AF_LOCAL
84 #define AF_LOCAL AF_UNIX
85 #endif
86
87 #ifdef DEBUG
88 #include <ctype.h>
89 #endif
90
91 #include "monitor.h"
92
93 /*
94  * Local function prototypes
95  */
96 static int connect_local(char *sockpath);
97 static int connect_remote(char *host, int portno);
98 static void usage();
99 static void mloop();
100 static void handle_input();
101 static void print_menu();
102 static void print_logevent(time_t tstamp, int prio, char * what, char * msg);
103 static void print_charge(time_t tstamp, int controller, int channel, int units, int estimated);
104 static void print_connect(time_t tstamp, int dir, int controller, int channel, char * cfgname, char * devname, char * remphone, char * locphone);
105 static void print_disconnect(time_t tstamp, int controller, int channel);
106 static void print_updown(time_t tstamp, int contoller, int channel, int isup);
107 static void handle_event(u_int8_t *msg, int len);
108 #ifdef DEBUG
109 static void dump_event(u_int8_t *msg, int len, int readflag);
110 #endif
111
112 static ssize_t sock_read(int fd, void *buf, size_t nbytes);
113 static ssize_t sock_write(int fd, void *buf, size_t nbytes);
114
115 static void mprintf(char *fmt, ...);
116
117 /*
118  * Global variables
119  */
120 static int debug = 0;
121 #define DBG_DUMPALL     0x01
122 #define DBG_PSEND       0x02
123
124 static int monsock = -1;
125 static int state = ST_INIT;
126 static int sub_state = 0;
127 static int sub_state_count = 0;
128
129 static int isdn_major = 0;
130 static int isdn_minor = 0;
131 static u_int32_t rights = 0;
132
133 static char *logfilename = NULL;
134 static FILE *lfp = NULL;
135
136 /*---------------------------------------------------------------------------
137  *      Display usage and exit
138  *---------------------------------------------------------------------------*/
139 static void
140 usage()
141 {
142         fprintf(stderr, "\n");
143         fprintf(stderr, "isdnmonitor - version %02d.%02d.%d, (protocol %02d.%02d)\n", VERSION, REL, STEP, MPROT_VERSION, MPROT_REL);
144 #ifdef FOREIGN
145         fprintf(stderr, "  usage: isdnmonitor [-c] [-d val] [-f name] [-h host] [-p port]\n");
146 #else
147         fprintf(stderr, "  usage: isdnmonitor [-c] [-d val] [-f name] [-h host] [-l path] [-p port]\n");
148 #endif
149         fprintf(stderr, "    -c        switch to curses fullscreen output\n");        
150         fprintf(stderr, "    -d <val>  debug flags (see source ...)\n");
151         fprintf(stderr, "    -dn       no debug output on fullscreen display\n");
152         fprintf(stderr, "    -f <name> filename to log output to\n");
153         fprintf(stderr, "    -h <host> hostname/address to connect to\n");        
154 #ifndef FOREIGN
155         fprintf(stderr, "    -l <path> pathname to local domain socket to connect to\n");
156 #endif
157         fprintf(stderr, "    -p <port> portnumber to use to connect to remote host\n");
158         exit(1);
159 }
160
161 /*---------------------------------------------------------------------------
162  *      Parse command line, startup monitor client
163  *---------------------------------------------------------------------------*/
164 int main(int argc, char **argv)
165 {
166         int i;
167
168 #ifdef WIN32
169         WSADATA wsCaps;
170         WSAStartup(MAKEWORD(2, 0), &wsCaps);
171 #endif
172
173         portno = DEF_MONPORT;
174         devbuf[0] = '\0';
175
176 #ifndef FOREIGN 
177         while((i = getopt(argc, argv, "cd:f:h:p:l:")) != -1)
178 #else
179         while((i = getopt(argc, argv, "cd:f:h:p:")) != -1)
180 #endif
181         {
182                 switch(i)
183                 {
184                         case 'c':
185                                 fullscreen = 1;
186                                 break;
187                         case 'd':
188                                 if(*optarg == 'n')
189                                 {
190                                         debug_noscreen = 1;
191                                 }
192                                 else
193                                 {
194                                         if((sscanf(optarg, "%i", &debug)) != 1)
195                                                 usage();
196                                 }
197                                 break;
198                         case 'f':
199                                 logfilename = optarg;
200                                 break;
201                         case 'h':
202                                 hostname = optarg;
203                                 break;
204 #ifndef FOREIGN
205                         case 'l':
206                                 sockpath = optarg;
207                                 break;
208 #endif
209                         case 'p':
210                                 if((sscanf(optarg, "%i", &portno)) != 1)
211                                         usage();
212                                 break;
213                         default:
214                                 usage();
215                                 break;
216                 }
217         }
218
219 #ifndef FOREIGN
220         if(hostname && sockpath)
221         {
222                 fprintf(stderr, "Error: can not use local socket path on remote machine\n"
223                                 "conflicting options -h and -l!\n");
224                 return 1;
225         }
226
227         if(sockpath)
228         {
229                 monsock = connect_local(sockpath);
230         }
231         else if(hostname)
232 #else
233         if(hostname)
234 #endif
235
236         {
237                 monsock = connect_remote(hostname, portno);
238         }
239         else
240         {
241                 usage();
242         }
243
244         if(monsock == -1)
245         {
246                 fprintf(stderr, "Could not connect to i4b isdn daemon.\n");
247                 return 1;
248         }
249
250         if(logfilename != NULL)
251         {
252                 if((lfp = fopen(logfilename, "w")) == NULL)
253                 {
254                         fprintf(stderr, "could not open logfile [%s], %s\n", logfilename, strerror(errno));
255                         exit(1);
256                 }
257         }
258
259 #ifndef WIN32
260         signal(SIGPIPE, SIG_IGN);
261 #endif
262                 
263         mloop();
264
265         close(monsock);
266
267         return 0;
268 }
269
270 /*---------------------------------------------------------------------------
271  *      Connect via tcp/ip.
272  *      Return socket if successfull, -1 on error.
273  ---------------------------------------------------------------------------*/
274 static int
275 connect_remote(char *host, int portno)
276 {
277         struct sockaddr_in sa;
278         struct hostent *h;
279         int remotesockfd;
280
281         h = gethostbyname(host);
282
283         if(!h)
284         {
285                 fprintf(stderr, "could not resolve hostname '%s'\n", host);
286                 exit(1);
287         }
288
289         remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
290
291         if(remotesockfd == -1)
292         {
293                 fprintf(stderr, "could not create remote monitor socket: %s\n", strerror(errno));
294                 exit(1);
295         }
296
297         memset(&sa, 0, sizeof(sa));
298
299 #ifdef BSD4_4
300         sa.sin_len = sizeof(sa);
301 #endif
302         sa.sin_family = AF_INET;
303         sa.sin_port = htons(portno);
304
305         memcpy(&sa.sin_addr.s_addr, h->h_addr_list[0], sizeof(sa.sin_addr.s_addr));
306
307         if(connect(remotesockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
308         {
309                 fprintf(stderr, "could not connect remote monitor: %s\n", strerror(errno));
310                 exit(1);
311         }
312
313         return remotesockfd;
314 }
315
316 #ifndef FOREIGN
317 /*---------------------------------------------------------------------------
318  *      Connect local.
319  *      Return socket on success, -1 on failure.
320  *---------------------------------------------------------------------------*/
321 static int
322 connect_local(char *sockpath)
323 {
324         int s;
325         struct sockaddr_un sa;
326
327         /* check path length */
328         if(strlen(sockpath) >= sizeof(sa.sun_path))
329         {
330                 fprintf(stderr, "pathname to long for local socket: %s\n",
331                         sockpath);
332                 exit(1);
333         }
334
335         /* create and setup socket */
336         s = socket(AF_LOCAL, SOCK_STREAM, 0);
337
338         if(s == -1)
339         {
340                 fprintf(stderr, "could not create local monitor socket:%s\n", strerror(errno));
341                 exit(1);
342         }
343
344         memset(&sa, 0, sizeof(sa));
345
346         sa.sun_len = sizeof(sa);
347         sa.sun_family = AF_LOCAL;
348         strcpy(sa.sun_path, sockpath);
349
350         if(connect(s, (struct sockaddr *)&sa, sizeof(sa)))
351         {
352                 fprintf(stderr, "could not connect local monitor socket [%s]: %s\n", sockpath, strerror(errno));
353         }
354
355         return s;
356 }
357 #endif
358
359 /*---------------------------------------------------------------------------*
360  *      data from keyboard available, read and process it 
361  *---------------------------------------------------------------------------*/
362 #ifndef WIN32
363 static void
364 kbdrdhdl(void)
365 {
366         int ch = getch();
367                 
368         switch(ch)
369         {
370                 case 0x0c:      /* control L */
371                         wrefresh(curscr);
372                         break;
373                 
374                 case '\n':
375                 case '\r':
376                         do_menu();
377                         break;
378         }
379 }
380 #endif
381
382 /*---------------------------------------------------------------------------
383  *      main event loop
384  *---------------------------------------------------------------------------*/
385 static void
386 mloop()
387 {
388         for(;;)
389         {
390                 fd_set rd, wr, ex;
391
392                 FD_ZERO(&rd);
393                 FD_ZERO(&wr);
394                 FD_ZERO(&ex);
395                 FD_SET(fileno(stdin), &rd);
396                 FD_SET(monsock, &rd);
397
398                 select(monsock+1, &rd, &wr, &ex, NULL);
399
400                 if(FD_ISSET(fileno(stdin), &rd))
401                 {
402 #ifndef WIN32
403                         if(fullscreen && curses_ready)
404                                 kbdrdhdl();
405                         else
406 #endif
407                              if(!fullscreen)
408                                 handle_input();
409                         else
410                                 getchar();
411                 }
412
413                 if(FD_ISSET(monsock, &rd))
414                 {
415                         u_int8_t buf[8192];
416                         int bytes, ret;
417
418                         /* Network transfer may deliver two or more packets concatenated.
419                          * Peek at the header and read only one event at a time... */
420
421                         bytes = recv(monsock, buf, I4B_MON_EVNT_HDR, MSG_PEEK);
422
423                         if(bytes == 0)
424                         {
425                                 close(monsock);
426
427 #ifndef WIN32
428                                 if(curses_ready)
429                                 {
430                                         endwin();
431                                         curses_ready = 0;
432                                 }
433 #endif
434                                 
435                                 mprintf("remote isdnd has closed our connection\n");
436                                 exit(0);
437                         }
438                         else if(bytes < 0)
439                         {
440                                 fprintf(stderr, "recv error: %s\n", strerror(errno));
441                                 close(monsock);
442                                 exit(1);
443                         }
444
445                         if (bytes < I4B_MON_EVNT_HDR)
446                                 continue;       /* errh? something must be wrong... */
447
448                         bytes = I4B_GET_2B(buf, I4B_MON_EVNT_LEN);
449
450                         if(bytes >= sizeof(buf))
451                         {
452                                 fprintf(stderr, "mloop: socket recv buffer overflow %d!\n", bytes);
453                                 break;
454                         }
455
456                         /* now we know the size, it fits, so lets read it! */
457                         
458                         ret = sock_read(monsock, buf, bytes);
459
460                         if(ret == 0)
461                         {
462                                 close(monsock);
463 #ifndef WIN32
464                                 if(curses_ready)
465                                         endwin();
466 #endif
467                                 mprintf("remote isdnd has closed our connection\n");
468                                 exit(0);
469                         }
470                         else if(ret < 0)
471                         {
472                                 mprintf("error reading from isdnd: %s", strerror(errno));
473                                 break;
474                         }
475 #ifdef DEBUG
476                         if(debug & DBG_DUMPALL)
477                                 dump_event(buf, ret, 1);
478 #endif
479                         handle_event(buf, ret);
480                 }
481         }
482 }
483
484 #ifdef DEBUG
485 /*
486  * Dump a complete event packet.
487  */
488 static void dump_event(u_int8_t *msg, int len, int read)
489 {
490         int i;
491
492         if(read)
493                 mprintf("read from socket:");
494         else
495                 mprintf("write to socket:");
496
497         for(i = 0; i < len; i++)
498         {
499                 if(i % 8 == 0)
500                         mprintf("\n%02d: ", i);
501                 mprintf("0x%02x %c  ", msg[i], isprint(msg[i]) ? msg[i] : '.');
502         }
503         mprintf("\n");
504 }
505 #endif
506
507 static void
508 print_logevent(time_t tstamp, int prio, char * what, char * msg)
509 {
510         char buf[256];
511         strftime(buf, sizeof(buf), I4B_TIME_FORMAT, localtime(&tstamp));
512         mprintf("log: %s prio %d what=%s msg=%s\n", buf, prio, what, msg);
513
514 #ifndef WIN32
515         if(fullscreen)
516         {
517                 if((!debug_noscreen) || (debug_noscreen && (((strcmp(what, "DBG"))) != 0)))
518                 {
519 /*
520  * FreeBSD-current integrated ncurses. Since then it is no longer possible
521  * to write to the last column in the logfilewindow without causing an
522  * automatic newline to occur resulting in a blank line in that window.
523  */
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 */