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 $
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 /*---------------------------------------------------------------------------*
49 * init curses fullscreen display
50 *---------------------------------------------------------------------------*/
59 initscr(); /* curses init */
61 if((COLS < 80) || (LINES < 24))
63 log(LL_ERR, "ERROR, minimal screensize must be 80x24, is %dx%d, terminating!",COLS, LINES);
70 uheight = ncontroller * 2; /* cards * b-channels */
71 lheight = LINES - uheight - 6 + 1; /* rest of display */
73 if((upper_w = newwin(uheight, COLS, UPPER_B, 0)) == NULL)
75 log(LL_ERR, "ERROR, curses init upper window, terminating!");
79 if((mid_w = newwin(1, COLS, UPPER_B+uheight+1, 0)) == NULL)
81 log(LL_ERR, "ERROR, curses init mid window, terminating!");
85 if((lower_w = newwin(lheight, COLS, UPPER_B+uheight+3, 0)) == NULL)
87 log(LL_ERR, "ERROR, curses init lower window, LINES = %d, lheight = %d, uheight = %d, terminating!", LINES, lheight, uheight);
93 snprintf(buffer, sizeof(buffer), "----- isdn controller channel state ------------- isdnd %02d.%02d.%d [pid %d] -", VERSION, REL, STEP, (int)getpid());
95 while(strlen(buffer) < COLS && strlen(buffer) < sizeof(buffer) - 1)
104 /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
105 addstr("c tei b remote iface dir outbytes obps inbytes ibps units");
107 snprintf(buffer, sizeof(buffer), "----- isdn userland interface state ------------------------------------------");
108 while(strlen(buffer) < COLS && strlen(buffer) < sizeof(buffer) - 1)
116 snprintf(buffer, sizeof(buffer), "----- isdnd logfile display --------------------------------------------------");
117 while(strlen(buffer) < COLS && strlen(buffer) < sizeof(buffer) - 1)
127 for(i=0, j=0; i <= ncontroller; i++, j+=2)
129 if(isdn_ctrl_tab[i].tei == -1)
130 mvwprintw(upper_w, j, H_CNTL, "%d --- 1 ", i);
132 mvwprintw(upper_w, j, H_CNTL, "%d %3d 1 ", i, isdn_ctrl_tab[i].tei);
133 mvwprintw(upper_w, j+1, H_CNTL, " L12 2 ");
137 for(i=0, j=0; i < nentries; i++) /* walk thru all entries */
139 p = &cfg_entry_tab[i]; /* get ptr to enry */
141 mvwprintw(mid_w, 0, j, "%s%d ", bdrivername(p->usrdevicename), p->usrdeviceunit);
145 j += ((strlen(bdrivername(p->usrdevicename)) + (p->usrdeviceunit > 9 ? 2 : 1) + 1));
149 wmove(lower_w, 0, 0);
155 /*---------------------------------------------------------------------------*
156 * curses menu for fullscreen command mode
157 *---------------------------------------------------------------------------*/
161 static char *menu[WMITEMS] =
163 "1 - (D)isplay refresh",
164 "2 - (H)angup (choose a channel)",
165 "3 - (R)eread config file",
166 "4 - (S)how card types",
167 "5 - (B)udget information",
168 "6 - (Q)uit the program",
175 struct timeval timeout;
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 log(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]);
214 FD_SET(STDIN_FILENO, &set);
215 timeout.tv_sec = WMTIMEOUT;
218 /* if no char is available within timeout, exit menu*/
220 if((select(STDIN_FILENO + 1, &set, NULL, NULL, &timeout)) <= 0)
228 case '\t': /* hilite next option */
229 mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
234 mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
238 case ('0'+WBUDGET+1): /* display budget info */
244 case ('0'+WREFRESH+1): /* display refresh */
250 case ('0'+WQUIT+1): /* quit program */
257 case ('0'+WHANGUP+1): /* hangup connection */
263 case ('0'+WREREAD+1): /* reread config file */
269 case ('0'+WSHOW+1): /* reread config file */
276 case '\r': /* exec highlighted option */
318 menuexit(WINDOW *menu_w)
320 int uheight = ncontroller * 2; /* cards * b-channels */
323 /* delete the menu window */
327 /* re-display the original lower window contents */
339 /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
340 addstr("c tei b remote iface dir outbytes obps inbytes ibps units");
342 sprintf(buffer, "----- isdn userland interface state ------------------------------------------");
343 while(strlen(buffer) < COLS)
351 sprintf(buffer, "----- isdnd logfile display --------------------------------------------------");
352 while(strlen(buffer) < COLS)
363 /*---------------------------------------------------------------------------*
364 * display the charge in units
365 *---------------------------------------------------------------------------*/
367 display_charge(cfg_entry_t *cep)
369 mvwprintw(upper_w, CHPOS(cep), H_UNITS, "%d", cep->charge);
374 /*---------------------------------------------------------------------------*
375 * display the calculated charge in units
376 *---------------------------------------------------------------------------*/
378 display_ccharge(cfg_entry_t *cep, int units)
380 mvwprintw(upper_w, CHPOS(cep), H_UNITS, "(%d)", units);
385 /*---------------------------------------------------------------------------*
386 * display accounting information
387 *---------------------------------------------------------------------------*/
389 display_acct(cfg_entry_t *cep)
391 mvwprintw(upper_w, CHPOS(cep), H_OUT, "%-10d", cep->outbytes);
392 mvwprintw(upper_w, CHPOS(cep), H_OUTBPS, "%-4d", cep->outbps);
393 mvwprintw(upper_w, CHPOS(cep), H_IN, "%-10d", cep->inbytes);
394 mvwprintw(upper_w, CHPOS(cep), H_INBPS, "%-4d", cep->inbps);
398 /*---------------------------------------------------------------------------*
399 * display connect information
400 *---------------------------------------------------------------------------*/
402 display_connect(cfg_entry_t *cep)
406 /* remote telephone number */
410 if(cep->direction == DIR_IN)
411 snprintf(buffer, sizeof(buffer), "%s", get_alias(cep->real_phone_incoming));
413 snprintf(buffer, sizeof(buffer), "%s", get_alias(cep->remote_phone_dialout));
417 if(cep->direction == DIR_IN)
418 snprintf(buffer, sizeof(buffer), "%s/%s", cep->name, cep->real_phone_incoming);
420 snprintf(buffer, sizeof(buffer), "%s/%s", cep->name, cep->remote_phone_dialout);
423 buffer[H_IFN - H_TELN - 1] = '\0';
425 mvwprintw(upper_w, CHPOS(cep), H_TELN, "%s", buffer);
429 mvwprintw(upper_w, CHPOS(cep), H_IFN, "%s%d ",
430 bdrivername(cep->usrdevicename), cep->usrdeviceunit);
432 mvwprintw(upper_w, CHPOS(cep), H_IO,
433 cep->direction == DIR_OUT ? "out" : "in");
435 mvwprintw(upper_w, CHPOS(cep), H_OUT, "-");
436 mvwprintw(upper_w, CHPOS(cep), H_OUTBPS, "-");
437 mvwprintw(upper_w, CHPOS(cep), H_IN, "-");
438 mvwprintw(upper_w, CHPOS(cep), H_INBPS, "-");
446 /*---------------------------------------------------------------------------*
447 * erase line at disconnect time
448 *---------------------------------------------------------------------------*/
450 display_disconnect(cfg_entry_t *cep)
452 wmove(upper_w, CHPOS(cep),
462 /*---------------------------------------------------------------------------*
463 * display interface up/down information
464 *---------------------------------------------------------------------------*/
466 display_updown(cfg_entry_t *cep, int updown)
473 mvwprintw(mid_w, 0, cep->fs_position, "%s%d ",
474 bdrivername(cep->usrdevicename), cep->usrdeviceunit);
480 /*---------------------------------------------------------------------------*
481 * display interface up/down information
482 *---------------------------------------------------------------------------*/
484 display_l12stat(int controller, int layer, int state)
486 if(controller > ncontroller)
488 if(!(layer == 1 || layer == 2))
498 mvwprintw(upper_w, (controller*2)+1, H_TEI+1, "1");
500 mvwprintw(upper_w, (controller*2)+1, H_TEI+2, "2");
504 mvwprintw(upper_w, (controller*2)+1, H_TEI+2, "2");
506 mvwprintw(upper_w, (controller*2)+1, H_TEI+1, "1");
513 /*---------------------------------------------------------------------------*
515 *---------------------------------------------------------------------------*/
517 display_tei(int controller, int tei)
519 if(controller > ncontroller)
523 mvwprintw(upper_w, controller*2, H_TEI, "---");
525 mvwprintw(upper_w, controller*2, H_TEI, "%3d", tei);
530 /*---------------------------------------------------------------------------*
532 *---------------------------------------------------------------------------*/
536 static char bell[1] = { 0x07 };
537 write(STDOUT_FILENO, &bell[0], 1);
540 /*---------------------------------------------------------------------------*
541 * display channel information for shutdown
542 *---------------------------------------------------------------------------*/
550 int nlines, ncols, pos_x, pos_y;
552 struct timeval timeout;
553 cfg_entry_t *cep = NULL;
555 /* need this later to close the connection */
561 for (i = 0; i < ncontroller; i++)
563 if((get_controller_state(i)) != CTRL_UP)
565 if((ret_channel_state(i, CHAN_B1)) == CHAN_RUN)
567 if((ret_channel_state(i, CHAN_B2)) == CHAN_RUN)
573 if ((cc = (struct ctlr_chan *)malloc (cnt *
574 sizeof (struct ctlr_chan))) == NULL)
587 pos_y = WMENU_POSLN + 4;
588 pos_x = WMENU_POSCO + 10;
590 /* create a new window in the lower screen area */
592 if((chan_w = newwin(nlines, ncols, pos_y, pos_x )) == NULL)
594 log(LL_WRN, "ERROR, curses init channel window!");
600 /* create a border around the window */
602 box(chan_w, '|', '-');
607 mvwaddstr(chan_w, 0, (ncols / 2) - (strlen("Channels") / 2), "Channels");
610 /* no active channels */
613 mvwaddstr(chan_w, 2, 2, "No active channels");
617 /* delete the channels window */
626 for (i = 0; i < ncontroller; i++)
628 if((get_controller_state(i)) != CTRL_UP)
631 if((ret_channel_state(i, CHAN_B1)) == CHAN_RUN)
633 snprintf(buffer, sizeof(buffer), "%d - Controller %d channel %s", ncols, i, "B1");
634 mvwaddstr(chan_w, nlines, 2, buffer);
635 cc[ncols - 1].cntl = i;
636 cc[ncols - 1].chn = CHAN_B1;
640 if((ret_channel_state(i, CHAN_B2)) == CHAN_RUN)
642 snprintf(buffer, sizeof(buffer), "%d - Controller %d channel %s", ncols, i, "B2");
643 mvwaddstr(chan_w, nlines, 2, buffer);
644 cc[ncols - 1].cntl = i;
645 cc[ncols - 1].chn = CHAN_B2;
656 FD_SET(STDIN_FILENO, &set);
657 timeout.tv_sec = WMTIMEOUT;
660 /* if no char is available within timeout, exit menu*/
662 if((select(STDIN_FILENO + 1, &set, NULL, NULL, &timeout)) <= 0)
665 ncols = wgetch(chan_w);
667 if (!(isdigit(ncols)))
673 nlines = ncols - '0';
675 if ((nlines == 0) || (nlines > cnt))
681 if((cep = get_cep_by_cc(cc[nlines-1].cntl, cc[nlines-1].chn))
684 log(LL_CHD, "%05d %s manual disconnect (fullscreen menu)", cep->cdid, cep->name);
692 /* delete the channels window */
697 /*---------------------------------------------------------------------------*
698 * display card type information
699 *---------------------------------------------------------------------------*/
704 int nlines, ncols, pos_x, pos_y;
706 struct timeval timeout;
709 nlines = 6+ncontroller;
714 /* create a new window in the lower screen area */
716 if((chan_w = newwin(nlines, ncols, pos_y, pos_x )) == NULL)
718 log(LL_WRN, "ERROR, curses init channel window!");
722 /* create a border around the window */
724 box(chan_w, '|', '-');
729 mvwaddstr(chan_w, 0, (ncols / 2) - (strlen("Cards") / 2), "Cards");
732 mvwprintw(chan_w, 2, 2, "ctrl description");
733 mvwprintw(chan_w, 3, 2, "---- ----------------------------------------------");
734 for (i = 0; i < ncontroller; i++)
736 mvwprintw(chan_w, 4+i, 2, " #%d %s", i,
737 name_of_controller(isdn_ctrl_tab[i].ctrl_type,
738 isdn_ctrl_tab[i].card_type));
744 FD_SET(STDIN_FILENO, &set);
745 timeout.tv_sec = WMTIMEOUT*2;
748 if((select(STDIN_FILENO + 1, &set, NULL, NULL, &timeout)) <= 0)
758 /*---------------------------------------------------------------------------*
759 * display budget info
760 *---------------------------------------------------------------------------*/
765 int nlines, ncols, pos_x, pos_y;
767 struct timeval timeout;
779 pos_x = WMENU_POSCO-3;
781 for(i=0, j=0; i < nentries; i++) /* walk thru all entries */
783 cep = &cfg_entry_tab[i]; /* get ptr to entry */
785 if(cep->budget_callbackperiod && cep->budget_callbackncalls)
787 if(cep->budget_calloutperiod && cep->budget_calloutncalls)
796 /* create a new window in the lower screen area */
798 if((bud_w = newwin(nlines, ncols, pos_y, pos_x )) == NULL)
800 log(LL_WRN, "ERROR, curses init budget window!");
805 uptime = difftime(now, starttime);
807 minutes = (time_t) (uptime / 60) % 60;
808 hours = (time_t) (uptime / (60*60)) % (60*60);
809 days = (time_t) (uptime / (60*60*24)) % (60*60*24);
811 uptime = uptime / (60*60);
813 /* create a border around the window */
815 box(bud_w, '|', '-');
820 mvwaddstr(bud_w, 0, (ncols / 2) - (strlen("Budget") / 2), "Budget");
823 mvwprintw(bud_w, 1, 2, "isdnd uptime: %d %s - %d %s - %d %s",
825 days == 1 ? "day" : "days",
827 hours == 1 ? "hour" : "hours",
829 minutes == 1 ? "minute" : "minutes");
831 mvwprintw(bud_w, 2, 2, "name t period rest ncall rest rqsts /hr rdone /hr rrjct /hr ");
832 mvwprintw(bud_w, 3, 2, "-------- - ------ ------ ----- ----- ----- ---- ----- ---- ----- ----");
834 for(i=0, j=4; i < nentries; i++) /* walk thru all entries */
836 cep = &cfg_entry_tab[i]; /* get ptr to enry */
838 if(cep->budget_calloutperiod && cep->budget_calloutncalls)
840 mvwprintw(bud_w, j, 2, "%-8s %c %-6d %-6ld %-5d %-5d %-5d %-4.1f %-5d %-4.1f %-5d %-4.1f",
843 cep->budget_calloutperiod,
844 (long)(cep->budget_calloutperiod_time - now),
845 cep->budget_calloutncalls,
846 cep->budget_calloutncalls_cnt,
847 cep->budget_callout_req,
848 (double)cep->budget_callout_req / uptime,
849 cep->budget_callout_done,
850 (double)cep->budget_callout_done / uptime,
851 cep->budget_callout_rej,
852 (double)cep->budget_callout_rej / uptime);
855 if(cep->budget_callbackperiod && cep->budget_callbackncalls)
857 mvwprintw(bud_w, j, 2, "%-8s %c %-6d %-6ld %-5d %-5d %-5d %-4.1f %-5d %-4.1f %-5d %-4.1f",
858 (cep->budget_calloutperiod && cep->budget_calloutncalls) ? "" : cep->name,
860 cep->budget_callbackperiod,
861 (long)(cep->budget_callbackperiod_time - now),
862 cep->budget_callbackncalls,
863 cep->budget_callbackncalls_cnt,
864 cep->budget_callback_req,
865 (double)cep->budget_callback_req / uptime,
866 cep->budget_callback_done,
867 (double)cep->budget_callback_done / uptime,
868 cep->budget_callback_rej,
869 (double)cep->budget_callback_rej / uptime);
877 FD_SET(STDIN_FILENO, &set);
878 timeout.tv_sec = WMTIMEOUT*3;
881 if((select(STDIN_FILENO + 1, &set, NULL, NULL, &timeout)) <= 0)