// Copyright (c) 2003-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:
//
/**
@file ced.cpp
@internalComponent
*/
#include <e32base.h>
#include <e32cons.h>
#include <e32std.h>
#include <f32file.h>
#include <bacline.h>
#include "dbdef.h"
#include "filedump.h"
#include "input.h"
#include "database.h"
#include "CXMLFile.h"
#include "CXMLContentHandler.h"
#include "CDBSTD.H"
#include <centralrepository.h>
/** max length of path/filename/column/table name */
#define MAX_BUFFER_LEN 256
/** max length of path/filename/column/table name */
#define MAX_ATTRIB_LEN 32
/** max length of arg list to program */
#define MAX_ARG_LEN (MAX_BUFFER_LEN * 3)
/** Application name */
#define APPLICATIONNAME _L("CommsDat Configuration Utility")
/** Version Info */
#define CEDUNVERSIONED _L("CED deliberately un-versioned") /** refer DEF092743 */
#ifdef __TOOLS2__
_LIT(CFG_TARGET, "ced.cfg");
_LIT(XML_TARGET, "ced.xml");
_LIT(LOG_TARGET, "ced.log");
_LIT(KMeshPrefaceFile, "meshpreface1.cfg");
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
#ifndef SYMBIAN_COMMSDAT_USE_INT_RECORD_LINKS
_LIT(SUPPORTED_OS, "95");
#else
_LIT(SUPPORTED_OS, "");
#endif
#else
#ifndef SYMBIAN_COMMSDAT_USE_INT_RECORD_LINKS
_LIT(SUPPORTED_OS, "94");
#else
_LIT(SUPPORTED_OS, "93");
#endif
#endif
#else
_LIT(CFG_TARGET, "c:\\ced.cfg");
_LIT(XML_TARGET, "c:\\ced.xml");
_LIT(LOG_TARGET, "c:\\ced.log");
_LIT(KMeshPrefaceFile, "z:\\system\\data\\meshpreface1.cfg");
_LIT(DEFAULT_SESSION_PATH, "c:\\");
#endif
// GLOBALS
/** Logging */
CFileDump* gMsg;
/** Database access */
DBAccess* gDB;
/** .ini file parsing */
CfgFile gCfg;
/** XML file parsing */
XMLFile* gXML;
/** Console accessor */
LOCAL_D CConsoleBase* gConsole;
/** Passed in arg list */
HBufC* gArgumentLine;
/** Flag to indicate a successful run */
TBool gProcessingSuccessful = ETrue;
/** Flag to indicate whether the '-V' arg was passed in */
TBool gValidityChecking = EFalse;
/** flag to indicate whether the execution format is .dll or .exe*/
TBool gIsExeDLL = EFalse;
/** flag to indicate whether the configuration file is in XML format */
TBool gIsXML = ETrue;
#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS
TBool gDeprecatedFields = EFalse;
#endif
//SYMBIAN_NETWORKING_3GPPDEFAULTQOS
// PROTOTYPES
TInt ParseCommandLineL(TInt &aDebugOn, TBool &aOverWrite, TBool &aForceXMLProcessing, TDes &aIn, TDes &aOut, TDes &aInPref);
TInt ParseArgument(TInt &aDebugOn, TBool &aOverWrite, TBool &aForceXMLProcessing, TDes &aIn, TDes &aOut);
TInt DoProcessL(TBool aIsCfg);
void DoDeleteL();
TInt DoCfgTemplateL(TDesC &aTable, const TInt &aIndex);
TInt DoCfgInsertsL(TDesC &aTable, const TInt &aIndex);
TInt DoXMLTemplateL(const TInt &aIndex);
TInt DoXMLInsertsL(const TInt &aIndex);
TInt SetColumnDetailsL(TInt aIndex, TInt aRecordCount);
TInt SetXMLColumnDetailsL(TInt aEntryIndex, TInt aIndex, TInt aRecCount);
void DisplayMessage(TPtrC aMessage, TInt aJustTheMessage = EFalse);
void HelpDump();
void MainL();
LOCAL_C void doMainL();
TInt DoProcessL(TBool aIsCfg)
/** Store the information provided in the configuration file to CommDB
@param aIsCfg Whether the file to be parsed is an older style .cfg rather than .xml
@return TInt refer only called functions
@leave refer only called functions and dependant components
*/
{
TRAPD(ret, gDB->InitCommsdatL());
// connect to DB manager
if (ret==KErrNone)
{
TVersion version = gDB->Version();
gMsg->Msg(_L("Database Version Maj %d Min %d Build %d"), version.iMajor, version.iMinor, version.iBuild);
gMsg->Dbg(_L(""));
gMsg->Dbg(_L("Session started"));
// loop through tables
TInt i = 0;
TInt j = 0;
TBuf<MAX_BUFFER_LEN> table = tableArray[i];
TBuf<MAX_BUFFER_LEN> tempColumn;
TBool changed;
while (table.Compare(TPtrC(NO_MORE_RECORDS)) != 0)
{
gMsg->Msg(_L(" "));
gMsg->Msg(_L("%S Table"), &table);
// get a count of editable columns
j = 0;
tempColumn = ColumnArray[i][j];
while(tempColumn.Compare(TPtrC(NO_MORE_RECORDS)) != 0)
{
j++;
tempColumn = ColumnArray[i][j];
}
gMsg->Dbg(_L("(%d editable fields in table)"), j);
TBool commitIndividualRecords = (table.CompareC(_L("ConnectionPreferences")) == 0);
if(commitIndividualRecords)
{
// Commit any current changes
TInt ret = gDB->CommitTransaction();
if(ret != KErrNone)
{
gMsg->Msg(_L("ERROR: CommitTransaction returned err [%d]"), ret);
if (gValidityChecking)
{
gProcessingSuccessful = EFalse;
}
}
}
else
{
gDB->MaybeBeginTransactionL();
}
gDB->SetCommitIndividualRecords(commitIndividualRecords);
changed = EFalse;
//Create a recordset for the table
ret = KErrNone;
if(!commitIndividualRecords)
{
TRAP(ret, gDB->CreateOrInsertRecordL(DBAccess::ECreateNew,elementIdArray[i], 0));
}
if(ret == KErrNone)
{
if (aIsCfg?DoCfgTemplateL(table,i):DoXMLTemplateL(i))
{
gMsg->Msg(_L(" "));
changed = ETrue;
}
if (aIsCfg?DoCfgInsertsL(table, i):DoXMLInsertsL(i))
{
gMsg->Msg(_L(" "));
changed = ETrue;
}
if (changed)
{
TInt commitErr = gDB->CommitChanges();
if (commitErr == KErrNone)
{
gMsg->Msg(_L("Insert successful"));
}
else
{
gMsg->Msg(_L("Insert failed [%d ]"), commitErr);
if (gValidityChecking)
{
gProcessingSuccessful = EFalse;
}
}
}
else
{
gMsg->Dbg(_L("Nothing to process"));
}
if(gDB->CommitIndividualRecords())
{
ret = gDB->CommitChanges();
}
gDB->CloseTable();
}
else
{
gMsg->Dbg(_L("(Creating Record set Failed [%d ])"), ret);
}
i++;
table = tableArray[i];
}
ret = gDB->CommitTransaction();
gDB->Close();
}
else
{
gMsg->Dbg(_L("(Could not connect to Commsdat [%d ])"), ret);
}
return ret;
}
void DoDeleteL()
/** Completely erase the communications database, not used when the append flag set
@return void
@leave refer only called functions and dependant components
*/
{
gMsg->Msg(_L("The old database will be replaced ") );
// Get a session with the central repository
const TUid KCDCommsRepositoryId = { 0xCCCCCC00 };
CRepository* storage = NULL;
TRAPD(err, storage = CRepository::NewL(KCDCommsRepositoryId));
if (KErrNone != err)
{
gMsg->Msg(_L("Failed to create Central Repository with ID : %x (error %d)"), KCDCommsRepositoryId, err);
_LIT(KCEDPanic, "CED");
User::Panic(KCEDPanic, KErrNotFound);
}
CleanupStack::PushL(storage);
// open transaction - if can't do this then fail.
User::LeaveIfError(storage->StartTransaction(CRepository::EReadWriteTransaction));
// Find everything in the database
RArray<TUint32> ids;
CleanupClosePushL(ids);
err = storage->FindL(0, 0, ids);
if(err != KErrNotFound)
{
User::LeaveIfError(err);
}
// delete everything in the database
if (ids.Count())
{
for ( TInt i = ids.Count()-1; i >=0 ; i--)
{
if( i == ids.Count()-1 || i>=10000 && i%10000==0 || i<10000 && i>= 1000 && i%1000==0 ||
i<1000 && i>=100 && i%100==0 || i<100 && i>=10 && i%10==0 || i<10)
{
gMsg->Msg(_L("%d"),i);
}
User::LeaveIfError(storage->Delete(ids[i]));
}
}
TUint32 aErrorId;
err = storage->CommitTransaction(aErrorId);
CleanupStack::PopAndDestroy(2);
if (err != KErrNone)
{
gMsg->Msg(_L("Central Repository CommitTransaction returned err [%d]"), err);
}
User::LeaveIfError(err);
}
void MainL()
/** Central processing unit of CED
@return void
@leave refer only called functions and dependant components
*/
{
TInt bDebugOn = EFalse;
TBool bOverWrite = EFalse;
TBool bForceXMLProcessing = EFalse;
TBuf<MAX_BUFFER_LEN> fIn;
TBuf<MAX_BUFFER_LEN> fOut;
TBuf<MAX_BUFFER_LEN> fInPref;
RFs fsSession; // file system session
// connect to file system
User::LeaveIfError(fsSession.Connect());
CleanupClosePushL(fsSession);
// check command line
TInt valid;
if (gIsExeDLL == EFalse)
{
// exe's get arguments from the command line
valid = ParseCommandLineL(bDebugOn, bOverWrite, bForceXMLProcessing, fIn, fOut, fInPref);
}
else
{
// exedll'd get the parameters passed in
valid = ParseArgument(bDebugOn, bOverWrite, bForceXMLProcessing, fIn, fOut);
}
if (valid)
{
// Get the type of the input file i.e. whether it is
// an XML file or a CFG file
(fIn.FindF(_L(".XML")) != KErrNotFound)?gIsXML = ETrue:gIsXML = EFalse;
// display title
gConsole->Printf(_L("------------------------------------------------------------\n"));
gConsole->Printf(APPLICATIONNAME);
gConsole->Printf(_L("\n------------------------------------------------------------\n\n"));
gConsole->Printf(_L("CED is now processing the configuration file from [%S], \n"), &fIn);
if ( bOverWrite ) gConsole->Printf(_L("The old database will be replaced \n") );
if ( gIsXML )
{
gConsole->Printf(_L("The config file is in XML format \n") );
if ( bForceXMLProcessing )
{
gConsole->Printf(_L("Invalid table entry links will be allowed \n") );
}
else
{
gConsole->Printf(_L("Invalid table entry links will not be allowed \n") );
}
}
else
{
gConsole->Printf(_L("The config file is in CFG format \n") );
}
// initialise output log file
#ifndef __TOOLS2__
// Set up the session path for WINSCW / ARMv5 incase the log file name has no path.
fsSession.SetSessionPath( DEFAULT_SESSION_PATH );
#endif
gMsg = CFileDump::NewL(fsSession, fOut, TPtrC(APPLICATIONNAME),
TPtrC(CEDUNVERSIONED), bDebugOn, gConsole, EFalse);
CleanupStack::PushL(gMsg);
if (!gMsg->IsInitialised())
{
gConsole->Printf(_L("Failed to open the output log file [%S]\n"), &fOut);
}
gMsg->Msg(_L(" "));
gMsg->Msg(_L("===================================================="));
gMsg->Msg(APPLICATIONNAME);
gMsg->Msg(_L("===================================================="));
gMsg->Msg(_L(" "));
gMsg->Msg(_L("Processing configuration from [%S]"), &fIn);
gIsXML?gMsg->Msg(_L("The config file is in XML format ")):gMsg->Msg(_L("The config file is in CFG format ") );
if(gProcessingSuccessful)
{
gDB = new (ELeave) DBAccess(gIsXML);
CleanupStack::PushL(gDB);
gDB->CheckElementValidity(gValidityChecking);
//If the settings are not ovewritten we are appending
//This will take care of commdb ids
gDB->SetInAppendMode(!bOverWrite);
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
TBool isMeshCompatible(EFalse);
if (bOverWrite)
//The database has to be re-built...
{
CInputFileParser* fileParser = CInputFileParser::FactoryLC(gIsXML, fIn, gMsg);
TRAPD(leaveVal, isMeshCompatible = fileParser->IsMeshCompatibleL());
CleanupStack::PopAndDestroy(fileParser);
if (leaveVal == KErrNone)
{
if (!isMeshCompatible)
{
gMsg->Msg(_L("MESHINFO: Configuration file [%S] is not mesh-compatible, inserting default meshtables"), &fIn);
// Insert the new mesh related tables/records into the database.
// The preface is a .cfg file, whatever the type of the original input file.
//
if (gCfg.OpenConfigFile(fInPref))
{
if (bOverWrite)
{
DoDeleteL();
}
/**
create a link resolver object which resolves all of the
link by tag linking (Link.TableName.Id) to link by recordId
(TableName.RecordId).
This is important because there can be circular referencing
between tables and if these tables contain link by tag refencing
to each other commsDat doesn't allow to commit those tables...
*/
//this object will resolve the linkByTag linking to simple linkByRecId format
LinkByTagResolver* resolver = LinkByTagResolver::NewLC(&gCfg, gMsg);
//set the resolver object to the gDB object
gDB->SetLinkByTagResolver(resolver);
//Set the iIsXML field to false as we are processing now a cfg file...
gDB->CfgXmlSetting() = EFalse;
//The MeshPreface file will be processed first. This is important to know since here
//we don't want to do any mappings...
gDB->SetMeshProcessing(ETrue);
DoProcessL(ETrue);
//if originally xml processing was set then set it back now...
gDB->CfgXmlSetting() = gIsXML;
//remove the resolver object form the gDB because it's not needed anymore
gDB->RemoveLinkByTagResolver();
CleanupStack::PopAndDestroy(resolver);
resolver = NULL;
gCfg.CloseConfigFile();
if (!gValidityChecking)
{
gProcessingSuccessful = ETrue;
}
}
else
{
gMsg->Error(_L("MESHERR: Configuration file [%S] could not be opened"), &fInPref);
gProcessingSuccessful = EFalse;
}
}
else
{
gMsg->Msg(_L("MESHINFO: Configuration file [%S] is mesh-compatible"), &fIn);
}
}
else
{
gMsg->Error(_L("MESHERR: Configuration file [%S], processing failed, reason=<%d>"), &fIn, leaveVal);
gProcessingSuccessful = EFalse;
}
}
else
{
gMsg->Msg(_L("Appending data to the DB - no need to use the meshpreface config file"));
}
if (gProcessingSuccessful)
{
#endif
// Process the XML configuration file
if (gIsXML)
{
// Create the XML database
CXMLDatabase* xmlDb = CXMLDatabase::NewL();
CleanupStack::PushL(xmlDb);
gXML = new (ELeave) XMLFile;
CleanupStack::PushL(gXML);
if (gXML->OpenConfigFile(fsSession,fIn,xmlDb,bForceXMLProcessing, !bOverWrite))
{
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
if (isMeshCompatible)
{
#endif
if (bOverWrite)
{
DoDeleteL();
}
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
}
if (isMeshCompatible)
{
gDB->SetMeshProcessing(ETrue);
}
else
#endif
{
gDB->SetMeshProcessing(EFalse);
}
TRAPD(ret, DoProcessL(EFalse));
gXML->CloseConfigFile();
if (gValidityChecking && ret != KErrNone)
{
gProcessingSuccessful = EFalse;
}
}
else
{
gMsg->Msg(_L("ERR: A problem was encountered while processing the configuration file [%S]"), &fIn);
gProcessingSuccessful = EFalse;
}
// Cleanup
CleanupStack::PopAndDestroy(gXML);
CleanupStack::PopAndDestroy(xmlDb);
gXML=NULL;
xmlDb=NULL;
}
else
{
if (gCfg.OpenConfigFile(fIn))
{
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
if (isMeshCompatible)
{
#endif
if (bOverWrite)
{
DoDeleteL();
}
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
}
/**
create a link resolver object which resolves all of the
link by tag linking (Link.TableName.Id) to link by recordId
(TableName.RecordId).
This is important because there can be circular referencing
between tables and if these tables contain link by tag refencing
to each other commsDat doesn't allow to commit those tables...
*/
LinkByTagResolver* resolver = LinkByTagResolver::NewLC(&gCfg, gMsg);
if (isMeshCompatible)
{
//our config file is a mesh compatible one so we can use the latestVersion in the DBSession
gDB->SetMeshProcessing(ETrue);
}
else
{
//our config file is not a mesh compatible one so we can should the version 1_1 in the
//DBSession
gDB->SetMeshProcessing(EFalse);
}
gDB->SetLinkByTagResolver(resolver);
#endif
TRAPD(ret, DoProcessL(ETrue));
gCfg.CloseConfigFile();
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
gDB->RemoveLinkByTagResolver();
CleanupStack::PopAndDestroy(resolver);
resolver = NULL;
#endif
if (gValidityChecking && ret != KErrNone)
{
gProcessingSuccessful = EFalse;
}
}
else
{
gMsg->Msg(_L("ERR: Configuration file [%S] could not be opened"), &fIn);
gProcessingSuccessful = EFalse;
}
}
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
}
#endif
CleanupStack::PopAndDestroy(gDB);
gDB=NULL;
}
gMsg->Dbg(_L(""));
gMsg->Dbg(_L("Session finished"));
gMsg->Dbg(_L(""));
gMsg->Msg(_L("==================="));
#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS
if (gDeprecatedFields)
{
gMsg->Msg(_L("WARNING: USE OF DEPRECATED FIELDS"));
}
#endif
//SYMBIAN_NETWORKING_3GPPDEFAULTQOS
// write our processing indicater to the log file
gProcessingSuccessful?gMsg->Msg(_L("SUCCESS")):gMsg->Msg(_L("ERROR"));
CleanupStack::PopAndDestroy(gMsg);
}
CleanupStack::PopAndDestroy(&fsSession);
}
LOCAL_C void doMainL()
{
// allocate a gConsole
gConsole = Console::NewL(APPLICATIONNAME, TSize(KConsFullScreen, KConsFullScreen));
CleanupStack::PushL(gConsole);
// call main routine
MainL();
CleanupStack::PopAndDestroy(gConsole);
}
TInt E32Main()
{
__UHEAP_MARK;
// set up trap cleanup framework
CTrapCleanup* theCleanup = CTrapCleanup::New();
// call main routine and trap any exceptions
TRAPD(ret,doMainL());
if(ret != KErrNone && gValidityChecking)
{
gProcessingSuccessful = EFalse;
}
// clean up when finished
delete theCleanup;
__UHEAP_MARKEND;
// Convert the boolean idea of "success" into the customary process idea of errorlevel, where zero
// is success and anything else designates particular kinds of failure. Specific failure reasons aren't
// provided, so the caller should only look for process exit != 0 to mean failure, and then examine the
// log to see what failed.
return !gProcessingSuccessful;
}
TInt ParseCommandLineL(TBool &aDebugOn, TBool &aOverWrite, TBool &aForceXMLProcessing, TDes &aIn, TDes &aOut, TDes &aInPref)
/** Parse the command line for any overriding settings from exe command line
@param bDebugOn Wether to output debug messages to the log file using CFileDump::Dbg(TPtrC text, ...)
@param bOverWrite Determines whether to append to or erase any existing databases
@param bForceXMLProcessing Determines if invalid table entry links will be allowed
@param fIn Path and filename of the configuration database file
@param fOut Filename of the file to send logging too
@return ETrue if Successful else EFalse
*/
{
TInt valid = EFalse;
CCommandLineArguments *pCmd;
pCmd = CCommandLineArguments::NewL();
CleanupStack::PushL(pCmd);
// set defaults
aIn = XML_TARGET;
aOut = LOG_TARGET;
aInPref = KMeshPrefaceFile;
// Flags for encountering the specification
// of an input and an output file
TBool bInFound = EFalse;
TBool bOutFound = EFalse;
TBool bDatabaseSpecified = EFalse;
//By default delete old database
aOverWrite = ETrue;
if (pCmd)
{
TBuf<MAX_ARG_LEN> arg;
// check all arguments for switches
TInt i = 0;
while( ++i < pCmd->Count() )
{
arg = pCmd->Arg(i);
arg.UpperCase();
// CED will report all the failures on the end, unlike success in all the cases except missing cfg file
// Switch introduced because of high impact on test results and to avoid BC break
if ( arg.FindF(_L("-V")) != KErrNotFound )
{
gValidityChecking = ETrue;
continue;
}
//Display help
if ( arg.FindF(_L("-H")) != KErrNotFound )
{
HelpDump();
CleanupStack::Pop(pCmd);
delete pCmd;
return valid;
}
// Append database switch
if ( arg.FindF(_L("-A")) != KErrNotFound )
{
aOverWrite = EFalse;
continue;
}
// Debug switch
if ( arg.FindF(_L("-D")) != KErrNotFound )
{
aDebugOn = ETrue;
continue;
}
// Debug switch
if ( arg.FindF(_L("-M")) != KErrNotFound )
{
aInPref = pCmd->Arg(++i);
continue;
}
// Presence of invalid table entry links
// will not cause an error
if ( arg.FindF(_L("-F")) != KErrNotFound )
{
aForceXMLProcessing = ETrue;
continue;
}
// Specification of an input file
if ( arg.FindF(_L("-I")) != KErrNotFound )
{
if( i != pCmd->Count()-1 )
{
aIn = pCmd->Arg(++i);
bInFound = ETrue;
continue;
}
else
{
gConsole->Printf(_L("Argument missing after '-i' switch\n"));
#ifndef __TOOLS2__
gConsole->Printf(_L("\nPress any key to finish"));
gConsole->Getch();
#endif
CleanupStack::Pop(pCmd);
delete pCmd;
return valid;
}
}
// Specification of an output file
if ( arg.FindF(_L("-O")) != KErrNotFound )
{
if( i != pCmd->Count()-1 )
{
aOut = pCmd->Arg(++i);
bOutFound = ETrue;
continue;
}
else
gConsole->Printf(_L("Argument missing after '-o' switch\n"));
#ifndef __TOOLS2__
gConsole->Printf(_L("\nPress any key to finish"));
gConsole->Getch();
#endif
CleanupStack::Pop(pCmd);
delete pCmd;
return valid;
}
#ifdef __TOOLS2__
// Specification of the database binary version
// This must be specified on the tools2 platform.
TBuf<16> databaseVersion;
if ( arg.FindF(_L("-B")) != KErrNotFound )
{
if( i != pCmd->Count()-1 )
{
databaseVersion = pCmd->Arg(++i);
if(databaseVersion.Compare(SUPPORTED_OS) == 0)
{
bDatabaseSpecified = ETrue;
continue;
}
else
{
gConsole->Printf(_L("O/S version '%S' is not supported by this version of CED"), &databaseVersion);
CleanupStack::Pop(pCmd);
delete pCmd;
return valid;
}
}
else
{
gConsole->Printf(_L("Argument missing after '-b' switch"));
CleanupStack::Pop(pCmd);
delete pCmd;
return valid;
}
}
#endif
// No flag is supplied: first file encountered is the input
// file and the following one is the output file
if ( !bInFound )
{
aIn = pCmd->Arg(i);
bInFound = ETrue;
continue;
}
if ( !bOutFound )
{
aOut = pCmd->Arg(i);
bOutFound = ETrue;
continue;
}
}
if (aIn.Length() > 0)
valid = ETrue;
//If here then no prefered config file has been specified.
//Find default input file
if ( !bInFound )
{
RFs fs;
fs.Connect();
CleanupClosePushL(fs);
TUint dummy;
if(fs.Att(XML_TARGET,dummy)==KErrNone)
{
aIn = XML_TARGET;
}
else if(fs.Att(CFG_TARGET,dummy)==KErrNone)
{
aIn = CFG_TARGET;
}
else
{
gConsole->Printf(_L("No configuration files found please specify a .cfg or .xml file\n"));
#ifndef __TOOLS2__
gConsole->Printf(_L("\nPress any key to finish"));
gConsole->Getch();
#endif
valid=EFalse;
}
CleanupStack::PopAndDestroy(&fs);
}
#ifdef __TOOLS2__
if ( !bDatabaseSpecified )
{
gConsole->Printf(_L("Must specify the '-b' switch\n"));
valid=EFalse;
}
#endif
CleanupStack::Pop(pCmd);
delete pCmd;
}
return valid;
}
void HelpDump()
/**
Prints basic help information to the emulator window including command switches
*/
{
gConsole->Printf(_L("Creates/Updates a Comms Database using an input file"));
gConsole->Printf(_L("\n\nCED [-a] [-d] [-f] [-i [path]filename] [-o [path]filename]"));
gConsole->Printf(_L("\n\n-a\tAppends the data read from the input file to the existing Comms Database."));
gConsole->Printf(_L("\n-d\tSwitches debug mode on giving more data in the log file."));
gConsole->Printf(_L("\n-f\tAllows invalid data entries. Primarily used for testing."));
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
gConsole->Printf(_L("\n-m Specifies the default mesh configuration file to CED. Defaults to reading '%S'."), &KMeshPrefaceFile);
#endif
gConsole->Printf(_L("\n-v Enables validation of the configuration data while writing to the database."));
gConsole->Printf(_L("\n-i Specifies an input file to CED. Must be either *.xml or *.cfg. Defaults to reading '%S' or '%S'."), &CFG_TARGET, &XML_TARGET);
gConsole->Printf(_L("\n-o Specifies an output file for CED to log to. Defaults to '%S'."), &LOG_TARGET);
#ifdef __TOOLS2__
gConsole->Printf(_L("\n-b Specifies the binary output should be compatible with this Symbian OS version.\n"));
#endif
#ifndef __TOOLS2__
gConsole->Printf(_L("\nPress any key to finish"));
gConsole->Getch();
#endif
}
TInt ParseArgument(TBool &aDebugOn, TBool &aOverWrite, TBool &aForceXMLProcessing, TDes &aIn, TDes &aOut)
/** Parse the command line for any overriding settings from DLL call
@param bDebugOn Wether to output debug messages to the log file using CFileDump::Dbg(TPtrC text, ...)
@param bOverWrite Determines whether to append to or erase any existing databases
@param bForceXMLProcessing Determines if invalid table entry links will be allowed
@param fIn Path and filename of the configuration database file
@param fOut Filename of the file to send logging too
@return ETrue if Successful else EFalse
*/
{
// use Tlex to decode the cmd line
TLex lex(gArgumentLine->Des());
// By default delete old database
aOverWrite = ETrue;
// get the input file
aIn=lex.NextToken();
if ( aIn.Length() == 0 )
aIn = XML_TARGET;
// get the output file
aOut = lex.NextToken();
if ( aOut.Length() == 0 ) // if valid potential
aOut = LOG_TARGET;
// get the debug switch parameters
if ( gArgumentLine->FindF(_L("-D")) != KErrNotFound )
aDebugOn = ETrue;
if ( gArgumentLine->FindF(_L("-O")) != KErrNotFound )
aDebugOn = ETrue;
// append switch
if ( gArgumentLine->FindF(_L("-A")) != KErrNotFound )
aOverWrite = EFalse;
// force processing of XML file even in the
// presence of invalid table entry links
if ( gArgumentLine->FindF(_L("-F")) != KErrNotFound )
aForceXMLProcessing = ETrue;
delete gArgumentLine;
return ETrue;
}
LOCAL_C TInt ProcessCfgDataL(TDesC &aTable,const TInt &aIndex)
/** Process old style .cfg database file
@param aTable Name of the entry being processed
@param aIndex Counted table number being processed
@return ETrue if Successful else EFalse
*/
{
TInt recordsInserted(0);
TInt fatalErr(KErrNone);
TBool firstRec(ETrue);
TInt valid(KErrNotReady);
_LIT(KConnectionPrefTableName, "ConnectionPreferences");
while(fatalErr == KErrNone && (firstRec || gCfg.StepToNextBlock()))
{
if (!firstRec)
{
gMsg->Msg(_L(" ")); // blank line between records
}
if(gDB->CommitIndividualRecords())
{
gDB->CreateOrInsertRecordL(firstRec? DBAccess::ECreateNew: DBAccess::ECreateInsert,elementIdArray[aIndex], 0);
}
firstRec = EFalse;
TInt value = recordsInserted + 1;
TPtrC idText;
_LIT(KCommDbIDTag, "COMMDB_ID ");
valid = gCfg.GetSetting(KCommDbIDTag, idText);
if (valid == KErrNone)
{
TLex lex(idText);
if(lex.Val(value) != KErrNone)
{
gMsg->Dbg(_L("Missing COMMDB_ID - defaulting to record count"));
}
}
gDB->CreateOrInsertRecordL(DBAccess::EInsert, 0, value);
// find out how many fields we are expecting in this insert
TPtrC result = NO_MORE_RECORDS;
TInt iValue;
valid = gCfg.GetSetting(FIELD_COUNT, result);
if (valid == KErrNone)
{
TLex iResult = result;
iValue = 0;
if (iResult.Val(iValue) == KErrNone)
gDB->SetFieldCount(iValue);
}
//Write column info
TInt err = SetColumnDetailsL(aIndex, recordsInserted + 1);
iValue = gDB->GetFieldCount(); //If Recordname was not supplied, SetColumnDetailsL fn would have added the misisng name..so refresh he actual field count
if(err == KErrNone)
{
if(gDB->GetActualFieldCount() != iValue)
{
gMsg->Msg(_L(" ERR Table %S Expected [%d] values, read [%d].Field count mismatch!"), &aTable, iValue, gDB->GetActualFieldCount());
gDB->RemoveCurrentRecord();
if (gValidityChecking)
{
gProcessingSuccessful = EFalse;
}
continue; // it's not fatal
}
if(aTable.Compare(KConnectionPrefTableName) == 0)
{
CMDBRecordBase* dontDelete = gDB->GetCurrentRecord();
if(!gDB->IsConnectionPrefValid(*(static_cast<CCDConnectionPrefsRecord*>(dontDelete))))
{
fatalErr = KErrArgument; // or should we continue?
}
}
if(gDB->CommitIndividualRecords())
{
err = gDB->CommitChanges();
}
if(err != KErrNone)
{
gMsg->Msg(_L("Error %d inserting record #%d to %S"), err, recordsInserted + 1, &aTable);
if (gValidityChecking)
{
gProcessingSuccessful = EFalse;
}
}
else
{
recordsInserted++;
}
}
else if(err != KErrCancel) //to ignore cancels called by ced itself, used to process unused entries produced by older ceddumpers
{
gMsg->Msg(_L("Error %d inserting record #%d to %S"), err, recordsInserted + 1, &aTable);
if (gValidityChecking)
{
gProcessingSuccessful = EFalse;
}
gDB->RemoveRecord(recordsInserted);
//fatalErr = err;
}
}
return ((fatalErr == KErrNone)?recordsInserted:fatalErr);
}
TInt DoCfgTemplateL(TDesC &aTable, const TInt &aIndex)
/**
Applying the templates
@param table A reference to a descriptor containing the name of a table
@param index Index in the Table
@return ETrue if Successful else EFalse
*/
{
// look for template and load it
if (!gCfg.OpenTemplateBlock(aTable))
return EFalse;
DisplayMessage(_L("Processing template"), ETrue);
gDB->RecordIsTemplate(ETrue);
TInt templateRecordsInserted = ProcessCfgDataL(aTable,aIndex);
if (templateRecordsInserted > 0)
{
gMsg->Msg(_L(" "));
gMsg->Msg(_L("[%d] Template record(s) successfully inserted"), templateRecordsInserted);
}
else
{
gMsg->Msg(_L(" "));
gMsg->Msg(_L("Insert record failed Err:[%d]"), templateRecordsInserted);
}
return templateRecordsInserted;
}
TInt DoCfgInsertsL(TDesC &aTable, const TInt &aIndex)
/**
Runs through all the steps involved in applying an insert to a particular table.
@param table A reference to a descriptor containing the name of a table
@param index Index in the Table
@return ETrue if Successful else EFalse
*/
{
// look for any inserts and load the first one
if (!gCfg.OpenAddBlock(aTable))
return EFalse;
DisplayMessage(_L("Processing inserts"), ETrue);
gDB->RecordIsTemplate(EFalse);
TInt recordsInserted = ProcessCfgDataL(aTable,aIndex);
if (recordsInserted >= 0)
{
gMsg->Msg(_L(" "));
gMsg->Msg(_L("[%d] record(s) successfully inserted"), recordsInserted);
}
else
{
gMsg->Msg(_L(" "));
gMsg->Msg(_L("Insert record failed Err:[%d]"), recordsInserted);
}
return recordsInserted;
}
#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS
/**
Loops through the table of deprecated columns/parameters and gives an information
to the user question column/parameter is deprecated.
@param aIndex Index in the elementIdArray Table
@param aColumnName Name of the questioned column/parameter
*/
void VerifyDeprecatedFields(TInt aIndex, TPtrC& aColumnName)
{
TBuf<MAX_BUFFER_LEN> tempColumn;
TInt i = 0;
if (elementIdArray[aIndex] == KCDTIdOutgoingGprsRecord
|| elementIdArray[aIndex] == KCDTIdIncomingGprsRecord )
{
tempColumn = DeprecParamArray[i];
while(tempColumn.Compare(TPtrC(NO_MORE_RECORDS)) != 0)
{
if (aColumnName.Compare(tempColumn) == 0 )
{
gMsg->Msg(_L(" Warning - Use of deprecated parameter [%S]"), &aColumnName);
gDeprecatedFields = ETrue;
}
tempColumn = DeprecParamArray[++i];
}
}
}
#endif
// SYMBIAN_NETWORKING_3GPPDEFAULTQOS
TBool IsGprsGatewayField(TInt aIndex, const TPtrC& aColumnName)
/**
Determine if a field being processed is the IpGateway field in OutgoingGPRS table
@param aIndex index into elementIdArray[] for identifying table
@param aColumnName descriptor identifying the field
*/
{
return (elementIdArray[aIndex] == KCDTIdOutgoingGprsRecord && aColumnName.Compare(TPtrC(GPRS_IP_GATEWAY)) == 0);
}
TInt SetupIpGatewayFieldDefaultL(TInt aIndex)
/**
Setup a safe default value for the IpGateway field in OutgoingGPRS tables. If a value has not
been specified in the CFG or XML file, then it would ordinarily default to 0.0.0.0. However,
this value will mean that the TCP/IP stack will not setup a default route. Consequently,
we must setup a safe default of 0.0.0.1.
@param aIndex index into elementIdArray[] for identifying the table
*/
{
if (elementIdArray[aIndex] == KCDTIdOutgoingGprsRecord) // only for OutgoingGPRS table records !
{
// Only setup IpGateway field if it is not already present in the OutgoingGPRS template record.
if (!gDB->TemplateFieldPresentL(KCDTIdOutgoingGprsRecord | KCDTIdWCDMAIPGateway))
{
TPtrC setting;
TPtrC column;
_LIT(KGprsIpGateway, "0.0.0.1");
setting.Set(KGprsIpGateway());
column.Set(TPtrC(GPRS_IP_GATEWAY));
gMsg->Msg(_L(" NOTE [%S] set to default value of %S"), &column, &setting);
TInt ret = gDB->SetColAndAttribL(column, setting);
gDB->SetFieldCount(gDB->GetFieldCount() + 1); //field count increment by one because we added the gateway field
return ret;
}
}
return KErrNone;
}
void HandleConnPrefWithoutDefaultIap()
/**
Handle special case of ConnPref record without default IAP set (empty db use case)
*/
{
if(gDB->GetCurrentRecord()->TableId() == KCDTIdConnectionPrefsRecord)
{
CCDConnectionPrefsRecord* connPref = static_cast<CCDConnectionPrefsRecord*>(gDB->GetCurrentRecord());
if(!(connPref->iDefaultIAP.ElementId() & KCDChangedFlag))
{
connPref->iDefaultIAP = 0;
}
}
}
TInt SetColumnDetailsL(TInt aIndex, TInt aRecordCount)
/**
Loops through all the columns of a particular table. If any of the columns match the setting
in the log file, it is stored, along with the value to write into this field.
@param aTable A reference to a descriptor containing the name of a table
@param aIndex Index in the Table
@param aRecCnt Index of the Record in the table
@return ETrue if Successful else EFalse
*/
{
static TBuf<MAX_BUFFER_LEN> tempColumn;
TPtrC column;
TPtrC setting;
TInt valid(KErrNone);
TInt i = 0;
tempColumn = ColumnArray[aIndex][i];
TInt fieldValueRead(KErrNone);
TBool gprsGatewayFieldIsSet = EFalse; // whether IpGateway field in OutgoingGPRS table record has been set
// loop through columns of table
while( (valid==KErrNone) && (tempColumn.Compare(TPtrC(NO_MORE_RECORDS)) != 0))
{
// get a column from the config file
gMsg->Dbg(_L(" Looking for [%S]"), &tempColumn);
// set the read value to the column
fieldValueRead = gCfg.GetSetting(tempColumn,setting);
if(fieldValueRead == KErrNone)
{
column.Set(tempColumn);
#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS
VerifyDeprecatedFields(aIndex, column);
#endif
// SYMBIAN_NETWORKING_3GPPDEFAULTQOS
// Determine whether the GPRS IP Gateway field has been set or not
if (IsGprsGatewayField(aIndex, column))
{
gprsGatewayFieldIsSet = ETrue;
}
if( (tempColumn.Compare(TPtrC(COMMDB_NAME)) == 0) &&
(setting.Compare(TPtrC(COMMDB_UNUSED_NAME)) == 0)
)
{
//this record is not valid,,,remove
gDB->RemoveCurrentRecord();
if (gValidityChecking)
{
gProcessingSuccessful = EFalse;
}
return KErrCancel;
}
valid = gDB->SetColAndAttribL(column,setting);
}
// decrement the field count for fields simply left blank
else if(fieldValueRead == KErrArgument)
{
gDB->SetFieldCount(gDB->GetFieldCount() - 1);
}
i++;
tempColumn = ColumnArray[aIndex][i];
}
//if the record is not empty and also has its name field or fieldvalue missing, set a default name, using the
//record id if set, else simply the record count
//Only do this if not entering a Template Record
if(gDB->GetCurrentRecord()->RecordId() != KCDDefaultRecord &&
((!gDB->IsNameSet() && gDB->GetActualFieldCount()) ||
(!gDB->IsNameSet() && KErrArgument)) )
{
_LIT(KNameTemplate, "DefaultRecordName-%d");
TBuf<MAX_BUFFER_LEN> recordName;
TInt recId = gDB->GetCurrentRecord()->RecordId();
recordName.Format(KNameTemplate, recId? recId: aRecordCount);
column.Set(TPtrC(COMMDB_NAME));
setting.Set(TPtrC(recordName));
valid = gDB->SetColAndAttribL(column,setting);
gDB->SetFieldCount(gDB->GetFieldCount() + 1); //field count increment by one because we added the missing name
}
if (valid == KErrNone && !gprsGatewayFieldIsSet)
{
// If required, setup a suitable default value for IpGateway field in OutgoingGPRS table records
valid = SetupIpGatewayFieldDefaultL(aIndex);
}
// Handle special case of ConnPref record without default IAP set (empty db use case)
HandleConnPrefWithoutDefaultIap();
return valid;
}
LOCAL_C TInt ProcessXmlDataL(TBool aIsTemplate,const TInt &aIndex)
/** Runs through all the steps involved in applying an insert to a particular table
(for the XML configuration file)
@param aIsTemplate Wether the entry being processed is a template or add entry
@param aIndex Counted table number being processed
@return Number of successfully inserted records
*/
{
TBuf<MAX_BUFFER_LEN> xmlTableName = xmlTableArray[aIndex];
xmlTableName.Append(_L("Table"));
// look for template
TInt startIndex = gXML->GetStartingIndex(xmlTableName);
TInt lastIndex = gXML->GetLastIndex(xmlTableName);
if(startIndex == -1 || lastIndex == -1)
return EFalse;
if(aIsTemplate)
{
DisplayMessage(_L("Processing template"), ETrue);
gDB->RecordIsTemplate(ETrue);
}
else
{
DisplayMessage(_L("Processing inserts"), ETrue);
gDB->RecordIsTemplate(EFalse);
}
TInt recordsInserted(0);
TInt ret(KErrNone);
for(TInt iEntryIndex = startIndex; iEntryIndex <= lastIndex; iEntryIndex++)
{
if(aIsTemplate)
{
if(gXML->GetOperation(iEntryIndex).Compare(_L("template")) != 0)
{
continue;
}
}
else
{
if(gXML->GetOperation(iEntryIndex).Compare(_L("add")) != 0)
{
continue;
}
}
gMsg->Msg(_L("Record Number: #[%d]"), gXML->GetElementRecordID(iEntryIndex));
if(gDB->CommitIndividualRecords())
{
gDB->CreateOrInsertRecordL(iEntryIndex == startIndex? DBAccess::ECreateNew: DBAccess::ECreateInsert,elementIdArray[aIndex], 0);
}
//!!!!!!!!!!!!!!!!!the record ID of the given xmlDBentry should be read here...
//gDB->CreateOrInsertRecordL(DBAccess::EInsert,0,0);
gDB->CreateOrInsertRecordL(DBAccess::EInsert,0,gXML->GetElementRecordID(iEntryIndex));
// find out how many fields we are expecting in this insert
TInt iValue = gXML->GetEntryNumberParameters(iEntryIndex);
gDB->SetFieldCount(iValue);
//Write column info
ret = SetXMLColumnDetailsL(iEntryIndex,aIndex,iEntryIndex - startIndex + 1);
/*if(ret != KErrNone)
return ret;*/
if(gDB->CommitIndividualRecords())
{
ret = gDB->CommitChanges();
}
if(ret != KErrNone)
{
gMsg->Msg(_L("Error %d inserting record #%d to %S"), ret, iEntryIndex - startIndex + 1, &xmlTableName);
if (gValidityChecking)
{
gProcessingSuccessful = EFalse;
}
gDB->RemoveRecord(gXML->GetElementRecordID(iEntryIndex)-1);
}
else
{
recordsInserted++;
}
}
if (recordsInserted)
{
gMsg->Msg(_L(" "));
gMsg->Msg(_L("[%d] record(s) successfully inserted"), recordsInserted);
}
return recordsInserted;
}
TInt DoXMLInsertsL(const TInt &aIndex)
/**
Runs through all the steps involved in applying an insert to a particular table.
@param index Index in the Table
@return Number of successfully inserted records
*/
{
return (ProcessXmlDataL(EFalse,aIndex));
}
TInt DoXMLTemplateL(const TInt &aIndex)
/**
Applying the templates (for the XML configuration file)
@param index Index in the Table
@return Number of successfully inserted records
*/
{
return (ProcessXmlDataL(ETrue,aIndex));
}
TInt SetXMLColumnDetailsL(TInt aEntryIndex, TInt aIndex, TInt aRecCount)
/** Loops through all the columns of a particular table. If any of the columns match the setting
in the log file, it is stored, along with the value to write into this field.
@param aEntryIndex
@param aIndex
@param aRecCount
@return True if successful else false
*/
{
static TBuf<MAX_BUFFER_LEN> tempColumn;
TPtrC setting;
TPtrC column;
TInt valid(KErrNone);
TInt i = 0;
TBool gprsGatewayFieldIsSet = EFalse; // whether IpGateway field in OutgoingGPRS table record has been set
tempColumn = ColumnArray[aIndex][i];
// loop through columns of table
while( (valid==KErrNone) && tempColumn.Compare(TPtrC(NO_MORE_RECORDS)) != 0)
{
// get a column from the config file
gMsg->Dbg(_L(" Looking for [%S]"), &tempColumn);
if (gXML->GetSetting(aEntryIndex, tempColumn, setting))
{
column.Set(ColumnArray[aIndex][i]);
valid = gDB->SetColAndAttribL(column,setting);
#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS
VerifyDeprecatedFields(aIndex, column);
#endif
// SYMBIAN_NETWORKING_3GPPDEFAULTQOS
// Determine whether the GPRS IP Gateway field has been set or not
if (IsGprsGatewayField(aIndex, column))
{
gprsGatewayFieldIsSet = ETrue;
}
}
i++;
tempColumn = ColumnArray[aIndex][i];
}
//if the record is not empty and also has its name missing, set a default name
//only do this if not processing a template record
if(!gDB->IsNameSet() &&
gDB->GetActualFieldCount() &&
gDB->GetCurrentRecord()->RecordId() != KCDDefaultRecord)
{
_LIT(KNameTemplate, "DefaultRecordName-%d");
TBuf<MAX_BUFFER_LEN> recordName;
recordName.Format(KNameTemplate, aRecCount);
column.Set(TPtrC(COMMDB_NAME));
setting.Set(TPtrC(recordName));
valid = gDB->SetColAndAttribL(column,setting);
gDB->SetFieldCount(gDB->GetFieldCount() + 1); //field count increment by one because we added the missing name
}
if (valid == KErrNone && !gprsGatewayFieldIsSet)
{
// If required, setup a suitable default value for IpGateway field in OutgoingGPRS table records
valid = SetupIpGatewayFieldDefaultL(aIndex);
}
// Handle special case of ConnPref record without default IAP set (empty db use case)
HandleConnPrefWithoutDefaultIap();
return valid;
}
void DisplayMessage(TPtrC aMessage, TInt aJustTheMessage)
/**
Writes a message to the log file, along with any associated error.
@param aMessage Message to be written
@param aJustTheMessage Output only the plain message to the log file
*/
{
if (aJustTheMessage)
{
gMsg->Msg(_L("%S"), &aMessage);
}
else
{
if (gDB->ErrorCode() != KErrAlreadyExists && gDB->ErrorCode() != E_ALREADYEXISTS)
gMsg->Msg(_L(" "));
gMsg->Msg(_L(" "));
if (gDB->ErrorCode())
{
static TBuf<MAX_BUFFER_LEN> errorText;
errorText = gDB->ErrorText();
if (gDB->ErrorCode() == KErrAlreadyExists || gDB->ErrorCode() == E_ALREADYEXISTS)
gMsg->Msg(_L("WARN: %S failed: %S [%d]"), &aMessage, &errorText, gDB->ErrorCode());
else if (gDB->ErrorCode() < 0)
gMsg->Msg(_L("ERR: %S failed: %S [%d]"), &aMessage, &errorText, gDB->ErrorCode());
else
gMsg->Msg(_L("ERR: %S failed: %S"), &aMessage, &errorText);
}
else
{
gMsg->Msg(_L("ERR: %S failed"), &aMessage);
}
// don't fail when the record is there already
if (gDB->ErrorCode() != KErrAlreadyExists && gDB->ErrorCode() != E_ALREADYEXISTS)
{
gMsg->Msg(_L(" "));
gMsg->Msg(_L(" "));
gProcessingSuccessful = EFalse;
}
}
}
#ifndef __TOOLS2__
EXPORT_C TInt NewApplicationL(const TDesC& aText)
/**
entry point used in WINS when ced is build as a exedll
@param Text Command line argument
*/
{
// save the command line info
gArgumentLine=aText.AllocL();
// record that ced is running as a exe dll
gIsExeDLL = ETrue;
// call main
return E32Main();
}
#endif