/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/*   (c) Copyright Systems Integration Specialists Company, Inc.,	*/
/*      	  1986 - 2002, All Rights Reserved.		        */
/*									*/
/*		    PROPRIETARY AND CONFIDENTIAL			*/
/*									*/
/* MODULE NAME : mms_rej.c						*/
/* PRODUCT(S)  : MMSEASE, MMSEASE-LITE					*/
/*									*/
/* MODULE DESCRIPTION : 						*/
/*	This module contains the functions to decode/encode a reject	*/
/*	operation.							*/
/*									*/
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE :				*/
/*									*/
/* MODIFICATION LOG :							*/
/*  Date     Who   Rev			Comments			*/
/* --------  ---  ------   -------------------------------------------	*/
/* 03/11/04  GLB     06    Cleaned up "thisFileName"                    */
/* 01/18/02  JRB     05    Fix encoding if !DEBUG_SISCO (use new fcts	*/
/*			   _ms_fin_pdu & _ms_fin_pdu_log.		*/
/* 12/20/01  JRB     04    Converted to use ASN1R (re-entrant ASN1)	*/
/* 09/13/99  MDE     03    Added SD_CONST modifiers			*/
/* 03/23/99  MDE     02    Changes to decode buffer allocation scheme	*/
/* 07/03/97  MDE     01    Op-specific info buffer handling changes	*/
/* 04/02/97  DTL   7.00    MMSEASE 7.0 release. See MODL70.DOC for	*/
/*			   history.					*/
/************************************************************************/

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

#include "mmsdefs.h"
#include "mms_pcon.h"
#include "asn1defs.h"

/************************************************************************/
/* For debug version, use a static pointer to avoid duplication of 	*/
/* __FILE__ strings.							*/

#if defined(DEBUG_SISCO) && defined(S_MT_SUPPORT)
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif

/************************************************************************/

static  REJECT_RESP_INFO	*rej_info_ptr;

static ST_VOID rej_get_problem (ASN1_DEC_CTXT *aCtx, ST_UINT16 id_code);


/************************************************************************/
/************************************************************************/
/*			mms_reject					*/
/* Reject PDU is being decoded, and this is a context-specific element. */
/* It should be an integer.						*/
/************************************************************************/

ST_VOID mms_reject (ASN1_DEC_CTXT *aCtx, ST_UINT16 id_code)
  {
  MLOG_CDEC0 ("mms_reject");

  if (aCtx->asn1r_constr_elmnt)
    {
    asn1r_set_dec_err (aCtx, PDU_INVALID);
    return;
    }

  rej_info_ptr = (REJECT_RESP_INFO *) 	_m_get_dec_buf (aCtx, sizeof (REJECT_RESP_INFO));
  aCtx->asn1r_decode_method = ASN1_CLASS_METHOD; 
  rej_info_ptr -> detected_here = SD_FALSE;   /* reject detected remotely	*/
  rej_info_ptr -> pdu_type = UNKNOWNTYPE;  /* in this case, no pdu type */

  if (!id_code)				/* if this is invoke id -	*/
    {
    if (asn1r_get_u32 (aCtx, &rej_info_ptr -> invoke)) /* read invoke id 	*/
      asn1r_set_dec_err (aCtx, PDU_INVALID);
    else
      {
      rej_info_ptr -> invoke_known = SD_TRUE;	/* set flag 		*/
      _mmsdec_rslt -> dec_level = 2;
      _mmsdec_rslt -> id = rej_info_ptr -> invoke; /* store invoke ID 	*/
      aCtx->asn1r_c_id_fun = rej_get_problem;
      }
    }
  else
    {
    rej_info_ptr -> invoke_known = SD_FALSE;	/* clear		*/
    rej_get_problem (aCtx, id_code);		/* call rejectreason fun direct	*/
    }
  }

/************************************************************************/
/*			rej_get_problem					*/
/* Reject PDU is being decoded, and this is a context-specific element. */
/* It should be an integer in which the tag is the error class and the	*/
/* value is the error code.						*/
/************************************************************************/

static ST_VOID rej_get_problem (ASN1_DEC_CTXT *aCtx, ST_UINT16 id_code)
  {
  MLOG_CDEC0 ("rej_get_problem");

  if (aCtx->asn1r_constr_elmnt || id_code < 1 || id_code > 11 || aCtx->asn1r_elmnt_len > 1)
    {					/* better not be constructor	*/
    asn1r_set_dec_err (aCtx, PDU_INVALID);		/* better be context tagged 1-4 */
    return;				/* max value = 8		*/
    }

/* Information looks OK; extract it.					*/

  rej_info_ptr -> rej_class = id_code;
  asn1r_get_i16 (aCtx, &rej_info_ptr -> rej_code);	/* get the problem value	*/

  aCtx->asn1r_decode_done_fun = _mms_dec_done_ok;	/* all done now 		*/
  aCtx->asn1r_decode_done = SD_TRUE;
  }

#ifndef MMS_LITE
/************************************************************************/
/************************************************************************/
/*			mp_reject_resp					*/
/* Sends reject message.  Returns integer value indicating success	*/
/* (value = 0) or failure (value <> 0) to send the reject message.	*/
/************************************************************************/

ST_RET mp_reject_resp (ST_INT chan, REJECT_RESP_INFO *info_ptr)
  {
ST_UCHAR	*msg_ptr;
ST_INT		msg_len;
LLP_ADDR_INFO add_llp_info;
ST_RET ret;
ASN1_ENC_CTXT localEncCtx;	/* For readability, use "aCtx" to access this.*/
ASN1_ENC_CTXT *aCtx = &localEncCtx;

  S_LOCK_COMMON_RESOURCES ();
  msg_ptr = _ms_mk_reject (aCtx, m_build_buf,mms_max_msgsize,info_ptr);
  msg_len = M_BUILD_BUF_END - msg_ptr; 	/* find length		*/

  add_llp_info.i.LLC.use_rem_addr = SD_FALSE;
  add_llp_info.i.LLC.send_type = REJECT_PDU;
  add_llp_info.i.LLC.req_ptr = (ST_CHAR *)NULL;

/* Check for encode overrun */
  if (aCtx->asn1r_encode_overrun)
    ret = ME_ASN1_ENCODE_OVERRUN;
  else
    ret = _mms_send_data (chan, msg_len, msg_ptr, P_context_sel[chan], &add_llp_info);

  S_UNLOCK_COMMON_RESOURCES ();
  return (ret);
  }

#else
/************************************************************************/
/************************************************************************/
/*			mpl_reject_resp					*/
/* Sends reject message.  Returns integer value indicating success	*/
/* (value = 0) or failure (value <> 0) to send the reject message.	*/
/************************************************************************/

ST_RET mpl_reject_resp (REJECT_RESP_INFO *info_ptr)
  {
ST_RET ret;
ASN1_ENC_CTXT localEncCtx;	/* For readability, use "aCtx" to access this.*/
ASN1_ENC_CTXT *aCtx = &localEncCtx;

  S_LOCK_COMMON_RESOURCES ();
  mmsl_msg_start = _ms_mk_reject (aCtx, mmsl_enc_buf,mmsl_enc_buf_size,info_ptr);
  						/* find length		*/
  mmsl_msg_len = (mmsl_enc_buf + mmsl_enc_buf_size) - mmsl_msg_start;

  if (aCtx->asn1r_encode_overrun)		/* Check for encode overrun	*/
    ret = ME_ASN1_ENCODE_OVERRUN;
  else
    ret = SD_SUCCESS;
  S_UNLOCK_COMMON_RESOURCES ();
  return (ret);
  }
#endif

/************************************************************************/
/*			_ms_mk_reject					*/
/* Construct a reject PDU.						*/
/************************************************************************/

ST_UCHAR *_ms_mk_reject (ASN1_ENC_CTXT *aCtx, ST_UCHAR *msg_ptr, ST_INT buf_len,
	REJECT_RESP_INFO *info_ptr)
  {
ST_UCHAR *pduStart;
ST_INT pduLen;

  asn1r_strt_asn1_bld (aCtx, msg_ptr,buf_len);	/* init the ASN.1 tools 	*/

  asn1r_wr_i16 (aCtx, info_ptr -> rej_code);
  asn1r_fin_prim (aCtx, info_ptr -> rej_class,CTX);

#ifndef MMS_LITE
  if (info_ptr->invoke_known && info_ptr->invoke <= MAX_INVOKE)
#else
  if (info_ptr->invoke_known)
#endif
    {
    asn1r_wr_u32 (aCtx, info_ptr -> invoke);	/* if the invoke ID is known &	*/
    asn1r_fin_prim (aCtx, 0,CTX);			/* is not artificial, write it	*/
    }

  pduStart = _ms_fin_pdu (aCtx, MMSREJECT, &pduLen);
#ifdef DEBUG_SISCO
  _ms_fin_pdu_log (MMSREJECT, "REJECT", pduStart, pduLen);
#endif

  return (pduStart);
  }

#ifndef MMS_LITE
/************************************************************************/
/************************************************************************/
/*			   _ms_reject_resp				*/
/* Function to reject an MMS confirmed response pdu, given the request	*/
/* control structure. This must be a valid response, parsed OK. 	*/
/* Called by the user or virtual machine after the confirm is matched.	*/
/************************************************************************/

ST_VOID _ms_reject_resp (MMSREQ_PEND *reqptr, ST_INT16 code)
  {
REJECT_RESP_INFO info;		/* reject input info structure	*/

  info.detected_here = SD_TRUE;		/* parse error detected locally */

  info.invoke_known = SD_TRUE;
  info.invoke = reqptr->id;

  info.pdu_type = MMSRESP;		/* confirmed response		*/
  info.rej_code = code; 		/* include error code		*/
  info.rej_class = 2;			/* invalid response class	*/

  if (mp_reject_resp (reqptr->chan,&info)) /* send the reject pdu	*/
    (*u_mmsexcept_ind_fun)(reqptr->chan,MX_REJECT);
  (*u_reject_ind_fun) (reqptr->chan,&info);
  }

/************************************************************************/
/*			   mp_reject_ind				*/
/************************************************************************/

ST_RET mp_reject_ind (MMSREQ_IND *req_ptr, REJECT_RESP_INFO *info_ptr)
  {
ST_RET	ret;				/* function return value	*/

  S_LOCK_COMMON_RESOURCES ();
  if (!(ret = _ms_check_ind_actv (req_ptr)))
    {
    if (!(ret = mp_reject_resp (req_ptr->chan, info_ptr)))
      _ms_ind_serve_done (req_ptr);
    }
  S_UNLOCK_COMMON_RESOURCES ();
  return (ret);
  }

/************************************************************************/
/*			   mp_reject_conf				*/
/************************************************************************/

ST_RET mp_reject_conf (MMSREQ_PEND *req_ptr, REJECT_RESP_INFO *info_ptr)
  {
ST_RET	ret;				/* function return value	*/

  S_LOCK_COMMON_RESOURCES ();
  if (!(ret = _ms_check_req_actv (req_ptr)))
    {
    ret = mp_reject_resp (req_ptr->chan, info_ptr);
    }
  S_UNLOCK_COMMON_RESOURCES ();
  return (ret);
  }

#endif
