2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 *---------------------------------------------------------------------------
27 * i4b daemon - curses fullscreen output
28 * -------------------------------------
30 * $Id: curses.c,v 1.36 2000/10/09 12:53:29 hm Exp $
32 * $FreeBSD: src/usr.sbin/i4b/isdnd/curses.c,v 1.6.2.2 2001/08/01 17:45:03 obrien Exp $
33 * $DragonFly: src/usr.sbin/i4b/isdnd/curses.c,v 1.2 2003/06/17 04:29:54 dillon Exp $
35 * last edit-date: [Thu Jun 1 16:24:43 2000]
37 *---------------------------------------------------------------------------*/
43 #define CHPOS(cfgp) (((cfgp)->isdncontrollerused*2) + (cfgp)->isdnchannelused)
45 static void display_budget(void);
46 static void display_cards(void);
47 static void menuexit(WINDOW
*menu_w
);
49 /*---------------------------------------------------------------------------*
50 * init curses fullscreen display
51 *---------------------------------------------------------------------------*/
60 initscr(); /* curses init */
62 if((COLS
< 80) || (LINES
< 24))
64 log(LL_ERR
, "ERROR, minimal screensize must be 80x24, is %dx%d, terminating!",COLS
, LINES
);
71 uheight
= ncontroller
* 2; /* cards * b-channels */
72 lheight
= LINES
- uheight
- 6 + 1; /* rest of display */
74 if((upper_w
= newwin(uheight
, COLS
, UPPER_B
, 0)) == NULL
)
76 log(LL_ERR
, "ERROR, curses init upper window, terminating!");
80 if((mid_w
= newwin(1, COLS
, UPPER_B
+uheight
+1, 0)) == NULL
)
82 log(LL_ERR
, "ERROR, curses init mid window, terminating!");
86 if((lower_w
= newwin(lheight
, COLS
, UPPER_B
+uheight
+3, 0)) == NULL
)
88 log(LL_ERR
, "ERROR, curses init lower window, LINES = %d, lheight = %d, uheight = %d, terminating!", LINES
, lheight
, uheight
);
94 snprintf(buffer
, sizeof(buffer
), "----- isdn controller channel state ------------- isdnd %02d.%02d.%d [pid %d] -", VERSION
, REL
, STEP
, (int)getpid());
96 while(strlen(buffer
) < COLS
&& strlen(buffer
) < sizeof(buffer
) - 1)
105 /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
106 addstr("c tei b remote iface dir outbytes obps inbytes ibps units");
108 snprintf(buffer
, sizeof(buffer
), "----- isdn userland interface state ------------------------------------------");
109 while(strlen(buffer
) < COLS
&& strlen(buffer
) < sizeof(buffer
) - 1)
117 snprintf(buffer
, sizeof(buffer
), "----- isdnd logfile display --------------------------------------------------");
118 while(strlen(buffer
) < COLS
&& strlen(buffer
) < sizeof(buffer
) - 1)
128 for(i
=0, j
=0; i
<= ncontroller
; i
++, j
+=2)
130 if(isdn_ctrl_tab
[i
].tei
== -1)
131 mvwprintw(upper_w
, j
, H_CNTL
, "%d --- 1 ", i
);
133 mvwprintw(upper_w
, j
, H_CNTL
, "%d %3d 1 ", i
, isdn_ctrl_tab
[i
].tei
);
134 mvwprintw(upper_w
, j
+1, H_CNTL
, " L12 2 ");
138 for(i
=0, j
=0; i
< nentries
; i
++) /* walk thru all entries */
140 p
= &cfg_entry_tab
[i
]; /* get ptr to enry */
142 mvwprintw(mid_w
, 0, j
, "%s%d ", bdrivername(p
->usrdevicename
), p
->usrdeviceunit
);
146 j
+= ((strlen(bdrivername(p
->usrdevicename
)) + (p
->usrdeviceunit
> 9 ? 2 : 1) + 1));
150 wmove(lower_w
, 0, 0);
156 /*---------------------------------------------------------------------------*
157 * curses menu for fullscreen command mode
158 *---------------------------------------------------------------------------*/
162 static char *menu
[WMITEMS
] =
164 "1 - (D)isplay refresh",
165 "2 - (H)angup (choose a channel)",
166 "3 - (R)eread config file",
167 "4 - (S)how card types",
168 "5 - (B)udget information",
169 "6 - (Q)uit the program",
176 struct timeval timeout
;
178 /* create a new window in the lower screen area */
180 if((menu_w
= newwin(WMENU_HGT
, WMENU_LEN
, WMENU_POSLN
, WMENU_POSCO
)) == NULL
)
182 log(LL_WRN
, "ERROR, curses init menu window!");
186 /* create a border around the window */
188 box(menu_w
, '|', '-');
193 mvwaddstr(menu_w
, 0, (WMENU_LEN
/ 2) - (strlen(WMENU_TITLE
) / 2), WMENU_TITLE
);
196 /* fill the window with the menu options */
198 for(mpos
=0; mpos
<= (WMITEMS
-1); mpos
++)
199 mvwaddstr(menu_w
, mpos
+ 2, 2, menu
[mpos
]);
201 /* highlight the first menu option */
205 mvwaddstr(menu_w
, mpos
+ 2, 2, menu
[mpos
]);
215 FD_SET(STDIN_FILENO
, &set
);
216 timeout
.tv_sec
= WMTIMEOUT
;
219 /* if no char is available within timeout, exit menu*/
221 if((select(STDIN_FILENO
+ 1, &set
, NULL
, NULL
, &timeout
)) <= 0)
229 case '\t': /* hilite next option */
230 mvwaddstr(menu_w
, mpos
+ 2, 2, menu
[mpos
]);
235 mvwaddstr(menu_w
, mpos
+ 2, 2, menu
[mpos
]);
239 case ('0'+WBUDGET
+1): /* display budget info */
245 case ('0'+WREFRESH
+1): /* display refresh */
251 case ('0'+WQUIT
+1): /* quit program */
258 case ('0'+WHANGUP
+1): /* hangup connection */
264 case ('0'+WREREAD
+1): /* reread config file */
270 case ('0'+WSHOW
+1): /* reread config file */
277 case '\r': /* exec highlighted option */
319 menuexit(WINDOW
*menu_w
)
321 int uheight
= ncontroller
* 2; /* cards * b-channels */
324 /* delete the menu window */
328 /* re-display the original lower window contents */
340 /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
341 addstr("c tei b remote iface dir outbytes obps inbytes ibps units");
343 sprintf(buffer
, "----- isdn userland interface state ------------------------------------------");
344 while(strlen(buffer
) < COLS
)
352 sprintf(buffer
, "----- isdnd logfile display --------------------------------------------------");
353 while(strlen(buffer
) < COLS
)
364 /*---------------------------------------------------------------------------*
365 * display the charge in units
366 *---------------------------------------------------------------------------*/
368 display_charge(cfg_entry_t
*cep
)
370 mvwprintw(upper_w
, CHPOS(cep
), H_UNITS
, "%d", cep
->charge
);
375 /*---------------------------------------------------------------------------*
376 * display the calculated charge in units
377 *---------------------------------------------------------------------------*/
379 display_ccharge(cfg_entry_t
*cep
, int units
)
381 mvwprintw(upper_w
, CHPOS(cep
), H_UNITS
, "(%d)", units
);
386 /*---------------------------------------------------------------------------*
387 * display accounting information
388 *---------------------------------------------------------------------------*/
390 display_acct(cfg_entry_t
*cep
)
392 mvwprintw(upper_w
, CHPOS(cep
), H_OUT
, "%-10d", cep
->outbytes
);
393 mvwprintw(upper_w
, CHPOS(cep
), H_OUTBPS
, "%-4d", cep
->outbps
);
394 mvwprintw(upper_w
, CHPOS(cep
), H_IN
, "%-10d", cep
->inbytes
);
395 mvwprintw(upper_w
, CHPOS(cep
), H_INBPS
, "%-4d", cep
->inbps
);
399 /*---------------------------------------------------------------------------*
400 * display connect information
401 *---------------------------------------------------------------------------*/
403 display_connect(cfg_entry_t
*cep
)
407 /* remote telephone number */
411 if(cep
->direction
== DIR_IN
)
412 snprintf(buffer
, sizeof(buffer
), "%s", get_alias(cep
->real_phone_incoming
));
414 snprintf(buffer
, sizeof(buffer
), "%s", get_alias(cep
->remote_phone_dialout
));
418 if(cep
->direction
== DIR_IN
)
419 snprintf(buffer
, sizeof(buffer
), "%s/%s", cep
->name
, cep
->real_phone_incoming
);
421 snprintf(buffer
, sizeof(buffer
), "%s/%s", cep
->name
, cep
->remote_phone_dialout
);
424 buffer
[H_IFN
- H_TELN
- 1] = '\0';
426 mvwprintw(upper_w
, CHPOS(cep
), H_TELN
, "%s", buffer
);
430 mvwprintw(upper_w
, CHPOS(cep
), H_IFN
, "%s%d ",
431 bdrivername(cep
->usrdevicename
), cep
->usrdeviceunit
);
433 mvwprintw(upper_w
, CHPOS(cep
), H_IO
,
434 cep
->direction
== DIR_OUT
? "out" : "in");
436 mvwprintw(upper_w
, CHPOS(cep
), H_OUT
, "-");
437 mvwprintw(upper_w
, CHPOS(cep
), H_OUTBPS
, "-");
438 mvwprintw(upper_w
, CHPOS(cep
), H_IN
, "-");
439 mvwprintw(upper_w
, CHPOS(cep
), H_INBPS
, "-");
447 /*---------------------------------------------------------------------------*
448 * erase line at disconnect time
449 *---------------------------------------------------------------------------*/
451 display_disconnect(cfg_entry_t
*cep
)
453 wmove(upper_w
, CHPOS(cep
),
463 /*---------------------------------------------------------------------------*
464 * display interface up/down information
465 *---------------------------------------------------------------------------*/
467 display_updown(cfg_entry_t
*cep
, int updown
)
474 mvwprintw(mid_w
, 0, cep
->fs_position
, "%s%d ",
475 bdrivername(cep
->usrdevicename
), cep
->usrdeviceunit
);
481 /*---------------------------------------------------------------------------*
482 * display interface up/down information
483 *---------------------------------------------------------------------------*/
485 display_l12stat(int controller
, int layer
, int state
)
487 if(controller
> ncontroller
)
489 if(!(layer
== 1 || layer
== 2))
499 mvwprintw(upper_w
, (controller
*2)+1, H_TEI
+1, "1");
501 mvwprintw(upper_w
, (controller
*2)+1, H_TEI
+2, "2");
505 mvwprintw(upper_w
, (controller
*2)+1, H_TEI
+2, "2");
507 mvwprintw(upper_w
, (controller
*2)+1, H_TEI
+1, "1");
514 /*---------------------------------------------------------------------------*
516 *---------------------------------------------------------------------------*/
518 display_tei(int controller
, int tei
)
520 if(controller
> ncontroller
)
524 mvwprintw(upper_w
, controller
*2, H_TEI
, "---");
526 mvwprintw(upper_w
, controller
*2, H_TEI
, "%3d", tei
);
531 /*---------------------------------------------------------------------------*
533 *---------------------------------------------------------------------------*/
537 static char bell
[1] = { 0x07 };
538 write(STDOUT_FILENO
, &bell
[0], 1);
541 /*---------------------------------------------------------------------------*
542 * display channel information for shutdown
543 *---------------------------------------------------------------------------*/
551 int nlines
, ncols
, pos_x
, pos_y
;
553 struct timeval timeout
;
554 cfg_entry_t
*cep
= NULL
;
556 /* need this later to close the connection */
562 for (i
= 0; i
< ncontroller
; i
++)
564 if((get_controller_state(i
)) != CTRL_UP
)
566 if((ret_channel_state(i
, CHAN_B1
)) == CHAN_RUN
)
568 if((ret_channel_state(i
, CHAN_B2
)) == CHAN_RUN
)
574 if ((cc
= (struct ctlr_chan
*)malloc (cnt
*
575 sizeof (struct ctlr_chan
))) == NULL
)
588 pos_y
= WMENU_POSLN
+ 4;
589 pos_x
= WMENU_POSCO
+ 10;
591 /* create a new window in the lower screen area */
593 if((chan_w
= newwin(nlines
, ncols
, pos_y
, pos_x
)) == NULL
)
595 log(LL_WRN
, "ERROR, curses init channel window!");
601 /* create a border around the window */
603 box(chan_w
, '|', '-');
608 mvwaddstr(chan_w
, 0, (ncols
/ 2) - (strlen("Channels") / 2), "Channels");
611 /* no active channels */
614 mvwaddstr(chan_w
, 2, 2, "No active channels");
618 /* delete the channels window */
627 for (i
= 0; i
< ncontroller
; i
++)
629 if((get_controller_state(i
)) != CTRL_UP
)
632 if((ret_channel_state(i
, CHAN_B1
)) == CHAN_RUN
)
634 snprintf(buffer
, sizeof(buffer
), "%d - Controller %d channel %s", ncols
, i
, "B1");
635 mvwaddstr(chan_w
, nlines
, 2, buffer
);
636 cc
[ncols
- 1].cntl
= i
;
637 cc
[ncols
- 1].chn
= CHAN_B1
;
641 if((ret_channel_state(i
, CHAN_B2
)) == CHAN_RUN
)
643 snprintf(buffer
, sizeof(buffer
), "%d - Controller %d channel %s", ncols
, i
, "B2");
644 mvwaddstr(chan_w
, nlines
, 2, buffer
);
645 cc
[ncols
- 1].cntl
= i
;
646 cc
[ncols
- 1].chn
= CHAN_B2
;
657 FD_SET(STDIN_FILENO
, &set
);
658 timeout
.tv_sec
= WMTIMEOUT
;
661 /* if no char is available within timeout, exit menu*/
663 if((select(STDIN_FILENO
+ 1, &set
, NULL
, NULL
, &timeout
)) <= 0)
666 ncols
= wgetch(chan_w
);
668 if (!(isdigit(ncols
)))
674 nlines
= ncols
- '0';
676 if ((nlines
== 0) || (nlines
> cnt
))
682 if((cep
= get_cep_by_cc(cc
[nlines
-1].cntl
, cc
[nlines
-1].chn
))
685 log(LL_CHD
, "%05d %s manual disconnect (fullscreen menu)", cep
->cdid
, cep
->name
);
693 /* delete the channels window */
698 /*---------------------------------------------------------------------------*
699 * display card type information
700 *---------------------------------------------------------------------------*/
705 int nlines
, ncols
, pos_x
, pos_y
;
707 struct timeval timeout
;
710 nlines
= 6+ncontroller
;
715 /* create a new window in the lower screen area */
717 if((chan_w
= newwin(nlines
, ncols
, pos_y
, pos_x
)) == NULL
)
719 log(LL_WRN
, "ERROR, curses init channel window!");
723 /* create a border around the window */
725 box(chan_w
, '|', '-');
730 mvwaddstr(chan_w
, 0, (ncols
/ 2) - (strlen("Cards") / 2), "Cards");
733 mvwprintw(chan_w
, 2, 2, "ctrl description");
734 mvwprintw(chan_w
, 3, 2, "---- ----------------------------------------------");
735 for (i
= 0; i
< ncontroller
; i
++)
737 mvwprintw(chan_w
, 4+i
, 2, " #%d %s", i
,
738 name_of_controller(isdn_ctrl_tab
[i
].ctrl_type
,
739 isdn_ctrl_tab
[i
].card_type
));
745 FD_SET(STDIN_FILENO
, &set
);
746 timeout
.tv_sec
= WMTIMEOUT
*2;
749 if((select(STDIN_FILENO
+ 1, &set
, NULL
, NULL
, &timeout
)) <= 0)
759 /*---------------------------------------------------------------------------*
760 * display budget info
761 *---------------------------------------------------------------------------*/
766 int nlines
, ncols
, pos_x
, pos_y
;
768 struct timeval timeout
;
780 pos_x
= WMENU_POSCO
-3;
782 for(i
=0, j
=0; i
< nentries
; i
++) /* walk thru all entries */
784 cep
= &cfg_entry_tab
[i
]; /* get ptr to entry */
786 if(cep
->budget_callbackperiod
&& cep
->budget_callbackncalls
)
788 if(cep
->budget_calloutperiod
&& cep
->budget_calloutncalls
)
797 /* create a new window in the lower screen area */
799 if((bud_w
= newwin(nlines
, ncols
, pos_y
, pos_x
)) == NULL
)
801 log(LL_WRN
, "ERROR, curses init budget window!");
806 uptime
= difftime(now
, starttime
);
808 minutes
= (time_t) (uptime
/ 60) % 60;
809 hours
= (time_t) (uptime
/ (60*60)) % (60*60);
810 days
= (time_t) (uptime
/ (60*60*24)) % (60*60*24);
812 uptime
= uptime
/ (60*60);
814 /* create a border around the window */
816 box(bud_w
, '|', '-');
821 mvwaddstr(bud_w
, 0, (ncols
/ 2) - (strlen("Budget") / 2), "Budget");
824 mvwprintw(bud_w
, 1, 2, "isdnd uptime: %d %s - %d %s - %d %s",
826 days
== 1 ? "day" : "days",
828 hours
== 1 ? "hour" : "hours",
830 minutes
== 1 ? "minute" : "minutes");
832 mvwprintw(bud_w
, 2, 2, "name t period rest ncall rest rqsts /hr rdone /hr rrjct /hr ");
833 mvwprintw(bud_w
, 3, 2, "-------- - ------ ------ ----- ----- ----- ---- ----- ---- ----- ----");
835 for(i
=0, j
=4; i
< nentries
; i
++) /* walk thru all entries */
837 cep
= &cfg_entry_tab
[i
]; /* get ptr to enry */
839 if(cep
->budget_calloutperiod
&& cep
->budget_calloutncalls
)
841 mvwprintw(bud_w
, j
, 2, "%-8s %c %-6d %-6ld %-5d %-5d %-5d %-4.1f %-5d %-4.1f %-5d %-4.1f",
844 cep
->budget_calloutperiod
,
845 (long)(cep
->budget_calloutperiod_time
- now
),
846 cep
->budget_calloutncalls
,
847 cep
->budget_calloutncalls_cnt
,
848 cep
->budget_callout_req
,
849 (double)cep
->budget_callout_req
/ uptime
,
850 cep
->budget_callout_done
,
851 (double)cep
->budget_callout_done
/ uptime
,
852 cep
->budget_callout_rej
,
853 (double)cep
->budget_callout_rej
/ uptime
);
856 if(cep
->budget_callbackperiod
&& cep
->budget_callbackncalls
)
858 mvwprintw(bud_w
, j
, 2, "%-8s %c %-6d %-6ld %-5d %-5d %-5d %-4.1f %-5d %-4.1f %-5d %-4.1f",
859 (cep
->budget_calloutperiod
&& cep
->budget_calloutncalls
) ? "" : cep
->name
,
861 cep
->budget_callbackperiod
,
862 (long)(cep
->budget_callbackperiod_time
- now
),
863 cep
->budget_callbackncalls
,
864 cep
->budget_callbackncalls_cnt
,
865 cep
->budget_callback_req
,
866 (double)cep
->budget_callback_req
/ uptime
,
867 cep
->budget_callback_done
,
868 (double)cep
->budget_callback_done
/ uptime
,
869 cep
->budget_callback_rej
,
870 (double)cep
->budget_callback_rej
/ uptime
);
878 FD_SET(STDIN_FILENO
, &set
);
879 timeout
.tv_sec
= WMTIMEOUT
*3;
882 if((select(STDIN_FILENO
+ 1, &set
, NULL
, NULL
, &timeout
)) <= 0)