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.10 2009/04/16 05:56:32 lukem Exp $
34 * last edit-date: [Thu Jun 1 16:24:43 2000]
36 *---------------------------------------------------------------------------*/
42 #define CHPOS(cfgp) (((cfgp)->isdncontrollerused*2) + (cfgp)->isdnchannelused)
44 static void display_budget(void);
45 static void display_cards(void);
46 static void menuexit(WINDOW
*menu_w
);
48 static int ncontroller
= 0;
50 /*---------------------------------------------------------------------------*
51 * init curses fullscreen display
52 *---------------------------------------------------------------------------*/
60 struct isdn_ctrl_state
*ctrl
;
62 initscr(); /* curses init */
63 ncontroller
= count_ctrl_states();
65 if ((COLS
< 80) || (LINES
< 24))
67 logit(LL_ERR
, "ERROR, minimal screensize must be 80x24, is %dx%d, terminating!",COLS
, LINES
);
74 uheight
= ncontroller
* 2; /* cards * b-channels */
75 lheight
= LINES
- uheight
- 6 + 1; /* rest of display */
77 if ((upper_w
= newwin(uheight
, COLS
, UPPER_B
, 0)) == NULL
)
79 logit(LL_ERR
, "ERROR, curses init upper window, terminating!");
83 if ((mid_w
= newwin(1, COLS
, UPPER_B
+uheight
+1, 0)) == NULL
)
85 logit(LL_ERR
, "ERROR, curses init mid window, terminating!");
89 if ((lower_w
= newwin(lheight
, COLS
, UPPER_B
+uheight
+3, 0)) == NULL
)
91 logit(LL_ERR
, "ERROR, curses init lower window, LINES = %d, lheight = %d, uheight = %d, terminating!", LINES
, lheight
, uheight
);
97 snprintf(buffer
, sizeof(buffer
), "----- isdn controller channel state ------------- isdnd %02d.%02d.%d [pid %d] -", VERSION
, REL
, STEP
, (int)getpid());
99 while((int)strlen(buffer
) < COLS
&& strlen(buffer
) < sizeof(buffer
) - 1)
100 strlcat(buffer
, "-", sizeof(buffer
));
108 /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
109 addstr("# tei b remote iface dir outbytes obps inbytes ibps units");
111 snprintf(buffer
, sizeof(buffer
), "----- isdn userland interface state ------------------------------------------");
112 while((int)strlen(buffer
) < COLS
&& strlen(buffer
) < sizeof(buffer
) - 1)
113 strlcat(buffer
, "-", sizeof(buffer
));
120 snprintf(buffer
, sizeof(buffer
), "----- isdnd logfile display --------------------------------------------------");
121 while((int)strlen(buffer
) < COLS
&& strlen(buffer
) < sizeof(buffer
) - 1)
122 strlcat(buffer
, "-", sizeof(buffer
));
131 for (ctrl
= get_first_ctrl_state(), i
=j
=0; ctrl
; ctrl
= NEXT_CTRL(ctrl
), i
++, j
+=2)
134 mvwprintw(upper_w
, j
, H_CNTL
, "%d --- 1 ", i
);
136 mvwprintw(upper_w
, j
, H_CNTL
, "%d %3d 1 ", i
, ctrl
->tei
);
137 mvwprintw(upper_w
, j
+1, H_CNTL
, " L12 2 ");
141 for (p
= get_first_cfg_entry(), j
=0; p
; p
= NEXT_CFE(p
)) {
142 mvwprintw(mid_w
, 0, j
, "%s%d ", p
->usrdevicename
, p
->usrdeviceunit
);
146 j
+= ((strlen(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 const 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",
175 struct pollfd set
[1];
177 /* create a new window in the lower screen area */
179 if ((menu_w
= newwin(WMENU_HGT
, WMENU_LEN
, WMENU_POSLN
, WMENU_POSCO
)) == NULL
)
181 logit(LL_WRN
, "ERROR, curses init menu window!");
185 /* create a border around the window */
187 box(menu_w
, '|', '-');
192 mvwaddstr(menu_w
, 0, (WMENU_LEN
/ 2) - (strlen(WMENU_TITLE
) / 2), WMENU_TITLE
);
195 /* fill the window with the menu options */
197 for (mpos
=0; mpos
<= (WMITEMS
-1); mpos
++)
198 mvwaddstr(menu_w
, mpos
+ 2, 2, menu
[mpos
]);
200 /* highlight the first menu option */
204 mvwaddstr(menu_w
, mpos
+ 2, 2, menu
[mpos
]);
209 set
[0].fd
= STDIN_FILENO
;
210 set
[0].events
= POLLIN
;
215 /* if no char is available within timeout, exit menu*/
217 if ((poll(set
, 1, WMTIMEOUT
* 1000)) <= 0)
225 case '\t': /* hilite next option */
226 mvwaddstr(menu_w
, mpos
+ 2, 2, menu
[mpos
]);
231 mvwaddstr(menu_w
, mpos
+ 2, 2, menu
[mpos
]);
235 case ('0'+WBUDGET
+1): /* display budget info */
241 case ('0'+WREFRESH
+1): /* display refresh */
247 case ('0'+WQUIT
+1): /* quit program */
254 case ('0'+WHANGUP
+1): /* hangup connection */
260 case ('0'+WREREAD
+1): /* reread config file */
266 case ('0'+WSHOW
+1): /* reread config file */
273 case '\r': /* exec highlighted option */
315 menuexit(WINDOW
*menu_w
)
317 int uheight
= ncontroller
* 2; /* cards * b-channels */
320 /* delete the menu window */
324 /* re-display the original lower window contents */
336 /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
337 addstr("# tei b remote iface dir outbytes obps inbytes ibps units");
339 snprintf(buffer
, sizeof(buffer
), "----- isdn userland interface state ------------------------------------------");
340 while((int)strlen(buffer
) < COLS
)
341 strlcat(buffer
, "-", sizeof(buffer
));
348 snprintf(buffer
, sizeof(buffer
), "----- isdnd logfile display --------------------------------------------------");
349 while((int)strlen(buffer
) < COLS
)
350 strlcat(buffer
, "-", sizeof(buffer
));
360 /*---------------------------------------------------------------------------*
361 * display the charge in units
362 *---------------------------------------------------------------------------*/
364 display_charge(struct cfg_entry
*cep
)
366 mvwprintw(upper_w
, CHPOS(cep
), H_UNITS
, "%d", cep
->charge
);
371 /*---------------------------------------------------------------------------*
372 * display the calculated charge in units
373 *---------------------------------------------------------------------------*/
375 display_ccharge(struct cfg_entry
*cep
, int units
)
377 mvwprintw(upper_w
, CHPOS(cep
), H_UNITS
, "(%d)", units
);
382 /*---------------------------------------------------------------------------*
383 * display accounting information
384 *---------------------------------------------------------------------------*/
386 display_acct(struct cfg_entry
*cep
)
388 mvwprintw(upper_w
, CHPOS(cep
), H_OUT
, "%-10d", cep
->outbytes
);
389 mvwprintw(upper_w
, CHPOS(cep
), H_OUTBPS
, "%-4d", cep
->outbps
);
390 mvwprintw(upper_w
, CHPOS(cep
), H_IN
, "%-10d", cep
->inbytes
);
391 mvwprintw(upper_w
, CHPOS(cep
), H_INBPS
, "%-4d", cep
->inbps
);
395 /*---------------------------------------------------------------------------*
396 * display connect information
397 *---------------------------------------------------------------------------*/
399 display_connect(struct cfg_entry
*cep
)
403 /* remote telephone number */
407 if (cep
->direction
== DIR_IN
)
408 snprintf(buffer
, sizeof(buffer
), "%s", get_alias(cep
->real_phone_incoming
));
410 snprintf(buffer
, sizeof(buffer
), "%s", get_alias(cep
->remote_phone_dialout
));
414 if (cep
->direction
== DIR_IN
)
415 snprintf(buffer
, sizeof(buffer
), "%s/%s", cep
->name
, cep
->real_phone_incoming
);
417 snprintf(buffer
, sizeof(buffer
), "%s/%s", cep
->name
, cep
->remote_phone_dialout
);
420 buffer
[H_IFN
- H_TELN
- 1] = '\0';
422 mvwprintw(upper_w
, CHPOS(cep
), H_TELN
, "%s", buffer
);
426 mvwprintw(upper_w
, CHPOS(cep
), H_IFN
, "%s%d ",
427 cep
->usrdevicename
, cep
->usrdeviceunit
);
429 mvwprintw(upper_w
, CHPOS(cep
), H_IO
,
430 cep
->direction
== DIR_OUT
? "out" : "in");
432 mvwprintw(upper_w
, CHPOS(cep
), H_OUT
, "-");
433 mvwprintw(upper_w
, CHPOS(cep
), H_OUTBPS
, "-");
434 mvwprintw(upper_w
, CHPOS(cep
), H_IN
, "-");
435 mvwprintw(upper_w
, CHPOS(cep
), H_INBPS
, "-");
443 /*---------------------------------------------------------------------------*
444 * erase line at disconnect time
445 *---------------------------------------------------------------------------*/
447 display_disconnect(struct cfg_entry
*cep
)
449 wmove(upper_w
, CHPOS(cep
),
459 /*---------------------------------------------------------------------------*
460 * display interface up/down information
461 *---------------------------------------------------------------------------*/
463 display_updown(struct cfg_entry
*cep
, int updown
)
470 mvwprintw(mid_w
, 0, cep
->fs_position
, "%s%d ",
471 cep
->usrdevicename
, cep
->usrdeviceunit
);
477 /*---------------------------------------------------------------------------*
478 * display interface up/down information
479 *---------------------------------------------------------------------------*/
481 display_l12stat(int controller
, int layer
, int state
)
483 if (controller
> ncontroller
)
485 if (!(layer
== 1 || layer
== 2))
495 mvwprintw(upper_w
, (controller
*2)+1, H_TEI
+1, "1");
497 mvwprintw(upper_w
, (controller
*2)+1, H_TEI
+2, "2");
501 mvwprintw(upper_w
, (controller
*2)+1, H_TEI
+2, "2");
503 mvwprintw(upper_w
, (controller
*2)+1, H_TEI
+1, "1");
510 /*---------------------------------------------------------------------------*
512 *---------------------------------------------------------------------------*/
514 display_tei(int controller
, int tei
)
516 if (controller
> ncontroller
)
520 mvwprintw(upper_w
, controller
*2, H_TEI
, "---");
522 mvwprintw(upper_w
, controller
*2, H_TEI
, "%3d", tei
);
527 /*---------------------------------------------------------------------------*
529 *---------------------------------------------------------------------------*/
533 static char bell
[1] = { 0x07 };
534 write(STDOUT_FILENO
, &bell
[0], 1);
537 /*---------------------------------------------------------------------------*
538 * display channel information for shutdown
539 *---------------------------------------------------------------------------*/
546 int nlines
, ncols
, pos_x
, pos_y
;
547 struct pollfd set
[1];
548 struct cfg_entry
*cep
= NULL
;
549 struct isdn_ctrl_state
*ctrl
;
551 /* need this later to close the connection */
557 for (ctrl
= get_first_ctrl_state(); ctrl
; ctrl
= NEXT_CTRL(ctrl
)) {
558 if ((get_controller_state(ctrl
)) != CTRL_UP
)
560 for (j
= 0; j
< ctrl
->nbch
; j
++)
561 if ((ret_channel_state(ctrl
, j
)) == CHAN_RUN
)
567 if ((cc
= (struct ctlr_chan
*)malloc (cnt
*
568 sizeof (struct ctlr_chan
))) == NULL
)
581 pos_y
= WMENU_POSLN
+ 4;
582 pos_x
= WMENU_POSCO
+ 10;
584 /* create a new window in the lower screen area */
586 if ((chan_w
= newwin(nlines
, ncols
, pos_y
, pos_x
)) == NULL
)
588 logit(LL_WRN
, "ERROR, curses init channel window!");
594 /* create a border around the window */
596 box(chan_w
, '|', '-');
601 mvwaddstr(chan_w
, 0, (ncols
/ 2) - (strlen("Channels") / 2), "Channels");
604 /* no active channels */
607 mvwaddstr(chan_w
, 2, 2, "No active channels");
611 /* delete the channels window */
620 for (ctrl
= get_first_ctrl_state(), i
= 0; ctrl
; ctrl
= NEXT_CTRL(ctrl
), i
++) {
621 if ((get_controller_state(ctrl
)) != CTRL_UP
)
624 for (j
= 0; j
< ctrl
->nbch
; i
++)
626 if ((ret_channel_state(ctrl
, j
)) == CHAN_RUN
)
628 snprintf(buffer
, sizeof(buffer
), "%d - Controller %d channel B%d", ncols
, i
, j
);
629 mvwaddstr(chan_w
, nlines
, 2, buffer
);
630 cc
[ncols
- 1].cntl
= i
;
631 cc
[ncols
- 1].chn
= j
;
638 set
[0].fd
= STDIN_FILENO
;
639 set
[0].events
= POLLIN
;
644 /* if no char is available within timeout, exit menu*/
646 if ((poll(set
, 1, WMTIMEOUT
* 1000)) <= 0)
649 ncols
= wgetch(chan_w
);
651 if (!(isdigit(ncols
)))
657 nlines
= ncols
- '0';
659 if ((nlines
== 0) || (nlines
> cnt
))
665 if ((cep
= get_cep_by_cc(cc
[nlines
-1].cntl
, cc
[nlines
-1].chn
))
668 logit(LL_CHD
, "%05d %s manual disconnect (fullscreen menu)", cep
->cdid
, cep
->name
);
676 /* delete the channels window */
681 /*---------------------------------------------------------------------------*
682 * display card type information
683 *---------------------------------------------------------------------------*/
688 int nlines
, ncols
, pos_x
, pos_y
;
689 struct pollfd set
[1];
691 struct isdn_ctrl_state
*ctrl
;
693 nlines
= 6+ncontroller
;
698 /* create a new window in the lower screen area */
700 if ((chan_w
= newwin(nlines
, ncols
, pos_y
, pos_x
)) == NULL
)
702 logit(LL_WRN
, "ERROR, curses init channel window!");
706 /* create a border around the window */
708 box(chan_w
, '|', '-');
713 mvwaddstr(chan_w
, 0, (ncols
/ 2) - (strlen("Cards") / 2), "Cards");
716 mvwprintw(chan_w
, 2, 2, "ctrl device");
717 mvwprintw(chan_w
, 3, 2, "---- ----------------------------------------------");
718 for (i
= 0, ctrl
= get_first_ctrl_state(); ctrl
; ctrl
= NEXT_CTRL(ctrl
), i
++)
720 mvwprintw(chan_w
, 4+i
, 2, " #%d %s: %s", i
,
727 set
[0].fd
= STDIN_FILENO
;
728 set
[0].events
= POLLIN
;
730 if ((poll(set
, 1, WMTIMEOUT
*2 * 1000)) <= 0)
740 /*---------------------------------------------------------------------------*
741 * display budget info
742 *---------------------------------------------------------------------------*/
747 int nlines
, ncols
, pos_x
, pos_y
;
748 struct pollfd set
[1];
750 struct cfg_entry
*cep
;
760 pos_x
= WMENU_POSCO
-3;
762 for (cep
= get_first_cfg_entry(), j
=0; cep
; cep
= NEXT_CFE(cep
)) {
763 if (cep
->budget_callbackperiod
&& cep
->budget_callbackncalls
)
765 if (cep
->budget_calloutperiod
&& cep
->budget_calloutncalls
)
774 /* create a new window in the lower screen area */
776 if ((bud_w
= newwin(nlines
, ncols
, pos_y
, pos_x
)) == NULL
)
778 logit(LL_WRN
, "ERROR, curses init budget window!");
783 uptime
= difftime(now
, starttime
);
785 minutes
= (time_t) (uptime
/ 60) % 60;
786 hours
= (time_t) (uptime
/ (60*60)) % (60*60);
787 days
= (time_t) (uptime
/ (60*60*24)) % (60*60*24);
789 uptime
= uptime
/ (60*60);
791 /* create a border around the window */
793 box(bud_w
, '|', '-');
798 mvwaddstr(bud_w
, 0, (ncols
/ 2) - (strlen("Budget") / 2), "Budget");
801 mvwprintw(bud_w
, 1, 2, "isdnd uptime: %d %s - %d %s - %d %s",
803 days
== 1 ? "day" : "days",
805 hours
== 1 ? "hour" : "hours",
807 minutes
== 1 ? "minute" : "minutes");
809 mvwprintw(bud_w
, 2, 2, "name t period rest ncall rest rqsts /hr rdone /hr rrjct /hr ");
810 mvwprintw(bud_w
, 3, 2, "-------- - ------ ------ ----- ----- ----- ---- ----- ---- ----- ----");
812 for (cep
= get_first_cfg_entry(), j
=4; cep
; cep
= NEXT_CFE(cep
)) {
813 if (cep
->budget_calloutperiod
&& cep
->budget_calloutncalls
)
815 mvwprintw(bud_w
, j
, 2, "%-8s %c %-6d %-6ld %-5d %-5d %-5d %-4.1f %-5d %-4.1f %-5d %-4.1f",
818 cep
->budget_calloutperiod
,
819 (long)(cep
->budget_calloutperiod_time
- now
),
820 cep
->budget_calloutncalls
,
821 cep
->budget_calloutncalls_cnt
,
822 cep
->budget_callout_req
,
823 (double)cep
->budget_callout_req
/ uptime
,
824 cep
->budget_callout_done
,
825 (double)cep
->budget_callout_done
/ uptime
,
826 cep
->budget_callout_rej
,
827 (double)cep
->budget_callout_rej
/ uptime
);
830 if (cep
->budget_callbackperiod
&& cep
->budget_callbackncalls
)
832 mvwprintw(bud_w
, j
, 2, "%-8s %c %-6d %-6ld %-5d %-5d %-5d %-4.1f %-5d %-4.1f %-5d %-4.1f",
833 (cep
->budget_calloutperiod
&& cep
->budget_calloutncalls
) ? "" : cep
->name
,
835 cep
->budget_callbackperiod
,
836 (long)(cep
->budget_callbackperiod_time
- now
),
837 cep
->budget_callbackncalls
,
838 cep
->budget_callbackncalls_cnt
,
839 cep
->budget_callback_req
,
840 (double)cep
->budget_callback_req
/ uptime
,
841 cep
->budget_callback_done
,
842 (double)cep
->budget_callback_done
/ uptime
,
843 cep
->budget_callback_rej
,
844 (double)cep
->budget_callback_rej
/ uptime
);
851 set
[0].fd
= STDIN_FILENO
;
852 set
[0].events
= POLLIN
;
854 if ((poll(set
, 1, WMTIMEOUT
*3 * 1000)) <= 0)