/***************************************************************************
 *
 *           Copyright 1997 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.
 * 
 * load - monitor processor load via SNMP for critical servers
 *
 * Erikas Aras Napjus
 * erikas+@cmu.edu
 * Network Development
 * Carnegie Mellon University
 *
 ***************************************************************************/

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

#define NUMSERV 2

#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <curses.h>

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

#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif /* HAVE_MALLOC_H */

#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif /* HAVE_STDLIB_H */

#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_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

#include <snmp/snmp.h>

#include "version.h"

static char rcsid[] = 
"$Id: ccon.c,v 1.1.1.1 1998/03/08 16:35:02 ryan Exp $";

void Usage(char *Err)
{
  if (Err != NULL)
    fprintf(stderr, "\nUnknown argument '%s'\n", Err);

  fprintf(stderr, "\nusage: ccon [--version] [--config=/path/to/file]\n");

  fprintf(stderr, "--version:  Print version information.\n");
  fprintf(stderr, "--config=:  Config file to use.\n\n");
  fprintf(stderr, "The config file used is either:\n");
  fprintf(stderr, "\t the specified file\n");
  fprintf(stderr, "\t the file specified by CCON_CONF\n");
  fprintf(stderr, "\t %s\n", DEF_CONF);
  fprintf(stderr, "\n");
  exit(-1);
}

void Version(void)
{
  fprintf(stderr, "Cisco Console, version %s\n", ccon_Version());
  fprintf(stderr, "CMU SNMP Library Version %s\n", snmp_Version());
  exit(-1);
}

struct Device
{
  char hostname[20];
  char ipaddr[20];
  char community[20];
} device[10];

int num_devices;

void readconf(char *File)
{
  FILE *config = NULL;
  char line[1024];

  if (File)
    config = fopen(File, "r");

  if (config == NULL) {
    char *env;
    env = getenv("CCON_CONF");
    if (env)
      config = fopen(env, "r");
  }

  if (config == NULL)
    config = fopen(DEF_CONF, "r");

  if (config == NULL) {
    fprintf(stderr, "Unable to locate configuration file!\n");
    exit(-1);
  }

  num_devices = 0;
  while (!(feof(config))) {

    /* First, read the line */
    if (fgets((char *)line, 1024, config) == NULL)
      break;

    /* Is this a comment? */
    if ((line[0] == '#') || 
	(line[0] == ';') ||
	(strlen((char *)line) < 6)) {
      /* A few blank spaces should actually be ignored.  I hope. */
      ;
	} else {
	  
	  sscanf(line, "%s %s %s\n",
		 device[num_devices].hostname, device[num_devices].ipaddr,
		 device[num_devices].community);
	printf("Read '%s'\n", device[num_devices].hostname);
	num_devices++;
      }
  }
  fclose(config);
  printf("Read a total of %d devices.\n", num_devices);
}
  
char *highlight(char *voivod)
{
#ifdef A_REVERSE
  return (voivod);
#else /* A_REVERSE */

#ifdef __sun
  /* This works under sunos */
  char str[80];
  int incr;

  for (incr=0; voivod[incr] != NULL; incr++)
    str[incr] = voivod[incr]+128;
  str[incr] = NULL;
  return str;
#else /* __sun */
  
  /* No inverse */
  return(voivod);

#endif /* __sun */
#endif /* A_REVERSE */
}

int main(int argc, char **argv)
{
  WINDOW *core, *title, *load;

  int incr;
  char *timer;
  int old[10];
  struct timeval tv;
  int loader;
  char holdme[80];
  char *Config = NULL;

  oid FiveSecond[11] = { 1, 3, 6, 1, 4, 1, 9, 2, 1, 56, 0 };
  oid IntakeTemp[14] = { 1, 3, 6, 1, 4, 1, 9, 9, 13, 1, 3, 1, 3, 1 };
  oid HotPntTemp[14] = { 1, 3, 6, 1, 4, 1, 9, 9, 13, 1, 3, 1, 3, 2 };
  oid MemFree[11]    = { 1, 3, 6, 1, 4, 1, 9, 2, 1, 8, 0 };

  oid *query[10];
  int querylens[10];

  int **response;

  /* Hideous argument parsing, 'cause nothing standard knows how to handle
   * long arguments.
   */
  {
    int arg;

    for (arg=1; arg<argc; arg++) {

      /* Check this arg */

      if (argv[arg][0] == '-') {
        if (argv[arg][1] != '-') {
	  
          /* Short args */
          if (argv[arg][1] == 'v')
            Version();

          else if (argv[arg][1] == 'c')
	    Config = argv[++arg];

          else
            Usage(argv[arg]);
        } else {

          /* Long args */
          if (!strcmp(&(argv[arg][2]), "version"))
            Version();

          else if (!strncmp(&(argv[arg][2]), "config=", 7))
	    Config = (argv[arg]+7);

          else
            Usage(argv[arg]);

        } /* End of long args */
      } else {
        goto EndOfDashArgs;
      } /* End of - args */

    } /* End of loop */

  EndOfDashArgs:
    /* ASSERT:  argv[arg] is the first non-parse argument */
    ;
  }

  init_mini_snmp_client(25);
  readconf(Config);

  core = initscr();
  title = newwin(3, 80, 0, 0);
  load = newwin(20, 80, 3, 0);

  refresh();
  cbreak();
  noecho();

  {
    char buf[80];
    sprintf(buf, "           Cisco Console - Version %s", ccon_Version());
    mvwprintw(title, 1, 0, buf);
    wrefresh(title);
  }

  sprintf(holdme, "device     load                in  hot   memory  ");
#ifdef A_REVERSE
  wattron(load, A_REVERSE);
#endif /* A_REVERSE */
  mvwprintw(load, 0, 0, "%s", highlight(holdme));
#ifdef A_REVERSE
  wattroff(load, A_REVERSE);
#endif /* A_REVERSE */


  for (incr=0; incr < num_devices; incr++)
    {
      mvwprintw(load, incr+1, 0, "%-10s --- [          ]",
		device[incr].hostname);
      old[incr] = -1;
    }

  while (1) {
    gettimeofday(&tv, 0);
    timer = ctime(&tv.tv_sec);
    timer[24] = 0;

    for (incr = 0; incr < num_devices; incr++) {

      /* load query options */
      query[0] = FiveSecond;
      querylens[0] = 11;

      response = (int **)snmp_mini_get(device[incr].ipaddr, 
				       device[incr].community,
				       1, query, querylens, NULL);

      if (response) {
	loader = *(response[0]);
	if (loader >= 95)
	  printf("\007");
	mvwprintw(load, incr+1, 11, "%2d%%", loader);
	loader = (int) loader / 10; 
	if (loader > 10)
	  loader = 10;
	if (old[incr] >= 0)
	  mvwprintw(load, incr+1, 16+old[incr], "-");
	old[incr] = loader;
	mvwprintw(load, incr+1, 16+loader, "*");
      }
      
      /* temperature query options */
      query[0] = IntakeTemp; querylens[0] = 14;
      query[1] = HotPntTemp; querylens[1] = 14;
	
      response = (int **)snmp_mini_get(device[incr].ipaddr,
				       device[incr].community,
				       2, query, querylens, NULL);
      if (response)
	mvwprintw(load, incr+1, 30, "%3d %3d",
		  (((*(response[0]))*9)/5)+32,
		  (((*(response[1]))*9)/5)+32);

      /* memory query options */
      query[0] = MemFree;
      querylens[0] = 11;

      response = (int **)snmp_mini_get(device[incr].ipaddr, 
				       device[incr].community,
				       1, query, querylens, NULL);

      if (response)
	mvwprintw(load, incr+1, 41, "%8d", *(response[0]));
      wrefresh(load);
    }

    /*  query[1] = ".1.3.6.1.4.1.9.2.1.57.0"; * one minute  */
    /*  query[2] = ".1.3.6.1.4.1.9.2.1.58.0"; * five minute */
      
    sleep(5);
  }
}
