1/*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. 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 * 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.
12 *
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
23 * SUCH DAMAGE.
24 *
25 *---------------------------------------------------------------------------
26 *
27 *	i4b daemon - curses fullscreen output
28 *	-------------------------------------
29 *
30 *	$Id: curses.c,v 1.10 2009/04/16 05:56:32 lukem Exp $
31 *
32 * $FreeBSD$
33 *
34 *      last edit-date: [Thu Jun  1 16:24:43 2000]
35 *
36 *---------------------------------------------------------------------------*/
37
38#ifdef USE_CURSES
39
40#include "isdnd.h"
41
42#define CHPOS(cfgp) (((cfgp)->isdncontrollerused*2) + (cfgp)->isdnchannelused)
43
44static void display_budget(void);
45static void display_cards(void);
46static void menuexit(WINDOW *menu_w);
47
48static int ncontroller = 0;
49
50/*---------------------------------------------------------------------------*
51 *	init curses fullscreen display
52 *---------------------------------------------------------------------------*/
53void
54init_screen(void)
55{
56	char buffer[512];
57	int uheight, lheight;
58	int i, j;
59	struct cfg_entry *p;
60	struct isdn_ctrl_state *ctrl;
61
62	initscr();			/* curses init */
63	ncontroller = count_ctrl_states();
64
65	if ((COLS < 80) || (LINES < 24))
66	{
67		logit(LL_ERR, "ERROR, minimal screensize must be 80x24, is %dx%d, terminating!",COLS, LINES);
68		do_exit(1);
69	}
70
71	noecho();
72	raw();
73
74	uheight = ncontroller * 2; /* cards * b-channels */
75	lheight = LINES - uheight - 6 + 1; /* rest of display */
76
77	if ((upper_w = newwin(uheight, COLS, UPPER_B, 0)) == NULL)
78	{
79		logit(LL_ERR, "ERROR, curses init upper window, terminating!");
80		exit(1);
81	}
82
83	if ((mid_w = newwin(1, COLS, UPPER_B+uheight+1, 0)) == NULL)
84	{
85		logit(LL_ERR, "ERROR, curses init mid window, terminating!");
86		exit(1);
87	}
88
89	if ((lower_w = newwin(lheight, COLS, UPPER_B+uheight+3, 0)) == NULL)
90	{
91		logit(LL_ERR, "ERROR, curses init lower window, LINES = %d, lheight = %d, uheight = %d, terminating!", LINES, lheight, uheight);
92		exit(1);
93	}
94
95	scrollok(lower_w, 1);
96
97	snprintf(buffer, sizeof(buffer), "----- isdn controller channel state ------------- isdnd %02d.%02d.%d [pid %d] -", VERSION, REL, STEP, (int)getpid());
98
99	while((int)strlen(buffer) < COLS && strlen(buffer) < sizeof(buffer) - 1)
100		strlcat(buffer, "-", sizeof(buffer));
101
102	move(0, 0);
103	standout();
104	addstr(buffer);
105	standend();
106
107	move(1, 0);
108	/*      01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
109	addstr("# tei b remote                 iface  dir outbytes   obps inbytes    ibps  units");
110
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));
114
115	move(uheight+2, 0);
116	standout();
117	addstr(buffer);
118	standend();
119
120	snprintf(buffer, sizeof(buffer), "----- isdnd logfile display --------------------------------------------------");
121	while((int)strlen(buffer) < COLS && strlen(buffer) < sizeof(buffer) - 1)
122		strlcat(buffer, "-", sizeof(buffer));
123
124	move(uheight+4, 0);
125	standout();
126	addstr(buffer);
127	standend();
128
129	refresh();
130
131	for (ctrl = get_first_ctrl_state(), i=j=0; ctrl; ctrl = NEXT_CTRL(ctrl), i++, j+=2)
132	{
133		if (ctrl->tei == -1)
134			mvwprintw(upper_w, j,   H_CNTL, "%d --- 1 ", i);
135		else
136			mvwprintw(upper_w, j,   H_CNTL, "%d %3d 1 ", i, ctrl->tei);
137		mvwprintw(upper_w, j+1, H_CNTL, "  L12 2 ");
138	}
139	wrefresh(upper_w);
140
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);
143
144		p->fs_position = j;
145
146		j += ((strlen(p->usrdevicename) + (p->usrdeviceunit > 9 ? 2 : 1) + 1));
147	}
148	wrefresh(mid_w);
149
150	wmove(lower_w, 0, 0);
151	wrefresh(lower_w);
152
153	curses_ready = 1;
154}
155
156/*---------------------------------------------------------------------------*
157 *	curses menu for fullscreen command mode
158 *---------------------------------------------------------------------------*/
159void
160do_menu(void)
161{
162	static const char *menu[WMITEMS] =
163	{
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",
170	};
171
172	WINDOW *menu_w;
173	int c;
174	int mpos;
175	struct pollfd set[1];
176
177	/* create a new window in the lower screen area */
178
179	if ((menu_w = newwin(WMENU_HGT, WMENU_LEN, WMENU_POSLN, WMENU_POSCO )) == NULL)
180	{
181		logit(LL_WRN, "ERROR, curses init menu window!");
182		return;
183	}
184
185	/* create a border around the window */
186
187	box(menu_w, '|', '-');
188
189	/* add a title */
190
191	wstandout(menu_w);
192	mvwaddstr(menu_w, 0, (WMENU_LEN / 2) - (strlen(WMENU_TITLE) / 2), WMENU_TITLE);
193	wstandend(menu_w);
194
195	/* fill the window with the menu options */
196
197	for (mpos=0; mpos <= (WMITEMS-1); mpos++)
198		mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
199
200	/* highlight the first menu option */
201
202	mpos = 0;
203	wstandout(menu_w);
204	mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
205	wstandend(menu_w);
206
207	/* input loop */
208
209	set[0].fd = STDIN_FILENO;
210	set[0].events = POLLIN;
211	for (;;)
212	{
213		wrefresh(menu_w);
214
215		/* if no char is available within timeout, exit menu*/
216
217		if ((poll(set, 1, WMTIMEOUT * 1000)) <= 0)
218			goto mexit;
219
220		c = wgetch(menu_w);
221
222		switch (c)
223		{
224		case ' ':
225		case '\t':	/* hilite next option */
226			mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
227			mpos++;
228			if (mpos >= WMITEMS)
229				mpos = 0;
230			wstandout(menu_w);
231			mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
232			wstandend(menu_w);
233			break;
234
235		case ('0'+WBUDGET+1):	/* display budget info */
236		case 'B':
237		case 'b':
238			display_budget();
239			goto mexit;
240
241		case ('0'+WREFRESH+1):	/* display refresh */
242		case 'D':
243		case 'd':
244			wrefresh(curscr);
245			goto mexit;
246
247		case ('0'+WQUIT+1):	/* quit program */
248		case 'Q':
249		case 'q':
250			menuexit(menu_w);
251			do_exit(0);
252			goto mexit;
253
254		case ('0'+WHANGUP+1):	/* hangup connection */
255		case 'H':
256		case 'h':
257			display_chans();
258			goto mexit;
259
260		case ('0'+WREREAD+1):	/* reread config file */
261		case 'R':
262		case 'r':
263			rereadconfig(42);
264			goto mexit;
265
266		case ('0'+WSHOW+1):	/* reread config file */
267		case 'S':
268		case 's':
269			display_cards();
270			goto mexit;
271
272		case '\n':
273		case '\r':	/* exec highlighted option */
274			switch (mpos)
275			{
276			case WREFRESH:
277				wrefresh(curscr);
278				break;
279
280			case WQUIT:
281				menuexit(menu_w);
282				do_exit(0);
283				break;
284
285			case WHANGUP:
286				display_chans();
287				break;
288
289			case WREREAD:
290				rereadconfig(42);
291				break;
292
293			case WBUDGET:
294				display_budget();
295				break;
296
297			case WSHOW:
298				display_cards();
299				break;
300			}
301			goto mexit;
302			break;
303
304		default:
305			goto mexit;
306			break;
307		}
308	}
309
310mexit:
311	menuexit(menu_w);
312}
313
314static void
315menuexit(WINDOW *menu_w)
316{
317	int uheight = ncontroller * 2; /* cards * b-channels */
318	char buffer[512];
319
320	/* delete the menu window */
321
322	delwin(menu_w);
323
324	/* re-display the original lower window contents */
325
326	touchwin(mid_w);
327	wrefresh(mid_w);
328
329	touchwin(lower_w);
330	wrefresh(lower_w);
331
332	touchwin(upper_w);
333	wrefresh(upper_w);
334
335	move(1, 0);
336	/*      01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
337	addstr("# tei b remote                 iface  dir outbytes   obps inbytes    ibps  units");
338
339	snprintf(buffer, sizeof(buffer), "----- isdn userland interface state ------------------------------------------");
340	while((int)strlen(buffer) < COLS)
341		strlcat(buffer, "-", sizeof(buffer));
342
343	move(uheight+2, 0);
344	standout();
345	addstr(buffer);
346	standend();
347
348	snprintf(buffer, sizeof(buffer), "----- isdnd logfile display --------------------------------------------------");
349	while((int)strlen(buffer) < COLS)
350		strlcat(buffer, "-", sizeof(buffer));
351
352	move(uheight+4, 0);
353	standout();
354	addstr(buffer);
355	standend();
356
357	refresh();
358}
359
360/*---------------------------------------------------------------------------*
361 *	display the charge in units
362 *---------------------------------------------------------------------------*/
363void
364display_charge(struct cfg_entry *cep)
365{
366	mvwprintw(upper_w, CHPOS(cep), H_UNITS, "%d", cep->charge);
367	wclrtoeol(upper_w);
368	wrefresh(upper_w);
369}
370
371/*---------------------------------------------------------------------------*
372 *	display the calculated charge in units
373 *---------------------------------------------------------------------------*/
374void
375display_ccharge(struct cfg_entry *cep, int units)
376{
377	mvwprintw(upper_w, CHPOS(cep), H_UNITS, "(%d)", units);
378	wclrtoeol(upper_w);
379	wrefresh(upper_w);
380}
381
382/*---------------------------------------------------------------------------*
383 *	display accounting information
384 *---------------------------------------------------------------------------*/
385void
386display_acct(struct cfg_entry *cep)
387{
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);
392	wrefresh(upper_w);
393}
394
395/*---------------------------------------------------------------------------*
396 *	display connect information
397 *---------------------------------------------------------------------------*/
398void
399display_connect(struct cfg_entry *cep)
400{
401	char buffer[256];
402
403	/* remote telephone number */
404
405	if (aliasing)
406	{
407		if (cep->direction == DIR_IN)
408			snprintf(buffer, sizeof(buffer), "%s", get_alias(cep->real_phone_incoming));
409		else
410			snprintf(buffer, sizeof(buffer), "%s", get_alias(cep->remote_phone_dialout));
411	}
412	else
413	{
414		if (cep->direction == DIR_IN)
415			snprintf(buffer, sizeof(buffer), "%s/%s", cep->name, cep->real_phone_incoming);
416		else
417			snprintf(buffer, sizeof(buffer), "%s/%s", cep->name, cep->remote_phone_dialout);
418	}
419
420	buffer[H_IFN - H_TELN - 1] = '\0';
421
422	mvwprintw(upper_w, CHPOS(cep), H_TELN, "%s", buffer);
423
424	/* interface */
425
426	mvwprintw(upper_w, CHPOS(cep), H_IFN, "%s%d ",
427			cep->usrdevicename, cep->usrdeviceunit);
428
429	mvwprintw(upper_w, CHPOS(cep), H_IO,
430		cep->direction == DIR_OUT ? "out" : "in");
431
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,  "-");
436
437	if (do_bell)
438		display_bell();
439
440	wrefresh(upper_w);
441}
442
443/*---------------------------------------------------------------------------*
444 *	erase line at disconnect time
445 *---------------------------------------------------------------------------*/
446void
447display_disconnect(struct cfg_entry *cep)
448{
449	wmove(upper_w, CHPOS(cep),
450		 H_TELN);
451	wclrtoeol(upper_w);
452	wrefresh(upper_w);
453
454	if (do_bell)
455		display_bell();
456
457}
458
459/*---------------------------------------------------------------------------*
460 *	display interface up/down information
461 *---------------------------------------------------------------------------*/
462void
463display_updown(struct cfg_entry *cep, int updown)
464{
465	if (updown)
466		wstandend(mid_w);
467	else
468		wstandout(mid_w);
469
470	mvwprintw(mid_w, 0, cep->fs_position, "%s%d ",
471			cep->usrdevicename, cep->usrdeviceunit);
472
473	wstandend(mid_w);
474	wrefresh(mid_w);
475}
476
477/*---------------------------------------------------------------------------*
478 *	display interface up/down information
479 *---------------------------------------------------------------------------*/
480void
481display_l12stat(int controller, int layer, int state)
482{
483	if (controller > ncontroller)
484		return;
485	if (!(layer == 1 || layer == 2))
486		return;
487
488	if (state)
489		wstandout(upper_w);
490	else
491		wstandend(upper_w);
492
493	if (layer == 1)
494	{
495		mvwprintw(upper_w, (controller*2)+1, H_TEI+1, "1");
496		if (!state)
497			mvwprintw(upper_w, (controller*2)+1, H_TEI+2, "2");
498	}
499	else if (layer == 2)
500	{
501		mvwprintw(upper_w, (controller*2)+1, H_TEI+2, "2");
502		if (state)
503			mvwprintw(upper_w, (controller*2)+1, H_TEI+1, "1");
504	}
505
506	wstandend(upper_w);
507	wrefresh(upper_w);
508}
509
510/*---------------------------------------------------------------------------*
511 *	display TEI
512 *---------------------------------------------------------------------------*/
513void
514display_tei(int controller, int tei)
515{
516	if (controller > ncontroller)
517		return;
518
519	if (tei == -1)
520		mvwprintw(upper_w, controller*2, H_TEI, "---");
521	else
522		mvwprintw(upper_w, controller*2, H_TEI, "%3d", tei);
523
524	wrefresh(upper_w);
525}
526
527/*---------------------------------------------------------------------------*
528 *	display bell :-)
529 *---------------------------------------------------------------------------*/
530void
531display_bell(void)
532{
533	static char bell[1] = { 0x07 };
534	write(STDOUT_FILENO, &bell[0], 1);
535}
536
537/*---------------------------------------------------------------------------*
538 *	display channel information for shutdown
539 *---------------------------------------------------------------------------*/
540void
541display_chans(void)
542{
543	char buffer[80];
544	int i, j, cnt = 0;
545	WINDOW *chan_w;
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;
550
551	/* need this later to close the connection */
552	struct ctlr_chan {
553		int cntl;
554		int chn;
555	} *cc = NULL;
556
557	for (ctrl = get_first_ctrl_state(); ctrl; ctrl = NEXT_CTRL(ctrl)) {
558		if ((get_controller_state(ctrl)) != CTRL_UP)
559			continue;
560		for (j = 0; j < ctrl->nbch; j++)
561			if ((ret_channel_state(ctrl, j)) == CHAN_RUN)
562				cnt++;
563	}
564
565	if (cnt > 0)
566	{
567		if ((cc = (struct ctlr_chan *)malloc (cnt *
568			sizeof (struct ctlr_chan))) == NULL)
569		{
570			return;
571		}
572		nlines = cnt + 4;
573		ncols = 60;
574	}
575	else
576	{
577		nlines = 5;
578		ncols = 22;
579	}
580
581	pos_y = WMENU_POSLN + 4;
582	pos_x = WMENU_POSCO + 10;
583
584	/* create a new window in the lower screen area */
585
586	if ((chan_w = newwin(nlines, ncols, pos_y, pos_x )) == NULL)
587	{
588		logit(LL_WRN, "ERROR, curses init channel window!");
589		if (cnt > 0)
590			free(cc);
591		return;
592	}
593
594	/* create a border around the window */
595
596	box(chan_w, '|', '-');
597
598	/* add a title */
599
600	wstandout(chan_w);
601	mvwaddstr(chan_w, 0, (ncols / 2) - (strlen("Channels") / 2), "Channels");
602	wstandend(chan_w);
603
604	/* no active channels */
605	if (cnt == 0)
606	{
607		mvwaddstr(chan_w, 2, 2, "No active channels");
608		wrefresh(chan_w);
609		sleep(1);
610
611		/* delete the channels window */
612
613		delwin(chan_w);
614		return;
615	}
616
617	nlines = 2;
618	ncols = 1;
619
620	for (ctrl = get_first_ctrl_state(), i = 0; ctrl; ctrl = NEXT_CTRL(ctrl), i++) {
621		if ((get_controller_state(ctrl)) != CTRL_UP)
622			continue;
623
624		for (j = 0; j < ctrl->nbch; i++)
625		{
626			if ((ret_channel_state(ctrl, j)) == CHAN_RUN)
627			{
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;
632				nlines++;
633				ncols++;
634			}
635		}
636	}
637
638	set[0].fd = STDIN_FILENO;
639	set[0].events = POLLIN;
640	for (;;)
641	{
642		wrefresh(chan_w);
643
644		/* if no char is available within timeout, exit menu*/
645
646		if ((poll(set, 1, WMTIMEOUT * 1000)) <= 0)
647			break;
648
649		ncols = wgetch(chan_w);
650
651		if (!(isdigit(ncols)))
652		{
653			display_bell();
654			continue;
655		}
656
657		nlines = ncols - '0';
658
659		if ((nlines == 0) || (nlines > cnt))
660		{
661			display_bell();
662			continue;
663		}
664
665		if ((cep = get_cep_by_cc(cc[nlines-1].cntl, cc[nlines-1].chn))
666			!= NULL)
667		{
668			logit(LL_CHD, "%05d %s manual disconnect (fullscreen menu)", cep->cdid, cep->name);
669			cep->hangup = 1;
670			break;
671		}
672	}
673
674	free(cc);
675
676	/* delete the channels window */
677
678	delwin(chan_w);
679}
680
681/*---------------------------------------------------------------------------*
682 *	display card type information
683 *---------------------------------------------------------------------------*/
684static void
685display_cards(void)
686{
687	WINDOW *chan_w;
688	int nlines, ncols, pos_x, pos_y;
689	struct pollfd set[1];
690	int i;
691	struct isdn_ctrl_state *ctrl;
692
693	nlines = 6+ncontroller;
694	ncols = 60;
695	pos_y = WMENU_POSLN;
696	pos_x = WMENU_POSCO;
697
698	/* create a new window in the lower screen area */
699
700	if ((chan_w = newwin(nlines, ncols, pos_y, pos_x )) == NULL)
701	{
702		logit(LL_WRN, "ERROR, curses init channel window!");
703		return;
704	}
705
706	/* create a border around the window */
707
708	box(chan_w, '|', '-');
709
710	/* add a title */
711
712	wstandout(chan_w);
713	mvwaddstr(chan_w, 0, (ncols / 2) - (strlen("Cards") / 2), "Cards");
714	wstandend(chan_w);
715
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++)
719	{
720		mvwprintw(chan_w, 4+i, 2, " #%d  %s: %s", i,
721		    ctrl->device_name,
722		    ctrl->controller);
723	}
724
725	wrefresh(chan_w);
726
727	set[0].fd = STDIN_FILENO;
728	set[0].events = POLLIN;
729
730	if ((poll(set, 1, WMTIMEOUT*2 * 1000)) <= 0)
731	{
732		delwin(chan_w);
733		return;
734	}
735
736	wgetch(chan_w);
737	delwin(chan_w);
738}
739
740/*---------------------------------------------------------------------------*
741 *	display budget info
742 *---------------------------------------------------------------------------*/
743static void
744display_budget(void)
745{
746	WINDOW *bud_w;
747	int nlines, ncols, pos_x, pos_y;
748	struct pollfd set[1];
749	int j;
750	struct cfg_entry *cep;
751	time_t now;
752	double uptime;
753	int minutes;
754	int hours;
755	int days;
756
757	nlines = 0;
758	ncols = 73;
759	pos_y = WMENU_POSLN;
760	pos_x = WMENU_POSCO-3;
761
762	for (cep = get_first_cfg_entry(), j=0; cep; cep = NEXT_CFE(cep)) {
763		if (cep->budget_callbackperiod && cep->budget_callbackncalls)
764			nlines++;
765		if (cep->budget_calloutperiod && cep->budget_calloutncalls)
766			nlines++;
767	}
768
769	if (nlines == 0)
770		return;
771
772	nlines += 6;
773
774	/* create a new window in the lower screen area */
775
776	if ((bud_w = newwin(nlines, ncols, pos_y, pos_x )) == NULL)
777	{
778		logit(LL_WRN, "ERROR, curses init budget window!");
779		return;
780	}
781
782	now = time(NULL);
783	uptime = difftime(now, starttime);
784
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);
788
789	uptime = uptime / (60*60);
790
791	/* create a border around the window */
792
793	box(bud_w, '|', '-');
794
795	/* add a title */
796
797	wstandout(bud_w);
798	mvwaddstr(bud_w, 0, (ncols / 2) - (strlen("Budget") / 2), "Budget");
799	wstandend(bud_w);
800
801	mvwprintw(bud_w, 1, 2, "isdnd uptime: %d %s - %d %s - %d %s",
802		days,
803		days == 1 ? "day" : "days",
804		hours,
805		hours == 1 ? "hour" : "hours",
806		minutes,
807		minutes == 1 ? "minute" : "minutes");
808
809	mvwprintw(bud_w, 2, 2, "name     t period rest   ncall rest  rqsts /hr  rdone /hr  rrjct /hr ");
810	mvwprintw(bud_w, 3, 2, "-------- - ------ ------ ----- ----- ----- ---- ----- ---- ----- ----");
811
812	for (cep = get_first_cfg_entry(), j=4; cep; cep = NEXT_CFE(cep)) {
813		if (cep->budget_calloutperiod && cep->budget_calloutncalls)
814		{
815			mvwprintw(bud_w, j, 2, "%-8s %c %-6d %-6ld %-5d %-5d %-5d %-4.1f %-5d %-4.1f %-5d %-4.1f",
816				cep->name,
817				'o',
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);
828			j++;
829		}
830		if (cep->budget_callbackperiod && cep->budget_callbackncalls)
831		{
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,
834				'b',
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);
845			j++;
846		}
847	}
848
849	wrefresh(bud_w);
850
851	set[0].fd = STDIN_FILENO;
852	set[0].events = POLLIN;
853
854	if ((poll(set, 1, WMTIMEOUT*3 * 1000)) <= 0)
855	{
856		delwin(bud_w);
857		return;
858	}
859
860	wgetch(bud_w);
861	delwin(bud_w);
862}
863
864#endif
865
866/* EOF */
867