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