/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/*   (c) Copyright Systems Integration Specialists Company, Inc.,	*/
/*      	  1986 - 2001, All Rights Reserved.		        */
/*									*/
/*		    PROPRIETARY AND CONFIDENTIAL			*/
/*									*/
/* MODULE NAME : mms_ced4.c						*/
/* PRODUCT(S)  : MMSEASE, MMSEASE-LITE					*/
/*									*/
/* MODULE DESCRIPTION : 						*/
/*	This module contains common primitive encode/decode functions	*/
/*	particular to getting and writing variables.			*/
/*									*/
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE :				*/
/*									*/
/* MODIFICATION LOG :							*/
/*  Date     Who   Rev			Comments			*/
/* --------  ---  ------   -------------------------------------------	*/
/* 02/09/09  JRB     04    Allow any value for DataAccessError.		*/
/* 03/11/04  GLB     03    Remove "thisFileName"                    	*/
/* 12/20/01  JRB     02    Converted to use ASN1R (re-entrant ASN1)	*/
/* 09/13/99  MDE     01    Added SD_CONST modifiers			*/
/* 04/02/97  DTL   7.00    MMSEASE 7.0 release. See MODL70.DOC for	*/
/*			   history.					*/
/************************************************************************/

#include "glbtypes.h"
#include "sysincs.h"

#include "mmsdefs.h"
#include "mms_pvar.h"
#include "asn1defs.h"

/************************************************************************/
static ST_VOID va_spec_objname_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_spec_vlist_list_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_spec_vlist_name_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_vlist_alt_acc_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_vlist_alt_acc_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_vlist_useq_cstr_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_vlist_var_spec_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_vlist_useq_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_var_spec_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID var_spec_type_spec (ASN1_DEC_CTXT *aCtx);
static ST_VOID var_spec_objname_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID var_spec_address_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID var_spec_var_descr_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID var_spec_scat_acc_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID var_spec_get_null (ASN1_DEC_CTXT *aCtx);
static ST_VOID alt_access_get_aa_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID scat_access_get_sa_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID type_spec_get_tspec_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID vdata_get_data_done  (ASN1_DEC_CTXT *aCtx);
static ST_VOID access_rslt_get_data_done  (ASN1_DEC_CTXT *aCtx);
static ST_VOID access_rslt_cstr_parse  (ASN1_DEC_CTXT *aCtx, ST_UINT16 id);
static ST_VOID access_rslt_get_result (ASN1_DEC_CTXT *aCtx, ST_UINT16 id);
static ST_VOID address_unc_addr_cstr_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID address_get_num_addr  (ASN1_DEC_CTXT *aCtx);
static ST_VOID address_get_sym_addr  (ASN1_DEC_CTXT *aCtx);
static ST_VOID address_get_unc_addr  (ASN1_DEC_CTXT *aCtx);
static ST_VOID address_unc_addr_cstr (ASN1_DEC_CTXT *aCtx);
static ST_VOID (*get_va_address_done) (ASN1_DEC_CTXT *aCtx);
static ST_VOID (*get_va_access_rslt_done) (ASN1_DEC_CTXT *aCtx);
static ST_VOID (*get_va_data_done) (ASN1_DEC_CTXT *aCtx);
static ST_VOID (*get_va_type_spec_done) (ASN1_DEC_CTXT *aCtx);
static ST_VOID (*get_va_scat_access_done) (ASN1_DEC_CTXT *aCtx);
static ST_VOID (*get_va_alt_access_done) (ASN1_DEC_CTXT *aCtx);
static ST_VOID (*get_va_var_spec_done) (ASN1_DEC_CTXT *aCtx);
static ST_VOID (*get_va_spec_done) (ASN1_DEC_CTXT *aCtx);
static ST_VOID var_spec_cstr_get_done (ASN1_DEC_CTXT *aCtx);
static ST_VOID va_spec_done (ASN1_DEC_CTXT *aCtx);

/************************************************************************/
/*			global structures & functions			*/
/************************************************************************/

static VAR_ACC_ADDR     *addr_ptr;
static ACCESS_RESULT    *acc_rslt_ptr;
static VAR_ACC_DATA     *vdata_ptr;
static VAR_ACC_TSPEC    *tspec_ptr;
static SCATTERED_ACCESS *scat_acc_ptr;
static ALTERNATE_ACCESS *alt_acc_ptr;
static VARIABLE_SPEC    *var_spec_ptr;
static VARIABLE_LIST    *var_list_ptr;
static VAR_ACC_SPEC     *va_spec_ptr;
static VARIABLE_LIST    *va_spec_vlist_ptr;

static ST_INT *NUM_OF_VARS;
static ST_INT  MAX_VARS;
static ST_RET  ERROR_CODE;
static ST_INT  save_dec_method;

/************************************************************************/
/************************************************************************/
/*			_ms_get_va_address					*/
/* Function to get a variable access address from the received message. */
/************************************************************************/

ST_VOID _ms_get_va_address (ASN1_DEC_CTXT *aCtx, VAR_ACC_ADDR *data_ptr, ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {

			/* set decode error for request or response	*/
  if (_mmsdec_rslt->type == MMSRESP)
    ERROR_CODE = RESP_BAD_VALUE;
  else
    ERROR_CODE = REQ_BAD_VALUE;

  addr_ptr = data_ptr;
  get_va_address_done = done_fun;

  ASN1R_TAG_ADD (aCtx, CTX, 	 0, address_get_num_addr);
  ASN1R_TAG_ADD (aCtx, CTX, 	 1, address_get_sym_addr);
  ASN1R_TAG_ADD (aCtx, CTX, 	 2, address_get_unc_addr);
  ASN1R_TAG_ADD (aCtx, CTX | CONSTR, 2, address_unc_addr_cstr);
  }

/************************************************************************/
/*			address_get_num_addr				*/
/* numeric address was encountered.					*/
/************************************************************************/

static ST_VOID address_get_num_addr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("get_num_addr");

  addr_ptr->addr_tag = 0;		/* set tag to numeric address	*/

					/* read numeric address 	*/
  if (asn1r_get_u32 (aCtx, &addr_ptr->addr.num_addr))
    asn1r_set_dec_err (aCtx, ERROR_CODE);

  (*get_va_address_done) (aCtx);		/* all done, call user set fun	*/
  }

/************************************************************************/
/*			address_get_sym_addr				*/
/* symbolic address was encountered.					*/
/************************************************************************/

static ST_VOID address_get_sym_addr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("address_get_sym_addr");

  addr_ptr->addr_tag = 1;		/* set tag to symbolic address	*/

	/* decode symbolic address onto itself, shifted by 1 ST_CHAR	*/
  addr_ptr->addr.sym_addr = (ST_CHAR *) aCtx->asn1r_field_ptr - 1;
					/* read symbolic address	*/
  if (asn1r_get_vstr (aCtx, addr_ptr->addr.sym_addr))
    asn1r_set_dec_err (aCtx, ERROR_CODE);

  (*get_va_address_done) (aCtx);		/* all done, call user set fun	*/
  }

/************************************************************************/
/*			address_get_unc_addr				*/
/* unconstrained address primitive was encountered.			*/
/************************************************************************/

static ST_VOID address_get_unc_addr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("address_get_unc_addr");

  addr_ptr->addr_tag = 2;		/* set tag to unconstrained	*/

	/* decode unconstrained address onto itself, shifted by 1 ST_CHAR	*/
  addr_ptr->addr.unc_addr.unc_ptr = aCtx->asn1r_field_ptr - 1;
					/* read unconstrained address	*/
  if (asn1r_get_octstr (aCtx, addr_ptr->addr.unc_addr.unc_ptr))
    asn1r_set_dec_err (aCtx, ERROR_CODE);
					/* save the address length	*/
  addr_ptr->addr.unc_addr.unc_len = aCtx->asn1r_octetcount;

  (*get_va_address_done) (aCtx);		/* all done, call user set fun	*/
  }

/************************************************************************/
/*			address_unc_addr_cstr				*/
/* unconstrained address constructor was encountered.			*/
/************************************************************************/

static ST_VOID address_unc_addr_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("address_unc_addr_cstr");

  addr_ptr->addr_tag = 2;		/* set tag to unconstrained	*/

	/* decode unconstrained address onto itself, shifted by 1 ST_CHAR	*/
  addr_ptr->addr.unc_addr.unc_ptr = aCtx->asn1r_field_ptr - 1;

			/* set up where to go when done decoding cstr	*/
  aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = address_unc_addr_cstr_done;

			/* read unconstrained address from message	*/
  asn1r_get_octstr_cstr (aCtx, _mmsdec_msglen, addr_ptr->addr.unc_addr.unc_ptr);
  }

/************************************************************************/
/*			address_unc_addr_cstr_done			*/
/* unconstrained address constructor done was encountered.		*/
/************************************************************************/

static ST_VOID address_unc_addr_cstr_done (ASN1_DEC_CTXT *aCtx)
  {
					/* save the address length	*/
  addr_ptr->addr.unc_addr.unc_len = aCtx->asn1r_octetcount;

  (*get_va_address_done) (aCtx);		/* all done, call user set fun	*/
  }


/************************************************************************/
/************************************************************************/
/*			_ms_get_va_access_rslt				*/
/* Function to get a variable access access result from the received	*/
/* message.								*/
/************************************************************************/

ST_VOID _ms_get_va_access_rslt (ASN1_DEC_CTXT *aCtx, ACCESS_RESULT *data_ptr,
	ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {
			/* set decode error for request or response	*/
  if (_mmsdec_rslt->type == MMSRESP)
    ERROR_CODE = RESP_BAD_VALUE;
  else
    ERROR_CODE = REQ_BAD_VALUE;

  acc_rslt_ptr = data_ptr;
  get_va_access_rslt_done = done_fun;

  acc_rslt_ptr->va_data.data = aCtx->asn1r_field_ptr;	/* set data pointer	*/

  save_dec_method = aCtx->asn1r_decode_method;
  aCtx->asn1r_decode_method   = ASN1_CLASS_METHOD;

  aCtx->asn1r_c_id_fun = access_rslt_get_result;		/* decode access result */
  aCtx->asn1r_u_id_fun = asn1r_class_err; 			/* no universals	*/
  aCtx->asn1r_a_id_fun = asn1r_class_err; 			/* no applications	*/
  aCtx->asn1r_p_id_fun = asn1r_class_err; 			/* no privates		*/
  }

/************************************************************************/
/*			access_rslt_get_result				*/
/* get access result.							*/
/************************************************************************/

static ST_VOID access_rslt_get_result (ASN1_DEC_CTXT *aCtx, ST_UINT16 id)
  {
  MLOG_CDEC0 ("access_rslt_get_result");

  if (aCtx->asn1r_constr_elmnt)
    {					/* constructor, success 	*/
    acc_rslt_ptr->acc_rslt_tag = ACC_RSLT_SUCCESS;
    aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = access_rslt_get_data_done;
    aCtx->asn1r_c_id_fun = access_rslt_cstr_parse;	/* decode access result */
    }
  else
    {					/* primitive			*/
    if (id != 0)
      { 				/* success			*/
      acc_rslt_ptr->acc_rslt_tag = ACC_RSLT_SUCCESS;
      aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len;		/* move past data element	*/
      access_rslt_get_data_done (aCtx);
      }
    else
      { 				  /* failure			*/
      acc_rslt_ptr->acc_rslt_tag = ACC_RSLT_FAILURE;
					  /* read data access error	*/
      if (asn1r_get_i16 (aCtx, &acc_rslt_ptr->failure))
	asn1r_set_dec_err (aCtx, ERROR_CODE);
      /* NOTE: DataAccessError should be [0-11] but allow any val here.	*/

      aCtx->asn1r_decode_method = save_dec_method;	/* restore original dec method	*/
      (*get_va_access_rslt_done) (aCtx);	/* all done, call user set fun	*/
      }
    }
  }

/************************************************************************/
/*			access_rslt_cstr_parse				*/
/* in the middle of a result constructor, just accept the elements	*/
/************************************************************************/

static ST_VOID access_rslt_cstr_parse (ASN1_DEC_CTXT *aCtx, ST_UINT16 id)
  {
  MLOG_CDEC0 ("access_rslt_cstr_parse");

  if (!aCtx->asn1r_constr_elmnt)			/* if primitive, need to move	*/
    aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len;		/* aCtx->asn1r_field_ptr			*/
  else					/* if cstr, need to set cstr	*/
    aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = NULL;	/* done function == safe	*/
  }

/************************************************************************/
/*			access_rslt_get_data_done			*/
/* variable data has been obtianed.					*/
/************************************************************************/

static ST_VOID access_rslt_get_data_done (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("access_rslt_get_data_done");
					/* set the variable data length */
  acc_rslt_ptr->va_data.len = 
			aCtx->asn1r_field_ptr - acc_rslt_ptr->va_data.data;

  aCtx->asn1r_decode_method = save_dec_method;	/* restore original dec method	*/

  (*get_va_access_rslt_done) (aCtx);	/* all done, call user set fun	*/
  }


/************************************************************************/
/************************************************************************/
/*			_ms_get_va_data					*/
/* Function to get a variable access data from the received message.	*/
/************************************************************************/

ST_VOID _ms_get_va_data (ASN1_DEC_CTXT *aCtx, VAR_ACC_DATA *data_ptr, ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {

  vdata_ptr = data_ptr;
  get_va_data_done = done_fun;

  vdata_ptr->data = aCtx->asn1r_field_ptr;			/* set data pointer	*/

  asn1r_parse_next (aCtx, vdata_get_data_done);		/* parse entire element */
  }

/************************************************************************/
/*			vdata_get_data_done				*/
/* variable data has been parsed.					*/
/************************************************************************/

static ST_VOID vdata_get_data_done (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("vdata_get_data_done");
					/* set the variable data length */
  vdata_ptr->len = aCtx->asn1r_field_ptr - vdata_ptr->data;

  (*get_va_data_done) (aCtx);		/* all done, call user set fun	*/
  }


/************************************************************************/
/************************************************************************/
/*			_ms_get_va_type_spec				*/
/* Function to get a variable access type specification from the	*/
/* received message.							*/
/************************************************************************/

ST_VOID _ms_get_va_type_spec (ASN1_DEC_CTXT *aCtx, VAR_ACC_TSPEC *data_ptr,
	ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {

  tspec_ptr = data_ptr;
  get_va_type_spec_done = done_fun;

  tspec_ptr->data = aCtx->asn1r_field_ptr;			/* set data pointer	*/

  asn1r_parse_next (aCtx, type_spec_get_tspec_done);	/* parse entire element */
  }

/************************************************************************/
/*			type_spec_get_tspec_done			*/
/* valid type specification was encountered.				*/
/************************************************************************/

static ST_VOID type_spec_get_tspec_done (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("type_spec_get_tspec_done");
					/* set type specification len	*/
  tspec_ptr->len = aCtx->asn1r_field_ptr - tspec_ptr->data;

  (*get_va_type_spec_done) (aCtx);		/* all done, call user set fun	*/
  }


/************************************************************************/
/************************************************************************/
/*			_ms_get_va_scat_access				*/
/* Function to get a variable access scattered access from the received */
/* message.								*/
/************************************************************************/

ST_VOID _ms_get_va_scat_access (ASN1_DEC_CTXT *aCtx, SCATTERED_ACCESS *data_ptr,
	ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {

  scat_acc_ptr = data_ptr;
  get_va_scat_access_done = done_fun;

  scat_acc_ptr->data = aCtx->asn1r_field_ptr;		/* set data pointer	*/

  asn1r_parse_next (aCtx, scat_access_get_sa_done); 	/* parse entire element */
  }

/************************************************************************/
/*			scat_access_get_sa_done 			*/
/* scattered access universal sequence constructor was encountered.	*/
/************************************************************************/

static ST_VOID scat_access_get_sa_done (ASN1_DEC_CTXT *aCtx)
  {
					/* set scattered access len	*/
  scat_acc_ptr->len = aCtx->asn1r_field_ptr - scat_acc_ptr->data;

  (*get_va_scat_access_done) (aCtx);	/* all done, call user set fun	*/
  }


/************************************************************************/
/************************************************************************/
/*			_ms_get_va_alt_access				*/
/* Function to get a variable access alternate access from the received */
/* message.								*/
/************************************************************************/

ST_VOID _ms_get_va_alt_access (ASN1_DEC_CTXT *aCtx, ALTERNATE_ACCESS *data_ptr,
	ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {
  MLOG_CDEC0 ("_ms_get_va_alt_access");

  alt_acc_ptr = data_ptr;
  get_va_alt_access_done = done_fun;

  alt_acc_ptr->data = aCtx->asn1r_field_ptr;		/* set data pointer	*/

  asn1r_parse_cstr_contents (aCtx, alt_access_get_aa_done); /* parse entire element */
  }

/************************************************************************/
/*			alt_access_get_aa_done				*/
/* scattered access was encountered.					*/
/************************************************************************/

static ST_VOID alt_access_get_aa_done (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("alt_access_get_aa_done");
					/* set type specification len	*/
  alt_acc_ptr->len = aCtx->asn1r_field_ptr - alt_acc_ptr->data;

  (*get_va_alt_access_done) (aCtx); 	/* all done, call user set fun	*/
  }


/************************************************************************/
/************************************************************************/
/*			_ms_get_va_var_spec 				*/
/* Function to get a variable access variable specification from the	*/
/* received message.							*/
/************************************************************************/

ST_VOID _ms_get_va_var_spec (ASN1_DEC_CTXT *aCtx, VARIABLE_SPEC *data_ptr,
	ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {
			/* set decode error for request or response	*/
  if (_mmsdec_rslt->type == MMSRESP)
    ERROR_CODE = RESP_BAD_VALUE;
  else
    ERROR_CODE = REQ_BAD_VALUE;

  var_spec_ptr = data_ptr;
  get_va_var_spec_done = done_fun;

  ASN1R_TAG_ADD (aCtx, CTX | CONSTR,  0, var_spec_objname_cstr);
  ASN1R_TAG_ADD (aCtx, CTX | CONSTR,  1, var_spec_address_cstr);
  ASN1R_TAG_ADD (aCtx, CTX | CONSTR,  2, var_spec_var_descr_cstr);
  ASN1R_TAG_ADD (aCtx, CTX | CONSTR,  3, var_spec_scat_acc_cstr);
  ASN1R_TAG_ADD (aCtx, CTX, 	  4, var_spec_get_null);
  }

/************************************************************************/
/*			var_spec_objname_cstr				*/
/* variable specification object name constructor was encountered.	*/
/************************************************************************/

static ST_VOID var_spec_objname_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("var_spec_objname_cstr");

  var_spec_ptr->var_spec_tag = 0;	/* set tag to name		*/

  _ms_get_mms_objname (aCtx, &var_spec_ptr->vs.name, var_spec_cstr_get_done);
  }

/************************************************************************/
/*			var_spec_address_cstr				*/
/* variable specification address was encountered.			*/
/************************************************************************/

static ST_VOID var_spec_address_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("var_spec_address_cstr");

  var_spec_ptr->var_spec_tag = 1;	/* set tag to address		*/

  _ms_get_va_address (aCtx, &var_spec_ptr->vs.address, var_spec_cstr_get_done);
  }

/************************************************************************/
/*			var_spec_var_descr_cstr 			*/
/* variable specification variable description constructor was		*/
/* encountered. 							*/
/************************************************************************/

static ST_VOID var_spec_var_descr_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("var_spec_var_descr_cstr");

  var_spec_ptr->var_spec_tag = 2;	/* set tag to variable descr	*/

  _ms_get_va_address (aCtx, &var_spec_ptr->vs.var_descr.address, var_spec_type_spec);
  }

/************************************************************************/
/*			var_spec_type_spec				*/
/* variable specification address is done, get the type specification.	*/
/************************************************************************/

static ST_VOID var_spec_type_spec (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("var_spec_type_spec");

  _ms_get_va_type_spec (aCtx, &var_spec_ptr->vs.var_descr.type, var_spec_cstr_get_done);
  }

/************************************************************************/
/*			var_spec_scat_acc_cstr				*/
/* variable specification scattered access constructor was encountered. */
/************************************************************************/

static ST_VOID var_spec_scat_acc_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("var_spec_scat_acc_cstr");

  var_spec_ptr->var_spec_tag = 3;	/* set tag to scattered access	*/

  _ms_get_va_scat_access (aCtx, &var_spec_ptr->vs.sa_descr, var_spec_cstr_get_done);
  }

/************************************************************************/
/*			var_spec_get_null				*/
/* variable specification null was encountered. 			*/
/************************************************************************/

static ST_VOID var_spec_get_null (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("var_spec_get_null");

  var_spec_ptr->var_spec_tag = 4;	/* set tag to variable descr	*/

  if (aCtx->asn1r_elmnt_len != 0)
    {
    asn1r_set_dec_err (aCtx, ERROR_CODE);
    return;
    }

  (*get_va_var_spec_done) (aCtx);		/* all done, call user set fun	*/
  }

/************************************************************************/
/*			var_spec_cstr_get_done				*/
/* variable specification object name constructor done was encountered. */
/************************************************************************/

static ST_VOID var_spec_cstr_get_done (ASN1_DEC_CTXT *aCtx)
  {

  aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = va_var_spec_done;
  }

/************************************************************************/
/*			va_var_spec_done				*/
/* variable specification has been obtained, return to set-up function. */
/************************************************************************/

static ST_VOID va_var_spec_done (ASN1_DEC_CTXT *aCtx)
  {
  (*get_va_var_spec_done) (aCtx);		/* all done, call user set fun	*/
  }


/************************************************************************/
/************************************************************************/
/*			_ms_get_va_var_list					*/
/* Function to get a variable access variable list from the received	*/
/* message.								*/
/************************************************************************/

ST_VOID _ms_get_va_var_list (ASN1_DEC_CTXT *aCtx, VARIABLE_LIST *data_ptr, ST_INT *num_of_vars,
	ST_INT max_vars, ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {
			/* set decode error for request or response	*/
  if (_mmsdec_rslt->type == MMSRESP)
    ERROR_CODE = RESP_BAD_VALUE;
  else
    ERROR_CODE = REQ_BAD_VALUE;

  var_list_ptr = data_ptr;
  NUM_OF_VARS  = num_of_vars;
  MAX_VARS     = max_vars;
  *NUM_OF_VARS = 0;	  		/* initialize # of variables	*/

  ASN1R_TAG_ADD (aCtx, UNI | CONSTR, SEQ_CODE, va_vlist_useq_cstr);
  aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = done_fun;		/* can be empty list	*/
  }

/************************************************************************/
/*			va_vlist_useq_cstr				*/
/* variable access variable list universal sequence was encountered.	*/
/************************************************************************/

static ST_VOID va_vlist_useq_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("va_vlist_useq_cstr");

  (*NUM_OF_VARS)++;			/* increment # of variables	*/
  if (*NUM_OF_VARS > MAX_VARS)
    asn1r_set_dec_err (aCtx, ERROR_CODE);

  var_list_ptr->alt_access_pres = SD_FALSE;

  _ms_get_va_var_spec (aCtx, &var_list_ptr->var_spec, va_vlist_var_spec_done);
  }

/************************************************************************/
/*			va_vlist_var_spec_done				*/
/* variable access variable specification done, get alternate access.	*/
/************************************************************************/

static ST_VOID va_vlist_var_spec_done (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("va_vlist_var_spec_done");

  ASN1R_TAG_ADD (aCtx, CTX | CONSTR,  5, va_vlist_alt_acc_cstr);

  aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = va_vlist_useq_cstr_done;
  }

/************************************************************************/
/*			va_vlist_alt_acc_cstr				*/
/* variable access variable list alternate access constructor was	*/
/* encountered. 							*/
/************************************************************************/

static ST_VOID va_vlist_alt_acc_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("va_vlist_alt_acc_cstr");

  var_list_ptr->alt_access_pres = SD_TRUE; /* set alternate access present */

  _ms_get_va_alt_access (aCtx, &var_list_ptr->alt_access, va_vlist_alt_acc_done);
  }

/************************************************************************/
/*			va_vlist_alt_acc_done				*/
/* variable specification alternate access has been obtained.		*/
/************************************************************************/

static ST_VOID va_vlist_alt_acc_done (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("va_vlist_alt_acc_done");
  }


/************************************************************************/
/*			va_vlist_useq_cstr_done 			*/
/* variable access variable list universal sequence constructor done	*/
/* was encountered.							*/
/************************************************************************/

static ST_VOID va_vlist_useq_cstr_done (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("va_vlist_useq_cstr_done");
  var_list_ptr++;			/* point to where next will go	*/

  ASN1R_TAG_ADD (aCtx, UNI | CONSTR, SEQ_CODE, va_vlist_useq_cstr);
  }


/************************************************************************/
/************************************************************************/
/*			_ms_get_va_spec					*/
/* Function to get a variable access specification from the received	*/
/* message.								*/
/************************************************************************/

ST_VOID _ms_get_va_spec (ASN1_DEC_CTXT *aCtx, VAR_ACC_SPEC *data_ptr, ST_INT max_vars,
	ST_VOID (*done_fun) (ASN1_DEC_CTXT *aCtx))
  {

			/* set decode error for request or response	*/
  if (_mmsdec_rslt->type == MMSRESP)
    ERROR_CODE = RESP_BAD_VALUE;
  else
    ERROR_CODE = REQ_BAD_VALUE;

  va_spec_ptr = data_ptr;
  va_spec_vlist_ptr = (VARIABLE_LIST *) (va_spec_ptr + 1);
  MAX_VARS    = max_vars;
  get_va_spec_done = done_fun;

  ASN1R_TAG_ADD (aCtx, CTX | CONSTR,  0, va_spec_vlist_list_cstr);
  ASN1R_TAG_ADD (aCtx, CTX | CONSTR,  1, va_spec_vlist_name_cstr);
  }

/************************************************************************/
/*			va_spec_vlist_list_cstr 			*/
/* variable access specification list of variables constructor was	*/
/* encountered. 							*/
/************************************************************************/

static ST_VOID va_spec_vlist_list_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("va_spec_vlist_list_cstr");

  va_spec_ptr->var_acc_tag = 0; 	/* set tag to list of variables	*/

  _ms_get_va_var_list (aCtx, va_spec_vlist_ptr, &va_spec_ptr->num_of_variables,
  			MAX_VARS, va_spec_done);
  }

/************************************************************************/
/*			va_spec_vlist_name_cstr 			*/
/* variable access specification variable list name constructor was	*/
/* encountered. 							*/
/************************************************************************/

static ST_VOID va_spec_vlist_name_cstr (ASN1_DEC_CTXT *aCtx)
  {
  MLOG_CDEC0 ("va_spec_vlist_name_cstr");

  va_spec_ptr->var_acc_tag = 1; 	/* set tag to var list name	*/

  _ms_get_mms_objname (aCtx, &va_spec_ptr->vl_name, va_spec_objname_done);
  }

/************************************************************************/
/*			va_spec_objname_done				*/
/* variable access specification variable list object name is complete. */
/************************************************************************/

static ST_VOID va_spec_objname_done (ASN1_DEC_CTXT *aCtx)
  {
  aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = va_spec_done;
  }

/************************************************************************/
/*			va_spec_done					*/
/* variable access specification has been obtained, return to set-up	*/
/* function.								*/
/************************************************************************/

static ST_VOID va_spec_done (ASN1_DEC_CTXT *aCtx)
  {
  (*get_va_spec_done) (aCtx);		/* all done, call user set fun	*/
  }

/************************************************************************/
/************************************************************************/
/*			_ms_wr_va_address					*/
/* Function to write a variable access address to the message.		*/
/************************************************************************/

ST_VOID _ms_wr_va_address (ASN1_ENC_CTXT *aCtx, VAR_ACC_ADDR *data_ptr)
  {
  switch (data_ptr->addr_tag)
    {
    case (0)  : 			/* write the numeric address	*/
      asn1r_wr_u32 (aCtx, data_ptr->addr.num_addr);
      asn1r_fin_prim (aCtx, 0, CTX);		/* context tag 0		*/
      break;

    case (1)  : 			/* write the symbolic address	*/
      asn1r_wr_vstr (aCtx, data_ptr->addr.sym_addr);
      asn1r_fin_prim (aCtx, 1,CTX); 		/* context tag 1		*/
      break;

    case (2)  : 			/* write the unconstrained addr */
      asn1r_wr_octstr (aCtx, data_ptr->addr.unc_addr.unc_ptr,
		 data_ptr->addr.unc_addr.unc_len);
      asn1r_fin_prim (aCtx, 2,CTX); 		/* context tag 2		*/
      break;
    }
  }

/************************************************************************/
/*			_ms_wr_va_access_rslt				*/
/* Function to write a variable access access result to the message.	*/
/************************************************************************/

ST_VOID _ms_wr_va_access_rslt (ASN1_ENC_CTXT *aCtx, ACCESS_RESULT *data_ptr)
  {
  if (data_ptr->acc_rslt_tag == ACC_RSLT_SUCCESS)
    _ms_wr_va_data (aCtx, &data_ptr->va_data);	/* success, write data		*/
  else
    {					/* failure, write failure value */
    asn1r_wr_i16 (aCtx, data_ptr->failure);
    asn1r_fin_prim (aCtx, 0, CTX);			/* context tag 0		*/
    }
  }

/************************************************************************/
/*			_ms_wr_va_data					*/
/* Function to write a variable access data to the message.		*/
/************************************************************************/

ST_VOID _ms_wr_va_data (ASN1_ENC_CTXT *aCtx, VAR_ACC_DATA *data_ptr)
  {
  asn1r_wr_delmnt (aCtx, data_ptr->data, data_ptr->len);
  }

/************************************************************************/
/*			_ms_wr_va_type_spec 				*/
/* Function to write a variable access type specification to the	*/
/* message.								*/
/************************************************************************/

ST_VOID _ms_wr_va_type_spec (ASN1_ENC_CTXT *aCtx, VAR_ACC_TSPEC *data_ptr)
  {
  asn1r_wr_delmnt (aCtx, data_ptr->data, data_ptr->len);
  }

/************************************************************************/
/*			_ms_wr_va_scat_access				*/
/* Function to write a variable access scattered access to the message. */
/************************************************************************/

ST_VOID _ms_wr_va_scat_access (ASN1_ENC_CTXT *aCtx, SCATTERED_ACCESS *data_ptr)
  {
  asn1r_wr_delmnt (aCtx, data_ptr->data, data_ptr->len);
  }

/************************************************************************/
/*			_ms_wr_va_alt_access				*/
/* Function to write a variable access alternate access to the message. */
/************************************************************************/

ST_VOID _ms_wr_va_alt_access (ASN1_ENC_CTXT *aCtx, ALTERNATE_ACCESS *data_ptr)
  {
  asn1r_wr_delmnt (aCtx, data_ptr->data, data_ptr->len);
  }

/************************************************************************/
/*			_ms_wr_va_var_spec					*/
/* Function to write a variable access variable specification to the	*/
/* message.								*/
/************************************************************************/

ST_VOID _ms_wr_va_var_spec (ASN1_ENC_CTXT *aCtx, VARIABLE_SPEC *data_ptr)
  {
  switch (data_ptr->var_spec_tag)
    {
    case   0 :
      asn1r_strt_constr (aCtx);
      _ms_wr_mms_objname (aCtx, &data_ptr->vs.name);
      asn1r_fin_constr (aCtx, 0, CTX, DEF);
      break;

    case   1 :
      asn1r_strt_constr (aCtx);
      _ms_wr_va_address (aCtx, &data_ptr->vs.address);
      asn1r_fin_constr (aCtx, 1, CTX, DEF);
      break;

    case   2 :
      asn1r_strt_constr (aCtx);
      _ms_wr_va_type_spec (aCtx, &data_ptr->vs.var_descr.type);
      _ms_wr_va_address (aCtx, &data_ptr->vs.var_descr.address);
      asn1r_fin_constr (aCtx, 2, CTX, DEF);
      break;

    case   3 :
      asn1r_strt_constr (aCtx);
      _ms_wr_va_scat_access (aCtx, &data_ptr->vs.sa_descr);
      asn1r_fin_constr (aCtx, 3, CTX, DEF);
      break;

    case   4 :
      asn1r_fin_prim (aCtx, 4, CTX);
      break;
    }
  }

/************************************************************************/
/*			_ms_wr_va_var_list					*/
/* Function to write a variable access variable list to the message.	*/
/************************************************************************/

ST_VOID _ms_wr_va_var_list (ASN1_ENC_CTXT *aCtx, VARIABLE_LIST *data_ptr, ST_INT num_of_vars)
  {
VARIABLE_LIST *vl_ptr;
ST_INT i;

  vl_ptr = data_ptr;
  vl_ptr += num_of_vars - 1; 		/* point to last in the list	*/
  for (i = 0; i < num_of_vars; i++)
    {
    asn1r_strt_constr (aCtx);			/* start universal sequece cstr */
    if (vl_ptr->alt_access_pres)
      {
      asn1r_strt_constr (aCtx); 			/* start context tag 5 cstr	*/
      _ms_wr_va_alt_access (aCtx, &vl_ptr->alt_access);
      asn1r_fin_constr (aCtx, 5, CTX, DEF);
      }
    _ms_wr_va_var_spec (aCtx, &vl_ptr->var_spec);
    asn1r_fin_constr (aCtx, SEQ_CODE, UNI, DEF);
    vl_ptr--; 				/* point to previous var name	*/
    }
  }

/************************************************************************/
/*			_ms_wr_va_spec					*/
/* Function to write a variable access specification to the message.	*/
/************************************************************************/

ST_VOID _ms_wr_va_spec (ASN1_ENC_CTXT *aCtx, VAR_ACC_SPEC *data_ptr)
  {
VARIABLE_LIST *vl_ptr;

  if (data_ptr->var_acc_tag == 1)
    {
    asn1r_strt_constr (aCtx);			/* start context tag 1 cstr	*/
    _ms_wr_mms_objname (aCtx, &data_ptr->vl_name);
    asn1r_fin_constr (aCtx, 1, CTX, DEF);
    }
  else
    {
    vl_ptr = (VARIABLE_LIST *) (data_ptr + 1);
    asn1r_strt_constr (aCtx);			/* start context tag 0 cstr	*/
    _ms_wr_va_var_list (aCtx, vl_ptr, data_ptr->num_of_variables);
    asn1r_fin_constr (aCtx, 0, CTX, DEF);
    }
  }
