// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include <e32std.h>
#include <msventry.h>
#include <bsp.h>
#include <wapp.h>
#include <wappdef.h>
#include "wapperr.h"
#include <wappstr.rsg>

#include "CWappBookmark.h"
#include "IspTableData.h"
#include "IpBearerData.h"
#include "SmsBearerData.h"
#include "GprsBearerData.h"

#include <mmssettingsproxybase.h>

#include <msvstd.h>
#include <msventry.h>
#include <msvids.h>
#include <msvuids.h>
#include <mtclreg.h>

#include <ipaddr.h>
#include <barsc.h>
#include <barsread.h>
#include <bautils.h>

#include <cbioasyncwaiter.h>
#include <cmsvattachment.h>
#include <mmsvattachmentmanager.h>
#include <mmsvattachmentmanagersync.h>

#ifdef SYMBIAN_BOOKMARK_DATABASE
#include <bookmarkdatabase.h>
#include <bookmark.h>
#endif // SYMBIAN_BOOKMARK_DATABASE

#ifdef _DEBUG
const TUid KUidSmartMessageMtm = {0x10001262};
const TInt32 KUidBIOWAPAccessPointMsg = 0x10005532;
#endif

const TInt KMaxNameBufferLength = 35;

_LIT8(KCRLinefeed,			"\r\n");
_LIT8(KEBookmarkItemBegin,	"BEGIN:eBOOKMARK\r\n");		//  Precedes a Bookmark in the Bookmark file
_LIT8(KEBookmarkItemName,	"NAME:");	// Precedes a Bookmark Name
_LIT8(KEBookmarkItemURL,	"URL:");		// Precedes a Bookmark URL
_LIT8(KEBookmarkType,		"TYPE:Wap\r\n");
_LIT8(KEBookmarkItemEnd,	"END:eBOOKMARK\r\n");

_LIT(KEBookmarkExtension,	".eBM");

_LIT(KWappResourceFile, "\\resource\\messaging\\wappstr.rsc");

const TUint32 KCharsetUCS2 = 1000;
const TUint32 KCharsetUTF8 = 106;
const TUint32 KCharsetASCII = 3;


// The number of characters that are constant for an eBookmark
// file. It is the sum of the above literals.
// 
const TInt KEBookmarkConstantChars = 55;

CMsvBIOWapAccessParser::CMsvBIOWapAccessParser(CRegisteredParserDll& aRegisteredParserDll, CMsvEntry& aEntry, RFs& aFs)
: CBaseScriptParser2(aRegisteredParserDll, aEntry, aFs)
   {
   }

EXPORT_C CMsvBIOWapAccessParser* CMsvBIOWapAccessParser::NewL(CRegisteredParserDll& aRegisteredParserDll, CMsvEntry& aEntry, RFs& aFs)
    {
    CMsvBIOWapAccessParser* self = new (ELeave) CMsvBIOWapAccessParser(aRegisteredParserDll, aEntry, aFs);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

CMsvBIOWapAccessParser::~CMsvBIOWapAccessParser()
    {
	Cancel();
	// Char Conversion
	delete iCharsetConverter;
    delete iSettings;
	delete iSmsBuf;
	delete iStringTable;
	if (iBookmarkList!=NULL)
		{
		iBookmarkList->ResetAndDestroy();
		delete iBookmarkList;
		}
	delete iModemInitString;
    if (iParsedFieldArray != NULL)
        {
        iParsedFieldArray->ResetAndDestroy();
        delete iParsedFieldArray;
        }
	delete iWapIpISPTable;
	delete iWapSmsTable;
	delete iWapGprsTable;
	delete iGsmCsdWapIpTable;
	delete iGprsWapIpTable;

	delete iDBSession;
	REComSession::FinalClose();
    }

//
//	ConstructL			- ConstructL fn - creates the Parsed Field array, 
//						  and connects the file system if unconnected
//	
void CMsvBIOWapAccessParser::ConstructL()
    {
	iParsedFieldArray = new(ELeave) CArrayPtrSeg<CParsedField>(16);	
	iDBSession = CMDBSession::NewL(CMDBSession::LatestVersion());
	iBookmarkList = new(ELeave) CArrayPtrSeg<CWappBookmark> (4);// 4 should be enough
	iGsmCsdData = EFalse;
	iGsmSmsData = EFalse;
	iGprsData	= EFalse;
	iURLData	= EFalse;
	iNameData	= EFalse;
	iIdData		= EFalse;
	iMMSURLData = EFalse;
    CActiveScheduler::Add(this);
    }

//
//	ParseL		- public method forming part of the API.  Calls ChangeState to set 
//				  state for parsing. Helper functions do the parsing
//
void CMsvBIOWapAccessParser::ParseL(TRequestStatus& aStatus, const TDesC& aSms)
    {
    TMsvEntry entry = iEntry.Entry();   //  Get the generic stuff
    iEntryId = entry.Id();              //  store the TMsvId

	// Message must be unparsed, or parsed or committed - anything else is a big error
    __ASSERT_DEBUG((   entry.MtmData3() == BIO_MSG_ENTRY_UNPARSED
					|| entry.MtmData3() == BIO_MSG_ENTRY_PARSED
					|| entry.MtmData3() == BIO_MSG_ENTRY_PROCESSED),
                            Panic(EWappErrMessageProcessed));
	
	// Message must not be empty 
	__ASSERT_DEBUG (aSms.Length() > 0 ,Panic( EWappEmptyBuffer));

   //  Already parsed....just return
    if(entry.MtmData3() == BIO_MSG_ENTRY_PARSED || entry.MtmData3() == BIO_MSG_ENTRY_PROCESSED)
        {
        iReport = &aStatus;
        User::RequestComplete(iReport, KErrNone);
        }
    //  not parsed so start the Parsing operation
    else if(entry.MtmData3() == BIO_MSG_ENTRY_UNPARSED)
        {
        delete iSmsBuf;
        iSettings = NULL;
        iSmsBuf = aSms.AllocL();
        ChangeStateL(EStart);		// Do do initial processing, and go Active
        aStatus = KRequestPending;
        iReport = &aStatus;
        }
    else
        {
        User::Leave(KErrNotSupported);
        }
    }

//
//  ProcessL() --   If  parsed data is not already in memory, ProcessL loads it from the store
//					created during parsing. Creates a new entry in the WAP settings CommDb tables, from the data
//
void CMsvBIOWapAccessParser::ProcessL(TRequestStatus& aStatus)
    {
	// Calls ChangeState to get State Engine going. ( DoProcess does the hard work)

	iEntryId= iEntry.Entry().Id(); //store id of Bio Msg entry 

	// Must be a smart/Bio message, of type WAP access point and not have the failure flag set
	__ASSERT_DEBUG(iEntry.Entry().iMtm==KUidSmartMessageMtm, Panic(EWappInvalidEntry));
	__ASSERT_DEBUG(iEntry.Entry().iBioType ==KUidBIOWAPAccessPointMsg, Panic(EWappInvalidEntry));
	__ASSERT_DEBUG(iEntry.Entry().Failed()== 0 , Panic(EWappInvalidEntry));

	ResetProcessVariablesL();       // Reset variables to initial state
	ChangeStateL(EProcessInitialise);   //Set the initial state

	aStatus = KRequestPending;
	iReport = &aStatus; 	
   	}

//	 DoCancel	-  Cancels the Active Object operation and returns control to the caller
//
void CMsvBIOWapAccessParser::DoCancel()
    {
	User::RequestComplete(iReport,KErrCancel);
    }

//
//	RunL()		-		Called by the Active Scheduler when it finishes its Wait Loop. 
//						Doesn't do much as ParseL and Process keep going until they are complete.
//						Returns the current status. 
//
void CMsvBIOWapAccessParser::RunL()
    {
    iCompleted = iStatus.Int();

	if (iCompleted != KErrNone)
		{
		User::RequestComplete(iReport,iCompleted);
		return;
		}
	TInt currentState = iState;
	TRAPD(error, CallChangeStateL(currentState));
	switch (currentState)
		{
		case EStart:
		case EProcessInitialise:
		case EProcessMessage:
			if (error!=KErrNone)
				User::RequestComplete(iReport, error);  // Return error code
			break;
		case EParseMessage:
		case ECompleteMessage:
			User::RequestComplete(iReport, iCompleted); // Nothing more - allow calling RunL to complete and return status
			break;
		default:
			break;
		}
    }

void CMsvBIOWapAccessParser::CallChangeStateL(TInt aState)
	{
	switch (aState)
		{
		case EStart:
			ChangeStateL(EParseMessage);
			break;
		case EProcessInitialise:
			ChangeStateL(EProcessMessage);
			break;
		case EProcessMessage:
			ChangeStateL(ECompleteMessage);  // last stage change iMtmData3 
			break;
		default:
			break;
		}
	}

//
//	ChangeStateL		-	Used to advance the state to the next level.
//							Makes most of the important calls.
//
void CMsvBIOWapAccessParser::ChangeStateL(TParseSession aState)
    {
	iState = aState;
    switch (iState)
        {                    
		case EStart:	// Check the data we've got - if OK get the Active Stuff going
			if (!iSmsBuf)			
				User::Leave(KWappErrNullValue);
			else if (iSmsBuf->Length() == 0)
				User::Leave(KWappErrContent);
			break;
        case EParseMessage:
			iSms = iSmsBuf->Des();      // initialise TLex object
			ParseMessageL();
            break;
		case EProcessInitialise:
			if (!iSmsParsed)
				RestoreParsedDataL();
			PreProcessL();  //Scan iParsedFieldArray extracting data - leaves if data is invalid
			ValidateCharacteristicsL(); // Ensures that the mix of characteristic is valid
			break;
		case EProcessMessage:
			DoProcessL(); // Do the proper processing of and committing to CommDb
			break;
		case ECompleteMessage:
			CompleteMessageL();
			break;
        default:
            break;
        }

	// Finished this step -add ourselves to Scheduler,& return error code to calling thread.
	RequestComplete(iStatus, KErrNone); 
	SetActive();
    }

//
//	ParseMessageL()		- Performs various checks, if data has been saved it restores it  
//						  else it calls DoParseL which does the hard stuff).
//
void CMsvBIOWapAccessParser::ParseMessageL()
	{
	// MUST have Bio message, of type WAP access point and no failure flag set
	__ASSERT_DEBUG(iEntry.Entry().iMtm==KUidSmartMessageMtm, Panic(EWappInvalidEntry));
	__ASSERT_DEBUG(iEntry.Entry().iBioType ==KUidBIOWAPAccessPointMsg, Panic(EWappInvalidEntry));
	__ASSERT_DEBUG(iEntry.Entry().Failed()== 0 , Panic(EWappInvalidEntry));

	// Message already parsed(includes processed).  Just restore data and return
	if (iEntry.Entry().MtmData3() == BIO_MSG_ENTRY_PARSED || 
		iEntry.Entry().MtmData3() == BIO_MSG_ENTRY_PROCESSED)
		iSmsParsed = ETrue;   // Have a store produced during parsing. 
	else 
		iSmsParsed = EFalse;

	if(iSmsParsed)  // parsed before - restore data
		{
		RestoreParsedDataL();
		return;
		}

	DoParseL();			// Does the actual parsing of the message contents
	SettingsNamePresentL(); // Check for Name Characteristic- if not found appends a default one
	StoreParsedDataL(); // Saves the parsed fields to store & sets TMSvEntry values
	iSmsParsed=ETrue;
	}

//
//  CompleteMessageL()	-	Completes the ProcessL operation, by setting the iMtmData3 
//							flag to BIO_MSG_ENTRY_PROCESSEDMessage body, and TMsvEntry's
//							iDescription and iDetails are left unchanged
//
void CMsvBIOWapAccessParser::CompleteMessageL()
    {
	TMsvEntry entry= iEntry.Entry();
	entry.SetMtmData3(BIO_MSG_ENTRY_PROCESSED);

	iEntry.ChangeL(entry);
    }

//
//	RequestComplete()	-	Completes an AO operation, and passes control back to the caller
//
void CMsvBIOWapAccessParser::RequestComplete(TRequestStatus& aStatus, TInt aError)
    {
    TRequestStatus* p = &aStatus;
    User::RequestComplete(p, aError);
    }

//
//  DoParseL()		- Parses through encoded message body extracting the fields from the characteristics
//					Uses helper functions to handle reading and storing of characteristics and parms. 
//					Parsing performed in one continuous operation.
//
void CMsvBIOWapAccessParser::DoParseL()
    {
	const TInt KDecimalSizeOfMaxInt = 10; // length of 0xFFFFFFFF in a string in decimal
	TBuf<KDecimalSizeOfMaxInt> localBuf;
	TChar thisCharacter;
 
	thisCharacter = GetNextMessageByteL();	// Read the first char to get XML version number
	/*
	The version byte contains the the major version minus one in the upper four bits 
	of the 8 bit integer, and the minor version in the lower four bits.
	*/
	TUint wbxmlversionbyte = thisCharacter; 
	TUint majorversion = ((wbxmlversionbyte & 0xF0) + 0x10) - 0x0F; // gives the major version, eg if wbxml spec version 1.2, it gives 1.
	TUint minorversion = wbxmlversionbyte & 0x0F; //gives the minor version, eg if wbxml spec version 1.2, it gives 2.
	
	iWBXMLversionX10 = (majorversion *10) + minorversion; //i.e. If actual version is 1.1 this is *10 to remove the decimal place.

	//Append this to the array
	localBuf.NumUC(iWBXMLversionX10,EDecimal);  //Format to a decimal string
	AppendDataPairL(KWappXMLversion, localBuf); // Append to array of parsed fields

	// Now need to get the 32bit int encoded over a number of bytes
	iPublicID = Read_mb_u_int32L();		// Read in a multi byte 32bit int value
	localBuf.NumUC(iPublicID, EHex);	// Format to a string as hex 
	AppendDataPairL(KWappPublicID, localBuf); 
	
	// WAP Binary XML version 1.1 also has additional info for the character set.
	if (iWBXMLversionX10 !=10)				// If WAP Binary XML version > 1.0
		iCharacterSet = Read_mb_u_int32L(); // Get the character set
	else
		//This is the character set MIBenum for UTF-8. 
		//According to WBXML spec version 1.1 and 1.2, this is the default which should 
		//be assumed if the charset value is not available. Value 0 must not be used. 
		iCharacterSet = 106; 

	delete iCharsetConverter;
	iCharsetConverter = NULL;
	iCharsetConverter = CWapCharsetConverter::NewL(iFs, iCharacterSet);

	localBuf.NumUC(iCharacterSet, EHex);	// Convert to string as hex 
	AppendDataPairL(KWappCharacterSet,localBuf);

	// Coded string table length - don't need this once we have string table
	// as we store copies of the strings within parsed data fields 
	TUint32 stringTableLength = Read_mb_u_int32L();

	//Read in string table if it exists, i.e. length >0 otherwise skip this step
	if (stringTableLength>0) 
		{
		iStringTable = HBufC::NewL(stringTableLength);
		iSms.Mark();					// Mark the current position

		TUint32 remaining = iSms.RemainderFromMark().Length(); //Eliminates warning about comparison in next line
		
		if ( remaining > stringTableLength) // Sting Table doesn't exceed end of message
			iSms.Inc(stringTableLength);	// so increment to the character following the string table
		else
			User::Leave(KWappErrEOS); // Table exceeds message length - unrecoverable error
		iStringTable->Des().Copy(iSms.MarkedToken());
		}

	thisCharacter = GetNextMessageByteL();
	//This should be a Characteristic List with content, but no attributes
	if (thisCharacter == (KWAPP_CHAR_LIST+KWAPP_TAG_CONTENT))
		{
		// Main loop - keep moving through the message, until we reach the end or error
		TBool finished = EFalse;
		while (!finished)
			{		
			// Read in characteristics, any order is accepted
			if (!iSms.Eos() && (iSms.Peek() & 0x3F) == KWAPP_CHARACTERISTIC)
				{
				// Read in characteristic, inc. its terminator tag - no terminator =error!
				ReadCharacteristicL();
				}
			else
				{
				if (iSms.Eos()) // Error end of message
					User::Leave(KWappErrEOS);
				else if ((TUint)iSms.Peek()==KWAPP_END_TAG) // END Tag - OK we've finished!
					finished = ETrue;
				else if ( (iSms.Peek()& 0x3F != KWAPP_CHARACTERISTIC) || (iSms.Peek() != KWAPP_END_TAG) )
					User::Leave(KWappErrUnexpectedValue); //Not a Characteristic or END token
				}
			}
		} // End of if (thisCharacter == (KWAPP_CHAR_LIST..... )
	else
		User::Leave(KWappErrMandatoryTagMissing);
    }
// end CMsvBIOWapAccessParser::DoParseL()

//	
//	ReadCharacteristicL()		-  Reads in a characteristic from the message.
//
void  CMsvBIOWapAccessParser::ReadCharacteristicL()
	{
	TBool hasContent;
	TInt  characteristicIndex=0; // start position in array for this characteristic
	CParsedField* parsedField = new(ELeave)CParsedField();
	CleanupStack::PushL(parsedField);		

	TChar currentCharacter = GetNextMessageByteL();
	iCurrentCharacteristic =EWappUnknown; // Reset flag for current characteristic's type

	// Use bit comparison of token with mask 0x3F to check explicitly that correct 
	// bits are set i.e. that bits 0-5 = 0x06   (NB Actual value = 0x86 or =0xC6)
	if ( ( currentCharacter & 0x3F) != KWAPP_CHARACTERISTIC ) // i.e. not or 0x06
		User::Leave(KWappErrUnexpectedValue);		
	else
		{
		if ( !(currentCharacter & KWAPP_TAG_ATTRIBUTES)) // Bit 7 must be set!
			User::Leave(KWappErrNoAttributes); 
		if (currentCharacter & KWAPP_TAG_CONTENT)  //Bit 6 is set - characteristic has content
			hasContent =ETrue;
		else
			hasContent =EFalse;


	// ***************			IMPORTANT NOTE		   ************************
	// An XML element name without a defined token is sent as an inline string or
	// string table ref. prefixed by the TYPE token 0x05 (ie "TYPE="). (True for
	// WirelessFuture web site!!) THE ONLY UNDEFINED Type tag is BOOKMARK in version
	// 1.0. Therefore if it's 0x05  - check the version. For 1.0 read next char.
	// Token must be an inline string or string table ref.Otherwise we have an error.
	// ****************************************************************************

		// Read the next byte - info on the type of our characteristic  
		currentCharacter = (TUint) GetNextMessageByteL();
		
		// Check if the tokens 0x05 "TYPE=" - should be for WBXML version = 1.0 
		// Read next character
		if (currentCharacter == KWAPP_TYPE)
			{
			// "TYPE=" should be followed by an inline string, or string table reference
			// So read another char & increment a place - should now 0x03 or 0x83
			currentCharacter = (TUint) GetNextMessageByteL();
			if  (	!(currentCharacter & KWAPP_STR_I) &&	// Is current character != 0x03 ?
					!(currentCharacter & KWAPP_STR_T))		// or != 0x83 
				 User::Leave(KWappErrUnexpectedValue);		// Doc is badly formed doc - leave
			}

	// NB for address characteristics, need to store position of the start, so that
	// we can search for certain fields. If they're not present we must add defaults.  
	// Could just scan from the end of the array, but if we miss our target then may
	// just increment past this characteristic, through previous ones.
 
		switch (currentCharacter)
			{
			case KWAPP_ADDR_TYPE:  // Token = 0x06
				{
				AppendNameFieldL(KWappCharAddress);		
				characteristicIndex = iParsedFieldArray->Count()-1; // Store index for this element
				iCurrentCharacteristic = EWappAddressCharacteristic; //General code for an address
				break;
				}
			case KWAPP_URL_TYPE:   //Token = 0x07
				{
				AppendNameFieldL(KWappCharURL);
				iCurrentCharacteristic  = EWappURLCharacteristic; // it's a URL characteristic
				break;
				}
			case KWAPP_NAME_TYPE:  // Token = 0x08
				{
				AppendNameFieldL(KWappCharName); 
				iCurrentCharacteristic = EWappNameCharacteristic;//it's a NAME characteristic
				break;
				}
			case KWAPP_STR_I:		// Token = 0x03  , Global WAP XML value
				{
				// Null terminated inline string follows the token, call fn to read it
				parsedField->SetFieldNameL(*ReadInlineStringLC());
				CleanupStack::PopAndDestroy(); //inline string
				break;
				}
			case KWAPP_STR_T:		// Token = 0x83,  Global WAP XML value
				{
				// multi byte 32 bit integer follows, an reference to an offset in the string table
				TUint32 offset =0;
				offset = Read_mb_u_int32L(); // read in the integer
				parsedField->SetFieldNameL(*ReadStringTableReferenceLC(offset));//Get string table value,& set the descriptor
				CleanupStack::PopAndDestroy(); // string table reference
				break;
				}
			case KWAPP_ID:			// Token = 0x7D.  Used in version 5.0
				{
				AppendNameFieldL(KWappCharID);  
				iCurrentCharacteristic = EWappIDCharacteristic; 
				break;
				}
			case KWAPP_BOOKMARK:	// Token = 07F, currently bookmarks stored in file
				{
				AppendNameFieldL(KWappCharBookmark);  
				iCurrentCharacteristic = EWappBookmarkCharacteristic; 
				break;
				}
			case KWAPP_MMS_URL:
				{
				AppendNameFieldL(KWappCharMMSURL);
				iCurrentCharacteristic = EWappMMSURLCharacteristic;
				break;
				}
			default:
				User::Leave(KWappErrUnrecognised);   // Unrecognised token or somethings badly wrong
			}
		

		// If iCurrentCharacteristic isn't set we've just read in a string table ref
		// or inline string. Now check the token and set the flag.
		if (iCurrentCharacteristic == EWappUnknown)
			{
			// Get index of last element
			if (parsedField->FieldName().CompareF(KWappAddr)==0)
				{
				iCurrentCharacteristic = EWappAddressCharacteristic; 
				AppendNameFieldL(KWappCharAddress);	
				characteristicIndex = iParsedFieldArray->Count()-1;//May be an address so store index
				}
			else if (parsedField->FieldName().CompareF(KWappURL)==0)
				{
				iCurrentCharacteristic = EWappURLCharacteristic;
				AppendNameFieldL(KWappCharURL);
				}
			else if (parsedField->FieldName().CompareF(KWappMMSURL)==0)
				{
				iCurrentCharacteristic = EWappMMSURLCharacteristic;
				AppendNameFieldL(KWappCharMMSURL);
				}
			else if (parsedField->FieldName().CompareF(KWappName)==0)
				{
				iCurrentCharacteristic = EWappNameCharacteristic;
				AppendNameFieldL(KWappCharName); 
				}
			else if (parsedField->FieldName().CompareF(KWappBookmark)==0)
				{
				iCurrentCharacteristic = EWappBookmarkCharacteristic;
				AppendNameFieldL(KWappCharBookmark);
				}
			else if (parsedField->FieldName().CompareF(KWappID)==0)
				{
				iCurrentCharacteristic = EWappIDCharacteristic;
				AppendNameFieldL(KWappCharID); 
				}
			else 
				{
				User::Leave(KWappErrUnrecognised);// Unrecognised characteristic type 
				}
			}		
		CleanupStack::PopAndDestroy(parsedField);
	
		//Check for a VALUE attribute before checking for Parms
		currentCharacter =(TUint) GetNextMessageByteL();
		if (currentCharacter ==KWAPP_VALUE_ATTRIB)
			{
			// Have a value following the TYPE - read in value and store it.
			TInt  lastElement = iParsedFieldArray->Count()-1;
			currentCharacter = (TUint) GetNextMessageByteL();

			if (currentCharacter == KWAPP_STR_I)		//Inline string
				{
				iParsedFieldArray->At(lastElement)->SetFieldValueL(*ReadInlineStringLC()); //Set value of last element in array
				CleanupStack::PopAndDestroy();
				}

			else if (currentCharacter ==KWAPP_STR_T)	//String table reference
				{
				TUint32 tableOffset = Read_mb_u_int32L();
				iParsedFieldArray->At(lastElement)->SetFieldValueL(*ReadStringTableReferenceLC(tableOffset));  //Set Value of last element in array
				CleanupStack::PopAndDestroy();
				}

			else 
				{
				User::Leave(KWappErrUnexpectedValue);
				}

			// Read the next character for the END TAG check in the following line 
			currentCharacter = (TUint)GetNextMessageByteL();
			}

		//Check the character- should be 0x01 the end of the characteristic header
		if (!currentCharacter ==KWAPP_END_TAG) // Not END - error condition
			{
			User::Leave(KWappErrNoTermination); 
			}

		// We shouldn't be at the end of the message. The next byte should be one of the following 
		//	    - PARM if this characteristic has content, 
		//		- start of another characteristic
		//		- END token (0x01).
		// So take a peek at the next byte
		TUint peekAhead;

		if (iSms.Eos())
			User::Leave(KWappErrEOS);	// Somethings wrong - message end
		
		peekAhead = (TUint) iSms.Peek();

		// Type is Set - address,URL,Name, Bookmark or ID. Check hasContent flag set correctly. 
		if ( ((iCurrentCharacteristic == EWappAddressCharacteristic) && !hasContent) || //Address must have Content
		     ((iCurrentCharacteristic == EWappNameCharacteristic) && !hasContent)	 ||  //Name must have Content
			 ((iCurrentCharacteristic == EWappBookmarkCharacteristic) && !hasContent)|| //Bookmark must have Content
			 ((iCurrentCharacteristic == EWappIDCharacteristic) && !hasContent)		 || //ID must have Content
			 ((iCurrentCharacteristic == EWappURLCharacteristic) && hasContent)		 ||  // Url must NOT have Content
			 ((iCurrentCharacteristic == EWappMMSURLCharacteristic) && hasContent)     )  // MmsUrl does not have content
			 User::Leave(KWappErrContent); // Test for validity of content flag failed.
			

		if (hasContent)  // passed previous test, - exclude URL as hasContent=EFalse
			{
			if ( (peekAhead & 0x3F) ==KWAPP_PARM) // bit comparison with 0x07
				{
				// Check sucessful, now check for attributes and content (0x80, & 0x40)
				if ( (peekAhead & KWAPP_TAG_ATTRIBUTES) && ( !(peekAhead & KWAPP_TAG_CONTENT) ) )
					{
					//Have attributes, and no content - ALL OK!
					currentCharacter = (TUint32) GetNextMessageByteL();
					while (currentCharacter != KWAPP_END_TAG)
						{
						ReadParmL(); // Sets iCurrentCharacteristic for addresses
						
						currentCharacter = (TUint32) GetNextMessageByteL();  // Get the next character from message
						
						if ( (currentCharacter != (KWAPP_PARM+KWAPP_TAG_ATTRIBUTES))
							&& (currentCharacter !=KWAPP_END_TAG) ) // Not 0x87, nor 0x01 = error
							User::Leave(KWappErrUnexpectedValue); 
						}
					}
				else  // Token MUST be 0x87, parms MUST have content but NO attributes!
					User::Leave(KWappErrNoAttributes);  
				}
			else  //Bits 0-5 are Not 0x07  Should be a PARM token
				User::Leave(KWappErrUnexpectedValue); 
			} //END of (hasContent)
		}
		// END of  if ( !( (TUint32)currentCharacter & KWAPP_CHARACTERISTIC) )



// ************************** MANDATORY PARMS & DEFAULT VALUES **************************
// Finished reading in the parms for the characteristic.  Each Address Characteristic 
// has it's own set of defaults. If this is an address - ensure defaults are present.
		

// CHARACTERISTIC TYPE = ADDRESS, BEARER TYPE  = GSM/CSD or IS-136/CSD
//	 Bearer, Proxy, and Csd_Dialstring are mandatory..
//   Auth. Names and Passwords don't have defaults so are not set here!
		
		if ( iCurrentCharacteristic == EWappGsmCsdCharacteristic||
			iCurrentCharacteristic == EWappIS136CsdCharacteristic )
			{
			//Required PARMS				OTA v4.0	   v5.0
			//CSD-		PROXY					Y			Y
			//			PORT				add default of 9200	
			//			CSD_DIALSTRING			Y			Y
			//			CSD_AUTHNAME			Y			N
			//			CSD_AUTHSECRET			Y			N
			//			CSD_CALLTYPE			Y		Add default of PAP
			//			CSD_CALLSPEED		    Y       Add default of AUTO

			// Check mandatory PARMS present else bad message - unrecoverable error!
			TInt index;
		
			// OTA v4.0 & 5.0:  required Parms present?
			index = LocateParsedFieldName(KWappProxy,characteristicIndex);
			if (index == KErrNotFound) // TODO can this be null? || (iParsedFieldArray->At(index)->FieldValue() == TPtrC()))
				User::Leave(KWappErrMandatoryTagMissing);
			
			index = LocateParsedFieldName(KWappCsdDial,characteristicIndex);
			if (index == KErrNotFound) // Can this be Null?? || (iParsedFieldArray->At(index)->FieldValue() == TPtrC()) )
				User::Leave(KWappErrMandatoryTagMissing); 

			// OTA v4.0 only, mandatory Parms  present?
			if (iWBXMLversionX10 == 10)
				{
				index = LocateParsedFieldName(KWappPPPAuthName,characteristicIndex);
				if (index == KErrNotFound)// Can this be NULL || (iParsedFieldArray->At(index)->FieldValue() == TPtrC()))
					User::Leave(KWappErrMandatoryTagMissing);
			
				index = LocateParsedFieldName(KWappPPPAuthSecret,characteristicIndex);
				if (index == KErrNotFound) // Can this be a Null value? || (iParsedFieldArray->At(index)->FieldValue() == TPtrC()) )
					User::Leave(KWappErrMandatoryTagMissing); 
				}

			// Search for PORT from beginning of this characteristic to array end or next 
			// Characteristic - whichever's first. NB this is currently the last characteristic in array!

			index = LocateParsedFieldName(KWappPort, characteristicIndex);
			if (index ==KErrNotFound)	// Not Found - add the default value
				{
				index = LocateParsedFieldName(KWappProxy,characteristicIndex); // Mandatory - check already made
				InsertDataPairL(KWappPort, KWappPort9200, index+1);
				}
			
			// Check for the PPP_AUTHTYPE element
			index = LocateParsedFieldName(KWappPPPAuthType, characteristicIndex);
			if (index ==KErrNotFound)	// Not Found - add the default value
				{
				index = LocateParsedFieldName(KWappCsdDial, characteristicIndex); // always present
				// Create new element,NAME="PPP_CALLTYPE", VALUE="PAP"
				InsertDataPairL(KWappPPPAuthType, KWappPAP, index+1);
				}

			// Check for the CSD_CALLTYPE element
			index = LocateParsedFieldName(KWappCsdCallType, characteristicIndex);
			if (index ==KErrNotFound)	// Not Found - add the default value
				{
				index = LocateParsedFieldName(KWappPPPAuthType, characteristicIndex); 
				if (index ==KErrNotFound)
					User::Leave(KWappErrMandatoryTagMissing); // Error - should be here from step above!!!
				else
					// Create new element,NAME="CSD_CALLTYPE", VALUE="ANALOGUE"
					InsertDataPairL(KWappCsdCallType, KWappAnalogue, index+1);
				}

			// Check for the CSD_CALLSPEED element
			index = LocateParsedFieldName(KWappCsdCallSpeed, characteristicIndex);
			if (index ==KErrNotFound)	// Not Found - add the default value
				{
				index = LocateParsedFieldName(KWappCsdCallType,characteristicIndex);
				if (index ==KErrNotFound)
					User::Leave(KWappErrMandatoryTagMissing); // Error - should be here from step above!!!
				else				
					//Create new PARM,
					// If CSD_CALLTYPE="ANALOGUE"   ->  NAME="CSD_CALLSPEED", VALUE="AUTO" 
					// else if CSD_CALLTYPE="ISDN"  ->  NAME="CSD_CALLSPEED", VALUE="9600" 
					if (iParsedFieldArray->At(index)->FieldValue().CompareF(KWappISDN)==0)
						InsertDataPairL(KWappCsdCallSpeed, KWappSpeed9600, index+1);
					else
						InsertDataPairL(KWappCsdCallSpeed, KWappSpeedAuto, index+1);
				}
			}// END of if(iCurrentCharacteristic == EWappCSDCharacteristic)|| .......


// CHARACTERISTIC TYPE = ADDRESS, BEARER TYPE  = GSM/SMS 
// Only the PORT PARM value is optional - all the rest are mandatory
		
		if (iCurrentCharacteristic == EWappGsmSmsCharacteristic)
			{
			//Required PARMS				OTA v4.0	   v5.0
			//SMS-		PROXY					Y			Y
			//			SMS_SMSC_ADDRESS		Y
	
			// Check that required fields are present - badly formed message otherwise
			TInt fieldIndex = LocateParsedFieldName(KWappProxy, characteristicIndex);
			if (fieldIndex == KErrNotFound ) // TODO Check if this can be null || (iParsedFieldArray->At(fieldIndex)->FieldValue().Length()==0) )
				User::Leave(KWappErrMandatoryTagMissing); 

			fieldIndex = LocateParsedFieldName(KWappSMSCAddress, characteristicIndex);
			if ((fieldIndex ==KErrNotFound)) // TODO Check if this can be null   || (iParsedFieldArray->At(fieldIndex)->FieldValue().Length()==0) )
				User::Leave(KWappErrMandatoryTagMissing);


			if (LocateParsedFieldName(KWappPort, characteristicIndex) ==KErrNotFound) //Tag not found
				{
				fieldIndex = LocateParsedFieldName(KWappProxy, characteristicIndex); //Mandatory field
				// Create a new  element, NAME="PORT", VALUE="9200"
				InsertDataPairL(KWappPort,KWappPort9200, fieldIndex+1);
				}
			}//END of  if(iCurrentCharacteristic == EWappSMSCharacteristic)


// CHARACTERISTIC TYPE = ADDRESS, BEARER TYPE  = GSM/USSD 
		if (iCurrentCharacteristic == EWappGsmUssdCharacteristic)
			{
			
			//Only USSD Service Code is mandatory - MUST not be NULL
			TInt index = LocateParsedFieldName(KWappUSSDCode, characteristicIndex);
			if (index == KErrNotFound || iParsedFieldArray->At(index)->FieldValue().Length()==0)
				User::Leave(KWappErrMandatoryTagMissing);
			
			// PROXY is optional for USSD but has no default value
			// Do have defaults for PROXY_TYPE and PORT
			if (LocateParsedFieldName(KWappProxyType, characteristicIndex)  ==KErrNotFound) //Tag not found
				{
				index = LocateParsedFieldName(KWappUSSDCode, characteristicIndex); //Mandatory field
			
				// Create a new  element, NAME="PROXY_TYPE", VALUE="MSISDNNO"
				InsertDataPairL(KWappProxyType,KWappMsisdnNo, index+1);
				}

			if ( LocateParsedFieldName(KWappPort, characteristicIndex) == KErrNotFound) // Not Found - add the default value
				{
				index = LocateParsedFieldName(KWappProxyType,characteristicIndex);
				if (index ==KErrNotFound)
					User::Leave(KWappErrMandatoryTagMissing); // Error - should be here from step above!!!
				else	// Create new element,NAME="PORT", VALUE="9200"
					InsertDataPairL(KWappPort, KWappPort9200, index+1);
				}
			} // END of -  if (iCurrentCharacteristic == EWappGsmUssdCharacteristic)... 


// CHARACTERISTIC TYPE = ADDRESS, BEARER TYPE  = GPRS 
		if (iCurrentCharacteristic == EWappGprsCharacteristic)
			{
			// AHF - Removed check for tag GPRSACCESSPOINTNAME - no longer mandatory in OTA v7.0

			// Check that mandatory PROXY field is present - else it's a badly formed msg
			TInt index = LocateParsedFieldName(KWappProxy, characteristicIndex);
			if (index == KErrNotFound ) 
				User::Leave(KWappErrMandatoryTagMissing); 

			//Search for optional Port field - if not found, search for mandatory Proxy field and insert "9200"
			index = LocateParsedFieldName(KWappPort, characteristicIndex);
			if (index ==KErrNotFound)
				{
				index = LocateParsedFieldName(KWappProxy,characteristicIndex); // Mandatory - check already made
				InsertDataPairL(KWappPort, KWappPort9200, index+1); // NAME="PORT", VALUE = "9200"
				}

			// Check for the PPP_AUTHTYPE element - add default value if not found
			index = LocateParsedFieldName(KWappPPPAuthType, characteristicIndex);
			if (index ==KErrNotFound)	
				{
				index = LocateParsedFieldName(KWappCsdDial, characteristicIndex); // always present
				InsertDataPairL(KWappPPPAuthType, KWappPAP, index+1); // NAME="PPP_CALLTYPE", VALUE="PAP"
				}
			}



	}
// END of CMsvBIOWapAccessParser::ReadCharacteristicL()

//
//	ReadParmL()		-	Reads in contents of a PARM & inserts into iParsedFieldArray
//						as a CParsedField object. ASSUME that the PARM tag has
//						been read & verified  before this is called. Consequently
//					    now positioned at the start of the attributes 

void CMsvBIOWapAccessParser::ReadParmL()
	{

	CParsedField* parsedField = new(ELeave) CParsedField;
	CleanupStack::PushL(parsedField);
	TChar currentCharacter = GetNextMessageByteL();

	switch ((TUint) currentCharacter)
		{
		case KWAPP_NAME_ATTRIB:  //0x10 "NAME=..." ,string(inline or table ref.) should follow
			{
			//Start of NAME attribute, check for inline string/string table reference
			currentCharacter=GetNextMessageByteL();
			if ((TUint32) currentCharacter == KWAPP_STR_I)
				{
				parsedField->SetFieldNameL(*ReadInlineStringLC());
				CleanupStack::PopAndDestroy(); 
				}
			else if ((TUint32) currentCharacter== KWAPP_STR_T)
				{
				TUint32 offset = Read_mb_u_int32L();
				parsedField->SetFieldNameL(*ReadStringTableReferenceLC(offset));
				CleanupStack::PopAndDestroy(); 
				}
				else // it isn't an inline string or string table ref - ERROR!
					User::Leave(KWappErrNoTermination); 
			break;
			}
		case KWAPP_BEARER: //0x12 NAME="BEARER"
			{
			parsedField->SetFieldNameL(KWappBearer); 
			break;
			}
		case KWAPP_PROXY: //0x13   NAME="PROXY"  (Mandatory for GSM/CSD, GSM/SMS, IS136/CSD)
			{
			parsedField->SetFieldNameL(KWappProxy);	
			break;
			}
		case KWAPP_PORT	://0x14 NAME="PORT"
			{
			parsedField->SetFieldNameL(KWappPort);	
			break;
			}
		case KWAPP_NAME ://0x15 NAME = "NAME"
			{
			parsedField->SetFieldNameL(KWappName);	
			break;
			}
		case KWAPP_PROXYTYPE  ://0x16 NAME="PROXY_TYPE"
			{
			parsedField->SetFieldNameL(KWappProxyType);
			break;
			}
		case KWAPP_URL	:	// 0x17 NAME="URL"
			{
			parsedField->SetFieldNameL(KWappURL);	
			break;
			}
		case KWAPP_PROXY_AUTHNAME :			// 0x18  NAME="PROXY_AUTHNAME"
			{
			parsedField->SetFieldNameL(KWappProxyAuthName);
			break;
			}
		case KWAPP_PROXY_AUTHSECRET :		//0x19 NAME="PROXY_AUTHSECRET"
			{
			parsedField->SetFieldNameL(KWappProxyAuthSecret);
			break;
			}
		case KWAPP_PROXY_LOGIN_TYPE :
			{
			parsedField->SetFieldNameL(KWappProxyLoginType);
			break;
			}
		case KWAPP_SMS_SMSC_ADDR  :    //0x1A   NAME="SMS_SMSC_ADDR"  (Mandatory field for GSM/SMS)
			{
			parsedField->SetFieldNameL(KWappSMSCAddress); 
			break;
			}
		case KWAPP_USSD_SERV_CODE :	//0x1B NAME="USSD_SER_CODE" (Mandatory for GSM/USSD)
			{
			parsedField->SetFieldNameL(KWappUSSDCode);	
			break;
			}
		case KWAPP_ACCESS_POINT_NAME :	//0x1C	 NAME="ACCESSPOINTNAME" (Mandatory for GPRS)
			{
			parsedField->SetFieldNameL(KWappAccessPointName);
			break;
			}
		case KWAPP_CSD_DIALSTRING :		//0x21   NAME="CSD_DIALSTRING" (Mandatory for GSM/CSD,IS136/CSD)
			{
			parsedField->SetFieldNameL(KWappCsdDial);
			break;
			}
		case KWAPP_PPP_AUTHTYPE	  :		//0x22   NAME="CSD_AUTHTYPE"
			{
			parsedField->SetFieldNameL(KWappPPPAuthType);
			break;
			}
		case KWAPP_PPP_AUTHNAME	  :	  //0x23   NAME="CSD_AUTHNAME"
			{
			parsedField->SetFieldNameL(KWappPPPAuthName);
			break;
			}
		case KWAPP_PPP_AUTHSECRET :	  //0x24    NAME="CSD_AUTHSECRET"
			{
			parsedField->SetFieldNameL(KWappPPPAuthSecret);
			break;
			}
		case KWAPP_PPP_LOGIN_TYPE :
			{
			parsedField->SetFieldNameL(KWappPPPLoginType);
			break;
			}
		case KWAPP_CSD_CALLTYPE	  :	// 0x25    NAME="CSD_CALLTYPE"
			{
			parsedField->SetFieldNameL(KWappCsdCallType);
			break;
			}
		case KWAPP_CSD_CALLSPEED  :	//0x28    NAME="CSD_CALLSPEED"
			{
			parsedField->SetFieldNameL(KWappCsdCallSpeed);
			break;
			}
		case KWAPP_NAME_ISP	  :		//0x7E    NAME="ISP_NAME"
			{
			parsedField->SetFieldNameL(KWappISP);
			break;
			}

		default:
			User::Leave(KWappErrUnexpectedValue); // don't recognise the tag
		}

	// The early version of the WAP server, supporting version 4.0 of the Nokia OTA specs
	// codes up PROXY_AUTHNAME & PROXY_AUTHSECRET as the PROXY token followed by
	// a string/str ref. So we MUST check if inline string/str table ref follows
	if (currentCharacter==KWAPP_PROXY) 
		{
		if (iSms.Eos())
			User::Leave(KWappErrEOS); // ERROR - Unexpected end of message!! Nothing to peek at!
		else if ( ((TUint)iSms.Peek() == KWAPP_STR_I) || ((TUint)iSms.Peek() == KWAPP_STR_T)) 
			{
			// String follows immediately after Name token not a Value Tag
			TUint32 anOffset;
			currentCharacter = GetNextMessageByteL();
			HBufC* name = NULL;
			if ((TUint) currentCharacter == KWAPP_STR_I)
				{
				name = ReadInlineStringLC();
				}
			else 
				{
				if ((TUint) currentCharacter != KWAPP_STR_T)
					User::Leave(KWappErrUnexpectedValue); // Should not get here unless something is very wrong! 
				anOffset = Read_mb_u_int32L();
				name = ReadStringTableReferenceLC(anOffset);
				}

			//Defect fix for Def021848-Incorrect use of ReAllocL in wapp	
			HBufC* newName = name->ReAllocL(name->Length() + parsedField->FieldName().Length());
			CleanupStack::Pop(name);//Remove name from the Cleanup Stack as it would have been deleted by ReAllocL()
			CleanupStack::PushL(newName);
			newName->Des().Append(parsedField->FieldName()); //insert PROXY at front of string 
			parsedField->SetFieldNameL(*newName);			  //replace current string  with new one
			CleanupStack::PopAndDestroy(newName); 
			}
		}

	TBool addParsedField = ETrue;

	currentCharacter=GetNextMessageByteL(); //Get next byte - should be the Value tag
	switch( (TUint32) currentCharacter)
		{
		case KWAPP_VALUE_ATTRIB : // 0x11  "VALUE=", string(inline or table ref) follows
			{
			if (iSms.Eos())
				{
				User::Leave(KWappErrEOS); // ERROR - Unexpected end of message!! Nothing to peek at!
				}		
			//Check for 0x01 (KWAPP_END_TAG) - assign fieldvalue with empty value and ignore the other 
			if ( ((TUint)iSms.Peek() == KWAPP_END_TAG)) //Something wrong - Wrong PARAM Value 
				{
				addParsedField = EFalse;
  				break;
				}
			// Start of VALUE attribute, string should follow
			currentCharacter= GetNextMessageByteL();
			if ((TUint32) currentCharacter == KWAPP_STR_I)		//Inline string
				{
				HBufC* value = ReadInlineStringLC();
				parsedField->SetFieldValueL(*value);
				CleanupStack::PopAndDestroy();
				}
			else if ((TUint32) currentCharacter== KWAPP_STR_T)	//String Table ref
				{
				TUint32 offset = Read_mb_u_int32L();			// Read 32bit int
				HBufC* value = ReadStringTableReferenceLC(offset);	// Read in characters
				parsedField->SetFieldValueL(*value);
				CleanupStack::PopAndDestroy();
				}
				else //Not an inline string or string table ref - somethings wrong!
					User::Leave(KWappErrUnexpectedValue); 
			break;
			}
		case KWAPP_GSM_SMS_OLD	:	// 0x41 VALUE="GSM/SMS"
			{
			// Old value of GSM/SMS tag - ONLY valid for Version 4.0 of the specs, ie WBXML = 1.0!			
			parsedField->SetFieldValueL(KWappGsmSms);		
			break;
			}
		case KWAPP_GSM_CSD		:	// 0x45 VALUE="GSM/CSD"
			{
			parsedField->SetFieldValueL(KWappGsmCsd);			
			break;
			}		
		case KWAPP_GSM_SMS_NEW	:	//  0x46 VALUE="GSM/SMS" ONLY valid for Version 5.0 of the specs, i.e.WBXML = 1.1!
			{
			parsedField->SetFieldValueL(KWappGsmSms);		
			break;
			}
		case KWAPP_GSM_USSD		:	//0x47	VALUE="GSM/USSD" only defined for version 5.0 only 
			{
			parsedField->SetFieldValueL(KWappGsmUssd);
			break;
			}
		case KWAPP_IS136		:	//  0x48   VALUE="IS136/CSD" for version 5.0 only
			{
			parsedField->SetFieldValueL(KWappIS136Csd);	
			break;
			}
		case KWAPP_GPRS			:	// 0x49    VALUE="GSM/GPRS"
			{
			parsedField->SetFieldValueL(KWappGprs);
			break;
			}
		case KWAPP_PORT_9200	:	// 0x60 VALUE="9200"
			{
			parsedField->SetFieldValueL(KWappPort9200);	
			break;
			}
		case KWAPP_PORT_9201	:	// 0x61 VALUE="9201"
			{
			parsedField->SetFieldValueL(KWappPort9201);		
			break;
			}
		case KWAPP_PORT_9202	:	// 0x62  VALUE="9202"
			{
			parsedField->SetFieldValueL(KWappPort9202);		
			break;
			}
		case KWAPP_PORT_9203	:	// 0x63  VALUE="9203"
			{
			parsedField->SetFieldValueL(KWappPort9203);		
			break;
			}
		case KWAPP_AUTOMATIC	:	//	0x64 
			{
			parsedField->SetFieldValueL(KWappAuthAutomatic);
			break;
			}
		case KWAPP_MANUAL		:	// 0x65
			{
			parsedField->SetFieldValueL(KWappAuthManual);
			break;
			}
		case KWAPP_SPEED_AUTO	:	// 0x6A VALUE="AUTO"
			{
			parsedField->SetFieldValueL(KWappSpeedAuto);		
			break;
			}
		case KWAPP_SPEED_9600	:	// 0x6B VALUE="9600"
			{
			parsedField->SetFieldValueL(KWappSpeed9600);		
			break;
			}
		case KWAPP_SPEED_14400	:	// 0x6C VALUE="14400"
			{
			parsedField->SetFieldValueL(KWappSpeed14400);		
			break;
			}
		case KWAPP_SPEED_19200	:   //0x6D  VALUE="19200"
			{
			parsedField->SetFieldValueL(KWappSpeed19200);	
			break;
			}
		case KWAPP_SPEED_28800  :   //0x6E  VALUE="28800"
			{
			parsedField->SetFieldValueL(KWappSpeed28800);	
			break;
			}
		case KWAPP_SPEED_38400  :   //0X6F	VALUE="38400"
			{
			parsedField->SetFieldValueL(KWappSpeed38400);	
			break;
			}
		case KWAPP_PAP			:	// 0x70	VALUE="PAP"
			{
			parsedField->SetFieldValueL(KWappPAP);		
			break;
			}
		case KWAPP_CHAP			:	//0X71	VALUE="CHAP"
			{
			parsedField->SetFieldValueL(KWappCHAP);			
			break;
			}
		case KWAPP_ANALOGUE		:	//0X72	VALUE="ANALOGUE"
			{
			parsedField->SetFieldValueL(KWappAnalogue);		
			break;
			}
		case KWAPP_ISDN			:	//0X73	VALUE="ISDN"
			{
			parsedField->SetFieldValueL(KWappISDN);	
			break;
			}
		case KWAPP_SPEED_43200  :   //0X74	VALUE="43200"
			{
			parsedField->SetFieldValueL(KWappSpeed43200);	
			break;
			}
		case KWAPP_SPEED_56700  :	//0X75	VALUE="56700"
			{
			parsedField->SetFieldValueL(KWappSpeed56700);	
			break;
			}
		case KWAPP_MSISDN_NO    :  //0X76	VALUE="MSISDN_NO"
			{
			parsedField->SetFieldValueL(KWappMsisdnNo);	
			break;
			}
		case KWAPP_IPV4         :	//OX77	VALUE="IPV4"
			{
			parsedField->SetFieldValueL(KWappIpv4);	
			
			break;
			}
		case KWAPP_MSCHAP		:	//0x78  VALUE="MSCHAP"
			{
			parsedField->SetFieldValueL(KWappMSCHAP);
			break;
			}
			
		default:
			User::Leave(KWappErrUnexpectedValue); // Unknown tag - can't process it
		}

	// If iCurrentCharacteristic is a general address type and NAME="BEARER". Then
	//  set the current type flag to the correct type, so we know exactly  what we're dealing with
	if (iCurrentCharacteristic==EWappAddressCharacteristic 
					&& parsedField->FieldName().CompareF(KWappBearer)==0)
		{
		if (parsedField->FieldValue().CompareF(KWappGsmCsd)==0)
			iCurrentCharacteristic =EWappGsmCsdCharacteristic;
		else if (parsedField->FieldValue().CompareF(KWappGsmSms)==0)
			iCurrentCharacteristic = EWappGsmSmsCharacteristic;
		else if (parsedField->FieldValue().CompareF(KWappGsmUssd)==0)
			iCurrentCharacteristic = EWappGsmUssdCharacteristic;
		else if (parsedField->FieldValue().CompareF(KWappIS136Csd)==0)
			iCurrentCharacteristic = EWappIS136CsdCharacteristic;
		else if (parsedField->FieldValue().CompareF(KWappGprs)==0)
			iCurrentCharacteristic = EWappGprsCharacteristic;
		else 
			User::Leave(KWappErrUnrecognised);
		}
	
	// Got our Name and Value fields- check next byte - should be 0x01 =END
	currentCharacter = GetNextMessageByteL();

	if (currentCharacter != KWAPP_END_TAG) // Our PARM is not correctly terminated!
		User::Leave(KWappErrNoTermination);
	
	// Check flag to see if parsed field should be added or not
	if (addParsedField)
		{
		// Extracted the NAME and VALUE so create a container and append to our array
		iParsedFieldArray->AppendL(parsedField);		
		CleanupStack::Pop(parsedField);
		}
	else
		{
		CleanupStack::PopAndDestroy(parsedField);	
		}
	}
//End of CMsvBIOWapAccessParser::ReadParmL()


//	SettingsNamePresentL()  - Check if the NAME characteristic is defined.  if it isn't add 
//							 a default one that is unique.  Use a base stem of "WAP Settings" and
//							 append a suffix to it. The suffix is calculated by incrementing, until
//							 a unique digit is found. 
//
void CMsvBIOWapAccessParser::SettingsNamePresentL()
	{
	TBool nameDefined = EFalse;		// Is a Name characteristic present?
	TBool bearerPresent = EFalse;	// Is address characteristic present?

	// Search  for the start of a NAME characteristic - i.e. Field Name="NAME"
	TInt nFields = iParsedFieldArray->Count();

	TInt loopCount=0;
	while (loopCount < nFields && !nameDefined)
		{
		if (iParsedFieldArray->At(loopCount)->FieldName().CompareF(KWappCharName)==0)
			{
			// At start of a Name characteristic
			// Make sure that we won't try checking past the end of the array
			if (loopCount+1 < nFields) // NB loopCount started at zero
				{
				// Verify that this is followed by NAME parm - NAME token & a non NULL value
				if (iParsedFieldArray->At(loopCount+1)->FieldName().CompareF(KWappName)==0)
					{
					if (iParsedFieldArray->At(loopCount+1)->FieldValue().Length()!=0)
						nameDefined = ETrue;
					}
				}
			}
		loopCount++;
		}

	loopCount = 0;
	while (loopCount < nFields)
		{
		// Beginning of an Address Characteristic? 
		if (iParsedFieldArray->At(loopCount)->FieldName().CompareF(KWappCharAddress) ==0)
			bearerPresent = ETrue; // Assume  all Parms are present- will leave later if not!
		loopCount++;
		}

	if (nameDefined ==EFalse && bearerPresent)   // NAME characteristic not defined - add a default
		{
		TBuf<KCommsDbSvrMaxColumnNameLength> recordName;
		HBufC*	nameBuffer = HBufC::NewLC(30);
		TInt	currentRecord = 1;
		TBool	nameExists = EFalse; 

		TFileName fileName;
		Dll::FileName(fileName);
		TParse parse;
		parse.Set(KWappResourceFile, &fileName, NULL);
		fileName = parse.FullName();
		BaflUtils::NearestLanguageFile(iFs, fileName);

		RResourceFile resourceFile;
	    resourceFile.OpenL(iFs, fileName);
	    CleanupClosePushL(resourceFile);
	    HBufC8* buffer = resourceFile.AllocReadLC(DEFAULT_WAP_SETTINGS_NAME);
	    TResourceReader resourceReader;
	    resourceReader.SetBuffer(buffer);
	    TPtrC defaultSettingsName = resourceReader.ReadTPtrC();
		CCDWAPAccessPointRecord *wapRecord = static_cast<CCDWAPAccessPointRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdWAPAccessPointRecord));
		CleanupStack::PushL(wapRecord);
		nameBuffer->Des().Format(defaultSettingsName, currentRecord);  // create our name string
		while(!nameExists)
			{
			wapRecord->iRecordName.SetMaxLengthL(nameBuffer->Length());
			wapRecord->iRecordName = *nameBuffer;				
				
			if(wapRecord->FindL(*iDBSession)) 		
				{
				++currentRecord;					
				nameBuffer->Des().Format(defaultSettingsName, currentRecord); 
				}
			else 
				nameExists = ETrue;				
			}
		CleanupStack::PopAndDestroy(wapRecord);

		// Add characteristic header, then name and value to the parsed fields
		AppendNameFieldL(KWappCharName);
		AppendDataPairL(KWappName, nameBuffer->Des());
		CleanupStack::PopAndDestroy(3, nameBuffer); // nameBuffer, resourceFile, buffer
		}

	}//END of SettingsNamePresentL()

//	RestoreParsedDataL()			-  Restores CParsedField data into the array
//
//
void CMsvBIOWapAccessParser::RestoreParsedDataL()
	{
	//	Assume that our server message context is correctly set to the Bio Msg entry	
	iEntry.SetEntryL(iEntryId);
	
	// Has the entry been parsed,(iMtmData3 =1) or parsed & processed (iMtmData3 =2)
	// If not leave with error code
	if (   iEntry.Entry().MtmData3() != BIO_MSG_ENTRY_PARSED
		&& iEntry.Entry().MtmData3() != BIO_MSG_ENTRY_PROCESSED)
		{
		iSmsParsed=EFalse;			// Entry has not been parsed yet no data to restore
		User::Leave(KWappErrMsgUnparsed);
		}

	if(!iEntry.HasStoreL())
		{
		iSmsParsed=EFalse;			// Entry has no store -  not parsed yet?
		User::Leave(KWappErrStoreNotFound);  
		}
	//Message has been parsed and data stored = restore it!
	CMsvStore* store=iEntry.EditStoreL();
	CleanupStack::PushL(store);
	RestoreL(*store);
	CleanupStack::PopAndDestroy();//store

	//Now set a few key variables using the data in the iParsedFieldArray
	TLex myLex;
	if (iParsedFieldArray->At(0)->FieldName().CompareF(KWappXMLversion)==0)
		{
		myLex =iParsedFieldArray->At(0)->FieldName(); 
		myLex.Mark();
		myLex.Val(iWBXMLversionX10, EDecimal);
		}
	else
		User::Leave(KWappErrMandatoryTagMissing);  // error- XML version is missing
	
	// Field at index=1 is PublicID - don't currently need this 
	// Field at index=2 is Character Set - will present if XML version =1.1, but not for 1.0

	if (iWBXMLversionX10==11)
		{ // Have the Character Set
		if (iParsedFieldArray->At(2)->FieldName().CompareF(KWappCharacterSet)==0 )
			{
			myLex =iParsedFieldArray->At(1)->FieldName();
			myLex.Mark(); //Mark the start.  
			myLex.Val(iCharacterSet, EHex);
			}
		}
	else 
		iCharacterSet=0;
	}
// End of function  CMsvBIOWapAccessParser::RestoreParsedDataL()

// StoreParsedDataL()  - stores array of parsed data in a store - calls base class StoreL()
// 
void CMsvBIOWapAccessParser::StoreParsedDataL()
	{
	// Set to the current Entry id, create a store & save data
	iEntry.SetEntryL(iEntryId);
	CMsvStore* store=iEntry.EditStoreL();
	CleanupStack::PushL(store);
	StoreL(*store);
	CleanupStack::PopAndDestroy();//store

	// Set the parsed flag on the TMsvEntry
	iEntry.SetEntryL(iEntryId);
	TMsvEntry entry= iEntry.Entry();
	entry.SetMtmData3(BIO_MSG_ENTRY_PARSED);

	iEntry.ChangeL(entry);
	}

//
//		ResetProcessVariablesL()-Resets array of bookmarks and recreates the objects mapping to CommDb Table s
//
//
void CMsvBIOWapAccessParser::ResetProcessVariablesL()
	{
	// Re-set boolean flags
	iGsmCsdData		= EFalse;
	iGsmSmsData		= EFalse;
	iGprsData		= EFalse;
	iURLData		= EFalse;
	iMMSURLData		= EFalse;
	iNameData		= EFalse;
	iIdData			= EFalse;
	// Zero IDs
	iRecordId = 0; 
	iWapAccessPtID = 0;	
	iWapLocation = 0; 
	iWapChargeCard = 0;

	iBookmarkList->ResetAndDestroy();

	iWAPSettingsName.Set(TPtrC());  // Null the value in this descriptor

	delete iGsmCsdWapIpTable;
	iGsmCsdWapIpTable = NULL;
	delete iGprsWapIpTable;
	iGprsWapIpTable =NULL;
	delete iWapIpISPTable;
	iWapIpISPTable = NULL;
	delete iWapSmsTable;
	iWapSmsTable = NULL;
	delete iWapGprsTable;
	iWapGprsTable = NULL;
	delete iModemInitString;
	iModemInitString = NULL;
	}

// 
// Read_mb_u_int32() -- Helper function that uses the TLex iSms to extract a 32-bit 
//						integer encoded in a number of bytes. If Bit7 of the first
//						byte is set, the number continues over into the next byte,
//						and so on. If Bit7 is not set then it's the last byte.
//
TUint32  CMsvBIOWapAccessParser::Read_mb_u_int32L()
	{
	TUint32 decodedValue = 0;
	TBool	completed =EFalse;

	while(!completed)
		{
		TUint32 thisByte = (TUint) GetNextMessageByteL();  // cast the character returned by Get to a TUint32
		if (decodedValue & 0x2000000)   // is Bit25 set? If so, bitshifting 7 places 
			User::Leave(KWappErrOutsideBoundaries);	// left will cause overflow 		
		
		(decodedValue = decodedValue<<7); // assignment to keep compiler happy 
								//shift current value 7 places to the left, i.e. *256

		if ( (thisByte & KWAPP_MB_INT32_CONTINUATION) ) 
			{ 
			// bit 7 set, integer continues into next byte so keep processing
			thisByte = thisByte & 0x7F; //	mask Bit7 by AND'ing with all other bits 
									    // set to 1, i.e. 01111111 =0x7F
			decodedValue += thisByte;
			// leave completed set to EFalse
			}
		else    // bit 7 isn't set, processing's completed so set flag  
			{
			decodedValue += thisByte;
			completed = ETrue;
			}
		}
	return decodedValue;
	}  

//
//		GetStringTableItemL()	- Returns the string contained within the string table starting
//								  at the offset passed in as a parameter.
//				
HBufC* CMsvBIOWapAccessParser::ReadStringTableReferenceLC(TUint32 anOffset)
	{
	if (iStringTable ==NULL)
		User::Leave(KWappErrStringTable);		// Making a call to an nonexistant object! 
	TUint32 stringTableLength = iStringTable->Length();
	if (stringTableLength<=0)					//Nothing to process, or worse, an error!
		User::Leave(KWappErrOutsideBoundaries);	//Past end of table
	if (anOffset >= stringTableLength)			// anOffset must be < last element of buffer								
		User::Leave(KWappErrOutsideBoundaries);	// Last element must be NULL terminator!

	TUint32 stringTableItem = anOffset; // Current element in iStringTable
	TUint32 stringLength=0; // Length of string
	while ( iStringTable->Des()[stringTableItem] !=KWAPP_STR_TERM)
		{	
		// increment through the String Table to first NULL terminator 
		stringTableItem++;
		if (stringTableItem > (TUint)iStringTable->Length())  // Cast to remove warning, Length >=0
			User::Leave(KWappErrOutsideBoundaries);   // Problem -gone past the end of the descriptor 
		stringLength++;
		}	
	// return a descriptor starting at the offset and up to the char before the NULL terminator

	// Char Conversion
	TPtrC data = iStringTable->Des().Mid(stringTableItem, stringTableLength-1);
	HBufC* text = HBufC::NewLC(data.Length());
	TPtr des(text->Des());
	iCharsetConverter->ConvertL(data, des);
	return text;
	}


/*
Finds the end of the UCS2 string. Each character is represented by exactly 2bytes of data 
According to WBXML version 1.0 
"if a character encoding includes a NULL then that NULL character must be used as the termination character"
Hence we are assuming that the end of the string is marked by two NULL bytes.
*/
void CMsvBIOWapAccessParser::ReadUCS2StringL()
{
	TBool endofinlinestring = EFalse;
	TBool endoflexstring = EFalse; 
	TBool foundNull;

	while (!endoflexstring && !endofinlinestring)
	{
		foundNull = EFalse;
		endoflexstring = iSms.Eos();

		if (!endoflexstring)
			{
			if (iSms.Peek() == KWAPP_STR_TERM)
				{
				foundNull = ETrue;
				}
			
			iSms.Inc();
			if (iSms.Eos()) //check we haven't reached the end of the sms
				User::Leave(KWappErrEOS);

			else if (foundNull && iSms.Peek()== KWAPP_STR_TERM)
				endofinlinestring = ETrue;
			}
		else
			User::Leave(KWappErrEOS);
	}
	
}



/*
According to WBXML version 1.0 
"if a character encoding includes a NULL then that NULL character must
 be used as the termination character"

Finding the end of the ASCII string:
 This is simply done as each character is represented by a maximum 
 of 7 bits of data, hence each character is one byte only. 
 Thus, it is assumed that the end of the string is marked by a NULL which in ASCII is 0x00

  so the string "hi" would be represented as 
  0x68 0x69 0x00

Finding the end of the UTF-8 string. 
 From RFC 2279:
 "In UTF-8, characters are encoded using sequences of 1 to 6 octets.
   The only octet of a "sequence" of one has the higher-order bit set to
   0, the remaining 7 bits being used to encode the character value. In
   a sequence of n octets, n>1, the initial octet has the n higher-order
   bits set to 1, followed by a bit set to 0.  The remaining bit(s) of
   that octet contain bits from the value of the character to be
   encoded.  The following octet(s) all have the higher-order bit set to
   1 and the following bit set to 0, leaving 6 bits in each to contain
   bits from the character to be encoded.

   The table below summarizes the format of these different octet types.
   The letter x indicates bits available for encoding bits of the UCS-4
   character value.

   UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   0000 0000-0000 007F   0xxxxxxx
   0000 0080-0000 07FF   110xxxxx 10xxxxxx
   0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx

   0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
   0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
 "
 ASCII values 0-127 are represented in UTF8 by one byte with the msb set to 0.

 This means that no byte in a stream of bytes representing a (non NULL) character will ever be 0x00.
 So there will only be one 0x00 in the string and this will represent the end of the string.

 For example
  the string of roman numerals "VIIIIII" where VIII is the first character and III is the second character
  would be represented in UTF-8 as:

  0xE2 0x85 0xA2 0xE2 0x85 0xA7 0x00

 The single byte 0x00 is the NULL terminator representing the end of the string.
*/
void CMsvBIOWapAccessParser::ReadASCIIorUTF8StringL()
{
	while (!iSms.Eos() && iSms.Peek() !=KWAPP_STR_TERM /*0x00*/)
		{
		iSms.Inc();
		}

	if (iSms.Eos()) // End of the string! Other chars should follow
			User::Leave(KWappErrEOS); 

}

/*
because iSms is a TLex it is padded out and so 
when parsing unicode strings you end up with unnecessary characters
*/

//HBufC* CMsvBIOWapAccessParser::RemovePadding()
//{
//}


//
//		ReadInlineStringL()	- Returns the string begining at the current position in the 
//							  message. Increments TLex position until string termination found.
//
HBufC* CMsvBIOWapAccessParser::ReadInlineStringLC()
	{
	if (!iSms.Eos())//Mark the starting point of the string
		iSms.Mark(); 
	else			// End of the string! Can't proceed!
		User::Leave(KWappErrEOS);

		//find the end of the string by taking into accout how it is encoded
	switch (iCharacterSet)
		{
		case KCharsetASCII:
		case KCharsetUTF8:
			ReadASCIIorUTF8StringL();
			break;
		case KCharsetUCS2:
			ReadUCS2StringL();
			break;
		default:
			User::Leave(KErrNotSupported);
			break;
		};
	
	//the end of the string has been found so mark it. 
	TPtrC data =iSms.MarkedToken();
	iSms.Inc(); //Increment up to the KWAPP_STR_TERM so next time we read the char after the end of the string
	/*
	Marked token is now converted to unicode 
	for the purpose of applying to commdb for example. 
	*/
	
	// Char Conversion
	//for unicode parsing to remove unnecessary padding	
	if (iCharacterSet == KCharsetUCS2)
		{
		HBufC* text = HBufC::NewMaxLC(data.Length() / 2);
		TPtr destext(text->Des()); 

		TInt	j = 0;
		TInt	i = 1;

		while (j < data.Length() / 2)
			{
			destext[j] = data[i];
			i += 2;
			j++;
			}

		return text;
		}
	else
		{
		HBufC* text = HBufC::NewMaxLC(data.Length());
		TPtr destext(text->Des()); 

		iCharsetConverter->ConvertL(data, destext);

		return text;
		}
	}


//
//		AppendDataPairL()	- Appends a CParsedField containing data from the message, to the 
//							  array of parsed fields (iParsedFieldsArray).
//
void CMsvBIOWapAccessParser::AppendDataPairL(const TDesC& aFieldName, const TDesC& aFieldValue)
	{
	// Appends a CParsedField object to iParsedFieldArray.
	// Both fields have valid data
	CParsedField* localData = new (ELeave) CParsedField;
	CleanupStack::PushL(localData);
	localData->SetFieldNameL(aFieldName);
	localData->SetFieldValueL(aFieldValue);
	CleanupStack::Pop();
	iParsedFieldArray->AppendL(localData);
	}

//
//		AppendNameFieldL()	- Appends a CParsedField containing just a Name from the message, 
//							  to the array of parsed fields (iParsedFieldsArray).
//
void CMsvBIOWapAccessParser::AppendNameFieldL(const TDesC& aFieldName)
	{
	// Appends a CParsedField object to iParsedFieldArray.
	// Only the Name field has valid data, the Value field is left NULL
	CParsedField* localData = new (ELeave) CParsedField;
	CleanupStack::PushL(localData);
	localData->SetFieldNameL(aFieldName);
	localData->SetFieldValueL(KNullDesC);  // Set to an empty descriptor
	CleanupStack::Pop();
	iParsedFieldArray->AppendL(localData);
	}

void CMsvBIOWapAccessParser::InsertDataPairL(const TDesC& aFieldName, const TDesC& aFieldValue, TInt anIndex)
	{	
	// check that the position is valid!  Leave if out of bounds
	// Limits 0 - insert at front of array, iParsedData->Count() append to end
	if (!(anIndex<= iParsedFieldArray->Count() && anIndex >= 0) )
		User::Leave(KErrArgument);
	CParsedField* localField = new (ELeave)CParsedField;
	CleanupStack::PushL(localField);
	localField->SetFieldNameL(aFieldName);
	localField->SetFieldValueL(aFieldValue);
	CleanupStack::Pop();
	iParsedFieldArray->InsertL(anIndex, localField);
	}

TChar CMsvBIOWapAccessParser::GetNextMessageByteL()
	{	
	if (iSms.Eos())  // Error - unexpectedly reached the end of the TLex buffer!!!!!
		User::Leave(KWappErrEOS);
	return iSms.Get();
	}

TInt CMsvBIOWapAccessParser::LocateParsedFieldName(const TDesC& aFieldName, const TInt aStartIndex)
	{
	//Searches from a start pos'n, default=0, until either finds a match, or end of array
	TInt  count=aStartIndex;
	TBool nextCharacteristic =EFalse;
	
	//loop until end of the array, found the first match or found another Characteristic!
	TInt nFields = iParsedFieldArray->Count();
	while	(count < nFields &&			//	End of array?
			(iParsedFieldArray->At(count)->FieldName().CompareF(aFieldName)  !=0) && //Match found?
			!nextCharacteristic  )
		{

		if ( (count !=aStartIndex)  && (IsCharacteristicName(count)) )
			// Not 1st first element of characteristic and found field for another
			// characteristic- Must have reached next characteristic - stop looping
			{
			nextCharacteristic =ETrue;
			}

		++count;
		}

	if (count < nFields && !nextCharacteristic)    // found a match in the array, even if it is last element
		return count;
	else 
		return KErrNotFound;  // Didn't find a match or reached next characteristic - flag the errror
	}

//
//	DoProcessL()  - Workhorse for ProcessL function.  Extracts information from parsed field 
//					array into separate objects. Writes settings to the COMMS DB, if 
//					there is data for at least one bearer type. Saves any Bookmarks to file.
//
void CMsvBIOWapAccessParser::DoProcessL()
	{
	if (iGsmCsdData || iGsmSmsData || iGprsData) 
		{
		WriteDataToDBL();
		}
	WriteBookmarksToFileL();

	if( iMMSURLData )
		{
		WriteMMSURLL();
		}		

	if (!iGprsData && !iGsmCsdData && !iGsmSmsData && !iMMSURLData && (iBookmarkList->Count()==0)) 
		{
		// No bearers, no bookmarks - must be a settings message - wouldn't be here otherwise 
		if (iNameData && iURLData)   // iIDData optional
			{
			UpdateStartPageUrlL();   // update the URL of the start page in WAP table		
			}
		}
		
	}

//
//	PreProcessL -	goes through the fields in the array of parsed data, extracting information
//					only extracts information for first of each of the 4 bearer types - i.e. max  
//					of 4 entries in the ISP/WAP tables. Additional address characteristics are 
//					ignored. 
//
void CMsvBIOWapAccessParser::PreProcessL()
	{
	TInt arrayPtr=0;   // current position in the array of ParsedFields

	while (arrayPtr < iParsedFieldArray->Count())
		{
		// Check current field if characteristic - peek at next field -> bearer type
					// GSM/CSD		- extract data from GSM/CSD Address characteristic
					// GSM/SMS		- extract data from GSM/SMS Address characteristic
					// GPRS			- extract data from GPRS Address characteristic
					// GSM/USSD		- TO DO,  GSM/USSD Address characteristic unsupported
					// IS136/CSD	- TO DO,  IS136/CSD Address characteristic unsupported 
					// ID			- extract data from ID characteristic
					// NAME			- extract data from NAME characteristic
					// URL			- extract data from URL characteristic
					// BOOKMARK		- extract Bookmark characteristic & append to Bookmark array
		// Otherwise report an error

		// Increment past WBXML Version, public ID or character set to the data we want
		if ((iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappXMLversion) ==0) ||
			(iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappPublicID) ==0)||
			(iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappCharacterSet) ==0))
		
			arrayPtr++;	
		else if	(iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappCharAddress) ==0)
			{
			// Stepped past first 3 fields & its an Address Characteristic
			// So read the next line to determine type of bearer 

			TPtrC addressValue;
			arrayPtr++;			//increment to the next element 
			
			if (iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappBearer)==0) 
				addressValue.Set(iParsedFieldArray->At(arrayPtr)->FieldValue());   // Note the bearer type
			else
				User::Leave(KWappErrMandatoryTagMissing); // Not a BEARER - error!

			// Next - either extract the bearer data into the table objects, if this is the 
			// first of this type, or skip past the data to the next characteristic. 
			if ((addressValue.CompareF(KWappGsmCsd)==0)) 
				{
				// GSM/CSD Characteristic so add data to ISP and WAP table objects, or go to next characteristic
				ExtractBearerDataL(arrayPtr); 
				}
			
			else if ((addressValue.CompareF(KWappGsmSms)==0)) 
				{
				// GSM/CSD Characteristic so either add data to ISP and WAP table objects, or skip past to next characteristic
				ExtractBearerDataL(arrayPtr);
				}

			else if (addressValue.CompareF(KWappGsmUssd)==0)
				{
				User::Leave(KWappErrNotSupported);  // Don't support these at the moment!

		//		ExtractBearerDataL(arrayPtr); //Add data to ISP and WAP table objects
				}

			else if (addressValue.CompareF(KWappIS136Csd)==0)
				{
				User::Leave(KWappErrNotSupported);  // Don't do these at the moment!
		//		ExtractBearerDataL(arrayPtr); //Add data to ISP and WAP table objects 
				}
			else if (addressValue.CompareF(KWappGprs)==0)
				{
				ExtractBearerDataL(arrayPtr);
				}
			else 
				User::Leave(KWappErrUnrecognised); // Value doesn't match any of the known ones
			}

		// Check if it's a  URL characteristic
		else if (iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappCharURL) ==0)
			{ 
			// The URL Characteristic has NO PARM elements only a value

			if (iURLData == EFalse)  // Not been set previously
				{
				// Use the first instance of a URL - set it to the characteristic value even if it's null 
				iUrl.Set(iParsedFieldArray->At(arrayPtr)->FieldValue()); 
				iURLData = ETrue;
				}
			arrayPtr++;
			}

		// Check if it's a Name Characteristic
		else if (iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappCharName) ==0)
			{ 
			// The NAME Characteristic should have EXACTLY 1 PARM element
			arrayPtr++; // increment to the Parm in this characteristic
			if (arrayPtr == iParsedFieldArray->Count() || 
				iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappName)!=0) 
				User::Leave(KWappErrBadMessage);
			
			// Initialise the Settings Name variable if it hasn't been set
			if (iWAPSettingsName.Length()==0)    
				{
				// Use the first instance of NAME - set it to the value even if it's null 
				iWAPSettingsName.Set(iParsedFieldArray->At(arrayPtr)->FieldValue());
				iNameData = ETrue;
				}
			
			while ( arrayPtr< iParsedFieldArray->Count() && !(IsCharacteristicName(arrayPtr)) )
					arrayPtr++;   // increment to beginning of next characteristic
			
			}

		//Is it a BOOKMARK ?  Bookmarks must contain EXACTLY 2 PARM elements - NAME then URL 
		else if (iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappCharBookmark)==0)
			{  
			arrayPtr++;							
			ExtractBookmarkDataL(arrayPtr);
			}

		// Is it an ID characteristic ?
		else  if (iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappCharID) ==0)
			{  
			arrayPtr++;		//Increment to the NAME Parm

			// End of array or PARM Type != NAME
			if (arrayPtr == iParsedFieldArray->Count() || 
				iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappName)!=0)
				User::Leave(KWappErrBadMessage);

			if (iIdData == EFalse)
				{
				// Use the 1st instance of an ID - set to value even if it's null!
				iID.Set(iParsedFieldArray->At(arrayPtr)->FieldValue());
				iIdData = ETrue;
				}

			while ( arrayPtr< iParsedFieldArray->Count() && !(IsCharacteristicName(arrayPtr)) )
					arrayPtr++;   // increment to beginning of next characteristic
 			}
		else if(iParsedFieldArray->At(arrayPtr)->FieldName().CompareF(KWappCharMMSURL) ==0)
			{
			// The MMSURL Characteristic has NO PARM elements only a value

			if (iMMSURLData == EFalse)  // Not been set previously
				{
				// Use the first instance of a URL - set it to the characteristic value even if it's null 
				iMMSUrl.Set(iParsedFieldArray->At(arrayPtr)->FieldValue()); 
				iMMSURLData = ETrue;
				}

			arrayPtr++; // Increment to the next element in the array
			}

		else // Unrecognised characteristic token
			User::Leave(KWappErrUnrecognised);
		}
	}
// END of function  CMsvBIOWapAccessParser::PreProcessL()

//
//	ExtractBearerDataL()	-  
//
//			Called by PreProcessL when it finds an address bearer type.  Uses the reference to 
//			the current position in iParsedFieldArray to extract info to insert into CWapTableData 
//			and CIspTableData objects. Increment the index position as the function scans
//			through the iParsedFieldArray - ensures the value in calling function is correct. 
//
void CMsvBIOWapAccessParser::ExtractBearerDataL(TInt& aCurrentPos)
	{
	
	TWappBearerType currentBearer = EWappUnknownBearer;

	// local flags - 
	// For all address characteristics, only process 1st instance of each parm type - ignore the rest
	TBool bearer			= EFalse;
	TBool proxy				= EFalse;
	TBool port				= EFalse;
	TBool csdDialstring		= EFalse;
	TBool pppAuthType		= EFalse;
	TBool pppAuthName		= EFalse;
	TBool pppAuthSecret		= EFalse;
	TBool pppLoginType		= EFalse;
	TBool csdCallType		= EFalse;
	TBool csdCallSpeed		= EFalse;
	TBool pxAuthName		= EFalse;
	TBool pxAuthSecret		= EFalse;
	TBool pxLoginType		= EFalse;
	TBool ispName			= EFalse;
	TBool smsSMSCAddr		= EFalse;
//	TBool ussdServiceCode	= EFalse;  //Currently not used - will be needed if GSM/USSD supported

	TInt arrayEnd  = iParsedFieldArray->Count();
	TCsdCallType  callType =EAnalogue;
	TCsdCallSpeed callSpeed =EAutobauding;

	// First check - current parm  MUST  BE A BEARER
	// Following Parms can be in any order, but the first must be a BEARER.

	if (iParsedFieldArray->At(aCurrentPos)->FieldName().CompareF(KWappBearer) !=0)
		User::Leave(KWappErrMandatoryTagMissing);   // First Parm is not a BEARER - big problem!!


	while ( aCurrentPos< arrayEnd &&  // Stop checking if past the array end, or next value
			!(IsCharacteristicName(aCurrentPos))  )     // is another Characteristic, ie.  address, URL, Bookmark, ID or Name
		{ 
		TPtrC fieldName = iParsedFieldArray->At(aCurrentPos)->FieldName();
		if (IsValidTokenNameL(aCurrentPos) !=KErrNone) //Validate this Parm Name
			User::Leave(KWappErrUnrecognised);		   
		
		// Check the next parsed field data -  BEARER type

		if (fieldName.CompareF(KWappBearer) ==0)
			{
			//Set the current local bearer type, & then bearer variable
			TPtrC currentValue = iParsedFieldArray->At(aCurrentPos)->FieldValue();
			if (currentValue.CompareF(KWappGsmCsd) ==0)
				{
				if (!bearer)   // first time here!
					{
					if (!iGsmCsdData) // No previous GSM bearers
						{
						iGsmCsdWapIpTable		= CWapIpBearerData::NewL();   // Create the required table mapping objects
						iWapIpISPTable	= CIspTableData::NewL();
						currentBearer = EWappGsmCsdBearer;// set local bearer type variable
						bearer = ETrue;  // ignore further BEARER's only for this characteristic
						}
					else // Already got data increment to next characteristic and return
						{
						while ( aCurrentPos< arrayEnd && !(IsCharacteristicName(aCurrentPos)) )
							aCurrentPos++;   // increment to beginning of next characteristic
						return;				 // return to PrePocessL
						}
					}
				}

			else if (currentValue.CompareF(KWappGsmSms) ==0)
				{
				if (!bearer)  // haven't set the bearer type yet,  ignore all after first
					{
					if (!iGsmSmsData)  // No previous SMS bearers
						{
						iWapSmsTable =  CWapSmsBearerData::NewL();
						currentBearer =EWappGsmSmsBearer;
						bearer = ETrue;			// ignore any further BEARERs in this Characteristic 
						}
					else   // Already got bearer data  goto next characteristic & return
						{
						while ( aCurrentPos< arrayEnd && !(IsCharacteristicName(aCurrentPos)) )
							aCurrentPos++;  // increment to beginning of next characteristic
						return;				// return to PrePocessL
						}
					}
				}
			
			else if (currentValue.CompareF(KWappGsmUssd) ==0)
				{
				currentBearer =EWappGsmUssdBearer;
				//NB   Add support for USSD bearer here when required
				// NOTE - must consider proxy & proxy type with USSD!
				User::Leave(KWappErrNotSupported);
				}
			
			else if (currentValue.CompareF(KWappIS136Csd) ==0)
				{
				currentBearer =EWappIS136CsdBearer;
				//NB  Add support for IS 136 when required
				// NOTE - will it be the same as for GSM/CSD ?
				User::Leave(KWappErrNotSupported);
				}
			else if (currentValue.CompareF(KWappGprs) ==0)
				{
				if (!bearer)   // first time here!
					{
					if (!iGprsData) // No previous bearers
						{
						iGprsWapIpTable		= CWapIpBearerData::NewL();   // Create the required table mapping objects
						iWapGprsTable =  CWapGprsBearerData::NewL();
						iWapIpISPTable = CIspTableData::NewL();
						currentBearer = EWappGprsBearer;// set local bearer type variable
						bearer = ETrue;  // ignore further BEARER's only for this characteristic
						}
					else // Already got bearer data, increment to next characteristic and return
						{
						while ( aCurrentPos< arrayEnd && !(IsCharacteristicName(aCurrentPos)) )
							aCurrentPos++;   // increment to beginning of next characteristic
						return;				 // return to PrePocessL
						}
					}
				}
			else 
				User::Leave(KWappErrUnrecognised);   // Unknown bearer type - Help!!!!
			}

		//Check for the PROXY characteristics - String used to set Table Data
	
		// CSD proxy value into		iIspTable::iGateway	    -  goes in   ISP_IP_GATEWAY 
		//							iWapTable::iGatewayAddr	-  goes into WAP_GATEWAY_ADDRESS
		// SMS proxy value into		iWapTable::iGatewayAddr	-  goes into WAP_GATEWAY_ADDRESS
			
		// NB If support for USSD, or IS136 required, add additional code here.
		else if (fieldName.CompareF(KWappProxy) ==0)
			{
			if(!proxy) // First PROXY for this characteristic
				{
				switch(currentBearer)
					{
					case EWappGsmSmsBearer:
						iWapSmsTable->iGatewayAddr.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						break;
					case EWappGsmCsdBearer:
						iGsmCsdWapIpTable->iGatewayAddr->SetAddrL(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						iWapIpISPTable->iGateway->SetAddrL(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						break;
					case EWappGprsBearer:
						iGprsWapIpTable->iGatewayAddr->SetAddrL(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						iWapGprsTable->iGatewayAddr->SetAddrL(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						break;
					default: 	
						User::Leave(KWappErrUnrecognised); // Unrecognised currentBearer
					}
				proxy = ETrue;
				}
			}


		//Check for the PORT characteristics - first encounter set it, ignore it afterwards
		else if ((fieldName.CompareF(KWappPort)==0) &&  !port)   
			{   
			// Record that we've checked a port value - should be one of 4 values!
			
			if (  (iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappPort9200) ==0)
				||(iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappPort9201) ==0) 
				||(iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappPort9202) ==0)
				||(iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappPort9203) ==0))
			
				{
				if (currentBearer == EWappGsmSmsBearer)
					iWapSmsTable->iPort.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
				else if (currentBearer == EWappGsmCsdBearer)
					iGsmCsdWapIpTable->iPort.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
				else if (currentBearer == EWappGprsBearer)
					iGprsWapIpTable->iPort.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
				}
			else
				{
				if (currentBearer == EWappGsmSmsBearer)
					iWapSmsTable->iPort.Set(KWappPort9200);
				else if (currentBearer == EWappGsmCsdBearer)
					iGsmCsdWapIpTable->iPort.Set(KWappPort9200);
				else if (currentBearer == EWappGprsBearer)
					iGprsWapIpTable->iPort.Set(KWappPort9200);
				}
			port = ETrue;
			}


// ******* Following group are for GSM/CSD & IS136/CSD - GSM/SMS and GSM/USSD follow after ********

		//	Is it a CSD_DIALSTRING? 
		else if (fieldName.CompareF(KWappCsdDial)==0)
			{
			// Must be either GSM/CSD or IS136/CSD
			if ( (currentBearer != EWappGsmCsdBearer) &&
				  (currentBearer != EWappIS136CsdBearer) )
				  User::Leave(KWappErrUnexpectedValue);
			else if (!csdDialstring)
				{
				iWapIpISPTable->iDefaultPhoneNum.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
				csdDialstring=ETrue;
				}
			}

		//	Check for PPP_AUTHTYPE 
		//  Now don't set the iIFName - always "ppp" & this protocol takes care of rest
		else if (fieldName.CompareF(KWappPPPAuthType)==0 && !pppAuthType)
			{
			if(currentBearer==EWappGprsBearer)
				{
				if(iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappPAP)==0)
					iWapGprsTable->iPlainTextAuthDisabled = EFalse;
				else 
					iWapGprsTable->iPlainTextAuthDisabled = ETrue;
				}
			// set the flag so we don't check again
			pppAuthType =ETrue;
			}

		//	Check if its a PPP_AUTHNAME
		else if (fieldName.CompareF(KWappPPPAuthName)==0)
			{
			if (!pppAuthName)
				{
				switch(currentBearer)
					{
					case EWappGsmCsdBearer:
					case EWappIS136CsdBearer:
						iWapIpISPTable->iLoginName.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						break;
					case EWappGprsBearer:
						iWapGprsTable->iLoginName.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						break;
					default:
						// SMS, USSD and GPRS don't have CSD authentication names
						User::Leave(KWappErrUnexpectedValue); 
					}
				pppAuthName = ETrue;
				}
			}

		//	Is it PPP_AUTHSECRET?
		else if (fieldName.CompareF(KWappPPPAuthSecret)==0 )
			{

			if (!pppAuthSecret)
				{
				switch(currentBearer)
					{
					case EWappGsmCsdBearer:
					case EWappIS136CsdBearer:
						iWapIpISPTable->iLoginPass.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						break;
					case EWappGprsBearer:
						iWapGprsTable->iLoginPass.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						break;
					default:
						// SMS, GPRS & USSD don't have authentication type
						User::Leave(KWappErrUnexpectedValue);
					}
				pppAuthSecret = ETrue;
				}
			}
		//	Is it a PPP_LOGIN_TYPE? 
		else if (fieldName.CompareF(KWappPPPLoginType)==0)
			{
			if(!pppLoginType)
				{
				const TDesC& val = iParsedFieldArray->At(aCurrentPos)->FieldValue();
				switch(currentBearer)
					{
					case EWappGsmCsdBearer:
					case EWappIS136CsdBearer:
						{
						if(val.CompareF(KWappAuthAutomatic)==0)
							{
							iWapIpISPTable->iIFPromptForAuthentication = EFalse;
							iWapIpISPTable->iPromptForLoginDetails = EFalse;
							}
						else
							{
							iWapIpISPTable->iIFPromptForAuthentication = ETrue;
							iWapIpISPTable->iPromptForLoginDetails = ETrue;
							}
						}
						break;
					case EWappGprsBearer:
						{
						if(val.CompareF(KWappAuthAutomatic)==0)
							iWapGprsTable->iIFPromptForAuth = EFalse;
						else
							iWapGprsTable->iIFPromptForAuth = ETrue;
						}
						break;
					default:
						User::Leave(KWappErrUnexpectedValue);
					}
				}
			pppLoginType = ETrue;
			}

		//	Is it a CSD_CALLTYPE? 
		else if (fieldName.CompareF(KWappCsdCallType)==0)
			{
			// ONLY  GSM/CSD bearer has call types
			if ( (currentBearer !=  EWappGsmCsdBearer) )
				  User::Leave(KWappErrUnexpectedValue);

			else if (!csdCallType)
				{
				// Can have values ANALOGUE (don't set  nothing) & ISDN (set modem init string)
				if (iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappISDN)==0)
					{
					// TODO implement this function when Symbian know device specs
					SetModemInitStringL(); 
					callType = EIsdn;
					}
				else if ((iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappAnalogue)==0))
					{
					callType = EAnalogue;
					}
				else
					callType = EAnalogue;  // Not recognised so set to default of ANALOGUE
				csdCallType =ETrue;
				}
			}

		//Check if its a CSD_CALLSPEED
		else if (fieldName.CompareF(KWappCsdCallSpeed)==0)
			{
			// ONLY CSD bearer has call speed - anything else is an error
			if  (currentBearer !=  EWappGsmCsdBearer)
				  User::Leave(KWappErrUnexpectedValue);
			else if (!csdCallSpeed)
				{
				TPtrC value = iParsedFieldArray->At(aCurrentPos)->FieldValue();
				// Set the local variable for callspeed - will set the iIspTable value at end of fn
				if (value.CompareF(KWappSpeedAuto)==0)
					callSpeed = EAutobauding ; // Auto speed select - device chooses
				else if (value.CompareF(KWappSpeed9600)==0)
					callSpeed = E9600baud;
				else if (value.CompareF(KWappSpeed14400)==0)
					callSpeed = E14400baud;
				else if (value.CompareF(KWappSpeed19200)==0)
					callSpeed = E19200baud;
				else if (value.CompareF(KWappSpeed28800)==0)
					callSpeed = E28800baud;
				else if (value.CompareF(KWappSpeed38400)==0)
					callSpeed = E38400baud;
				else if (value.CompareF(KWappSpeed43200)==0)
					callSpeed = E43200baud;
				else if (value.CompareF(KWappSpeed56700)==0)
					callSpeed = E57600baud;
				else 
					callSpeed = EAutobauding;// Set to the default of AUTO 

				csdCallSpeed =ETrue;
				}
			}

		//	Check if its a PROXY_AUTHNAME - must be CSD or GPRS
		else if (fieldName.CompareF(KWappProxyAuthName)==0 )
			{
			switch(currentBearer)
				{
				case EWappGsmCsdBearer:
				case EWappIS136CsdBearer:
					if (!pxAuthName)
						{
						iGsmCsdWapIpTable->iProxyAuthName.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						pxAuthName =ETrue;
						}
					break;
				case EWappGprsBearer:
					if (!pxAuthName)
						{
						iGprsWapIpTable->iProxyAuthName.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						pxAuthName =ETrue;
						}
					break;
				default:
					User::Leave(KWappErrUnexpectedValue);
				}
			}

		//	Is it a PROXY_AUTHSECRET?  
		else if (fieldName.CompareF(KWappProxyAuthSecret)==0)
			{
			switch(currentBearer)
				{
				case EWappGsmCsdBearer:
				case EWappIS136CsdBearer:
					if (!pxAuthSecret)
						{
						iGsmCsdWapIpTable->iProxyAuthSecret.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						pxAuthSecret =ETrue;
						}
					break;
				case EWappGprsBearer:
					if (!pxAuthSecret)
						{
						iGprsWapIpTable->iProxyAuthSecret.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
						pxAuthSecret =ETrue;
						}
					break;
				default:
					User::Leave(KWappErrUnexpectedValue);
				}
			}

		// Is it a PROXY_LOGIN_TYPE?
		
		else if (fieldName.CompareF(KWappProxyLoginType)==0)
			{
			//We just set the variable in the mapping object for the WAP IP Bearer Table. Don't do anything with it yet.
			switch(currentBearer)
				{
				case EWappGsmCsdBearer:
				case EWappIS136CsdBearer:
					if (!pxAuthSecret)
						{
						if (iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappAuthAutomatic))
							iGsmCsdWapIpTable->iProxyUseAutoLogin = ETrue;
						else
							iGsmCsdWapIpTable->iProxyUseAutoLogin = EFalse;
						}
					break;
				case EWappGprsBearer:
					if (!pxAuthSecret)
						{
						if (iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappAuthAutomatic))
							iGprsWapIpTable->iProxyUseAutoLogin = ETrue;
						else
							iGprsWapIpTable->iProxyUseAutoLogin = EFalse;
						}
					break;
				default:
					User::Leave(KWappErrUnexpectedValue);
				}


			pxLoginType = ETrue;
			}


		//  Is it a ISP _NAME element?
		else if (fieldName.CompareF(KWappISP)==0)
			{
			// Must be a CSD or Grps bearer
			if ( (currentBearer !=  EWappGsmCsdBearer) &&
				  (currentBearer  != EWappIS136CsdBearer) &&
				  (currentBearer  != EWappGprsBearer)   )
				  User::Leave(KWappErrUnexpectedValue);
			else if (!ispName)
				{
				iWapIpISPTable->iISPDescription.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
				ispName =ETrue;
				}			
			} 


// ******************  Following are for GSM/SMS settings  *********************
		else if (fieldName.CompareF(KWappSMSCAddress)==0)
			{
			if (currentBearer  !=  EWappGsmSmsBearer) 
				User::Leave(KWappErrUnexpectedValue);// Only SMS has a SMSC address - error condition
			else if (!smsSMSCAddr)
				{
				iWapSmsTable->iWapServiceAddr.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
				smsSMSCAddr = ETrue;
				}
			}

		//Check for PROXY_TYPE characteristic

		// TO DO When/If USSD support is required! Add it here
		// Need to know how to set Addressing Scheme for USSD & CSD/SMS/etc!!!!!
		// Currently only alter value of dummy variable to keep the compiler happy
		else if (fieldName.CompareF(KWappProxyType) ==0)
			{
			// Must be a USSD or GPRS bearer type - otherwise error!
			if (currentBearer == EWappGsmUssdBearer) 
				{
				// NB If USSD support req'd,set the Addressing type here. NB Not yet defined in CommDb!
				}
			else if(currentBearer == EWappGprsBearer)
				{
				if(iParsedFieldArray->At(aCurrentPos)->FieldValue().CompareF(KWappIpv4)!=0)
					User::Leave(KWappErrUnrecognised);
				}
			else
				User::Leave(KWappErrUnrecognised);
			}

		//  Check for USSD service code
		else if (fieldName.CompareF(KWappUSSDCode)==0)
			{
			if (currentBearer  == EWappGsmUssdBearer)
				{  
				// NB - If USSD support req'd, set the Service Centre Address here!
				}
			else 
				User::Leave(KWappErrUnrecognised); // Not a USSD address, so shouldn't be here - error
			}

		// Access point is GPRS only
		else if (fieldName.CompareF(KWappAccessPointName)==0)
			{
			if (currentBearer  == EWappGprsBearer)
				{
				iWapGprsTable->iAccessPointName.Set(iParsedFieldArray->At(aCurrentPos)->FieldValue());
				}
			else
				User::Leave(KWappErrUnrecognised); // Shouldn't have a GPRS address if we aren't GPRS!
			}

		aCurrentPos++;
		}// END of the While loop

	if (currentBearer == EWappGsmCsdBearer)
		{
		if (!iGsmCsdData)
			{
			if (!pppLoginType) 
				{
				// Login type not set so determine value for whether login and authorisation set
				if (iWapIpISPTable->iLoginName.Length()!=0 && iWapIpISPTable->iLoginPass.Length()!=0)
					{
					iWapIpISPTable->iPromptForLoginDetails =EFalse;
					iWapIpISPTable->iIFPromptForAuthentication =EFalse;
					}
				}
			if (! pxLoginType)
				if (iGsmCsdWapIpTable->iProxyAuthName.Length()!=0 && iGsmCsdWapIpTable->iProxyAuthSecret.Length()!=0)
					{
					iGsmCsdWapIpTable->iProxyUseAutoLogin = ETrue;
					}
	
			// Set the iIspTable->iCsdCallSpeed member -  need the calltype and the callspeed values
			if (callType == EAnalogue)
				{
				switch (callSpeed)
					{
					case EAutobauding:
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeedAutobauding;
						iWapIpISPTable->iCallDataProtocol = RMobileCall::EProtocolV34;
						break;
					case E9600baud:
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeed9600;
						iWapIpISPTable->iCallDataProtocol = RMobileCall::EProtocolV32;
						break;
					case E14400baud:
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeed14400;
						iWapIpISPTable->iCallDataProtocol = RMobileCall::EProtocolV34;
						break;
					case E19200baud:
						iWapIpISPTable->iCallSpeed =RMobileCall::ESpeed19200;
						iWapIpISPTable->iCallDataProtocol = RMobileCall::EProtocolV34;
						break;
					case E28800baud:
						iWapIpISPTable->iCallSpeed =RMobileCall::ESpeed28800;
						iWapIpISPTable->iCallDataProtocol = RMobileCall::EProtocolV34;
						break;
					case E38400baud:
					case E43200baud:
					case E57600baud:
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeedAutobauding;
						iWapIpISPTable->iCallDataProtocol = RMobileCall::EProtocolV34;
						break;
					default:  //SHOULD be one of the above!
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeedAutobauding;
						iWapIpISPTable->iCallDataProtocol = RMobileCall::EProtocolV34;
						break;
					}
				}
			else if (!iGsmCsdData && callType == EIsdn)
				{
				iWapIpISPTable->iCallDataProtocol = RMobileCall::EProtocolV110;
				switch (callSpeed)
					{
					case EAutobauding:				
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeedAutobauding;
					break;
					case E9600baud:
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeed9600;
						break;
					case E14400baud:
						iWapIpISPTable->iCallSpeed =RMobileCall::ESpeed14400;
						break;
					case E19200baud:
						iWapIpISPTable->iCallSpeed =RMobileCall::ESpeed19200;
						break;
					case E28800baud:
						iWapIpISPTable->iCallSpeed =RMobileCall::ESpeed28800;
						break;
					case E38400baud:
						iWapIpISPTable->iCallSpeed =RMobileCall::ESpeed38400;
						break;
					case E43200baud:
						iWapIpISPTable->iCallSpeed =RMobileCall::ESpeed48000;
						break;
					case E57600baud:
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeed56000;
						break;
					default:  //SHOULD be one of the above!
						iWapIpISPTable->iCallSpeed = RMobileCall::ESpeedAutobauding;
						break;
					}
				}
			else
				User::Leave(KWappErrUnrecognised); //Unrecognised value for calltype - error
			}
		iGsmCsdData = ETrue;
		}

	else if (currentBearer == EWappGsmSmsBearer)
		iGsmSmsData = ETrue;
	else if(currentBearer == EWappGprsBearer)
		{
		if (!pppLoginType)
			{
			if (iWapGprsTable->iLoginName.Length() > 0 && iWapGprsTable->iLoginPass.Length() > 0)
				iWapGprsTable->iIFPromptForAuth =EFalse;
			}
		iGprsData = ETrue;
		}

	}
//  End of function  CMsvBIOWapAccessParser::ExtractBearerDataL()

//
//	ExtractBookmarkDataL() - 
//			Extracts bookmark from parsed data.  Adds default if name field is not
//			set.  Discards the Bookmark if URL field is blank (ie nothing added to Bookmark 
//			List) NB exactly 2 PARMs in a bookmark, NAME & URL, any order.
//	
void CMsvBIOWapAccessParser::ExtractBookmarkDataL(TInt& aIndex)
	{
	TPtrC tempPtr;
	TBool foundName = EFalse;
	TBool foundURL = EFalse;
	TInt  parmsChecked = 0;

	HBufC* bookmarkName = NULL;
	HBufC* bookmarkURL = NULL;

	// Should be set to the next parm in the Bookmark  NOTE: Can't properly check that 
	// an Empty Name or URL Parsed field is not the start of another characteristic
	while (aIndex < iParsedFieldArray->Count() && !IsCharacteristicName(aIndex))  
		{
		// check token is correct - copy NAME 
		if (parmsChecked <2 && iParsedFieldArray->At(aIndex)->FieldName().CompareF(KWappName) ==0) 
			{
			if (foundName ==EFalse)
				{
				tempPtr.Set(iParsedFieldArray->At(aIndex)->FieldValue());
				if (tempPtr.Length()==0)
					tempPtr.Set(KWappDefaultBMName);
				bookmarkName = tempPtr.AllocL();
				CleanupStack::PushL(bookmarkName);
				foundName =ETrue;
				}
			parmsChecked++;
			}
		else if (parmsChecked <2 && iParsedFieldArray->At(aIndex)->FieldName().CompareF(KWappURL)==0)
			{
			if (foundURL == EFalse)
				{
				tempPtr.Set(iParsedFieldArray->At(aIndex)->FieldValue());
				if (tempPtr.Length() > 0)
					{
					bookmarkURL = tempPtr.AllocL();
					CleanupStack::PushL(bookmarkURL);
					foundURL =ETrue;
					}
				}
			parmsChecked++;
			}
		// Advance to next field if not at the end of the array
		if (aIndex <iParsedFieldArray->Count())
			aIndex++;		 
		}
		// If we've only looked at 2 Parms and have both a Name AND URL 
		// it's a well-formed bookmark so add to it to our List
		if (foundName && foundURL && parmsChecked ==2) 
			{
			CWappBookmark* newBookmark =  CWappBookmark::NewLC();
			newBookmark->SetNameL(*bookmarkName);
			newBookmark->SetUrlL(*bookmarkURL);
			iBookmarkList->AppendL(newBookmark); 				
			CleanupStack::Pop(); // release newBookmark	
			}
		if(bookmarkName) CleanupStack::PopAndDestroy();
		if(bookmarkURL) CleanupStack::PopAndDestroy();
	}

//
//	ValidateCharacteristicsL() - Validates the data extracted by PreProcessL. 
//
//	Following are legitimate messages
//		 -  entirely bookmarks
//		 -  1+ bearers with any no of other characteristics
//		 -  Non-Null URL and Non Null name of existing settings records
//
//	Any other combinations are invalid i.e.
//				
//				Bookmarks with ID/URL/NAME & NO Bearer
//									
void CMsvBIOWapAccessParser::ValidateCharacteristicsL()
	{
	
	// Bookmarks message - bookmarks & no bearers, should be no URL, ID or Settings Name
	if ((iBookmarkList->Count() >0) && 
		!(iGsmCsdData || iGsmSmsData || iGprsData) && 
		(iURLData || iNameData || iIdData))
			User::Leave(KWappErrBadMessage);  
	
	// start page update message - URL+NAME but no Bearers, no bookmarks
	if (iURLData && iNameData && 
		!(iGsmCsdData || iGsmSmsData || iGprsData) && 
		(iBookmarkList->Count()==0) && 
		((iUrl.Length()==0) || (iWAPSettingsName.Length()==0)))
			User::Leave(KWappErrBadMessage);

	if ((iGsmCsdData || iGsmSmsData || iGprsData) && 
		(iWAPSettingsName.Length()==0))     // Need a name for CommDb - default
			User::Leave(KWappErrBadMessage); //  should have been given if nothing in message 
	}

//
//	IsCharacteristicName	-	Returns ETrue if the Name at the index is a genuine 
//								Characteristic Type and the Value is NULL
//
TBool CMsvBIOWapAccessParser::IsCharacteristicName(TInt anIndex)
	{
	TPtrC name = iParsedFieldArray->At(anIndex)->FieldName();
	if (  
		(name.CompareF(KWappCharAddress) ==0) ||  // Address
		(name.CompareF(KWappCharURL) ==0) ||	  // URL 
		(name.CompareF(KWappCharMMSURL) ==0) ||	  // MMS URL 
		(name.CompareF(KWappCharName) ==0) ||  // NAME
		(name.CompareF(KWappCharBookmark) ==0) || // Bookmark
		(name.CompareF(KWappCharID) ==0)  ) // ID
			return ETrue;	// Is a characteristic name
	else
		return EFalse;		// Not a characteristic name
	}

//		
//	SetModemInitStringL() -  Sets the modem initialisation string
//
void CMsvBIOWapAccessParser::SetModemInitStringL() // Sets the modem initialisation string
	{
	delete iModemInitString;
	iModemInitString =NULL;
	iModemInitString=KDummyModemInitStr().AllocL();
	}


void CMsvBIOWapAccessParser::DeleteCommDatTableEntryL(TMDBElementId aElementName, const TDesC& aCsdNameStr)
	{	
	switch	(aElementName)
		{
		case KCDTIdWAPIPBearerRecord:
			{
			CCDWAPIPBearerRecord *wapIPRecord = static_cast<CCDWAPIPBearerRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdWAPIPBearerRecord));
			CleanupStack::PushL(wapIPRecord);
			wapIPRecord->iWAPAccessPointId = iWapAccessPtID;
			
			if(wapIPRecord->FindL(*iDBSession))
				{
				TUint32 accessId = wapIPRecord->iWAPIAP;
				if ( !((iGsmCsdData && iGsmCsdWapIpTable->iIapId == accessId) ||
			           			(iGprsData && iGprsWapIpTable->iIapId == accessId)))					
					{
					wapIPRecord->DeleteL(*iDBSession);			
					}
				}
			CleanupStack::PopAndDestroy(wapIPRecord);					
			}			
			break;
		case KCDTIdWAPSMSBearerRecord:
			{
			CCDWAPSMSBearerRecord *smsRecord = static_cast<CCDWAPSMSBearerRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdWAPSMSBearerRecord));
			CleanupStack::PushL(smsRecord);
			smsRecord->iWAPAccessPointId = iWapAccessPtID;
			if(smsRecord->FindL(*iDBSession))
				{
				smsRecord->DeleteL(*iDBSession);			
				}
			CleanupStack::PopAndDestroy(smsRecord);	
			}			
			break;
		case KCDTIdIAPRecord:
			{
			CCDIAPRecord *iapRecord = static_cast<CCDIAPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord));
			CleanupStack::PushL(iapRecord);
			iapRecord->iRecordName.SetMaxLengthL(aCsdNameStr.Length());
			iapRecord->iRecordName = aCsdNameStr;				
			if(iapRecord->FindL(*iDBSession))
				{
				iapRecord->DeleteL(*iDBSession);				
				}
			CleanupStack::PopAndDestroy(iapRecord);
			}			
			break;
		case KCDTIdDialOutISPRecord:
			{
			CCDDialOutISPRecord *dialOutISPRecord = static_cast<CCDDialOutISPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdDialOutISPRecord));
			CleanupStack::PushL(dialOutISPRecord);
			dialOutISPRecord->iRecordName.SetMaxLengthL(aCsdNameStr.Length());
			dialOutISPRecord->iRecordName = aCsdNameStr;
			if(dialOutISPRecord->FindL(*iDBSession))
				{
				dialOutISPRecord->DeleteL(*iDBSession);				
				}
			CleanupStack::PopAndDestroy(dialOutISPRecord);						
			}
			break;		
		case KCDTIdOutgoingGprsRecord:
			{
			CCDOutgoingGprsRecord *gprsRecord = static_cast<CCDOutgoingGprsRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdOutgoingGprsRecord));
			CleanupStack::PushL(gprsRecord);
			gprsRecord->iRecordName.SetMaxLengthL(aCsdNameStr.Length());
			gprsRecord->iRecordName = aCsdNameStr;
			if(gprsRecord->FindL(*iDBSession))
				{
				gprsRecord->DeleteL(*iDBSession);				
				}
			CleanupStack::PopAndDestroy(gprsRecord);		
			}
			break;			
		}
	}	

void CMsvBIOWapAccessParser::WriteDataToDBL()
	{
	// Should have a table for at least one bearer!!
	__ASSERT_DEBUG (iWapSmsTable != NULL || iWapGprsTable != NULL || (iGsmCsdWapIpTable != NULL && iWapIpISPTable !=NULL), 
									  Panic(EWappNullPointer));

	if (iWAPSettingsName.Length()==0)
		{
		iWAPSettingsName.Set(KWapDefaultSettingsName);
		}	

	TBuf<KMaxNameBufferLength> csdNameStr;
	csdNameStr.Copy(iWAPSettingsName);
	csdNameStr.Append(KGsmCsdSuffix);
	if (iGsmCsdData)
		{
		iCurrentBearerType = EWappGsmCsdBearer;  // Set the bearer type indicator for use in next functions

		WriteToCommDatDialOutISPTableL(csdNameStr);
		SetWapIspEntryIdL(csdNameStr);	// Sets iWapIspID		
		
		WriteToCommsDatIAPTableL(csdNameStr);			
		SetWapIapEntryIdL(csdNameStr, *iGsmCsdWapIpTable);			// Sets iWapIapID
		}
	else
		{
		DeleteCommDatTableEntryL(KCDTIdDialOutISPRecord,csdNameStr);
		DeleteCommDatTableEntryL(KCDTIdIAPRecord,csdNameStr);
		}

	TBuf<KMaxNameBufferLength> gprsNameStr;
	gprsNameStr.Copy(iWAPSettingsName);
	gprsNameStr.Append(KGprsSuffix);
	if(iGprsData)
		{
		iCurrentBearerType = EWappGprsBearer;		
		WriteToCommDatGprsTableL(gprsNameStr);		
		SetWapIspEntryIdL(gprsNameStr);	// Sets iWapIspID
		WriteToCommsDatIAPTableL(gprsNameStr);				
				
		SetWapIapEntryIdL(gprsNameStr, *iGprsWapIpTable);			// Sets iWapIapID
		}
	else
		{
		DeleteCommDatTableEntryL(KCDTIdOutgoingGprsRecord,gprsNameStr);
		DeleteCommDatTableEntryL(KCDTIdIAPRecord,gprsNameStr);
		}
		
	WriteToCommDatWapAccessPointTableL(iWAPSettingsName);		

	SetWapAPEntryIdL();


	if (iGsmCsdData)
		{
		// Set the flag so that correct mapping object is used to set the data in the WAP IP Bearer table
		iCurrentBearerType = EWappGsmCsdBearer;
		WriteToCommDatWapIpBearerTableL();		
		}
	else 		
		{
		DeleteCommDatTableEntryL(KCDTIdWAPIPBearerRecord,csdNameStr);
		}
		

	if ((iGprsData))
		{
		// Set the flag so that correct mapping object is used to set the data in the WAP IP Bearer table
		iCurrentBearerType = EWappGprsBearer;
		WriteToCommDatWapIpBearerTableL();
		}
	else
		{
		DeleteCommDatTableEntryL(KCDTIdWAPIPBearerRecord,gprsNameStr);
		}
		
		
	if (iGsmSmsData)
		{
		WriteToCommDatWapSmsBearerTableL();	
		}		
	else		
		{
		DeleteCommDatTableEntryL(KCDTIdWAPSMSBearerRecord,iWAPSettingsName);
		}
		
		


//	if ((iGsmCsdData) && iModemInitString)    // Only if CSD and has string set (ie ISDN)
//		CreateTableL(TPtrC(MODEM), iWAPSettingsName);  //TODO Not yet implemented 
	}

// End of function  CMsvBIOWapAccessParser::WriteDataToDBL()


void CMsvBIOWapAccessParser::WriteToCommsDatIAPTableL(const TDesC& aRecName)
	{	
	CCDIAPRecord *iapRecord = static_cast<CCDIAPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord));
	CleanupStack::PushL(iapRecord);
	iapRecord->iRecordName.SetMaxLengthL(aRecName.Length());
	iapRecord->iRecordName = aRecName;
	
	TBool newRecord = EFalse;
	if(!iapRecord->FindL(*iDBSession))
		{
		iapRecord->SetRecordId(KCDNewRecordRequest);
		newRecord = ETrue;
		}		
			
	switch (iCurrentBearerType)
		{
		case EWappGsmCsdBearer:
			{
			iapRecord->iService = iWapIpISPTable->iISPCommDbRecordId;
			iapRecord->iServiceType.SetMaxLengthL(((TPtrC)KCDTypeNameDialOutISP).Length());
			iapRecord->iServiceType = (TPtrC)KCDTypeNameDialOutISP;			

			//there are 7 fields in IAP table which cannot have null values, and so when creating an IAP record we were only filling in one of the fields which meant we were submitting a record with lots of null values which can't be handled.
			iapRecord->iBearer = (TUint32)2;
			
			iapRecord->iBearerType.SetMaxLengthL(((TPtrC)KCDTypeNameModemBearer).Length());
			iapRecord->iBearerType = (TPtrC)KCDTypeNameModemBearer;
			iapRecord->iNetwork = (TUint32)1;
			iapRecord->iNetworkWeighting = (TUint32)0;
			iapRecord->iLocation = (TUint32)4;							
			}
			break;
		case EWappGprsBearer:
			{
			iapRecord->iService = iWapGprsTable->iGprsCommDbRecordId;
			iapRecord->iServiceType.SetMaxLengthL(((TPtrC)KCDTypeNameDialOutISP).Length());
			iapRecord->iServiceType = (TPtrC)KCDTypeNameOutgoingWCDMA;

			//there are 7 fields in IAP table which cannot have null values, and so when creating an IAP record we were only filling in one of the fields which meant we were submitting a record with lots of null values which can't be handled.
			iapRecord->iBearer = (TUint32)2;
			iapRecord->iBearerType.SetMaxLengthL(((TPtrC)KCDTypeNameModemBearer).Length());
			iapRecord->iBearerType = (TPtrC)KCDTypeNameModemBearer;
			iapRecord->iNetwork = (TUint32)1;
			iapRecord->iNetworkWeighting = (TUint32)0;	
			iapRecord->iLocation = (TUint32)4;	
			}									
			break;
		default:
			break;
		}	
	
	if(newRecord)
		{					
		iapRecord->StoreL(*iDBSession);
		}		
	else
		{
		iapRecord->ModifyL(*iDBSession);	
		}	
	
	CleanupStack::PopAndDestroy(iapRecord);
	}
	
void CMsvBIOWapAccessParser::WriteToCommDatWapSmsBearerTableL()
	{	
	CCDWAPSMSBearerRecord *wapSMSBearerRecord = static_cast<CCDWAPSMSBearerRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdWAPSMSBearerRecord));
	CleanupStack::PushL(wapSMSBearerRecord);
	//Search based on WAPAccessPointId
	wapSMSBearerRecord->iWAPAccessPointId = iWapAccessPtID;	
	
	TBool newRecord = EFalse;	
	if(!wapSMSBearerRecord->FindL(*iDBSession))	
		{
		wapSMSBearerRecord->SetRecordId(KCDNewRecordRequest);			
		newRecord = ETrue;
		}			
	
	wapSMSBearerRecord->iWAPGatewayAddress.SetMaxLengthL(iWapSmsTable->iGatewayAddr.Length());
	wapSMSBearerRecord->iWAPGatewayAddress = iWapSmsTable->iGatewayAddr;
	
	wapSMSBearerRecord->iWAPServiceCentreAddress.SetMaxLengthL(iWapSmsTable->iWapServiceAddr.Length());
	wapSMSBearerRecord->iWAPServiceCentreAddress = iWapSmsTable->iWapServiceAddr;
	
	wapSMSBearerRecord->iWAPWSPOption = GetWSPType(iWapSmsTable->iPort);			
	wapSMSBearerRecord->iWAPSecurity = UseSecurity(iWapSmsTable->iPort);	
		
	if(newRecord)
		{					
		wapSMSBearerRecord->StoreL(*iDBSession);
		}		
	else
		{
		wapSMSBearerRecord->ModifyL(*iDBSession);	
		}		
	
	CleanupStack::PopAndDestroy(wapSMSBearerRecord);
	}

void CMsvBIOWapAccessParser::WriteToCommDatWapIpBearerTableL()
	{	
	CCDWAPIPBearerRecord *wapIPBearerRecord = static_cast<CCDWAPIPBearerRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdWAPIPBearerRecord));
	CleanupStack::PushL(wapIPBearerRecord);
	//Search based on WAPAccessPointId
	wapIPBearerRecord->iWAPAccessPointId = iWapAccessPtID;	
	
	TBool newRecord = EFalse;	
	if(!wapIPBearerRecord->FindL(*iDBSession))
		{
		wapIPBearerRecord->SetRecordId(KCDNewRecordRequest);					
		newRecord = ETrue;
		}		
	
	CWapIpBearerData* wapIpTableData = NULL;
	switch (iCurrentBearerType)
		{
		case EWappGsmCsdBearer:
			{
			wapIpTableData = iGsmCsdWapIpTable;	
			}			
			break;
		case EWappGprsBearer:
			{
			wapIpTableData = iGprsWapIpTable;	
			}			
			break;
		default:
			User::Leave(KWappErrUnexpectedValue);
		}
	__ASSERT_DEBUG(wapIpTableData, Panic(KWappErrNullValue));

	wapIPBearerRecord->iWAPAccessPointId = iWapAccessPtID;
 	wapIPBearerRecord->iWAPIAP = wapIpTableData->iIapId;			// Get from SetWapEntryIdsL

	wapIPBearerRecord->iWAPGatewayAddress.SetMaxLengthL((wapIpTableData->iGatewayAddr->Addr()).Length());
	wapIPBearerRecord->iWAPGatewayAddress = wapIpTableData->iGatewayAddr->Addr();
	
	wapIPBearerRecord->iWAPWSPOption =  GetWSPType(wapIpTableData->iPort);
	wapIPBearerRecord->iWAPSecurity =  UseSecurity(wapIpTableData->iPort);
	
	TLex lex = wapIpTableData->iPort;
	TInt port = 0;	
	User::LeaveIfError(lex.Val(port));
	wapIPBearerRecord->iWAPProxyPort =  port;
	
	wapIPBearerRecord->iWAPProxyLoginName.SetMaxLengthL(wapIpTableData->iProxyAuthName.Length());
	wapIPBearerRecord->iWAPProxyLoginName = wapIpTableData->iProxyAuthName;
	
	wapIPBearerRecord->iWAPProxyLoginPass.SetMaxLengthL(wapIpTableData->iProxyAuthSecret.Length());
	wapIPBearerRecord->iWAPProxyLoginPass = wapIpTableData->iProxyAuthSecret;
	
	if(newRecord)
		{					
		wapIPBearerRecord->StoreL(*iDBSession);
		}		
	else
		{
		wapIPBearerRecord->ModifyL(*iDBSession);	
		}	
	
	CleanupStack::PopAndDestroy(wapIPBearerRecord);	
	}

void CMsvBIOWapAccessParser::WriteToCommDatWapAccessPointTableL(const TDesC& aRecName)
	{	
	CCDWAPAccessPointRecord *wapAPRecord = static_cast<CCDWAPAccessPointRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdWAPAccessPointRecord));
	CleanupStack::PushL(wapAPRecord);
	wapAPRecord->iRecordName.SetMaxLengthL(aRecName.Length());	
	wapAPRecord->iRecordName = aRecName;
	TBool newRecord = EFalse;
	if(!wapAPRecord->FindL(*iDBSession))
		{
		wapAPRecord->SetRecordId(KCDNewRecordRequest);
		newRecord = ETrue;	
		}
				
	if (iUrl.Length() != 0)
		{
		wapAPRecord->iWAPStartPage.SetMaxLengthL(iUrl.Length());
		wapAPRecord->iWAPStartPage = iUrl;	
		}		

	if ((iGsmCsdData) || (iGprsData))
		wapAPRecord->iWAPCurrentBearer = TPtrC(WAP_IP_BEARER);
	else if (iGsmSmsData)
		wapAPRecord->iWAPCurrentBearer = TPtrC(WAP_SMS_BEARER);
	else
		User::Leave(KWappErrUnexpectedValue);	
	
	if(newRecord)
		{					
		wapAPRecord->StoreL(*iDBSession);
		}		
	else
		{
		wapAPRecord->ModifyL(*iDBSession);	
		}
	
	CleanupStack::PopAndDestroy(wapAPRecord);
	}

void CMsvBIOWapAccessParser::WriteToCommDatGprsTableL(const TDesC& aRecName)
	{	
	CCDOutgoingGprsRecord *gprsRecord = static_cast<CCDOutgoingGprsRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdOutgoingGprsRecord));
	CleanupStack::PushL(gprsRecord);
	gprsRecord->iRecordName.SetMaxLengthL(aRecName.Length());
	gprsRecord->iRecordName = aRecName;
	
	TBool newRecord = EFalse;
	if(!gprsRecord->FindL(*iDBSession))	
		{
		gprsRecord->SetRecordId(KCDNewRecordRequest);
		newRecord = ETrue;	
		}
				
	gprsRecord->iGPRSAPN.SetMaxLengthL(iWapGprsTable->iAccessPointName.Length());
	gprsRecord->iGPRSAPN = iWapGprsTable->iAccessPointName;
	
	gprsRecord->iGPRSPDPType = iWapGprsTable->iPDPType;
	
	gprsRecord->iGPRSPDPAddress.SetMaxLengthL(iWapGprsTable->iPDPAddress->Des().Length());
	gprsRecord->iGPRSPDPAddress = iWapGprsTable->iPDPAddress->Des();

	gprsRecord->iGPRSIfPromptForAuth = iWapGprsTable->iIFPromptForAuth;
	
	gprsRecord->iGPRSIfAuthName.SetMaxLengthL(iWapGprsTable->iLoginName.Length());
	gprsRecord->iGPRSIfAuthName = iWapGprsTable->iLoginName;
	
	gprsRecord->iGPRSIfAuthPass.SetMaxLengthL(iWapGprsTable->iLoginPass.Length());
	gprsRecord->iGPRSIfAuthPass = iWapGprsTable->iLoginPass;
	
	gprsRecord->iGPRSIPGateway.SetMaxLengthL(iWapGprsTable->iGatewayAddr->Addr().Length());
	gprsRecord->iGPRSIPGateway = iWapGprsTable->iGatewayAddr->Addr();
	
	gprsRecord->iGPRSIPAddrFromServer = iWapGprsTable->iIpAddrFromServer;
	
	gprsRecord->iGPRSIPDNSAddrFromServer = iWapGprsTable->iIPDnsAddrFromServer;
	gprsRecord->iGPRSDisablePlainTextAuth = iWapGprsTable->iPlainTextAuthDisabled;	
	
	if(newRecord)
		{					
		gprsRecord->StoreL(*iDBSession);
		}		
	else
		{
		gprsRecord->ModifyL(*iDBSession);	
		}
	
	CleanupStack::PopAndDestroy(gprsRecord);	
	}

void CMsvBIOWapAccessParser::WriteToCommDatDialOutISPTableL(const TDesC& aRecName)
	{	
	CCDDialOutISPRecord *dialoutRecord = static_cast<CCDDialOutISPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdDialOutISPRecord));
	CleanupStack::PushL(dialoutRecord);
	dialoutRecord->iRecordName.SetMaxLengthL(aRecName.Length());	
	dialoutRecord->iRecordName = aRecName;
	
	TBool newRecord = EFalse;
	if(!dialoutRecord->FindL(*iDBSession))
		{										
		dialoutRecord->SetRecordId(KCDNewRecordRequest);
		newRecord = ETrue;
		
		iWapIpISPTable->iISPCommDbRecordId = dialoutRecord->iRecordTag.RecordId();
		}
		
	//It's time to write values	
	(dialoutRecord->iDescription).SetMaxLengthL(iWapIpISPTable->iISPDescription.Length());
	dialoutRecord->iDescription = iWapIpISPTable->iISPDescription;
	
	dialoutRecord->iType = iWapIpISPTable->iISPType; 
	
	dialoutRecord->iDefaultTelNum.SetMaxLengthL(iWapIpISPTable->iDefaultPhoneNum.Length());
	dialoutRecord->iDefaultTelNum = iWapIpISPTable->iDefaultPhoneNum;
	
	dialoutRecord->iDialResolution = iWapIpISPTable->iDialResolution; //Mandatory, ETrue  default

	dialoutRecord->iUseLoginScript = iWapIpISPTable->iUseScript;	//Mandatory, EFalse by default
	
	if (iWapIpISPTable->iLoginScript.Length() != 0)
		{
		(dialoutRecord->iLoginScript).SetMaxLengthL(iWapIpISPTable->iLoginScript.Length()); 	
		dialoutRecord->iLoginScript = iWapIpISPTable->iLoginScript; 
		}	
	dialoutRecord->iPromptForLogin = iWapIpISPTable->iPromptForLoginDetails; // Mandatory, ETrue by default
	dialoutRecord->iLoginName.SetMaxLengthL((iWapIpISPTable->iLoginName).Length());
	dialoutRecord->iLoginName = iWapIpISPTable->iLoginName;
	
	(dialoutRecord->iLoginPass).SetMaxLengthL((iWapIpISPTable->iLoginPass).Length());
	dialoutRecord->iLoginPass = iWapIpISPTable->iLoginPass;
	
	dialoutRecord->iDisplayPct = iWapIpISPTable->iDisplayPCT;

	(dialoutRecord->iIfParams).SetMaxLengthL((iWapIpISPTable->iIFParams).Length());
	dialoutRecord->iIfParams = iWapIpISPTable->iIFParams;
	
	(dialoutRecord->iIfNetworks).SetMaxLengthL((iWapIpISPTable->iIFNetworks->Des()).Length());
	dialoutRecord->iIfNetworks = iWapIpISPTable->iIFNetworks->Des(); // Set to "IP"
	
	dialoutRecord->iIfPromptForAuth = iWapIpISPTable->iPromptForLoginDetails; //Mandatory, default is ETrue
	
	(dialoutRecord->iIfAuthName).SetMaxLengthL((iWapIpISPTable->iLoginName).Length());
	dialoutRecord->iIfAuthName = iWapIpISPTable->iLoginName;
	
	(dialoutRecord->iIfAuthPass).SetMaxLengthL((iWapIpISPTable->iLoginPass).Length());
	dialoutRecord->iIfAuthPass = iWapIpISPTable->iLoginPass;
	
	dialoutRecord->iIfAuthRetries = iWapIpISPTable->iNumAuthAttempts;

	dialoutRecord->iIfCallbackEnabled = iWapIpISPTable->iCallBackEnabled;
	if (iWapIpISPTable->iCallBackEnabled)
		{
		dialoutRecord->iIfCallbackType = iWapIpISPTable->iCallBackType;		
		TPtr8 tempPtr(0,0); 		
		tempPtr.Copy(iWapIpISPTable->iCallBackInfo);
		
		dialoutRecord->iIfCallbackInfo.SetMaxLengthL(tempPtr.Length());
		dialoutRecord->iIfCallbackInfo = tempPtr;
		dialoutRecord->iCallbackTimeout = 10000; 
		}

	dialoutRecord->iIpAddrFromServer = iWapIpISPTable->iAddrFromServer; //Mandatory set to True
	
	(dialoutRecord->iIpAddr).SetMaxLengthL((iWapIpISPTable->iInOutAddress->Addr()).Length());
	dialoutRecord->iIpNetMask = iWapIpISPTable->iNetmask->Addr();
	
	(dialoutRecord->iIpGateway).SetMaxLengthL((iWapIpISPTable->iGateway->Addr()).Length());
	dialoutRecord->iIpGateway = iWapIpISPTable->iGateway->Addr();
	
	dialoutRecord->iIpDnsAddrFromServer = iWapIpISPTable->iDNSFromServer;
	// Following will write NULL strings to database, clearing any previous settings.
	
	(dialoutRecord->iIpNameServer1).SetMaxLengthL((iWapIpISPTable->iDNS1->Addr()).Length());
	dialoutRecord->iIpNameServer1 = iWapIpISPTable->iDNS1->Addr();
	
	(dialoutRecord->iIpNameServer2).SetMaxLengthL((iWapIpISPTable->iDNS2->Addr()).Length());
	dialoutRecord->iIpNameServer2 = iWapIpISPTable->iDNS2->Addr();
	
	dialoutRecord->iEnableIpHeaderComp = iWapIpISPTable->iHeaderCompressionEnabled;
	// Don't bother with LCP extensions -  leave as null field
	dialoutRecord->iDisablePlainTextAuth = iWapIpISPTable->iPlainTextAuthDisabled;
	dialoutRecord->iEnableSwComp = iWapIpISPTable->iSwCompressionEnabled;	
	dialoutRecord->iBearerSpeed = iWapIpISPTable->iCallSpeed;
	dialoutRecord->iBearerProtocol = iWapIpISPTable->iCallDataProtocol;

	if(newRecord)
		{					
		dialoutRecord->StoreL(*iDBSession);
		}		
	else
		{
		dialoutRecord->ModifyL(*iDBSession);	
		}
	
	CleanupStack::PopAndDestroy(dialoutRecord);
	}


//
//		SetWapIspEntryIdL	- The iCurrentBearerType variable MUST be correctly set before this 
//							  function is called. Searches the appropriate Service table - DIAL_OUT_ISP
//							 or  OUTGOING_WCDMA  - for records named as aEntryName (which should be unique!)
//						   When it finds the record, it uses the record ID to set the class member iWapIspID.
//
void CMsvBIOWapAccessParser::SetWapIspEntryIdL(const TDesC& aEntryName)
	{
	TUint32 recId = 0;	
	switch (iCurrentBearerType)
		{
		case EWappGsmCsdBearer:
			{
			CCDDialOutISPRecord *dialOutRecord = static_cast<CCDDialOutISPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdDialOutISPRecord));
			CleanupStack::PushL(dialOutRecord);
			dialOutRecord->iRecordName.SetMaxLengthL(aEntryName.Length());
			dialOutRecord->iRecordName = aEntryName;			
						
			if (dialOutRecord->FindL(*iDBSession))			
				{				
				recId = dialOutRecord->iRecordTag.RecordId();									
				}
			else
				{				
				User::Leave(KErrNotFound);
				}
			CleanupStack::PopAndDestroy(dialOutRecord);			
			}			
			break;
		case EWappGprsBearer:
			{
			CCDOutgoingGprsRecord *gprsRecord = static_cast<CCDOutgoingGprsRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdOutgoingGprsRecord));
			CleanupStack::PushL(gprsRecord);
			gprsRecord->iRecordName.SetMaxLengthL(aEntryName.Length());
			gprsRecord->iRecordName = aEntryName;
						
			if (gprsRecord->FindL(*iDBSession))
				{
				recId = gprsRecord->iRecordTag.RecordId();					
				}
			else
				{				
				User::Leave(KErrNotFound);
				}
			CleanupStack::PopAndDestroy(gprsRecord);	
			}						
			break;
		default:
			User::Leave(KWappErrUnexpectedValue);
		}
		
	switch (iCurrentBearerType)
		{
		case EWappGsmCsdBearer:
			iWapIpISPTable->iISPCommDbRecordId = recId;
			break;
		case EWappGprsBearer:
			iWapGprsTable->iGprsCommDbRecordId = recId;
			break;
		default:
			User::Leave(KWappErrUnexpectedValue);
			break;
		}	
	}


//
//		SetWapIapEntryIdL	- Searches the IAP database for records of the same name 
//						  as aEntryName (which should be unique!). When it finds the 
//						  record, it uses the record ID to set the class member iWapIapID.
//
void CMsvBIOWapAccessParser::SetWapIapEntryIdL(const TDesC& aEntryName, CWapIpBearerData& aWapIpTable)
	{
	CCDIAPRecord *iAPRecord = static_cast<CCDIAPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdIAPRecord));
	CleanupStack::PushL(iAPRecord);
	iAPRecord->iRecordName.SetMaxLengthL(aEntryName.Length());
	iAPRecord->iRecordName = aEntryName;
				
	if (iAPRecord->FindL(*iDBSession))
		{
		aWapIpTable.iIapId = iAPRecord->iRecordTag.RecordId();					
		}
	else
		{
		User::Leave(KErrNotFound);		
		}
	CleanupStack::PopAndDestroy(iAPRecord);	
	}

//
//		SetWapIspEntryIdL	- Searches the WAP_ACCESS_POINT table for records of the same name 
//						  as iWapSettingsName (which should be unique!). When it finds the 
//						  record, it uses the record ID to set the class member iWapIspID.
//
void CMsvBIOWapAccessParser::SetWapAPEntryIdL()
	{
	CCDWAPAccessPointRecord *wapAccessRecord = static_cast<CCDWAPAccessPointRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdWAPAccessPointRecord));
	CleanupStack::PushL(wapAccessRecord);
	wapAccessRecord->iRecordName.SetMaxLengthL(iWAPSettingsName.Length());
	wapAccessRecord->iRecordName = iWAPSettingsName;	
	
	if (wapAccessRecord->FindL(*iDBSession))
		{    
		iWapAccessPtID = wapAccessRecord->iRecordTag.RecordId();	//  set the WAP AP table ID					
		}
	else
		{
		User::Leave(KErrNotFound);		
		}
	CleanupStack::PopAndDestroy(wapAccessRecord);	
	}
	

void CMsvBIOWapAccessParser::WriteMMSURLL()
	{

	// check that the version of the MMS settings proxy dll is suitable
	RImplInfoPtrArray list;
   	REComSession::ListImplementationsL(KMMSSettingsProxyInterfaceUid, list);
   	TInt count = list.Count();
   	TBool found = EFalse;
   	// may be more than one implementation, look for the 'right' one
   	while (!found && count-- > 0)
    	{
      	if (list[count]->ImplementationUid() == KMMSSettingsProxyBaseUid &&
        	list[count]->Version() == KMMSSettingsProxyVersionSupported)
         	{
         	// Found supported version - stop looking.
         	found = ETrue;
         	}
      	}
   	list.ResetAndDestroy();
   	// if there are no implementations or the version is unsupported, then leave
	if (!found)
		User::Leave(KErrNotFound);

	CMMSSettingsProxyBase* settings = CMMSSettingsProxyBase::NewL(KMMSSettingsProxyBaseUid);
	CleanupStack::PushL(settings);

	TSglQue<TMMSSettingsPair> settingList(_FOFF(TMMSSettingsPair, iLink));

	// Different MMS implementations require different things.  Pass all the things they might
	// want and allow the implementation to use those it chooses.

	// The MMS Url
	TMMSSettingsPair urlPair;
	urlPair.iName.Set(KMMSUrl);
	urlPair.iValue = &iMMSUrl;
	settingList.AddFirst(urlPair);


	TBuf<KMaxNameBufferLength> nameStr;
	nameStr.Copy(iWAPSettingsName);
	if (iGsmCsdData)
		{
		nameStr.Append(KGsmCsdSuffix);
		}

	if(iGprsData)
		{
		nameStr.Append(KGprsSuffix);
		}	


	TUint32 id=0;

	switch (iCurrentBearerType)
		{
		case EWappGsmCsdBearer:
			{
			CCDDialOutISPRecord *dialOutISPRecord = static_cast<CCDDialOutISPRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdDialOutISPRecord));
			CleanupStack::PushL(dialOutISPRecord);
			dialOutISPRecord->iRecordName.SetMaxLengthL(nameStr.Length());
			dialOutISPRecord->iRecordName = nameStr;		
			if(!dialOutISPRecord->FindL(*iDBSession))
				{
				User::Leave(KErrNotFound);	
				}				
			id = dialOutISPRecord->iRecordTag.RecordId();
			CleanupStack::PopAndDestroy(dialOutISPRecord);
			}
			break;
		case EWappGprsBearer:
			{
			CCDOutgoingGprsRecord *gprsRecord = static_cast<CCDOutgoingGprsRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdOutgoingGprsRecord));
			CleanupStack::PushL(gprsRecord);
			gprsRecord->iRecordName.SetMaxLengthL(nameStr.Length());
			gprsRecord->iRecordName = nameStr;	
				
			if(!gprsRecord->FindL(*iDBSession))
				{
				User::Leave(KErrNotFound);	
				}			
			id = gprsRecord->iRecordTag.RecordId();
			CleanupStack::PopAndDestroy(gprsRecord);
			}
			break;
		default:
			User::Leave(KWappErrUnexpectedValue);
		}	

	TMMSSettingsPair commDbRecordId;
	commDbRecordId.iName.Set(KCommDbRecordId);
	commDbRecordId.iValue = &id;
	settingList.AddFirst(commDbRecordId);

	TMMSSettingsPair msvServerEntryPair;
	// 24/08/04
	// In messaging API v2, iEntry is no longer a CMsvServerEntry, but rather a CMsvEntry.
	// For this reason, the following code has been changed.
	// This breaks data compatability.
	// CMsvEntry
	msvServerEntryPair.iName.Set(KMsvEntry);
	msvServerEntryPair.iValue = &iEntry;
	settingList.AddFirst(msvServerEntryPair);

	settings->SetMMSValuesL(settingList);
	CleanupStack::PopAndDestroy(settings);
	}


//	GetWSPTypeL - Helper function used by IP and SMS functions above. Returns appropriate enum
//
TCommsDbWapWspOption CMsvBIOWapAccessParser::GetWSPType(TDesC& aPortValue)
	{
	TCommsDbWapWspOption wspType;

	// Is it Connection Orientated link ?
	if ( (aPortValue.CompareF(KWappPort9201)==0)||
			(aPortValue.CompareF(KWappPort9203)==0) )
		
			wspType=EWapWspOptionConnectionOriented;
	
	else
		if ( (aPortValue.CompareF(KWappPort9200)==0)||
		  (aPortValue.CompareF(KWappPort9202)==0) )

			wspType=EWapWspOptionConnectionless;
		else  //unknown type -  so apply the default 
			wspType=EWapWspOptionConnectionless;

	return  wspType;
	}

TBool CMsvBIOWapAccessParser::UseSecurity(TDesC& aPortValue)
	{
	TBool useWapSecurity;
	// Is it unsecured link?
	if ( (aPortValue.CompareF(KWappPort9200)==0)||
		  (aPortValue.CompareF(KWappPort9201)==0) )
		useWapSecurity=EFalse;
	else
		if ( (aPortValue.CompareF(KWappPort9202)==0)||
			 (aPortValue.CompareF(KWappPort9203)==0) )
			useWapSecurity=ETrue;
		else  // unknown Port value - shouldn't happen but use default anyway
			useWapSecurity = EFalse;
	
	return useWapSecurity;
	}

//	UpdateStartPageUrlL() - Searchs the WAP table for a match to the name and updates
//							the WAP_START_PAGE field with the value in the URL char of the message
//

void CMsvBIOWapAccessParser::UpdateStartPageUrlL()
	{
	__ASSERT_DEBUG(iWAPSettingsName.Length() != 0, Panic(EWappEmptyBuffer));
	__ASSERT_DEBUG(iUrl.Length() != 0, Panic(EWappEmptyBuffer));

	CCDWAPAccessPointRecord *wapAPRecord = static_cast<CCDWAPAccessPointRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdWAPAccessPointRecord));
	CleanupStack::PushL(wapAPRecord);
	wapAPRecord->iRecordName.SetMaxLengthL(iWAPSettingsName.Length());
	wapAPRecord->iRecordName = iWAPSettingsName;	
	
	if(!wapAPRecord->FindL(*iDBSession))
		{
		User::Leave(KErrNotFound);
		}	
	wapAPRecord->iWAPStartPage.SetMaxLengthL(iUrl.Length());
	wapAPRecord->iWAPStartPage = iUrl;
	wapAPRecord->ModifyL(*iDBSession);	
	CleanupStack::PopAndDestroy(wapAPRecord);
	}


//
// IsValidTokenNameL()	- Checks that the name field at the position specified is 
//						  a valid Characteristic or Parm name
//

TInt CMsvBIOWapAccessParser::IsValidTokenNameL(const TInt aArrayIndex)
	{
	TPtrC name;

	name.Set(iParsedFieldArray->At(aArrayIndex)->FieldName());

	if ( (name.CompareF(KWappXMLversion) ==0)||
		 (name.CompareF(KWappPublicID) ==0)||
		 (name.CompareF(KWappCharacterSet) ==0)||   		
		 (name.CompareF(KWappCharAddress) ==0)||		// ADDRESS Characteristic
		 (name.CompareF(KWappCharURL) ==0)||			// URL Characteristic 
		 (name.CompareF(KWappCharMMSURL) ==0)||			// URL Characteristic 
		 (name.CompareF(KWappCharName) ==0)||				// NAME Characteristic OR ATTRIBUTE 
		 (name.CompareF(KWappCharBookmark) ==0)||		// BOOKMARK Characteristic 
		 (name.CompareF(KWappCharID) ==0)||				// ID Characteristic 
		 (name.CompareF(KWappURL) ==0)||				// URL Parm 
		 (name.CompareF(KWappName) ==0)||				// NAME Parm OR ATTRIBUTE 
		 (name.CompareF(KWappBearer) ==0)||				// BEARER Attribute 
		 (name.CompareF(KWappProxy) ==0)||				// PROXY
		 (name.CompareF(KWappPort) ==0)||				// PORT
		 (name.CompareF(KWappProxyType) ==0)||			// PROXY_TYPE  - for USSD only
		 (name.CompareF(KWappProxyAuthName) ==0)||		// PROXY_AUTHNAME
		 (name.CompareF(KWappProxyAuthSecret) ==0)||	// PROXY_AUTHSECRET
		 (name.CompareF(KWappProxyLoginType) ==0)||		// PROXY_LOGIN_TYPE
		 (name.CompareF(KWappSMSCAddress) ==0)||		// SMS_SMSC_ADDRESS
		 (name.CompareF(KWappUSSDCode) ==0)||			// USSD SERVICE CODE
		 (name.CompareF(KWappAccessPointName) ==0)||	// ACCESSPOINTNAME
		 (name.CompareF(KWappCsdDial) ==0)||			// CSD_DIALSTRING
		 (name.CompareF(KWappPPPAuthType) ==0)||		// PPP_AUTHTYPE
		 (name.CompareF(KWappPPPAuthName) ==0)||		// PPP_AUTHNAME
		 (name.CompareF(KWappPPPAuthSecret) ==0)||		// PPP_AUTHSECRET
		 (name.CompareF(KWappPPPLoginType) ==0)||		// PPP_LOGIN_TYPE
		 (name.CompareF(KWappCsdCallType) ==0)||		// CSD_CALLTYPE
		 (name.CompareF(KWappCsdCallSpeed) ==0)||		// CSD_CALLSPEED
		 (name.CompareF(KWappISP) ==0) )				// ISP_NAME
 

		return KErrNone;
	else 
		return KWappErrUnrecognised;
	}

//
//  WriteBookmarksToFileL() - Store Bookmarks as an attachment file 
//	in the .eBM format. If the system runs out of memory while
//  the bookmarks are being written to the file, the file will be
//	deleted. For example, if 2 bookmarks have already been written
//	to the file, and the writing of the third bookmark fails, the
//	file will be deleted. Otherwise, a failure of file writing would
//	need to be handled differently from memory allocation failure.
//
void CMsvBIOWapAccessParser::WriteBookmarksToFileL()
{
	
	TInt numberOfItems = iBookmarkList->Count();

	if (numberOfItems > 0)	// Only create a file if there is something 
							//to save
	{	

		TFileName filePath;


		// build the filename
		TMsvId entryId = iEntry.Entry().Id();
		filePath.Num(entryId,EHex);
		filePath.Append(KEBookmarkExtension);
		
		// Get the attachment manager and create an empty attachment file
		CMsvStore* store = iEntry.EditStoreL();
		CleanupStack::PushL(store);
		
		MMsvAttachmentManager& manager = store->AttachmentManagerL();
		MMsvAttachmentManagerSync& managerSync = store->AttachmentManagerExtensionsL();		
		RemoveAttachmentIfExistL(filePath, manager, managerSync);
		CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
		CleanupStack::PushL(attachment);
		attachment->SetAttachmentNameL(filePath);
		
		RFile file;
		managerSync.CreateAttachmentL(filePath, file, attachment);
		CleanupStack::Pop(attachment); // ownership passed
		
		CleanupClosePushL(file);
		

#ifdef SYMBIAN_BOOKMARK_DATABASE
		// Open the bookmark database ready to add the bookmarks
		RBkDatabase bookmarkDb;
		bookmarkDb.OpenL();
		CleanupClosePushL(bookmarkDb);
#endif // SYMBIAN_BOOKMARK_DATABASE

		// Stream each bookmark into the file.
		// The eBookmark file must contain only 8bit ascii.
		// Add a linefeed to the end of each line.
		
		TInt count = 0;
			
		while(count < numberOfItems)
			{
			CWappBookmark& item = *iBookmarkList->At(count);
			
			// Allocate enough space to hold the full bookmark entry.

			TInt length =	item.Name().Length() + 
							item.Url().Length()  + 
							KEBookmarkConstantChars;
			
			HBufC8* writeBuf = HBufC8::NewLC(length);
			
			TPtr8 des = writeBuf->Des();

			des.Append(KEBookmarkItemBegin);
			des.Append(KEBookmarkItemURL);
			des.Append(item.Url());
			des.Append(KCRLinefeed);
			des.Append(KEBookmarkItemName);
			des.Append(item.Name());
			des.Append(KCRLinefeed);
			des.Append(KEBookmarkType);
			des.Append(KEBookmarkItemEnd);

			User::LeaveIfError(file.Write(des));
			
			CleanupStack::PopAndDestroy();

#ifdef SYMBIAN_BOOKMARK_DATABASE
			// Add the bookmark to the bookmark database
			RBkBookmark bookmark = bookmarkDb.CreateBookmarkL();
			CleanupClosePushL(bookmark);
			bookmark.SetTitleL(item.Name());
			// Convert Uri to 8-bit
			HBufC8* bookmarkUri = HBufC8::NewLC(item.Url().Length());
			bookmarkUri->Des().Copy(item.Url());
			bookmark.SetUriL(*bookmarkUri);
			CleanupStack::PopAndDestroy(2, &bookmark); // bookmarkUri, bookmark
#endif // SYMBIAN_BOOKMARK_DATABASE

			count++;
			}

#ifdef SYMBIAN_BOOKMARK_DATABASE			
		// Commit all the added bookmarks and close bookmark db
		bookmarkDb.CommitL();
		CleanupStack::PopAndDestroy(&bookmarkDb);
#endif // SYMBIAN_BOOKMARK_DATABASE

		// File writing has completed, set the size in the attachment
		TInt fileSize;
		User::LeaveIfError(file.Size(fileSize));
		attachment->SetSize(fileSize);
		
		// commit the changes
		store->CommitL();
		CleanupStack::PopAndDestroy(2, store); // file, store

	}
}	
//  End of function WriteBookmarksToFileL()

void CMsvBIOWapAccessParser::RemoveAttachmentIfExistL(const TDesC& aFileName, MMsvAttachmentManager& aManager, MMsvAttachmentManagerSync& aManagerSync)
	{
	// If an attachment already exists with the same filename then delete
	// the existing one so multiple files of the same name dont exist
	for( TInt ii=0; ii<aManager.AttachmentCount(); ++ii )
		{
		CMsvAttachment* attachmentInfo = aManager.GetAttachmentInfoL(ii);
		CleanupStack::PushL(attachmentInfo);
		if( attachmentInfo->AttachmentName().CompareF(aFileName) == 0 )
			{
			
			// We have a match, delete the attachment as we will have
			// to add it as new one
			aManagerSync.RemoveAttachmentL(ii);
			CleanupStack::PopAndDestroy(attachmentInfo); // attachmentInfo
			break;
			}
		CleanupStack::PopAndDestroy(attachmentInfo);
		}
	}

void CMsvBIOWapAccessParser::Panic(TInt aPanic)
	{
	User::Panic(KWappDll, aPanic);
	}


CWapCharsetConverter* CWapCharsetConverter::NewL(RFs& aFs, TUint aMibEnum)
	{
	CWapCharsetConverter* self = new (ELeave) CWapCharsetConverter(aFs);
	CleanupStack::PushL(self);
	self->ConstructL(aMibEnum);
	CleanupStack::Pop(self);
	return self;
	}

void CWapCharsetConverter::ConstructL(TInt aMibEnum)
	{
	iConverter = CCnvCharacterSetConverter::NewL();
	iAvailableCharsets = iConverter->CreateArrayOfCharacterSetsAvailableL(iFs);

	if(aMibEnum == 0)
		{
		iParseable = EFalse;
		return;
		}
	
	TInt charset = iConverter->ConvertMibEnumOfCharacterSetToIdentifierL(aMibEnum, iFs);

	if(charset==0)
		{
		iParseable = EFalse;
		return;
		}

	CCnvCharacterSetConverter::TAvailability t = iConverter->PrepareToConvertToOrFromL(charset, iFs);
	iParseable = (t == CCnvCharacterSetConverter::EAvailable);
	}

void CWapCharsetConverter::ConvertL(const TDesC& aSource, TDes& aSink)
	{
	if(iParseable)
		{
		//defect fix for Inc021752
		HBufC8* des = HBufC8::NewLC(aSource.Length());
		des->Des().Copy(aSource);

		TInt state = CCnvCharacterSetConverter::KStateDefault;

		//defect fix for Inc021752
		User::LeaveIfError(iConverter->ConvertToUnicode(aSink, *des, state));
		CleanupStack::PopAndDestroy(des);
		}
	else
		{
		aSink.Copy(aSource);
		}
	}

CWapCharsetConverter::~CWapCharsetConverter()
	{
	delete iConverter;
	delete iAvailableCharsets;
	}
