/********************************************************************/
/*                                                                  */
/*   rfhsubs.c - Common subroutines for processing RFH headers.     */
/*                                                                  */
/********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

/* includes for MQI */
#include <cmqc.h>

/* common subroutines include */
#include "int64defs.h"
#include "comsubs.h"

#include "parmline.h"
#include "rfhsubs.h"

#define CHAR_ASCII		0
#define CHAR_EBCDIC		1

#define RFH2_JMS_DST_BEGIN "<Dst>"
#define RFH2_JMS_DST_END "</Dst>"
#define RFH2_JMS_RTO_BEGIN "<Rto>"
#define RFH2_JMS_RTO_END "</Rto>"
#define RFH2_JMS_PRI_BEGIN "<Pri>"
#define RFH2_JMS_PRI_END "</Pri>"
#define RFH2_JMS_DLV_BEGIN "<Dlv>"
#define RFH2_JMS_DLV_END "</Dlv>"
#define RFH2_JMS_EXP_BEGIN "<Exp>"
#define RFH2_JMS_EXP_END "</Exp>"
#define RFH2_JMS_CID_BEGIN "<Cid>"
#define RFH2_JMS_CID_END "</Cid>"
#define RFH2_JMS_GID_BEGIN "<Gid>"
#define RFH2_JMS_GID_END "</Gid>"
#define RFH2_JMS_SEQ_BEGIN "<Seq>"
#define RFH2_JMS_SEQ_END "</Seq>"

#define JMS_TEXT		"jms_text"
#define JMS_BYTES		"jms_bytes"
#define JMS_OBJECT		"jms_object"
#define JMS_STREAM		"jms_stream"
#define JMS_MAP			"jms_map"
#define JMS_NONE		"jms_none"

void releaseRFH(putParms * parms)

{
	if (parms->rfh_usr != NULL)
	{
		free(parms->rfh_usr);
		parms->rfh_usr = NULL;
		parms->max_usr = 0;
	}

	if (parms->rfh_jms != NULL)
	{
		free(parms->rfh_jms);
		parms->rfh_jms = NULL;
		parms->max_jms = 0;
	}

	if (parms->rfh_mcd != NULL)
	{
		free(parms->rfh_mcd);
		parms->rfh_mcd = NULL;
		parms->max_mcd = 0;
	}

	if (parms->rfh_psc != NULL)
	{
		free(parms->rfh_psc);
		parms->rfh_psc = NULL;
		parms->max_psc = 0;
	}

	if (parms->rfh_pscr != NULL)
	{
		free(parms->rfh_pscr);
		parms->rfh_pscr = NULL;
		parms->max_pscr = 0;
	}
}

/**************************************************************/
/*                                                            */
/* Routine to replace certain special characters with their   */
/* respective escape sequences, as follows:                   */
/*                                                            */
/* & &amp;                                                    */
/* " &quot;                                                   */
/* < &gt;                                                     */
/* > &lt;                                                     */
/* ' &apos;                                                   */
/*                                                            */
/**************************************************************/

void replaceChars(const char *value, char *valStr)

{
	int		i=0;
	int		j=0;
	int		len;

	/* get the total length of the input string */
	len = strlen(value);

	while (i < len)
	{
		switch (value[i])
		{
		case '&':
			{
				valStr[j++] = '&';
				valStr[j++] = 'a';
				valStr[j++] = 'm';
				valStr[j++] = 'p';
				valStr[j++] = ';';
				break;
			}
		case '<':
			{
				valStr[j++] = '&';
				valStr[j++] = 'l';
				valStr[j++] = 't';
				valStr[j++] = ';';
				break;
			}
		case '>':
			{
				valStr[j++] = '&';
				valStr[j++] = 'g';
				valStr[j++] = 't';
				valStr[j++] = ';';
				break;
			}
		case '"':
			{
				valStr[j++] = '&';
				valStr[j++] = 'q';
				valStr[j++] = 'u';
				valStr[j++] = 'o';
				valStr[j++] = 't';
				valStr[j++] = ';';
				break;
			}
		case '\'':
			{
				valStr[j++] = '&';
				valStr[j++] = 'a';
				valStr[j++] = 'p';
				valStr[j++] = 'o';
				valStr[j++] = 's';
				valStr[j++] = ';';
				break;
			}
		default:
			{
				valStr[j++] = value[i];
			}
		}

		i++;
	}

	/* terminate the result string */
	valStr[j] = 0;
}

/**************************************************************/
/*                                                            */
/* Routine to determine if a code page is ASCII or EBCDIC     */
/*                                                            */
/**************************************************************/

int getCcsidType(const int ccsid)

{
	int	result= CHAR_ASCII;

	if ((ccsid == 037) || (ccsid == 500) ||
		(ccsid == 924) || (ccsid == 1140) ||
		(ccsid == 273) || (ccsid == 1141) ||
		(ccsid == 273) || (ccsid == 1142) ||
		(ccsid == 277) || (ccsid == 1143) ||
		(ccsid == 278) || (ccsid == 1144) ||
		(ccsid == 284) || (ccsid == 1145) ||
		(ccsid == 285) || (ccsid == 1146) ||
		(ccsid == 297) || (ccsid == 1147) ||
		(ccsid == 871) || (ccsid == 1148) ||
		(ccsid == 870) || (ccsid == 1149))
	{
		result = CHAR_EBCDIC;
	}

	return result;
}

/**************************************************************/
/*                                                            */
/* Routine to construct an RFH V1 header.                     */
/*                                                            */
/**************************************************************/

int buildRFH1(char * rfhdata, putParms *parms)

{
	unsigned int	varlength;
	MQRFH	tempRFH;
	char	tempfield[1024];

	/* get a pointer to the area to build the non-fixed part of the RFH */
	memset(tempfield, 0, sizeof(tempfield));

	/* move in the identifier */
	strcpy(tempfield, MQNVS_APPL_TYPE);

	/* get the application group name */
	strcat(tempfield, parms->rfhappgroup);
	strcat(tempfield, " ");

	/* next, copy in the message type name */
	strcat(tempfield, MQNVS_MSG_TYPE);

	/* get the message type into a string */
	strcat(tempfield, parms->rfhformat);

	/* calculate the length of the variable part of the rfh */
	varlength = strlen(tempfield);

	/* Round it up to a multiple of 4 if necessary */
	if ((varlength % 4) > 0)
	{
		varlength += 4 - (varlength % 4);
	}

	while (strlen(tempfield) < varlength)
	{
		strcat(tempfield, " ");
	}

	/* check if we need to translate the variable rfh data to EBCDIC */
	if (getCcsidType(parms->rfhccsid) == CHAR_ASCII)
	{
		/* ASCII, no need to translate */
		memcpy(rfhdata + MQRFH_STRUC_LENGTH_FIXED, tempfield, varlength);
	}
	else
	{
		/* translate to EBCDIC */
		AsciiToEbcdic((unsigned char *)rfhdata + MQRFH_STRUC_LENGTH_FIXED, (unsigned char *)tempfield, varlength);
	}

	/* initialize the header */
	tempRFH.Version = MQRFH_VERSION_1;
	tempRFH.StrucLength = MQRFH_STRUC_LENGTH_FIXED + varlength;
	tempRFH.Flags = MQRFH_NONE;

	/* was the RFH encoding field specified? */
	if (parms->rfhencoding > 0)
	{
		/* set the encoding for the user data */
		tempRFH.Encoding = parms->rfhencoding;
	}
	else
	{
		/* use a default if not set */
		tempRFH.Encoding = MQENC_NATIVE;
	}

	/* get the code page of the user data */
	if (parms->rfhccsid > 0)
	{
		tempRFH.CodedCharSetId = parms->rfhccsid;
	}
	else
	{
		/* use a default if not set */
		tempRFH.CodedCharSetId = MQCCSI_INHERIT;
	}

	/* find out if the character set is EBCDIC */
	if (getCcsidType(parms->codepage) == CHAR_ASCII)
	{
		/* ASCII - no need to translate */
		memcpy(tempRFH.StrucId, MQRFH_STRUC_ID, sizeof(tempRFH.StrucId));
		memcpy(tempRFH.Format, parms->msgformat, MQ_FORMAT_LENGTH);
	}
	else
	{
		/* EBCDIC - must translate from ASCII */
		AsciiToEbcdic((unsigned char *)tempRFH.StrucId, (unsigned char *)MQRFH_STRUC_ID, sizeof(tempRFH.StrucId));
		AsciiToEbcdic((unsigned char *)tempRFH.Format, (unsigned char *)&(parms->msgformat), MQ_FORMAT_LENGTH);
	}

	/* check if the encoding is host integers */
#if defined WIN32 || defined __i386__
	if ((parms->encoding & MQENC_INTEGER_REVERSED) == 0)
#else
	if ((parms->encoding & MQENC_INTEGER_REVERSED) != 0)
#endif
	{
		/* we need to reverse the integers in all of the RFH header fields */
		tempRFH.Version        = reverseBytes4(tempRFH.Version);
		tempRFH.StrucLength    = reverseBytes4(tempRFH.StrucLength);
		tempRFH.Encoding       = reverseBytes4(tempRFH.Encoding);
		tempRFH.CodedCharSetId = reverseBytes4(tempRFH.CodedCharSetId);
		tempRFH.Flags          = reverseBytes4(tempRFH.Flags);
	}

	/* copy the fixed portion of the header to the data area */
	memcpy(rfhdata, (char *) &tempRFH, MQRFH_STRUC_LENGTH_FIXED);

	/* return the length of the RFH header */
	return varlength + MQRFH_STRUC_LENGTH_FIXED;
}

int roundVarArea(char * varArea)

{
	int		extra;
	int		varlen;

	varlen = strlen(varArea);

	/* round to a multiple of four bytes */
	/* check if the length is already a multiple of 4 */
	extra = varlen % 4;
	if (extra > 0)
	{
		/* not a multiple of four - calculate bytes that must be added */
		extra = 4 - extra;
		varlen += extra;

		/* append the extra blanks to make a multiple of 4 */
		while (extra > 0)
		{
			strcat(varArea, " ");
			extra--;
		}
	}

	return varlen;
}

void setVarLength(void * ptr, int len, int encoding)

{
	/* set the binary length field at the front of the data */
#if defined WIN32 || defined __i386__
	if ((encoding & MQENC_INTEGER_REVERSED) == 0)
#else
	if ((encoding & MQENC_INTEGER_REVERSED) != 0)
#endif
	{
		/* we need to reverse the integers in all of the RFH header fields */
		len = reverseBytes4(len);
	}

	memcpy(ptr, (const void *) &len, 4);
}

int appendFolder(char * ptr, char * folder, int encoding)

{
	int		len = 0;

	/* check for explicit folder definiion */
	if (folder != NULL)
	{
		strcat(ptr + 4, folder);				/* append the folder data                             */
		len = roundVarArea(ptr + 4);			/* get the total length of the folder                 */
		setVarLength(ptr, len, encoding);		/* set the length field including 4 byte length field */
		len += 4;								/* remember the length of the length field            */
	}

	/* return the length of the folder */
	return len;
}

void buildJMS(putParms *parms)

{
	int		varlen=0;
	char	*varArea;
	char	tempValue[256];
	char	tempfield[1024];

	/* get a pointer to the area to use */
	varArea = parms->rfh_jms;

	tempfield[0] = 0;

	if (strlen(parms->rfh_jms_dest) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_JMS_DST_BEGIN);

		/* get the message domain name and append it to the XML message */
		replaceChars(parms->rfh_jms_dest, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_JMS_DST_END);
	}

	if (strlen(parms->rfh_jms_reply) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_JMS_RTO_BEGIN);

		/* get the message domain name and append it to the XML message */
		replaceChars(parms->rfh_jms_reply, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_JMS_RTO_END);
	}

	if (strlen(parms->rfh_jms_correlid) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_JMS_CID_BEGIN);

		/* get the message domain name and append it to the XML message */
		replaceChars(parms->rfh_jms_correlid, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_JMS_CID_END);
	}

	if (strlen(parms->rfh_jms_groupid) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_JMS_GID_BEGIN);

		/* get the message domain name and append it to the XML message */
		replaceChars(parms->rfh_jms_groupid, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_JMS_GID_END);
	}

	if (strlen(parms->rfh_jms_expire) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_JMS_EXP_BEGIN);

		/* get the message domain name and append it to the XML message */
		replaceChars(parms->rfh_jms_groupid, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_JMS_EXP_END);
	}

	if (strlen(parms->rfh_jms_delmode) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_JMS_DLV_BEGIN);

		/* get the message domain name and append it to the XML message */
		replaceChars(parms->rfh_jms_delmode, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_JMS_DLV_END);
	}

	if (strlen(parms->rfh_jms_seq) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_JMS_SEQ_BEGIN);

		/* get the message domain name and append it to the XML message */
		replaceChars(parms->rfh_jms_seq, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_JMS_SEQ_END);
	}

	if (strlen(parms->rfh_jms_priority) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_JMS_PRI_BEGIN);

		/* get the message domain name and append it to the XML message */
		replaceChars(parms->rfh_jms_priority, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_JMS_PRI_END);
	}

	/* check if we found any jms fields */
	if (tempfield[0] != 0)
	{
		/* add the XML tags and data */
		strcpy(varArea, RFH2_JMS_BEGIN);
		strcat(varArea, tempfield);
		strcat(varArea, RFH2_JMS_END);

		/* round to a multiple of four bytes */
		varlen = roundVarArea(varArea);
	}
}

void appendOption(char * tempfield, const char * optfield, int reqType)

{
	switch (reqType)
	{
	case RFH_PSC_SUB:
		{
			strcat(tempfield, RFH2_PSC_REGOPT_BEGIN);
			break;
		}
	case RFH_PSC_UNSUB:
		{
			strcat(tempfield, RFH2_PSC_REGOPT_BEGIN);
			break;
		}
	case RFH_PSC_PUB:
		{
			strcat(tempfield, RFH2_PSC_PUBOPT_BEGIN);
			break;
		}
	case RFH_PSC_REQPUB:
		{
			strcat(tempfield, RFH2_PSC_REGOPT_BEGIN);
			break;
		}
	case RFH_PSC_DELPUB:
		{
			strcat(tempfield, RFH2_PSC_DELOPT_BEGIN);
			break;
		}
	}

	strcat(tempfield, optfield);

	switch (reqType)
	{
	case RFH_PSC_SUB:
		{
			strcat(tempfield, RFH2_PSC_REGOPT_END);
			break;
		}
	case RFH_PSC_UNSUB:
		{
			strcat(tempfield, RFH2_PSC_REGOPT_END);
			break;
		}
	case RFH_PSC_PUB:
		{
			strcat(tempfield, RFH2_PSC_PUBOPT_END);
			break;
		}
	case RFH_PSC_REQPUB:
		{
			strcat(tempfield, RFH2_PSC_REGOPT_END);
			break;
		}
	case RFH_PSC_DELPUB:
		{
			strcat(tempfield, RFH2_PSC_DELOPT_END);
			break;
		}
	}
}

void buildPSC(putParms * parms)

{
	int		varlen=0;
	char	*varArea;
	char	tempValue[256];
	char	tempfield[1024];

	/* get a pointer to the area to use */
	varArea = parms->rfh_psc;

	tempfield[0] = 0;

	if (parms->rfh_psc_reqtype > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_COMMAND_BEGIN);

		/* get the command and append it to the XML message */
		switch (parms->rfh_psc_reqtype)
		{
		case RFH_PSC_SUB:
			{
				strcat(tempfield, PSC_REGSUB);
				break;
			}
		case RFH_PSC_UNSUB:
			{
				strcat(tempfield, PSC_DEREGSUB);
				break;
			}
		case RFH_PSC_PUB:
			{
				strcat(tempfield, PSC_PUBLISH);
				break;
			}
		case RFH_PSC_REQPUB:
			{
				strcat(tempfield, PSC_REQUPDATE);
				break;
			}
		case RFH_PSC_DELPUB:
			{
				strcat(tempfield, PSC_DELETEPUB);
				break;
			}
		}

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_COMMAND_END);
	}

	if (strlen(parms->rfh_topic1) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_TOPIC_BEGIN);

		/* get the topic and append it to the XML message */
		replaceChars(parms->rfh_topic1, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_TOPIC_END);
	}

	if (strlen(parms->rfh_topic2) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_TOPIC_BEGIN);

		/* get the topic and append it to the XML message */
		replaceChars(parms->rfh_topic2, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_TOPIC_END);
	}

	if (strlen(parms->rfh_topic3) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_TOPIC_BEGIN);

		/* get the topic and append it to the XML message */
		replaceChars(parms->rfh_topic3, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_TOPIC_END);
	}

	if (strlen(parms->rfh_topic4) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_TOPIC_BEGIN);

		/* get the topic and append it to the XML message */
		replaceChars(parms->rfh_topic4, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_TOPIC_END);
	}

	if (strlen(parms->rfh_subpoint) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_SUBPOINT_BEGIN);

		/* get the subscription point and append it to the XML message */
		replaceChars(parms->rfh_subpoint, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_SUBPOINT_END);
	}

	if (strlen(parms->rfh_filter) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_FILTER_BEGIN);

		/* get the filter and append it to the XML message */
		replaceChars(parms->rfh_filter, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_FILTER_END);
	}

	if (strlen(parms->rfh_PscReplyQM) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_QMGRNAME_BEGIN);

		/* get the reply queue manager name and append it to the XML message */
		replaceChars(parms->rfh_PscReplyQM, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_QMGRNAME_END);
	}

	if (strlen(parms->rfh_PscReplyQ) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_QNAME_BEGIN);

		/* get the reply queue name and append it to the XML message */
		replaceChars(parms->rfh_PscReplyQ, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_QNAME_END);
	}

	if (strlen(parms->rfh_pubtime) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_PUBTIME_BEGIN);

		/* get the pub time and append it to the XML message */
		replaceChars(parms->rfh_pubtime, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_PUBTIME_END);
	}

	if (parms->rfh_psc_seqno > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_PSC_SEQNUM_BEGIN);

		/* get the sequence number in character format and append it to the XML message */
		sprintf(tempValue, "%d", parms->rfh_psc_seqno);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_PSC_SEQNUM_END);
	}

	if (parms->rfh_psc_local > 0)
	{
		appendOption(tempfield, RFH2_PSC_LOCAL, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_newonly > 0)
	{
		appendOption(tempfield, RFH2_PSC_NEWONLY, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_otheronly > 0)
	{
		appendOption(tempfield, RFH2_PSC_OTHERONLY, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_ondemand > 0)
	{
		appendOption(tempfield, RFH2_PSC_ONDEMAND, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_retainpub > 0)
	{
		appendOption(tempfield, RFH2_PSC_RETAINPUB, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_isretainpub > 0)
	{
		appendOption(tempfield, RFH2_PSC_ISRETAINPUB, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_correlid > 0)
	{
		appendOption(tempfield, RFH2_PSC_CORRELASID, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_deregall > 0)
	{
		appendOption(tempfield, RFH2_PSC_DEREGALL, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_infretain > 0)
	{
		appendOption(tempfield, RFH2_PSC_INFORMIFRET, parms->rfh_psc_reqtype);
	}

	if (parms->rfh_psc_pers_type > 0)
	{
		switch(parms->rfh_psc_pers_type)
		{
		case RFH_PSC_PERS:
			{
				appendOption(tempfield, RFH2_PSC_PERS, parms->rfh_psc_reqtype);
				break;
			}
		case RFH_PSC_NON_PERS:
			{
				appendOption(tempfield, RFH2_PSC_NON_PERS, parms->rfh_psc_reqtype);
				break;
			}
		case RFH_PSC_PERS_PUB:
			{
				appendOption(tempfield, RFH2_PSC_PERSASPUB, parms->rfh_psc_reqtype);
				break;
			}
		case RFH_PSC_PERS_QUEUE:
			{
				appendOption(tempfield, RFH2_PSC_PERSASQUEUE, parms->rfh_psc_reqtype);
				break;
			}
		}
	}

	/* check if we found any psc fields */
	if (tempfield[0] != 0)
	{
		/* add the XML tags and data */
		strcpy(varArea, RFH2_PSC_BEGIN);
		strcat(varArea, tempfield);
		strcat(varArea, RFH2_PSC_END);

		/* round to a multiple of four bytes */
		varlen = roundVarArea(varArea + 4);
	}
}

void buildMCD(putParms * parms)

{
	int		varlen=0;
	char	*varArea;
	char	tempValue[256];
	char	tempfield[1024];

	/* get a pointer to the area to use */
	varArea = parms->rfh_mcd;

	/* initialize the string to a null string */
	tempfield[0] = 0;

	if (parms->rfh_jms_reqtype > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_MSD_BEGIN);

		switch (parms->rfh_jms_reqtype)
		{
		case RFH_JMS_TEXT:
			{
				strcat(tempfield, JMS_TEXT);
				break;
			}
		case RFH_JMS_BYTES:
			{
				strcat(tempfield, JMS_BYTES);
				break;
			}
		case RFH_JMS_OBJECT:
			{
				strcat(tempfield, JMS_OBJECT);
				break;
			}
		case RFH_JMS_STREAM:
			{
				strcat(tempfield, JMS_STREAM);
				break;
			}
		case RFH_JMS_MAP:
			{
				strcat(tempfield, JMS_MAP);
				break;
			}
		case RFH_JMS_NONE:
			{
				strcat(tempfield, JMS_NONE);
				break;
			}
		}

		/* Add the closing tag */
		strcat(tempfield, RFH2_MSD_END);
	}
	else
	{
		if (strlen(parms->rfhdomain) > 0)
		{
			/* add the XML tag */
			strcat(tempfield, RFH2_MSD_BEGIN);

			/* get the message domain name and append it to the XML message */
			replaceChars(parms->rfhdomain, tempValue);
			strcat(tempfield, tempValue);

			/* Add the closing tag */
			strcat(tempfield, RFH2_MSD_END);
		}
	}

	if (strlen(parms->rfhset) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_SET_BEGIN);

		/* get the message set name and append it to the XML message */
		replaceChars(parms->rfhset, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_SET_END);
	}

	if (strlen(parms->rfhtype) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_TYPE_BEGIN);

		/* get the message type name and append it to the XML message */
		replaceChars(parms->rfhtype, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_TYPE_END);
	}

	if (strlen(parms->rfhfmt) > 0)
	{
		/* add the XML tag */
		strcat(tempfield, RFH2_FMT_BEGIN);

		/* get the message fmt name and append it to the XML message */
		replaceChars(parms->rfhfmt, tempValue);
		strcat(tempfield, tempValue);

		/* Add the closing tag */
		strcat(tempfield, RFH2_FMT_END);
	}

	/* check if we found any mcd fields */
	if (tempfield[0] != 0)
	{
		/* add the XML tags and data */
		strcpy(varArea, RFH2_MCD_BEGIN);
		strcat(varArea, tempfield);
		strcat(varArea, RFH2_MCD_END);

		/* round to a multiple of four bytes */
		varlen = roundVarArea(varArea + 4);
	}
}

/**************************************************************/
/*                                                            */
/* Routine to construct an RFH V2 header.                     */
/*                                                            */
/**************************************************************/

int buildRFH2(char * rfhdata, putParms *parms, int xmlOnly)

{
	int				rfhlength;
	unsigned int	varlength=0;
	MQRFH2			tempRFH;
	char			tempfield[USR_AREA_SIZE];

	/* get a pointer to the area to build the variable part of the RFH */
	memset(tempfield, 0, sizeof(tempfield));

	/* initialize the RFH length */
	rfhlength = MQRFH_STRUC_LENGTH_FIXED_2;

	/* check if we have a variable part */
	if (1 == xmlOnly)
	{
		tempfield[0] = 0;

		/* check for explicit folder definiions */
		varlength += appendFolder(tempfield + varlength, parms->rfh_mcd, parms->encoding);
		varlength += appendFolder(tempfield + varlength, parms->rfh_jms, parms->encoding);
		varlength += appendFolder(tempfield + varlength, parms->rfh_psc, parms->encoding);
		varlength += appendFolder(tempfield + varlength, parms->rfh_pscr, parms->encoding);
		varlength += appendFolder(tempfield + varlength, parms->rfh_usr, parms->encoding);

		/* Allow for the variable part length and data */
		rfhlength += varlength;
	}

	/* initialize the header */
	tempRFH.Version = MQRFH_VERSION_2;
	tempRFH.Flags = MQRFH_NONE;
	tempRFH.StrucLength = rfhlength;

	if (parms->nameValueCCSID > 0)
	{
		tempRFH.NameValueCCSID = parms->nameValueCCSID;
	}
	else
	{
		tempRFH.NameValueCCSID = 1208;
	}

	/* set the encoding for the user data */
	if (parms->rfhencoding > 0)
	{
		tempRFH.Encoding = parms->rfhencoding;
	}
	else
	{
		tempRFH.Encoding = MQENC_NATIVE;
	}

	/* get the code page of the user data */
	if (parms->rfhccsid > 0)
	{
		/* set the ccsid field in the RFH header */
		tempRFH.CodedCharSetId = parms->rfhccsid;
	}
	else
	{
		/* choose an intelligent default */
		tempRFH.CodedCharSetId = MQCCSI_INHERIT;
	}

	/* find out if the character set is EBCDIC */
	if (getCcsidType(parms->codepage) == CHAR_ASCII)
	{
		/* set the structure id and format fields in ASCII */
		memcpy(tempRFH.StrucId, MQRFH_STRUC_ID, sizeof(tempRFH.StrucId));
		memcpy(tempRFH.Format, parms->msgformat, MQ_FORMAT_LENGTH);
	}
	else
	{
		/* set the structure id and format fields in EBCDIC */
		AsciiToEbcdic((unsigned char *)tempRFH.StrucId, (unsigned char *)MQRFH_STRUC_ID, sizeof(tempRFH.StrucId));
		AsciiToEbcdic((unsigned char *)tempRFH.Format, (unsigned char *)&(parms->msgformat), MQ_FORMAT_LENGTH);
	}

#if defined WIN32 || defined __i386__
	if ((parms->encoding & MQENC_INTEGER_REVERSED) == 0)
#else
	if ((parms->encoding & MQENC_INTEGER_REVERSED) != 0)
#endif
	{
		/* we need to reverse the integers in all of the RFH header fields */
		tempRFH.Version        = reverseBytes4(tempRFH.Version);
		tempRFH.StrucLength    = reverseBytes4(tempRFH.StrucLength);
		tempRFH.Encoding       = reverseBytes4(tempRFH.Encoding);
		tempRFH.CodedCharSetId = reverseBytes4(tempRFH.CodedCharSetId);
		tempRFH.Flags          = reverseBytes4(tempRFH.Flags);
		tempRFH.NameValueCCSID = reverseBytes4(tempRFH.NameValueCCSID);
	}

	/* copy the fixed portion of the header and the length of the */
	/* variable part to the data area */
	memcpy(rfhdata, (char *) &tempRFH, MQRFH_STRUC_LENGTH_FIXED_2);

	/* check if we have a variable part */
	if (varlength > 0)
	{
		memcpy(rfhdata + MQRFH_STRUC_LENGTH_FIXED_2, tempfield, varlength);
	}

	/* return the length of the RFH2 header */
	return rfhlength;
}

void resetPtr(char **ptr, unsigned int *len)

{
	/* do we have an existing area? */
	if (*ptr != NULL)
	{
		free((*ptr));		/* release the storage              */
		(*ptr) = NULL;		/* remember we released the storage */
		(*len) = 0;			/* reset the length of the storage  */
	}
}

char * allocateFolderArea(int len)

{
	char *	tempPtr;

	tempPtr = (char *)malloc(len + 16);		/* allocate a new folder area */
	memset(tempPtr, 0, len + 16);			/* clear the storage          */

	return tempPtr;
}

void appendPtr(char **ptr, unsigned int *length, char * data)

{
	char *			tempPtr;
	char *			newPtr;
	unsigned int	len;

	tempPtr = (*ptr);
	len = (*length);

	if ((NULL == tempPtr) || (0 == len))
	{
		/* allocate a new area to store the usr folder */
		tempPtr = allocateFolderArea(USR_AREA_SIZE);
		len = USR_AREA_SIZE;
		(*ptr) = tempPtr;
		(*length) = len;
	}

	/* check if we are going to overflow the existing area */
	if ((strlen(data) + strlen(tempPtr)) > len)
	{
		/* allocate a new area that is twice as large */
		len *= 2;							/* double the size               */
		newPtr = (char *)malloc(len + 16);	/* allocate a new larger area	 */
		memset(newPtr, 0, len + 16);		/* clear the new area            */
		strcpy(newPtr, tempPtr);			/* capture the previous data     */
		free(tempPtr);						/* release the old storage area  */
		tempPtr = newPtr;					/* point to the new storage area */
		(*ptr) = newPtr;					/* remember the new storage area */
		(*length) = len;					/* and the new length            */
	}

	strcat(tempPtr, data);
}

void resetMCD(putParms * parms)

{
	/* get rid of any previous values */
	resetPtr(&(parms->rfh_mcd), &parms->max_mcd);
}

void appendMCD(char * data, putParms * parms)

{
	appendPtr(&(parms->rfh_mcd), &parms->max_mcd, data);
}

void resetPSC(putParms * parms)

{
	/* get rid of any previous values */
	resetPtr(&(parms->rfh_psc), &parms->max_psc);
}

void appendPSC(char * data, putParms * parms)

{
	appendPtr(&(parms->rfh_psc), &parms->max_psc, data);
}


void resetPSCR(putParms * parms)

{
	/* get rid of any previous values */
	resetPtr(&(parms->rfh_pscr), &parms->max_pscr);
}

void appendPSCR(char * data, putParms * parms)

{
	appendPtr(&(parms->rfh_pscr), &parms->max_pscr, data);
}

void resetJMS(putParms * parms)

{
	/* get rid of any previous values */
	resetPtr(&(parms->rfh_jms), &parms->max_jms);
}

void appendJMS(char * data, putParms * parms)

{
	appendPtr(&(parms->rfh_jms), &parms->max_jms, data);
}

void resetUSR(putParms * parms)

{
	/* get rid of any previous values */
	resetPtr(&parms->rfh_usr, &parms->max_usr);
}

void appendUSR(char * data, putParms * parms)

{
	appendPtr(&(parms->rfh_usr), &parms->max_usr, data);
}

void rebuildMCD(putParms * parms)

{
	resetMCD(parms);
	parms->rfh_mcd = allocateFolderArea(USR_AREA_SIZE);
	parms->max_mcd = USR_AREA_SIZE;
	buildMCD(parms);
}

void rebuildJMS(putParms * parms)

{
	resetJMS(parms);
	parms->rfh_jms = allocateFolderArea(USR_AREA_SIZE);
	parms->max_jms = USR_AREA_SIZE;
	buildJMS(parms);
}

void rebuildPSC(putParms * parms)

{
	resetPSC(parms);
	parms->rfh_psc = allocateFolderArea(USR_AREA_SIZE);
	parms->max_psc = USR_AREA_SIZE;
	buildPSC(parms);
}
