Annotation of embedaddon/trafshow/getkey.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1998,2004 Rinet Corp., Novosibirsk, Russia
! 3: *
! 4: * Redistribution and use in source forms, with and without modification,
! 5: * are permitted provided that this entire comment appears intact.
! 6: *
! 7: * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
! 8: */
! 9:
! 10: #ifdef HAVE_CONFIG_H
! 11: #include <config.h>
! 12: #endif
! 13:
! 14: #ifdef HAVE_SLCURSES
! 15: #include <slcurses.h>
! 16: #elif HAVE_NCURSES
! 17: #include <ncurses.h>
! 18: #else
! 19: #include <curses.h>
! 20: #endif
! 21: #include <stdio.h>
! 22: #include <stdlib.h>
! 23: #include <string.h>
! 24: #include <unistd.h>
! 25:
! 26: #include "getkey.h"
! 27: #include "screen.h"
! 28: #include "session.h"
! 29: #include "trafshow.h"
! 30: #include "selector.h"
! 31: #include "show_if.h"
! 32: #include "show_stat.h"
! 33: #include "show_dump.h"
! 34: #include "events.h"
! 35: #include "netstat.h"
! 36: #include "help_page.h"
! 37:
! 38:
! 39: static void read_key(SESSION *sd, const unsigned char *data, int len);
! 40: static int scan_key(const unsigned char *buf, int len);
! 41: static void parse_key(int key, PCAP_HANDLER *ph);
! 42: static void init_edit_string(const char *prompter, const char *charset, int size);
! 43: static int edit_string(int ch);
! 44:
! 45: /* edit string stuff */
! 46: static const char *numbers = "1234567890";
! 47: static const char *spaces = " ,.;@/\\";
! 48: static char prompt_buf[MAX_PARAM_LEN], cut_buf[MAX_PARAM_LEN];
! 49: static const char *char_set;
! 50: static int buf_size, cur, nb, win, scr, bartop, barlen, touch, show_win;
! 51:
! 52:
! 53: void
! 54: getkey_init(ph)
! 55: PCAP_HANDLER *ph;
! 56: {
! 57: SESSION *sd;
! 58:
! 59: if ((sd = session_open(0, 0, PlainFile)) == 0) {
! 60: perror("session_open 0"); /* should not happen */
! 61: exit(1);
! 62: }
! 63: session_setcallback(sd, 0, 0, read_key);
! 64: session_setcookie(sd, ph);
! 65: prompt_mode = 0;
! 66: }
! 67:
! 68: static void
! 69: read_key(sd, data, len)
! 70: SESSION *sd;
! 71: const unsigned char *data;
! 72: int len;
! 73: {
! 74: /* sanity check */
! 75: if (sd && data && len > 0) {
! 76: int key = scan_key(data, len);
! 77: if (key != -1)
! 78: parse_key(key, (PCAP_HANDLER *)session_cookie(sd));
! 79: }
! 80: }
! 81:
! 82: static SELECTOR *
! 83: get_selector(ph_list)
! 84: PCAP_HANDLER *ph_list;
! 85: {
! 86: /* return current selector */
! 87: switch (show_mode) {
! 88: case Interfaces:
! 89: return show_if_selector();
! 90: case NetStat:
! 91: return show_stat_selector(pcap_get_selected(ph_list));
! 92: case FlowDump:
! 93: /* nope */
! 94: break;
! 95: case HelpPage:
! 96: return help_page_selector();
! 97: }
! 98: return 0;
! 99: }
! 100:
! 101: static void
! 102: parse_key(key, ph_list)
! 103: int key;
! 104: PCAP_HANDLER *ph_list;
! 105: {
! 106: int ch = key;
! 107: PCAP_HANDLER *ph = 0;
! 108: SELECTOR *sp = 0;
! 109: struct timeval now;
! 110:
! 111: if (prompt_mode) {
! 112: const char *txt = 0;
! 113: int redraw = 1;
! 114: if ((ch = edit_string(ch)) == 0) /* still edit */
! 115: return;
! 116: if (ch > 0) {
! 117: switch (prompt_mode) {
! 118: case 'r': /* end of getting refresh time */
! 119: case 'R':
! 120: ch = atoi(prompt_buf);
! 121: if (ch > 0 && ch != refresh_time) {
! 122: if (ch < purge_time)
! 123: refresh_time = ch;
! 124: else txt = "Refresh Time must be less than Purge Time";
! 125: }
! 126: break;
! 127: case 'p': /* end of getting purge time */
! 128: case 'P':
! 129: ch = atoi(prompt_buf);
! 130: if (ch > 0 && ch != purge_time) {
! 131: if (ch > refresh_time) {
! 132: purge_time = ch;
! 133: add_event(0, pcap_purge, ph_list);
! 134: redraw = 0;
! 135: } else txt = "Purge Time must be bigger than Refresh Time";
! 136: }
! 137: break;
! 138: case 'f': /* end of getting filter expression */
! 139: case 'F':
! 140: if (!expression || strcmp(prompt_buf, expression)) {
! 141: if (expression) free(expression);
! 142: expression = strdup(prompt_buf);
! 143: if ((txt = pcap_setexpr(ph_list, expression)) == 0) {
! 144: if (prompt_mode == 'F') {
! 145: add_event(0, pcap_clear, ph_list);
! 146: redraw = 0;
! 147: }
! 148: }
! 149: }
! 150: break;
! 151: case '/': /* end of getting search string */
! 152: if (prompt_buf[0] == '\0') {
! 153: if (search) {
! 154: free(search);
! 155: search = 0;
! 156: txt = "Search mode turned Off";
! 157: }
! 158: } else if (!search || strcmp(prompt_buf, search)) {
! 159: if (search) free(search);
! 160: search = strdup(prompt_buf);
! 161: }
! 162: break;
! 163: case 'a': /* end of getting aggregation masklen */
! 164: case 'A':
! 165: if (prompt_buf[0]) {
! 166: ch = atoi(prompt_buf);
! 167: if (ch < 0 || ch > ADDRBITLEN) {
! 168: txt = "Wrong netmask length";
! 169: break;
! 170: }
! 171: } else ch = -1;
! 172: if (show_mode == NetStat &&
! 173: (ph = pcap_get_selected(ph_list)) != 0) {
! 174: if (ph->masklen != ch) {
! 175: ph->masklen = ch;
! 176: if (prompt_mode == 'A')
! 177: netstat_purge(ph, 0);
! 178: }
! 179: } else {
! 180: aggregate = ch;
! 181: for (ph = ph_list; ph; ph = ph->next) {
! 182: if (ph->masklen != aggregate) {
! 183: ph->masklen = aggregate;
! 184: if (prompt_mode == 'A')
! 185: netstat_purge(ph, 0);
! 186: }
! 187: }
! 188: }
! 189: break;
! 190: }
! 191: }
! 192: prompt_mode = 0;
! 193: if (redraw)
! 194: add_event(0, pcap_show, ph_list);
! 195: if (txt)
! 196: screen_status(txt);
! 197: else screen_update();
! 198: return;
! 199: }
! 200:
! 201: /* try global operation keys */
! 202: switch (ch) {
! 203: case K_ESC: /* get back show mode */
! 204: case 'q':
! 205: case 'Q':
! 206: switch (show_mode) {
! 207: case Interfaces:
! 208: exit(0);
! 209: case NetStat:
! 210: if ((ph = pcap_get_selected(ph_list)) != 0 && ph->top)
! 211: pcaph_close(ph);
! 212: else show_mode = Interfaces;
! 213: pcap_show(ph_list);
! 214: return;
! 215: case FlowDump:
! 216: show_dump_close();
! 217: show_mode = NetStat;
! 218: pcap_show(ph_list);
! 219: return;
! 220: case HelpPage:
! 221: show_mode = help_page_mode();
! 222: pcap_show(ph_list);
! 223: return;
! 224: }
! 225: break;
! 226: case K_CTRL('L'): /* refresh screen */
! 227: clear();
! 228: refresh();
! 229: pcap_show(ph_list);
! 230: return;
! 231: case 'h': /* help page if any */
! 232: case 'H':
! 233: case '?':
! 234: case K_F1:
! 235: if (help_page_list(show_mode)) {
! 236: show_mode = HelpPage;
! 237: pcap_show(ph_list);
! 238: return;
! 239: }
! 240: break;
! 241: case 'r': /* start to get refresh time */
! 242: case 'R':
! 243: if (show_mode != FlowDump) {
! 244: prompt_mode = ch;
! 245: snprintf(prompt_buf, sizeof(prompt_buf), "%d", refresh_time);
! 246: init_edit_string("Refresh seconds: ", numbers, 5);
! 247: selector_withdraw(get_selector(ph_list));
! 248: screen_update();
! 249: return;
! 250: }
! 251: break;
! 252: case 'p': /* start to get purge time */
! 253: case 'P':
! 254: if (show_mode != FlowDump) {
! 255: prompt_mode = ch;
! 256: snprintf(prompt_buf, sizeof(prompt_buf), "%d", purge_time);
! 257: init_edit_string("Purge seconds: ", numbers, 5);
! 258: selector_withdraw(get_selector(ph_list));
! 259: screen_update();
! 260: return;
! 261: }
! 262: break;
! 263: case 'f': /* start to get filter expression */
! 264: case 'F':
! 265: if (show_mode != FlowDump) {
! 266: prompt_mode = ch;
! 267: prompt_buf[0] = '\0';
! 268: if (expression) {
! 269: (void)strncpy(prompt_buf, expression, sizeof(prompt_buf));
! 270: prompt_buf[sizeof(prompt_buf)-1] = '\0';
! 271: }
! 272: init_edit_string("Filter expression: ", 0, sizeof(prompt_buf));
! 273: selector_withdraw(get_selector(ph_list));
! 274: screen_update();
! 275: return;
! 276: }
! 277: break;
! 278: case '/': /* start to get search string */
! 279: if (show_mode != FlowDump) {
! 280: prompt_mode = ch;
! 281: prompt_buf[0] = '\0';
! 282: if (search) {
! 283: (void)strncpy(prompt_buf, search, sizeof(prompt_buf));
! 284: prompt_buf[sizeof(prompt_buf)-1] = '\0';
! 285: }
! 286: init_edit_string("Search string: ", 0, sizeof(prompt_buf));
! 287: selector_withdraw(get_selector(ph_list));
! 288: screen_update();
! 289: return;
! 290: }
! 291: break;
! 292: case K_CTRL('_'): /* turn off search mode */
! 293: if (show_mode != FlowDump) {
! 294: if (search) {
! 295: free(search);
! 296: search = 0;
! 297: screen_status("Search mode turned Off");
! 298: }
! 299: return;
! 300: }
! 301: break;
! 302: case 'a': /* start to get aggregation masklen */
! 303: case 'A':
! 304: if (show_mode != FlowDump) {
! 305: char buf[100];
! 306: prompt_mode = ch;
! 307: prompt_buf[0] = '\0';
! 308: if (show_mode == NetStat &&
! 309: (ph = pcap_get_selected(ph_list)) != 0) {
! 310: if (ph->masklen >= 0)
! 311: snprintf(prompt_buf, sizeof(prompt_buf), "%d", ph->masklen);
! 312: snprintf(buf, sizeof(buf), "%s aggregation netmask length: ", ph->name);
! 313: } else {
! 314: if (aggregate >= 0)
! 315: snprintf(prompt_buf, sizeof(prompt_buf), "%d", aggregate);
! 316: (void)strcpy(buf, "Aggregation netmask length: ");
! 317: }
! 318: init_edit_string(buf, numbers, 5);
! 319: selector_withdraw(get_selector(ph_list));
! 320: screen_update();
! 321: return;
! 322: }
! 323: break;
! 324: case K_CTRL('R'): /* reset all netstat hash */
! 325: if (show_mode == Interfaces) {
! 326: add_event(0, pcap_clear, ph_list);
! 327: screen_status("Resetting all flows");
! 328: return;
! 329: }
! 330: break;
! 331: case 'n': /* toggle numeric values to names conversion */
! 332: case 'N':
! 333: if (show_mode != FlowDump) {
! 334: nflag ^= 1;
! 335: if (ch == 'N') {
! 336: add_event(0, pcap_show, ph_list);
! 337: } else {
! 338: screen_status("Numeric values turned %s",
! 339: nflag ? "On" : "Off");
! 340: }
! 341: return;
! 342: }
! 343: break;
! 344: }
! 345:
! 346: /* prevent screen refresh overhead */
! 347: gettimeofday(&now, 0);
! 348: now.tv_sec += refresh_time;
! 349: add_event(&now, pcap_show, ph_list);
! 350:
! 351: /* get current selector */
! 352: switch (show_mode) {
! 353: case Interfaces:
! 354: sp = show_if_selector();
! 355: break;
! 356: case NetStat:
! 357: if ((ph = pcap_get_selected(ph_list)) == 0)
! 358: return;
! 359: sp = show_stat_selector(ph);
! 360:
! 361: /* try special input for the show mode */
! 362: if (show_stat_input(ph, ch)) {
! 363: selector_redraw(sp);
! 364: return;
! 365: }
! 366: break;
! 367: case FlowDump:
! 368: /* special input only for the show mode */
! 369: show_dump_input(ch);
! 370: return;
! 371: case HelpPage:
! 372: sp = help_page_selector();
! 373: break;
! 374: }
! 375:
! 376: /* try special input for the selecting */
! 377: ch = selector_move(ch, sp);
! 378: if (ch < 0) {
! 379: selector_redraw(sp);
! 380: return;
! 381: }
! 382:
! 383: /* something selected */
! 384: switch (show_mode) {
! 385: case Interfaces:
! 386: if ((ph = pcap_set_selected(ph_list, ch)) == 0)
! 387: return; /* should not happen */
! 388: /*selector_withdraw(sp);*/
! 389: show_mode = NetStat;
! 390: pcap_show(ph_list);
! 391: return;
! 392: case NetStat:
! 393: /*selector_withdraw(sp);*/
! 394: if (ph->masklen == -1) {
! 395: if (show_dump_open(ph, show_stat_get(ph, ch)) == 0)
! 396: show_mode = FlowDump;
! 397: } else if (pcaph_create(ph, (struct netstat_header *)show_stat_get(ph, ch))) {
! 398: pcap_show(ph_list);
! 399: }
! 400: return;
! 401: case FlowDump:
! 402: /* not reached; just to avoid compiler warning */
! 403: return;
! 404: case HelpPage:
! 405: key = help_page_key(ch);
! 406: if (key != -1 && key != 0) {
! 407: show_mode = help_page_mode(); /* get back show mode */
! 408: pcap_show(ph_list);
! 409: parse_key(key, ph_list);
! 410: }
! 411: return;
! 412: }
! 413: }
! 414:
! 415: static int
! 416: scan_key(buf, len)
! 417: const unsigned char *buf;
! 418: int len;
! 419: {
! 420: int i;
! 421:
! 422: if (buf[0] != ESCAPE) return buf[0];
! 423: if (len == 1) return K_ESC;
! 424: i = 1;
! 425: if (buf[i] == '[' || buf[i] == 'O')
! 426: if (++i >= len) return -1;
! 427:
! 428: switch (buf[i]) {
! 429: case '\0': /* xterm */
! 430: return K_HOME;
! 431: case 'A':
! 432: case 'i':
! 433: return K_UP;
! 434: case 'B':
! 435: return K_DOWN;
! 436: case 'D':
! 437: return K_LEFT;
! 438: case 'C':
! 439: return K_RIGHT;
! 440: case 'I': /* ansi PgUp */
! 441: case 'V': /* at386 PgUp */
! 442: case 'S': /* 97801 PgUp */
! 443: case 'v': /* emacs style */
! 444: return K_PAGEUP;
! 445: case 'G': /* ansi PgDn */
! 446: case 'U': /* at386 PgDn */
! 447: case 'T': /* 97801 PgDn */
! 448: return K_PAGEDOWN;
! 449: case 'H': /* at386 Home */
! 450: return K_HOME;
! 451: case 'F': /* ansi End */
! 452: case 'Y': /* at386 End */
! 453: return K_END;
! 454: case '5': /* vt200 PgUp */
! 455: return K_PAGEUP;
! 456: case '6': /* vt200 PgUp */
! 457: return K_PAGEDOWN;
! 458: case '1': /* vt200 PgUp */
! 459: if (++i >= len) return -1;
! 460: switch(buf[i]) { /* xterm */
! 461: case '1':
! 462: return K_F1;
! 463: case '2':
! 464: return K_F2;
! 465: case '3':
! 466: return K_F3;
! 467: case '4':
! 468: return K_F4;
! 469: case '5': /* RS/6000 PgUp is 150g, PgDn is 154g */
! 470: if (++i >= len) return -1;
! 471: if (buf[i] == '0')
! 472: return K_PAGEUP;
! 473: if (buf[i] == '4')
! 474: return K_PAGEDOWN;
! 475: }
! 476: return K_HOME;
! 477: case '4': /* vt200 PgUp */
! 478: return K_END;
! 479: case '2': /* xterm */
! 480: case 'L':
! 481: return K_INS;
! 482: case 'M':
! 483: return K_F1;
! 484: case 'N':
! 485: return K_F2;
! 486: case 'O':
! 487: return K_F3;
! 488: case 'P':
! 489: return K_F4;
! 490: }
! 491: return -1;
! 492: }
! 493:
! 494: static void
! 495: init_edit_string(prompter, charset, size)
! 496: const char *prompter, *charset;
! 497: int size;
! 498: {
! 499: int i;
! 500:
! 501: char_set = charset;
! 502: touch = 0;
! 503: show_win = 0;
! 504:
! 505: *cut_buf = '\0';
! 506: bartop = strlen(prompter);
! 507: i = COLS - (bartop + 3);
! 508: barlen = buf_size = size;
! 509: if (barlen < 1 || barlen > i) {
! 510: barlen = i;
! 511: show_win = 1;
! 512: }
! 513:
! 514: attrset(A_NORMAL);
! 515: move(LINES-1, 0);
! 516: clrtoeol();
! 517: addstr(prompter);
! 518:
! 519: nb = strlen(prompt_buf);
! 520: if (nb >= buf_size) nb = buf_size - 1;
! 521: prompt_buf[nb] = '\0';
! 522: cur = nb;
! 523:
! 524: win = cur / barlen; /* window number */
! 525: scr = cur % barlen; /* screen position */
! 526:
! 527: if (show_win) mvprintw(LINES-1, COLS-2, "%-2d", win+1);
! 528:
! 529: attrset(A_STANDOUT);
! 530: mvprintw(LINES-1, bartop, "%-*.*s", barlen, barlen, &prompt_buf[win * barlen]);
! 531:
! 532: screen_dock_cursor(LINES-1, bartop + scr);
! 533: }
! 534:
! 535: static int
! 536: edit_string(ch)
! 537: int ch;
! 538: {
! 539: int i;
! 540:
! 541: switch (ch) {
! 542: case K_ESC:
! 543: case K_CR:
! 544: case K_NL:
! 545: prompt_buf[nb] = '\0';
! 546: attrset(A_NORMAL);
! 547: move(LINES-1, 0);
! 548: clrtoeol();
! 549: screen_dock_cursor(0, 0);
! 550: return (ch == K_ESC ? -1 : 1);
! 551:
! 552: case K_PAGEUP: /* move to begin of window */
! 553: cur -= cur % barlen;
! 554: break;
! 555: case K_PAGEDOWN:/* move to end of window */
! 556: if (strlen(&prompt_buf[cur]) < barlen)
! 557: cur = nb;
! 558: else cur += barlen - cur % barlen - 1;
! 559: break;
! 560: case K_UP: /* skip to previous word */
! 561: case K_CTRL('P'):
! 562: ch = 0;
! 563: for (i = cur; i > 0; i--) {
! 564: if (!ch) {
! 565: if (strchr(spaces, prompt_buf[i-1]))
! 566: ch++;
! 567: } else if (!strchr(spaces, prompt_buf[i-1]))
! 568: break;
! 569: }
! 570: cur = i;
! 571: break;
! 572: case K_DOWN: /* skip to next word */
! 573: case K_CTRL('N'):
! 574: ch = 0;
! 575: for (i = cur; i < nb; i++) {
! 576: if (!ch) {
! 577: if (strchr(spaces, prompt_buf[i]))
! 578: ch++;
! 579: } else if (!strchr(spaces, prompt_buf[i]))
! 580: break;
! 581: }
! 582: cur = i;
! 583: break;
! 584: case K_HOME: /* move to begin of line */
! 585: case K_CTRL('A'):
! 586: cur = 0;
! 587: break;
! 588: case K_END: /* move to end of line */
! 589: case K_CTRL('E'):
! 590: cur = nb;
! 591: break;
! 592: case K_LEFT: /* move cursor left */
! 593: case K_CTRL('B'):
! 594: if (cur > 0) cur--;
! 595: break;
! 596: case K_RIGHT: /* move cursor right */
! 597: case K_CTRL('F'):
! 598: if (cur < nb) cur++;
! 599: break;
! 600: case K_BS: /* backspace */
! 601: if (nb && cur) {
! 602: memmove(&prompt_buf[cur-1], &prompt_buf[cur], nb - cur);
! 603: cur--;
! 604: nb--;
! 605: }
! 606: break;
! 607: case K_DEL: /* delete */
! 608: case K_CTRL('D'):
! 609: if (nb && cur < nb) {
! 610: memmove(&prompt_buf[cur], &prompt_buf[cur+1], nb - cur);
! 611: nb--;
! 612: }
! 613: break;
! 614: case K_CTRL('U'): /* erase entire line */
! 615: (void)strcpy(cut_buf, prompt_buf);
! 616: nb = 0;
! 617: cur = 0;
! 618: break;
! 619: case K_CTRL('W'): /* erase last word */
! 620: ch = 0;
! 621: for (i = cur; i > 0; i--) {
! 622: if (!ch) {
! 623: if (strchr(spaces, prompt_buf[i-1]))
! 624: ch++;
! 625: } else if (!strchr(spaces, prompt_buf[i-1]))
! 626: break;
! 627: }
! 628: if (cur > i) {
! 629: memcpy(cut_buf, &prompt_buf[i], cur - i);
! 630: cut_buf[cur - i] = '\0';
! 631: memmove(&prompt_buf[i], &prompt_buf[cur], cur - i);
! 632: nb -= cur - i;
! 633: cur = i;
! 634: }
! 635: break;
! 636: case K_CTRL('K'): /* erase end of line */
! 637: if (prompt_buf[cur] != '\0')
! 638: (void)strcpy(cut_buf, &prompt_buf[cur]);
! 639: nb = cur;
! 640: break;
! 641: case K_TAB: /* insert cut_buf */
! 642: i = strlen(cut_buf);
! 643: if (i && (buf_size - 1) - strlen(prompt_buf) >= i) {
! 644: memmove(&prompt_buf[cur+i], &prompt_buf[cur], nb - cur);
! 645: memmove(&prompt_buf[cur], cut_buf, i);
! 646: nb += i;
! 647: cur += i;
! 648: }
! 649: break;
! 650: default:
! 651: if (ch < 32 || ch > 126)
! 652: return 0; /* skip garbage chars */
! 653:
! 654: if (char_set && !strchr(char_set, ch)) {
! 655: beep();
! 656: return 0;
! 657: }
! 658: if (!touch) {
! 659: nb = 0;
! 660: cur = 0;
! 661: }
! 662: if (nb >= buf_size - 1) { /* no more space available */
! 663: beep();
! 664: return 0;
! 665: }
! 666: if (nb > cur)
! 667: memmove(&prompt_buf[cur+1], &prompt_buf[cur], nb - cur);
! 668: prompt_buf[cur++] = ch;
! 669: nb++;
! 670: }
! 671: touch = 1;
! 672:
! 673: prompt_buf[nb] = '\0';
! 674:
! 675: win = cur / barlen; /* window number */
! 676: scr = cur % barlen; /* screen position */
! 677:
! 678: attrset(A_STANDOUT);
! 679: mvprintw(LINES-1, bartop, "%-*.*s", barlen, barlen, &prompt_buf[win * barlen]);
! 680: if (show_win) {
! 681: attrset(A_NORMAL);
! 682: mvprintw(LINES-1, COLS-2, "%-2d", win+1);
! 683: }
! 684:
! 685: screen_dock_cursor(LINES-1, bartop + scr);
! 686: screen_update();
! 687: return 0;
! 688: }
! 689:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>