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