File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / ui / curses.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 14:25:31 2019 UTC (4 years, 9 months ago) by misho
Branches: mtr, MAIN
CVS tags: v0_92, HEAD
mtr ver 0.92

    1: /*
    2:     mtr  --  a network diagnostic tool
    3:     Copyright (C) 1997,1998  Matt Kimball
    4: 
    5:     This program is free software; you can redistribute it and/or modify
    6:     it under the terms of the GNU General Public License version 2 as 
    7:     published by the Free Software Foundation.
    8: 
    9:     This program is distributed in the hope that it will be useful,
   10:     but WITHOUT ANY WARRANTY; without even the implied warranty of
   11:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12:     GNU General Public License for more details.
   13: 
   14:     You should have received a copy of the GNU General Public License
   15:     along with this program; if not, write to the Free Software
   16:     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   17: */
   18: 
   19: #include "config.h"
   20: 
   21: #include "mtr.h"
   22: 
   23: #include <strings.h>
   24: #include <unistd.h>
   25: 
   26: #include <ctype.h>
   27: #include <stdlib.h>
   28: #include <string.h>
   29: #include <time.h>
   30: 
   31: /* MacOSX may need this before socket.h...*/
   32: #if defined(HAVE_SYS_TYPES_H)
   33: #include <sys/types.h>
   34: #endif
   35: 
   36: #include <sys/socket.h>
   37: #include <netinet/in.h>
   38: #include <arpa/inet.h>
   39: 
   40: #if defined(HAVE_NCURSES_H)
   41: #include <ncurses.h>
   42: #elif defined(HAVE_NCURSES_CURSES_H)
   43: #include <ncurses/curses.h>
   44: #elif defined(HAVE_CURSES_H)
   45: #include <curses.h>
   46: #elif defined(HAVE_CURSESX_H)
   47: #include <cursesX.h>
   48: #else
   49: #error No curses header file available
   50: #endif
   51: 
   52: /* This go-around is needed only when compiling with antique version of curses.
   53:    getmaxyx is part of Technical Standard X/Open Curses Issue 4, Version 2 (1996).
   54:    http://pubs.opengroup.org/onlinepubs/9693989999/toc.pdf see page 106 */
   55: #ifndef getmaxyx
   56: #define getmaxyx(win,y,x)	((y) = (win)->_maxy + 1, (x) = (win)->_maxx + 1)
   57: #endif
   58: 
   59: #include "mtr.h"
   60: #include "mtr-curses.h"
   61: #include "net.h"
   62: #include "dns.h"
   63: #include "asn.h"
   64: #include "display.h"
   65: #include "utils.h"
   66: 
   67: 
   68: enum { NUM_FACTORS = 8 };
   69: static double factors[NUM_FACTORS];
   70: static int scale[NUM_FACTORS];
   71: static char block_map[NUM_FACTORS];
   72: 
   73: enum { black = 1, red, green, yellow, blue, magenta, cyan, white };
   74: static const int block_col[NUM_FACTORS + 1] = {
   75:     COLOR_PAIR(red) | A_BOLD,
   76:     A_NORMAL,
   77:     COLOR_PAIR(green),
   78:     COLOR_PAIR(green) | A_BOLD,
   79:     COLOR_PAIR(yellow) | A_BOLD,
   80:     COLOR_PAIR(magenta) | A_BOLD,
   81:     COLOR_PAIR(magenta),
   82:     COLOR_PAIR(red),
   83:     COLOR_PAIR(red) | A_BOLD
   84: };
   85: 
   86: static void pwcenter(
   87:     char *str)
   88: {
   89:     int maxx;
   90:     size_t cx;
   91:     int __unused_int ATTRIBUTE_UNUSED;
   92: 
   93:     getmaxyx(stdscr, __unused_int, maxx);
   94:     cx = (size_t) (maxx - strlen(str)) / 2;
   95:     printw("%*s%s", (int) cx, "", str);
   96: }
   97: 
   98: 
   99: static char *format_number(
  100:     int n,
  101:     int w,
  102:     char *buf)
  103: {
  104:     if (w != 5)
  105:         /* XXX todo: implement w != 5.. */
  106:         snprintf(buf, w + 1, "%s", "unimpl");
  107:     else if (n < 100000)
  108:         /* buf is good as-is */ ;
  109:     else if (n < 1000000)
  110:         snprintf(buf, w + 1, "%3dk%1d", n / 1000, (n % 1000) / 100);
  111:     else if (n < 10000000)
  112:         snprintf(buf, w + 1, "%1dM%03d", n / 1000000,
  113:                  (n % 1000000) / 1000);
  114:     else if (n < 100000000)
  115:         snprintf(buf, w + 1, "%2dM%02d", n / 1000000,
  116:                  (n % 1000000) / 10000);
  117:     else if (n < 1000000000)
  118:         snprintf(buf, w + 1, "%3dM%01d", n / 1000000,
  119:                  (n % 1000000) / 100000);
  120:     else                        /* if (n < 10000000000) */
  121:         snprintf(buf, w + 1, "%1dG%03d", n / 1000000000,
  122:                  (n % 1000000000) / 1000000);
  123: 
  124:     return buf;
  125: }
  126: 
  127: 
  128: int mtr_curses_keyaction(
  129:     struct mtr_ctl *ctl)
  130: {
  131:     int c = getch();
  132:     int i = 0;
  133:     float f = 0.0;
  134:     char buf[MAXFLD + 1];
  135: 
  136:     if (c == 'Q') {             /* must be checked before c = tolower(c) */
  137:         mvprintw(2, 0, "Type of Service(tos): %d\n", ctl->tos);
  138:         mvprintw(3, 0,
  139:                  "default 0x00, min cost 0x02, rel 0x04,, thr 0x08, low del 0x10...\n");
  140:         move(2, 22);
  141:         refresh();
  142:         while ((c = getch()) != '\n' && i < MAXFLD) {
  143:             attron(A_BOLD);
  144:             printw("%c", c);
  145:             attroff(A_BOLD);
  146:             refresh();
  147:             buf[i++] = c;       /* need more checking on 'c' */
  148:         }
  149:         buf[i] = '\0';
  150:         ctl->tos = atoi(buf);
  151:         if (ctl->tos > 255 || ctl->tos < 0)
  152:             ctl->tos = 0;
  153:         return ActionNone;
  154:     }
  155: 
  156:     c = tolower(c);
  157: 
  158:     switch (c) {
  159:     case 'q':
  160:     case 3:
  161:         return ActionQuit;
  162:     case 12:
  163:         return ActionClear;
  164:     case 19:
  165:     case 'p':
  166:         return ActionPause;
  167:     case 17:
  168:     case ' ':
  169:         return ActionResume;
  170:     case 'r':
  171:         return ActionReset;
  172:     case 'd':
  173:         return ActionDisplay;
  174:     case 'e':
  175:         return ActionMPLS;
  176:     case 'n':
  177:         return ActionDNS;
  178: #ifdef HAVE_IPINFO
  179:     case 'y':
  180:         return ActionII;
  181:     case 'z':
  182:         return ActionAS;
  183: #endif
  184:     case '+':
  185:         return ActionScrollDown;
  186:     case '-':
  187:         return ActionScrollUp;
  188:     case 's':
  189:         mvprintw(2, 0, "Change Packet Size: %d\n", ctl->cpacketsize);
  190:         mvprintw(3, 0, "Size Range: %d-%d, < 0:random.\n", MINPACKET,
  191:                  MAXPACKET);
  192:         move(2, 20);
  193:         refresh();
  194:         while ((c = getch()) != '\n' && i < MAXFLD) {
  195:             attron(A_BOLD);
  196:             printw("%c", c);
  197:             attroff(A_BOLD);
  198:             refresh();
  199:             buf[i++] = c;       /* need more checking on 'c' */
  200:         }
  201:         buf[i] = '\0';
  202:         ctl->cpacketsize = atoi(buf);
  203:         return ActionNone;
  204:     case 'b':
  205:         mvprintw(2, 0, "Ping Bit Pattern: %d\n", ctl->bitpattern);
  206:         mvprintw(3, 0, "Pattern Range: 0(0x00)-255(0xff), <0 random.\n");
  207:         move(2, 18);
  208:         refresh();
  209:         while ((c = getch()) != '\n' && i < MAXFLD) {
  210:             attron(A_BOLD);
  211:             printw("%c", c);
  212:             attroff(A_BOLD);
  213:             refresh();
  214:             buf[i++] = c;       /* need more checking on 'c' */
  215:         }
  216:         buf[i] = '\0';
  217:         ctl->bitpattern = atoi(buf);
  218:         if (ctl->bitpattern > 255)
  219:             ctl->bitpattern = -1;
  220:         return ActionNone;
  221:     case 'i':
  222:         mvprintw(2, 0, "Interval : %0.0f\n\n", ctl->WaitTime);
  223:         move(2, 11);
  224:         refresh();
  225:         while ((c = getch()) != '\n' && i < MAXFLD) {
  226:             attron(A_BOLD);
  227:             printw("%c", c);
  228:             attroff(A_BOLD);
  229:             refresh();
  230:             buf[i++] = c;       /* need more checking on 'c' */
  231:         }
  232:         buf[i] = '\0';
  233: 
  234:         f = atof(buf);
  235: 
  236:         if (f <= 0.0)
  237:             return ActionNone;
  238:         if (getuid() != 0 && f < 1.0)
  239:             return ActionNone;
  240:         ctl->WaitTime = f;
  241: 
  242:         return ActionNone;
  243:     case 'f':
  244:         mvprintw(2, 0, "First TTL: %d\n\n", ctl->fstTTL);
  245:         move(2, 11);
  246:         refresh();
  247:         while ((c = getch()) != '\n' && i < MAXFLD) {
  248:             attron(A_BOLD);
  249:             printw("%c", c);
  250:             attroff(A_BOLD);
  251:             refresh();
  252:             buf[i++] = c;       /* need more checking on 'c' */
  253:         }
  254:         buf[i] = '\0';
  255:         i = atoi(buf);
  256: 
  257:         if (i < 1 || i > ctl->maxTTL)
  258:             return ActionNone;
  259:         ctl->fstTTL = i;
  260: 
  261:         return ActionNone;
  262:     case 'm':
  263:         mvprintw(2, 0, "Max TTL: %d\n\n", ctl->maxTTL);
  264:         move(2, 9);
  265:         refresh();
  266:         while ((c = getch()) != '\n' && i < MAXFLD) {
  267:             attron(A_BOLD);
  268:             printw("%c", c);
  269:             attroff(A_BOLD);
  270:             refresh();
  271:             buf[i++] = c;       /* need more checking on 'c' */
  272:         }
  273:         buf[i] = '\0';
  274:         i = atoi(buf);
  275: 
  276:         if (i < ctl->fstTTL || i > (MaxHost - 1))
  277:             return ActionNone;
  278:         ctl->maxTTL = i;
  279: 
  280:         return ActionNone;
  281:         /* fields to display & their ordering */
  282:     case 'o':
  283:         mvprintw(2, 0, "Fields: %s\n\n", ctl->fld_active);
  284: 
  285:         for (i = 0; i < MAXFLD; i++) {
  286:             if (data_fields[i].descr != NULL)
  287:                 printw("  %s\n", data_fields[i].descr);
  288:         }
  289:         printw("\n");
  290:         move(2, 8);             /* length of "Fields: " */
  291:         refresh();
  292: 
  293:         i = 0;
  294:         while ((c = getch()) != '\n' && i < MAXFLD) {
  295:             if (strchr(ctl->available_options, c)) {
  296:                 attron(A_BOLD);
  297:                 printw("%c", c);
  298:                 attroff(A_BOLD);
  299:                 refresh();
  300:                 buf[i++] = c;   /* Only permit values in "available_options" be entered */
  301:             } else {
  302:                 printf("\a");   /* Illegal character. Beep, ring the bell. */
  303:             }
  304:         }
  305:         buf[i] = '\0';
  306:         if (strlen(buf) > 0)
  307:             xstrncpy(ctl->fld_active, buf, 2 * MAXFLD);
  308: 
  309:         return ActionNone;
  310:     case 'j':
  311:         if (strchr(ctl->fld_active, 'N'))
  312:             /* GeoMean and jitter */
  313:             xstrncpy(ctl->fld_active, "DR AGJMXI", 2 * MAXFLD);
  314:         else
  315:             /* default */
  316:             xstrncpy(ctl->fld_active, "LS NABWV", 2 * MAXFLD);
  317:         return ActionNone;
  318:     case 'u':
  319:         switch (ctl->mtrtype) {
  320:         case IPPROTO_ICMP:
  321:         case IPPROTO_TCP:
  322:             ctl->mtrtype = IPPROTO_UDP;
  323:             break;
  324:         case IPPROTO_UDP:
  325:             ctl->mtrtype = IPPROTO_ICMP;
  326:             break;
  327:         }
  328:         return ActionNone;
  329:     case 't':
  330:         switch (ctl->mtrtype) {
  331:         case IPPROTO_ICMP:
  332:         case IPPROTO_UDP:
  333:             ctl->mtrtype = IPPROTO_TCP;
  334:             break;
  335:         case IPPROTO_TCP:
  336:             ctl->mtrtype = IPPROTO_ICMP;
  337:             break;
  338:         }
  339:         return ActionNone;
  340:         /* reserve to display help message -Min */
  341:     case '?':
  342:     case 'h':
  343:         mvprintw(2, 0, "Command:\n");
  344:         printw("  ?|h     help\n");
  345:         printw("  p       pause (SPACE to resume)\n");
  346:         printw("  d       switching display mode\n");
  347:         printw("  e       toggle MPLS information on/off\n");
  348:         printw("  n       toggle DNS on/off\n");
  349:         printw("  r       reset all counters\n");
  350:         printw
  351:             ("  o str   set the columns to display, default str='LRS N BAWV'\n");
  352:         printw
  353:             ("  j       toggle latency(LS NABWV)/jitter(DR AGJMXI) stats\n");
  354:         printw("  c <n>   report cycle n, default n=infinite\n");
  355:         printw
  356:             ("  i <n>   set the ping interval to n seconds, default n=1\n");
  357:         printw
  358:             ("  f <n>   set the initial time-to-live(ttl), default n=1\n");
  359:         printw
  360:             ("  m <n>   set the max time-to-live, default n= # of hops\n");
  361:         printw("  s <n>   set the packet size to n or random(n<0)\n");
  362:         printw
  363:             ("  b <c>   set ping bit pattern to c(0..255) or random(c<0)\n");
  364:         printw("  Q <t>   set ping packet's TOS to t\n");
  365:         printw("  u       switch between ICMP ECHO and UDP datagrams\n");
  366: #ifdef HAVE_IPINFO
  367:         printw("  y       switching IP info\n");
  368:         printw("  z       toggle ASN info on/off\n");
  369: #endif
  370:         printw("\n");
  371:         printw(" press any key to go back...");
  372:         getch();                /* read and ignore 'any key' */
  373:         return ActionNone;
  374:     default:                   /* ignore unknown input */
  375:         return ActionNone;
  376:     }
  377: }
  378: 
  379: 
  380: static void format_field(
  381:     char *dst,
  382:     int dst_length,
  383:     const char *format,
  384:     int n)
  385: {
  386:     if (index(format, 'N')) {
  387:         *dst++ = ' ';
  388:         format_number(n, 5, dst);
  389:     } else if (strchr(format, 'f')) {
  390:         /* this is for fields where we measure integer microseconds but
  391:            display floating point miliseconds. Convert to float here. */
  392:         snprintf(dst, dst_length, format, n / 1000.0);
  393:         /* this was marked as a temporary hack over 10 years ago. -- REW */
  394:     } else {
  395:         snprintf(dst, dst_length, format, n);
  396:     }
  397: }
  398: 
  399: static void mtr_curses_hosts(
  400:     struct mtr_ctl *ctl,
  401:     int startstat)
  402: {
  403:     int max;
  404:     int at;
  405:     struct mplslen *mpls, *mplss;
  406:     ip_t *addr, *addrs;
  407:     int y;
  408:     char *name;
  409: 
  410:     int i, j, k;
  411:     int hd_len;
  412:     char buf[1024];
  413:     int __unused_int ATTRIBUTE_UNUSED;
  414: 
  415:     max = net_max(ctl);
  416: 
  417:     for (at = net_min(ctl) + ctl->display_offset; at < max; at++) {
  418:         printw("%2d. ", at + 1);
  419:         addr = net_addr(at);
  420:         mpls = net_mpls(at);
  421: 
  422:         if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af) !=
  423:             0) {
  424:             name = dns_lookup(ctl, addr);
  425:             if (!net_up(at))
  426:                 attron(A_BOLD);
  427: #ifdef HAVE_IPINFO
  428:             if (is_printii(ctl))
  429:                 printw(fmt_ipinfo(ctl, addr));
  430: #endif
  431:             if (name != NULL) {
  432:                 if (ctl->show_ips)
  433:                     printw("%s (%s)", name, strlongip(ctl, addr));
  434:                 else
  435:                     printw("%s", name);
  436:             } else {
  437:                 printw("%s", strlongip(ctl, addr));
  438:             }
  439:             attroff(A_BOLD);
  440: 
  441:             getyx(stdscr, y, __unused_int);
  442:             move(y, startstat);
  443: 
  444:             /* net_xxx returns times in usecs. Just display millisecs */
  445:             hd_len = 0;
  446:             for (i = 0; i < MAXFLD; i++) {
  447:                 /* Ignore options that don't exist */
  448:                 /* On the other hand, we now check the input side. Shouldn't happen, 
  449:                    can't be careful enough. */
  450:                 j = ctl->fld_index[ctl->fld_active[i]];
  451:                 if (j == -1)
  452:                     continue;
  453:                 format_field(buf + hd_len, sizeof(buf) - hd_len,
  454:                              data_fields[j].format,
  455:                              data_fields[j].net_xxx(at));
  456:                 hd_len += data_fields[j].length;
  457:             }
  458:             buf[hd_len] = 0;
  459:             printw("%s", buf);
  460: 
  461:             for (k = 0; k < mpls->labels && ctl->enablempls; k++) {
  462:                 printw("\n    [MPLS: Lbl %lu Exp %u S %u TTL %u]",
  463:                        mpls->label[k], mpls->exp[k], mpls->s[k],
  464:                        mpls->ttl[k]);
  465:             }
  466: 
  467:             /* Multi path */
  468:             for (i = 0; i < MAXPATH; i++) {
  469:                 addrs = net_addrs(at, i);
  470:                 mplss = net_mplss(at, i);
  471:                 if (addrcmp((void *) addrs, (void *) addr, ctl->af) == 0)
  472:                     continue;
  473:                 if (addrcmp
  474:                     ((void *) addrs, (void *) &ctl->unspec_addr,
  475:                      ctl->af) == 0)
  476:                     break;
  477: 
  478:                 name = dns_lookup(ctl, addrs);
  479:                 if (!net_up(at))
  480:                     attron(A_BOLD);
  481:                 printw("\n    ");
  482: #ifdef HAVE_IPINFO
  483:                 if (is_printii(ctl))
  484:                     printw(fmt_ipinfo(ctl, addrs));
  485: #endif
  486:                 if (name != NULL) {
  487:                     if (ctl->show_ips)
  488:                         printw("%s (%s)", name, strlongip(ctl, addrs));
  489:                     else
  490:                         printw("%s", name);
  491:                 } else {
  492:                     printw("%s", strlongip(ctl, addrs));
  493:                 }
  494:                 for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
  495:                     printw("\n    [MPLS: Lbl %lu Exp %u S %u TTL %u]",
  496:                            mplss->label[k], mplss->exp[k], mplss->s[k],
  497:                            mplss->ttl[k]);
  498:                 }
  499:                 attroff(A_BOLD);
  500:             }
  501: 
  502:         } else {
  503:             printw("???");
  504:         }
  505: 
  506:         printw("\n");
  507:     }
  508:     move(2, 0);
  509: }
  510: 
  511: static void mtr_gen_scale(
  512:     struct mtr_ctl *ctl)
  513: {
  514:     int *saved, i, max, at;
  515:     int range;
  516:     static int low_ms, high_ms;
  517: 
  518:     low_ms = 1000000;
  519:     high_ms = -1;
  520: 
  521:     for (i = 0; i < NUM_FACTORS; i++) {
  522:         scale[i] = 0;
  523:     }
  524:     max = net_max(ctl);
  525:     for (at = ctl->display_offset; at < max; at++) {
  526:         saved = net_saved_pings(at);
  527:         for (i = 0; i < SAVED_PINGS; i++) {
  528:             if (saved[i] < 0)
  529:                 continue;
  530:             if (saved[i] < low_ms) {
  531:                 low_ms = saved[i];
  532:             }
  533:             if (saved[i] > high_ms) {
  534:                 high_ms = saved[i];
  535:             }
  536:         }
  537:     }
  538:     range = high_ms - low_ms;
  539:     for (i = 0; i < NUM_FACTORS; i++) {
  540:         scale[i] = low_ms + ((double) range * factors[i]);
  541:     }
  542: }
  543: 
  544: static void mtr_curses_init(
  545:     void)
  546: {
  547:     int i;
  548:     int block_split;
  549: 
  550:     /* Initialize factors to a log scale. */
  551:     for (i = 0; i < NUM_FACTORS; i++) {
  552:         factors[i] = ((double) 1 / NUM_FACTORS) * (i + 1);
  553:         factors[i] *= factors[i];       /* Squared. */
  554:     }
  555: 
  556:     /* Initialize block_map.  The block_split is always smaller than 9 */
  557:     block_split = (NUM_FACTORS - 2) / 2;
  558:     for (i = 1; i <= block_split; i++) {
  559:         block_map[i] = '0' + i;
  560:     }
  561:     for (i = block_split + 1; i < NUM_FACTORS - 1; i++) {
  562:         block_map[i] = 'a' + i - block_split - 1;
  563:     }
  564:     block_map[0] = '.';
  565:     block_map[NUM_FACTORS - 1] = '>';
  566: }
  567: 
  568: static void mtr_print_scaled(
  569:     int ms)
  570: {
  571:     int i;
  572: 
  573:     for (i = 0; i < NUM_FACTORS; i++) {
  574:         if (ms <= scale[i]) {
  575:             attrset(block_col[i + 1]);
  576:             printw("%c", block_map[i]);
  577:             attrset(A_NORMAL);
  578:             return;
  579:         }
  580:     }
  581:     printw(">");
  582: }
  583: 
  584: 
  585: static void mtr_fill_graph(
  586:     struct mtr_ctl *ctl,
  587:     int at,
  588:     int cols)
  589: {
  590:     int *saved;
  591:     int i;
  592: 
  593:     saved = net_saved_pings(at);
  594:     for (i = SAVED_PINGS - cols; i < SAVED_PINGS; i++) {
  595:         if (saved[i] == -2) {
  596:             printw(" ");
  597:         } else if (saved[i] == -1) {
  598:             attrset(block_col[0]);
  599:             printw("%c", '?');
  600:             attrset(A_NORMAL);
  601:         } else {
  602:             if (ctl->display_mode == DisplayModeBlockmap) {
  603:                 if (saved[i] > scale[6]) {
  604:                     printw("%c", block_map[NUM_FACTORS - 1]);
  605:                 } else {
  606:                     printw(".");
  607:                 }
  608:             } else {
  609:                 mtr_print_scaled(saved[i]);
  610:             }
  611:         }
  612:     }
  613: }
  614: 
  615: 
  616: static void mtr_curses_graph(
  617:     struct mtr_ctl *ctl,
  618:     int startstat,
  619:     int cols)
  620: {
  621:     int max, at, y;
  622:     ip_t *addr;
  623:     char *name;
  624:     int __unused_int ATTRIBUTE_UNUSED;
  625: 
  626:     max = net_max(ctl);
  627: 
  628:     for (at = ctl->display_offset; at < max; at++) {
  629:         printw("%2d. ", at + 1);
  630: 
  631:         addr = net_addr(at);
  632:         if (!addr) {
  633:             printw("???\n");
  634:             continue;
  635:         }
  636: 
  637:         if (!net_up(at))
  638:             attron(A_BOLD);
  639:         if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
  640: #ifdef HAVE_IPINFO
  641:             if (is_printii(ctl))
  642:                 printw(fmt_ipinfo(ctl, addr));
  643: #endif
  644:             name = dns_lookup(ctl, addr);
  645:             printw("%s", name ? name : strlongip(ctl, addr));
  646:         } else
  647:             printw("???");
  648:         attroff(A_BOLD);
  649: 
  650:         getyx(stdscr, y, __unused_int);
  651:         move(y, startstat);
  652: 
  653:         printw(" ");
  654:         mtr_fill_graph(ctl, at, cols);
  655:         printw("\n");
  656:     }
  657: }
  658: 
  659: 
  660: void mtr_curses_redraw(
  661:     struct mtr_ctl *ctl)
  662: {
  663:     int maxx;
  664:     int startstat;
  665:     int rowstat;
  666:     time_t t;
  667:     int __unused_int ATTRIBUTE_UNUSED;
  668: 
  669:     int i, j;
  670:     int hd_len = 0;
  671:     char buf[1024];
  672:     char fmt[16];
  673: 
  674: 
  675:     erase();
  676:     getmaxyx(stdscr, __unused_int, maxx);
  677: 
  678:     rowstat = 5;
  679: 
  680:     move(0, 0);
  681:     attron(A_BOLD);
  682:     snprintf(buf, sizeof(buf), "%s%s%s", "My traceroute  [v",
  683:              PACKAGE_VERSION, "]");
  684:     pwcenter(buf);
  685:     attroff(A_BOLD);
  686: 
  687:     mvprintw(1, 0, "%s (%s)", ctl->LocalHostname, net_localaddr());
  688:     t = time(NULL);
  689:     mvprintw(1, maxx - 25, iso_time(&t));
  690:     printw("\n");
  691: 
  692:     printw("Keys:  ");
  693:     attron(A_BOLD);
  694:     printw("H");
  695:     attroff(A_BOLD);
  696:     printw("elp   ");
  697:     attron(A_BOLD);
  698:     printw("D");
  699:     attroff(A_BOLD);
  700:     printw("isplay mode   ");
  701:     attron(A_BOLD);
  702:     printw("R");
  703:     attroff(A_BOLD);
  704:     printw("estart statistics   ");
  705:     attron(A_BOLD);
  706:     printw("O");
  707:     attroff(A_BOLD);
  708:     printw("rder of fields   ");
  709:     attron(A_BOLD);
  710:     printw("q");
  711:     attroff(A_BOLD);
  712:     printw("uit\n");
  713: 
  714:     if (ctl->display_mode == DisplayModeDefault) {
  715:         for (i = 0; i < MAXFLD; i++) {
  716:             j = ctl->fld_index[ctl->fld_active[i]];
  717:             if (j < 0)
  718:                 continue;
  719: 
  720:             snprintf(fmt, sizeof(fmt), "%%%ds", data_fields[j].length);
  721:             snprintf(buf + hd_len, sizeof(buf) - hd_len, fmt,
  722:                      data_fields[j].title);
  723:             hd_len += data_fields[j].length;
  724:         }
  725:         attron(A_BOLD);
  726:         mvprintw(rowstat - 1, 0, " Host");
  727:         mvprintw(rowstat - 1, maxx - hd_len - 1, "%s", buf);
  728:         mvprintw(rowstat - 2, maxx - hd_len - 1,
  729:                  "   Packets               Pings");
  730:         attroff(A_BOLD);
  731: 
  732:         move(rowstat, 0);
  733:         mtr_curses_hosts(ctl, maxx - hd_len - 1);
  734: 
  735:     } else {
  736:         char msg[80];
  737:         int padding = 30;
  738:         int max_cols;
  739: 
  740: #ifdef HAVE_IPINFO
  741:         if (is_printii(ctl))
  742:             padding += get_iiwidth(ctl->ipinfo_no);
  743: #endif
  744:         max_cols =
  745:             maxx <= SAVED_PINGS + padding ? maxx - padding : SAVED_PINGS;
  746:         startstat = padding - 2;
  747: 
  748:         snprintf(msg, sizeof(msg), " Last %3d pings", max_cols);
  749:         mvprintw(rowstat - 1, startstat, msg);
  750: 
  751:         attroff(A_BOLD);
  752:         move(rowstat, 0);
  753: 
  754:         mtr_gen_scale(ctl);
  755:         mtr_curses_graph(ctl, startstat, max_cols);
  756: 
  757:         printw("\n");
  758:         attron(A_BOLD);
  759:         printw("Scale:");
  760:         attroff(A_BOLD);
  761: 
  762:         for (i = 0; i < NUM_FACTORS - 1; i++) {
  763:             printw("  ");
  764:             attrset(block_col[i + 1]);
  765:             printw("%c", block_map[i]);
  766:             attrset(A_NORMAL);
  767:             printw(":%d ms", scale[i] / 1000);
  768:         }
  769:         printw("  ");
  770:         attrset(block_col[NUM_FACTORS]);
  771:         printw("%c", block_map[NUM_FACTORS - 1]);
  772:         attrset(A_NORMAL);
  773:     }
  774: 
  775:     refresh();
  776: }
  777: 
  778: 
  779: void mtr_curses_open(
  780:     struct mtr_ctl *ctl)
  781: {
  782:     int bg_col = 0;
  783:     int i;
  784: 
  785:     initscr();
  786:     raw();
  787:     noecho();
  788:     start_color();
  789:     if (use_default_colors() == OK)
  790:         bg_col = -1;
  791:     for (i = 0; i < NUM_FACTORS; i++)
  792:         init_pair(i + 1, i, bg_col);
  793: 
  794:     mtr_curses_init();
  795:     mtr_curses_redraw(ctl);
  796: }
  797: 
  798: 
  799: void mtr_curses_close(
  800:     void)
  801: {
  802:     printw("\n");
  803:     endwin();
  804: }
  805: 
  806: 
  807: void mtr_curses_clear(
  808:     struct mtr_ctl *ctl)
  809: {
  810:     mtr_curses_close();
  811:     mtr_curses_open(ctl);
  812: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>