1/*
2 * Copyright (c) 1999 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.7 2009/04/16 05:56:33 lukem Exp $
31 *
32 * $FreeBSD$
33 *
34 *      last edit-date: [Mon Dec 13 21:51:47 1999]
35 *
36 *---------------------------------------------------------------------------*/
37
38#include "monprivate.h"
39
40#ifndef WIN32
41
42static void display_bell(void);
43static void display_chans(void);
44
45/*---------------------------------------------------------------------------*
46 *	program exit
47 *---------------------------------------------------------------------------*/
48void
49do_exit(int exitval)
50{
51	if (curses_ready)
52		endwin();
53	exit(exitval);
54}
55
56/*---------------------------------------------------------------------------*
57 *	init curses fullscreen display
58 *---------------------------------------------------------------------------*/
59void
60init_screen(void)
61{
62	char buffer[512];
63	int uheight, lheight;
64	int i, j;
65
66	initscr();			/* curses init */
67
68	if ((COLS < 80) || (LINES < 24))
69	{
70		endwin();
71		fprintf(stderr, "ERROR, minimal screensize must be 80x24, is %dx%d, terminating!",COLS, LINES);
72		exit(1);
73	}
74
75	noecho();
76	raw();
77
78	uheight = nctrl * 2; /* cards * b-channels */
79	lheight = LINES - uheight - 6 + 1; /* rest of display */
80
81	if ((upper_w = newwin(uheight, COLS, UPPER_B, 0)) == NULL)
82	{
83		endwin();
84		fprintf(stderr, "ERROR, curses init upper window, terminating!");
85		exit(1);
86	}
87
88	if ((mid_w = newwin(1, COLS, UPPER_B+uheight+1, 0)) == NULL)
89	{
90		endwin();
91		fprintf(stderr, "ERROR, curses init mid window, terminating!");
92		exit(1);
93	}
94
95	if ((lower_w = newwin(lheight, COLS, UPPER_B+uheight+3, 0)) == NULL)
96	{
97		endwin();
98		fprintf(stderr, "ERROR, curses init lower window, LINES = %d, lheight = %d, uheight = %d, terminating!", LINES, lheight, uheight);
99		exit(1);
100	}
101
102	scrollok(lower_w, 1);
103
104	snprintf(buffer, sizeof(buffer), "----- isdn controller channel state ------------- isdnmonitor %02d.%02d.%d -", VERSION, REL, STEP);
105
106	while((int)strlen(buffer) < COLS)
107		strlcat(buffer, "-", sizeof(buffer));
108
109	move(0, 0);
110	standout();
111	addstr(buffer);
112	standend();
113
114	move(1, 0);
115	/*      01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
116	addstr("# tei b remote                 iface  dir outbytes   obps inbytes    ibps  units");
117
118	if (hostname)
119		snprintf(buffer, sizeof(buffer), "----- isdn userland interface state ------------- %s:%d -", hostname, portno);
120	else
121		snprintf(buffer, sizeof(buffer), "----- isdn userland interface state ------------- %s -", sockpath);
122
123	while((int)strlen(buffer) < COLS)
124		strlcat(buffer, "-", sizeof(buffer));
125
126	move(uheight+2, 0);
127	standout();
128	addstr(buffer);
129	standend();
130
131	snprintf(buffer, sizeof(buffer), "----- isdnd logfile display --------------------------------------------------");
132	while((int)strlen(buffer) < COLS)
133		strlcat(buffer, "-", sizeof(buffer));
134
135	move(uheight+4, 0);
136	standout();
137	addstr(buffer);
138	standend();
139
140	refresh();
141
142	for (i=0, j=0; i <= nctrl; i++, j+=2)
143	{
144		mvwprintw(upper_w, j,   H_CNTL, "%d --- 1 ", i);  /*TEI*/
145		mvwprintw(upper_w, j+1, H_CNTL, "  L12 2 ");
146	}
147	wrefresh(upper_w);
148
149#ifdef NOTDEF
150	for (i=0, j=0; i < nentries; i++)	/* walk thru all entries */
151	{
152		p = &cfg_entry_tab[i];		/* get ptr to enry */
153
154		mvwprintw(mid_w, 0, j, "%s%d ", bdrivername(p->usrdevicename), p->usrdeviceunit);
155
156		p->fs_position = j;
157
158		j += ((strlen(bdrivername(p->usrdevicename)) + (p->usrdeviceunit > 9 ? 2 : 1) + 1));
159	}
160#else
161	mvwprintw(mid_w, 0, 0, "%s", devbuf);
162#endif
163	wrefresh(mid_w);
164
165	wmove(lower_w, 0, 0);
166	wrefresh(lower_w);
167
168	curses_ready = 1;
169}
170
171/*---------------------------------------------------------------------------*
172 *	display the charge in units
173 *---------------------------------------------------------------------------*/
174void
175display_charge(int pos, int charge)
176{
177	mvwprintw(upper_w, pos, H_UNITS, "%d", charge);
178	wclrtoeol(upper_w);
179	wrefresh(upper_w);
180}
181
182/*---------------------------------------------------------------------------*
183 *	display the calculated charge in units
184 *---------------------------------------------------------------------------*/
185void
186display_ccharge(int pos, int units)
187{
188	mvwprintw(upper_w, pos, H_UNITS, "(%d)", units);
189	wclrtoeol(upper_w);
190	wrefresh(upper_w);
191}
192
193/*---------------------------------------------------------------------------*
194 *	display accounting information
195 *---------------------------------------------------------------------------*/
196void
197display_acct(int pos, int obyte, int obps, int ibyte, int ibps)
198{
199	mvwprintw(upper_w, pos, H_OUT,    "%-10d", obyte);
200	mvwprintw(upper_w, pos, H_OUTBPS, "%-4d",  obps);
201	mvwprintw(upper_w, pos, H_IN,     "%-10d", ibyte);
202	mvwprintw(upper_w, pos, H_INBPS,  "%-4d",  ibps);
203	wrefresh(upper_w);
204}
205
206/*---------------------------------------------------------------------------*
207 *	erase line at disconnect time
208 *---------------------------------------------------------------------------*/
209void
210display_disconnect(int pos)
211{
212	wmove(upper_w, pos, H_TELN);
213	wclrtoeol(upper_w);
214	wrefresh(upper_w);
215
216	if (do_bell)
217		display_bell();
218}
219
220/*---------------------------------------------------------------------------*
221 *	display interface up/down information
222 *---------------------------------------------------------------------------*/
223void
224display_updown(int pos, int updown, char *device)
225{
226	if (updown)
227		wstandend(mid_w);
228	else
229		wstandout(mid_w);
230
231	mvwprintw(mid_w, 0, pos, "%s ", device);
232
233	wstandend(mid_w);
234	wrefresh(mid_w);
235}
236
237/*---------------------------------------------------------------------------*
238 *	display interface up/down information
239 *---------------------------------------------------------------------------*/
240void
241display_l12stat(int controller, int layer, int state)
242{
243	if (controller > nctrl)
244		return;
245
246	if (!(layer == 1 || layer == 2))
247		return;
248
249	if (state)
250		wstandout(upper_w);
251	else
252		wstandend(upper_w);
253
254	if (layer == 1)
255	{
256		mvwprintw(upper_w, (controller*2)+1, H_TEI+1, "1");
257
258		if (!state)
259			mvwprintw(upper_w, (controller*2)+1, H_TEI+2, "2");
260	}
261	else if (layer == 2)
262	{
263		mvwprintw(upper_w, (controller*2)+1, H_TEI+2, "2");
264		if (state)
265			mvwprintw(upper_w, (controller*2)+1, H_TEI+1, "1");
266	}
267
268	wstandend(upper_w);
269	wrefresh(upper_w);
270}
271
272/*---------------------------------------------------------------------------*
273 *	display TEI
274 *---------------------------------------------------------------------------*/
275void
276display_tei(int controller, int tei)
277{
278	if (controller > nctrl)
279		return;
280
281	if (tei == -1)
282		mvwprintw(upper_w, controller*2, H_TEI, "---");
283	else
284		mvwprintw(upper_w, controller*2, H_TEI, "%3d", tei);
285
286	wrefresh(upper_w);
287}
288
289/*---------------------------------------------------------------------------*
290 *	display bell :-)
291 *---------------------------------------------------------------------------*/
292static void
293display_bell(void)
294{
295	static char bell[1] = { 0x07 };
296	write(STDOUT_FILENO, &bell[0], 1);
297}
298
299/*---------------------------------------------------------------------------*
300 *	curses menu for fullscreen command mode
301 *---------------------------------------------------------------------------*/
302void
303do_menu(void)
304{
305	static const char *menu[WMITEMS] =
306	{
307		"1 - (D)isplay refresh",
308		"2 - (H)angup (choose a channel)",
309		"3 - (R)eread config file",
310		"4 - (Q)uit the program",
311	};
312
313	WINDOW *menu_w;
314	int c;
315	int mpos;
316	struct pollfd set[1];
317
318	/* create a new window in the lower screen area */
319
320	if ((menu_w = newwin(WMENU_HGT, WMENU_LEN, WMENU_POSLN, WMENU_POSCO )) == NULL)
321	{
322		return;
323	}
324
325	/* create a border around the window */
326
327	box(menu_w, '|', '-');
328
329	/* add a title */
330
331	wstandout(menu_w);
332	mvwaddstr(menu_w, 0, (WMENU_LEN / 2) - (strlen(WMENU_TITLE) / 2), WMENU_TITLE);
333	wstandend(menu_w);
334
335	/* fill the window with the menu options */
336
337	for (mpos=0; mpos <= (WMITEMS-1); mpos++)
338		mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
339
340	/* highlight the first menu option */
341
342	mpos = 0;
343	wstandout(menu_w);
344	mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
345	wstandend(menu_w);
346
347	/* input loop */
348
349	set[0].fd = STDIN_FILENO;
350	set[0].events = POLLIN;
351	for (;;)
352	{
353		wrefresh(menu_w);
354
355		/* if no char is available within timeout, exit menu*/
356
357		if ((poll(set, 1, WMTIMEOUT * 1000)) <= 0)
358			goto mexit;
359
360		c = wgetch(menu_w);
361
362		switch (c)
363		{
364		case ' ':
365		case '\t':	/* hilite next option */
366			mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
367			mpos++;
368			if (mpos >= WMITEMS)
369				mpos = 0;
370			wstandout(menu_w);
371			mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
372			wstandend(menu_w);
373			break;
374
375		case ('0'+WREFRESH+1):	/* display refresh */
376		case 'D':
377		case 'd':
378			wrefresh(curscr);
379			goto mexit;
380
381		case ('0'+WQUIT+1):	/* quit program */
382		case 'Q':
383		case 'q':
384			do_exit(0);
385			goto mexit;
386
387
388		case ('0'+WHANGUP+1):	/* hangup connection */
389		case 'H':
390		case 'h':
391			display_chans();
392			goto mexit;
393
394		case ('0'+WREREAD+1):	/* reread config file */
395		case 'R':
396		case 'r':
397			reread();
398			goto mexit;
399
400		case '\n':
401		case '\r':	/* exec highlighted option */
402			switch (mpos)
403			{
404			case WREFRESH:
405				wrefresh(curscr);
406				break;
407
408			case WQUIT:
409				do_exit(0);
410				break;
411
412			case WHANGUP:
413				display_chans();
414				break;
415
416			case WREREAD:
417				reread();
418				break;
419			}
420			goto mexit;
421			break;
422
423		default:
424			goto mexit;
425			break;
426		}
427	}
428
429mexit:
430	/* delete the menu window */
431
432	delwin(menu_w);
433
434	/* re-display the original lower window contents */
435
436	touchwin(lower_w);
437	wrefresh(lower_w);
438}
439
440/*---------------------------------------------------------------------------*
441 *	display connect information
442 *---------------------------------------------------------------------------*/
443void
444display_connect(int pos, int dir, char *name, char *remtel, char *dev)
445{
446	char buffer[256];
447
448	/* remote telephone number */
449
450	snprintf(buffer, sizeof(buffer), "%s/%s", name, remtel);
451
452	buffer[H_IFN - H_TELN - 1] = '\0';
453
454	mvwprintw(upper_w, pos, H_TELN, "%s", buffer);
455
456	/* interface */
457
458	mvwprintw(upper_w, pos, H_IFN, "%s ", dev);
459
460	mvwprintw(upper_w, pos, H_IO, dir ? "out" : "in");
461
462	mvwprintw(upper_w, pos, H_OUT,    "-");
463	mvwprintw(upper_w, pos, H_OUTBPS, "-");
464	mvwprintw(upper_w, pos, H_IN,     "-");
465	mvwprintw(upper_w, pos, H_INBPS,  "-");
466
467	if (do_bell)
468		display_bell();
469
470	wrefresh(upper_w);
471}
472
473/*---------------------------------------------------------------------------*
474 *	display channel information for shutdown
475 *---------------------------------------------------------------------------*/
476static void
477display_chans(void)
478{
479	char buffer[80];
480	int i;
481	int cnt = 0;
482	WINDOW *chan_w;
483	int nlines, ncols, pos_x, pos_y;
484	struct pollfd set[1];
485
486	/* need this later to close the connection */
487	struct ctlr_chan {
488		int cntl;
489		int chn;
490	} *cc = NULL;
491
492        for (i = 0; i < nctrl; i++)
493        {
494		if (remstate[i].ch1state)
495	                cnt++;
496		if (remstate[i].ch2state)
497                        cnt++;
498        }
499
500	if (cnt > 0)
501	{
502		if ((cc = (struct ctlr_chan *)malloc (cnt *
503			sizeof (struct ctlr_chan))) == NULL)
504		{
505			return;
506		}
507		nlines = cnt + 4;
508		ncols = 60;
509	}
510	else
511	{
512		nlines = 5;
513		ncols = 22;
514	}
515
516	pos_y = WMENU_POSLN + 4;
517	pos_x = WMENU_POSCO + 10;
518
519	/* create a new window in the lower screen area */
520
521	if ((chan_w = newwin(nlines, ncols, pos_y, pos_x )) == NULL)
522	{
523		if (cnt > 0)
524			free(cc);
525		return;
526	}
527
528	/* create a border around the window */
529
530	box(chan_w, '|', '-');
531
532	/* add a title */
533
534	wstandout(chan_w);
535	mvwaddstr(chan_w, 0, (ncols / 2) - (strlen("Channels") / 2), "Channels");
536	wstandend(chan_w);
537
538	/* no active channels */
539	if (cnt == 0)
540	{
541		mvwaddstr(chan_w, 2, 2, "No active channels");
542		wrefresh(chan_w);
543		sleep(1);
544
545		/* delete the channels window */
546
547		delwin(chan_w);
548		return;
549	}
550
551	nlines = 2;
552	ncols = 1;
553
554	for (i = 0; i < nctrl; i++)
555	{
556		if (remstate[i].ch1state)
557		{
558			snprintf(buffer, sizeof(buffer),
559			    "%d - Controller %d channel %s", ncols, i, "B1");
560			mvwaddstr(chan_w, nlines, 2, buffer);
561			cc[ncols - 1].cntl = i;
562			cc[ncols - 1].chn = CHAN_B1;
563			nlines++;
564			ncols++;
565		}
566		if (remstate[i].ch2state)
567		{
568			snprintf(buffer, sizeof(buffer),
569			    "%d - Controller %d channel %s", ncols, i, "B2");
570			mvwaddstr(chan_w, nlines, 2, buffer);
571			cc[ncols - 1].cntl = i;
572			cc[ncols - 1].chn = CHAN_B2;
573			nlines++;
574			ncols++;
575		}
576	}
577
578	set[0].fd = STDIN_FILENO;
579	set[0].events = POLLIN;
580	for (;;)
581	{
582		wrefresh(chan_w);
583
584		/* if no char is available within timeout, exit menu*/
585
586		if ((poll(set, 1, WMTIMEOUT * 1000)) <= 0)
587			break;
588
589		ncols = wgetch(chan_w);
590
591		if (!(isdigit(ncols)))
592		{
593			display_bell();
594			continue;
595		}
596
597		nlines = ncols - '0';
598
599		if ((nlines == 0) || (nlines > cnt))
600		{
601			display_bell();
602			continue;
603		}
604
605		hangup(cc[nlines-1].cntl, cc[nlines-1].chn);
606		break;
607	}
608
609	free(cc);
610
611	/* delete the channels window */
612
613	delwin(chan_w);
614}
615
616#endif /* !WIN32*/
617
618/* EOF */
619