              <<< LASSIE::UCXAXP$DKA0:[NOTES$LIBRARY]UCX.NOTE;1 >>>
                      -< DEC TCP/IP Services for OpenVMS >-
================================================================================
Note 5355.0                       SNMP director                          1 reply
AUBER::VOUTERS "Philippe VOUTERS, Evry (France)"   1683 lines  19-MAR-1997 04:07
--------------------------------------------------------------------------------
    Hello UCX Community,
    
    Below is a SNMP director that interogates agents. It has fully been
    tested on OpenVMS V6.1 (VAX) and V7.1 (AXP). It fits with the data
    file SNMPINFO.DAT provided in next reply.
    Commands to rebuild SNMP.EXE :
    $ CC[/DECC] SNMP
    $ LINK SNMP
    $ RUN SNMP
    At program's prompt ("SNMP> "), enter "help". This lists the valid
    commands.
    
    This program should run on Digital Unix (partially tested).
    Have fun.
    Philippe Vouters (MCS France)
    
    
    
#ifdef __DECC
#pragma module snmpc "SNMPC V1.0-00"
#endif
/*
 * Copyright (c) 1997
 * by Digital Equipment Corporation, Maynard, Mass.
 *
 * This software is furnished under a license and may be used and copied
 * only in accordance with the terms of such license and with the inclusion
 * of the above copyright notice.  This software or any other copies thereof
 * may not be provided or otherwise made available to any other person.  No
 * title to and ownership of the software is hereby transferred.
 *
 * The information in this software is subject to change without notice and 
 * should not be construed as a commitment by Digital Equipment Corporation.
 *
 * Digital assumes no responsibility for the use or reliability of its 
 * software on equipment which is not supported by Digital.
 */
/*
 * Data types and routines implement SNMP protocol as described in RFC 1155
 * and RFC 1157.
 *
 * Author : Philippe Vouters
 * Creation date : 24-FEB-1997
 *
 * Modification history : 
 */



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include <ctype.h>
#ifdef __VMS
#ifdef __DECC
#pragma extern_prefix save
#pragma extern_prefix "decc$"
#include <socket.h>
#include <file.h>
#include <in.h>
#include <netdb.h>
#include <inet.h>
#include <unixio.h>
#include <strings.h>
#include <fcntl.h>
#pragma extern_prefix restore
#include <lbr$routines.h>
#else   /* __VAXC */
#include <socket.h>
#include <file.h>
#include <in.h>
#include <netdb.h>
#include <inet.h>
#include <unixio.h>
#include <fcntl.h>
#endif  /* #ifdef __DECC */
#include <smg$routines.h>
#include <lib$routines.h>
#include <descrip.h>
#else /* other than __VMS */
#include <sys/socket.h>
#include <fcntl.h>
#include </sys/include/netinet/in.h>
#include <netdb.h>
#include <sys/file.h>
#include <arpa/inet.h>
#include <sys/time.h>
#endif /* #ifdef __VMS */

/*
** The following defines where to place the first command parameter in the
** call_arg array by the parser.
*/

#define FIRST_COMMAND_ARG	4

/*
** The following defines the maximum number of parameters parsed in a command 
** line.
*/

#define MAX_NBR_PARAMS		16

/*
** The following defines the number of command available in the dispatch
** table
*/
#define MAX_ENTRIES 6
/*
** The following defines the screen width for entering a command to the
** parser. Defines the number of bytes of the screen.
*/
#define SCREENWIDTH 80

#define BOOLEAN char
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif

#define PRIMITIVE 0
#define CONSTRUCTOR 1
#define UNIVERSAL 0
#define APPLICATION 1
#define CONTEXT_SPECIFIC 2
#define PRIVATE 3

#define BOOL 1
#define INTEGER 2
#define BIT_STRING 3
#define OCTET_STRING 4
#define NUL 5
#define OBJECT_IDENTIFIER 6
#define ObjectDescriptor 7
#define EXTERNAL 8
#define REAL 9
#define ENUMERATED 10
#define SEQUENCE 16+32
#define SET 17+32
#define IpAddress 0 /* IMPLICIT OCTET STRING SIZE(4) */
#define Counter 1   /* IMPLICIT INTEGER (0..42949667295) */
#define Gauge 2     /* IMPLICIT INTEGER (0..42949667295) */
#define TimeTicks 3  /* IMPLICIT INTEGER (0..42949667295) */
#define Opaque 4   /* IMPLICIT OCTET STRING */
/*
** define ASN.1 functions
*/
#define GETREQUEST 0
#define GETNEXTREQUEST 1
#define GETRESPONSE 2
#define SETREQUEST 3

#define SNMP_SERVICE 161

#define UDPERR -1   /* UDP error */
#define TMO -2      /* timeout */

#define RETRY 2
/*
** The following is the size of buffers allocated.
*/
#define DATASIZ 512

#ifndef FD_SET
struct fd_set_struct {u_char fds_bits[8];};
typedef struct fd_set_struct fd_set;
#define NFDBITS         sizeof(struct fd_set_struct)/sizeof (u_char)
#define FD_SETSIZE      NFDBITS
#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
#define FD_ZERO(p)      memset ((char *)(p),0, sizeof(*(p)))
#endif

/* Convert short port number from host to network byte order */
#define htons(x) ((unsigned short)((x<<8)|(x>>8)))
/* Convert short port number from network to host byte order */
#define ntohs(x) ((unsigned short)((x<<8)|(x>>8)))

struct dispatch_table_type {
	char *command;
	unsigned char *(*routine)();
};
unsigned char keep_going = TRUE;
struct  {char *type;
         unsigned char value;
}  type_specifier[] = {	"0",0,
		 	"BOOLEAN",BOOL,
			"INTEGER",INTEGER,
			"BIT STRING",BIT_STRING,
			"OctetString", OCTET_STRING,
                        "DisplayString", OCTET_STRING,
                      	"NULL",NUL,
		      	"OBJECT IDENTIFIER",OBJECT_IDENTIFIER,
		      	"ObjectDescriptor",ObjectDescriptor,
			"EXTERNAL",EXTERNAL,
			"REAL",REAL,
			"ENUMERATED",ENUMERATED,
			"Reserved 11",11,
			"Reserved 12",12,
		        "Reserved 13",13,
			"Reserved 14",14,
			"Reserved 15",15,
		      	"SEQUENCE",SEQUENCE,
		      	"SET",SET,
			"IpAddress",IpAddress+(APPLICATION<<6),
			"NetworkAddress",IpAddress+(APPLICATION<<6),
                        "Counter",Counter+(APPLICATION<<6),
			"Gauge",Gauge+(APPLICATION<<6),
			"TimeTicks",TimeTicks+(APPLICATION<<6),
			"Opaque",Opaque+(APPLICATION<<6),
			"GetRequest",GETREQUEST + 32 + (CONTEXT_SPECIFIC<<6),
			"GetNextRequest",GETNEXTREQUEST + 32 + (CONTEXT_SPECIFIC<<6),
			"GetResponse",GETRESPONSE + 32 + (CONTEXT_SPECIFIC<<6),
		   	"SetRequest",SETREQUEST + 32 + (CONTEXT_SPECIFIC<<6)
};

typedef struct identifier {
	unsigned char tag:5;
        unsigned char P_C:1;
	unsigned char class:2;
        } identifier_t;


void cleanup (socket)
int socket ;
{
   (void) shutdown (socket,0) ;
   (void) close (socket) ;
}

/*
** exchange_data :
**    Sends a datagram to the remote SNMP port using UDP and receives
**    the response.
**    Inputs : remote_address : Internet address of the SNMP server host.
**	       port : the remote SNMP port. If port = 0, then the default
**		      assigned SNMP port (161) is used.
**	       buffer: the buffer to be sent to the remote destination.
**    Output:  buffer: the buffer received from the remote peer.
**    Return : 0 success
**	       TMO timeout.
**	       UDPERR error with socket functions.
*/
int exchange_data (unsigned int remote_address,
		unsigned short port,
		unsigned char *buffer) {
   int s;
   struct sockaddr_in *s_name;
   fd_set read_mask,write_mask,exception_mask ;
   int retry_nbr, sendlen, added_size;
   int received_bytes ;
   int status, i;
   struct timeval timeout ;
   BOOLEAN connected ;
   unsigned int fromlen;
   unsigned char *cp;

   /*
    * Compute buffer length.
    */
   cp = buffer;
   cp++;
   sendlen = 0;
   added_size = 1;
   if ((*cp & 0x80) == 0x80){
	added_size = *cp & 0x3f;
	cp++;
	}
   for (i=0;i < added_size; i++){ 
	sendlen = (sendlen<<8) + *cp;
	cp++;
	}
   sendlen += added_size + 1;
   /*
    * Get a UDP socket number.
    */
   if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
	return (UDPERR) ;
   /*
    * Setup the structure name and bind it to the socket s.
    */
   s_name = calloc (1,sizeof(struct sockaddr_in));
   s_name->sin_family = AF_INET ;
   s_name->sin_port = htons (0) ;
   s_name->sin_addr.s_addr = htonl (INADDR_ANY) ;
   if (bind (s, (struct sockaddr *)s_name, sizeof(struct sockaddr_in))!= 0)
	{
	cleanup (s) ;
	return (UDPERR) ;
	}
   /*
    * Setup remote peer sockaddr_in structure.
    */
   s_name->sin_family = AF_INET ;
   if (port != 0)
   	s_name->sin_port = htons (port) ;
   else	s_name->sin_port = htons (SNMP_SERVICE) ;
   s_name->sin_addr.s_addr = remote_address;

   do
     {
     /*
      * send buffer containing SNMP protocol to remote destination
      * specified by s_name
      */
      if (sendto (s,(char *)buffer,sendlen,0,(struct sockaddr *)s_name,
			sizeof (struct sockaddr_in)) ==-1 )
        {
        cleanup (s) ;
	return (UDPERR) ;
        }

      /*
       * check if there is a response.
       */
      FD_ZERO(&read_mask);
      FD_SET( s, &read_mask);
      FD_ZERO(&exception_mask);
      FD_ZERO(&write_mask);
      timeout.tv_sec = 10 ;
      timeout.tv_usec = 0 ;
      switch ( select (s+1,&read_mask,&write_mask,&exception_mask,&timeout) )
        {
        case -1:
                cleanup (s) ;
	        return (UDPERR) ;
		break ;
        case 0 :
		retry_nbr++ ;
		connected = FALSE ;
		break ;
	default :
		if (!FD_ISSET( s, &read_mask))
		     retry_nbr++ ;
		else
	  	     connected = TRUE ;
	}/* end switch */
      } while ((retry_nbr < RETRY) & (!connected)) ;
   if (!connected)
	{
	cleanup (s) ;
	return (TMO) ;
	}
   /*
    * Remote peer answered. Get data into buffer.
    */
   fromlen = sizeof (struct sockaddr_in) ;
   if ((received_bytes = recvfrom (s,(char *)buffer,DATASIZ,0,
				(struct sockaddr *)s_name,
				&fromlen))==-1)
            {
            cleanup (s) ;
	    return (UDPERR) ;
            }
   /*
    * Cleanup socket and return success.
    */
   cleanup (s) ;
   return (0);
}

void lower (char *s,char stpchr){
   for (;(*s!=stpchr)&&(*s!=0);s++) *s = tolower(*s);
}

/*
** format_ia
** Returns the ASCII equivalent in Internet notation of an internet address.
** Inputs : ia: the internet address.
** Returns : pointer to a character string containing the ASCII internet
** 	     address
*/
char *format_ia(ia)
unsigned long   ia;
{
        static char     str[16];

        sprintf (str, "%d.%d.%d.%d", ia&0xFF, (ia>>8)&0xFF, (ia>>16)&0xFF,
                (ia>>24)&0xFF);

        return (str);
}

/*
** format_ia
** Returns the Internet address of ASCII string in Internet notation.
** Inputs : str: the ASCII string in Internet notation.
** Returns : Internet address
** 	     -1 in case of failure to convert.
*/
unsigned long get_ia(char *str)
{
        unsigned long ia;
        unsigned long temp[4];
        char ch;

        for(;;) {
            if (sscanf (str, "%d.%d.%d.%d%c",
                &temp[0],&temp[1],&temp[2],
                &temp[3],&ch) != 4) return (-1);

            if ((temp[0] > 255) ||
                (temp[1] > 255) ||
                (temp[2] > 255) ||
                (temp[3] > 255)) return(-1);

            break;
        }
        ia = temp[0] + (temp[1] << 8) + (temp[2] << 16) + (temp[3] << 24);
        return (ia);
}

/*
** insert_length
** Sets the length value in ASN.1 notation inside a buffer.
** Inputs: cp : character pointer inside the buffer.
**	   length : the value to be written
** Returns: cp : updated to point to first free byte.
*/
unsigned char *insert_length (unsigned char *cp,int length) {
    unsigned char count = 0;
    unsigned char *cp1,*cp2;
    int i;

    cp1 = cp;
    if (length >= 0x80) *cp--;
    if (length == 0x80) {
	*cp-- = 1;     /* Most significant byte */
	*cp-- = 0;     /* Least significant byte */
	*cp1 = 0x82;
        }
    if (length > 0x80){
        cp2 = (unsigned char *)&length + sizeof(int) - 1;
        for (;*cp2 == 0; cp2--);
        for (i=sizeof(int);i>0;i--) {
	     count++;
	     *cp-- = *cp2--;
	     }
	*cp1 = 0x80 + count;
	} 
    if (length < 0x80) *cp-- = (unsigned char) length;
    return (cp);
}

/*
** strnmatch
** returns the number of matching bytes of two buffers.
** Inputs : s1,s2 : buffers to compare.
**	    max : maximum number of bytes to compare.
*/
int strnmatch (char *s1,char *s2,int max) {
     int num_match = 0;
     for (;*s1 != 0,*s2 != 0,max > 0;s1++,s2++,max--) 
	  if (*s1 == *s2) num_match++;
	  else break;
     return (num_match);
}

/*
** find_names
** Returns the ASCII equivalent of ASN.1 numbers from the SNMP data file.
** The tree and leaf is located.
*/
char *find_names (char *names,int max_index) {
     char buffer[100];
     static char buffer1[256];
     char line [256];
     char saved_line[256];
     char *cp,*cp1,*cp2;
     BOOLEAN comments;
     int match = 0;
     int i,j;
     FILE *fp;

     /*
      * Clear all bytes of buffer.
      */
     memset (buffer,0,sizeof(buffer));
     memset (buffer1,0,sizeof(buffer1));
     /*
      * Recompute data bytes whose value is
      * greater than 128 (0x80) which are in two
      * bytes.
      */
     cp1 = &names[max_index];
     for (cp = cp2 = names;cp <= cp1;cp++,cp2++){    
	  if ((*cp & 0x80) == 0x80) {
		*cp2 = *(cp+1) +0x80;
		cp++;
                max_index--;
		}
	  else *cp2 = *cp;
	}
     /*
      * format the buffer using numeric string in dot notation.
      */
     for (i=0;i<max_index;i++)
	 sprintf (&buffer[strlen(buffer)],"%1u.",(unsigned char)names[i]);
     sprintf (&buffer[strlen(buffer)],"%1u",(unsigned char)names[i]); 	
     /*
      * open the MIB compiled file
      */
     if ((fp = fopen ("snmpinfo.dat","r")) == NULL) {
	  strcpy (line,"error opening file snmpinfo.dat");
          perror (line);
	  exit(0);
          }
     /*
      * Read the file until found or end of file
      */
     while (!(feof(fp))){
          memset (line,0,sizeof(line));
	  if (fgets(line,sizeof(line),fp) == NULL) break;
          /*
	   * Skip comments in file.
	   */
          cp = line;
	  for (;*cp == ' ';cp++);
	  if ((strcmp (cp,"/*") == 0) && (*cp == '/'))comments = TRUE;
	  /*
	   * check for end of comments in line.
	   */
	  cp1 = strstr (cp,"*/");
          if (cp1 != NULL) {
              cp = cp1 + 2;
	      comments = FALSE;
	      } 
	  if (*cp == 0) continue;
          if (comments) continue;
          /*
	   * Locate open and close parenthesis
	   */
	  if (strcmp (cp,"(") == 0) comments = TRUE;
	  cp1 = strchr (cp,')');
          if (cp1 != NULL) {
              cp = cp1 + 1;
	      comments = FALSE;
	      } 
          if (comments) continue;
          /*
	   * Locate the first numeric digit inside the line
	   * and replace the first blank by a null character.
	   */
          cp = strchr(line,' ');
          if (cp == NULL) continue;
	  cp = strpbrk (cp,"1234567890");
          if (cp == NULL) continue;
          if (strchr (cp,' ') == NULL) continue;
          *strchr(cp,' ') = 0;
          /*
	   * If the numeric notation is contained
	   * inside the line read, exit loop.
	   */
          if (strnmatch(buffer,cp,strlen(cp)) > match){
                if ((strnmatch(buffer,cp,strlen(cp)) == strlen(cp)) &&
		    ((buffer[strnmatch(buffer,cp,strlen(cp))] == '.') ||
			(buffer[strnmatch(buffer,cp,strlen(cp))] == 0)))
			match = strlen(cp);
		else continue;
		*strchr(line,' ') = 0;
		strcat(buffer1,line);
		/*
		 * save line into matching line.
		 */
                cp = cp + strlen(cp) + 1;
	      	strcpy (saved_line,cp);
          	if (match != strlen(buffer))
		    strcat(buffer1,".");
		}
          if (match == strlen(buffer)) break;
         } /* end while */
     fclose(fp);
     strcat (buffer1,&buffer[match+1]);
     free(names);
     return (buffer1);
}

/*
** find_object
** Locates from SNMP data file the matching string equal to the object
** string, translates the ASCII numeric digits into an ASN.1 notation
** and returns the number of bytes of the translated buffer.
** Inputs : object : the SNMP identifier (ASCII string).
**	    idents : the address of a character pointer that will receive
**		     the start of the allocated buffer.
** Returns: the number of effictive bytes of the allocated buffer.
*/
int find_object (char *object, unsigned char **idents) {
     char line [256];
     char ascii_values[40];
     char object_name[256];
     char *cp, *cp1;
     unsigned char *cp2, *cp3;
     char **cp4,*cp5;
     BOOLEAN comments;
     unsigned char value;
     int i = 0, match, object_id =0;
     int object_max=0;
     FILE *fp;

     /*
      * Initialize all variables.
      */
     *idents = NULL;
     memset (ascii_values,0,sizeof(ascii_values));
     strcpy (object_name,object);
     cp4 = malloc (30*sizeof(char *));
     cp = object_name;
     object_max = 0;
     /*
      * Separate ASCII identifiers from numeric digits.
      */
     do {
	if (isdigit (*cp) == 0) { /* non digit character */
	    cp5 = strchr (cp,'.');
	    if (cp5 != NULL) {
		*cp5 = 0;
		cp4[object_max] = cp;
		cp = cp5+1;
		object_max++;
                }
	    else cp4[object_max] = cp;
        }
      }while ((cp5 != NULL) && (isdigit (*cp) == 0));
     if (isdigit (*cp) == 0)
	  cp5 = cp + strlen(cp);
     else {
          object_max--;
	  cp5 = cp;
	  }			
     /*
      * open the MIB compiled file
      */
     if ((fp = fopen ("snmpinfo.dat","r")) == NULL) {
	  strcpy (line,"error opening file snmpinfo.dat");
          perror (line);
	  exit(0);
          }
     /*
      * Read the file until found or end of file
      */
     while ((!(feof(fp))) && (object_id <= object_max)){
          memset (line,0,sizeof(line));
	  if (fgets(line,sizeof(line),fp) == NULL) break;
          /*
	   * Skip comments in file.
	   */
          cp = line;
	  for (;*cp == ' ';cp++);
	  if ((strcmp (cp,"/*") == 0) && (*cp == '/'))comments = TRUE;
	  /*
	   * check for end of comments in line.
	   */
	  cp1 = strstr (cp,"*/");
          if (cp1 != NULL) {
              cp = cp1 + 2;
	      comments = FALSE;
	      } 
	  if (*cp == 0) continue;
          if (comments) continue;
          /*
	   * Lowercase the identifier
	   */
	  lower(line,' ');
          /*
	   * Compare the Object Identifier in file with the searched one.
           */
          if (strncmp(line,cp4[object_id], strlen(cp4[object_id])) == 0) {
              cp = strchr(line,' ');
	      cp = strpbrk (cp,"1234567890");
              if (cp == NULL) continue;
              *strchr (cp,' ') = 0;
              /*
	      * If the numeric notation is contained
	      * inside the line read, exit loop.
	      */
              match = strnmatch(ascii_values,cp,strlen(ascii_values));
              if (match == strlen(ascii_values))
		  strcat(ascii_values,&cp[match]);
              object_id++;
	      }/* end if strstr */
          else continue;
         } /* end while */
     /*
      * If at end-of-file, the translation between an object name
      * and object identifier has not been found. Return 0 as the
      * size of object.
      */
     free(cp4);
     if (feof(fp)) {
	 fclose (fp);
         return (0);
         }
     fclose(fp);
     /*
      * Append a dot to the numeric buffer if there is a numeric
      * digit passed to this routine in an Object Identifier.
      * (example : ipRouteDest.16.189.144.0)
      */
     if ((strcmp(object_name,cp5) != 0) && ( *cp5 != 0))
	  strcat(ascii_values,".");
     strcat (ascii_values,cp5);
     /*
      * Setup the numeric values according to ASN.1 rules.
      */
     value = 0;
     *idents = malloc (50);
     cp2 = cp3 = *idents;
     for (cp1 = ascii_values;*cp1!=0;cp1++)
        if (*cp1 == '.') {
            if (value >= 0x80) {
		*cp2 = 0x81;
		cp2++;
		*cp2 = value - 0x80;
		}
            else *cp2 = value; 
	    cp2++;
            value = 0;
	    }
        else value = value*10 + *cp1 - '0';
     if (value >= 0x80) {
	*cp2 = 0x81;
	cp2++;
	*cp2 = value - 0x80;
	}
     else *cp2 = value; 
     *cp3 = (*cp3)*40+*(cp3+1);
     for (cp3 = cp3+1,i=1; cp3 <cp2;cp3++,i++)
	  *cp3 = *(cp3 + 1);
     /*
      * If the object identifier is a Leaf and
      * no numeric digits was appended to the object
      * identifier, then append a trailing null byte.
      */
     cp = cp +strlen(cp) + 1;
     if ((strstr(cp,"nonLeaf") == NULL) &&
	  (*cp5 == 0)){
	    *cp3 = 0;
	    i++;
	    }
     /*
      * Last check. Return an error if the identifier is
      * not accessible.
      */
     if (strstr(cp,"not-accessible") != NULL) i = -1;
     return (i);
}

/*
** set_object
** Locates from SNMP data file the matching string equal to the object
** string, translates the ASCII numeric digits into an ASN.1 notation
** and returns the number of bytes of the translated buffer.Also appends
** in the buffer the value to be set of the Object Identifier.
** Inputs : object : the SNMP identifier (ASCII string).
**	    object_value : the ASCII string of the new value to be set.
**	    idents : the address of a character pointer that will receive
**		     the start of the allocated buffer.
** Output : len : receives the effective length of the allocated buffer.
** Returns: the number of bytes of the identifier inside the allocated buffer.
*/
int set_object (char *object, char *object_value,
		unsigned char **idents,unsigned int *len) {
     char line [256];
     char ascii_values[40];
     char object_name[256];
     char *cp, *cp1;
     unsigned char *cp2, *cp3;
     char **cp4,*cp5;
     BOOLEAN comments;
     unsigned char value;
     int i = 0, match, object_id =0;
     int object_max=0;
     FILE *fp;

     /*
      * Initialize all variables.
      */
     *idents = NULL;
     memset (ascii_values,0,sizeof(ascii_values));
     strcpy (object_name,object);
     cp4 = malloc (30*sizeof(char *));
     cp = object_name;
     object_max = 0;
     /*
      * Separate ASCII identifiers from numeric digits.
      */
     do {
	if (isdigit (*cp) == 0) { /* non digit character */
	    cp5 = strchr (cp,'.');
	    if (cp5 != NULL) {
		*cp5 = 0;
		cp4[object_max] = cp;
		cp = cp5+1;
		object_max++;
                }
	    else cp4[object_max] = cp;
        }
      }while ((cp5 != NULL) && (isdigit (*cp) == 0));
     if (isdigit (*cp) == 0)
	  cp5 = cp + strlen(cp);
     else {
          object_max--;
	  cp5 = cp;
	  }			
     /*
      * open the MIB compiled file
      */
     if ((fp = fopen ("snmpinfo.dat","r")) == NULL) {
	  strcpy (line,"error opening file snmpinfo.dat");
          perror (line);
	  exit(0);
          }
     /*
      * Read the file until found or end of file
      */
     while ((!(feof(fp))) && (object_id <= object_max)){
          memset (line,0,sizeof(line));
	  if (fgets(line,sizeof(line),fp) == NULL) break;
          /*
	   * Skip comments in file.
	   */
          cp = line;
	  for (;*cp == ' ';cp++);
	  if ((strcmp (cp,"/*") == 0) && (*cp == '/'))comments = TRUE;
	  /*
	   * check for end of comments in line.
	   */
	  cp1 = strstr (cp,"*/");
          if (cp1 != NULL) {
              cp = cp1 + 2;
	      comments = FALSE;
	      } 
	  if (*cp == 0) continue;
          if (comments) continue;
          /*
	   * Lowercase the identifier
	   */
	  lower(line,' ');
          /*
	   * Compare the Object Identifier in file with the searched one.
           */
          if (strstr(line,cp4[object_id]) != NULL) {
              cp = strchr(line,' ');
	      cp = strpbrk (cp,"1234567890");
              if (cp == NULL) continue;
              *strchr (cp,' ') = 0;
              /*
	      * If the numeric notation is contained
	      * inside the line read, exit loop.
	      */
              match = strnmatch(ascii_values,cp,strlen(ascii_values));
              if (match == strlen(ascii_values))
		  strcat(ascii_values,&cp[match]);
              object_id++;
	      }/* end if strstr */
          else continue;
         } /* end while */
     /*
      * If at end-of-file, the translation between an object name
      * and object identifier has not been found. Return 0 as the
      * size of object.
      */
     free(cp4);
     if (feof(fp)) {
	 fclose (fp);
         return (0);
         }
     /*
      * Append a dot to the numeric buffer if there is a numeric
      * digit passed to this routine in an Object Identifier.
      * (example : ipRouteDest.16.189.144.0)
      */
     if ((strcmp(object_name,cp5) != 0) && ( *cp5 != 0))
	  strcat(ascii_values,".");
     strcat(ascii_values,cp5);
     /*
      * Setup the numeric values according to ASN.1 rules.
      */
     value = 0;
     *idents = malloc (50);
     cp2 = cp3 = *idents;
     for (cp1 = ascii_values;*cp1!=0;cp1++)
        if (*cp1 == '.') {
            if (value >= 0x80) {
		*cp2 = 0x81;
		cp2++;
		*cp2 = value - 0x80;
		}
            else *cp2 = value; 
	    cp2++;           
            value = 0; 
	}
     else value = value*10 + *cp1 - '0';
     *cp2 = value;
     *cp3 = (*cp3)*40+*(cp3+1);
     for (cp3 = cp3+1,i=1; cp3 <cp2;cp3++,i++)
	  *cp3 = *(cp3 + 1);
     cp = cp +strlen(cp) + 1;
     /*
      * If the object identifier is a Leaf and
      * no numeric digits was appended to the object
      * identifier, then append a trailing null byte.
      */
     if ((strstr(cp,"nonLeaf") == NULL) &&
	  (*cp5 == 0)){
	    *cp3++ = 0;
	    i++;
	    }
     /*
      * If the identifier is not read/write then returns
      * an error.
      */
     if (strstr(cp,"read-write") == NULL) return(-1);
     /*
      * Add the object identifier value to be set.
      */
     if ((strstr(cp,"DisplayString") != NULL) ||
	 (strstr(cp,"OctetString") != NULL)) {
        *cp3++ = OCTET_STRING;
	*cp3++ = strlen(object_value);
	strncpy((char *)cp3,object_value,strlen(object_value));
        *len =i + 2 + strlen(object_value);
	}
     if (strstr(cp,"INTEGER") != NULL){
	int value;
        unsigned int l;

	sscanf(object_value,"%d",&value);
        *cp3++ = INTEGER;
	cp2 = cp3;
        cp3++;
	l = 0;
        do {
	    *cp3++= value&0xFF;
	    value = ((value&0xFFFFFF00) >> 8);
	    l++;
	} while (value > 0);
	*cp2 = l;
        *len = i + l + 2;
	}
     if ((strstr(cp,"NetworkAddress") != NULL) ||
	 (strstr(cp,"IpAddress") != NULL)){
	  unsigned long value;
          unsigned int l;

	  value = get_ia(object_value);
          if (value == -1) {
		fclose(fp);
     		return (-2);
                }
          *cp3++ = IpAddress+(APPLICATION<<6);
          *cp3++ = sizeof(unsigned long);
          for (l=0;l<sizeof(unsigned long);l++) {
	      *cp3++= value&0xFF;
	      value = ((value&0xFFFFFF00) >> 8);
	      }
          *len = i + 6;
	  }
     if (strstr(cp,"Gauge") != NULL){
	unsigned int value;
        unsigned int l;

	sscanf(object_value,"%u",&value);
        *cp3++ = Gauge+(APPLICATION<<6);
	cp2 = cp3;
        cp3++;
	l = 0;
        do {
	    *cp3++= value&0xFF;
	    value = ((value&0xFFFFFF00) >> 8);
	    l++;
	  } while (value > 0);
	*cp2 = l;
        *len = i + l + 2;
        }
     fclose(fp);
     return (i);
}

/*
** interpret
** Interpret an SNMP coded buffer into readable ASCII data.
** Inputs : the buffer.
** Outputs : none
*/
void  interpret (unsigned char *buffer){
   unsigned char *cp;
   int length;
   int number_of_ints = 0,integer_value;
   unsigned int unsigned_value;
   identifier_t *ident;
   int i,number_of_spaces = 0;
   char spaces[3] = "  ";
   int added_size;
   int number_of_length_octets;
   int size;
   char *names;
   char *error_table[] = {"noError","tooBig","noSuchName",
			  "badValue","readOnly","genErr"};

   /*
    * first determine size of whole packet.
    */
   cp = buffer;
   cp++;
   size = 0;
   added_size = 1;
   if ((*cp & 0x80) == 0x80){
	added_size = *cp & 0x3f;
	cp++;
	}
   for (i=0;i < added_size; i++){ 
	size = (size<<8) + *cp;
	cp++;
	}
   /*
    * decompose buffer
    */
   cp = buffer;
   while (cp <buffer + size + added_size + 1){
          /*
	   * get type field
           */
          ident = (identifier_t *)cp;
          for (i = 0; i < number_of_spaces; i++) 
               printf ("%s",spaces);

          /*
	   * Search matching value
           */
          for (i=0;i< sizeof (type_specifier)/sizeof (type_specifier[0]);i++)
		if (type_specifier[i].value == *cp) break;

          switch(ident->class) {
	      case CONTEXT_SPECIFIC:
	           printf ("[CONTEXT %2d]",ident->tag);
              	   break;
              case APPLICATION :
	           printf ("[APPLICATION %2d]",ident->tag);
              	   break;
              case UNIVERSAL :
	           printf ("[UNIVERSAL %2d] ",ident->tag);
                   break;
              case PRIVATE:
	           printf ("[PRIVATE %2d]",ident->tag);
              }/* end switch */
          /*
	   * Display the ASCII type code. (ex: 2 == "INTEGER")
	   */
	  if (i < sizeof (type_specifier)/sizeof (type_specifier[0]))
	      printf("(%s)",type_specifier[i].type);

          if (ident->P_C == CONSTRUCTOR) {
	       cp++;
               /* determine bytes to skip */
	       if ((*cp & 0x80) == 0x80)
	           cp = cp +(*cp & 0x3f);
	       cp++;
	       printf ("(\n");
               number_of_spaces ++;
	       } /* end then */
	  else {
		cp++;
		/*
		 * cp points to the length octets;
		 * get length.
		 */
		length = 0;
		number_of_length_octets = 1;
	        if ((*cp & 0x80) == 0x80){
	              number_of_length_octets = *cp & 0x3f;
		      cp++;
		      }
                for (i=0;i <number_of_length_octets;i++){ 
		    length = (length<<8) + *cp;
		    cp++;
		    }
                /*
		 * Display length of item.
		 */
                printf ("Length = %d",length);
                /*
		 * Display value of item according to type field.
		 */
		printf ("; value = ");
                switch (*((unsigned char *)ident)) {
                  case OCTET_STRING : 
		        printf ("%.*s",length,cp);
		        cp = cp+length;
		        break;

		  case OBJECT_IDENTIFIER:
                        names = calloc (length+1,sizeof (char));
		    	printf ("%1x.",*cp/40);
                        names [0] = *cp/40;
			printf ("%1x.",*cp%40);
                        names [1] = *cp%40;
		    	cp++;
		    	for (i = 1; i < length ; i++) {
                             names [1+i] = *cp;
  		             printf ("%1x",*cp);
	                     if (i < length - 1) printf (".");
                             cp++;
                             } /* end for */
                       printf (" (%s)",find_names(names,length));
                       break;

                  case INTEGER:
                        integer_value = 0;
			for (i = 0; i < length ; i++) {
                             integer_value = (integer_value<<8) + *cp;
                             cp++;
                             } /* end for */
                        printf ("%d",integer_value);
                        switch (number_of_ints) {
                           case 0 : printf ("   (snmp version)");
				    break;
			   case 1 : printf ("   (Request ID)");
			   	    break;
			   case 2 : printf ("   (Error status = %s)",
							error_table[integer_value]);
                                    break;
			   case 3 : printf ("   (Error Index)");
			}
			number_of_ints++;	
                        break;

                  case IpAddress+(APPLICATION<<6):
			printf ("%s",format_ia(*((unsigned int *)cp)));
		        cp = cp+length;
		        break;

		  case Counter+(APPLICATION<<6):
		  case Gauge+(APPLICATION<<6):
		  case TimeTicks+(APPLICATION<<6):
                        unsigned_value = 0;
			for (i = 0; i < length ; i++) {
                             unsigned_value = (unsigned_value<<8) + *cp;
                             cp++;
                             } /* end for */
			printf ("%u",unsigned_value);
			break;

                  case Opaque+(APPLICATION<<6):
			interpret(cp);
		        cp = cp+length;
		        break;

		  default:
			for (i = 0; i < length ; i++) {
  		             printf ("%1x",*cp);
	                     if (i < length - 1) printf (".");
                             cp++;
                             } /* end for */
                  }/* end switch */
		printf ("\n");
 		} /* end else */
          }
}

/*
** GetRequest
** This highlevel routine sets up an SNMP buffer for the get function.
** Inputs : argc : count of arguments in line.
** 	    argv : pointer to an array of pointers to command line
**		   arguments.
** Returns: SNMP allocated buffer.
*/
unsigned char *GetRequest (int argc,char **argv) {
  int i,j;
  unsigned char *buffer;
  unsigned int length;
  int remainder,divider;
  int size_object;
  unsigned char *cp,*cp1;
  unsigned int *request_id;
  unsigned char *objects;

  buffer = malloc(2*DATASIZ);
  length = 0;

  /* The buffer is filled from the end. */

  cp = buffer+(2*DATASIZ)-1;
  for (i=argc-1; i>0;i--) {
     *cp-- = 0;
     *cp-- = NUL;
     /* Lowercase object */
     lower(argv[i],0);
     /* get object identifier in binary format */
     size_object = find_object (argv[i], &cp1);
     if (size_object == 0) {
	printf ("%%SNMP-F-NOSUCHOBJ, no such object %s\n",argv[i]);
        free(buffer);
	free (cp1);
	return (NULL);
	}
     if (size_object == -1) {
	printf ("%%SNMP-F-NOACCESS, no access to object %s\n",argv[i]);
        free(buffer);
	free (cp1);
	return (NULL);
	}
     else
	for (j=size_object-1;j>=0;j--) *cp-- = cp1[j];
     free (cp1);
     cp = insert_length (cp,size_object);
     *cp-- = OBJECT_IDENTIFIER;
     length = (int)buffer + 2*DATASIZ - (int)cp;
     cp = insert_length (cp,length-1);
     *cp-- = SEQUENCE;
     }/* end for */
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp-- = SEQUENCE;
   *cp-- = 0; /* Error index */
   *cp-- = 1;
   *cp-- = INTEGER;
   *cp-- = 0; /* Error status */
   *cp-- = 1;
   *cp-- = INTEGER;
   cp = cp - sizeof (int) + 1;
   request_id = (unsigned int *)cp;
   *request_id-- = 0x1CB50E7E;
   cp--;
   *cp-- = sizeof(int);
   *cp-- = INTEGER;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp-- = GETREQUEST + 32 + (CONTEXT_SPECIFIC<<6);
   /* Fetch community */
   cp = cp - strlen(argv[0]) + 1;
   strncpy ((char *)cp,argv[0],strlen(argv[0]));
   cp--;
   cp = insert_length (cp,strlen(argv[0]));
   *cp-- = OCTET_STRING;
   *cp-- = 0; /* snmp version */
   *cp-- = 1;
   *cp-- = INTEGER;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp = SEQUENCE;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   memcpy (buffer,cp,length);
   return (buffer);
}

/*
** ExitCommand
** This highlevel routine causes an exit of the application by setting
** main variable keep_going to FALSE.
** Inputs : argc : count of arguments in line.
** 	    argv : pointer to an array of pointers to command line
**		   arguments.
** Returns: SNMP allocated buffer.
*/
unsigned char *ExitCommand(int argc,char **argv) {
     keep_going--;
     return(NULL);
}

/*
** Help
** This highlevel routine causes an exit of the application by setting
** main variable keep_going to FALSE.
** Inputs : argc : count of arguments in line.
** 	    argv : pointer to an array of pointers to command line
**		   arguments.
** Returns: SNMP allocated buffer.
*/
unsigned char *Help(int argc,char **argv) {
     printf ("Available commands :\n");
     printf ("      get\n");
     printf ("      getnext\n");
     printf ("      set\n");
     printf ("      exit\n");
     printf ("      help\n\n");
     printf (" For get, getnext and set : Syntax :\n");
     printf (" \tget/getNext hostname community object1 [objectn]\n");
     printf (" \tset hostname community object1 value1 [objectn valuen]\n");
     return(NULL);
}

/*
** GetNextRequest
** This highlevel routine sets up an SNMP buffer for the getnext function.
** Inputs : argc : count of arguments in line.
** 	    argv : pointer to an array of pointers to command line
**		   arguments.
** Returns: SNMP allocated buffer.
*/
unsigned char *GetNextRequest (int argc,char **argv) {
  int i,j;
  unsigned char *buffer;
  unsigned int length;
  int remainder,divider;
  int size_object;
  unsigned char *cp,*cp1;
  unsigned int *request_id;
  unsigned char *objects;

  buffer = malloc(2*DATASIZ);
  length = 0;

  /* The buffer is filled from the end. */

  cp = buffer+(2*DATASIZ)-1;
  for (i=argc-1; i>0;i--) {
     *cp-- = 0;
     *cp-- = NUL;
     /* Lowercase object */
     lower(argv[i],0);
     /* get object identifier in binary format */
     size_object = find_object (argv[i], &cp1);
     if (size_object == 0) {
	printf ("%%SNMP-F-NOSUCHOBJ, no such object %s\n",argv[i]);
        free(buffer);
	free (cp1);
	return (NULL);
	}
     if (size_object == -1) {
	printf ("%%SNMP-F-NOACCESS, no access to object %s\n",argv[i]);
        free(buffer);
	free (cp1);
	return (NULL);
	}
     else
	for (j=size_object-1;j>=0;j--) *cp-- = cp1[j];
     free (cp1);
     cp = insert_length (cp,size_object);
     *cp-- = OBJECT_IDENTIFIER;
     length = (int)buffer + 2*DATASIZ - (int)cp;
     cp = insert_length (cp,length-1);
     *cp-- = SEQUENCE;
     }/* end for */
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp-- = SEQUENCE;
   *cp-- = 0; /* Error index */
   *cp-- = 1;
   *cp-- = INTEGER;
   *cp-- = 0; /* Error status */
   *cp-- = 1;
   *cp-- = INTEGER;
   cp = cp - sizeof (int) + 1;
   request_id = (unsigned int *)cp;
   *request_id-- = 0x1CB50E7E;
   cp--;
   *cp-- = sizeof(int);
   *cp-- = INTEGER;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp-- = GETNEXTREQUEST + 32 + (CONTEXT_SPECIFIC<<6);
   /* Fetch community */
   cp = cp - strlen(argv[0]) + 1;
   strncpy ((char *)cp,argv[0],strlen(argv[0]));
   cp--;
   cp = insert_length (cp,strlen(argv[0]));
   *cp-- = OCTET_STRING;
   *cp-- = 0; /* snmp version */
   *cp-- = 1;
   *cp-- = INTEGER;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp = SEQUENCE;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   memcpy (buffer,cp,length);
   return (buffer);
}

/*
** SetRequest
** This highlevel routine sets up an SNMP buffer for the set function.
** Inputs : argc : count of arguments in line.
** 	    argv : pointer to an array of pointers to command line
**		   arguments.
** Returns: SNMP allocated buffer.
*/
unsigned char *SetRequest (int argc,char **argv) {
  int i,j;
  unsigned char *buffer;
  unsigned int length;
  int remainder,divider;
  int size_object;
  unsigned char *cp,*cp1;
  unsigned int total_len;
  unsigned int *request_id;
  unsigned char *objects;

  buffer = malloc(2*DATASIZ);
  length = 0;

  /* The buffer is filled from the end. */

  cp = buffer+(2*DATASIZ)-1;
  for (i=argc-2; i>0;i-=2) {
     /* Lowercase object */
     lower(argv[i],0);
     /* get object identifier in binary format */
     size_object = set_object (argv[i],argv[i+1], &cp1,&total_len);
     switch (size_object) {
	case 0:
		printf ("%%SNMP-F-NOSUCHOBJ, no such object %s\n",argv[i]);
        	free(buffer);
		free (cp1);
		return (NULL);
		break;
     	case -1:
		printf ("%%SNMP-F-NOACCESS, no read-write access to object %s\n",argv[i]);
        	free(buffer);
		free (cp1);
		return (NULL);
		break;
     	case -2: 
		printf ("%%SNMP-F-BADVAL, bad value %s\n",argv[i+1]);
        	free(buffer);
		free (cp1);
		return (NULL);
		break;
     	default:
		for (j=total_len-1;j>=0;j--) *cp-- = cp1[j];
        }
     free (cp1);
     cp = insert_length (cp,size_object);
     *cp-- = OBJECT_IDENTIFIER;
     length = (int)buffer + 2*DATASIZ - (int)cp;
     cp = insert_length (cp,length-1);
     *cp-- = SEQUENCE;
     }/* end for */
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp-- = SEQUENCE;
   *cp-- = 0; /* Error index */
   *cp-- = 1;
   *cp-- = INTEGER;
   *cp-- = 0; /* Error status */
   *cp-- = 1;
   *cp-- = INTEGER;
   cp = cp - sizeof (int) + 1;
   request_id = (unsigned int *)cp;
   *request_id-- = 0x1CB50E7E;
   cp--;
   *cp-- = sizeof(int);
   *cp-- = INTEGER;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp-- = SETREQUEST + 32 + (CONTEXT_SPECIFIC<<6);
   /* Fetch community */
   cp = cp - strlen(argv[0]) + 1;
   strncpy ((char *)cp,argv[0],strlen(argv[0]));
   cp--;
   cp = insert_length (cp,strlen(argv[0]));
   *cp-- = OCTET_STRING;
   *cp-- = 0; /* snmp version */
   *cp-- = 1;
   *cp-- = INTEGER;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   cp = insert_length (cp,length-1);
   *cp = SEQUENCE;
   length = (int)buffer + 2*DATASIZ - (int)cp;
   memcpy (buffer,cp,length);
   return (buffer);
}

#ifdef __VMS
unsigned long screen_setup()
{
/*
 * Returns a keyboard id for a pasteboard
 */
   int kbdid,stat;

   stat = smg$create_virtual_keyboard(&kbdid,0,0,0);
   if (!(stat&1)) lib$stop(stat);
   return (kbdid);
}

int parse (char *line_buff,int length,
	    struct dispatch_table_type dispatch_table[],
            unsigned int *call_args)
{
 int i,j,k;
 int matching_entry;
 char	*verb;
 int keyword_length;
 BOOLEAN match_found;
 BOOLEAN in_quotes = FALSE;

 for (i=0;i<length;i++) {
    if (line_buff[i] == '"') {
        in_quotes = !in_quotes;
    }
    else {
        if (!in_quotes) {
            if ((line_buff[i] == ' ') || (line_buff[i] == '\t'))
	        line_buff [i] = '\0';
        }
    }
 }

 while (*line_buff == '\0'){ *line_buff++; length--;}

  match_found = FALSE;
  keyword_length = strlen (line_buff);
  matching_entry = MAX_ENTRIES;
  for (j=0;j<MAX_ENTRIES;j++) {
      if (strncmp (line_buff,dispatch_table[j].command,keyword_length) == 0) {
          if (keyword_length == strlen (dispatch_table[j].command)) {
	      matching_entry = j;
	      break; /* an exact match */
	  }
          if (match_found) {
              printf ("%%SNMP-W-AMVERB, ambiguous command verb  - supply more characters");
              return (-1);
          }
	  else {
	      matching_entry = j;
	      match_found = TRUE;
	  }
      }
  }

 k = i = 0;
 length = length - strlen (line_buff);
 verb = line_buff;
 line_buff = line_buff + strlen (line_buff);
 if (matching_entry <MAX_ENTRIES) {
     call_args [0] = (unsigned int) dispatch_table[matching_entry].routine;
     while (i< length) {
       if (*line_buff =='\0'){
		i++; line_buff++;
	}
	else {
		if (k == MAX_NBR_PARAMS) {
		     printf ("%%SNMP-W-MAXPARM, too many parameters - reenter command with fewer parameters");
		     return(-1);
		}

		k++;
		call_args[3] = (unsigned int)&call_args[FIRST_COMMAND_ARG];
		call_args[3+k] = (unsigned int)line_buff;
		i = i +strlen (line_buff);
		line_buff = line_buff +strlen (line_buff);
	}	
     }/* end while */
     call_args[1] = 2;
     call_args[2] = k;
     return (0);
 }                    
 return (-1);
}

int main(){
      int argc;
      char **argv;
      $DESCRIPTOR (prompt,"SNMP> ");
      unsigned long keyboard_id;
      short len;
      struct dsc$descriptor_s command_desc;
      char string[SCREENWIDTH+1];
      unsigned int call_args[MAX_NBR_PARAMS+FIRST_COMMAND_ARG];
#else
int main(int argc,char **argv){
      int keyword_length,matching_entry,j;
#endif
      int ia, status, remote_address;
      struct	hostent	*hp;
      char *hostname =NULL;
      unsigned char *buffer;
      unsigned char *(*dispatch)();
      struct dispatch_table_type dispatch_table[]= {
			"get",GetRequest,
			"getnext",GetNextRequest,
			"set",SetRequest,
			"exit",ExitCommand,
			"help",Help,
			"?",Help};

     unsigned char *buffer1;

#ifdef __VMS
    keyboard_id = screen_setup();
    while (keep_going){
cont:;
/*
** Setup the CLASS S descriptor.
*/
       command_desc.dsc$w_length = SCREENWIDTH;
       command_desc.dsc$b_dtype = DSC$K_DTYPE_T;
       command_desc.dsc$b_class = DSC$K_CLASS_S;
       command_desc.dsc$a_pointer = string;
       status = smg$read_composed_line(&keyboard_id,NULL,&command_desc,
					   &prompt,&len,NULL,NULL,NULL,
					   NULL,NULL,NULL,NULL);
       if (!(status & 1)) break;
       status = parse (string,len+1,dispatch_table,call_args);
       if (status != -1) 
	      dispatch = (unsigned char *(*)()) call_args[0];
       else {
	     printf ("%%SNMP-F-UNRECOG, unrecognized command\n");
	     goto cont;
	     }
       argc = (int) call_args[2];
       argv = (char **)call_args[3];
#else
    argc -= 2;
    argv++;
#endif
       if ((argc <3)
#ifdef __VMS
	  && ((call_args[0] != (unsigned int) dispatch_table[3].routine) &&
              (call_args[0] != (unsigned int) dispatch_table[4].routine))
#endif
            ) {
	     printf ("%%SNMP-F-TOOFEWARGS, Too few arguments\n");
#ifdef __VMS
	     goto cont;	   
#else
	     exit(0);
#endif
          }
#ifndef __VMS
       keyword_length = strlen (argv[0]);
       matching_entry = MAX_ENTRIES;
       for (j=0;j<MAX_ENTRIES;j++) 
       if (strncmp (argv[0],dispatch_table[j].command,keyword_length) == 0) 
           if (keyword_length == strlen (dispatch_table[j].command)) {
	       matching_entry = j;
	       break; /* an exact match */
	   }
       if (matching_entry <MAX_ENTRIES) 
           dispatch = dispatch_table[matching_entry].routine;
       else {
	     printf ("%%SNMP-F-UNRECOG, unrecognized command\n");
	     exit(0);
	     }
       argv++;
#endif 
       if (argc > 1){
           ia = (int) inet_addr(argv[0]);
           if ( ia == -1) {
	        hp = gethostbyname(argv[0]);
	        if (hp) {
	     	    memcpy((char *)&ia,(char *)*hp->h_addr_list,
				   hp->h_length);
	       	    hostname = hp->h_name;
		    }
                else {
		    printf("%%SNMP-F-NOSUCHHOST, Unknown host %s\n",argv[0]);
#ifdef __VMS
                    goto cont;
#else
		    exit(0);
#endif
		    }
                }
           else hostname = 0;
           remote_address = ia;
	   }
       argc--; argv++;
       buffer = dispatch (argc,argv);
       if (buffer != NULL) {
	   printf ("***** buffer sent : *****\n");
	   interpret (buffer);
           if ((status = exchange_data(remote_address,0,buffer)) == 0) {
	        printf ("***** buffer received : *****\n");
	        interpret (buffer);
                }
	   else switch (status) {
		case -1 : printf ("%%SNMP-F-UDPERR, UDP error\n");
			  break;
		case -2 : printf ("%%SNMP-F-TMO, no answer from agent\n");
	  } 
          free (buffer);
       }
#ifdef __VMS
       }/* end keep_going */
#endif
}/* end main */
