ui.c 23.3 KB
Newer Older
pdw's avatar
pdw committed
1 2 3 4 5
/*
 * ui.c:
 *
 */

6 7
#include "config.h"

chris's avatar
chris committed
8 9
#include <sys/types.h>

chris's avatar
chris committed
10
#include <ctype.h>
11
#include <ncurses.h>
chris's avatar
chris committed
12
#include <errno.h>
pdw's avatar
pdw committed
13
#include <string.h>
chris's avatar
chris committed
14
#include <math.h>
pdw's avatar
pdw committed
15
#include <pthread.h>
chris's avatar
chris committed
16
#include <signal.h>
pdw's avatar
pdw committed
17
#include <stdlib.h>
chris's avatar
chris committed
18
#include <unistd.h>
19
#include <netdb.h>
chris's avatar
chris committed
20

chris's avatar
chris committed
21 22
#include <sys/wait.h>

pdw's avatar
pdw committed
23
#include "addr_hash.h"
24
#include "serv_hash.h"
pdw's avatar
pdw committed
25 26 27
#include "iftop.h"
#include "resolver.h"
#include "sorted_list.h"
pdw's avatar
pdw committed
28
#include "options.h"
29
#include "screenfilter.h"
pdw's avatar
pdw committed
30

31
#include "ui_common.h"
pdw's avatar
pdw committed
32

pdw's avatar
pdw committed
33 34
#define HELP_TIME 2

pdw's avatar
pdw committed
35
#define HELP_MESSAGE \
chris's avatar
chris committed
36
"Host display:                          General:\n"\
37
" n - toggle DNS host resolution         P - pause display\n"\
chris's avatar
chris committed
38 39
" s - toggle show source host            h - toggle this help display\n"\
" d - toggle show destination host       b - toggle bar graph display\n"\
pdw's avatar
pdw committed
40
" t - cycle line display mode            B - cycle bar graph average\n"\
41
"                                        T - toggle cumulative line totals\n"\
pdw's avatar
pdw committed
42
"Port display:                           j/k - scroll display\n"\
43
" N - toggle service resolution          f - edit filter code\n"\
pdw's avatar
pdw committed
44 45 46 47
" S - toggle show source port            l - set screen filter\n"\
" D - toggle show destination port       L - lin/log scales\n"\
" p - toggle port display                ! - shell command\n"\
"                                        q - quit\n"\
chris's avatar
chris committed
48
"Sorting:\n"\
pdw's avatar
pdw committed
49 50 51
" 1/2/3 - sort by 1st/2nd/3rd column\n"\
" < - sort by source name\n"\
" > - sort by dest name\n"\
52
" o - freeze current order\n"\
chris's avatar
chris committed
53
"\n"\
54
"iftop, version " PACKAGE_VERSION
pdw's avatar
pdw committed
55 56


pdw's avatar
pdw committed
57 58 59 60
extern hash_type* history;
extern int history_pos;
extern int history_len;

pdw's avatar
pdw committed
61 62
extern options_t options ;

chris's avatar
chris committed
63 64
void ui_finish();

pdw's avatar
pdw committed
65
#define HELP_MSG_SIZE 80
pdw's avatar
pdw committed
66
int showhelphint = 0;
67 68
int persistenthelp = 0;
time_t helptimer = 0;
pdw's avatar
pdw committed
69
char helpmsg[HELP_MSG_SIZE];
chris's avatar
chris committed
70
int dontshowdisplay = 0;
pdw's avatar
pdw committed
71

chris's avatar
chris committed
72 73
/* Barchart scales. */
static struct {
74
    long max; int interval;
chris's avatar
chris committed
75
} scale[] = {
76 77 78 79 80 81
        {      64000,     10 },     /* 64 kbit/s */
        {     128000,     10 },
        {     256000,     10 },
        {    1000000,     10 },     /* 1 Mbit/s */
        {   10000000,     10 },     
        {  100000000,    100 },
82 83 84
        { 1000000000,    100 },     /* 1 Gbit/s */
        {10000000000,    100 },
       {100000000000,    100 }
chris's avatar
chris committed
85 86
    };
static int rateidx = 0, wantbiggerrate;
chris's avatar
chris committed
87

88 89
static int rateidx_init = 0;

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
static int get_bar_interval(float bandwidth) {
    int i = 10;
    if(bandwidth > 100000000) {
        i = 100;
    }
    return i;
}

static float get_max_bandwidth() {
    float max;
    if(options.max_bandwidth > 0) {
        max = options.max_bandwidth;
    }
    else {
        max = scale[rateidx].max;
    }
    return max;
}

109
/* rate in bits */
110
static int get_bar_length(const long rate) {
chris's avatar
chris committed
111 112 113
    float l;
    if (rate <= 0)
        return 0;
114 115 116 117 118 119 120 121
    if (rate > scale[rateidx].max) {
      wantbiggerrate = 1;
      if(! rateidx_init) {
	while(rate > scale[rateidx_init++].max) {
	}
	rateidx = rateidx_init;
      }
    }
122 123 124 125 126 127
    if(options.log_scale) {
        l = log(rate) / log(get_max_bandwidth());
    }
    else {
        l = rate / get_max_bandwidth();
    }
pdw's avatar
pdw committed
128
    return (l * COLS);
chris's avatar
chris committed
129 130
}

pdw's avatar
pdw committed
131
static void draw_bar_scale(int* y) {
132
    float i;
133 134 135
    float max,interval;
    max = get_max_bandwidth();
    interval = get_bar_interval(max);
pdw's avatar
pdw committed
136
    if(options.showbars) {
137
        float stop;
pdw's avatar
pdw committed
138
        /* Draw bar graph scale on top of the window. */
chris's avatar
chris committed
139 140
        move(*y, 0);
        clrtoeol();
pdw's avatar
pdw committed
141
        mvhline(*y + 1, 0, 0, COLS);
142
        /* i in bytes */
143 144 145 146 147 148 149 150 151 152 153 154

        if(options.log_scale) {
            i = 1.25;
            stop = max / 8;
        }
        else {
            i = max / (5 * 8);
            stop = max / 8;
        }

        /* for (i = 1.25; i * 8 <= max; i *= interval) { */
        while(i <= stop) {
pdw's avatar
pdw committed
155 156
            char s[40], *p;
            int x;
157
            /* This 1024 vs 1000 stuff is just plain evil */
158
            readable_size(i, s, sizeof s, options.log_scale ? 1000 : 1024, options.bandwidth_unit);
pdw's avatar
pdw committed
159
            p = s + strspn(s, " ");
160
            x = get_bar_length(i * 8);
pdw's avatar
pdw committed
161 162 163 164
            mvaddch(*y + 1, x, ACS_BTEE);
            if (x + strlen(p) >= COLS)
                x = COLS - strlen(p);
            mvaddstr(*y, x, p);
165 166 167 168 169 170 171

            if(options.log_scale) {
                i *= interval;
            }
            else {
                i += max / (5 * 8);
            }
pdw's avatar
pdw committed
172 173 174 175 176 177 178
        }
        mvaddch(*y + 1, 0, ACS_LLCORNER);
        *y += 2;
    }
    else {
        mvhline(*y, 0, 0, COLS);
        *y += 1;
chris's avatar
chris committed
179
    }
pdw's avatar
pdw committed
180 181
}

182
void draw_line_total(float sent, float recv, int y, int x, option_linedisplay_t linedisplay, option_bw_unit_t unit) {
pdw's avatar
pdw committed
183
    char buf[10];
184
    float n = 0;
pdw's avatar
pdw committed
185 186
    switch(linedisplay) {
        case OPTION_LINEDISPLAY_TWO_LINE:
187 188
          draw_line_total(sent, recv, y, x, OPTION_LINEDISPLAY_ONE_LINE_SENT, unit);
          draw_line_total(sent, recv, y+1, x, OPTION_LINEDISPLAY_ONE_LINE_RECV, unit);
pdw's avatar
pdw committed
189 190 191 192 193 194 195 196 197 198 199 200
          break;
        case OPTION_LINEDISPLAY_ONE_LINE_SENT:
          n = sent;
          break;
        case OPTION_LINEDISPLAY_ONE_LINE_RECV:
          n = recv;
          break;
        case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
          n = recv + sent;
          break;
    }
    if(linedisplay != OPTION_LINEDISPLAY_TWO_LINE) {
201
        readable_size(n, buf, 10, 1024, unit);
pdw's avatar
pdw committed
202 203
        mvaddstr(y, x, buf);
    }
pdw's avatar
pdw committed
204 205 206
}

void draw_bar(float n, int y) {
207 208 209 210 211
    int L;
    mvchgat(y, 0, -1, A_NORMAL, 0, NULL);
    L = get_bar_length(8 * n);
    if (L > 0)
        mvchgat(y, 0, L + 1, A_REVERSE, 0, NULL);
pdw's avatar
pdw committed
212 213 214 215
}

void draw_line_totals(int y, host_pair_line* line, option_linedisplay_t linedisplay) {
    int j;
pdw's avatar
pdw committed
216 217 218
    int x = (COLS - 8 * HISTORY_DIVISIONS);

    for(j = 0; j < HISTORY_DIVISIONS; j++) {
219
        draw_line_total(line->sent[j], line->recv[j], y, x, linedisplay, options.bandwidth_unit);
pdw's avatar
pdw committed
220
        x += 8;
pdw's avatar
pdw committed
221
    }
chris's avatar
chris committed
222
    
pdw's avatar
pdw committed
223
    if(options.showbars) {
pdw's avatar
pdw committed
224 225
      switch(linedisplay) {
        case OPTION_LINEDISPLAY_TWO_LINE:
pdw's avatar
pdw committed
226 227
          draw_bar(line->sent[options.bar_interval],y);
          draw_bar(line->recv[options.bar_interval],y+1);
pdw's avatar
pdw committed
228 229
          break;
        case OPTION_LINEDISPLAY_ONE_LINE_SENT:
pdw's avatar
pdw committed
230
          draw_bar(line->sent[options.bar_interval],y);
pdw's avatar
pdw committed
231 232
          break;
        case OPTION_LINEDISPLAY_ONE_LINE_RECV:
pdw's avatar
pdw committed
233
          draw_bar(line->recv[options.bar_interval],y);
pdw's avatar
pdw committed
234 235
          break;
        case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
pdw's avatar
pdw committed
236
          draw_bar(line->recv[options.bar_interval] + line->sent[options.bar_interval],y);
pdw's avatar
pdw committed
237 238
          break;
      }
pdw's avatar
pdw committed
239
    }
pdw's avatar
pdw committed
240 241 242 243
}

void draw_totals(host_pair_line* totals) {
    /* Draw rule */
pdw's avatar
pdw committed
244
    int y = LINES - 4;
pdw's avatar
pdw committed
245
    int j;
pdw's avatar
pdw committed
246 247
    char buf[10];
    int x = (COLS - 8 * HISTORY_DIVISIONS);
pdw's avatar
pdw committed
248
    y++;
pdw's avatar
pdw committed
249
    draw_line_totals(y, totals, OPTION_LINEDISPLAY_TWO_LINE);
pdw's avatar
pdw committed
250 251
    y += 2;
    for(j = 0; j < HISTORY_DIVISIONS; j++) {
252
        readable_size((totals->sent[j] + totals->recv[j]) , buf, 10, 1024, options.bandwidth_unit);
pdw's avatar
pdw committed
253 254 255
        mvaddstr(y, x, buf);
        x += 8;
    }
chris's avatar
chris committed
256 257
}

pdw's avatar
pdw committed
258
extern history_type history_totals;
pdw's avatar
pdw committed
259

pdw's avatar
pdw committed
260

261 262
void ui_print() {
    sorted_list_node* nn = NULL;
263
    char host1[HOSTNAME_LENGTH], host2[HOSTNAME_LENGTH];
264 265
    static char *line;
    static int lcols;
pdw's avatar
pdw committed
266
    int y = 0;
267
    option_bw_unit_t cumunit;
268

chris's avatar
chris committed
269 270 271
    if (dontshowdisplay)
        return;

272 273 274 275 276
    if (!line || lcols != COLS) {
        xfree(line);
        line = calloc(COLS + 1, 1);
    }

pdw's avatar
pdw committed
277 278 279 280 281
    /* 
     * erase() is faster than clear().  Dunno why we switched to 
     * clear() -pdw 24/10/02
     */
    erase();
282

283 284
    draw_bar_scale(&y);

pdw's avatar
pdw committed
285 286 287 288
    if(options.showhelp) {
      mvaddstr(y,0,HELP_MESSAGE);
    }
    else {
pdw's avatar
pdw committed
289 290 291 292 293
      int i = 0;

      while(i < options.screen_offset && ((nn = sorted_list_next_item(&screen_list, nn)) != NULL)) {
        i++;
      }
294

pdw's avatar
pdw committed
295 296 297
      /* Screen layout: we have 2 * HISTORY_DIVISIONS 6-character wide history
       * items, and so can use COLS - 12 * HISTORY_DIVISIONS to print the two
       * host names. */
chris's avatar
chris committed
298

pdw's avatar
pdw committed
299 300 301
      if(i == 0 || nn != NULL) {
        while((y < LINES - 5) && ((nn = sorted_list_next_item(&screen_list, nn)) != NULL)) {
            int x = 0, L;
302

pdw's avatar
pdw committed
303

pdw's avatar
pdw committed
304
            host_pair_line* screen_line = (host_pair_line*)nn->data;
pdw's avatar
pdw committed
305

pdw's avatar
pdw committed
306 307
            if(y < LINES - 5) {
                L = (COLS - 8 * HISTORY_DIVISIONS - 4) / 2;
pdw's avatar
pdw committed
308 309 310
                if(options.show_totals) {
                    L -= 4;    
                }
pdw's avatar
pdw committed
311 312 313
                if(L > HOSTNAME_LENGTH) {
                    L = HOSTNAME_LENGTH;
                }
314

315 316 317
                sprint_host(host1, screen_line->ap.af,
                            &(screen_line->ap.src6),
                            screen_line->ap.src_port,
318
                            screen_line->ap.protocol, L, options.aggregate_src);
319 320 321
                sprint_host(host2, screen_line->ap.af,
                            &(screen_line->ap.dst6),
                            screen_line->ap.dst_port,
322
                            screen_line->ap.protocol, L, options.aggregate_dest);
323

pdw's avatar
pdw committed
324 325 326
                if(!screen_filter_match(host1) && !screen_filter_match(host2)) {
                  continue;
                }
pdw's avatar
pdw committed
327

pdw's avatar
pdw committed
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
                mvaddstr(y, x, host1);
                x += L;

                switch(options.linedisplay) {
                  case OPTION_LINEDISPLAY_TWO_LINE:
                    mvaddstr(y, x, " => ");
                    mvaddstr(y+1, x, " <= ");
                    break;
                  case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
                    mvaddstr(y, x, "<=> ");
                    break;
                  case OPTION_LINEDISPLAY_ONE_LINE_SENT:
                    mvaddstr(y, x, " => ");
                    break;
                  case OPTION_LINEDISPLAY_ONE_LINE_RECV:
                    mvaddstr(y, x, " <= ");
                    break;
                }
pdw's avatar
pdw committed
346

pdw's avatar
pdw committed
347
                x += 4;
348 349


pdw's avatar
pdw committed
350 351
                mvaddstr(y, x, host2);
                
pdw's avatar
pdw committed
352 353 354 355
                if(options.show_totals) {
                    draw_line_total(screen_line->total_sent, screen_line->total_recv, y, COLS - 8 * (HISTORY_DIVISIONS + 1), options.linedisplay, 1);
                }

pdw's avatar
pdw committed
356
                draw_line_totals(y, screen_line, options.linedisplay);
pdw's avatar
pdw committed
357

pdw's avatar
pdw committed
358 359 360 361 362 363 364 365
            }
            if(options.linedisplay == OPTION_LINEDISPLAY_TWO_LINE) {
              y += 2;
            }
            else {
              y += 1;
            }
        }
pdw's avatar
pdw committed
366
      }
pdw's avatar
pdw committed
367
    }
pdw's avatar
pdw committed
368 369


pdw's avatar
pdw committed
370
    y = LINES - 3;
pdw's avatar
pdw committed
371 372
    
    mvhline(y-1, 0, 0, COLS);
pdw's avatar
pdw committed
373

pdw's avatar
pdw committed
374 375
    mvaddstr(y, 0, "TX: ");
    mvaddstr(y+1, 0, "RX: ");
pdw's avatar
pdw committed
376
    mvaddstr(y+2, 0, "TOTAL: ");
pdw's avatar
pdw committed
377

pdw's avatar
pdw committed
378
    /* Cummulative totals */
379
    mvaddstr(y, 16, "cum: ");
pdw's avatar
pdw committed
380

381 382 383 384 385 386 387
    /* Previous versions of iftop always displayed totals in bytes, even when
       use-bytes = false. Stay compatible when the default unit hasn't been
       changed. */
    cumunit = options.bandwidth_unit;
    if (cumunit == OPTION_BW_BITS)
      cumunit = OPTION_BW_BYTES;
    readable_size(history_totals.total_sent, line, 10, 1024, cumunit);
pdw's avatar
pdw committed
388 389
    mvaddstr(y, 22, line);

390
    readable_size(history_totals.total_recv, line, 10, 1024, cumunit);
pdw's avatar
pdw committed
391 392
    mvaddstr(y+1, 22, line);

393
    readable_size(history_totals.total_recv + history_totals.total_sent, line, 10, 1024, cumunit);
pdw's avatar
pdw committed
394
    mvaddstr(y+2, 22, line);
pdw's avatar
pdw committed
395 396 397

    /* peak traffic */
    mvaddstr(y, 32, "peak: ");
pdw's avatar
pdw committed
398

399
    readable_size(peaksent / RESOLUTION, line, 10, 1024, options.bandwidth_unit);
pdw's avatar
pdw committed
400
    mvaddstr(y, 39, line);
pdw's avatar
pdw committed
401

402
    readable_size(peakrecv / RESOLUTION, line, 10, 1024, options.bandwidth_unit);
pdw's avatar
pdw committed
403
    mvaddstr(y+1, 39, line);
pdw's avatar
pdw committed
404

405
    readable_size(peaktotal / RESOLUTION, line, 10, 1024, options.bandwidth_unit);
pdw's avatar
pdw committed
406
    mvaddstr(y+2, 39, line);
pdw's avatar
pdw committed
407 408

    mvaddstr(y, COLS - 8 * HISTORY_DIVISIONS - 8, "rates:");
pdw's avatar
pdw committed
409

chris's avatar
chris committed
410
    draw_totals(&totals);
pdw's avatar
pdw committed
411

pdw's avatar
pdw committed
412

pdw's avatar
pdw committed
413
    if(showhelphint) {
chris's avatar
chris committed
414 415 416 417
      mvaddstr(0, 0, " ");
      mvaddstr(0, 1, helpmsg);
      mvaddstr(0, 1 + strlen(helpmsg), " ");
      mvchgat(0, 0, strlen(helpmsg) + 2, A_REVERSE, 0, NULL);
pdw's avatar
pdw committed
418
    }
419
    move(LINES - 1, COLS - 1);
chris's avatar
chris committed
420
    
pdw's avatar
pdw committed
421 422
    refresh();

chris's avatar
chris committed
423
    /* Bar chart auto scale */
424
    if (wantbiggerrate && options.max_bandwidth == 0) {
425 426
      ++rateidx;
      wantbiggerrate = 0;
chris's avatar
chris committed
427
    }
pdw's avatar
pdw committed
428 429
}

pdw's avatar
pdw committed
430 431 432 433
void ui_tick(int print) {
  if(print) {
    ui_print();
  }
434
  else if(showhelphint && (time(NULL) - helptimer > HELP_TIME) && !persistenthelp) {
pdw's avatar
pdw committed
435 436 437 438 439
    showhelphint = 0;
    ui_print();
  }
}

chris's avatar
chris committed
440
void ui_curses_init() {
pdw's avatar
pdw committed
441 442 443 444 445
    (void) initscr();      /* initialize the curses library */
    keypad(stdscr, TRUE);  /* enable keyboard mapping */
    (void) nonl();         /* tell curses not to do NL->CR/NL on output */
    (void) cbreak();       /* take input chars one at a time, no wait for \n */
    (void) noecho();       /* don't echo input */
446
    (void) curs_set(0);    /* hide blinking cursor in ui */
pdw's avatar
pdw committed
447
    halfdelay(2);
chris's avatar
chris committed
448
}
pdw's avatar
pdw committed
449

450 451 452 453 454 455 456 457
void showhelp(const char * s) {
  strncpy(helpmsg, s, HELP_MSG_SIZE);
  showhelphint = 1;
  helptimer = time(NULL);
  persistenthelp = 0;
  tick(1);
}

chris's avatar
chris committed
458
void ui_init() {
459
    char msg[20];
chris's avatar
chris committed
460 461
    ui_curses_init();
    
chris's avatar
chris committed
462
    erase();
463 464

    screen_list_init();
465
    screen_hash = addr_hash_create();
466

467 468 469
    service_hash = serv_hash_create();
    serv_hash_initialise(service_hash);

470 471
    snprintf(msg,20,"Listening on %s",options.interface);
    showhelp(msg);
472

473

pdw's avatar
pdw committed
474 475
}

476

pdw's avatar
pdw committed
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
void showportstatus() {
  if(options.showports == OPTION_PORTS_ON) {
    showhelp("Port display ON");
  }
  else if(options.showports == OPTION_PORTS_OFF) {
    showhelp("Port display OFF");
  }
  else if(options.showports == OPTION_PORTS_DEST) {
    showhelp("Port display DEST");
  }
  else if(options.showports == OPTION_PORTS_SRC) {
    showhelp("Port display SOURCE");
  }
}

chris's avatar
chris committed
492

493
void ui_loop() {
chris's avatar
chris committed
494 495 496
    /* in edline.c */
    char *edline(int linenum, const char *prompt, const char *initial);
    /* in iftop.c */
chris's avatar
chris committed
497
    char *set_filter_code(const char *filter);
chris's avatar
chris committed
498

499
    extern sig_atomic_t foad;
chris's avatar
chris committed
500

chris's avatar
chris committed
501
    while(foad == 0) {
chris's avatar
chris committed
502
        int i;
503
        i = getch();
chris's avatar
chris committed
504
        switch (i) {
505
            case 'q':
chris's avatar
chris committed
506 507 508
                foad = 1;
                break;

509
            case 'n':
pdw's avatar
pdw committed
510 511 512 513 514 515 516 517
                if(options.dnsresolution) {
                    options.dnsresolution = 0;
                    showhelp("DNS resolution off");
                }
                else {
                    options.dnsresolution = 1;
                    showhelp("DNS resolution on");
                }
518
                tick(1);
chris's avatar
chris committed
519
                break;
pdw's avatar
pdw committed
520

521
            case 'N':
pdw's avatar
pdw committed
522 523 524 525 526 527 528 529
                if(options.portresolution) {
                    options.portresolution = 0;
                    showhelp("Port resolution off");
                }
                else {
                    options.portresolution = 1;
                    showhelp("Port resolution on");
                }
530 531 532
                tick(1);
                break;

pdw's avatar
pdw committed
533
            case 'h':
chris's avatar
chris committed
534
            case '?':
pdw's avatar
pdw committed
535 536 537 538
                options.showhelp = !options.showhelp;
                tick(1);
                break;

pdw's avatar
pdw committed
539
            case 'b':
pdw's avatar
pdw committed
540 541 542 543 544 545 546 547
                if(options.showbars) {
                    options.showbars = 0;
                    showhelp("Bars off");
                }
                else {
                    options.showbars = 1;
                    showhelp("Bars on");
                }
548
                tick(1);
pdw's avatar
pdw committed
549
                break;
550

pdw's avatar
pdw committed
551 552 553 554 555 556 557 558 559 560 561 562 563
            case 'B':
                options.bar_interval = (options.bar_interval + 1) % 3;
                if(options.bar_interval == 0) {
                    showhelp("Bars show 2s average");
                }
                else if(options.bar_interval == 1) { 
                    showhelp("Bars show 10s average");
                }
                else {
                    showhelp("Bars show 40s average");
                }
                ui_print();
                break;
564
            case 's':
pdw's avatar
pdw committed
565 566 567 568 569 570 571 572
                if(options.aggregate_src) {
                    options.aggregate_src = 0;
                    showhelp("Show source host");
                }
                else {
                    options.aggregate_src = 1;
                    showhelp("Hide source host");
                }
573
                break;
574
            case 'd':
pdw's avatar
pdw committed
575 576 577 578 579 580 581 582
                if(options.aggregate_dest) {
                    options.aggregate_dest = 0;
                    showhelp("Show dest host");
                }
                else {
                    options.aggregate_dest = 1;
                    showhelp("Hide dest host");
                }
583
                break;
584 585 586 587 588 589 590 591 592 593 594 595 596 597
            case 'S':
                /* Show source ports */
                if(options.showports == OPTION_PORTS_OFF) {
                  options.showports = OPTION_PORTS_SRC;
                }
                else if(options.showports == OPTION_PORTS_DEST) {
                  options.showports = OPTION_PORTS_ON;
                }
                else if(options.showports == OPTION_PORTS_ON) {
                  options.showports = OPTION_PORTS_DEST;
                }
                else {
                  options.showports = OPTION_PORTS_OFF;
                }
pdw's avatar
pdw committed
598
                showportstatus();
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
                break;
            case 'D':
                /* Show dest ports */
                if(options.showports == OPTION_PORTS_OFF) {
                  options.showports = OPTION_PORTS_DEST;
                }
                else if(options.showports == OPTION_PORTS_SRC) {
                  options.showports = OPTION_PORTS_ON;
                }
                else if(options.showports == OPTION_PORTS_ON) {
                  options.showports = OPTION_PORTS_SRC;
                }
                else {
                  options.showports = OPTION_PORTS_OFF;
                }
pdw's avatar
pdw committed
614
                showportstatus();
615 616
                break;
            case 'p':
617 618 619 620
                options.showports = 
                  (options.showports == OPTION_PORTS_OFF)
                  ? OPTION_PORTS_ON
                  : OPTION_PORTS_OFF;
pdw's avatar
pdw committed
621
                showportstatus();
622 623
                // Don't tick here, otherwise we get a bogus display
                break;
pdw's avatar
pdw committed
624
            case 'P':
625 626 627 628 629 630 631 632 633
                if(options.paused) {
                    options.paused = 0;
                    showhelp("Display unpaused");
                }
                else {
                    options.paused = 1;
                    showhelp("Display paused");
                    persistenthelp = 1;
                }
pdw's avatar
pdw committed
634
                break;
635 636 637 638 639 640 641 642
            case 'o':
                if(options.freezeorder) {
                    options.freezeorder = 0;
                    showhelp("Order unfrozen");
                }
                else {
                    options.freezeorder = 1;
                    showhelp("Order frozen");
643
                    persistenthelp = 1;
644 645
                }
                break;
pdw's avatar
pdw committed
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
            case '1':
                options.sort = OPTION_SORT_DIV1;
                showhelp("Sort by col 1");
                break;
            case '2':
                options.sort = OPTION_SORT_DIV2;
                showhelp("Sort by col 2");
                break;
            case '3':
                options.sort = OPTION_SORT_DIV3;
                showhelp("Sort by col 3");
                break;
            case '<':
                options.sort = OPTION_SORT_SRC;
                showhelp("Sort by source");
                break;
            case '>':
                options.sort = OPTION_SORT_DEST;
                showhelp("Sort by dest");
                break;
pdw's avatar
pdw committed
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
            case 'j':
                options.screen_offset++;
                ui_print();
                break;
            case 'k':
                if(options.screen_offset > 0) {
                  options.screen_offset--;
                  ui_print();
                }
                break;
            case 't':
                options.linedisplay = (options.linedisplay + 1) % 4;
                switch(options.linedisplay) {
                  case OPTION_LINEDISPLAY_TWO_LINE:
                    showhelp("Two lines per host");
                    break;
                  case OPTION_LINEDISPLAY_ONE_LINE_SENT:
                    showhelp("Sent traffic only");
                    break;
                  case OPTION_LINEDISPLAY_ONE_LINE_RECV:
                    showhelp("Received traffic only");
                    break;
                  case OPTION_LINEDISPLAY_ONE_LINE_BOTH:
                    showhelp("One line per host");
                    break;
                }
                ui_print();
                break;
chris's avatar
chris committed
694 695 696
            case 'f': {
                char *s;
                dontshowdisplay = 1;
697
                if ((s = edline(0, "Net filter", options.filtercode))) {
chris's avatar
chris committed
698
                    char *m;
chris's avatar
chris committed
699 700 701 702 703
                    if (s[strspn(s, " \t")] == 0) {
                        /* Empty filter; set to NULL. */
                        xfree(s);
                        s = NULL;
                    }
chris's avatar
chris committed
704 705 706
                    if (!(m = set_filter_code(s))) {
                        xfree(options.filtercode);
                        options.filtercode = s;
chris's avatar
chris committed
707 708
                        /* -lpcap will write junk to stderr; we do our best to
                         * erase it.... */
chris's avatar
chris committed
709 710 711
                        move(COLS - 1, LINES - 1);
                        wrefresh(curscr);
                        showhelp("Installed new filter");
chris's avatar
chris committed
712 713 714 715 716 717
                    } else {
                        showhelp(m);
                        xfree(s);
                    }
                }
                dontshowdisplay = 0;
pdw's avatar
pdw committed
718
                ui_print();
chris's avatar
chris committed
719 720
                break;
            }
721
            case 'l': {
chris's avatar
chris committed
722
#ifdef HAVE_REGCOMP
723 724 725 726 727 728 729 730
                char *s;
                dontshowdisplay = 1;
                if ((s = edline(0, "Screen filter", options.screenfilter))) {
                    if(!screen_filter_set(s)) {
                        showhelp("Invalid regexp");
                    }
                }
                dontshowdisplay = 0;
pdw's avatar
pdw committed
731
                ui_print();
chris's avatar
chris committed
732 733 734
#else
                showhelp("Sorry, screen filters not supported on this platform")
#endif
735 736
                break;
            }
chris's avatar
chris committed
737
            case '!': {
738
#ifdef ALLOW_SUBSHELL
chris's avatar
chris committed
739 740
                char *s;
                dontshowdisplay = 1;
chris's avatar
chris committed
741
                if ((s = edline(0, "Command", "")) && s[strspn(s, " \t")]) {
chris's avatar
chris committed
742
                    int i, dowait = 0;
chris's avatar
chris committed
743 744 745 746 747 748 749
                    erase();
                    refresh();
                    endwin();
                    errno = 0;
                    i = system(s);
                    if (i == -1 || (i == 127 && errno != 0)) {
                        fprintf(stderr, "system: %s: %s\n", s, strerror(errno));
chris's avatar
chris committed
750
                        dowait = 1;
chris's avatar
chris committed
751 752 753 754 755
                    } else if (i != 0) {
                        if (WIFEXITED(i))
                            fprintf(stderr, "%s: exited with code %d\n", s, WEXITSTATUS(i));
                        else if (WIFSIGNALED(i))
                            fprintf(stderr, "%s: killed by signal %d\n", s, WTERMSIG(i));
chris's avatar
chris committed
756
                        dowait = 1;
chris's avatar
chris committed
757 758
                    }
                    ui_curses_init();
chris's avatar
chris committed
759 760 761 762
                    if (dowait) {
                        fprintf(stderr, "Press any key....");
                        while (getch() == ERR);
                    }
chris's avatar
chris committed
763 764 765 766
                    erase();
                    xfree(s);
                }
                dontshowdisplay = 0;
767 768 769
#else
                showhelp("Sorry, subshells have been disabled.");
#endif
chris's avatar
chris committed
770
                break;
chris's avatar
chris committed
771
            }
pdw's avatar
pdw committed
772 773 774
            case 'T':
                options.show_totals = !options.show_totals;
                if(options.show_totals) {
775
                    showhelp("Show cumulative totals");
pdw's avatar
pdw committed
776 777
                }
                else {
778
                    showhelp("Hide cumulative totals");
pdw's avatar
pdw committed
779 780 781
                }
                ui_print();
                break;
pdw's avatar
pdw committed
782 783 784 785 786
            case 'L':
                options.log_scale = !options.log_scale;
                showhelp(options.log_scale ? "Logarithmic scale" : "Linear scale");
                ui_print();
                break;
chris's avatar
chris committed
787 788 789 790
            case KEY_CLEAR:
            case 12:    /* ^L */
                wrefresh(curscr);
                break;
pdw's avatar
pdw committed
791 792 793
            case ERR:
                break;
            default:
chris's avatar
chris committed
794
                showhelp("Press H or ? for help");
pdw's avatar
pdw committed
795
                break;
pdw's avatar
pdw committed
796
        }
797
        tick(0);
pdw's avatar
pdw committed
798 799 800 801 802 803
    }
}

void ui_finish() {
    endwin();
}