/********************************************************************/
/*                                                                  */
/*   putparms.c - Input parameter file processing subroutines       */
/*                                                                  */
/********************************************************************/

/**************************************************************/
/*                                                            */
/* Read the parameters file and process each line.            */
/*                                                            */
/**************************************************************/

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

#ifdef WIN32
#include <windows.h>
#endif

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

/* parameter file processing routines */
#include "putparms.h"
#include "parmline.h"

/* RFH processing subroutines include */
#include "rfhsubs.h"

/* default code page to use */
#define DEF_EBCDIC_CODEPAGE	500
#ifdef WIN32
#define DEF_CODEPAGE	437
#else
#define DEF_CODEPAGE	850
#endif

void mallocError(const int len, int memUsed)

{
	printf("*****Error - memory allocation for %d bytes failed (total used previously %d)\n", len, memUsed);
#ifndef _WIN32
	printf(" use ulimit with the -d parameter to increase the heap size\n");
#endif
}

/**************************************************************/
/*                                                            */
/* Routine to check for an rfh in the file data.  This        */
/*  routine checks the first four characters for an RFH       */
/*  structure id in either ASCII or EBCDIC, and then checks   */
/*  the next four bytes for either a binary 1 or 2, trying    */
/*  both normal and reversed integers.                        */
/*                                                            */
/**************************************************************/

int findRFH(FILEPTR* fptr, int *rfhLen, putParms *parms)

{
	int		rfhtype=0;
	int		rfhversion=0;
	MQRFH	*tempRFH;
	char	tempid[5];

	/* initialize the rfh length to zero */
	(*rfhLen) = 0;

	/* tell what we are doing */
	if (parms->verbose)
	{
		printf("Looking for rfh in file\n");
	}

	/* is the message long enough to have an RFH? */
	if (fptr->length >= MQRFH_STRUC_LENGTH_FIXED_2)
	{
		/* translate the first 4 bytes from EBCDIC to ASCII */
		EbcdicToAscii((unsigned char *) fptr->dataptr, sizeof(MQRFH_STRUC_ID) - 1, (unsigned char *) &tempid);

		/* check for either an ASCII or EBCDIC structure id */
		if ((memcmp(tempid, MQRFH_STRUC_ID, sizeof(MQRFH_STRUC_ID) - 1) == 0) ||
			(memcmp(fptr->dataptr, MQRFH_STRUC_ID, sizeof(MQRFH_STRUC_ID) - 1) == 0))
		{
			/* the first four bytes match an RFH structure id */
			tempRFH = (MQRFH *) fptr->dataptr;
			rfhversion = tempRFH->Version;
			
			/* check for the RFH version field in PC format */
			if ((MQRFH_VERSION_1 == rfhversion) || (MQRFH_VERSION_2 == rfhversion))
			{
				/* the version field is ok - asssume we have an rfh in the file */
				rfhtype = rfhversion;

				/* set the rfhLen from the rfh header */
				(*rfhLen) = tempRFH->StrucLength;

				/* was encoding for rfh specified in parameters file? */
				if (parms->encoding > 0)
				{
					/* yes, use it */
					fptr->Encoding = parms->encoding;
				}
				else
				{
					/* pick an intelligent default based on the platform - e.g. for PC Intel = 546 */
					fptr->Encoding = MQENC_NATIVE;
				}
			}
			else
			{
				/* reverse the order, and check for host integers */
				rfhversion = reverseBytes4(rfhversion);

				/* check for the RFH version field in host format */
				if ((MQRFH_VERSION_1 == rfhversion) || (MQRFH_VERSION_2 == rfhversion))
				{
					rfhtype = rfhversion;

					/* set the rfhLen from the rfh header */
					(*rfhLen) = reverseBytes4(tempRFH->StrucLength);

					/* was encoding for rfh specified in parameters file? */
					if (parms->encoding > 0)
					{
						/* yes, use it */
						fptr->Encoding = parms->encoding;
					}
					else
					{
						/* pick an intelligent default - PC = 546 */
						fptr->Encoding = MQENC_NATIVE;
					}
				}
			}

			/* did we find an rfh at the front of the file? */
			if (rfhtype > 0)
			{
				/* check if the length makes sense */
				if (((*rfhLen) > 0) && ((*rfhLen) <= fptr->length))
				{
					/* check if a code page was specified */
					if (0 == parms->codepage)
					{
						/* pick an intelligent default */
						if (memcmp(tempid, MQRFH_STRUC_ID, sizeof(MQRFH_STRUC_ID)) == 0)
						{
							/* set an EBCDIC default value */
							fptr->Codepage = DEF_EBCDIC_CODEPAGE;
						}
						else
						{
							/* set an ASCII default value */
							fptr->Codepage = DEF_CODEPAGE;
						}
					}
				}
				else
				{
					rfhtype = 0;
					printf("***** Error - invalid RFH header found in data - StrucLength=%d\n", *rfhLen);
				}
			}
		}
	}

	if (1 == parms->verbose)
	{
		/* did we find an rfh at the front of the file? */
		if (rfhtype > 0)
		{
			/* found rfh */
			printf("using rfh version %d found in file\n", rfhtype);
		}
		else
		{
			/* no rfh found in file - rfh set to no */
			printf("no rfh found in file\n");
		}
	}

	return rfhtype;
}

/**************************************************************/
/*                                                            */
/* Create a message data file block.                          */
/*                                                            */
/* This routine will check for the presence of an MQMD and    */
/* RFH header at the front of the data.  It will adjust the   */
/* user data pointer and length if either header is present.  */
/*                                                            */
/**************************************************************/

FILEPTR * createFileBlock(char * msgPtr, char * userPtr, char * allocPtr, const int msgLen, putParms *parms)

{
	FILEPTR*	newfptr=NULL;							/* pointer to the newly allocated file block */
	int			memlen=sizeof(FILEPTR);					/* number of bytes to allocate */
	int			mqmdLen=0;								/* length of the mqmd if found in the input file */
	int			rfhLen;									/* length of the RFH or RFH2 if present */
	int			len = msgLen;
	int			templen;
	MQMD		*mqmdPtr;								/* pointer to the MQMD */
	MQRFH2		*rfhHeaderPtr;
	char		tempRFHid[8];							/* working storage for RFH id field in EBCDIC */
	char		tempid[2 * MQ_CORREL_ID_LENGTH + 1];
	char		tempid2[2 * MQ_GROUP_ID_LENGTH + 1];

	/* increase the message count */
	parms->mesgCount++;

	/* allocate a new message data block */
	newfptr  = (FILEPTR *) malloc(memlen);

	/* check if malloc worked */
	if (newfptr != NULL)
	{
		/* calculate total memory used */
		parms->memUsed += memlen;

		/* do some initializstion */
		newfptr->hasMQMD = 0;
		newfptr->mqmdptr = NULL;

		/* should we check for mqmds? */
		if ((1 == parms->useMQMD) || (1 == parms->ignoreMQMD))
		{
			/* check if there is an mqmd in front of the data */
			if ((msgLen >= sizeof(MQMD)) && (memcmp(msgPtr, MQMD_STRUC_ID, 4) == 0))
			{
				/* found MQMD */
				if (0 == parms->ignoreMQMD)
				{
					parms->foundMQMD = 1;				/* remember we found an MQMD */
					newfptr->mqmdptr = msgPtr;
					newfptr->hasMQMD = 1;
					newfptr->newMsgId = parms->newMsgId;
				}

				/* update the message data pointers */
				msgPtr += sizeof(MQMD);
				userPtr = msgPtr;
				len -= sizeof(MQMD);

				/* check for an rfh header */
				mqmdPtr = (MQMD *)(newfptr->mqmdptr);
				if ((mqmdPtr != NULL) && ((memcmp(mqmdPtr->Format, MQFMT_RF_HEADER_2, 8) == 0) || (memcmp(mqmdPtr->Format, MQFMT_RF_HEADER, 8) == 0)))
				{
					/* move the user data pointer past the RFH header */
					rfhHeaderPtr = (MQRFH2 *)userPtr;
					templen = rfhHeaderPtr->StrucLength;

					/* check what kind of encoding is in use */
					if ((mqmdPtr->Encoding & MQENC_INTEGER_NORMAL) > 0)
					{
						/* need to reverse the bytes */
						templen = reverseBytes4(templen);
					}

					/* make sure the length makes sense */
					if ((templen > 0) && (templen <= len))
					{
						userPtr += templen;
					}
					else
					{
						printf("***** Invalid rfh header found in data - StrucLength=%d\n", templen);
					}
				}
			}
		}

		newfptr->dataptr = msgPtr;			/* point to the start of the message data */
		newfptr->userDataPtr = userPtr;		/* remember where the user data starts    */
		newfptr->length = len;
		newfptr->rfhlen = 0;
		newfptr->hasRFH = parms->rfh;
		newfptr->useFileRFH = 0;
		newfptr->nextfile = NULL;
		newfptr->acqStorAddr = allocPtr;

		if ((parms->rfh != RFH_NO) && (parms->rfh != RFH_AUTO))
		{
			newfptr->rfhlen = parms->rfhlength;	/* remember the length of the rfh header */
		}

		newfptr->Codepage = parms->codepage;
		newfptr->Encoding = parms->encoding;
		newfptr->Expiry   = parms->expiry;
		newfptr->Msgtype  = parms->msgtype;
		newfptr->Persist  = parms->persist;
		newfptr->Priority = parms->priority;
		newfptr->Report = parms->report;
		newfptr->Feedback = parms->feedback;

		memset(newfptr->CorrelId, 0, sizeof(newfptr->CorrelId));
		newfptr->CorrelIdSet = parms->correlidSet;
		if (parms->correlidSet)
		{
			memcpy(newfptr->CorrelId, parms->correlid, sizeof(newfptr->CorrelId));
		}

		memset(newfptr->GroupId, 0, sizeof(newfptr->GroupId));
		newfptr->GroupIdSet = parms->groupidSet;
		if (parms->groupidSet)
		{
			memcpy(newfptr->GroupId, parms->groupid, sizeof(newfptr->GroupId));
		}

		/* capture the group information */
		newfptr->inGroup = parms->inGroup;
		newfptr->lastGroup = parms->lastGroup;

		/* check if the accounting token parameter was set */
		if (1 == parms->acctTokenSet)
		{
			newfptr->AcctTokenSet = 1;
			memcpy(newfptr->AccountingToken, parms->accountingToken, MQ_ACCOUNTING_TOKEN_LENGTH);
		}
		else
		{
			newfptr->AcctTokenSet = 0;
			memset(newfptr->AccountingToken, 0, MQ_ACCOUNTING_TOKEN_LENGTH);
		}

		memset(newfptr->Format, 0, sizeof(newfptr->Format));
		newfptr->FormatSet = parms->formatSet;
		if (parms->formatSet)
		{
			memcpy(newfptr->Format, parms->msgformat, sizeof(newfptr->Format));
		}

		strcpy(newfptr->ReplyQM, parms->replyQM);
		strcpy(newfptr->ReplyQ, parms->replyQ);
		strcpy(newfptr->UserId, parms->userId);

		/* check if we should scan for an RFH header embedded with the data in the file */
		if (RFH_AUTO == parms->rfh)
		{
			/* look for an RFH header in the data */
			newfptr->hasRFH = findRFH(newfptr, &rfhLen, parms);

			/* was an RFH found? */
			if (RFH_NO != newfptr->hasRFH)
			{
				/* found RFH in data */
				newfptr->useFileRFH = 1;

				/* we need to update the user data pointer */
				newfptr->userDataPtr += rfhLen;
				newfptr->rfhlen = rfhLen;		/* remember the length of the rfh header */
			}
		}
		else if (parms->rfh != RFH_NO)
		{
			/* allocate storage for the rfh plus the message data */
			newfptr->acqStorAddr = (char *)malloc(len + parms->rfhlength + 1);
			
			/* check if the malloc worked */
			if (NULL == newfptr->acqStorAddr)
			{
				/* tell the user what happened */
				printf("Storage allocation (malloc) failed for message data area\n");

				/* set the error switch to terminate the program */
				parms->err = 1;
			}
			else
			{
				/* indicate that an RFH is present */
				newfptr->hasRFH = parms->rfh;

				/* indicate the type of RFH header */
				if (RFH_V1 == parms->rfh)
				{
					/* set the format field to indicate the RFH1 header */
					memcpy(newfptr->Format, MQFMT_RF_HEADER_1, MQ_FORMAT_LENGTH);
				}
				else
				{
					/* set the format field to indicate the RFH1 header */
					memcpy(newfptr->Format, MQFMT_RF_HEADER_2, MQ_FORMAT_LENGTH);
				}

				/* is a codepage set? */
				if (0 == newfptr->Codepage)
				{
					/* initialize a working storage area */
					memset(tempRFHid, 0, sizeof(tempRFHid));

					/* translate an RFH id to EBCDIC */
					AsciiToEbcdic((unsigned char *)tempRFHid, (const unsigned char *)MQRFH_STRUC_ID, 4);

					/* check if the RFH is in EBCDIC */
					if (memcmp(newfptr->dataptr, tempRFHid, sizeof(MQRFH_STRUC_ID) - 1) == 0);
					{
						/* the header is in EBCDIC */
						/* set a default EBCDIC code page */
						newfptr->Codepage = DEF_EBCDIC_CODEPAGE;
					}
				}
			}
		}

		if (1 == parms->correlidSet)
		{
			memset(tempid, 0, sizeof(tempid));
			AsciiToHex((unsigned char *)tempid, (unsigned char *)&(parms->correlid), MQ_CORREL_ID_LENGTH);
			if (parms->verbose)
				printf("Correlation id set to %s\n", tempid);
		}

		if (1 == parms->groupidSet)
		{
			memset(tempid2, 0, sizeof(tempid2));
			AsciiToHex((unsigned char *)tempid2, (unsigned char *)&(parms->groupid), MQ_GROUP_ID_LENGTH);
			if (parms->verbose)
				printf("Group id set to %s\n", tempid2);
		}

		newfptr->thinkTime = parms->thinkTime;
		newfptr->setTimeStamp = parms->setTimeStamp;
	}
	else
	{
		mallocError(memlen, parms->memUsed);
	}

	return newfptr;
}

/**************************************************************/
/*                                                            */
/* Read message data from a file.                             */
/*                                                            */
/**************************************************************/

int readFileData(const char *filename, int *length, char ** dataptr, putParms * parms)

{
	int	rc=0;
	int datalen;
	int memlen;
	char *msgdata=NULL;
	char *ptr;
	FILE*	datafile;

	if ((datafile = fopen(filename, "rb")) == NULL)
	{
		printf("Unable to open input file %s\n", filename);
		exit(1);
	}

	/* figure out how long the data is and read it into a buffer */
	fseek(datafile, 0L, SEEK_END);
	datalen = ftell(datafile);
	fseek(datafile, 0L, SEEK_SET);
	memlen = datalen + parms->rfhlength + 1;
	msgdata = (char *) malloc(memlen);

	/* check if the malloc worked */
	if (msgdata != NULL)
	{
		/* calculate total memory used */
		parms->memUsed += memlen;

		ptr = msgdata;
		memset(msgdata, 0, datalen + parms->rfhlength + 1);

		/* check if we need to add an RFH to the beginning of the data */
		if ((parms->rfhdata != NULL) && (RFH_V1 == parms->rfh) || (RFH_V2 == parms->rfh) || (RFH_XML == parms->rfh))
		{
			/* move the rfh header to the front of the data */
			memcpy(msgdata, parms->rfhdata, parms->rfhlength);

			/* read in the data after the rfh */
			ptr += parms->rfhlength;
		}

		fread(ptr, 1, datalen, datafile);
		fclose(datafile);

		/* tell what we are doing */
		printf("\n%d bytes read from data file %s\n", datalen, filename);

		/* set the length and data pointers */
		(*length) = datalen;
		(*dataptr) = msgdata;
	}
	else
	{
		mallocError(memlen, parms->memUsed);
	}

	return rc;
}

/**************************************************************/
/*                                                            */
/* Routine to scan for a delimiter sequence in the data.      */
/*                                                            */
/**************************************************************/

char * scanForDelim(char * msgdata, const int datalen, putParms *parms)

{
	char *		ptr=NULL;
	char *		ptrend;

	/* do we have a delimiter? */
	if (parms->delimiterLen > 0)
	{
		ptr = msgdata;
		ptrend = msgdata + datalen - parms->delimiterLen;
		while ((ptr != NULL) && (ptr < ptrend) && (memcmp(ptr, parms->delimiter, parms->delimiterLen) != 0))
		{
			while ((ptr < ptrend) && (ptr[0] != parms->delimiter[0]))
			{
				ptr++;
			}

			/* could not find first character of delimiter - time to get out */
			if (ptr[0] != parms->delimiter[0])
			{
				ptr = NULL;
			}
			else
			{
				if ((ptr != NULL) && (memcmp(ptr, parms->delimiter, parms->delimiterLen) != 0))
				{
					ptr++;
				}
			}
		}
	}

	return ptr;
}

void listMessage(int datalen, int useFileRFH, putParms *parms)

{
	if (parms->verbose)
	{
		/* tell what we did */
		if (parms->msgformat[0] > 0)
		{
			printf("mqmd format is (\"%s\")\n", parms->msgformat);
		}

		printf("persistence = %d, code page %d, encoding %d expiry %d priority %d report %d feedback %d\n", 
				parms->persist, parms->codepage, parms->encoding, parms->expiry, parms->priority, parms->report, parms->feedback);

		printf("reply to QM (%s), reply to Queue (%s), userid(%s)\n", parms->replyQM, parms->replyQ, parms->userId);

		/* indicate whether RFH headers are to be used or not */
		switch (parms->rfh)
		{
		case RFH_NO:
			{
				printf("no record format headers (rfh) to be used\n");
				break;
			}
		case RFH_V1:
			{
				if (0 == useFileRFH)
				{
					printf("V1 record format headers (rfh) will be used\n");
					printf(" App group (%s) Format (%s)\n", parms->rfhappgroup, parms->rfhformat);
				}
				else
				{
					printf("V1 record format headers (rfh) found in file will be used\n");
				}

				break;
			}
		case RFH_V2:
			{
				if (0 == useFileRFH)
				{
					printf("V2 record format headers (rfh) will be used\n");
					printf(" Domain (%s) Set (%s) Type (%s) Fmt (%s)\n", 
							parms->rfhdomain, parms->rfhset, parms->rfhtype, parms->rfhfmt);
				}
				else
				{
					printf("V2 record format headers (rfh) found in file will be used\n");
				}

				break;
			}
		case RFH_XML:
			{
				printf("XML only record format headers (rfh) will be used\n");
				break;
			}
		case RFH_AUTO:
			{
				printf("Record format headers (rfh) will be used if found with message data\n");
				break;
			}
		}
	}
}

/**************************************************************/
/*                                                            */
/* Create a message data file block and read and process the  */
/* file data.                                                 */
/*                                                            */
/* There are several possibilities that must be taken into    */
/* account.  First, the file may contain one or more messages */
/* separated by a delimiter string.  Second, the individual   */
/* messages may contain an embedded MQMD.  Third, the         */
/* individual messages may contain an embedded RFH header.    */
/* Finally, the parameters file may indicate that an RFH      */
/* header is to be inserted into the data.                    */
/*                                                            */
/* In all cases, delimiters will break the file into multiple */
/* individual messages.  The search for a delimiter is done   */
/* first.                                                     */
/*                                                            */
/* Once the individual messages in the file have been found,  */
/* a check will be made for an MQMD at the front of the user  */
/* data.  If an MQMD is found, then this will be used.  No    */
/* RFH header will be inserted.                               */
/*                                                            */
/* If an RFH header is to be inserted at the front of the     */
/* user data (options 1, 2 or XML) then the RFH will be       */
/* inserted in front of the data.  If there is more than one  */
/* message in the file, then a new area of storage must be    */
/* allocated for each message after the first one, since      */
/* there is no room for the rfh header in the data buffer.    */
/*                                                            */
/* Finally, if the rfh option has been set to auto (A) then   */
/* a check will be made for an RFH header at the front of the */
/* data.                                                      */
/*                                                            */
/**************************************************************/

FILEPTR * getFileData(char *filename, putParms *parms)

{
	int			rc;
	int			datalen=0;
	int			remainLen=0;
	int			memlen;
	int			len=0;
	char		*msgdata=NULL;
	char		*msgPtr;			/* pointer to front of message data */
	char		*userPtr;			/* pointer to user data             */
	char		*delimPtr;
	char		*allocPtr=NULL;
	MQMD		*mqmdPtr;
	FILEPTR *	newfptr=NULL;
	FILEPTR *	currfptr=NULL;
	FILEPTR *	fptr=NULL;
	int			foundMQMD=0;
	int			insertRFH=0;

	/* read the message data file after inserting an RFH header */
	rc = readFileData(filename, &datalen, &msgdata, parms);

	/* was the read successful? */
	if (0 == rc) 
	{
		/* check if we are inserted an RFH header at the front of the data */
		if ((RFH_V1 == parms->rfh) || (RFH_V2 == parms->rfh) || (RFH_XML == parms->rfh))
		{
			insertRFH = 1;
		}

		/* increase the file counter */
		parms->fileCount++;

		/* was the data length > 0 */
		if ((msgdata != NULL) && (datalen > 0))
		{
			/* check if we are treating all the messages as a single group */
			if (1 == parms->fileAsGroup)
			{
				/* indicate that we are in a group */
				parms->inGroup = 1;
			}

			/* point to the message data, including the RFH header */
			msgPtr = msgdata;
			allocPtr = msgdata;
			userPtr = msgdata;

			/* did we insert an RFH header? */
			if (1 == insertRFH)
			{
				/* skip any RFH headers that were inserted */
				userPtr = msgdata + parms->rfhlength;
			}

			/* check if we have a delimiter in the data */
			delimPtr = scanForDelim(userPtr, datalen, parms);

			/* did we find a delimiter in the data we just read in? */
			if (delimPtr != NULL)
			{
				/* found a delimiter */
				/* recalculate the data length and calculate the bytes remaining */
				remainLen = datalen;
				datalen = delimPtr - userPtr;
				remainLen -= (datalen + parms->delimiterLen);
			}

			/* should the program look for the presence of an MQMD in the data */
			foundMQMD = 0;
			if (((1 == parms->useMQMD) || (1 == parms->ignoreMQMD)) && (datalen >= sizeof(MQMD)))
			{
				/* check for an embedded MQMD */
				/* point to the user data that we read */
				mqmdPtr = (MQMD *)userPtr;

				/* check for an MQMD at the front of the data */
				if ((memcmp(mqmdPtr->StrucId, MQMD_STRUC_ID, sizeof(mqmdPtr->StrucId)) == 0) && ((MQMD_VERSION_1 == mqmdPtr->Version) || (MQMD_VERSION_2 == mqmdPtr->Version)))
				{
					/* found an MQMD at the front of the data */
					/* the MQMD will be used and any generated RFH header will be ignored */
					foundMQMD = 1;
				}
			}

			if ((1 == foundMQMD) || (0 == insertRFH))
			{
				/* any rfh inserted at the front of the data will be ignored */
				/* we will use the existing file area for the first message	 */
				/* allocate a file block for the first entry                 */
				fptr = createFileBlock(userPtr, userPtr, allocPtr, datalen, parms);
			}
			else
			{
				/* honor any rfh inserted at the front of the user data      */
				/* we will use the existing file area for the first message  */
				/* allocate a file block for the first entry                 */
				fptr = createFileBlock(msgPtr, userPtr, allocPtr, datalen + parms->rfhlength, parms);
			}

			/* point to the file block */
			currfptr = fptr;

			/* tell what we did */
			listMessage(datalen, fptr->useFileRFH, parms);

			/* process any additional messages in this file */
			/* note that rc is set to -1 if a malloc fails  */
			while ((remainLen > 0) && (delimPtr != NULL) && (0 == rc))
			{
				/* move past the current delimiter */
				userPtr = delimPtr + parms->delimiterLen;

				/* check if we have a delimiter left in the input data */
				delimPtr = scanForDelim(userPtr, remainLen, parms);

				/* did we find a delimiter? */
				if (delimPtr != NULL)
				{
					/* adjust the data length */
					datalen = delimPtr - userPtr;
					remainLen -= (datalen + parms->delimiterLen);
				}
				else
				{
					/* set the data length to the length of the remaining data */
					datalen = remainLen;
					remainLen = 0;
				}

				/* check if we are looking for MQMDs in the data */
				foundMQMD = 0;
				if ((1 == parms->useMQMD) && (datalen >= sizeof(MQMD)))
				{
					/* point to the user data that we read */
					mqmdPtr = (MQMD *)userPtr;

					/* check for an MQMD at the front of the data */
					if ((memcmp(mqmdPtr->StrucId, MQMD_STRUC_ID, sizeof(mqmdPtr->StrucId)) == 0) && ((MQMD_VERSION_1 == mqmdPtr->Version) || (MQMD_VERSION_2 == mqmdPtr->Version)))
					{
						/* found an MQMD at the front of the data */
						/* use this rather than any generated rfh data */
						/* if there is an rfh header, there is a natural conflict */
						/* if an MQMD is found at the front of the user data, then */
						/* it will be used rather and any generated RFH header is  */
						/* ignored.  */
						foundMQMD = 1;
					}
				}

				/* now check if we need to allocate storage or if we can use the existing data area */
				/* storage must be allocated if an RFH header is to be inserted in front of the     */
				/* user data.  If an MQMD was found with the data then no headers will be inserted. */
				if (((RFH_V1 == parms->rfh) || (RFH_V2 == parms->rfh)) && (parms->rfhlength > 0) && (0 == foundMQMD))
				{
					/* need to allocate a new memory area to hold this message plus the RFH */
					memlen = parms->rfhlength + datalen + 1;
					msgPtr = (char *)malloc(memlen);
				
					/* check if it worked */
					if (msgPtr != NULL)
					{
						/* remember how much memory we have used */
						parms->memUsed += memlen;

						/* terminate the data with a binary zero */
						msgPtr[parms->rfhlength + datalen] = 0;

						/* copy the RFH to the message data area */
						memcpy(msgPtr, &(parms->rfhdata), parms->rfhlength);

						/* copy the user data to the message data area */
						memcpy(msgPtr + parms->rfhlength, userPtr, datalen);

						/* allocate a file pointer for this message */
						newfptr = createFileBlock(msgPtr, msgPtr + parms->rfhlength, msgPtr, datalen + parms->rfhlength, parms);
					}
					else
					{
						/* issue the error message and continue */
						mallocError(memlen, parms->memUsed);
						rc = -1;
					}
				}
				else
				{
					/* there is no rfh header to be inserted, so use the existing message buffer */
					newfptr = createFileBlock(userPtr, userPtr, NULL, datalen, parms);
				}
				
				/* insert the file block at the end of the chain */
				currfptr->nextfile = newfptr;

				/* remember the current file block */
				currfptr = newfptr;

				/* tell what we did */
				listMessage(datalen, newfptr->useFileRFH, parms);
			}

			/* check if we are treating a file as a group */
			if (1 == parms->fileAsGroup)
			{
				/* check if we found at least one message in the file */
				if (currfptr != NULL)
				{
					/* mark the last message in the file as last in group */
					currfptr->lastGroup = 1;
				}
			}
		}
	}
	else
	{
		printf("***** invalid data file name or zero length file %s *****\n", filename);
	}

	return fptr;
}

FILEPTR * processParmFile(char * parmFileName, putParms * parms)

{
	int		len;
	int		foundfiles=0;
	int		foundUsr=0;
	FILE *	parmfile;
	char *	ptr;
	FILEPTR * fileptr;
	FILEPTR * tempfptr;
	FILEPTR * fptr=NULL;
	char	parmline[512];

	/* initialize the parameter input area */
	memset(parmline, 0, sizeof(parmline));

	/* set the nextfile variable to the anchor */
	fileptr = fptr;

	/* open the parameters file */
	parmfile = fopen(parmFileName, "r");

	if (parmfile != NULL)
	{
		/* read the parameter file */
		while (fgets(parmline, sizeof(parmline) - 1, parmfile) != NULL)
		{
			/* check for a new line character at the end of the line */
			while ((strlen(parmline) > 0) && (parmline[strlen(parmline) - 1] < ' '))
			{
				/* get rid of the new line character */
				parmline[strlen(parmline) - 1] = 0;
			}

			/* point to the beginning of the line */
			/* skip any leading blanks */
			ptr = skipBlanks(parmline);

			/* truncate any trailing blanks */
			len = strlen(ptr);
			while ((len > 0) && (ptr[len] == ' '))
			{
				ptr[len] = 0;
				len--;
			}

			/* check for a comment or blank line */
			if ((ptr[0] != 0) && (ptr[0] != ';') && (ptr[0] != '#') && (ptr[0] != '*'))
			{
				/* strip trailing blanks */
				rtrim(ptr);

				if ('<' == ptr[0])
				{
					/* process this as an XML data entry */
					if (0 == foundUsr)
					{
						/* must be the first entry */
						foundUsr = processFirstUsrLine(ptr, parms);
					}
					else
					{
						/* figure out what kind of entry this belongs to */
						foundUsr = processUsrLine(ptr, foundUsr, parms);
					}
				}
				else
				{
					if ((0 == foundfiles) || ('[' == ptr[0]))
					{
						/* process this line as message parameters */
						foundfiles = processParmLine(ptr, parms);
					}
					else
					{
						/* process this line as a message data file name */
						tempfptr = getFileData(ptr, parms);

						/* do we create a file block? */
						if (tempfptr != NULL)
						{
							/* is this the first one? */
							if (fptr != NULL)
							{
								/* not the first - append to the end */
								fileptr = fptr;

								/* check if we need to update our nextfile pointer */
								while (fileptr->nextfile != NULL)
								{
									fileptr = (FILEPTR *)fileptr->nextfile;
								}

								/* insert the new one at the end of the chain */
								fileptr->nextfile = tempfptr;
							}
							else
							{
								/* first file block */
								fptr = tempfptr;
							}
						}
					}
				}
			}

			/* re-initialize the parameter input area */
			memset(parmline, 0, sizeof(parmline));
		}

		fclose(parmfile);
	}
	else
	{
		printf("***** Error opening parameters file *****\n");
		printf("***** Using default parameters *****\n");
	}

	return fptr;
}

