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