/*
 * Copyright (c) 2003 Linuxant inc.
 * Copyright (c) 2001-2003 Conexant Systems, Inc.
 *
 * NOTE: The use and distribution of this software is governed by the terms in
 * the file LICENSE, which is included in the package. You must read this and
 * agree to these terms before using or distributing this software.
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <assert.h>
#include <ctype.h>
#include <sys/stat.h>
#include <stdarg.h>

#include "framewrk.h"
#include "ossysenv.h"
#include "osnvm.h"
#include "configtypes.h"
#include "configcodes.h"
#include "dpaloem.h"

#define MAX_CFGCODES  256
#define MAX_COUNTRIES 256

typedef struct
{
	CFGMGR_CODE CfgCode;
	PUCHAR      Data;
	UINT32      Size;
} CFG_TABLE, *PCFG_TABLE;

typedef struct
{
	const char *InfString;
	BOOL (*pConvFunc)(char*, PCFG_TABLE, const char*, CFGMGR_CODE, int);
	CFGMGR_CODE ItemCode;
	int ItemSize;
}  CONV_TABLE, *PCONV_TABLE;

typedef struct tagCountryConvTable
{
	const char *InfString;
	void (*pConvFunc)(FILE *, struct tagCountryConvTable *);
	int ItemSize;
	int CtryPrmsStructOffset;
}  COUNTRY_CONV_TABLE, *PCOUNTRY_CONV_TABLE;

 
static CtryPrmsStruct CtryPrms[MAX_COUNTRIES];
 
static int verbose = 0;
static char *progname;

static void
BuildKeyBuf(char *Line, char *Key)
{
	char *pTmpLine, *pTmpKey = Key;

	pTmpLine = strchr(Line, ',');
	if(!pTmpLine) {
		*pTmpKey = '\0';
		return;
	}

	pTmpLine++;

	while (*pTmpLine == ' ' || *pTmpLine == '\t')
		pTmpLine++;

	while (*pTmpLine != ',' && *pTmpLine != ' ' && *pTmpLine != '\t')
	{
		*pTmpKey = *pTmpLine;
		pTmpKey++;
		pTmpLine++;
	}
	*pTmpKey++ = '\\';

	while (*pTmpLine == ',' || *pTmpLine == ' ' || *pTmpLine == '\t')
		pTmpLine++;
	
	while (*pTmpLine != ',' && *pTmpLine != ' ' && *pTmpLine != '\t')
	{
		*pTmpKey = *pTmpLine;
		pTmpKey++;
		pTmpLine++;
	}
	*pTmpKey = '\0';
}

static char *
SkipToValue(char *Line)
{
	int i;
	char *TmpVal = strchr(Line , ',');

	for (i=0; i<3 ; i++)
		TmpVal = strchr(++TmpVal , ',');

	return TmpVal+1;
}

/******************************************************************************/
/*
Function Name : BuildCountryKey
What          : the function builds the key for a country key in a way that 
                deletes the Country-Id. For example, the function will
				convert "Country\\0001\\TXLEVEL" to "Country\\TXLEVEL".
Input         : Line - the inf line including the value.
                Key  - (output parm) to initiate the key.
Output        : none.
Assumptions   : the Line is a valid Country Inf line.
*/
static void
BuildCountryKey(char *Line, char *Key)
{
	char *pTmpLine = Line;
	char *pTmpKey = Key;
 
 
	pTmpLine += 3;
	while (*pTmpLine == ',' || *pTmpLine == ' ' || *pTmpLine == '\t')
		pTmpLine++;
 
	while (*pTmpLine != ',' && *pTmpLine != ' ' && *pTmpLine != '\t' && 
		   *pTmpLine != '\\')
	{
		*pTmpKey = *pTmpLine;
		pTmpKey++;
		pTmpLine++;
	}
	*pTmpKey++ = '\\';
 
	while (*pTmpLine != ',' ) /* go to the next field */
		pTmpLine++;
	
	while (*pTmpLine == ',' || *pTmpLine == ' ' || *pTmpLine == '\t')
		pTmpLine++;
	
	while (*pTmpLine != ',' && *pTmpLine != ' ' && *pTmpLine != '\t')
	{
		*pTmpKey = *pTmpLine;
		pTmpKey++;
		pTmpLine++;
	}
	*pTmpKey = '\0';
 
}  /* BuildCountryKey */
 

static BOOL
HandleConvTable(FILE *pFile, PCONV_TABLE pConvTable, PCFG_TABLE pCfgTable)
{
	char LineBuf[1024];
	char KeyBuf[80] = "";

	while (fgets(LineBuf, sizeof(LineBuf), pFile))
	{
		if (strncmp(LineBuf, "HKR", 3))
			continue;

		BuildKeyBuf(LineBuf, KeyBuf);

		if (strcmp(KeyBuf, pConvTable->InfString))
			continue;
		
		return pConvTable->pConvFunc(SkipToValue(LineBuf),
				pCfgTable,
				pConvTable->InfString,
				pConvTable->ItemCode,
				pConvTable->ItemSize);
	}

	return FALSE;
}


static BOOL
ProcessString(char* inbuff, PCFG_TABLE pCfgTable,
		const char* InfString, CFGMGR_CODE ItemCode, int ItemSize)
{
	char *p;

	if((p = strtok(inbuff, "\"\r\n")) == NULL)
		return FALSE;

	pCfgTable->Size = strlen(p);
	pCfgTable->CfgCode = ItemCode;

	pCfgTable->Data = strdup(p);
	if(!pCfgTable->Data) {
		fprintf(stderr, "%s: %s: strdup() failed!\n", progname, __FUNCTION__);
		exit(5);
	}

	return TRUE;
}

static BOOL
ProcessGeneric(char* inbuff, PCFG_TABLE pCfgTable,
		const char* InfString, CFGMGR_CODE ItemCode, int ItemSize)
{
	char *Temp = inbuff;
	char ByteVal[10];
	char Val;
	unsigned char *p;
	int i=0;
	int j=0;
	int cnt=0;

	pCfgTable->Data = p = calloc(1, ItemSize);
	if(!pCfgTable->Data) {
		fprintf(stderr, "%s: %s: calloc(1, %d) failed!\n", progname, __FUNCTION__, ItemSize);
		exit(5);
	}
	pCfgTable->Size = ItemSize;
	pCfgTable->CfgCode = ItemCode;
	while ( *Temp )
	{
		if ( i%3  )
		{
			ByteVal[j] = inbuff[i-1];
			j++;
			if ( 2 == j )
			{
				if (cnt == ItemSize) {
					fprintf(stderr, "%s: Warning: skipping extraneous bytes for %s (ItemSize=%d)\n", progname, InfString, ItemSize);
					break;
				}
				ByteVal[j] = '\0';
				j=0;
				Val = strtol(ByteVal, NULL, 16);
				*p++ = Val&0xFF;
				cnt++;
			}
		}
		i++;
		Temp++;
	}
	if(cnt < ItemSize) {
		if(verbose)
			fprintf(stderr, "%s: Warning: %d byte(s) missing for %s\n", progname, ItemSize - cnt, InfString);
	}

	return TRUE;
}

static BOOL
ProcessMSSTR(char* inbuff, PCFG_TABLE pCfgTable,
		const char* InfString, CFGMGR_CODE ItemCode, int ItemSize)
{
	MODULATION_TYPE Mod = MODULATION_TYPE_V90;

	if ( 0 == strcmp("\"V90\"\n", inbuff) )
	{
		Mod = MODULATION_TYPE_V90;
	}
	if ( 0 == strcmp("\"V34\"\n", inbuff) )
	{
		Mod = MODULATION_TYPE_V34;
	}

	assert(ItemSize == sizeof(MODULATION_TYPE));

	pCfgTable->Data = malloc(ItemSize);
	if(!pCfgTable->Data) {
		fprintf(stderr, "%s: %s: malloc(%d) failed!\n", progname, __FUNCTION__, ItemSize);
		exit(5);
	}

	pCfgTable->Size = ItemSize;
	pCfgTable->CfgCode = ItemCode;
	memcpy(pCfgTable->Data, &Mod, pCfgTable->Size);
	return TRUE;
}


static void
ProcessCtryString(FILE *pFile, PCOUNTRY_CONV_TABLE pEntry)
{
	char LineBuf[1024];
	char KeyBuf[80] = "";
	char *p;
	int CountryNum;
 
	while (fgets(LineBuf, sizeof(LineBuf), pFile))
	{
		if (strncmp(LineBuf, "HKR,Country\\", 12))
			continue;
 
		BuildCountryKey(LineBuf, KeyBuf);
		if (strcmp(KeyBuf, pEntry->InfString))
			continue;

		CountryNum = strtol(LineBuf+12, NULL, 16);
		if(CountryNum >= MAX_COUNTRIES) {
			fprintf(stderr, "%s: Warning: country number 0x%x exceeds 0x%x\n", progname, CountryNum, MAX_COUNTRIES);
			continue;
		}

		/* get the data line */
		if((p = strtok(SkipToValue(LineBuf), "\"\r\n")))
			memcpy(((char*)&CtryPrms[CountryNum])+pEntry->CtryPrmsStructOffset, p, strlen(p));
	}
 
	return;
}
 

static void
ProcessCtryStruct(FILE *pFile, PCOUNTRY_CONV_TABLE pEntry)
{
	char *Temp;
	char ByteVal[10];
	char Val;
	char LineBuf[1024];
	char KeyBuf[80] = "";
	char *ValBuf;
	int i;
	int j;
	int cnt;
	int CountryNum;
	unsigned char *dp;
 
	while (fgets(LineBuf, sizeof(LineBuf), pFile))
	{
		if (strncmp(LineBuf, "HKR,Country\\", 12))
			continue;
 
		BuildCountryKey(LineBuf, KeyBuf);
		if (strcmp(KeyBuf, pEntry->InfString))
			continue;

		CountryNum = strtol(LineBuf+12, NULL, 16);
		if(CountryNum >= MAX_COUNTRIES) {
			fprintf(stderr, "%s: Warning: country number 0x%x exceeds 0x%x\n", progname, CountryNum, MAX_COUNTRIES);
			continue;
		}

		/* get the data line */
		Temp = ValBuf = SkipToValue(LineBuf);
		
		j = 0;
		i = 0;
		cnt = 0;

		dp = ((char*)&CtryPrms[CountryNum])+pEntry->CtryPrmsStructOffset;

		while ( *Temp )
		{

			if ( i%3  )
			{
				ByteVal[j] = ValBuf[i-1];
				j++;
				if ( 2 == j )
				{
					if (cnt == pEntry->ItemSize) {
						fprintf(stderr, "%s: Warning: skipping extraneous bytes for %s (ItemSize=%d, country#%04X)\n", progname, pEntry->InfString, pEntry->ItemSize, CountryNum);
						break;
					}
					ByteVal[j] = '\0';
					j=0;
					Val = strtol(ByteVal, NULL, 16);
					*dp++ = Val&0xFF;
					cnt++;
				}
			}
			i++;
			Temp++;
		}
		
		if(cnt < pEntry->ItemSize) {
			int missing = pEntry->ItemSize - cnt;

			if(verbose)
				fprintf(stderr, "%s: Warning: %d byte(s) missing for %s (country#%04X)\n", progname, missing, pEntry->InfString, CountryNum);
			memset(dp, 0, missing);
		}
	}
 
	return;
}

static CONV_TABLE ConvTable[] = 
{
	{ "OEM\\ATI\\000"         , ProcessString, CFGMGR_ATMESSAGE_I0, 0 },
	{ "OEM\\ATI\\001"         , ProcessString, CFGMGR_ATMESSAGE_I1, 0 },
	{ "OEM\\ATI\\002"         , ProcessString, CFGMGR_ATMESSAGE_I2, 0 },
	{ "OEM\\ATI\\003"         , ProcessString, CFGMGR_ATMESSAGE_I3, 0 },
	{ "OEM\\ATI\\004"         , ProcessString, CFGMGR_ATMESSAGE_I4, 0 },
	{ "OEM\\ATI\\005"         , ProcessString, CFGMGR_ATMESSAGE_I5, 0 },
	{ "OEM\\ATI\\006"         , ProcessString, CFGMGR_ATMESSAGE_I6, 0 },
	{ "OEM\\ATI\\007"         , ProcessString, CFGMGR_ATMESSAGE_I7, 0 },
	{ "OEM\\ATI\\008"         , ProcessString, CFGMGR_ATMESSAGE_I8, 0 },
	{ "OEM\\ATI\\009"         , ProcessString, CFGMGR_ATMESSAGE_I9, 0 },
	{ "OEM\\ATI\\010"         , ProcessString, CFGMGR_ATMESSAGE_I10, 0 },
	{ "OEM\\ATI\\011"         , ProcessString, CFGMGR_ATMESSAGE_I11, 0 },
	{ "OEM\\ATI\\012"         , ProcessString, CFGMGR_ATMESSAGE_I12, 0 },
	{ "OEM\\ATPLUSID\\GMI"    , ProcessString,
			CFGMGR_ATMESSAGE_MANUFACTURER, 0 },
	{ "OEM\\ATPLUSID\\GMM"    , ProcessString,
			CFGMGR_ATMESSAGE_MODEL, 0 },
	{ "OEM\\ATPLUSID\\GMR"    , ProcessString,
			CFGMGR_ATMESSAGE_REVISION, 0 },
	{ "OEM\\ATPLUSID\\GSN"    , ProcessString,
			CFGMGR_ATMESSAGE_SERIAL_NUM, 0 },
	{ "OEM\\ATPLUSID\\GOI"    , ProcessString,
			CFGMGR_ATMESSAGE_GOI, 0 },
	{ "OEM\\ATPLUSID\\GCAP"   , ProcessString,
			CFGMGR_ATMESSAGE_CAPABILITIES, 0 },
	{ "ID\\VENDOR"            , ProcessString,
			CFGMGR_PCI_VENDOR_ID, 0 },
	{ "ID\\DEVICE"            , ProcessString,
			CFGMGR_PCI_DEVICE_ID, 0 },
	{ "OEM\\AT+MSSTR"         , ProcessMSSTR,
			CFGMGR_MS_STR, sizeof(MODULATION_TYPE) },
	{ "OEM\\AT+MS"            , ProcessGeneric,
			CFGMGR_MS_PARAMS, sizeof(MS_USER_CONFIG) },
	{ "OEM\\SREGS"            , ProcessGeneric,
			CFGMGR_SREG, 40*sizeof(char) },
	{ "OEM\\FLAGS"            , ProcessGeneric,
			CFGMGR_OEM_FLAGS, sizeof(OEMFlagStructure) },
	{ "OEM\\HwData"           , ProcessGeneric,
			CFGMGR_OEM_HWDATA, sizeof(HW_DATA) },
	{ "OEM\\DAAType"          , ProcessGeneric,
			CFGMGR_OEM_DAATYPE, sizeof(char) },
	{ "OEM\\SmartDAAParams"   , ProcessGeneric,
			CFGMGR_OEM_SMARTDAA_PARAMS, sizeof(CAESAR_PARAMS) },
	{ "OEM\\SmartDAAParamsK3"   , ProcessGeneric,
			CFGMGR_OEM_SMARTDAA_PARAMSK3, sizeof(CAESAR_PARAMS) },
 	{ "OEM\\HwAdapterType"    , ProcessGeneric,
			CFGMGR_HW_ADAPTER_TYPE, sizeof(int) },
 	{ "Country\\Current"    , ProcessGeneric,
			CFGMGR_COUNTRY_CODE, sizeof(UINT16) },
 	{ "Country\\Previous"   , ProcessGeneric,
			CFGMGR_PREVIOUS_COUNTRY_CODE, sizeof(UINT16) },
 	{ "\\BuffersDelay"    , ProcessGeneric,
			CFGMGR_BUFFERS_DELAY, sizeof(UINT16) },
};
 
#define _c(f) sizeof((((CtryPrmsStruct *)0)->f)), ((int)&((CtryPrmsStruct *)0)->f)
static COUNTRY_CONV_TABLE ConvCountryTable[] = 
{
	{ "Country\\T35CODE"      , ProcessCtryStruct, _c(T35Code) },
	{ "Country\\NAME"         , ProcessCtryString, _c(cInter) },
	{ "Country\\INTCODE"      , ProcessCtryString, _c(cIntCode) },
	{ "Country\\TXLEVEL"      , ProcessCtryStruct, _c(Txlevel) },
	{ "Country\\RELAYS"       , ProcessCtryStruct, _c(Relays) },
	{ "Country\\PULSE"        , ProcessCtryStruct, _c(Pulse) },
	{ "Country\\RING"         , ProcessCtryStruct, _c(Ring) },
	{ "Country\\SREG"         , ProcessCtryStruct, _c(SRegLimits) },
	{ "Country\\DTMF"         , ProcessCtryStruct, _c(DTMF) },
	{ "Country\\THRESHOLD"    , ProcessCtryStruct, _c(Threshold) },
	{ "Country\\RLSD"         , ProcessCtryStruct, _c(RLSD) },
	{ "Country\\TONE"         , ProcessCtryStruct, _c(Tone) },
	{ "Country\\TIMING"       , ProcessCtryStruct, _c(Timing) },
	{ "Country\\CADENCE"      , ProcessCtryStruct, _c(Cadence) },
	{ "Country\\BLACKLISTING" , ProcessCtryStruct, _c(Blacklisting) },
	{ "Country\\CALLERID"     , ProcessCtryStruct, _c(CallerID) },
#ifdef CW_CID_SUPPORTED
	{ "Country\\CALLERID2"    , ProcessCtryStruct, _c(CallerID2) },
#endif
	{ "Country\\FLAGS"        , ProcessCtryStruct, _c(Flags) },
	{ "Country\\SPEEDADJUST"  , ProcessCtryStruct, _c(AgressSpeedIndex) },
#ifdef CW_CID_SUPPORTED
	{ "Country\\CALL_WAITING" , ProcessCtryStruct, _c(CallWaitingParms) },
#endif
	{ "Country\\SMART_TXLEVEL",ProcessCtryStruct  ,_c(SmartTxlevel)}, 
	{ "Country\\SMART_RELAYS",ProcessCtryStruct  , _c(SmartRelays)},
	{ "Country\\SMART_DTMF", ProcessCtryStruct,  _c(SmartDTMF)},

};
#undef _c


#define caseretstr(x) case x: return #x

static char* eCodeStr(CFGMGR_CODE eCode)
{
	switch(eCode) {
		caseretstr(CFGMGR_MS_STR);
		caseretstr(CFGMGR_MS_PARAMS);
		caseretstr(CFGMGR_EC_PARAMS);
		caseretstr(CFGMGR_COMPRESSION_PARAMS);
		caseretstr(CFGMGR_COMPRESSION_ENABLE);
		caseretstr(CFGMGR_RETRAIN_ENABLED);
		caseretstr(CFGMGR_K56_USE_ULAW);
		caseretstr(CFGMGR_DCD_ON);
		caseretstr(CFGMGR_CADENCE_PARAMS);
		caseretstr(CFGMGR_ITF_PARAMS);
		caseretstr(CFGMGR_V44_PARAMS);
		caseretstr(CFGMGR_FORCE_RENEG_UP);
		caseretstr(CFGMGR_FORCE_RENEG_DOWN);
		caseretstr(CFGMGR_IN_V34FAX);
		//caseretstr(CFGMGR_SREG);
		caseretstr(CFGMGR_NRINGS_TO_ANSWER);
		caseretstr(CFGMGR_RING_COUNTER);
		caseretstr(CFGMGR_ESCAPE_CHAR);
		caseretstr(CFGMGR_CR_CHAR);
		caseretstr(CFGMGR_LF_CHAR);
		caseretstr(CFGMGR_BS_CHAR);
		caseretstr(CFGMGR_BLIND_DIAL_WAIT_TIME);
		caseretstr(CFGMGR_CARRIER_WAIT_TIME);
		caseretstr(CFGMGR_PAUSE_DELAY_TIME);
		caseretstr(CFGMGR_CARDET_RESPONSE_TIME);
		caseretstr(CFGMGR_HANGUP_DELAY_TIME);
		caseretstr(CFGMGR_DTMF_DURATION);
		caseretstr(CFGMGR_ESCAPE_PROMPT_DELAY);
		caseretstr(CFGMGR_TEST_TIMER);
		caseretstr(CFGMGR_FLASH_DELAY_TIME);
		caseretstr(CFGMGR_INACTIVITY_TIME);
		caseretstr(CFGMGR_DATA_COMPRESSION);
		caseretstr(CFGMGR_EXTENDED_RESULT_CODES);
		caseretstr(CFGMGR_SREG_LAST);
		caseretstr(CFGMGR_DIALSTRING);
		caseretstr(CFGMGR_PULSE_DIAL_CONFIG);
		caseretstr(CFGMGR_TONE_DIAL_CONFIG);
		caseretstr(CFGMGR_DIALTONE_WAIT_TIME);
		caseretstr(CFGMGR_DIAL_MODE);
		caseretstr(CFGMGR_AMPERP);
		caseretstr(CFGMGR_USE_S7_WHEN_W);
		caseretstr(CFGMGR_INVERT_CALLING_TONE);
		caseretstr(CFGMGR_CALL_PROGRESS_TONE_DEBOUNCE);
		caseretstr(CFGMGR_CALL_MODE);
		caseretstr(CFGMGR_CALL_PROGRESS_TIMING);
		caseretstr(CFGMGR_CALL_PROGRESS_FLAGS);
		caseretstr(CFGMGR_V8BIS_CONTROL);
		caseretstr(CFGMGR_V8BIS_RESULT);
		caseretstr(CFGMGR_FIRST_CONNECTION_AFTER_TRAINING);
		caseretstr(CFGMGR_PREFERRED_FLEX_VERSION);
		caseretstr(CFGMGR_V90_ENABLED);
		caseretstr(CFGMGR_V70_ALLOWED);
		caseretstr(CFGMGR_ATRESULT_OK);
		caseretstr(CFGMGR_ATRESULT_CONNECT);
		caseretstr(CFGMGR_ATRESULT_RING);
		caseretstr(CFGMGR_ATRESULT_NOCARRIER);
		caseretstr(CFGMGR_ATRESULT_ERROR);
		caseretstr(CFGMGR_ATRESULT_NODIALTONE);
		caseretstr(CFGMGR_ATRESULT_BUSY);
		caseretstr(CFGMGR_ATRESULT_NOANSWER);
		caseretstr(CFGMGR_ATRESULT_DELAYED);
		caseretstr(CFGMGR_ATRESULT_BLACKLISTED);
		caseretstr(CFGMGR_ATRESULT_FAX);
		caseretstr(CFGMGR_ATRESULT_DATA);
		caseretstr(CFGMGR_ATRESULT_FCERROR);
		caseretstr(CFGMGR_MCR_B103);
		caseretstr(CFGMGR_MCR_B212);
		caseretstr(CFGMGR_MCR_V21);
		caseretstr(CFGMGR_MCR_V22);
		caseretstr(CFGMGR_MCR_V22B);
		caseretstr(CFGMGR_MCR_V23);
		caseretstr(CFGMGR_MCR_V32);
		caseretstr(CFGMGR_MCR_V32B);
		caseretstr(CFGMGR_MCR_V34);
		caseretstr(CFGMGR_MCR_K56);
		caseretstr(CFGMGR_MCR_V90);
		caseretstr(CFGMGR_ER_NONE);
		caseretstr(CFGMGR_ER_LAPM);
		caseretstr(CFGMGR_ER_ALT);
		caseretstr(CFGMGR_DR_ALT);
		caseretstr(CFGMGR_DR_V42B);
		caseretstr(CFGMGR_DR_NONE);
		caseretstr(CFGMGR_ATMESSAGE_I0);
		caseretstr(CFGMGR_ATMESSAGE_I1);
		caseretstr(CFGMGR_ATMESSAGE_I2);
		caseretstr(CFGMGR_ATMESSAGE_I3);
		caseretstr(CFGMGR_ATMESSAGE_I4);
		caseretstr(CFGMGR_ATMESSAGE_I5);
		caseretstr(CFGMGR_ATMESSAGE_I6);
		caseretstr(CFGMGR_ATMESSAGE_I7);
		caseretstr(CFGMGR_ATMESSAGE_I8);
		caseretstr(CFGMGR_ATMESSAGE_I9);
		caseretstr(CFGMGR_ATMESSAGE_I10);
		caseretstr(CFGMGR_ATMESSAGE_I11);
		caseretstr(CFGMGR_ATMESSAGE_I12);
		caseretstr(CFGMGR_ATMESSAGE_MANUFACTURER);
		caseretstr(CFGMGR_ATMESSAGE_MODEL);
		caseretstr(CFGMGR_ATMESSAGE_REVISION);
		caseretstr(CFGMGR_ATMESSAGE_SERIAL_NUM);
		caseretstr(CFGMGR_ATMESSAGE_GOI);
		caseretstr(CFGMGR_ATMESSAGE_CAPABILITIES);
		caseretstr(CFGMGR_DTE_ECHO);
		caseretstr(CFGMGR_DTE_CONFIG);
		caseretstr(CFGMGR_SYNC_MODE);
		caseretstr(CFGMGR_RLSD_BEHAVIOR);
		caseretstr(CFGMGR_DTR_BEHAVIOR);
		caseretstr(CFGMGR_SPEAKER_VOLUME);
		caseretstr(CFGMGR_SPEAKER_CONTROL);
		caseretstr(CFGMGR_PULSE_MAKE_BREAK);
		caseretstr(CFGMGR_RING_BURST);
		caseretstr(CFGMGR_ANSWER_TONE_DETECTOR);
		caseretstr(CFGMGR_BELL_TONE_DETECTOR);
		caseretstr(CFGMGR_DTMF_GENERATOR);
		caseretstr(CFGMGR_MODULATION_REPORT);
		//caseretstr(CFGMGR_CADENCE_BASE);
		caseretstr(CFGMGR_BUSY_TONE_CADENCE);
		caseretstr(CFGMGR_RING_CADENCE);
		caseretstr(CFGMGR_REORDER_TONE_CADENCE);
		caseretstr(CFGMGR_SDIAL_TONE_CADENCE);
		caseretstr(CFGMGR_FAX_CALL_TONE_CADENCE);
		caseretstr(CFGMGR_FAX_AUTO_ANSWER);
		caseretstr(CFGMGR_OEM_FLAGS);
		caseretstr(CFGMGR_OEM_FLAGS2);
		caseretstr(CFGMGR_OEM_FILTERS);
		caseretstr(CFGMGR_OEM_SPKR_MUTE_DELAY);
		caseretstr(CFGMGR_OEM_READ_MASK);
		caseretstr(CFGMGR_OEM_THRESHOLD);
		caseretstr(CFGMGR_COUNTRY_CODE);
		caseretstr(CFGMGR_PREVIOUS_COUNTRY_CODE);
		caseretstr(CFGMGR_COUNTRY_NAME);
		caseretstr(CFGMGR_COUNTRY_CODE_LIST);
		//caseretstr(CFGMGR_COUNTRY_STRUCT);
		caseretstr(CFGMGR_COUNTRY_BLIST);
		caseretstr(CFGMGR_FILTERS);
		caseretstr(CFGMGR_DTMF);
		caseretstr(CFGMGR_SMART_DTMF);
		caseretstr(CFGMGR_RING_PARAMS);
		caseretstr(CFGMGR_RLSDOFFSET);
		caseretstr(CFGMGR_THRESHOLD);
		caseretstr(CFGMGR_TXLEVELS);
		caseretstr(CFGMGR_SMART_TXLEVELS);
		caseretstr(CFGMGR_RELAYS);
		caseretstr(CFGMGR_SMART_RELAYS);
		caseretstr(CFGMGR_SPEED_ADJUST);
		caseretstr(CFGMGR_SREG_LIMITS);
		caseretstr(CFGMGR_PR_IGNORE_TIME);
#ifdef CW_CID_SUPPORTED
		caseretstr(CFGMGR_COUNTRY_CALLERID1);
		caseretstr(CFGMGR_COUNTRY_CALLERID2);
		caseretstr(CFGMGR_COUNTRY_CALL_WAITING);
		caseretstr(CFGMGR_VCID_FORMAT);
		caseretstr(CFGMGR_VRID_FORMAT);
		caseretstr(CFGMGR_CALL_WAITING);
		caseretstr(CFGMGR_CALLER_ID_INFO);
		caseretstr(CFGMGR_VRID_CRC);
		caseretstr(CFGMGR_VRID_TYPE);
		caseretstr(CFGMGR_VRID_LENGTH);
		caseretstr(CFGMGR_VRID_DATA);
#endif
#ifdef V92_SUPPORTED
		caseretstr(CFGMGR_MOH);
		caseretstr(CFGMGR_PCMUPSTREAM);
		caseretstr(CFGMGR_QC);
#endif // V92_SUPPORTED
		caseretstr(CFGMGR_PROFILE_STORED);
		caseretstr(CFGMGR_PROFILE_FACTORY);
		caseretstr(CFGMGR_POUND_UD);
		caseretstr(CFGMGR_ATPARSER_ONLINE);
		caseretstr(CFGMGR_BLACK_LIST);
		caseretstr(CFGMGR_SMARTDAA);
		caseretstr(CFGMGR_TONE_PRIMARY_PARAMS);
		caseretstr(CFGMGR_TONE_ALTERNATE_PARAMS);
		caseretstr(CFGMGR_TONE_ATBEL_PARAMS);
		caseretstr(CFGMGR_TONE_ATV25_PARAMS);
		caseretstr(CFGMGR_TONE_1100_PARAMS);
		caseretstr(CFGMGR_TONE_2130_PARAMS);
		caseretstr(CFGMGR_TONE_2312_PARAMS);
		caseretstr(CFGMGR_TONE_2750_PARAMS);
		caseretstr(CFGMGR_TONE_2912_PARAMS);
		caseretstr(CFGMGR_VOICETONEACALLPROG_PARAMS);
		caseretstr(CFGMGR_VOICETONEB_1100_PARAMS);
		caseretstr(CFGMGR_VOICETONEC_1300_PARAMS);
		caseretstr(CFGMGR_VOICETONEC_2100_PARAMS);
		caseretstr(CFGMGR_VOICETONEB_2225_PARAMS);
		caseretstr(CFGMGR_V8BTONE_2100_PARAMS);
		caseretstr(CFGMGR_V8BTONE_2225_PARAMS);
		caseretstr(CFGMGR_CI_CENTER_TONEB_PARAMS);
		caseretstr(CFGMGR_CI_SIDE_TONEC_PARAMS);
		caseretstr(CFGMGR_VOICEVIEW_TONEC_2912_PARAMS);
		caseretstr(CFGMGR_VOICEVIEW_TONEB_2312_PARAMS);
		caseretstr(CFGMGR_VOICEVIEW_TONEB_2750_PARAMS);
		caseretstr(CFGMGR_VOICEVIEW_TONEA_2130_PARAMS);
		caseretstr(CFGMGR_VOICEVIEW_TONEA_NOT_ST_PARAMS);
		caseretstr(CFGMGR_TONEC_1650_PARAMS);
		caseretstr(CFGMGR_CReSEG1_2002PARAMS);
		caseretstr(CFGMGR_TONE_GEN_V25CALL);
		caseretstr(CFGMGR_TONE_GEN_CNG);
		caseretstr(CFGMGR_TONE_GEN_CED);
		caseretstr(CFGMGR_TONE_GEN_CI);
		caseretstr(CFGMGR_BUFFERS_DELAY);
		caseretstr(CFGMGR_PCI_DEVICE_ID);
		caseretstr(CFGMGR_PCI_VENDOR_ID);
		caseretstr(CFGMGR_OEM_HWDATA);
		caseretstr(CFGMGR_OEM_DAATYPE);
		caseretstr(CFGMGR_OEM_SMARTDAA_PARAMS);
		caseretstr(CFGMGR_OEM_SMARTDAA_PARAMSK3);
		caseretstr(CFGMGR_HW_ADAPTER_TYPE);
		caseretstr(CFGMGR_CTRY_TONE);
		caseretstr(CFGMGR_CTRY_CADENCE);
		caseretstr(CFGMGR_CTRY_CALLERID);
		caseretstr(CFGMGR_LAST);
		default: {
					 static char buf[80];

					 if((eCode & 0xffff) == CFGMGR_COUNTRY_STRUCT) {
					 	sprintf(buf, "CFGMGR_COUNTRY_STRUCT_%02x\n", eCode >> 16);
					 } else {
					 	sprintf(buf, "code_%d\n", eCode);
					 }
					 return buf;
				 }
	}
}

int main(int argc, char **argv)
{
	FILE *pInfFile;
	FILE *pOutFile;
	int c, err = 0;
	int i;
	int j;
	CFG_TABLE CfgData[MAX_CFGCODES];
	UINT32 NumCodes = 0, NumCountries = 0, Num;

	char *inf_filename, *out_filename;

	if ((progname = strrchr(argv[0], '/')) == NULL)
		progname = argv[0];
	else
		progname++;

	while ((c = getopt(argc, argv, "v")) != -1) {
		switch(c) {
		case 'v':
			verbose++;
			break;
		default:
			err++;
		}
	}

	if(argc - optind != 2) {
		err++;
	}

	if(err) {
		fprintf(stderr, "usage : %s [-v] <INFNAME> <OUTPUTFILE>\n", progname);
		return 1;
	}

	inf_filename = argv[optind];
	out_filename = argv[optind+1];

	if(verbose) {
		printf("INF Name is %s\n", inf_filename);
		printf("Output File Name is %s\n", out_filename);
	}

	pInfFile = fopen(inf_filename, "r");

	/* handle Conv Table */
	for (i=0 ;i < sizeof(ConvTable) / sizeof(CONV_TABLE); i++)
	{
		fseek(pInfFile, 0, SEEK_SET);
		if (TRUE == HandleConvTable(pInfFile, &ConvTable[i], &CfgData[NumCodes]))
		{
			NumCodes++;
		}
	}
 
	memset(&CtryPrms, 0, sizeof(CtryPrms));
 
	/* handle Country Conv Table */
	for (i=0 ;i < sizeof(ConvCountryTable) / sizeof(COUNTRY_CONV_TABLE); i++)
	{
		fseek(pInfFile, 0, SEEK_SET);
		ConvCountryTable[i].pConvFunc(pInfFile, &ConvCountryTable[i]);
	}
	for(i=0; i < MAX_COUNTRIES; i++) {
		if(CtryPrms[i].cInter[0]) {
			NumCountries++;
		}
	}
 
	umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
	pOutFile = fopen(out_filename, "w+");
	if (!pOutFile)
	{
		fprintf(stderr, "%s: Couldn't open %s for writing\n", progname, out_filename);
		return 2;
	}

	fchmod(fileno(pOutFile), S_IRUSR|S_IWUSR);

	if(fwrite(NVM_MAGIC_HSF_VERSION, NVM_MAGIC_LENGTH, 1, pOutFile) != 1) {
		fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
		fclose(pOutFile);
		return 2;
	}

	Num = sizeof(HSFLINUXVERSION);
	if(fwrite(&Num, sizeof(Num), 1, pOutFile) != 1) {
		fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
		fclose(pOutFile);
		return 2;
	}

	if(fwrite(HSFLINUXVERSION, sizeof(HSFLINUXVERSION), 1, pOutFile) != 1) {
		fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
		fclose(pOutFile);
		return 2;
	}

	Num = NumCodes + NumCountries;
	if(fwrite(&Num, sizeof(Num), 1, pOutFile) != 1) {
		fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
		fclose(pOutFile);
		return 2;
	}

	if(verbose) {
		printf("There were %ld keys found\n",NumCodes);
		printf("---------------------------------------------------------------------\n");
		printf("\tCfgCode\tSize\n");
	}

	for (i=0;i<NumCodes;i++)
	{
		if(verbose) {
			printf("\t%s\t%ld\t", eCodeStr(CfgData[i].CfgCode), CfgData[i].Size);
			for ( j=0;j<CfgData[i].Size ; j++ )
			{
				printf(" %02x",CfgData[i].Data[j]);
			}
			printf("\n");
		}
		if(fwrite(&CfgData[i].CfgCode, sizeof(CFGMGR_CODE), 1, pOutFile) != 1) {
			fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
			fclose(pOutFile);
			return 2;
		}
		if(fwrite(&CfgData[i].Size, sizeof(UINT32), 1, pOutFile) != 1) {
			fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
			fclose(pOutFile);
			return 2;
		}
		if(fwrite(CfgData[i].Data, CfgData[i].Size, 1, pOutFile) != 1) {
			fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
			fclose(pOutFile);
			return 2;
		}
	}

	if(verbose)
		printf("\n\tCty\tCfgCode\t\tT35Code\tName\n");
	for(i=0; i < MAX_COUNTRIES; i++) {
		if(CtryPrms[i].cInter[0]) {
			CFGMGR_CODE c = CFGMGR_COUNTRY_STRUCT | (CtryPrms[i].T35Code << 16);
			UINT32 s = sizeof(CtryPrmsStruct);

			if(fwrite(&c, sizeof(CFGMGR_CODE), 1, pOutFile) != 1) {
				fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
				fclose(pOutFile);
				return 2;
			}
			if(fwrite(&s, sizeof(UINT32), 1, pOutFile) != 1) {
				fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
				fclose(pOutFile);
				return 2;
			}
			if(fwrite(&CtryPrms[i], s, 1, pOutFile) != 1) {
				fprintf(stderr, "%s: Error writing to %s\n", progname, out_filename);
				fclose(pOutFile);
				return 2;
			}

			if(verbose)
				printf("\t%d\t%s\t0x%02x\t%s\n",i,eCodeStr(c),CtryPrms[i].T35Code,CtryPrms[i].cInter);
		}
	}

	if(verbose)
		printf("---------------------------------------------------------------------\n");

	if(fclose(pOutFile)) {
		fprintf(stderr, "%s: Error closing %s\n", progname, out_filename);
		return 3;
	}

	fclose(pInfFile);

	return 0;
}
