/*
 * This file is part of an snmp query application.
 * This file contains query commands.
 *
 * Copyright 1990 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 *
 * Tom Coppeto
 * MIT Network Services
 * 15 April 1990
 *
 *    $Source: /afs/.net.mit.edu/tools/src/simon/RCS/query.c,v $
 *    $Author: tom $
 *    $Locker: tom $
 *    $Log:	query.c,v $
 * Revision 1.8  91/04/22  10:14:22  tom
 * added hardware addr hack
 * 
 * Revision 1.7  91/02/21  13:54:24  tom
 * ability to make multiple queries inside one packet, and deal
 * with errors
 * 
 * Revision 1.6  90/07/27  15:20:16  tom
 * was using symbolic variable string instead or numeric variable string
 * when one was expected in make_queries()
 * 
 * Revision 1.5  90/07/26  01:01:01  tom
 * tsk tsk .. not checking arguments
 * 
 * Revision 1.4  90/07/25  10:31:17  tom
 * query commands will prompt for something if it is not specified after the
 * flag switch
 * print_replies() modified to deal with numeric display of variable
 * what_now? skipped for certain arguments
 * 
 * Revision 1.3  90/07/21  00:54:40  tom
 * shortened pauses between queries
 * 
 * Revision 1.2  90/07/20  21:36:47  tom
 * static/extern compiler warning fixed
 * 
 * Revision 1.1  90/07/20  21:17:42  tom
 * Initial revision
 * 
 *
 */

#ifndef lint
static char *rcsid = "$Header: /afs/.net.mit.edu/tools/src/simon/RCS/query.c,v 1.8 91/04/22 10:14:22 tom Exp Locker: tom $";
#endif
		
#include <simon.h>
#include <mit-copyright.h>

#define PAUSE 100000L
	
static time_t  delta;
extern int     s;

static void command_loop();
static void really_make_queries();
static void get_replies();
static void print_replies();
static void list_outstanding_requests();
static void do_mquery_hack();
static void cleanup();
static void cleanup_agent_requests();
static void cleanup_agent_replies();
static int  query_agents();
static int  query_agent();
static int  register_reply();
static int  assign_request();

static int  cowabunga = 0;
static char *community;
static char communitybuf[NAME_SIZE];

void 
cmd_query_variable(argc, argv)
     int argc; 
     char **argv;
{
  VARIABLE  v;
  CLASS     class;
  CLUSTER   cluster;
  CLUSTER   *c      = (CLUSTER *) NULL;
  char      *cname  = (char *) NULL;
  char      *aname  = (char *) NULL;
  int       i = 0, j;
  int       cluster_spec = 0;
  int       agent_spec = 0;
  int       comm_spec = 0;
  int       loop = TRUE;

  pname = *argv;
  bzero(&cluster, sizeof(cluster));
  bzero(&class, sizeof(class));
  bzero(&v, sizeof(v));
  community = (char *) NULL;

  while (*++argv != (char *) NULL)
    {
      if(**argv != '-')
        {
	  argptr[i++] = *argv;
	  continue;
        }
      
      if(string_equiv(*argv, "-cluster", 2))
        {
	  if(!cluster_spec)
	    {
	      cluster_spec = TRUE;
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        cname = *++argv;
	      continue;
	    }
	  fprintf(stderr, "Too many clusters specified.\n");
        }

      if(string_equiv(*argv, "-agent", 2))
	{
	  if(!agent_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        aname = *++argv;
	      agent_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many agents specified.\n");
	}

      if(string_equiv(*argv, "-community", 4))
	{
	  if(!comm_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        community = *++argv;
	      comm_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many communities specified.\n");
	}

      if(string_equiv(*argv, "-cowabunga", 4))
	{
	  cowabunga = TRUE;
	  continue;
	}

      if(string_equiv(*argv, "-noprompt", 2))
	{
	  loop = 0;
	  continue;
	}

      if(!string_equiv(*argv, "-help", 2))
	printf("%s: unknown switch \"%s\".\n", pname, *argv);
      
      printf("usage: %s [<variable>] [-cluster <cluster>] [-agent <agent>]\n",
	     pname);
      printf("\t[-community <community name>] [-noprompt]\n");
      return;
    }

  if((aname != (char *) NULL) && (cname != (char *) NULL))
    {
      printf("Cannot specify both an agent and a group of agents.\n");
      return;
    }

  /*
   * get cluster or agent
   */

  if((cluster_spec == TRUE) || 
     ((cname == (char *) NULL) && (stuff.cluster == (CLUSTER *) NULL) &&
      (aname == (char *) NULL)))
    c = prompt_for_cluster("cluster name: ", cname);
  else
    c = stuff.cluster;

  if((agent_spec == TRUE) || (c == (CLUSTER *) NULL))
    {
      if(make_agent(&cluster, aname) != SUCCESS)
	{
	  printf("unable to get agent's name.\n");
	  return;
	}
      else
	c = &cluster;
    }

  if(!c || !c->agents)
    {
      printf("No agents to query.\n");
      return;
    }

  /*
   * get variable or class 
   */
  
  
  for(j = 0; j < i; j++)
    {
      if((v.variable = find_abbrev_variable(argptr[j])) == (char *) NULL)
	v.variable = argptr[j];
      if(make_variable(&class, &v) != SUCCESS)
	{
	  printf("unable to get variable.\n");
	  free_cluster(&cluster);
	  return;
	}
    }

  if(class.vars == (VARIABLE *) NULL)
    {
      printf("No variables to query.\n");
      free_cluster(&cluster);
      return;
    }

  if((comm_spec == TRUE) && (community == (char *) NULL))
    {
      if(get_prompted_input("community: ", communitybuf, sizeof(communitybuf))
	 != SUCCESS)
	return;
      community = communitybuf;
    }
  
  make_queries(class.vars, c->agents, loop);
  free_class(&class);
  free_cluster(&cluster);
  return;
}



void 
cmd_query_class(argc, argv)
     int  argc; 
     char **argv;
{
  CLASS     *cl;
  CLUSTER   cluster;
  CLUSTER   *c      = (CLUSTER *) NULL;
  char      *cname  = (char *) NULL;
  char      *clname = (char *) NULL;
  char      *aname  = (char *) NULL;
  int       loop = TRUE;
  int       cluster_spec = 0;
  int       agent_spec = 0;
  int       comm_spec = 0;

  pname = *argv;
  bzero(&cluster, sizeof(cluster));
  community = (char *) NULL;

  while (*++argv != (char *) NULL)
    {
      if(**argv != '-')
        {
	  if(clname == (char *) NULL)
	    {
	      clname =  *argv;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many classes specified.\n");
	}
	  
      if(string_equiv(*argv, "-cluster", 2))
        {
	  if(!cluster_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        cname = *++argv;
	      cluster_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many clusters specified.\n");
	}

      if(string_equiv(*argv, "-agent", 2))
	{
	  if(!agent_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        aname = *++argv;
	      agent_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many agents specified.\n");
	}
       
      if(string_equiv(*argv, "-community", 4))
	{
	  if(!comm_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        community = *++argv;
	      comm_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many communities specified.\n");
	}

      if(string_equiv(*argv, "-noprompt", 2))
	{
	  loop = 0;
	  continue;
	}

      if(string_equiv(*argv, "-cowabunga", 4))
	{
	  cowabunga = TRUE;
	  continue;
	}
	
      if(!string_equiv(*argv, "-help", 2))
	printf("%s: unknown switch \"%s\".\n", pname, *argv);
      
      printf("usage: %s <class name> [-cluster <cluster>] [-agent <agent>]\n",
	     pname);
      printf("\t[-community <community name>] [-noprompt]\n");
      return;
    }

  if(agent_spec && cluster_spec)
    {
      printf("Cannot specify both an agent and a group of agents.\n");
      return;
    }
  
  /*
   * get cluster or agent
   */

  if((cluster_spec) || 
     ((cname == (char *) NULL) && (stuff.cluster == (CLUSTER *) NULL) &&
      !agent_spec))
    c = prompt_for_cluster("cluster name: ", cname);
  else
    c = stuff.cluster;

  if(agent_spec || (c == (CLUSTER *) NULL))
    {
      if(make_agent(&cluster, aname) != SUCCESS)
	{
	  printf("unable to get agent's name.\n");
	  return;
	}
      else
	c = &cluster;
    }

   if(!c || !c->agents)
    {
      printf("No agents to query.\n");
      return;
    }

  /*
   * get variable or class 
   */
  
  
  if((clname == (char *) NULL) && (stuff.class != (CLASS *) NULL))
    cl = stuff.class;
  else
    if((cl = prompt_for_class("class name: ", clname)) == (CLASS *) NULL)
      return;
  
  if(cl->vars == (VARIABLE *) NULL)
    {
      printf("No variables to query.\n");
      free_cluster(&cluster);
      return;
    }

  if((comm_spec == TRUE) && (community == (char *) NULL))
    {
      if(get_prompted_input("community: ", communitybuf, sizeof(communitybuf))
	 != SUCCESS)
	return;
      community = communitybuf;
    }

  make_queries(cl->vars, c->agents, loop);
  free_cluster(&cluster);
  return;
}




void
cmd_query_agent(argc, argv)
     int argc; 
     char **argv;
{
  CLASS     *cl;
  CLASS     class;
  CLUSTER   cluster;
  CLUSTER   *c      = (CLUSTER *) NULL;
  VARIABLE  v;
  char      *cname  = (char *) NULL;
  char      *clname = (char *) NULL;
  char      *var = (char *) NULL;
  int       i=0, j;
  int       loop = TRUE;
  int       cluster_spec = 0;
  int       class_spec = 0;
  int       comm_spec = 0;
  int       var_spec = 0;

  pname = *argv;
  bzero(&cluster, sizeof(cluster));
  community = (char *) NULL;

  while (*++argv != (char *) NULL)
    {
      if(**argv != '-')
        {
	  argptr[i++] = *argv;
	  continue;
	}
	  
      if(string_equiv(*argv, "-cluster", 3))
        {
	  if(!cluster_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        cname = *++argv;
	      cluster_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many clusters specified.\n");
        }

      if(string_equiv(*argv, "-class", 3))
	{
	  if(!class_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        clname =  *++argv;
	      class_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many classes specified.\n");
	}

      if(string_equiv(*argv, "-community", 4))
	{
	  if(!comm_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        community = *++argv;
	      comm_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many communities specified.\n");
	}

      if(string_equiv(*argv, "-variable", 2))
	{
	  if(!var_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        var = *++argv;
	      var_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many variables specified.\n");
	}

      if(string_equiv(*argv, "-cowabunga", 4))
	{
	  cowabunga = TRUE;
	  continue;
	}
      
      if(string_equiv(*argv, "-noprompt", 2))
	{
	  loop = 0;
	  continue;
	}

      if(!string_equiv(*argv, "-help", 2))
	printf("%s: unknown switch \"%s\".\n", pname, *argv);
      
      printf("usage: %s [<hostnames>] [-cluster <cluster>] [-class <class>]\n",
	     pname);
      printf("\t[-community <community name>] [-variable <variable>] [-noprompt]\n");
      return;
    }

  /*
   * get cluster or agent
   */

  if((i != 0) && cluster_spec)
    {
      printf("Cannot specify both an agent and a group of agents.\n");
      return;
    }

  if(cluster_spec || 
     ((cname == (char *) NULL) && (stuff.cluster == (CLUSTER *) NULL) &&
      (i == 0)))
    c = prompt_for_cluster("cluster name: ", cname);
  else
    c = stuff.cluster;

  if((i == 0) && (c == (CLUSTER *) NULL))
    {
      if(make_agent(&cluster, NULL) != SUCCESS)
	{
	  printf("unable to get agent's name.\n");
	  return;
	}
      else
	c = &cluster;
    }

  if(i != 0)
    {
      for(j = 0; j < i; j++)
	make_agent(&cluster, argptr[j]);
      c = &cluster;
    }

   if(!c  || !c->agents)
    {
      printf("No agents to query.\n");
      return;
    }

  /*
   * get variable or class 
   */
  
  
  if((clname == (char *) NULL) && (stuff.class != (CLASS *) NULL) && 
     !class_spec)
    cl = stuff.class;
  else
    cl = prompt_for_class("class name: ", clname);

  if(var_spec == TRUE)
    {
      bzero(&class, sizeof(class));
      bzero(&v, sizeof(v));
      if((v.variable = find_abbrev_variable(var)) == (char *) NULL)
	v.variable = var;
      if(make_variable(&class, &v) != SUCCESS)
	{
	  printf("unable to get variable.\n");
	  free_cluster(&cluster);
	  return;
	}
      else
	cl = &class;
    }

  if((cl == (CLASS *) NULL) || (cl->vars == (VARIABLE *) NULL))
    {
      printf("No variables to query.\n");
      free_cluster(&cluster);
      return;
    }

  if((comm_spec == TRUE) && (community == (char *) NULL))
    {
      if(get_prompted_input("community: ", communitybuf, sizeof(communitybuf))
	 != SUCCESS)
	{
	  free_cluster(&cluster);
	  return;
	}
      community = communitybuf;
    }

  make_queries(cl->vars, c->agents, loop);
  free_cluster(&cluster);
  return;
}



cmd_query_cluster(argc, argv)
     int argc;
     char **argv;
{
  CLASS     *cl;
  CLUSTER   cluster;
  CLUSTER   *c      = (CLUSTER *) NULL;
  char      *cname  = (char *) NULL;
  char      *clname = (char *) NULL;
  char      *aname  = (char *) NULL;
  int       loop = TRUE;
  int       agent_spec = 0;
  int       cluster_spec = 0;
  int       class_spec = 0;
  int       comm_spec = 0;

  pname = *argv;
  bzero(&cluster, sizeof(cluster));
  community = (char *) NULL;

  while (*++argv != (char *) NULL)
    {
      if(**argv != '-')
        {
	  if(cname == (char *) NULL)
	    {
	      cname = *argv;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many clusters specified.\n");
	}
	  
      if(string_equiv(*argv, "-agent", 2))
	{
	  if(!agent_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        aname = *++argv;
	      agent_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many agents specified.\n");
	}

      if(string_equiv(*argv, "-class", 3))
	{
	  if(!class_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        clname =  *++argv;
	      class_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many classes specified.\n");
	}

      if(string_equiv(*argv, "-community", 4))
	{
	  if(!comm_spec)
	    {
              if((argv[1] != (char *) NULL) && (*argv[1] != '-'))
	        community = *++argv;
	      comm_spec = TRUE;
	      continue;
	    }
	  else
	    fprintf(stderr, "Too many communities specified.\n");
	}

      if(string_equiv(*argv, "-cowabunga", 4))
	{
	  cowabunga = TRUE;
	  continue;
	}

      if(string_equiv(*argv, "-noprompt", 2))
	{
	  loop = 0;
	  continue;
	}

      if(!string_equiv(*argv, "-help", 2))
	printf("%s: unknown switch \"%s\".\n", pname, *argv);
      
      printf("usage: %s <cluster name> [-agent <agent>] [-class <class>]\n",
	     pname);
      printf("\t[-community <community name>] [-noprompt]\n");
      return;
    }

  if((aname != (char *) NULL) && (cname != (char *) NULL))
    {
      printf("Cannot specify both an agent and a group of agents.\n");
      return;
    }
  
  /*
   * get cluster or agent
   */

  if((cname != (char *) NULL) || 
     ((cname == (char *) NULL) && (stuff.cluster == (CLUSTER *) NULL) &&
      (aname == (char *) NULL)))
    c = prompt_for_cluster("cluster name: ", cname);
  else
    c = stuff.cluster;

  if(agent_spec || (c == (CLUSTER *) NULL))
    {
      if(make_agent(&cluster, aname) != SUCCESS)
	{
	  printf("unable to get agent's name.\n");
	  return;
	}
      else
	c = &cluster;
    }

   if(!c || !c->agents)
    {
      printf("No agents to query.\n");
      return;
    }

  
  /*
   * get variable or class 
   */
  
  
  if((clname == (char *) NULL) && (stuff.class != (CLASS *) NULL) &&
     !class_spec)
    cl = stuff.class;
  else
    cl = prompt_for_class("class name: ", clname);
  
  if((cl == (CLASS *) NULL) || (cl->vars == (VARIABLE *) NULL))
    {
      printf("No variables to query.\n");
      free_cluster(&cluster);
      return;
    }

  if((comm_spec == TRUE) && (community == (char *) NULL))
    {
      if(get_prompted_input("community: ", communitybuf, sizeof(communitybuf))
	  != SUCCESS)
	return;
      community = communitybuf;
    }

  make_queries(cl->vars, c->agents, loop);
  free_cluster(&cluster);
  return;
}



  
int
make_queries(variables, agents, loop)
     VARIABLE  *variables;
     AGENT     *agents;
     int       loop;
{
  VARIABLE   *vptr;
  objident   name;
  strng      vname;
  int        rc;

  if(!variables || !agents)
    return(ERROR);

  vptr = variables;
  while(vptr)
    {
      bzero(&name, sizeof(name));
      if(vptr->nvariable)
	{
	  vname.str = vptr->nvariable;
	  vname.len = strlen(vname.str);
	}
      else
	if(vptr->variable != (char *) NULL)
	  {
	    vname.str = vptr->variable;
	    vname.len = strlen(vname.str);
	  }
	else
	  {
	    fprintf(stderr, "make_queries: no variable name!\n");
	    vptr = vptr->next;
	    continue;
	  }

      if(vptr->nvariable)
	numtonum(&vname, &name);
      else
	{
	  if((rc = symtonum(&vname, &name)))
	    {
	      fprintf(stderr, "Unable to convert (error = %d) variable: %s\n", 
		      rc, vname.str);
	      while(TRUE)
		{
		  get_prompted_input("continue? ", cmdbuf, sizeof(cmdbuf));
		  if(*cmdbuf == '?')
		    {
		      printf("Would you like to continue with remaining queries?");
		      printf(" (yes or no)\n");
		      continue;
		    }
		  
		  if(string_equiv(cmdbuf, "yes", 1))
		    break;
		  
		  if(string_equiv(cmdbuf, "no", 1))
		    {
		      return(ERROR);
		    }
		  vptr = vptr->next;
		  continue;
		}
	    }
	}
      assign_request(agents, vptr, &name);
      vptr = vptr->next;
    }  

  command_loop(agents, loop);
  cowabunga = 0;
  return(SUCCESS);
}



 

static void
command_loop(agents, loop)
     AGENT *agents;
     int loop;
{
  AGENT *a;
  char buf[BUF_SIZE];

  really_make_queries(agents);
  print_replies(agents);

  if(!loop)
    return;

  while(TRUE)
    {
      get_prompted_input("What now? ", buf, sizeof(buf));
      if(string_equiv(buf, "help", 1) || string_equiv(buf, "?", 1))
	{
	  printf("\thelp\tget this listing.\n");
	  printf("\tcdm\tchange display mode.\n");
	  printf("\tcont\tcontinue querying.\n");
	  printf("\tlist\tlist outstanding requests.\n");
	  printf("\tprint\tprint replies.\n");
	  printf("\tredo\tredo queries.\n");
	  printf("\tquit\treturn to command level\n");
	  continue;
	}
      if(*buf == '\0')
        {
          cleanup(agents);
  	  return;
        }

      if(string_equiv(buf, "print", 1))
	{
	  print_replies(agents);
	  continue;
	}
      if(string_equiv(buf, "list", 1))
	{
	  list_outstanding_requests(agents);
	  continue;
	}
      if(string_equiv(buf, "redo", 1))
	{
	  cleanup_agent_replies(agents);
	  really_make_queries(agents);
	  continue;
	}
      if(string_equiv(buf, "continue", 2))
	{
	  for(a = agents; a != (AGENT *) NULL; a = a->next)
	    if(a->status == PUNT)
	      a->status = SEND;
	  really_make_queries(agents);
	  continue;
	}
      if(string_equiv(buf, "cdm", 2))
	{
	  cmd_change_dspmode(0, 0);
	  continue;
	}
      if(string_equiv(buf, "quit", 1))
	{
	  cleanup(agents);
	  return;
	}
      printf("unknown command \"%s\". Try \"?\" for options.\n", buf);
    }
}




static void 
really_make_queries(agents)
     AGENT *agents;
{
  AGENT  *a;
  int    i = 0;
  int    notdone;
  int    retries;
  time_t t;

  if(!agents)
    return;

  printf("sending");
  notdone = 0;
  a = agents;
  while(a)
    {
#ifdef DEBUG
      printf("status of %s is %d\n", a->name, a->status);
#endif /* DEBUG */
      if(a->status == SEND)
	notdone = TRUE;	      
      a = a->next;
    }

  if(!notdone)
    {
      printf("no queries ready to send.\n");
      return;
    }

  retries = 0;
  while(TRUE)
    {
      t = time(0);
      if(query_agents(agents) != SUCCESS)
	return;

      while(TRUE)
	{
	  get_replies(agents);	
	  
	  /*
	   * zip thru and see if we are done with this round of queries
	   */

	  notdone = 0;
	  a = agents;
	  while(a)
	    {
	      if((a->status != REPLIED) && (a->status != PUNT))
		notdone = TRUE;	      
	      a = a->next;
	    }


	  /*
	   * if we are done with round, go to next round unless we are in
	   * get-next mode, then getnext unless we are done altogether,
	   * then return;
	   */

	  if(!notdone)
	    {
	      notdone = 0;
	      a = agents;
	      while(a)
		{
		  if(a->status == REPLIED)
		    {
		      if(a->cur_req == (REQUEST *) NULL)
			{
			  a = a->next;
			  continue;
			}
		      if(a->cur_req->vars[0]->mquery)
			do_mquery_hack(a);
		      else
			a->cur_req = a->cur_req->next;
		      if(a->cur_req)
			{
			  notdone = TRUE;
			  a->status = SEND;                           
			}
		    }
		  a = a->next;
		}

	      if(!notdone)
		{
		  printf(" query session complete.\n\n");
		  return;
		}

              if(!cowabunga)
                 timer(0, PAUSE);
	      retries = 0;
	      break;
	    }


	  /*
	   * check for timeouts
	   */

	  if((++i % 10) == 0)
	    if((time(0) - t) > (stuff.timeout + delta))
	      {
		printf("timed out on outsnading replies");
		if(retries < stuff.retry) 
 		  {
		    ++retries;
		    printf(", retrying...\n");
		    a = agents;
		    while(a)
		      {
			if(a->status != REPLIED)
			  a->status = SEND;
			a = a->next;
		      }
		    break;
		  }
		else
		  {		    
		    printf(", giving up.\n");
		    a = agents;
		    while(a)
		      {
			if(a->status != REPLIED)
			  a->status = PUNT;
			a = a->next;
		      }
		    retries = 0;
		    continue;
		  }
	      }
	}
    }
}


static int
query_agents(agents)
     AGENT *agents;
{
  AGENT    *aptr;
  time_t   t;

  if(!agents)
    return(ERROR);

  aptr = agents;
  t    = time(0);

  while(aptr)
    {
      if(!aptr->requests)
	{
	  aptr = aptr->next;
	  continue;
	}
      if(!aptr->cur_req)
	{
	  aptr = aptr->next;
	  continue;
	}
      if(aptr->status != SEND)
	{
	  aptr = aptr->next;
	  continue;
	}
      query_agent(aptr);
      get_replies(agents);
    }
  delta = time(0) - t;
  return(SUCCESS);
}


static int
query_agent(agent)
     AGENT *agent;
{
  getreq   *msg;
  static   int counter = 0;
  int      rc;
  int      req;

  if(!agent)
    return(ERROR);

  msg = &(agent->cur_req->msg);
  if(agent->cur_req->vars[0]->mquery)
    req = NXT;
  else
    req = REQ;
  agent->cur_req->reqid = msg->reqid = ++counter;
  agent->status = SENT;
  msg->errindex   = 0;
  msg->errstat    = 0;

#ifdef DEBUG
      printf("sending query to %s\n", aptr->name);
#endif DEBUG

  if((rc = snmpsend(req, msg->reqid, &(agent->in), "snmp", (char *) msg,
		    community ? community : stuff.session_id, 
		    community ? strlen(community) : 
		    strlen(stuff.session_id), 
		    (long) stuff.timeout)) < 0)
    printf("error = %d\n", rc);
  putchar('.');
  fflush(stdout);
  if(!cowabunga)
    timer(0, PAUSE);
  return(SUCCESS);
}





static void
get_replies(agents)
     AGENT *agents;
{
  struct in_addr from;
  getreq reply;
  int    reqid;
  int    sidlen;
  char   *s_id = (char *) NULL;
  int    type;

  while(fd_ready(s)) 
    {
#ifdef DEBUG
      printf("fd ready \n");
#endif DEBUG

      bzero(&reply, sizeof(reply));
      reqid = REQ_ANY;
      if((type = snmprecv(&from, (char *) NULL, &reqid, s_id,
			  &sidlen, (char *) &reply, sizeof(getreq))) < 0)
	{
	  printf("error = %d\n", type);
	  continue;
	}
  
      if(type != RSP)
	continue;
      
      register_reply(agents, &reply);
    }
  return;
}




static void
print_replies(agents)
     AGENT *agents;
{
  VARIABLE *v = (VARIABLE *) NULL;
  AGENT    *a;
  varbind  *vb;
  char     buf[BUF_SIZE];
  char     save[BUF_SIZE];
  strng    vname;
  char     *label;
  char     *inst;
  char     *p;
  int      status;
  int      plen;
  int      mlen;
  int      len;
  int      i, j;

  if(!agents)
    return;
  
  bzero(&vname, sizeof(vname));

  if(stuff.dispmode & SYMBOLIC)
    plen = strlen(stuff.prefix);
  else 
    plen = 0;
  a = agents;
  
  /*
   * here we have a mess. if the display is not in unique mode, zip thru
   * and print the vars & replies. In unique mode we have to go thru once
   * and determine what the common prefix is, the go thru again and print
   * them. (unless we are printing a table)! Of course this all takes 
   * place here.
   */
  
  while(a)
    {
      /*
       * print header and prefix (in standard mode)
       */

      printf("[%s %s]\n", a->name, inet_ntoa(a->in));

      if((stuff.dispmode & STANDARD) && (stuff.dispmode & SYMBOLIC) && 
	 (stuff.prefix != (char *) NULL))
	printf("%s...\n", stuff.prefix);

      /*
       * initialize agent specific variables 
       */

      bzero(buf, sizeof(buf));
      *save = '~';
      mlen = 0;
      i = 0;
      while(i < a->nreplies)
	{
	  j = 0;
	  while(j < a->replies[i].varlist.len)
	    {
	      vb = &(a->replies[i].varlist.elem[j]);

	      /*
	       * get symbolic variable string 
	       */
	      
	      if(stuff.dispmode & SYMBOLIC)
		{
		  if((status = numtosym(&(vb->name), &vname)) < 0)
		    { 
		      error(status, stderr);
		      continue;
		    }
		}
	      else
		vname.str = numtostr(&(vb->name));

	      /*
	       * get the corresponding queried variable. not needed for unique 
	       * mode yet
	       */
	      
	      if(!(stuff.dispmode & UNIQUE) && (stuff.dispmode & SYMBOLIC))
		{
		  putchar (' ');
		  v = get_variable(vname.str);
		}
	      
	      /*
	       * label mode: print label and instance
	       */
	      
	      if(!(stuff.dispmode & SYMBOLIC))
		printf(" %-30s\t", vname.str);
	      else
		if((stuff.dispmode & LABEL) && v && v->label)
		  {
		    inst = get_instance(vname.str, v->itype);
		    printf(" %-15s (%s)\t", v->label, inst ? inst : "");
		  }
		else
		  {
		    /*
		     * using label variable as a marker for the end of symbolic
		     * variable. mark off the two.
		     */
		    
		    label = (char *) NULL;
		    if(v && (v->itype == STR) &&
		       (label = rindex(vname.str, '_')))
		      *label++ = '\0';
		    
		    /*
		     * standard: print known variable symbol minus prefix
		     */
		    
		    if(stuff.dispmode & STANDARD)
		      printf("%-50s", (vname.str+plen));
		    else
		      
		      /*
		       * truncated: print last part of known variable
		       */
		      
		      if(stuff.dispmode & TRUNCATED)
			printf("%-25s", truncate(vname.str));
		      else
			
			/*
			 * unique: determine common prefix
			 */
			
			if(stuff.dispmode & UNIQUE)
			  {
			    if(*save == '~')
			      {
				strcpy(save, vname.str);
				strcpy(buf, save);
			      }
			    else
			      {
				plen = strlen(vname.str);
				if(plen > mlen)
				  mlen = plen;
				p = common_prefix(save, vname.str, buf);
				buf[(p - save) + 1] = '\0';
				strcpy(save, vname.str);
			      }
			  }
			else
			  
			  /*
			   * just print the thing
			   */
			  
			  printf("%-50s", vname.str);
		    
		    
		    /*
		     * if not in unique mode, convert the instance to a string
		     * if specified in variable
		     */
		    
		    if(!(stuff.dispmode & (UNIQUE | SYMBOLIC)))
		      {
			if(label != (char *) NULL)
			  {
			    printf("_%s\t", numtostring(label));
			    *(label-1) = '_';
			  }
			else
			  putchar('\t');
		      }
		  }
	      
	      /*
	       * free the string and print the value if not in unique mode
	       */
	      
	      if(stuff.dispmode & SYMBOLIC)
		free(vname.str); 
	      
	      vname.str = (char *) NULL;      	  
	      if(!(stuff.dispmode & UNIQUE))
		{
		  if(stuff.dispmode & NEWLINE)
		    printf("\n\t");
		  if(v->label)
		    print_value(&(vb->val), stdout, 
				strcmp(v->label, "address") ? 0 : 1);
		  else
		    print_value(&(vb->val), stdout, 0);
		  putchar('\n');
		}
	      ++j;
	    }
	  ++i;
	}


      /*
       * now zip through again and print out unique variable endings
       */

      if((stuff.dispmode & UNIQUE) && (stuff.dispmode & SYMBOLIC))
	{
	  i = 0;
	  printf("%s...\n", buf);
          plen = strlen(buf);
	  while(i < a->nreplies)
	    {	
	      j = 0;
	      while(j < a->replies[i].varlist.len)
		{
		  vb = &(a->replies[i].varlist.elem[j]);
		  
		  if((status = numtosym(&(vb->name), &vname)) < 0)
		    { 
		      error(status, stderr);
		      continue;
		    }
		  v = get_variable(vname.str);
		  label = (char *) NULL;
		  if((v != (VARIABLE *) NULL) && (v->itype == STR) &&
		     ((label = rindex(vname.str, '_')) != (char *) NULL))
		    *label++ = '\0';
		  
		  printf(" %s", (vname.str + plen));
		  if(label != (char *) NULL)
		    {
		      p = numtostring(label);
		      printf("_%s", p);
		      *(label-1) = '_';
		    }
		  for(len = strlen(vname.str+plen); len<(mlen-plen) + 1; len++)
		    putchar(' ');
		  putchar('\t');
		  free(vname.str); 
		  vname.str = (char *) NULL;      	
		  if(stuff.dispmode & NEWLINE)
		    printf("\n\t");
		  print_value(&(vb->val), stdout, strcmp(v->label, "address") ? 0 : 1);
		  putchar('\n');
		  ++j;
		}
	      ++i;
	    }
	}
      
      putchar('\n');
      a = a->next;
    }
  return;
}





static void
list_outstanding_requests(agents)
     AGENT *agents;
{
  AGENT *aptr;
  int foo = 0;

  aptr = agents;
  while(aptr != (AGENT *) NULL)
    {
      if(aptr->status == PUNT)
	{
	  printf("%s: \n", aptr->name);
	  foo = 1;
	}
      aptr = aptr->next;;
    }
  if(!foo)
    printf("no outstanding requests.\n");

  return;
}





static int
register_reply(agents, reply)
     AGENT *agents;
     getreq *reply;
{
  REQUEST *r;
  AGENT   *a;

  if(!agents)
    return(ERROR);
  
  a = agents;
  while(a)
    {
      r = a->requests;
      while(r)
	{
	  if(reply->reqid == r->reqid)
	    {
	      if(reply->errindex && (reply->varlist.len > 1))
		{
		  if(reply->errindex < r->msg.varlist.len)
		    bcopy(&(r->msg.varlist.elem[reply->errindex]), 
			  &(r->msg.varlist.elem[reply->errindex-1]),
			  sizeof(objident) * 
			  (r->msg.varlist.len - reply->errindex));
		  r->msg.varlist.len--;
		  bzero(&(r->msg.varlist.elem[r->msg.varlist.len]),
			sizeof(objident));
		  reply->errstat = 0;
		  reply->errindex = 0;
		  a->status = SEND;
		  query_agents(a);
		  break;
		}
	      if(a->replies == (getreq *) NULL)
		a->replies = (getreq *) malloc(sizeof(getreq));
	      else
		a->replies = (getreq *) realloc(a->replies, sizeof(getreq) *
						 (a->nreplies + 1));
	      if(a->replies == (getreq *) NULL)
		{
		  perror("getting replies");
		  return(ERROR);
		}
	      
	      bcopy(reply, &(a->replies[a->nreplies]), sizeof(getreq));
	      a->nreplies++;
	      a->status = REPLIED;
	    }
	  r = r->next;
	}
      a = a->next;
    }
  return(SUCCESS);
}




/*
 * 
 */


static int
assign_request(agents, var, name)
     AGENT    *agents;
     VARIABLE *var;
     objident *name;
{
  REQUEST *r;
  REQUEST *s;
  AGENT   *a;

  a = agents;
  if(!a)
    return(ERROR);

  while(a)
    {
      if(!a->requests || (a->last_req->msg.varlist.len >= MAX_VAR) ||
	 (a->last_req && !var->mquery &&
	  a->last_req->vars[a->last_req->msg.varlist.len - 1]->mquery) || 
	 (a->last_req && var->mquery && 
	  !a->last_req->vars[a->last_req->msg.varlist.len - 1]->mquery))
	{
#ifdef DEBUG
	  printf("making new request\n");
#endif /* DEBUG */
	  if((r = (REQUEST *) malloc(sizeof(REQUEST))) == (REQUEST *) NULL)
	    {
	      perror("");
	      return(ERROR);
	    }
	  bzero(r, sizeof(REQUEST));
	  if(a->requests)
	    {
	      s = a->requests;
	      while(s->next != (REQUEST *) NULL)
		s = s->next;
	      s->next = r;
	    }
	  else
	    a->requests = r;
	  a->last_req = r;
	}
      else
	r = a->last_req;
      
      r->vars[r->msg.varlist.len] = var;
      bcopy(name, &(r->msg.varlist.elem[r->msg.varlist.len].name),
	    sizeof(objident));
      r->ncmp = r->msg.varlist.elem[r->msg.varlist.len].name.ncmp;
      r->msg.varlist.elem[r->msg.varlist.len].val.type = EMPTY;
      r->msg.varlist.len++;
      a->status  = SEND;
      a->cur_req = a->requests;
      a = a->next;
    }
  return(SUCCESS);
}






static void
do_mquery_hack(a)
     AGENT *a;
{
  int i;

  if((oidncmp(&(a->cur_req->msg.varlist.elem[0].name), 
	     &(a->replies[a->nreplies-1].varlist.elem[0].name), 
	      a->cur_req->ncmp) != 0) ||
     (a->replies[a->nreplies-1].errstat))
    {
#ifdef DEBUG
      printf("done with mquery.\n");
#endif DEBUG
      
      a->replies = (getreq *) realloc(a->replies, sizeof(getreq) *a->nreplies);
      a->cur_req = a->cur_req->next;
      a->nreplies--;
      return;
    }
      
  for(i = 0; i < a->cur_req->msg.varlist.len; i++)
    oidcpy(&(a->cur_req->msg.varlist.elem[i].name),
	   &(a->replies[a->nreplies-1].varlist.elem[i].name));
  return;
}
 




static void
cleanup(agents)
     AGENT *agents;
{
  cleanup_agent_requests(agents);
  cleanup_agent_replies(agents);
  return;
}





static void
cleanup_agent_requests(agents)
     AGENT *agents;
{
  REQUEST *r;
  REQUEST *s;
  AGENT  *a;
  
  a = agents;
  while(a != (AGENT *) NULL)
    {
      r = a->requests;
      while(r)
	{
	  s = r->next;
	  free(r);
	  r = s;
	}
      a->requests  = (REQUEST *) NULL;
      a->status    = 0;
      a = a->next;
    }
 return;
}




static void
cleanup_agent_replies(agents)
     AGENT *agents;
{
  AGENT *a;
  
  if(!agents)
    return;
  
  a = agents;
  while(a)
    {
      free(a->replies);
      a->nreplies  = 0;
      a->status    = SEND;
      a->replies   = (getreq *) NULL;
      a = a->next;
    }

 return;
}




