diff -ur mtr-0.58/AUTHORS mtr-0.59/AUTHORS
--- mtr-0.58/AUTHORS	Thu Apr  1 16:20:07 2004
+++ mtr-0.59/AUTHORS	Tue Aug 10 09:48:16 2004
@@ -26,6 +26,7 @@
         Craig Milo Rogers (Rogers@ISI.EDU)
         Russell Nelson (rn-mtr@crynwr.com)
         Davin Milun (milun@acm.org)
+        Josh Martin (jmartin@columbiaservices.net)
         Alexander V. Lukyanov (lav@yars.free.net)
         Charles Levert (charles@comm.polymtl.ca) 
         Bertrand Leconte (B.Leconte@mail.dotcom.fr)
diff -ur mtr-0.58/NEWS mtr-0.59/NEWS
--- mtr-0.58/NEWS	Wed Apr  7 11:50:40 2004
+++ mtr-0.59/NEWS	Tue Aug 10 10:01:29 2004
@@ -1,4 +1,12 @@
 WHAT'S NEW?
+  v0.59 Josh Martin suggested to add some bounds checking to 
+        the dynamic field code. This caused me to delve in, and
+        rewrite some things. Now 50 lines of code less, but cleaner
+        code. :-)
+
+  v0.58 I don't remember. Fogot to update this. :-( Check the 
+        patch.
+
   v0.57 Lots of whitespace cleanups. And a DNS fix: Don't do DNS
         lookups in raw mode with -n specified. 
 
diff -ur mtr-0.58/README mtr-0.59/README
--- mtr-0.58/README	Thu Mar  7 13:19:11 2002
+++ mtr-0.59/README	Tue Aug 10 10:00:57 2004
@@ -75,3 +75,8 @@
   jitterbug bug-tracking system at http://www.BitWizard.nl/cgi-bin/mtr .
   If you don't have web-access, mail the mailinglist. 
 
+  Patches can be submitted by Email to me, or submitted to the 
+  bug tracking system. Please use unified diffs. 
+
+-- REW
+
diff -ur mtr-0.58/configure mtr-0.59/configure
--- mtr-0.58/configure	Wed Apr  7 11:51:30 2004
+++ mtr-0.59/configure	Wed Apr  7 14:34:43 2004
@@ -699,7 +699,7 @@
 
 PACKAGE=mtr
 
-VERSION=0.58
+VERSION=0.59
 
 if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
   { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
diff -ur mtr-0.58/configure.in mtr-0.59/configure.in
--- mtr-0.58/configure.in	Wed Apr  7 11:51:29 2004
+++ mtr-0.59/configure.in	Wed Apr  7 14:34:42 2004
@@ -1,5 +1,5 @@
 AC_INIT(mtr.c)
-AM_INIT_AUTOMAKE(mtr, 0.58)
+AM_INIT_AUTOMAKE(mtr, 0.59)
 
 
 AC_SUBST(GTK_OBJ)
diff -ur mtr-0.58/curses.c mtr-0.59/curses.c
--- mtr-0.58/curses.c	Mon Apr  5 15:57:35 2004
+++ mtr-0.59/curses.c	Tue Aug 10 09:45:37 2004
@@ -61,7 +61,6 @@
 #include <time.h>
 
 extern char LocalHostname[];
-extern char fld_active[];
 extern int fstTTL;
 extern int maxTTL;
 extern int packetsize;
@@ -70,38 +69,6 @@
 extern float WaitTime;
 
 
-struct fields data_fields[MAXFLD] = {
-  /* Remark, Header, Format, Width, CallBackFunc */
-  { "<sp>: Space between fields", " ",  " ",        1, &net_drop  },   /* 0 */
-  { "L: Loss Ratio",          "Loss%",  " %4.1f%%", 6, &net_loss  },   /* 1 */
-  { "D: Dropped Packets",     "Drop",   " %4d",     5, &net_drop  },   /* 2 */
-  { "R: Received Packets",    "Rcv",    " %5d",     6, &net_returned}, /* 3 */
-  { "S: Sent Packets",        "Snt",    " %5d",     6, &net_xmit  },   /* 4 */
-  { "N: Newest RTT(ms)",      "Last",   " %5.1f",   6, &net_last  },   /* 5 */
-  { "B: Min/Best RTT(ms)",    "Best",   " %5.1f",   6, &net_best  },   /* 6 */
-  { "A: Average RTT(ms)",     "Avg",    " %5.1f",   6, &net_avg   },   /* 7 */
-  { "W: Max/Worst RTT(ms)",   "Wrst",   " %5.1f",   6, &net_worst },   /* 8 */
-  { "V: Standard Deviation",  "StDev",  " %5.1f",   6, &net_stdev },   /* 9 */
-  { "G: Geometric Mean",      "Gmean",  " %5.1f",   6, &net_gmean },   /* 10 */
-  { "J: Current Jitter",      "Jttr",   " %4.1f",   5, &net_jitter},   /* 11 */
-  { "M: Jitter Mean/Avg.",    "Javg",   " %4.1f",   5, &net_javg  },   /* 12 */
-  { "X: Worst Jitter",        "Jmax",   " %4.1f",   5, &net_jworst},   /* 13 */
-  { "I: Interarrival Jitter", "Jint",   " %4.1f",   5, &net_jinta },   /* 14 */
-  { 0, 0, 0, 0, 0 }
-};
-
-
-/* keys: the value in the array is the index number in data_fields[] */
-int fld_index[] = {
-   0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,           /* ' ', 0,1..9 */
-   7,  6, -1,  2, -1, -1, 10, -1, 14, 11, -1,  1, 12,   /* A..M */
-   5, -1, -1, -1,  3,  4, -1, -1,  9,  8, 13, -1, -1,   /* N..Z */
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   /* a..m */
-  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   /* n..z */
-  -1
-};
-
-
 void pwcenter(char *str) 
 {
   int maxx, maxy;
@@ -254,10 +221,12 @@
     refresh();
 
     i = 0;
-    while ( (c=getch ()) != '\n' && i<MAXFLD ) {
-      attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
-      if( (c>= 'A' && c<= 'Z') || c==' ') {
-        buf[i++] = c; /* only accept [ A-Z], can be extend to [a-z0-9] */
+    while ( (c=getch ()) != '\n' && i < MAXFLD ) {
+      if( strchr(available_options, c) ) {
+        attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
+        buf[i++] = c; /* Only permit values in "available_options" be entered */
+      } else {
+        printf("\a"); /* Illegal character. Beep, ring the bell. */
       }
     }
     buf[i] = '\0';
@@ -334,42 +303,34 @@
       /* changedByMin */
       hd_len = 0;
       for( i=0; i<MAXFLD; i++ ) {
-	// assume only a-zA-Z are valid options, and error checking
-	// is done in the input side?
-	if( fld_active[i]>= 'a' && fld_active[i]<= 'z') {
-	  j = fld_active[i] - 'a' + 11 + 26; 
-	} else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') {
-	  j = fld_active[i] - 'A' + 11; 
-	} else if( fld_active[i]>= '0' && fld_active[i]<= '9') {
-	  j = fld_active[i] - '0' +1; 
-	} else if( fld_active[i] == ' ' ) {
-	  j = 0;
-	} else {
-	  continue;	/* ignore stuff don't understand */
-	}
+	/* Ignore options that don't exist */
+	/* On the other hand, we now check the input side. Shouldn't happen, 
+	   can't be careful enough. */
+	j = fld_index[fld_active[i]];
+	if (j == -1) continue; 
 
 	/* temporay hack for stats usec to ms... */
-	if( index( data_fields[ fld_index[j] ].format, 'f' ) ) {
-	  sprintf(buf + hd_len, data_fields[ fld_index[j] ].format,
-		data_fields[ fld_index[j] ].net_xxx(at) /1000.0 );
+	if( index( data_fields[j].format, 'f' ) ) {
+	  sprintf(buf + hd_len, data_fields[j].format,
+		data_fields[j].net_xxx(at) /1000.0 );
 	} else {
-	  sprintf(buf + hd_len, data_fields[ fld_index[j] ].format,
-		data_fields[ fld_index[j] ].net_xxx(at) );
+	  sprintf(buf + hd_len, data_fields[j].format,
+		data_fields[j].net_xxx(at) );
 	}
-	hd_len +=  data_fields[ fld_index[j] ].length;
+	hd_len +=  data_fields[j].length;
       }
       buf[hd_len] = 0;
       printw("%s", buf);
 
       /* Multi path by Min */
-      for( i=0; i<MAXPATH; i++ ) {
+      for (i=0; i < MAXPATH; i++ ) {
         addrs = net_addrs(at, i);
-	if( addrs == addr ) continue;
-	if( addrs == 0 ) break;
+	if (addrs == addr) continue;
+	if (addrs == 0) break;
 
         name = dns_lookup(addrs);
         if (! net_up(at)) attron(A_BOLD);
-        if(name != NULL) {
+        if (name != NULL) {
 	  printw("\n    %s", name);
         } else {
 	  printw("\n    %d.%d.%d.%d",
@@ -549,24 +510,13 @@
   
   if (display_mode == 0) {
     /* changedByMin */
-    for( i=0; i<MAXFLD; i++ ) {
-	// assume only 0-9A-Za-z are valid options, and error checking
-	// is down on the input side
-	if( fld_active[i]>= 'a' && fld_active[i]<= 'z') {
-	  j = fld_active[i] - 'a' + 11 + 26; 
-	} else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') {
-	  j = fld_active[i] - 'A' + 11; 
-	} else if( fld_active[i]>= '0' && fld_active[i]<= '9') {
-	  j = fld_active[i] - '0' +1; 
-	} else if( fld_active[i] == ' ' ) {
-	  j = 0;
-	} else {
-	  continue;	/* ignore unknown */
-	}
-
-	sprintf( fmt, "%%%ds", data_fields[fld_index[j]].length );
-        sprintf( buf + hd_len, fmt, data_fields[fld_index[j]].title );
-	hd_len +=  data_fields[fld_index[j]].length;
+    for (i=0; i < MAXFLD; i++ ) {
+	j = fld_index[fld_active[i]];
+	if (j < 0) continue;
+
+	sprintf( fmt, "%%%ds", data_fields[j].length );
+        sprintf( buf + hd_len, fmt, data_fields[j].title );
+	hd_len +=  data_fields[j].length;
     }
     attron(A_BOLD);
     mvprintw(rowstat - 1, 0, " Host");
@@ -605,6 +555,7 @@
   refresh();
 }
 
+
 void mtr_curses_open() 
 {
   initscr();
@@ -614,11 +565,13 @@
   mtr_curses_redraw();
 }
 
+
 void mtr_curses_close() 
 {  
   printw("\n");
   endwin();
 }
+
 
 void mtr_curses_clear() 
 {
Only in mtr-0.59: depcomp
diff -ur mtr-0.58/mtr.c mtr-0.59/mtr.c
--- mtr-0.58/mtr.c	Thu Apr  1 15:33:27 2004
+++ mtr-0.59/mtr.c	Tue Aug 10 09:58:06 2004
@@ -75,13 +75,51 @@
 int af = DEFAULT_AF;
 
 /* default display field(defined by key in net.h) and order */
-char fld_active[2*MAXFLD] = "LS NABWV";
+unsigned char fld_active[2*MAXFLD] = "LS NABWV";
+char fld_index[256];
+char available_options[MAXFLD];
+
+
+struct fields data_fields[MAXFLD] = {
+  /* key, Remark, Header, Format, Width, CallBackFunc */
+  {' ', "<sp>: Space between fields", " ",  " ",        1, &net_drop  },   /* 0 */
+  {'L', "L: Loss Ratio",          "Loss%",  " %4.1f%%", 6, &net_loss  },   /* 1 */
+  {'D', "D: Dropped Packets",     "Drop",   " %4d",     5, &net_drop  },   /* 2 */
+  {'R', "R: Received Packets",    "Rcv",    " %5d",     6, &net_returned}, /* 3 */
+  {'S', "S: Sent Packets",        "Snt",    " %5d",     6, &net_xmit  },   /* 4 */
+  {'N', "N: Newest RTT(ms)",      "Last",   " %5.1f",   6, &net_last  },   /* 5 */
+  {'B', "B: Min/Best RTT(ms)",    "Best",   " %5.1f",   6, &net_best  },   /* 6 */
+  {'A', "A: Average RTT(ms)",     "Avg",    " %5.1f",   6, &net_avg   },   /* 7 */
+  {'W', "W: Max/Worst RTT(ms)",   "Wrst",   " %5.1f",   6, &net_worst },   /* 8 */
+  {'V', "V: Standard Deviation",  "StDev",  " %5.1f",   6, &net_stdev },   /* 9 */
+  {'G', "G: Geometric Mean",      "Gmean",  " %5.1f",   6, &net_gmean },   /* 10 */
+  {'J', "J: Current Jitter",      "Jttr",   " %4.1f",   5, &net_jitter},   /* 11 */
+  {'M', "M: Jitter Mean/Avg.",    "Javg",   " %4.1f",   5, &net_javg  },   /* 12 */
+  {'X', "X: Worst Jitter",        "Jmax",   " %4.1f",   5, &net_jworst},   /* 13 */
+  {'I', "I: Interarrival Jitter", "Jint",   " %4.1f",   5, &net_jinta },   /* 14 */
+  {'\0', 0, 0, 0, 0, 0 }
+};
 
 
+void init_fld_options (void)
+{
+  int i;
+
+  for (i=0;i < 256;i++)
+    fld_index[i] = -1;
+
+  for (i=0;data_fields[i].key != 0;i++) {
+    available_options[i] = data_fields[i].key;
+    fld_index[data_fields[i].key] = i;
+  }
+  available_options[i] = 0;
+}
+
 
 void parse_arg(int argc, char **argv) 
 {
   int opt;
+  int i;
   static struct option long_options[] = {
     { "version", 0, 0, 'v' },
     { "help", 0, 0, 'h' },
@@ -187,13 +225,23 @@
       if( maxTTL < 1) {                       /* prevent 0 hop */
 	maxTTL = 1;
       }
-      if( fstTTL > maxTTL ) {         /* don't know the pos of -m or -f */
+      if (fstTTL > maxTTL) {         /* don't know the pos of -m or -f */
 	fstTTL = maxTTL;
       }
       break;
     case 'o':
-      /* XXX no error checking on the input string, lazy */
-      strncpy (fld_active, optarg, MAXFLD-1 );
+      /* Check option before passing it on to fld_active. */
+      if (strlen (optarg) > MAXFLD) {
+	fprintf (stderr, "Too many fields: %s\n", optarg);
+        exit (1);
+      }
+      for (i=0; optarg[i]; i++) {
+        if(!strchr(available_options, optarg[i])) {
+          fprintf (stderr, "Unknown field identifier: %c\n", optarg[i]);
+          exit (1);
+        }
+      }
+      strcpy (fld_active, optarg);
       break;
     case 'b':
       bitpattern = atoi (optarg);
@@ -281,6 +329,10 @@
   srand(getpid());
   
   display_detect(&argc, &argv);
+
+  /* The field options are now in a static array all together, 
+     but that requires a run-time initialization. -- REW */
+  init_fld_options ();
 
   parse_mtr_options (getenv ("MTR_OPTIONS"));
 
diff -ur mtr-0.58/net.h mtr-0.59/net.h
--- mtr-0.58/net.h	Mon Apr  5 14:02:02 2004
+++ mtr-0.59/net.h	Tue Aug 10 09:46:37 2004
@@ -82,8 +82,12 @@
 #endif
 
 
+/* XXX This doesn't really belong in this header file, but as the
+   right c-files include it, it will have to do for now. -- REW */
+
 /* dynamic field drawing */
 struct fields {
+  CONST unsigned char key;
   CONST char *descr;
   CONST char *title;
   CONST char *format;
@@ -95,4 +99,7 @@
 
 
 /* keys: the value in the array is the index number in data_fields[] */
-extern  int fld_index[];
+extern char fld_index[];
+extern unsigned char fld_active[];
+extern char available_options[];
+
diff -ur mtr-0.58/report.c mtr-0.59/report.c
--- mtr-0.58/report.c	Mon May  5 15:33:36 2003
+++ mtr-0.59/report.c	Tue Aug 10 09:35:18 2004
@@ -31,7 +31,6 @@
 extern int dns;
 extern char LocalHostname[];
 extern char *Hostname;
-extern char fld_active[];
 extern int fstTTL;
 extern int maxTTL;
 extern int packetsize;
@@ -52,20 +51,12 @@
 
   sprintf(buf, "HOST: %-33s", LocalHostname);
   for( i=0; i<MAXFLD; i++ ) {
-    if( fld_active[i]>= 'a' && fld_active[i]<= 'z') {
-      j = fld_active[i] - 'a' + 11 + 26;
-    } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') {
-      j = fld_active[i] - 'A' + 11;
-    } else if( fld_active[i]>= '0' && fld_active[i]<= '9') {
-      j = fld_active[i] - '0' +1;
-    } else if( fld_active[i] == ' ' ) {
-      j = 0;
-    } else {
-      continue;     /* ignore unknown */
-    }
-    sprintf( fmt, "%%%ds", data_fields[fld_index[j]].length );
-    sprintf( buf +33+ len, fmt, data_fields[fld_index[j]].title );
-    len +=  data_fields[fld_index[j]].length;
+    j = fld_index[fld_active[i]];
+    if (j < 0) continue;
+
+    sprintf( fmt, "%%%ds", data_fields[j].length );
+    sprintf( buf +33+ len, fmt, data_fields[j].title );
+    len +=  data_fields[j].length;
   }
   printf("%s\n",buf);
 
@@ -92,27 +83,18 @@
     len=0;
     sprintf( buf, " %2d. %-33s", at+1, name);
     for( i=0; i<MAXFLD; i++ ) {
-      if( fld_active[i]>= 'a' && fld_active[i]<= 'z') {
-        j = fld_active[i] - 'a' + 11 + 26;
-      } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') {
-        j = fld_active[i] - 'A' + 11;
-      } else if( fld_active[i]>= '0' && fld_active[i]<= '9') {
-        j = fld_active[i] - '0' +1;
-      } else if( fld_active[i] == ' ' ) {
-        j = 0;
-      } else {
-        continue;     /* ignore stuff don't understand */
-      }
+      j = fld_index[fld_active [i]];
+      if (j < 0) continue;
 
       /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */
-      if( index( data_fields[ fld_index[j] ].format, 'f' ) ) {
-	sprintf( buf +33+ len, data_fields[ fld_index[j] ].format,
-		data_fields[ fld_index[j] ].net_xxx(at) /1000.0 );
+      if( index( data_fields[j].format, 'f' ) ) {
+	sprintf( buf +33+ len, data_fields[j].format,
+		data_fields[j].net_xxx(at) /1000.0 );
       } else {
-	sprintf( buf +33+ len, data_fields[ fld_index[j] ].format,
-		data_fields[ fld_index[j] ].net_xxx(at) );
+	sprintf( buf +33+ len, data_fields[j].format,
+		data_fields[j].net_xxx(at) );
       }
-      len +=  data_fields[fld_index[j]].length;
+      len +=  data_fields[j].length;
     }
     printf("%s\n",buf);
   }
@@ -165,33 +147,23 @@
 
     printf("    <HUB COUNT=%d HOST=%s>\n", at+1, name);
     for( i=0; i<MAXFLD; i++ ) {
-      if( fld_active[i]>= 'a' && fld_active[i]<= 'z') {
-        j = fld_active[i] - 'a' + 11 + 26;
-      } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') {
-        j = fld_active[i] - 'A' + 11;
-      } else if( fld_active[i]>= '0' && fld_active[i]<= '9') {
-        j = fld_active[i] - '0' +1;
-      } else if( fld_active[i] == ' ' ) {
-        continue;     /* ignore space */
-        j = 0;
-      } else {
-        continue;     /* ignore stuff don't understand */
-      }
+      j = fld_index[fld_active[i]];
+      if (j < 0) continue;
 
       strcpy(name, "        <%s>");
-      strcat(name, data_fields[ fld_index[j] ].format);
+      strcat(name, data_fields[j].format);
       strcat(name, "</%s>\n");
       /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */
-      if( index( data_fields[ fld_index[j] ].format, 'f' ) ) {
+      if( index( data_fields[j].format, 'f' ) ) {
 	printf( name,
-		data_fields[fld_index[j]].title,
-		data_fields[ fld_index[j] ].net_xxx(at) /1000.0,
-		data_fields[fld_index[j]].title );
+		data_fields[j].title,
+		data_fields[j].net_xxx(at) /1000.0,
+		data_fields[j].title );
       } else {
 	printf( name,
-		data_fields[fld_index[j]].title,
-		data_fields[ fld_index[j] ].net_xxx(at),
-		data_fields[fld_index[j]].title );
+		data_fields[j].title,
+		data_fields[j].net_xxx(at),
+		data_fields[j].title );
       }
     }
     printf("    </HUB>\n");
@@ -224,19 +196,10 @@
   /* Header */
   printf("HUPCOUNT, HOST");
   for( i=0; i<MAXFLD; i++ ) {
-      if( fld_active[i]>= 'a' && fld_active[i]<= 'z') {
-        j = fld_active[i] - 'a' + 11 + 26;
-      } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') {
-        j = fld_active[i] - 'A' + 11;
-      } else if( fld_active[i]>= '0' && fld_active[i]<= '9') {
-        j = fld_active[i] - '0' +1;
-      } else if( fld_active[i] == ' ' ) {
-        continue;     /* ignore space */
-        j = 0;
-      } else {
-        continue;     /* ignore stuff don't understand */
-      }
-      printf( ", %s", data_fields[fld_index[j]].title );
+      j = fld_index[fld_active[i]];
+      if (j < 0) continue; 
+
+      printf( ", %s", data_fields[j].title );
   }
   printf("\n");
 
@@ -262,24 +225,14 @@
 
     printf("%d, %s", at+1, name);
     for( i=0; i<MAXFLD; i++ ) {
-      if( fld_active[i]>= 'a' && fld_active[i]<= 'z') {
-        j = fld_active[i] - 'a' + 11 + 26;
-      } else if( fld_active[i]>= 'A' && fld_active[i]<= 'Z') {
-        j = fld_active[i] - 'A' + 11;
-      } else if( fld_active[i]>= '0' && fld_active[i]<= '9') {
-        j = fld_active[i] - '0' +1;
-      } else if( fld_active[i] == ' ' ) {
-        continue;     /* ignore space */
-        j = 0;
-      } else {
-        continue;     /* ignore stuff don't understand */
-      }
+      j = fld_index[fld_active[j]];
+      if (j < 0) continue; 
 
       /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */
-      if( index( data_fields[ fld_index[j] ].format, 'f' ) ) {
-	printf( ", %.2f", data_fields[ fld_index[j] ].net_xxx(at) /1000.0);
+      if( index( data_fields[j].format, 'f' ) ) {
+	printf( ", %.2f", data_fields[j].net_xxx(at) / 1000.0);
       } else {
-	printf( ", %d", data_fields[ fld_index[j] ].net_xxx(at) );
+	printf( ", %d",   data_fields[j].net_xxx(at) );
       }
     }
     printf("\n");
