#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <ctype.h>
#include <syslog.h>

#define STATUS	"/usr/cmon/cmon.status"
#define PSTATUS	"/usr/cmon/printer2.status"
#define CONFIG	"/usr/cmon/cluster.conf"
#define CONFIG2	"/usr/cmon/cluster.conf2"
#define CONFIG3	"/usr/cmon/cluster.conf3"
#define HEADER	"/usr/cmon/cview.header"
#define RIOS	"/usr/cmon/rios.status"

#define P_DIVIDER   "PRINTER     CLUSTER  STATUS   JOBS"
#define PH_DIVIDER   "CLUSTER   PHONE NUMBER"
#define DASHED "\
------------------------------------------------------------------------------"

#define FMT	"%-9.9s"
#define FMT2	"%3d / %-3d "
#define BLANK	"    -     "

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#define ACCESS 0
#define OPEN 1

#define PUBLIC "BARKER5 BARKER6 M1-142 M2-032 M2-225 M4-167 M11-113\
 M11-116 M14S-010 M37-312 M37-318 M37-332 M38-370 M56-129 M66-080 E51-075 ROTCH W20-575"


void main(), cluster(), printer(), phones(), config(), bye_bye();

int grand_free, grand_inuse;
int type_free[20], type_inuse[20];
char invalid[BUFSIZ];
int num_machtypes=0;		/* number will be read in from file. */


/*
 *  main();  Scan down standard input, looking up cluster info for each
 *     name read in.  If no clusters specified, display all.
 */
/* ARGSUSED */
void
main(argc, argv)
     int argc;
     char *argv[];
{
  char buf[BUFSIZ];
  char logbuf[BUFSIZ*2];
  int i;
  int ints_only = FALSE;
  int first_time = TRUE;
  struct sockaddr_in name;
  int namelen;

  /* find out where the request came from... */
  namelen = sizeof(name);
  if (getpeername(0, &name, &namelen))
    perror("getpeername");

  openlog ("cviewd", LOG_PID, LOG_LOCAL6);

  for (i=0; i < 20; i++)
    type_free[i] = type_inuse[i] = 0;
  grand_free=0;  grand_inuse=0;

  if (gets(buf) == NULL)
    {
      sprintf(logbuf, "%s default request", inet_ntoa(name.sin_addr));
      syslog (LOG_INFO, logbuf);
      strcpy(buf, PUBLIC);
#ifdef notdef
      cluster("", ints_only, version); /* shouldn't ever happen, but... */
#endif
    }

  else if (buf[0] == NULL || buf[0] == '\r')
    {
      sprintf(logbuf, "%s default request", inet_ntoa(name.sin_addr));
      syslog (LOG_INFO, logbuf);
      strcpy(buf, PUBLIC);
#ifdef notdef
      cluster("", ints_only, version);
#endif
    }

  else
    {
      sprintf(logbuf, "%s %s", inet_ntoa(name.sin_addr), buf);
      syslog (LOG_INFO, logbuf);
    }

  do_clusters(buf, &ints_only, &first_time);


  if (!ints_only &&
      (grand_free != 0) &&
      (grand_inuse != 0))
    {
      printf(FMT, "TOTALS");
      for (i=0; i < num_machtypes; i++)
	{
	  if (type_free[i] == 0  &&  type_inuse[i] == 0)
	    printf(BLANK);
	  else
	    printf(FMT2, type_free[i],
		   type_free[i]+type_inuse[i]);
	}
      printf(FMT2, grand_free, grand_free+grand_inuse);
      printf("\n");
    }

  /* If we didn't do anything, tell the user what he can do... */
  if (strlen(invalid))
    {
      int line_len;
      FILE *f;
      char buf[BUFSIZ];
      int free, inuse, i;
      char *ptr;

      if (strcasecmp(invalid, " help"))
	{
	  ptr = rindex(invalid, ' ');
	  printf("\nInvalid cluster %s:%s\n",
		 ptr == invalid ? "name" : "names",
		 invalid);
	}
      printf("\nUsage: cview [cluster] [cluster] [cluster...]\n");

      if ((f = fopen(STATUS, "r")) == (FILE *) NULL) /* is file readable? */
	exit(-1);

      line_len = 1;
      printf("Where \"cluster\" is one of:\n ");
      while (fscanf(f, "%s", buf) != EOF)
	{
	  line_len += strlen(buf) + 1;
	  if (line_len > 80)
	    {
	      printf("\n ");
	      line_len = strlen(buf) + 2;
	    }
	  printf("%s ",  buf);
	  for (i=0; i < num_machtypes; i++)
	    (void) fscanf(f, "%d %d", &free, &inuse);
	}
      (void) fclose(f);
      printf("\n or \"printers\" for printer status, or \"phones\" for phone numbers.\n");
    }

  exit(0);
}


do_clusters(buf, ints_only, first_time)
     char *buf;
     int *ints_only;
     int *first_time;
{
  char buf2[BUFSIZ];
  char *ptr;
  int n;
  static int version = 0;

  ptr = buf;
  while (ptr - buf < strlen(buf))
    {
      while (isspace(*ptr))
	ptr++;
      if (ptr[0] != NULL)
	{
	  sscanf(ptr, "%s", buf2);
	  n = strlen(buf2) - 1;
	  if (buf2[n] == '\r')
	    buf2[n] = '\0';

	  if (!strcasecmp(buf2, "configplease"))
	    {
	      config(1);
	      exit(0);
	    }

	  else if (!strcasecmp(buf2, "configplease2"))
	    {
	      config(2);
	      exit(0);
	    }

	  else if (!strcasecmp(buf2, "configplease3"))
	    {
	      config(3);
	      exit(0);
	    }

	  else if (!strcasecmp(buf2, "public"))
	    do_clusters(PUBLIC, ints_only, first_time);

	  else if (!strcasecmp(buf2, "printers"))
	    {
	      printer(*ints_only);
	      exit(0);
	    }
	      
	  else if (!strcasecmp(buf2, "phones"))
	    {
	      phones();
	      exit(0);
	    }
	      
	  else if (!strcasecmp(buf2, "intsonlyplease"))
	    *ints_only = TRUE;

	  else if (!strcasecmp(buf2, "intsonlyplease2"))
	    {
	      *ints_only = TRUE;
	      version = 2;
	    }

	  else if (!strcasecmp(buf2, "intsonlyplease3"))
	    {
	      *ints_only = TRUE;
	      version = 3;
	    }

	  else
	    {
	      cluster(buf2, *ints_only, version);
	      *first_time = FALSE;
	    }

	  ptr += n + 1;
	}
    }

  if (*ints_only && *first_time)
    {
      cluster("", *ints_only, version);
      *first_time = FALSE;
    }
}



/*
 *  cluster(name):   display cluster info for named cluster.  if name is
 *      "", display info for all clusters.
 */
void
cluster(name, ints_only, version)
     char *name;
     int ints_only;
     int version;
{
  FILE *f, *rios;
  char buf[BUFSIZ];
  char buf2[BUFSIZ];
  int free, inuse, i;
  int clus_free, clus_inuse;
  int found = FALSE;
  struct stat statbuf;
  char *date;
  static int first_time = TRUE;
  char *name_ptr = name;

/* Cluster info. */

  if (!strcasecmp("m14-010", name_ptr))
    name_ptr = "m14s-010";	/* for backwards-compatibility */

  if (!access(CONFIG2, R_OK))	/* is file accessible? */
    if ((f = fopen(CONFIG2, "r")) != (FILE *) NULL) /* is file readable? */
      {
	(void) fscanf(f, "%d", &num_machtypes);
	(void) fclose(f);
      }

  if (access(STATUS, R_OK))	/* is file accessible? */
    bye_bye(-1, ACCESS);

  if ((f = fopen(STATUS, "r")) == (FILE *) NULL) /* is file readable? */
    bye_bye(-1, OPEN);
  rios = fopen(RIOS, "r");

  stat(STATUS, &statbuf);	/* find out when it was updated. */
  date = (char *) ctime(&(statbuf.st_ctime));
  date[strlen(date) - 1] = '\0';

  while ((fscanf(f, "%s", buf) != EOF))
    {
      if (!strcasecmp(buf, name_ptr)
	  || (!strcmp(name_ptr, ""))
	  || (!strcmp(name_ptr, "all")))
	{
	  /*
	   * print headers first time around.
	   */
	  if (first_time && !ints_only)
	    {
	      FILE *header;

	      first_time = FALSE;
	      if (!strcmp(name_ptr, "") || !strcmp(name_ptr, "all"))
		printf("  --  The Status of ALL Athena clusters");
	      else
		printf("             --  Cluster status");

	      printf(" as of %s:  --\n", date);
	      if ((header = fopen(HEADER, "r")) != (FILE *) NULL)
		{
		  char buf[100];

		  while (fgets(buf, 100, header) != NULL)
		    printf(buf);
		}		  
	    }

	  found = TRUE;

	  if (ints_only && version >= 2)
	    printf("cluster %-9.9s", buf);
	  else
	    printf(FMT, buf);

	  clus_free = clus_inuse = 0;
	  for (i=0; i < num_machtypes; i++)
	    {
	      (void) fscanf(f, "%d %d", &free, &inuse);

	      if ((i == num_machtypes - 1) && (rios != (FILE *) NULL))
		{
		  (void) fscanf(rios, "%d %d ", &free, &inuse);
		}

	      clus_free += free;
	      clus_inuse += inuse;
	      type_free[i] += free;
	      type_inuse[i] += inuse;
	      if (ints_only)
		{
		  if ((version < 3  &&  i < 5)  ||  (version >=3))
		    printf("%3d %3d   ", free, inuse);
		}
	      else
		if (free == 0  &&  inuse == 0)
		  printf(BLANK);
		else
		  printf(FMT2, free, free+inuse);
	    }
	  grand_free += clus_free;
	  grand_inuse += clus_inuse;
	  if (ints_only)
	    (void) fscanf(f, "%d %d", &free, &inuse);
	  else
	    printf(FMT2, clus_free, clus_free+clus_inuse);
	  printf("\n");
	}

      else
	{
	  (void) fgets(buf2, BUFSIZ, f); /* throw away rest of line */
	  
	  if (rios != (FILE *) NULL)
	    (void) fgets(buf2, BUFSIZ, rios); /* throw away a line */
	}

    }
  (void) fclose(f);

  if (rios != (FILE *) NULL)
    (void) fclose(rios);

/* Printer info. */

  if (ints_only && version >= 2)
    {
      found = TRUE;
      printer(TRUE);
    }

/* If we didn't find the named cluster, add to the list of invalids... */

  if (!found)
    {
      strcat(invalid, " ");
      strcat(invalid, name_ptr);
    }
}



/*
 *  printer():   display all printer info.
 */
void
printer(ints_only)
     int ints_only;
{
  FILE *f;
  char buf[BUFSIZ];
  struct stat statbuf;
  char *date;
  static int first_time = TRUE;
  int times = 0;

/* Printer info. */

  if (access(PSTATUS, R_OK))	/* is file accessible? */
    bye_bye(-1, ACCESS);

  if ((f = fopen(PSTATUS, "r")) == (FILE *) NULL) /* is file readable? */
    bye_bye(-1, OPEN);

  stat(PSTATUS, &statbuf);	/* find out when it was updated. */
  date = (char *) ctime(&(statbuf.st_ctime));
  date[strlen(date) - 1] = '\0';

  while (fscanf(f, "%s", buf) != EOF)
    {
      if (first_time && !ints_only)	/* print hdrs first time 'round. */
	{
	  first_time = FALSE;
	  printf("            --  Printer status as of %s:  --\n", date);
	  printf("%s          %s\n", P_DIVIDER, P_DIVIDER);
	  printf("%.*s\n", 2 * strlen(P_DIVIDER) + 10, DASHED);
	}

      if (ints_only)
	printf("printer ");

      printf("%-12.12s", buf);

      (void) fscanf(f, "%s", buf); /* cluster name... */
      if (!ints_only)
	printf("%7.7s", buf);

      (void) fscanf(f, "%s", buf); /* status */
      printf("   %-9.9s", buf);

      (void) fscanf(f, "%s", buf); /* number of jobs */
      printf("%2.2s", buf);

      if (ints_only || times % 2)
	printf("\n");
      else
	printf("           ");

      times++;
    }

  if (!ints_only  &&  times % 2)
    printf("\n");

  (void) fclose(f);
}



/*
 *  phones():   display phone numbers for clusters.
 */
void
phones()
{
  FILE *f;
  char buf[BUFSIZ];
  char *str;
  static int first_time = TRUE;

  if (access(CONFIG3, R_OK))		/* is file accessible? */
    bye_bye(-1, ACCESS);

  if ((f = fopen(CONFIG3, "r")) == (FILE *) NULL) /* is file readable? */
    bye_bye(-1, OPEN);

  str = fgets(buf, BUFSIZ, f);		/* throw away first line */
  while (fgets(buf, BUFSIZ, f) != NULL) /* throw away first of group */
    {

      if (first_time)			/* print hdrs first time 'round. */
	{
	  first_time = FALSE;
	  printf("\n%s\n", PH_DIVIDER);
	  printf("%.*s\n", strlen(PH_DIVIDER), DASHED);
	}

      fscanf(f, "%s", buf);
      while (strcmp(buf, "XXXXX"))
	{
	  printf(FMT, buf);
	  fscanf(f, "%s", buf);
	  printf(" %s\n", buf);
	  fscanf(f, "%s", buf);
	}
      str = fgets(buf, BUFSIZ, f);	/* throw away third of group (nl) */
      str = fgets(buf, BUFSIZ, f);	/* throw away fourth of group */
      str = fgets(buf, BUFSIZ, f);	/* throw away fifth of group */
    }

  (void) fclose(f);
}



/*
 *  config():   return cluster configuration data.
 */
void
config(version)
     int version;
{
  FILE *f;
  char buf[BUFSIZ];
  char ver[10];

  strcpy(buf, CONFIG);
  sprintf(ver, "%d", version);
  strcat(buf, ver);

  if (access(buf, R_OK))	/* is file accessible? */
    bye_bye(-1, ACCESS);

  if ((f = fopen(buf, "r")) == (FILE *) NULL) /* is file readable? */
    bye_bye(-1, OPEN);

  while (fgets(buf, BUFSIZ, f) != NULL)
    printf("%s", buf);

  fclose(f);
}
    


/*
 *  bye_bye():  exit with an error message.
 */
void
bye_bye(num, reason)
     int num, reason;
{
  switch (reason)
    {
    case ACCESS:
      printf("Unable to access file.  Please try again.\n");
      break;

    case OPEN:
      printf("Unable to open file for reading.  Please try again.\n");
      break;

    default:
      printf("An error occurred.  Please try again.\n");
      break;
    }

  printf("If the problem persists, please contact hardware hotline\n");
  printf("or send mail to \"hotline\".\n");
  exit(num);
}
