/* query.c - statistics, control, and configuration screens
** 
** SWADMIN PROJECT - NETWORK 2000
** Network Development
**
** Copyright (c) 1994, 1996 - Carnegie Mellon University - All Rights Reserved
**
** Erikas Aras Napjus (erikas@cmu.edu)
** Ryan Troll (ryan@andrew.cmu.edu)
*/

/**********************************************************************
 *
 *           Copyright 1996 by Carnegie Mellon University
 * 
 *                       All Rights Reserved
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of CMU not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 * 
 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 * 
 * Authors: Erikas Napjus <erikas@cmu.edu>
 *          Ryan Troll <ryan@andrew.cmu.edu>
 * 
 **********************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <assert.h>
#include <ctype.h>

#ifdef HAVE_TERMIOS_H
# include <termios.h>
#endif /* HAVE_TERMIOS_H */

#include <curses.h>      /* Curses support */

#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif /* HAVE_FCNTL_H */

#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif

#ifdef HAVE_STRINGS_H
# include <strings.h>
#else /* HAVE_STRINGS_H */
# include <string.h>
#endif /* HAVE_STRINGS_H */

/* CMU SNMP Library */
#include <snmp/snmp.h>

#include "swadmin.h"
#include "screen.h"
#include "menuitem.h"
#include "client.h"
#include "query.h"

static char rcsid[] = 
"$Id: query.c,v 1.3 1997/02/17 17:05:25 ryan Exp $";

extern int  errno;
extern int errorcode;

/**********************************************************************/

/* Password management.
 */

/* Yuck! YYYYY */
char passwd[80];
int password = FALSE;

/* get_password - get the user to give us his/her password (w/ verification)
 *
 * NOTE: NULL passwords automatically fail because snmpapi switches to public
 * gotta love that steve code...
 */
int get_password(char *gateway, char *fqdn)
{
  WINDOW *main;                /* Password fetch window */
  int incr;                    /* Placeholder in passwd array */
  char ch;              
int step;
  char *request[10];
  void **response = NULL;

  /* Create a new window for this */
  main = newwin(18, 80, 5, 0);

  /* obtain the password from the screen with standard shadowing  
   */
  screen_area("Get Password");
  screen_status(STAT_READY);
  screen_hub(fqdn);

  mvwprintw(main, 0, 0, "Password     [                    ]");
  wmove(main, 0, 14);
  wrefresh(main);

  step = incr = 0;
  ch = getc(stdin);

  while (TRUE) {
    switch (step) {

      /* First char */
    case 0:
      switch (toupper(ch)) {

	/* Move forward */
      case 27:
	step++;
	break;

	/* Enter */
      case 10:
      case 13:
	passwd[incr] = 0;
	goto HavePassword;
	break;

	/* Backspace */
      case 127:
      case 2:
      case 8:
	if (incr > 0) {
	  mvwprintw(main, 0, incr+13, " "); 
	  wmove(main, 0, incr+13);
	  wrefresh(main);
	  passwd[incr--] = 0;
	}
	else
	  printf("\007");
	break;

	/* Letter */
      default:
	if (incr <= 19) {
	  passwd[incr++] = ch;
	  mvwprintw(main, 0, incr+13, "*");
	  wmove(main, 0, incr+14);
	  wrefresh(main);
	}
	else
	  printf("\007");
	break;
      }  
      break;

      /* Step 1 */
    case 1:
	/* YYYYY */
      if (ch == 91)
	step++;
      else
	step--;
      break;

      /* Step 2 */
    case 2:
      step = 0;
      switch (ch) {
	/* YYYYY */
      case 68:
	passwd[incr] = 0;
	goto HavePassword;
	break;
	/* YYYYY */
      case 67:
	printf("\07");
	break;
      }
    } 
    ch = getc(stdin);
  }

  /* verify the password */
  /* this is done by requesting sysUpTime with the write community string */
HavePassword:
  werase(main);

  screen_area("Verify Password");
  screen_status(STAT_WAIT);
  screen_hub(fqdn);
  mvwprintw(main, 0, 0, "Verifying password...");
  wrefresh(main);

  request[0] = ".1.3.6.1.2.1.1.3.0";

  /* If we have a password, verify it. */
  if (passwd[0] != 0)
    response = snmpget(gateway, passwd, 1, request, NULL);

  if (response == NULL) {
    mvwprintw(main, 1, 2, "Incorrect Password");
    printf("\007");
    password = FALSE;
    wrefresh(main);
  } else {
    mvwprintw(main, 1, 2, "Password Verified");
    wrefresh(main);
    screen_status(STAT_READY);
    password = TRUE;
  }
  sleep(5);
  return ERR_BACK;
}



/* set_port_name - names a given port
**
*/
void set_port_name(char *gateway, char *community, char *fqdn, 
		   int module, int port)
{
  WINDOW *main;
  int incr;
  char ch;
  int step;
  char name[80];
  char temp[80];

  main = newwin(18, 80, 5, 0);

  screen_area("Set Port Name");
  screen_status(STAT_READY);
  screen_hub(fqdn);

  mvwprintw(main, 0, 0, "Name         [                    ]");
  wmove(main, 0, 14);
  wrefresh(main);

  step = incr = 0;
  ch = getc(stdin);
  
  while (TRUE) {
    switch (step) {

      /* First char */
    case 0:
      switch (toupper(ch)) {


	/* Move forward */
      case 27:
	step++;
	break;

	/* Enter */
      case 10:
      case 13:
	name[incr] = 0;
	goto HavePassword;
	break;

	/* Backspace */
      case 127:
      case 2:
      case 8:
	if (incr > 0) {
	  mvwprintw(main, 0, incr+13, " "); 
	  wmove(main, 0, incr+13);
	  wrefresh(main);
	  name[incr--] = 0;
	} else 
	  printf("\007");
	break;

	/* Letter */
      default:
	if (incr <= 19) {
	  name[incr++] = ch;
	  mvwprintw(main, 0, incr+13, "%c", ch);
	  wmove(main, 0, incr+14);
	  wrefresh(main);
	} else
	  printf("\007");
	break;
      }  
      break;
        case 1:
          if (ch == 91)
            step++;
          else
            step--;
          break;
        case 2:
          step = 0;
          switch (ch)
            {
            case 68:
              name[incr] = 0;
              goto HavePassword;
              break;
            case 67:
              printf("\07");
              break;
            }
        } 
      ch = getc(stdin);
    }

/* set the port name */
 HavePassword:
  sprintf(temp, ".1.3.6.1.4.1.9.5.1.4.1.1.4.%d.%d", module, port);
  if (!snmpsetstr(gateway, community, temp, name, incr, NULL))
    screen_error("Unable to configure port");

  werase(main);
  wrefresh(main);
  delwin(main);
  return;
}

/* cdp_neighbors - show neighboring cisco devices using cdp mib
**
** (this uses snmpgetnext to get all of the cdp information)
**
** this routine is known not to work properly with all CDP implementations
** it also makes a number of assumptions about the MIB (which seem reasonable)
*/
int cdp_neighbors(char *gateway, char *community, char *fqdn)
{
  WINDOW *stats;
  oid *nameP;
  int name_length, result;
  int last = 1;
  char ch;
  int step;
  int returnable;
  char query[80];
  int count;
  oid respond[MAX_NAME_LEN];  
  u_char response[80];
  char localport[350][5];

  stats = newwin(18, 80, 5, 0);

  screen_area("Show Connected Cisco Devices");
  screen_status(STAT_WAIT);
  screen_hub(fqdn);

  mvwprintw(stats, 0, 0, 
	    highlight("PORT  IP ADDRESS    NAME                  REMOTE PORT                         "));

  wrefresh(stats);

/* here we determine the inverse mapping of ifindex to module/port */
/* localport[ifindex] = "module/port" after this runs */
/* this could be taken out of this function to autogenerate on a per
   switch basis for faster response, but that's probably overkill unless
   this is used in multiple routeines */

  sprintf(query, ".1.3.6.1.4.1.9.5.1.4.1.1.11");

  if (!mib_TxtToOid((void *) query, &nameP, &name_length)) {
    screen_error("Internal SWADMIN Error");
    return ERR_BACK;
  }

  result = snmpgetnext(gateway, community, 
		       nameP, name_length, 
		       respond, response, 
		       NULL);

  if (result < 0) {
    return ERR_BACK;
  }

  last = 1; count = 0;

  while (nameP[12] == respond[12]) {
    count++;

    sprintf(localport[*(int*)response], "%d/%d", respond[13], respond[14]);

    result = snmpgetnext(gateway, community, 
			 respond, result, 
			 respond, response,
			 NULL);

    if (result < 0) {
      return ERR_BACK;
    }
  }
  free(nameP);

/* ip addresses in cdp matrix -- only for catalysts */
  sprintf(query, ".1.3.6.1.4.1.9.9.23.1.2.1.1.4");

  if (!mib_TxtToOid((void *) query, &nameP, &name_length)) {
    screen_error("Internal SWADMIN Error");
    return ERR_BACK;
  }

  result = snmpgetnext(gateway, community, 
		       nameP, name_length, 
		       respond, response,
		       NULL);

  if (result < 0)
    goto down;

  last = 1; count = 0;

  while ((nameP[13] == respond[13]) && (count < 17)) {
    count++;

    mvwprintw(stats, count, 0, "%s", localport[respond[14]]);

    mvwprintw(stats, count, 6, "%d.%d.%d.%d", 
	      response[0], response[1], response[2], response[3]);

    result = snmpgetnext(gateway, community, 
			 respond, result, 
			 respond, response,
			 NULL);
    if (result < 0) {
      return ERR_BACK;
    }
  }
  free(nameP);

  wrefresh(stats);

/* device names in cdp matrix */
  sprintf(query, ".1.3.6.1.4.1.9.9.23.1.2.1.1.6");

  if (!mib_TxtToOid((void *) query, &nameP, &name_length)) {
    screen_error("Internal SWADMIN Error");
    return ERR_BACK;
  }

  result = snmpgetnext(gateway, community, 
		       nameP, name_length, 
		       respond, response,
		       NULL);

  if (result < 0) {
    return ERR_BACK;
  }

  last = 1; count = 0;

  while ((nameP[13] == respond[13]) && (count < 17)) {
    count++;
    response[20] = 0;

    mvwprintw(stats, count, 20, "%s", response);

    result = snmpgetnext(gateway, community, 
			 respond, result, 
			 respond, response,
			 NULL);
    if (result < 0) {
      return ERR_BACK;
    }
  }
  free(nameP);

  wrefresh(stats);

/* remote port in cdp matrix */
  sprintf(query, ".1.3.6.1.4.1.9.9.23.1.2.1.1.7");

  if (!mib_TxtToOid((void *) query, &nameP, &name_length)) {
    screen_error("Internal SWADMIN Error");
    return ERR_BACK;
  }

  result = snmpgetnext(gateway, community, 
		       nameP, name_length, 
		       respond, response,
		       NULL);

  if (result < 0) {
    return ERR_BACK;
  }

  last = 1; count = 0;

  while ((nameP[13] == respond[13]) && (count < 17)) {
    count++;

    response[20] = 0;
    mvwprintw(stats, count, 42, "%s", response);

    result = snmpgetnext(gateway, community, 
			 respond, result, 
			 respond, response,
			 NULL);
    if (result < 0) {
      return ERR_BACK;
    }
  }
  free(nameP);

/* remote version in cdp matrix 
** this code currently not used because of screen real estate issues
**
  sprintf(query, ".1.3.6.1.4.1.9.9.23.1.2.1.1.4");

  name_length = MAX_NAME_LEN;
  if (!read_objid((void *) query, 
		  name, &name_length))
    {
      screen_error("Internal SWADMIN Error");
      return ERR_BACK;
    }

  result = snmpgetnext(gateway, community, name, name_length, respond, 
		       response);

  if (result < 0)
    {
      return ERR_BACK;
    }

  name_length = MAX_NAME_LEN;
  if (!read_objid((void *) query, 
		  name, &name_length))
    {
      screen_error("Internal SWADMIN Error");
      return ERR_BACK;
    }

  last = 1; count = 0;

  while ((name[13] == respond[13]) && (count < 17))
    {
      count++;
      mvwprintw(stats, (count-1), 70, "%s", response);

      name_length = MAX_NAME_LEN;
      if (!read_objid((void *) query, 
		      name, &name_length))
	{
	  screen_error("Internal SWADMIN Error");
	  return ERR_BACK;
	}
      result = snmpgetnext(gateway, community, respond, result, respond, 
			   response);
      if (result < 0)
	{
	  return ERR_BACK;
	}
    }
*/

  if (count == 17)
    mvwprintw(stats, count+1, 0, "  ...");

  wrefresh(stats);
 
  screen_status(STAT_READY);

  clear_legend();
  
  set_legend(0, "The first sixteen Cisco devices attached to this switch are displayed");
  set_legend(1, "on this screen. The local port on this switch, the IP address of the");
  set_legend(2, "remote device, the configured name of the remote device, and the");
  set_legend(3, "port on the remote device where this switch is attached are listed");

  step = 0;
  ch = getc(stdin);
  while (TRUE)
    {
      switch (step)
	{
	case 0:
	  switch (toupper(ch))
	    {
	    case 'B':
	    case 2:
	    case 7:
	      returnable = ERR_BACK;
	      goto down;
	    case 'L':
	    case '?':
	      screen_legend();
	      touchwin(stats); wrefresh(stats);
	      break;
	    case 'Q':
	    case 'E':
	      returnable = ERR_QUIT;
	      goto down;
	    case 'M':
	    case 'T':
	      returnable = ERR_TOP;
	      clear_stack();
	      goto down;
	    down:
	      werase(stats);
	      wrefresh(stats);
	      delwin(stats);
	      return returnable;
	      break;
	    case 27:
	      step++;
	      break;
	    }  
	  break;
	case 1:
	  if (ch == 91)
	    step++;
	  else
	    step--;
	  break;
	case 2:
	  step = 0;
	  switch (ch)
	    {
	    case 68:
	      returnable = ERR_BACK;
	      goto down;
	    case 67:
	      printf("\07");
	      break;
	    }
	} 
      ch = getc(stdin);
    }
}


/* get_switch_software - get the software configuration of the switch
** 
** this is specific to catalyst 2900/5000 switches (enterprise MIB)
*/
int get_switch_software(char *gateway, char *community, char *fqdn)
{
  WINDOW *stats;
  char *request[10];
  int returnable;
  char ch;
  time_t block;
  int step;

  /* The response.  Mostly integers. */
  int **response;
  u_char *bufp;

  stats = newwin(18, 70, 5, 0);

  screen_area("Switch Software Configuration");
  screen_status(STAT_WAIT);
  screen_hub(fqdn);

  request[0] = ".1.3.6.1.4.1.9.5.1.3.1.1.20.1";
  request[1] = ".1.3.6.1.4.1.9.5.1.1.17.0";
  request[2] = ".1.3.6.1.4.1.9.5.1.1.2.0";
  request[3] = ".1.3.6.1.4.1.9.5.1.1.3.0";
  request[4] = ".1.3.6.1.4.1.9.5.1.1.4.0";

  /* Get the information */
  response = (int **)snmpget(gateway, community, 5, request, NULL);
  if (response) {
    mvwprintw(stats, 0, 0, "Software Version :");
    mvwprintw(stats, 0, 19, "%s", (char *)response[0]);

    mvwprintw(stats, 2, 0, "Remote Monitoring:");
    if (*(response[1]) == 1) {
      mvwprintw(stats, 2, 19, "Enabled");
    } else {
      mvwprintw(stats, 2, 19, "Disabled");
    }

    bufp = (u_char *)response[2];
    mvwprintw(stats, 4, 0, "IP Address       : %d.%d.%d.%d",
	      bufp[0], bufp[1], bufp[2], bufp[3]);
    bufp = (u_char *)response[3];
    mvwprintw(stats, 5, 0, "Subnet Mask      : %d.%d.%d.%d",
	      bufp[0], bufp[1], bufp[2], bufp[3]);
    bufp = (u_char *)response[4];
    mvwprintw(stats, 6, 0, "Broadcast Address: %d.%d.%d.%d",
	      bufp[0], bufp[1], bufp[2], bufp[3]);
  }

  /* The next batch of information */
  request[0] = ".1.3.6.1.4.1.9.5.1.1.19.0";
  request[1] = ".1.3.6.1.4.1.9.5.1.1.20.0";
  request[2] = ".1.3.6.1.4.1.9.5.1.1.8.0"; 

  response = (int **)snmpget(gateway, community, 3, request, NULL);
  if (response) {
    mvwprintw(stats, 8, 0, "Utilization Now  : %2d%% (%3d Mbps)",
	      *(response[2]), (*(response[2]))*12);
    mvwprintw(stats, 9, 0, "Peak Utilization : %2d%% (%3d Mbps)",
	      *(response[0]), (*(response[0]))*12);
    block = time(NULL) - (*(response[1])/100);
    mvwprintw(stats, 10, 0, "Peak Time        : %s",
	      ctime(&block));
  }
  wrefresh(stats);

  clear_legend();
  set_legend(0, "The software configuration of the specified switch is displayed");
  set_legend(1, "in this window. These parameters cannot be modified from this program.");

  screen_status(STAT_READY);

  step = 0;
  ch = getc(stdin);
  while (TRUE)
    {
      switch (step)
	{
	case 0:
	  switch (toupper(ch))
	    {
	    case 'B':
	    case 2:
	    case 7:
	      returnable = ERR_BACK;
	      goto down2;
	    case 'L':
	    case '?':
	      screen_legend();
	      touchwin(stats); wrefresh(stats);
	      break;
	    case 'Q':
	    case 'E':
	      returnable = ERR_QUIT;
	      goto down2;
	    case 'M':
	    case 'T':
	      returnable = ERR_TOP;
	      clear_stack();
	      goto down2;
	    down2:
	      werase(stats);
	      wrefresh(stats);
	      delwin(stats);
	      return returnable;
	      break;
	    case 27:
	      step++;
	      break;
	    }  
	  break;
	case 1:
	  if (ch == 91)
	    step++;
	  else
	    step--;
	  break;
	case 2:
	  step = 0;
	  switch (ch)
	    {
	    case 68:
	      returnable = ERR_BACK;
	      goto down2;
	    case 67:
	      printf("\07");
	      break;
	    }
	} 
      ch = getc(stdin);
    }
}

/* get_switch_hardware - get the hardware configuration of the switch
**
** this needs to be updated if Cisco ever adds new cards/equipment to their
** product line; this is also all catalyst specific (Enterprise MIB)
*/
int get_switch_hardware(char *gateway, char *community, char *fqdn)
{
  WINDOW *stats;
  char *request[10];
  int returnable;
  char ch;
  int step;
  char buf[80];

  /* SNMP Responses. */
  int **response;
  u_char *bufp;

  stats = newwin(18, 70, 5, 0);

  screen_area("Switch Hardware Configuration");
  screen_status(STAT_WAIT);
  screen_hub(fqdn);

  request[0] = ".1.3.6.1.2.1.1.3.0";

  /* Uptime */
  response = (int **)snmpget(gateway, community, 1, request, NULL);
  if (response) {
    uptime_string((*(response[0])), buf);
    mvwprintw(stats, 0, 0, "Uptime           : %s\n\n", buf);
  }

  /* Hardware Address */
  request[0] = ".1.3.6.1.2.1.2.2.1.6.1";

  response = (int **)snmpget(gateway, community, 1, request, NULL);
  if (response) {
    bufp = (u_char *)response[0];
    mvwprintw(stats, 2, 0, "MAC Address      : %02X-%02X-%02X-%02X-%02X-%02X",
	      bufp[0], bufp[1], bufp[2], bufp[3], bufp[4], bufp[5]);
  }

  wrefresh(stats);

  /* Chassis's */
  request[0] = ".1.3.6.1.4.1.9.5.1.2.1.0";
  request[1] = ".1.3.6.1.4.1.9.5.1.2.2.0";
  request[2] = ".1.3.6.1.4.1.9.5.1.2.9.0";
  request[3] = ".1.3.6.1.4.1.9.5.1.2.10.0";
  request[4] = ".1.3.6.1.4.1.9.5.1.2.11.0";
  request[5] = ".1.3.6.1.4.1.9.5.1.2.12.0";
  request[6] = ".1.3.6.1.4.1.9.5.1.2.13.0";

  response = (int **)snmpget(gateway, community, 7, request, NULL);
  if (response) {
    switch(*response[0]) {
    case 3: 
      mvwprintw(stats, 4, 0, "Chassis Type     : Catalyst 1000"); break;
    case 4: 
      mvwprintw(stats, 4, 0, "Chassis Type     : Catalyst 1001"); break;
    case 5: 
      mvwprintw(stats, 4, 0, "Chassis Type     : Catalyst 1100"); break;
    case 6: 
      mvwprintw(stats, 4, 0, "Chassis Type     : Catalyst 5000"); break;
    case 7: 
      mvwprintw(stats, 4, 0, "Chassis Type     : Catalyst 2900"); break;
    case 11: 
      mvwprintw(stats, 4, 0, "Chassis Type     : Catalyst 1200"); break;
    case 12: 
      mvwprintw(stats, 4, 0, "Chassis Type     : Catalyst 1400"); break;
    case 1: 
    default:
      mvwprintw(stats, 4, 0, "Chassis Type     : Unknown"); break;
    }
    
    switch(*response[1]) {
    case 2: 
      mvwprintw(stats, 5, 0, "Backplane        : FDDI"); break;
    case 3: 
      mvwprintw(stats, 5, 0, "Backplane        : FDDI/Ethernet"); break;
    case 4: 
      mvwprintw(stats, 5, 0, "Backplane        : Gigabit Switch"); break;
    case 1: 
    default:
      mvwprintw(stats, 5, 0, "Backplane        : Unknown"); break;
    }

    switch(*response[2]) {
    case 2: 
      mvwprintw(stats, 6, 0, "Chassis Fan      : Operational"); break;
    case 3: 
      mvwprintw(stats, 6, 0, "Chassis Fan      : Minor Fault"); break;
    case 4: 
      mvwprintw(stats, 6, 0, "Chassis Fan      : Major Fault"); break;
    case 1: 
    default:
      mvwprintw(stats, 6, 0, "Chassis Fan      : Unknown"); break;
    }

    if ((*response[3]) == 0)
      mvwprintw(stats, 6, 55, "Passed Test");
    else
      mvwprintw(stats, 6, 55, "Failed Test");

    if (((*response[4]) == 2) && ((*response[5]) == 2))
      mvwprintw(stats, 7, 0, "Chassis Status   : Minor, Major Faults"); 
    else if ((*response[4]) == 2)
      mvwprintw(stats, 7, 0, "Chassis Status   : Minor Fault");
    else if ((*response[5]) == 2)
      mvwprintw(stats, 7, 0, "Chassis Status   : Major Fault");
    else 
      mvwprintw(stats, 7, 0, "Chassis Status   : No Faults");

    if ((*response[6]) != 2)
      mvwprintw(stats, 8, 0, "Temperature      : Normal");
    else
      mvwprintw(stats, 8, 0, "Temperature      : Warning");
  }

  wrefresh(stats);

  /* Power supply, etc. */
  request[0] = ".1.3.6.1.4.1.9.5.1.2.3.0";
  request[1] = ".1.3.6.1.4.1.9.5.1.2.4.0";
  request[2] = ".1.3.6.1.4.1.9.5.1.2.5.0";
  request[3] = ".1.3.6.1.4.1.9.5.1.2.6.0";
  request[4] = ".1.3.6.1.4.1.9.5.1.2.7.0";
  request[5] = ".1.3.6.1.4.1.9.5.1.2.8.0";

  response = (int **)snmpget(gateway, community, 6, request, NULL);
  if (response) {
    switch(*response[0]) {
    case 2: 
      mvwprintw(stats, 10, 0, "Power Supply One : None"); break;
    case 3: 
      mvwprintw(stats, 10, 0, "Power Supply One : 50 Watt"); break;
    case 4: 
      mvwprintw(stats, 10, 0, "Power Supply One : 200 Watt"); break;
    case 5: 
      mvwprintw(stats, 10, 0, "Power Supply One : 600 Watt"); break;
    case 6: 
      mvwprintw(stats, 10, 0, "Power Supply One : 80 Watt"); break;
    case 7: 
      mvwprintw(stats, 10, 0, "Power Supply One : 130 Watt"); break;
    case 8: 
      mvwprintw(stats, 10, 0, "Power Supply One : 350 Watt"); break;
    case 9: 
      mvwprintw(stats, 10, 0, "Power Supply One : 350 Watt"); break;
    case 10: 
      mvwprintw(stats, 10, 0, "Power Supply One : 175 Watt"); break;
    case 11: 
      mvwprintw(stats, 10, 0, "Power Supply One : 350 Watt DC"); break;
    case 1: 
    default:
      mvwprintw(stats, 10, 0, "Power Supply One : Unknown"); break;
    }

    switch(*response[1]) {
    case 2: mvwprintw(stats, 10, 35, "Operational"); break;
    case 3: mvwprintw(stats, 10, 35, "Minor Fault"); break;
    case 4: mvwprintw(stats, 10, 35, "Major Fault"); break;
    case 1: 
    default:
      mvwprintw(stats, 10, 35, "Unknown"); break;	
    }

    if ((*response[2]) == 0)
      mvwprintw(stats, 10, 55, "Passed Test");
    else
      mvwprintw(stats, 10, 55, "Failed Test");

    switch(*response[3]) {
    case 2: 
      mvwprintw(stats, 11, 0, "Power Supply Two : None"); break;
    case 3: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 50 Watt"); break;
    case 4: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 200 Watt"); break;
    case 5: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 600 Watt"); break;
    case 6: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 80 Watt"); break;
    case 7: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 130 Watt"); break;
    case 8: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 350 Watt"); break;
    case 9: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 350 Watt"); break;
    case 10: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 175 Watt"); break;
    case 11: 
      mvwprintw(stats, 11, 0, "Power Supply Two : 350 Watt DC"); break;
    case 1: 
    default:
      mvwprintw(stats, 11, 0, "Power Supply Two : Unknown"); break;
    }
      
    switch(*response[4]) {
    case 2: mvwprintw(stats, 11, 35, "Operational"); break;
    case 3: mvwprintw(stats, 11, 35, "Minor Fault"); break;
    case 4: mvwprintw(stats, 11, 35, "Major Fault"); break;
    default:
    case 1: mvwprintw(stats, 11, 35, "Unknown"); break;
    }

    if ((*response[5]) == 0)
      mvwprintw(stats, 11, 55, "Passed Test");
    else
      mvwprintw(stats, 11, 55, "Failed Test");
  }
    
  wrefresh(stats);

  clear_legend();
  set_legend(0, "The hardware configuration and operational status for the specified");
  set_legend(1, "switch are displayed here.");

  screen_status(STAT_READY);

  step = 0;
  ch = getc(stdin);
  while (TRUE)
    {
      switch (step)
	{
	case 0:
	  switch (toupper(ch))
	    {
	    case 'B':
	    case 2:
	    case 7:
	      returnable = ERR_BACK;
	      goto down3;
	    case 'L':
	    case '?':
	      screen_legend();
	      touchwin(stats); wrefresh(stats);
	      break;
	    case 'Q':
	    case 'E':
	      returnable = ERR_QUIT;
	      goto down3;
	    case 'M':
	    case 'T':
	      returnable = ERR_TOP;
	      clear_stack();
	      goto down3;
	    down3:
	      werase(stats);
	      wrefresh(stats);
	      delwin(stats);
	      return returnable;
	      break;
	    case 27:
	      step++;
	      break;
	    }  
	  break;
	case 1:
	  if (ch == 91)
	    step++;
	  else
	    step--;
	  break;
	case 2:
	  step = 0;
	  switch (ch)
	    {
	    case 68:
	      returnable = ERR_BACK;
	      goto down3;
	    case 67:
	      printf("\07");
	      break;
	    }
	} 
      ch = getc(stdin);
    }
}

/* control_port - change the configuration of a given port 
**
** this routine superceeds select_port's previous functionality for control
*/
int control_port(char *gateway, char *community, char *fqdn, 
		 int module, int port)
{
  char temp[80];
  int last = 1;
  char requestor[10][50];
  char *requests[10];
  char buffer[80];
  int magic;

  /* Responses to the SNMP requests */
  int **response;

  pushd(-1);

  sprintf(buffer, "%s - %d/%d", fqdn, module, port);
  screen_hub(buffer);

  init_item();

  add_item("Enable Port", (void *)100);
  add_item("Partition Port", (void *)101);
  add_item("Set Autodetect", (void *)102);
  add_item("Set 10-BASE-T", (void *)103);
  add_item("Set 100-BASE-TX", (void *)104);
  add_item("Set Full Duplex", (void *)105);
  add_item("Set Half Duplex", (void *)106);
  add_item("Set Port Name", (void *)107);

  clear_legend();
  set_legend(0, "Select the action which you would like to take on the port you have");
  set_legend(1, "previously selected. Be careful not to partition the port to which you are");
  set_legend(2, "attached.");

  last = (int)menu_item("configuration option", fqdn); 

  switch (last) {
  case 0:
    switch (errorcode) {
    case ERR_QUIT:
      return ERR_QUIT;
    case ERR_TOP:
      clear_stack();
      return ERR_TOP;
    case ERR_BACK:
      return ERR_BACK;
    }
    break;
/* enable port */
    case 100:
      /* first need to get ifIndex */
      sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.11.%d.%d", module, port);
      requests[0] = requestor[0];
  
      response = (int **)snmpget(gateway, community, 1, requests, NULL);
      if (!response)
	screen_error("Unable to contact host");
      else {
	magic = *(response[0]);
	sprintf(temp, ".1.3.6.1.2.1.2.2.1.7.%d", magic);
	if (!snmpset(gateway, community, temp, 1, NULL))
	  screen_error("Unable to configure port");
      }
      break;
/* partition port */
    case 101:
      /* first need to get ifIndex */
      sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.11.%d.%d", module, port);
      requests[0] = requestor[0];
  
      response = (int **)snmpget(gateway, community, 1, requests, NULL);
      if (!response)
	screen_error("Unable to contact host");
      else {
	  magic = *(response[0]);
	  sprintf(temp, ".1.3.6.1.2.1.2.2.1.7.%d", magic);
	  if (!snmpset(gateway, community, temp, 2, NULL))
	    screen_error("Unable to configure port");
	}
      break;
/* set autodetect */
    case 102:
      sprintf(temp, ".1.3.6.1.4.1.9.5.1.4.1.1.9.%d.%d", module, port);
      if (!snmpset(gateway, community, temp, 1, NULL))
	screen_error("Unable to configure port");
      break;
/* set 10-BASE-T */
    case 103:
      sprintf(temp, ".1.3.6.1.4.1.9.5.1.4.1.1.9.%d.%d", module, port);
      if (!snmpset(gateway, community, temp, 10000000, NULL))
	screen_error("Unable to configure port");
      break;
/* set 100-BASE-TX */
    case 104:
      sprintf(temp, ".1.3.6.1.4.1.9.5.1.4.1.1.9.%d.%d", module, port);
      if (!snmpset(gateway, community, temp, 100000000, NULL))
	screen_error("Unable to configure port");
      break;
/* set full duplex */
    case 105:
      sprintf(temp, ".1.3.6.1.4.1.9.5.1.4.1.1.10.%d.%d", module, port);
      if (!snmpset(gateway, community, temp, 2, NULL))
	screen_error("Unable to configure port");
      break;
/* set half duplex */
    case 106:
      sprintf(temp, ".1.3.6.1.4.1.9.5.1.4.1.1.10.%d.%d", module, port);
      if (!snmpset(gateway, community, temp, 1, NULL))
	screen_error("Unable to configure port");
      break;
    case 107:
      set_port_name(gateway, community, fqdn, module, port);
      break;
    }
  popd();
  return 0;
}

/* select_port - port selection code
**
** module = module to display information about
** change = type of change to be made (or just statistics)
*/
int select_port(char *gateway, char *community, char *fqdn, 
		int module, int change)
{
  char buffers[25][80];
  int last = 1;
  char requestor[10][50];
  char *requests[10];
  int prompts[25];
  int port_count;
  char buffer[80];
  char bufferette[80];

  /* SNMP Responses */
  int **response;

  screen_status(STAT_WAIT);

/* get the port count for this module */
  sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.3.1.1.14.%d", module);
  requests[0] = requestor[0];
  
  response = (int **)snmpget(gateway, community, 1, requests, NULL);
  if (!response) {
    return ERR_BACK;
  }
  
  port_count = *(response[0]);
  
 top:

  /* for each port, get basic data */
  for (last=1; last <= port_count; last++) {
    sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.6.%d.%d", module, last);
    sprintf(requestor[1], ".1.3.6.1.4.1.9.5.1.4.1.1.9.%d.%d", module, last);
    sprintf(requestor[2], ".1.3.6.1.4.1.9.5.1.4.1.1.10.%d.%d", module, last);
      
    requests[0] = requestor[0];
    requests[1] = requestor[1];
    requests[2] = requestor[2];
    
    response = (int **)snmpget(gateway, community, 3, requests, NULL);
    if (!response) {
      return ERR_BACK;
    }
    sprintf(bufferette, "%d/%d", module, last);
    sprintf(buffers[last], "%4s - ", bufferette);

    switch (*(response[0])) {
    case 1: strcat(buffers[last], "X "); break;
    case 2: strcat(buffers[last], "O "); break;
    case 3: strcat(buffers[last], "F "); break;
    case 4: strcat(buffers[last], "X "); break;
    default: strcat(buffers[last], "? "); break;
    }
    switch (*(response[1])) {
    case 1: strcat(buffers[last], "A "); break;
    case 10000000: strcat(buffers[last], "E "); break;
    case 100000000: strcat(buffers[last], "F "); break;
    case 155000000: strcat(buffers[last], "O "); break;
    default: strcat(buffers[last], "? "); break;
    }
    switch (*(response[2])) {
    case 1: strcat(buffers[last], "H "); break;
    case 2: strcat(buffers[last], "F "); break;
    default: strcat(buffers[last], "? "); break;
    }
    strcat(buffers[last], "- ");

    sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.4.%d.%d", module, last);
    requests[0] = requestor[0];

    response = (int **)snmpget(gateway, community, 1, requests, NULL);
    if (!response) {
      return ERR_BACK;
    }

    sprintf(buffer, "%s", (char *)response[0]);
    strcat(buffers[last], buffer);
  }

  for (last = 1; last <= port_count; last++) {
    prompts[last] = last;
  }
  
  init_item();

  for (last = 1; last <= port_count; last++)
    add_item(buffers[last], (void *)prompts[last]);

 topee:
  clear_legend();
  set_legend(0, "       ^---------------- module/port");
  set_legend(1, "           ^------------ O=On-Line      X=Off-Line     F=Failure");
  set_legend(2, "             ^---------- A=Autodetect   E=10-BASE-T    F=100-BASE-TX   O=OC3 ATM");
  set_legend(3, "               ^-------- H=Half Duplex  F=Full Duplex");
  set_legend(4, "                   ^---- port name");

  switch(change) {
  case -1: last = (int)menu_item("port to monitor", fqdn); break;
  default: last = (int)menu_item("port to configure", fqdn); break;
  }

  if (last == 0)
    switch (errorcode) {
    case ERR_QUIT:
      return ERR_QUIT;
    case ERR_TOP:
      clear_stack();
      return ERR_TOP;
    case ERR_BACK:
      return ERR_BACK;
    }
  else
    if (change == CURRENT)
      {
	dynamic_port_statistics(gateway, community, fqdn, module, last);
	goto topee;
      }
    else
      {
	control_port(gateway, community, fqdn, module, last);
	goto top;
      }
  return 0;
}

/* static_port_statistics - show the historical port statistics
*/
int static_port_statistics(char *gateway, char *community, char *fqdn, 
			   int module, int port)
{
  WINDOW *stats, *ports;
  char ch;
  char *requests[10];
  char requestor[10][50];
  int returnable;
  int step;
  int magic;
  char buffer[80];

  /* SNMP Responses */
  int **response;

  ports = newwin(18, 80, 5, 0);

  screen_area("Show Historical Port Statistics");
  screen_status(STAT_WAIT);
  sprintf(buffer, "%s - %d/%d", fqdn, module, port);
  screen_hub(buffer);

/* first we need to get the ifindex mapping for this module/port combo */
  sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.11.%d.%d",
	  module, port);
  requests[0] = requestor[0];
  response = (int **)snmpget(gateway, community, 1, requests, NULL);
  if (!response) {
    return ERR_BACK;
  }
  magic = *(response[0]);

  mvwprintw(ports, 0, 0, 
	    highlight("MEASUREMENT                     IN             OUT"));

  /* in unicasts */
  sprintf(requestor[0], ".1.3.6.1.2.1.2.2.1.11.%d", magic);
  /* in multicasts/broadcasts */
  sprintf(requestor[1], ".1.3.6.1.2.1.2.2.1.12.%d", magic);
  /* in discards */
  sprintf(requestor[2], ".1.3.6.1.2.1.2.2.1.13.%d", magic);
  /* in errors */
  sprintf(requestor[3], ".1.3.6.1.2.1.2.2.1.14.%d", magic);
  /* out unicasts */
  sprintf(requestor[4], ".1.3.6.1.2.1.2.2.1.17.%d", magic);
  /* out broadcasts/multicasts */
  sprintf(requestor[5], ".1.3.6.1.2.1.2.2.1.18.%d", magic);
  /* out discards */
  sprintf(requestor[6], ".1.3.6.1.2.1.2.2.1.19.%d", magic);
  /* out errors */
  sprintf(requestor[7], ".1.3.6.1.2.1.2.2.1.20.%d", magic);

  requests[0] = requestor[0];
  requests[1] = requestor[1];
  requests[2] = requestor[2];
  requests[3] = requestor[3];
  requests[4] = requestor[4];
  requests[5] = requestor[5];
  requests[6] = requestor[6];
  requests[7] = requestor[7];
  
  response = (int **)snmpget(gateway, community, 8, requests, NULL);
  if (response) {
    mvwprintw(ports, 1, 0, "Unicast Packets       %12d    %12d",
	      *(response[0]), *(response[4]));
    mvwprintw(ports, 2, 0, "Broadcast/Multicast   %12d    %12d",
	      *(response[1]), *(response[5]));
    mvwprintw(ports, 3, 0, "Discarded Packets     %12d    %12d",
	      *(response[2]), *(response[6]));
    mvwprintw(ports, 4, 0, "Error Packets         %12d    %12d",
	      *(response[3]), *(response[7]));
  }
  wrefresh(ports);

  /* alignment errors */
  sprintf(requestor[0], ".1.3.6.1.2.1.10.7.2.1.2.%d", magic);
  /* FCS errors */
  sprintf(requestor[1], ".1.3.6.1.2.1.10.7.2.1.3.%d", magic);
  /* single collisions */
  sprintf(requestor[2], ".1.3.6.1.2.1.10.7.2.1.4.%d", magic);
  /* multiple collision */
  sprintf(requestor[3], ".1.3.6.1.2.1.10.7.2.1.5.%d", magic);
  /* deferrals */
  sprintf(requestor[4], ".1.3.6.1.2.1.10.7.2.1.7.%d", magic);
  /* late collisions */
  sprintf(requestor[5], ".1.3.6.1.2.1.10.7.2.1.8.%d", magic);
  /* excessive collisions */
  sprintf(requestor[6], ".1.3.6.1.2.1.10.7.2.1.9.%d", magic);
  /* too long errors */
  sprintf(requestor[7], ".1.3.6.1.2.1.10.7.2.1.13.%d", magic);

  requests[0] = requestor[0];
  requests[1] = requestor[1];
  requests[2] = requestor[2];
  requests[3] = requestor[3];
  requests[4] = requestor[4];
  requests[5] = requestor[5];
  requests[6] = requestor[6];
  requests[7] = requestor[7];

  response = (int **)snmpget(gateway, community, 8, requests, NULL);
  if (response) {
    mvwprintw(ports, 5, 0, 
	      "Deferrals                       --    %12d", 
	      *(response[4]));
    mvwprintw(ports, 7, 0, 
	      "Alignment Errors      %12d              --", 
	      *(response[0]));
    mvwprintw(ports, 8, 0, 
	      "CRC Errors            %12d              --", 
	      *(response[1]));
    mvwprintw(ports, 9 ,0, 
	      "Too Long Errors       %12d              --", 
	      *(response[7]));
    mvwprintw(ports, 10,0, 
	      "Late Collisions       %12d              --", 
	      *(response[5]));
    mvwprintw(ports, 11,0, 
	      "Single Collisions               --    %12d", 
	      *(response[2]));
    mvwprintw(ports, 12,0, 
	      "Multiple Collisions             --    %12d", 
	      *(response[3]));
    mvwprintw(ports, 13,0, 
	      "Excessive Collisions            --    %12d", 
	      *(response[6]));
  }

  wrefresh(ports);

  screen_status(STAT_READY);

  clear_legend();
  set_legend(0, "The historical statistics for the specified module/port are displayed");
  set_legend(1, "on this screen. These are the packet and error counts seen on this");
  set_legend(2, "port since the counters were last cleared or the switch last restarted");

  step = 0;
  ch = getc(stdin);
  while (TRUE)
    {
      switch (step)
	{
	case 0:
	  switch (toupper(ch))
	    {
	    case 'B':
	    case 2:
	    case 7:
	      returnable = ERR_BACK;
	      goto down4;
	    case 'L':
	    case '?':
	      screen_legend();
	      touchwin(stats); wrefresh(stats);
	      break;
	    case 'Q':
	    case 'E':
	      returnable = ERR_QUIT;
	      goto down4;
	    case 'M':
	    case 'T':
	      returnable = ERR_TOP;
	      clear_stack();
	      goto down4;
	    down4:
	      werase(ports);
	      wrefresh(ports);
	      delwin(ports);
	      return returnable;
	      break;
	    case 27:
	      step++;
	      break;
	    }  
	  break;
	case 1:
	  if (ch == 91)
	    step++;
	  else
	    step--;
	  break;
	case 2:
	  step = 0;
	  switch (ch)
	    {
	    case 68:
	      returnable = ERR_BACK;
	      goto down4;
	    case 67:
	      printf("\07");
	      break;
	    }
	} 
      ch = getc(stdin);
    }
}

/* static_module_statistics - display historical port statistics given module
**
** uses menuitem to allow you to select a port for more details
*/
int static_module_statistics(char *gateway, char *community, char *fqdn, 
			     int module)
{
  int incr;
  char *requests[10];
  char requestor[10][50];
  int returnable;
  int port_count;
  int magic;
  char buffer[24][80];
  int values;
  char buffers[80];

  /* SNMP Responses */
  int **response;

  init_item();

  screen_area("Show Historic Module Statistics");
  screen_status(STAT_WAIT);
  screen_hub(fqdn);

/* find out the number of ports on this module */
  sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.3.1.1.14.%d", module);
  requests[0] = requestor[0];

  response = (int **)snmpget(gateway, community, 1, requests, NULL);
  if (!response) {
    return ERR_BACK;
  }

  port_count = *(response[0]);

  for (incr=0; incr < port_count; incr++)
    {
/* first we need to get the ifindex mapping for this module/port combo */
      sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.11.%d.%d",
	      module, incr+1);

      response = (int **)snmpget(gateway, community, 1, requests, NULL);
      if (!response) {
	return ERR_BACK;
      }
      magic = *(response[0]);
/* then get the actual statistics */      
      /* in unicasts */
      sprintf(requestor[0], ".1.3.6.1.2.1.2.2.1.11.%d", magic);
      /* in multicasts/broadcasts */
      sprintf(requestor[1], ".1.3.6.1.2.1.2.2.1.12.%d", magic);
      /* in discards */
      sprintf(requestor[2], ".1.3.6.1.2.1.2.2.1.13.%d", magic);
      /* in errors */
      sprintf(requestor[3], ".1.3.6.1.2.1.2.2.1.14.%d", magic);
      /* out unicasts */
      sprintf(requestor[4], ".1.3.6.1.2.1.2.2.1.17.%d", magic);
      /* out broadcasts/multicasts */
      sprintf(requestor[5], ".1.3.6.1.2.1.2.2.1.18.%d", magic);
      /* out discards */
      sprintf(requestor[6], ".1.3.6.1.2.1.2.2.1.19.%d", magic);
      /* out errors */
      sprintf(requestor[7], ".1.3.6.1.2.1.2.2.1.20.%d", magic);

      requests[0] = requestor[0];
      requests[1] = requestor[1];
      requests[2] = requestor[2];
      requests[3] = requestor[3];
      requests[4] = requestor[4];
      requests[5] = requestor[5];
      requests[6] = requestor[6];
      requests[7] = requestor[7];

      response = (int **)snmpget(gateway, community, 8, requests, NULL);
      if (!response) {
	screen_error("unable to contact switch");
	return ERR_BACK;
      }

      sprintf(buffers, "%d/%d", module, incr+1);
      sprintf(buffer[incr], "%5s %12d   %12d   %12d   %12d",
	      buffers, (unsigned int) *(response[0])+*(response[1]),
	      (unsigned int) *(response[2])+*(response[3]),
	      (unsigned int) *(response[4])+*(response[5]), 
	      (unsigned int) *(response[6])+*(response[7]));
      add_item(buffer[incr], (void *)(incr+1));
    }

  menu_label("      PORT   IN PACKETS      IN ERRORS    OUT PACKETS     OUT ERRORS");


 toper:

  clear_legend();
  set_legend(0, "        ^-------------- interface on this module");
  set_legend(1, "                     ^--- packets received from network");
  set_legend(2, "                                    ^----- number of errors from network");
  set_legend(3, "                      packets sent to network -----^");
  set_legend(4, "           errors/discards sending to network --------------------^");

  values = (int)menu_item("port for details", fqdn);
  if (values == 0)
    {	
      switch (errorcode)
	{
	case ERR_BACK:
	  returnable = ERR_BACK;
	  goto downers;
	case ERR_TOP:
	  returnable = ERR_TOP;
	  clear_stack();
	  goto downers;
	case ERR_QUIT:
	  returnable = ERR_QUIT;
	downers:
	  return returnable;
	  break;
	}
    }
  else
    switch(static_port_statistics(gateway, community, fqdn, module, values))
      {
      case ERR_QUIT:
	return ERR_QUIT;
      case ERR_TOP:
	clear_stack();
	return ERR_TOP;
      case ERR_BACK:
      default:
	goto toper;
      }
  /* XXXXX */
  return ERR_TOP;
}

/* dynamic_port_statistics - show the current (live) port statistics
** 
** this is all done on a per port basis 
*/
int dynamic_port_statistics(char *gateway, char *community, char *fqdn, 
			    int module, int port)
{
  WINDOW *ports;
  char ch;
  char *requests[10];
  char requestor[10][50];
  int incr, subincr, returnable;
  int step;
  int magic;
  int older_value[3][10], old_value[3][10], new_value[3][10];
  int older_time[3], old_time[3], new_time[3];
  int diff_time;
  char buffer[80];

  /* SNMP Responses */
  int **response;

  ports = newwin(18, 80, 5, 0);

  screen_area("Show Current Port Statistics");
  screen_status(STAT_WAIT);
  sprintf(buffer, "%s - Port %d/%d", fqdn, module, port);
  screen_hub(buffer);

/* first we need to get the ifindex mapping for this module/port combo */
  sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.11.%d.%d",
	  module, port);
  requests[0] = requestor[0];
  response = (int **)snmpget(gateway, community, 1, requests, NULL);
  if (!response) {
    return ERR_BACK;
  }
  magic = *(response[0]);

/* initialize all of the values to play it safe */
  for (incr=0; incr < 3; incr++)
    {
      for (subincr=0; subincr < 10; subincr++)
	old_value[incr][subincr] = 0;
      old_time[incr] = 0;
      older_time[incr] = 0;
    }

  clear_legend();
  set_legend(0, "The current (live) statistics for the specified port are displayed on");
  set_legend(1, "this screen. In and out packet and error counters are tabulated on a");
  set_legend(2, "per second basis (updated every 5 seconds) and on a per minute basis.");

  mvwprintw(ports, 0, 0, 
	    highlight("MEASUREMENT               IN/SEC   OUT/SEC    IN/MIN   OUT/MIN"));

  mvwprintw(ports, 1, 0, "Octets");
  mvwprintw(ports, 2, 0, "Unicast Packets");
  mvwprintw(ports, 3, 0, "Broadcast/Multicast");
  mvwprintw(ports, 4, 0, "Discarded Packets");
  mvwprintw(ports, 5, 0, "Error Packets");
  mvwprintw(ports, 6, 0, "Deferrals");

  mvwprintw(ports, 8, 0, "Alignment Errors");
  mvwprintw(ports, 9, 0, "CRC Errors");
  mvwprintw(ports, 10,0, "Too Long Errors");
  mvwprintw(ports, 11,0, "Late Collisions");
  mvwprintw(ports, 12,0, "Single Collisions");
  mvwprintw(ports, 13,0, "Multiple Collisions");
  mvwprintw(ports, 14,0, "Excessive Collisions");

  fcntl(0, F_SETFL, O_NDELAY);
  
/* keep looping until the user departs */
  while (TRUE)
    {
/* first query sequence */
      /* uptime */
      sprintf(requestor[0], ".1.3.6.1.2.1.1.3.0");
      /* in octets */
      sprintf(requestor[1], ".1.3.6.1.2.1.2.2.1.10.%d", magic);       
      /* in unicasts */
      sprintf(requestor[2], ".1.3.6.1.2.1.2.2.1.11.%d", magic);
      /* in multicasts/broadcasts */
      sprintf(requestor[3], ".1.3.6.1.2.1.2.2.1.12.%d", magic);
      /* in discards */
      sprintf(requestor[4], ".1.3.6.1.2.1.2.2.1.13.%d", magic);
      /* in errors */
      sprintf(requestor[5], ".1.3.6.1.2.1.2.2.1.14.%d", magic);

      requests[0] = requestor[0];
      requests[1] = requestor[1];
      requests[2] = requestor[2];
      requests[3] = requestor[3];
      requests[4] = requestor[4];
      requests[5] = requestor[5];

      response = (int **)snmpget(gateway, community, 6, requests, NULL);
      if (!response) {
	screen_error("unable to contact switch");
	return ERR_BACK;
      }

      for (incr=1; incr < 6; incr++)
	new_value[0][incr] = *(response[incr]);
      new_time[0] = *(response[0]);

/* if this isn't the first set of data */
      if (old_time[0] != 0)
	{
	  diff_time = (new_time[0] - old_time[0])/100;
	  mvwprintw(ports, 1, 24, "%8d", 
		    (new_value[0][1]-old_value[0][1]) / diff_time);
	  mvwprintw(ports, 2, 24, "%8d", 
		    (new_value[0][2]-old_value[0][2]) / diff_time);
	  mvwprintw(ports, 3, 24, "%8d", 
		    (new_value[0][3]-old_value[0][3]) / diff_time);
	  mvwprintw(ports, 4, 24, "%8d", 
		    (new_value[0][4]-old_value[0][4]) / diff_time);
	  mvwprintw(ports, 5, 24, "%8d", 
		    (new_value[0][5]-old_value[0][5]) / diff_time);

	  wrefresh(ports);
	}
/* if this isn't the first set of data and sixty seconds have elapsed */
      if ((older_time[0] != 0) && 
	  ((new_time[0] - older_time[0]) > 6000))
	{
	  diff_time = ((new_time[0] - older_time[0])/100)/60;
	  mvwprintw(ports, 1, 44, "%8d", 
		    (new_value[0][1]-old_value[0][1]) / diff_time);
	  mvwprintw(ports, 2, 44, "%8d", 
		    (new_value[0][2]-old_value[0][2]) / diff_time);
	  mvwprintw(ports, 3, 44, "%8d", 
		    (new_value[0][3]-old_value[0][3]) / diff_time);
	  mvwprintw(ports, 4, 44, "%8d", 
		    (new_value[0][4]-old_value[0][4]) / diff_time);
	  mvwprintw(ports, 5, 44, "%8d", 
		    (new_value[0][5]-old_value[0][5]) / diff_time);

	  wrefresh(ports);

	  for (incr=0; incr < 6; incr++)
	    older_value[0][incr] = new_value[0][incr];
	  older_time[0] = new_time[0];
	}
      else if ((new_time[0] - older_time[0]) > 6000)
	{
	  for (incr=0; incr < 6; incr++)
	    older_value[0][incr] = new_value[0][incr];
	  older_time[0] = new_time[0];
	}

      for (incr=0; incr < 6; incr++)
	old_value[0][incr] = new_value[0][incr];
      old_time[0] = new_time[0];

/* second set of data to query */
      /* out octets */
      sprintf(requestor[1], ".1.3.6.1.2.1.2.2.1.16.%d", magic);
      /* out unicasts */
      sprintf(requestor[2], ".1.3.6.1.2.1.2.2.1.17.%d", magic);
      /* out broadcasts/multicasts */
      sprintf(requestor[3], ".1.3.6.1.2.1.2.2.1.18.%d", magic);
      /* out discards */
      sprintf(requestor[4], ".1.3.6.1.2.1.2.2.1.19.%d", magic);
      /* out errors */
      sprintf(requestor[5], ".1.3.6.1.2.1.2.2.1.20.%d", magic);
      
      requests[1] = requestor[1];
      requests[2] = requestor[2];
      requests[3] = requestor[3];
      requests[4] = requestor[4];
      requests[5] = requestor[5];
      
      response = (int **)snmpget(gateway, community, 6, requests, NULL);
      if (!response) {
	screen_error("unable to contact switch");
	return ERR_BACK;
      }

      for (incr=1; incr < 6; incr++)
	new_value[1][incr] = *(response[incr]);
      new_time[1] = *(response[0]);
      
/* if this isn't the first set of data */
      if (old_time[1] != 0)
	{
	  diff_time = (new_time[1] - old_time[1])/100;
	  mvwprintw(ports, 1, 34, "%8d", 
		    (new_value[1][1]-old_value[1][1]) / diff_time);
	  mvwprintw(ports, 2, 34, "%8d", 
		    (new_value[1][2]-old_value[1][2]) / diff_time);
	  mvwprintw(ports, 3, 34, "%8d", 
		    (new_value[1][3]-old_value[1][3]) / diff_time);
	  mvwprintw(ports, 4, 34, "%8d", 
		    (new_value[1][4]-old_value[1][4]) / diff_time);
	  mvwprintw(ports, 5, 34, "%8d", 
		    (new_value[1][5]-old_value[1][5]) / diff_time);

	  wrefresh(ports);
	}      
/* if this isn't the first set of data and sixty seconds have elapsed */
      if ((older_time[1] != 0) && 
	  ((new_time[1] - older_time[1]) > 6000))
	{
	  diff_time = ((new_time[1] - older_time[1])/100)/60;
	  mvwprintw(ports, 1, 54, "%8d", 
		    (new_value[1][1]-old_value[1][1]) / diff_time);
	  mvwprintw(ports, 2, 54, "%8d", 
		    (new_value[1][2]-old_value[1][2]) / diff_time);
	  mvwprintw(ports, 3, 54, "%8d", 
		    (new_value[1][3]-old_value[1][3]) / diff_time);
	  mvwprintw(ports, 4, 54, "%8d", 
		    (new_value[1][4]-old_value[1][4]) / diff_time);
	  mvwprintw(ports, 5, 54, "%8d", 
		    (new_value[1][5]-old_value[1][5]) / diff_time);

	  wrefresh(ports);

	  for (incr=0; incr < 6; incr++)
	    older_value[1][incr] = new_value[1][incr];
	  older_time[1] = new_time[1];
	}
      else if ((new_time[1] - older_time[1]) > 6000)
	{
	  for (incr=0; incr < 6; incr++)
	    older_value[1][incr] = new_value[1][incr];
	  older_time[1] = new_time[1];
	}

      for (incr=0; incr < 6; incr++)
	old_value[1][incr] = new_value[1][incr];
      old_time[1] = new_time[1];

/* final (third) set of data */
      /* alignment errors */
      sprintf(requestor[1], ".1.3.6.1.2.1.10.7.2.1.2.%d", magic);
      /* FCS errors */
      sprintf(requestor[2], ".1.3.6.1.2.1.10.7.2.1.3.%d", magic);
      /* single collisions */
      sprintf(requestor[3], ".1.3.6.1.2.1.10.7.2.1.4.%d", magic);
      /* multiple collision */
      sprintf(requestor[4], ".1.3.6.1.2.1.10.7.2.1.5.%d", magic);
      /* deferrals */
      sprintf(requestor[5], ".1.3.6.1.2.1.10.7.2.1.7.%d", magic);
      /* late collisions */
      sprintf(requestor[6], ".1.3.6.1.2.1.10.7.2.1.8.%d", magic);
      /* excessive collisions */
      sprintf(requestor[7], ".1.3.6.1.2.1.10.7.2.1.9.%d", magic);
      /* too long errors */
      sprintf(requestor[8], ".1.3.6.1.2.1.10.7.2.1.13.%d", magic);
      
      requests[1] = requestor[1];
      requests[2] = requestor[2];
      requests[3] = requestor[3];
      requests[4] = requestor[4];
      requests[5] = requestor[5];
      requests[6] = requestor[6];
      requests[7] = requestor[7];
      requests[8] = requestor[8];
      
      response = (int **)snmpget(gateway, community, 9, requests, NULL);
      if (!response) {
	screen_error("unable to contact switch");
	return ERR_BACK;
      }

      for (incr=1; incr < 9; incr++)
	new_value[2][incr] = *(response[incr]);
      new_time[2] = *(response[0]);

/* if this isn't the first set of data */
      if (old_time[2] != 0)
	{
	  diff_time = (new_time[2] - old_time[2])/100;
	  mvwprintw(ports, 6, 34, "%8d", 
		    (new_value[2][5]-old_value[2][5]) / diff_time);
	  mvwprintw(ports, 8, 24, "%8d", 
		    (new_value[2][1]-old_value[2][1]) / diff_time);
	  mvwprintw(ports, 9, 24, "%8d", 
		    (new_value[2][2]-old_value[2][2]) / diff_time);
	  mvwprintw(ports, 10, 24, "%8d", 
		    (new_value[2][8]-old_value[2][8]) / diff_time);
	  mvwprintw(ports, 11, 24, "%8d", 
		    (new_value[2][6]-old_value[2][6]) / diff_time);
	  mvwprintw(ports, 12, 34, "%8d", 
		    (new_value[2][3]-old_value[2][3]) / diff_time);
	  mvwprintw(ports, 13, 34, "%8d", 
		    (new_value[2][4]-old_value[2][4]) / diff_time);
	  mvwprintw(ports, 14, 34, "%8d", 
		    (new_value[2][7]-old_value[2][7]) / diff_time);

	  wrefresh(ports);
	}      
/* if this isn't the first set of data and sixty seconds have elapsed */
      if ((older_time[2] != 0) && 
	  ((new_time[2] - older_time[2]) > 6000))
	{
	  diff_time = ((new_time[2] - older_time[2])/100)/60;
	  mvwprintw(ports, 6, 54, "%8d", 
		    (new_value[2][5]-old_value[2][5]) / diff_time);
	  mvwprintw(ports, 8, 44, "%8d", 
		    (new_value[2][1]-old_value[2][1]) / diff_time);
	  mvwprintw(ports, 9, 44, "%8d", 
		    (new_value[2][2]-old_value[2][2]) / diff_time);
	  mvwprintw(ports, 10, 44, "%8d", 
		    (new_value[2][8]-old_value[2][8]) / diff_time);
	  mvwprintw(ports, 11, 44, "%8d", 
		    (new_value[2][6]-old_value[2][6]) / diff_time);
	  mvwprintw(ports, 12, 54, "%8d", 
		    (new_value[2][3]-old_value[2][3]) / diff_time);
	  mvwprintw(ports, 13, 54, "%8d", 
		    (new_value[2][4]-old_value[2][4]) / diff_time);
	  mvwprintw(ports, 14, 54, "%8d", 
		    (new_value[2][7]-old_value[2][7]) / diff_time);

	  wrefresh(ports);

	  for (incr=0; incr < 6; incr++)
	    older_value[2][incr] = new_value[2][incr];
	  older_time[2] = new_time[2];
	}
      else if ((new_time[2] - older_time[2]) > 6000)
	{
	  for (incr=0; incr < 6; incr++)
	    older_value[2][incr] = new_value[2][incr];
	  older_time[2] = new_time[2];
	}

      for (incr=0; incr < 9; incr++)
	old_value[2][incr] = new_value[2][incr];
      old_time[2] = new_time[2];

      step = 0;
      ch = getc(stdin);
      while (ch != -1)
	{
	  switch (step)
	    {
	    case 0:
	      switch (toupper(ch))
		{
		case 'L':
		case '?':
		  fcntl(0, F_SETFL, !O_NDELAY);
		  screen_legend();
		  touchwin(ports); wrefresh(ports);
		  fcntl(0, F_SETFL, O_NDELAY);
		  break;
		case 'B':
		case 2:
		case 7:
		  returnable = ERR_BACK;
		  goto down;
		case 'M':
		case 'T':
		  returnable = ERR_TOP;
		  clear_stack();
		  goto down;
		case 'E':
		case 'Q':
		  returnable = ERR_QUIT;
		  goto down;
		  break;
		case 27:
		  step++;
		  break;
		}  
	      break;
	    case 1:
	      if (ch == 91)
		step++;
	      else
		step--;
	      break;
	    case 2:
	      step = 0;
	      switch (ch)
		{
		case 68:
		  returnable = ERR_BACK;
		  goto down;
		down:
		  fcntl(0, F_SETFL, !O_NDELAY);
		  werase(ports);
		  wrefresh(ports);
		  return returnable;
		  break;
		case 67:
		  printf("\07");
		  break;
		}
	    } 
	  ch = getc(stdin);
	}
      sleep(5);
      screen_status(STAT_ACTIVE);
    }
}

/* dynamic_module_statistics - display current (live) statistics by module
** 
** this keeps running until the user kills it
** check after every query for user input to improve interactive performance
*/
int dynamic_module_statistics(char *gateway, char *community, char *fqdn, 
			      int module)
{
  WINDOW *ports;
  char *requests[10];
  char requestor[10][50];
  int incr, subincr;
  int returnable;
  int step;
  char ch;
  int port_count;
  int mapping[50];
  int stats[50][5];
  int old[50][5];
  int x, y;
  int faster;

  /* SNMP Responses */
  int **response;

  ports = newwin(18, 80, 5, 0);

  fcntl(0, F_SETFL, O_NDELAY);
  
  screen_area("Show Current Module Statistics");
  screen_status(STAT_WAIT);
  screen_hub(fqdn);

  clear_legend();
  set_legend(0, "For each port on the specified module, the number of bytes received and");
  set_legend(1, "transmitted per second and the total number of errors received and sent");
  set_legend(2, "per second are displayed.");

/* get the number of ports on this module */
  sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.3.1.1.14.%d", module);
  requests[0] = requestor[0];

  response = (int **)snmpget(gateway, community, 1, requests, NULL);
  if (!response) {
    screen_error("unable to contact switch");
    return ERR_BACK;
  }

  port_count = *(response[0]);
  
/* get the inindex port mapping each port on the module (runs only once) */
  for (incr = 0; incr < port_count; incr++)
    {
      sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.11.%d.%d", 
	      module, incr+1);
      response = (int **)snmpget(gateway, community, 1, requests, NULL);
      if (!response) {
	screen_error("unable to contact switch");
	return ERR_BACK;
      }
      mapping[incr] = *(response[0]);
    }

/* print out the basic legend for these (runs only once) */
  mvwprintw(ports, 0, 0, highlight("               IN   IN     OUT  OUT"));
  mvwprintw(ports, 1, 0, highlight("PORT        BYTES  ERR   BYTES  ERR"));
  if (port_count > 12)
    {
      mvwprintw(ports, 0, 40, 
		highlight("               IN   IN     OUT  OUT"));
      mvwprintw(ports, 1, 40, 
		highlight("PORT        BYTES  ERR   BYTES  ERR"));
    }

  for (incr=0; incr < port_count; incr++)
    if (incr < 12)
      mvwprintw(ports, incr+2, 0, "%d/%d", module, incr+1);
    else
      mvwprintw(ports, incr-12+2, 40, "%d/%d", module, incr+1);

  wrefresh(ports);

/* initilize the values to be on the safe side (and warn of first run) */
  for (incr=0; incr < 50; incr++)
    for (subincr=0; subincr < 5; subincr++)
      stats[incr][subincr] = old[incr][subincr] = 0;

/* add the first entry for uptime so it appears in all queries */
  sprintf(requestor[0], ".1.3.6.1.2.1.1.3.0");
  requests[0] = requestor[0];

/* enter into the update loop here */
  while (TRUE)
    {
      if (old[0][0] != 0)
	screen_status(STAT_ACTIVE);
/* for each interface */
      for (incr=0; incr < port_count; incr++)
	{
/* get the latest statistics */
	  sprintf(requestor[1], ".1.3.6.1.2.1.2.2.1.10.%d", mapping[incr]);
	  sprintf(requestor[2], ".1.3.6.1.2.1.2.2.1.14.%d", mapping[incr]);
	  sprintf(requestor[3], ".1.3.6.1.2.1.2.2.1.16.%d", mapping[incr]);
	  sprintf(requestor[4], ".1.3.6.1.2.1.2.2.1.20.%d", mapping[incr]);
	  
	  requests[1] = requestor[1];
	  requests[2] = requestor[2];
	  requests[3] = requestor[3];
	  requests[4] = requestor[4];

	  response = (int **)snmpget(gateway, community, 5, requests, NULL);
	  if (!response) {
	    screen_error("unable to contact switch");
	    return ERR_BACK;
	  }
	  
	  for (subincr=0; subincr < 5; subincr++)
	    stats[incr][subincr] = *(response[subincr]);

	  if (incr < 12)
	    {
	      y = incr+2;
	      x = 10;
	    }
	  else
	    {
	      y = incr-12+2;
	      x = 50;
	    }

/* now check to see if we can print statistics */
	  if (old[incr][0] != 0)
	    {
	      faster = (stats[incr][0] - old[incr][0])/100;

	      mvwprintw(ports, y, x, "%7d %4d %7d %4d",
			(stats[incr][1]-old[incr][1])/faster,
			(stats[incr][2]-old[incr][2])/faster,
			(stats[incr][3]-old[incr][3])/faster,
			(stats[incr][4]-old[incr][4])/faster);
	    }
	  wrefresh(ports);
/* update the values */
	  for (subincr=0; subincr < 5; subincr++)
	    old[incr][subincr] = stats[incr][subincr];
	  step = 0;
	  ch = getc(stdin);
	  while (ch != -1)
	    {
	      switch (step)
		{
		case 0:
		  switch (toupper(ch))
		    {
		    case 'B':
		    case 2:
		    case 7:
		      returnable = ERR_BACK;
		      goto down;
		    case 'L':
		    case '?':
		      fcntl(0, F_SETFL, !O_NDELAY);
		      screen_legend();
		      touchwin(ports); wrefresh(ports);
		      fcntl(0, F_SETFL, O_NDELAY);
		      break;
		    case 'E':
		    case 'Q':
		      returnable = ERR_QUIT;
		      goto down;
		    case 'M':
		    case 'T':
		      returnable = ERR_TOP;
		      clear_stack();
		      goto down;
		    down:
		      fcntl(0, F_SETFL, !O_NDELAY);
		      werase(ports);
		      wrefresh(ports);
		      return returnable;
		      break;
		    case 27:
		      step++;
		      break;
		    }  
		  break;
		case 1:
		  if (ch == 91)
		    step++;
		  else
		    step--;
		  break;
		case 2:
		  step = 0;
		  switch (ch)
		    {
		    case 68:
		      returnable = ERR_BACK;
		      goto down;
		    case 67:
		      printf("\07");
		  break;
		    }
		} 
	      ch = getc(stdin);
	    }
	}
      sleep(5);
    }
}

/* select_module - select a module on the switch (also show debug info)
**
** basically, display statistics relevant to the purpose of this call
** and then feed the module number into the appropriate subroutine
**
** mode = the type of setting we want to do (port set only)
** purpose = the subroutine that we should call from this function
*/
int select_module(char *gateway, char *community, char *fqdn, 
		  int mode, int purpose)
{
  char requestor[10][100];
  char *request[10];
  char query[80];
  int count;
  oid respond[MAX_NAME_LEN];
  oid *nameP;
  int name_length, result;
  int last = 1;
  int modules[20]; /* note - we support a maximum of twenty modules */
  char buffer[80];
  char temper[80];
  char buffers[20][80];
  int run = FALSE;

  /* SNMP Responses */
  int **response;
  u_char GNResponse[24];

/* let's pretend there are no modules in the unit */
  for (count=0; count < 20; count++)
    modules[count] = FALSE;

 top:
  init_item();

  screen_area("Show Switch Modules");
  screen_status(STAT_WAIT);
  screen_hub(fqdn);

/* section to determine which slots are populated with cards */
/* only do this on the first time through this function */
  if (!run)
    {
      sprintf(query, ".1.3.6.1.4.1.9.5.1.3.1.1.1");

      if (!mib_TxtToOid((void *) query, &nameP, &name_length)) {
	screen_error("Internal SWADMIN Error");
	return ERR_BACK;
      }
      
      result = snmpgetnext(gateway, community, 
			   nameP, name_length, 
			   respond, GNResponse,
			   NULL);
      
      if (result < 0) {
	return ERR_BACK;
      }
      
      last = 1; count = 0;
      
      while ((nameP[12] == respond[12]) && (count < 20)) {
	count++;
	modules[respond[13]] = TRUE;
	result = snmpgetnext(gateway, community, 
			     respond, result, 
			     respond, GNResponse,
			     NULL);
	if (result < 0) {
	  return ERR_BACK;
	}
      }
      free(nameP);
    }      


/* now that we have module information, display statistics about the modules */
  for (count=0; count < 20; count++)
    {
/* If a card exists in this slot */
      if (modules[count])
	{
	  sprintf(temper, "Slot %d  ", count);
/* if the user is browing, always update; otherwise, only update on first pass
*/
	  if ((purpose == BROWSING) || (!run))
	    {
	      sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.3.1.1.2.%d", count);
	      sprintf(requestor[1], ".1.3.6.1.4.1.9.5.1.3.1.1.10.%d", count);
	      sprintf(requestor[2], ".1.3.6.1.4.1.9.5.1.3.1.1.11.%d", count);
	      sprintf(requestor[3], ".1.3.6.1.4.1.9.5.1.3.1.1.12.%d", count);
	      sprintf(requestor[4], ".1.3.6.1.4.1.9.5.1.3.1.1.14.%d", count);
	      sprintf(requestor[5], ".1.3.6.1.4.1.9.5.1.3.1.1.15.%d", count);
	      sprintf(requestor[6], ".1.3.6.1.4.1.9.5.1.3.1.1.17.%d", count);
	      request[0] = requestor[0];
	      request[1] = requestor[1];
	      request[2] = requestor[2];
	      request[3] = requestor[3];
	      request[4] = requestor[4];
	      request[5] = requestor[5];
	      request[6] = requestor[6];
	      
	      response = (int **)snmpget(gateway, community, 7, request, NULL);
	      if (!response) {
		return ERR_BACK;
	      }

	      switch(*(response[1]))
		{
		case 1: sprintf(buffer, "%s- ", temper); break;
		case 2: sprintf(buffer, "%sO ", temper); break;
		case 3: sprintf(buffer, "%sF ", temper); break;
		case 4: sprintf(buffer, "%sX ", temper); break;
		}
	      switch(*(response[3]))
		{
		case 1:
		case 3: sprintf(temper, "%sE ", buffer); break;
		case 4: sprintf(temper, "%sD ", buffer); break;
		}
	      if ((*(response[2])) == 0)
		sprintf(buffer, "%sP  ", temper); 
	      else
		sprintf(buffer, "%sF  ", temper); 
	      
	      switch(*(response[0]))
		{
		case 2: 
		  sprintf(temper, "Empty"); break;
		case 3: 
		  sprintf(temper, "2+8 Port CDDI Concentrator"); break;
		case 4: 
		  sprintf(temper, "2+8 Port FDDI Concentrator"); break;
		case 5: 
		  sprintf(temper, "2+16 Port FDDI/CDDI Concentrator"); break;
		case 11: 
		  sprintf(temper, "2+8 Port FDDI/Ethernet Switch"); break;
		case 12: 
		  sprintf(temper, "2 Slot FDDI/CDDI Concentrator"); break;
		case 23: 
		  sprintf(temper, "Supervisor Module (2 100-BASE-TX)"); break;
		case 25: 
		  sprintf(temper, "12 10-BASE-FL"); break;
		case 26: 
		  sprintf(temper, "24 10-BASE-T"); break;
		case 27: 
		  sprintf(temper, "12 100-BASE-TX"); break;
		case 28:
		case 31: 
		  sprintf(temper, "DAS MM FDDI"); break;
		case 29: 
		  sprintf(temper, "DAS CDDI"); break;
		case 30: 
		  sprintf(temper, "DAS SM FDDI"); break;
		case 32: 
		  sprintf(temper, "MM ATM"); break;
		case 33: 
		  sprintf(temper, "SM ATM"); break;
		case 34: 
		  sprintf(temper, "UTP ATM"); break;
		case 35: 
		  sprintf(temper, "12 100-BASE-FX"); break;
		case 36: 
		  sprintf(temper, "12 10/100-BASE-TX"); break;
		case 37: 
		  sprintf(temper, "48 10-BASE-T (4 Segment)"); break;
		case 38: 
		  sprintf(temper, "Supervisor (2 100-BASE-FX MM)"); break;
		case 39: 
		  sprintf(temper, "Supervisor (2 100-BASE-FX SM)"); break;
		case 1: 
		default:
		  sprintf(temper, "Unknown"); break;
		}
	      sprintf(buffer, "%s%s  %s", buffer, (u_char *) response[6], 
		      temper);
	      strcpy(buffers[count], buffer);
	    }
	  add_item(buffers[count], (void *)count);
	}
    }

  clear_legend();
  set_legend(0, "            ^------------- O=Operational  F=Failure  X=Unknown");
  set_legend(1, "              ^----------- E=Enabled      D=Disabled");
  set_legend(2, "                ^--------- P=Passed Test  F=Failed Test");
  set_legend(3, "                   ^------ Cisco Model Number");

  run = TRUE;
  switch (purpose)
    {
    case CURRENT:
    case BACKGROUND:
    case CURRENTMOD:
    case BROWSING:
      last = (int)menu_item("module to examine", fqdn); break;
    case CONTROL:
      last = (int)menu_item("module to configure", fqdn); break;
    }

  if (last == 0)
    switch (errorcode)
      {
      case ERR_QUIT:
	return ERR_QUIT;
      case ERR_TOP:
	clear_stack();
	return ERR_TOP;
      case ERR_BACK:
	return ERR_BACK;
      }

  switch(purpose)
    {
/* if we're just getting module/port statistics, then call the port stats */
    case BROWSING:
      switch(get_sw_port(gateway, community, fqdn, last))
	{
	case ERR_QUIT:
	  return ERR_QUIT;
	case ERR_TOP:
	  clear_stack();
	  return ERR_TOP;
	case ERR_BACK:
	default:
	  goto top;
	}
      break;
/* show the live module statistics for this module */
    case CURRENTMOD:
      switch(dynamic_module_statistics(gateway, community, fqdn, last))
	{
	case ERR_QUIT:
	  return ERR_QUIT;
	case ERR_TOP:
	  clear_stack();
	  return ERR_TOP;
	case ERR_BACK:
	default:
	  goto top;
	}
      break;
/* get current port statistics by passing off to port selection first */
    case CURRENT:
      pushd(-1);
      switch(select_port(gateway, community, fqdn, last, CURRENT))
	{
	case ERR_QUIT:
	  return ERR_QUIT;
	case ERR_TOP:
	  clear_stack();
	  return ERR_TOP;
	case ERR_BACK:
	default:
	  goto top;
	}
      break;
/* set current port statistics by selection port and passing off command 
** NOTE: commands are no longer passed in from the menu system; they are
** handled at a layer below this
*/
    case CONTROL:
      pushd(-1);
      switch(select_port(gateway, community, fqdn, last, mode))
	{
	case ERR_QUIT:
	  return ERR_QUIT;
	case ERR_TOP:
	  clear_stack();
	  return ERR_TOP;
	case ERR_BACK:
	default:
	  goto top;
	}
      break;
/* give historical module statistics (and port statistics) */
    case BACKGROUND:
      pushd(-1);
      switch(static_module_statistics(gateway, community, fqdn, last))
	{
	case ERR_QUIT:
	  return ERR_QUIT;
	case ERR_TOP:
	  clear_stack();
	  return ERR_TOP;
	case ERR_BACK:
	default:
	  goto top;
	}
      break;
    default:
      return ERR_BACK;
    }
}

/* get_sw_port - get per port configuration given module
*/
int get_sw_port(char *gateway, char *community, char *fqdn, int module)
{
  WINDOW *stats;
  char *request[10];
  char requestor[10][80];
  int returnable;
  char ch;
  int port_count, count, step, count1;
  int x, y;

  /* SNMP Responses */
  int **response;
  u_char *bufp;

  stats = newwin(18, 70, 5, 0);

  fcntl(0, F_SETFL, O_NDELAY);
  
  screen_area("Show Module Status");
  screen_status(STAT_WAIT);
  screen_hub(fqdn);

  clear_legend();
  set_legend(0, "^---------------- module/port");
  set_legend(1, "     ^----------- O=On-Line       X=Off-Line      F=Failure");
  set_legend(2, "       ^--------- A=Autodetect    E=10-BASE-T     F=100-BASE-TX");
  set_legend(3, "         ^------- H=Half Duplex   F=Full Duplex");
  set_legend(4, "            ^---- port name");

/* determine the number of ports on this module */
  sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.3.1.1.14.%d", module);
  request[0] = requestor[0];

  response = (int **)snmpget(gateway, community, 1, request, NULL);
  if (!response) {
    return ERR_BACK;
  }

  port_count = *(response[0]);

  mvwprintw(stats, 0, 0, highlight("PORT  STATUS NAME                  "));
  if (port_count > 12)
    mvwprintw(stats, 0, 40, highlight("PORT  STATUS NAME                  "));


  for (count = 1; count <= port_count; count++)
    if (count > 12)
      mvwprintw(stats, count-12, 40, "%d/%d", module, count);
    else
      mvwprintw(stats, count, 0, "%d/%d", module, count);

  while(TRUE)
    {
/* for each port on the module */
      for (count = 1; count <= port_count; count++)
	{
	  sprintf(requestor[0], 
		  ".1.3.6.1.4.1.9.5.1.4.1.1.6.%d.%d", module, count);
	  sprintf(requestor[1], 
		  ".1.3.6.1.4.1.9.5.1.4.1.1.8.%d.%d", module, count);
	  sprintf(requestor[2], 
		  ".1.3.6.1.4.1.9.5.1.4.1.1.9.%d.%d", module, count);
	  sprintf(requestor[3], 
		  ".1.3.6.1.4.1.9.5.1.4.1.1.10.%d.%d", module, count);
	  
	  request[0] = requestor[0];
	  request[1] = requestor[1];
	  request[2] = requestor[2];
	  request[3] = requestor[3];
	  
	  response = (int **)snmpget(gateway, community, 4, request, NULL);
	  if (!response) {
	    screen_error("unable to contact switch");
	    return ERR_BACK;
	  }

	  if (count > 12) {
	    y = count-12;
	    x = 40;
	  } else {
	    y = count;
	    x = 0;
	  }

	  switch(*(response[0]))
	    {
	    case 2: mvwprintw(stats, y, x+6, "O"); break;
	    case 3: mvwprintw(stats, y, x+6, "F"); break;
	    case 1: 
	    case 4: 
	    default: mvwprintw(stats, y, x+6, "X"); break;
	    }

	  switch(*(response[2]))
	    {
	    case 1: mvwprintw(stats, y, x+8, "A"); break;
	    case 10000000: mvwprintw(stats, y, x+8, "E"); break;
	    case 100000000: mvwprintw(stats, y, x+8, "F"); break;
	    case 155000000: mvwprintw(stats, y, x+8, "O"); break;
	    default: mvwprintw(stats, y, x+8, "X"); break;
	    }
	  switch(*(response[3]))
	    {
	    case 1: mvwprintw(stats, y, x+10, "H"); break;
	    case 2: mvwprintw(stats, y, x+10, "F"); break;
	    default: mvwprintw(stats, y, x+10, "X"); break;
	    }

	  sprintf(requestor[0], ".1.3.6.1.4.1.9.5.1.4.1.1.4.%d.%d", module,
		  count);

	  request[0] = requestor[0];

	  response = (int **)snmpget(gateway, community, 1, request, NULL);
	  if (!response) {
	    screen_error("unable to contact switch");
	    return ERR_BACK;
	  }

	  bufp = (u_char *)response[0];
	  for (count1=0; (bufp[count1] != 0) && (count1 < 26);)
	    mvwprintw(stats, y, x+13+count1, "%c", 
		      bufp[count1++]);

	  step = 0;
	  ch = getc(stdin);
	  while (ch != -1)
	    {
	      switch (step)
		{
		case 0:
		  switch (toupper(ch))
		    {
		    case 'B':
		    case 2:
		    case 7:
		      returnable = ERR_BACK;
		      goto down;
		    case 'L':
		    case '?':
		      fcntl(0, F_SETFL, !O_NDELAY);
		      screen_legend();
		      touchwin(stats); wrefresh(stats);
		      fcntl(0, F_SETFL, O_NDELAY);
		      break;
		    case 'E':
		    case 'Q':
		      returnable = ERR_QUIT;
		      goto down;
		    case 'M':
		    case 'T':
		      returnable = ERR_TOP;
		      clear_stack();
		      goto down;
		    down:
		      fcntl(0, F_SETFL, !O_NDELAY);
		      werase(stats);
		      wrefresh(stats);
		      delwin(stats);
		      return returnable;
		      break;
		    case 27:
		      step++;
		      break;
		    }  
		  break;
		case 1:
		  if (ch == 91)
		    step++;
		  else
		    step--;
		  break;
		case 2:
		  step = 0;
		  switch (ch)
		    {
		    case 68:
		      returnable = ERR_BACK;
		      goto down;
		    case 67:
		      printf("\07");
		      break;
		    }
		} 
	      ch = getc(stdin);
	    }
	}
      
      wrefresh(stats);
      screen_status(STAT_ACTIVE);
      
      sleep(1);
    }
}
