tripwire-open-source/src/twprint/twprintcmdline.cpp

1035 lines
38 KiB
C++

//
// The developer of the original code and/or files is Tripwire, Inc.
// Portions created by Tripwire, Inc. are copyright (C) 2000-2018 Tripwire,
// Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights
// reserved.
//
// This program is free software. The contents of this file are subject
// to the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version. You may redistribute it and/or modify it
// only in compliance with the GNU General Public License.
//
// This program is distributed in the hope that it will be useful.
// However, this program is distributed AS-IS WITHOUT ANY
// WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
// FOR A PARTICULAR PURPOSE. Please see the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// Nothing in the GNU General Public License or any other license to use
// the code or files shall permit you to use Tripwire's trademarks,
// service marks, or other intellectual property without Tripwire's
// prior written consent.
//
// If you have any questions, please contact Tripwire, Inc. at either
// info@tripwire.org or www.tripwire.org.
//
///////////////////////////////////////////////////////////////////////////////
// twprintcmdline.cpp
//
#include "stdtwprint.h"
#include "twprintcmdline.h"
#include "twprintstrings.h" // strings specific to twprint
#include "twprintcmdline.h" // functions for the cmd line
#include "twprinterrors.h"
#include "core/cmdlineparser.h"
#include "core/errorgeneral.h"
#include "core/errorbucketimpl.h" // for the error table
#include "core/usernotify.h" // for notifying the user of even
#include "core/serializerimpl.h" // cSerializerImpl
#include "core/archive.h" // cArchive and friends
#include "tw/configfile.h"
#include "tw/fcodatabasefile.h" // cFCODatabaseFile
#include "tw/fcoreport.h" // for reports
#include "tw/textdbviewer.h"
#include "tw/textreportviewer.h" // text report viewer
#include "tw/twutil.h"
#include "tw/headerinfo.h"
#include "tw/systeminfo.h"
#include "tw/twerrors.h"
#include "tw/dbdatasource.h"
#include "tw/twstrings.h"
#include "twcrypto/keyfile.h" // cKeyFile -- used for encryption
#include "util/fileutil.h"
#include "fco/fcogenre.h"
#include "fco/genreswitcher.h"
#include "fco/twfactory.h"
#include "fco/fcospeclist.h" // cFCOSpecList
#include "fco/fcopropdisplayer.h"
#include "fco/signature.h"
#include <set>
///////////////////////////////////////////////////////////////////////////////
// Static functions --
///////////////////////////////////////////////////////////////////////////////
static void InitCmdLineCommon(cCmdLineParser& parser);
// A method for initializing the command line parser with arguments that
// are common to all modes of twprint.
//#############################################################################
// cTWPrintCmdLine
//#############################################################################
// this is used to make required condition checking in the Init() functions a little more compact
#define TEST_INIT_REQUIREMENT(t, n) \
if (!t) \
{ \
TCERR << TSS_GetString(cTW, n) << std::endl; \
return false; \
}
// TODO: get Matt to update this with changes he made to tripwire
///////////////////////////////////////////////////////////////////////////////
// InitCmdLineCommon --
// Initialize the cmdlineparser with the arguments that are common
// to all modes. Other parameters must be added in the
// InitCmdLineParser method of the derived mode.
///////////////////////////////////////////////////////////////////////////////
static void InitCmdLineCommon(cCmdLineParser& parser)
{
// help
parser.AddArg(cTWPrintCmdLine::HELP, TSTRING(_T("?")), TSTRING(_T("help")), cCmdLineParser::PARAM_NONE);
// mode
parser.AddArg(cTWPrintCmdLine::MODE, TSTRING(_T("m")), TSTRING(_T("")), cCmdLineParser::PARAM_ONE);
parser.AddArg(
cTWPrintCmdLine::MODE_DBPRINT, TSTRING(_T("")), TSTRING(_T("print-dbfile")), cCmdLineParser::PARAM_NONE);
parser.AddArg(
cTWPrintCmdLine::MODE_REPORTPRINT, TSTRING(_T("")), TSTRING(_T("print-report")), cCmdLineParser::PARAM_NONE);
// reporting
parser.AddArg(cTWPrintCmdLine::VERBOSE, TSTRING(_T("v")), TSTRING(_T("verbose")), cCmdLineParser::PARAM_NONE);
parser.AddArg(cTWPrintCmdLine::SILENT, TSTRING(_T("s")), TSTRING(_T("silent")), cCmdLineParser::PARAM_NONE);
parser.AddArg(cTWPrintCmdLine::SILENT, TSTRING(_T("")), TSTRING(_T("quiet")), cCmdLineParser::PARAM_NONE);
// config file overrides
parser.AddArg(cTWPrintCmdLine::CFG_FILE, TSTRING(_T("c")), TSTRING(_T("cfgfile")), cCmdLineParser::PARAM_ONE);
parser.AddArg(
cTWPrintCmdLine::LOCAL_KEY_FILE, TSTRING(_T("L")), TSTRING(_T("local-keyfile")), cCmdLineParser::PARAM_ONE);
parser.AddArg(
cTWPrintCmdLine::SITE_KEY_FILE, TSTRING(_T("S")), TSTRING(_T("site-keyfile")), cCmdLineParser::PARAM_ONE);
// unattended operation
parser.AddArg(cTWPrintCmdLine::PASSPHRASE, TSTRING(_T("P")), TSTRING(_T("passphrase")), cCmdLineParser::PARAM_ONE);
parser.AddArg(
cTWPrintCmdLine::HEXADECIMAL, TSTRING(_T("h")), TSTRING(_T("hexadecimal")), cCmdLineParser::PARAM_NONE);
// the paramters to the command line ... for now, this will take "many", even though in some
// modes, this is not valid to do...
// NOTE -- print report doesn't take any naked parameters, and neither does print database (we took that
// functionality out) so I changed this to PARAM_NONE.
// NOTE -- We __DO__ take "naked" parameters in print-database mode, contrary to the above comment!!! It is an error
// to add this argument here, in the "common" code between the two modes of twprint. I'm moving the PARAMS arg to
// twprint --print-database's "personal" initialization (below). -DRA 8/9/99
//parser.AddArg(cTWPrintCmdLine::PARAMS, TSTRING(_T("")), TSTRING(_T("")), cCmdLineParser::/*PARAM_NONE*/PARAM_MANY);
// Error for print-report!!!!
parser.AddMutEx(cTWPrintCmdLine::VERBOSE, cTWPrintCmdLine::SILENT);
}
///////////////////////////////////////////////////////////////////////////////
// GetMode -- processes the command line arguments and creates an appropriate
// structure for the selected mode, or NULL if an error occurs
///////////////////////////////////////////////////////////////////////////////
iTWMode* cTWPrintCmdLine::GetMode(int argc, const TCHAR* const* argv)
{
// note -- it is assumed the executable name is the first parameter
if (argc < 2)
{
TCOUT << TSS_GetString(cTWPrint, twprint::STR_TWPRINT_VERSION) << std::endl;
TCOUT << TSS_GetString(cTW, tw::STR_VERSION) << std::endl;
TCOUT << TSS_GetString(cTW, tw::STR_GET_HELP) << std::endl;
return NULL;
}
int mode = MODE;
const TCHAR* pcMode;
if (_tcscmp(argv[1], _T("-m")) == 0)
{
if (argc < 3)
{
TCOUT << TSS_GetString(cTWPrint, twprint::STR_TWPRINT_VERSION) << std::endl;
TCOUT << TSS_GetString(cTW, tw::STR_VERSION) << std::endl;
TCOUT << TSS_GetString(cTW, tw::STR_ERR_NO_MODE) << std::endl;
TCOUT << TSS_GetString(cTW, tw::STR_GET_HELP) << std::endl;
return NULL;
}
pcMode = argv[2];
if (_tcscmp(argv[2], _T("d")) == 0)
mode = MODE_DBPRINT;
else if (_tcscmp(argv[2], _T("r")) == 0)
mode = MODE_REPORTPRINT;
}
else
{
pcMode = argv[1];
if (_tcscmp(argv[1], _T("--print-dbfile")) == 0)
mode = MODE_DBPRINT;
else if (_tcscmp(argv[1], _T("--print-report")) == 0)
mode = MODE_REPORTPRINT;
else if (_tcscmp(argv[1], _T("--version")) == 0)
{
TCOUT << TSS_GetString(cTW, tw::STR_VERSION) << std::endl;
return NULL;
}
else if (_tcscmp(argv[1], _T("--help")) == 0 || _tcscmp(argv[1], _T("-?")) == 0)
mode = MODE_HELP;
}
if (mode == MODE)
{
// unknown mode switch
cDebug d("cTWPrintCmdLine::GetMode");
d.TraceError(_T("Error: Bad mode switch: %s\n"), pcMode);
TCERR << TSS_GetString(cTW, tw::STR_UNKNOWN_MODE_SPECIFIED) << pcMode << std::endl;
TCERR << TSS_GetString(cTW, tw::STR_GET_HELP) << std::endl;
return NULL;
}
iTWMode* pRtn = 0;
switch (mode)
{
case cTWPrintCmdLine::MODE_DBPRINT:
pRtn = new cTWPrintDBMode;
break;
case cTWPrintCmdLine::MODE_REPORTPRINT:
pRtn = new cTWPrintReportMode;
break;
case cTWPrintCmdLine::MODE_HELP:
pRtn = new cTWPrintHelpMode;
break;
default:
ASSERT(false);
}
return pRtn;
}
//#############################################################################
// cTWPrintModeCommon -- contains data common to all modes; all cTWMode*_i will
// derive from this class.
//#############################################################################
class cTWPrintModeCommon
{
public:
int mVerbosity; // must be 0 <= n <= 2
std::string mPassPhrase; // pass phrase for private key
TSTRING mLocalKeyFile;
TSTRING mSiteKeyFile;
TSTRING mConfigFilePath;
cTWPrintModeCommon() : mVerbosity(1)
{
}
cTextReportViewer::ReportingLevel mReportLevel; // The level of reporting to use.
};
///////////////////////////////////////////////////////////////////////////////
// FillOutCommonConfigInfo -- fills out all the common info with config file information
///////////////////////////////////////////////////////////////////////////////
static void FillOutCommonConfigInfo(cTWPrintModeCommon* pModeInfo, const cConfigFile& cf)
{
TSTRING str;
if (cf.Lookup(TSTRING(_T("LOCALKEYFILE")), str))
pModeInfo->mLocalKeyFile = str;
if (cf.Lookup(TSTRING(_T("SITEKEYFILE")), str))
pModeInfo->mSiteKeyFile = str;
//
// turn all of the file names into full paths (they're relative to the exe dir)
//
TSTRING fullPath;
if (iFSServices::GetInstance()->FullPath(fullPath, pModeInfo->mLocalKeyFile, cSystemInfo::GetExeDir()))
pModeInfo->mLocalKeyFile = fullPath;
}
///////////////////////////////////////////////////////////////////////////////
// FillOutCmdLineInfo -- fills out info common to all modes that appears on the
// command line.
///////////////////////////////////////////////////////////////////////////////
static void FillOutCmdLineInfo(cTWPrintModeCommon* pModeInfo, const cCmdLineParser& cmdLine)
{
cCmdLineIter iter(cmdLine);
for (iter.SeekBegin(); !iter.Done(); iter.Next())
{
switch (iter.ArgId())
{
case cTWPrintCmdLine::VERBOSE:
pModeInfo->mVerbosity = 2;
break;
case cTWPrintCmdLine::SILENT:
pModeInfo->mVerbosity = 0;
break;
case cTWPrintCmdLine::LOCAL_KEY_FILE:
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
pModeInfo->mLocalKeyFile = iter.ParamAt(0);
break;
case cTWPrintCmdLine::SITE_KEY_FILE:
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
pModeInfo->mSiteKeyFile = iter.ParamAt(0);
break;
case cTWPrintCmdLine::HEXADECIMAL:
cArchiveSigGen::SetHex(true);
break;
case cTWPrintCmdLine::PASSPHRASE:
{
// this bites! I have to make sure it is a narrow char string
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
pModeInfo->mPassPhrase = iter.ParamAt(0);
break;
}
default:
break;
}
}
// use the verbosity information
ASSERT((pModeInfo->mVerbosity >= 0) && (pModeInfo->mVerbosity < 3));
iUserNotify::GetInstance()->SetVerboseLevel(pModeInfo->mVerbosity);
}
//#############################################################################
// cTWPrintReportMode
//#############################################################################
class cTWPrintReportMode_i : public cTWPrintModeCommon
{
public:
TSTRING mReportFile;
std::set<TSTRING> mFilesToCheck;
// ctor can set up some default values
cTWPrintReportMode_i() : cTWPrintModeCommon()
{
}
};
void cTWPrintReportMode::SetConfigFile(TSTRING configFilePath)
{
mpData->mConfigFilePath = configFilePath;
}
///////////////////////////////////////////////////////////////////////////////
// FillOutReportModeConfigInfo -- fills out all the common info with config file information
///////////////////////////////////////////////////////////////////////////////
void cTWPrintReportMode::FillOutReportModeConfigInfo(cTWPrintReportMode_i* pModeInfo, const cConfigFile& cf)
{
TSTRING str;
if (cf.Lookup(TSTRING(_T("REPORTFILE")), str))
pModeInfo->mReportFile = str;
// Find out what level of reporting we should use, use default level if none
// has been specified.
if (cf.Lookup(TSTRING(_T("REPORTLEVEL")), str))
{
if (_tcsicmp(str.c_str(), _T("0")) == 0)
/*throw eTWPrintReportLevelZeroCfg( TSS_GetString( cTWPrint, twprint::STR_ERR2_REPORT_LEVEL_ZERO_CFG ) );
// We error if reporting-level 0 is specified in the config. file
// Level zero must be specified on the command line. - changed, 7/14/99 dra */
pModeInfo->mReportLevel = cTextReportViewer::SINGLE_LINE;
else if (_tcsicmp(str.c_str(), _T("1")) == 0)
pModeInfo->mReportLevel = cTextReportViewer::PARSEABLE;
else if (_tcsicmp(str.c_str(), _T("2")) == 0)
pModeInfo->mReportLevel = cTextReportViewer::SUMMARY_ONLY;
else if (_tcsicmp(str.c_str(), _T("3")) == 0)
pModeInfo->mReportLevel = cTextReportViewer::CONCISE_REPORT;
else if (_tcsicmp(str.c_str(), _T("4")) == 0)
pModeInfo->mReportLevel = cTextReportViewer::FULL_REPORT;
else
{
// They specified an illegal level, error.
TSTRING errStr = _T("Invalid Level: ");
errStr += str;
throw eTWPrintInvalidReportLevelCfg(errStr);
}
}
else
// Use the default level of reporting, they specified none in configuration file.
pModeInfo->mReportLevel = cTextReportViewer::CONCISE_REPORT;
//
// turn all of the file names into full paths (they're relative to the exe dir)
//
TSTRING fullPath;
if (iFSServices::GetInstance()->FullPath(fullPath, pModeInfo->mReportFile, cSystemInfo::GetExeDir()))
pModeInfo->mReportFile = fullPath;
}
///////////////////////////////////////////////////////////////////////////////
// ctor, dtor
///////////////////////////////////////////////////////////////////////////////
cTWPrintReportMode::cTWPrintReportMode()
{
mpData = new cTWPrintReportMode_i;
}
cTWPrintReportMode::~cTWPrintReportMode()
{
delete mpData;
}
///////////////////////////////////////////////////////////////////////////////
// InitCmdLineParser
///////////////////////////////////////////////////////////////////////////////
void cTWPrintReportMode::InitCmdLineParser(cCmdLineParser& parser)
{
InitCmdLineCommon(parser);
parser.AddArg(cTWPrintCmdLine::REPORT_FILE, TSTRING(_T("r")), TSTRING(_T("twrfile")), cCmdLineParser::PARAM_ONE);
// multiple levels of reporting
parser.AddArg(
cTWPrintCmdLine::REPORTLEVEL, TSTRING(_T("t")), TSTRING(_T("report-level")), cCmdLineParser::PARAM_ONE);
// For the variable object list.
parser.AddArg(cTWPrintCmdLine::PARAMS, TSTRING(_T("")), TSTRING(_T("")), cCmdLineParser::PARAM_MANY);
}
///////////////////////////////////////////////////////////////////////////////
// Init
///////////////////////////////////////////////////////////////////////////////
bool cTWPrintReportMode::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
{
// first, fill out everything with the config file info...
FillOutCommonConfigInfo(mpData, cf);
FillOutReportModeConfigInfo(mpData, cf);
// TODO -- should I error or warn for (1) mutual exclustion errors or (2) unneeded cmd line
// parameters? I think I should, but I won't right now.
// TODO -- error at the end of Init() if I am missing any requires parameter values..
// now, parse the command line...
// this takes care of the common stuff...
FillOutCmdLineInfo(mpData, cmdLine);
// now do the stuff specific to this mode...
cCmdLineIter iter(cmdLine);
for (iter.SeekBegin(); !iter.Done(); iter.Next())
{
switch (iter.ArgId())
{
case cTWPrintCmdLine::REPORT_FILE:
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
mpData->mReportFile = iter.ParamAt(0);
break;
case cTWPrintCmdLine::REPORTLEVEL:
{
if (iter.ParamAt(0) == _T("0"))
mpData->mReportLevel = cTextReportViewer::SINGLE_LINE;
else if (iter.ParamAt(0) == _T("1"))
mpData->mReportLevel = cTextReportViewer::PARSEABLE;
else if (iter.ParamAt(0) == _T("2"))
mpData->mReportLevel = cTextReportViewer::SUMMARY_ONLY;
else if (iter.ParamAt(0) == _T("3"))
mpData->mReportLevel = cTextReportViewer::CONCISE_REPORT;
else if (iter.ParamAt(0) == _T("4"))
mpData->mReportLevel = cTextReportViewer::FULL_REPORT;
else
{
// They specified an illegal level, error.
TSTRING errStr = _T("Invalid Level: ");
errStr += iter.ParamAt(0);
throw eTWPrintInvalidReportLevel(errStr);
}
break;
}
case cTWPrintCmdLine::PARAMS:
{
// pack all of these onto the files to check list...
mpData->mFilesToCheck.clear();
for (int i = 0; i < iter.NumParams(); i++)
{
mpData->mFilesToCheck.insert(iter.ParamAt(i));
}
}
//done with report-level stuff.
break;
default:
// should I do anything, or just ignore this?
;
}
}
//----------------------------------------
// I require the following information:
//
// * local key file
// * report file
//-----------------------------------------
TEST_INIT_REQUIREMENT((!mpData->mLocalKeyFile.empty()), tw::STR_ERR_MISSING_LOCAL_KEY);
TEST_INIT_REQUIREMENT((!mpData->mReportFile.empty()), tw::STR_ERR_MISSING_REPORT);
// check that the config file and site key file are in sync...
//
if (!mpData->mConfigFilePath.empty())
try
{
if (cTWUtil::VerifyCfgSiteKey(mpData->mConfigFilePath, mpData->mSiteKeyFile) == false)
cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL | eError::SUPRESS_THIRD_MSG));
}
catch (eTWUtilCfgKeyMismatch& e)
{
e.SetFatality(false);
cTWUtil::PrintErrorMsg(e);
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Execute
///////////////////////////////////////////////////////////////////////////////
int cTWPrintReportMode::Execute(cErrorQueue* pQueue)
{
try
{
ASSERT(!mpData->mReportFile.empty());
// make sure the report file exists...
cFileUtil::TestFileExists(mpData->mReportFile);
cKeyFile localKeyfile;
const cElGamalSigPublicKey* pKey;
cFCOReport report;
cFCOReportHeader reportHeader;
cTWUtil::OpenKeyFile(localKeyfile, mpData->mLocalKeyFile);
pKey = localKeyfile.GetPublicKey();
if (!cTWUtil::IsObjectEncrypted(mpData->mReportFile.c_str(),
cFCOReport::GetFileHeaderID(),
TSS_GetString(cTW, tw::STR_ERR_REPORT_READ)))
{
// note (rather than warn) if the database is not encrytped
iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL,
TSS_GetString(cTW, tw::STR_REPORT_NOT_ENCRYPTED).c_str());
}
// open the report...
bool bDummy;
cTWUtil::ReadReport(mpData->mReportFile.c_str(), reportHeader, report, pKey, false, bDummy);
// print it
cTextReportViewer trv(reportHeader, report);
if (!mpData->mFilesToCheck.empty())
{
trv.SetObjects(mpData->mFilesToCheck);
}
trv.PrintTextReport(_T("-"), mpData->mReportLevel);
}
catch (eError& e)
{
cTWUtil::PrintErrorMsg(e);
return 1;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// GetModeUsage -- returns a mode-specific usage statement.
///////////////////////////////////////////////////////////////////////////////
TSTRING cTWPrintReportMode::GetModeUsage()
{
return TSS_GetString(cTWPrint, twprint::STR_TWPRINT_HELP_PRINT_REPORT);
}
//#############################################################################
// cTWPrintDBMode
//#############################################################################
class cTWPrintDBMode_i : public cTWPrintModeCommon
{
public:
TSTRING mDbFile;
std::vector<TSTRING> mFilesToCheck;
cTextDBViewer::DbVerbosity mDbVerbosity;
// ctor can set up some default values
cTWPrintDBMode_i() : cTWPrintModeCommon(), mDbVerbosity(cTextDBViewer::VERBOSE)
{
}
};
///////////////////////////////////////////////////////////////////////////////
// ctor, dtor
///////////////////////////////////////////////////////////////////////////////
cTWPrintDBMode::cTWPrintDBMode()
{
mpData = new cTWPrintDBMode_i;
}
cTWPrintDBMode::~cTWPrintDBMode()
{
delete mpData;
}
void cTWPrintDBMode::SetConfigFile(TSTRING configFilePath)
{
mpData->mConfigFilePath = configFilePath;
}
///////////////////////////////////////////////////////////////////////////////
// FillOutDBModeConfigInfo -- fills out all the common info with config file information
///////////////////////////////////////////////////////////////////////////////
void cTWPrintDBMode::FillOutDBModeConfigInfo(cTWPrintDBMode_i* pModeInfo, const cConfigFile& cf)
{
TSTRING str;
if (cf.Lookup(TSTRING(_T("DBFILE")), str))
pModeInfo->mDbFile = str;
if (cf.Lookup(TSTRING(_T("DBPRINTLEVEL")), str))
{
if (_tcsicmp(str.c_str(), _T("0")) == 0)
pModeInfo->mDbVerbosity = cTextDBViewer::SUMMARY;
else if (_tcsicmp(str.c_str(), _T("1")) == 0)
pModeInfo->mDbVerbosity = cTextDBViewer::CONCISE;
else if (_tcsicmp(str.c_str(), _T("2")) == 0)
pModeInfo->mDbVerbosity = cTextDBViewer::VERBOSE;
else
{
// They specified an illegal level, error.
TSTRING errStr = _T("Invalid Level: ");
errStr += str;
throw eTWPrintInvalidDbPrintLevelCfg(errStr);
}
}
else
// Use the default level of reporting, they specified none in configuration file.
pModeInfo->mVerbosity = cTextDBViewer::VERBOSE;
//
// turn all of the file names into full paths (they're relative to the exe dir)
//
TSTRING fullPath;
if (iFSServices::GetInstance()->FullPath(fullPath, pModeInfo->mDbFile, cSystemInfo::GetExeDir()))
pModeInfo->mDbFile = fullPath;
}
///////////////////////////////////////////////////////////////////////////////
// InitCmdLineParser
///////////////////////////////////////////////////////////////////////////////
void cTWPrintDBMode::InitCmdLineParser(cCmdLineParser& parser)
{
InitCmdLineCommon(parser);
parser.AddArg(cTWPrintCmdLine::DB_FILE, TSTRING(_T("d")), TSTRING(_T("dbfile")), cCmdLineParser::PARAM_ONE);
// multiple levels of reporting
parser.AddArg(
cTWPrintCmdLine::REPORTLEVEL, TSTRING(_T("t")), TSTRING(_T("output-level")), cCmdLineParser::PARAM_ONE);
// For the variable object list.
parser.AddArg(cTWPrintCmdLine::PARAMS, TSTRING(_T("")), TSTRING(_T("")), cCmdLineParser::PARAM_MANY);
}
///////////////////////////////////////////////////////////////////////////////
// Init
///////////////////////////////////////////////////////////////////////////////
bool cTWPrintDBMode::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
{
// first, fill out everything with the config file info...
FillOutCommonConfigInfo(mpData, cf);
FillOutDBModeConfigInfo(mpData, cf);
// TODO -- should I error or warn for (1) mutual exclustion errors or (2) unneeded cmd line
// parameters? I think I should, but I won't right now.
// TODO -- error at the end of Init() if I am missing any requires parameter values..
// now, parse the command line...
// this takes care of the common stuff...
FillOutCmdLineInfo(mpData, cmdLine);
// now do the stuff specific to this mode...
cCmdLineIter iter(cmdLine);
for (iter.SeekBegin(); !iter.Done(); iter.Next())
{
switch (iter.ArgId())
{
case cTWPrintCmdLine::DB_FILE:
{
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
mpData->mDbFile = iter.ParamAt(0);
break;
}
case cTWPrintCmdLine::REPORTLEVEL:
{
if (iter.ParamAt(0) == _T("0"))
mpData->mDbVerbosity = cTextDBViewer::SUMMARY;
else if (iter.ParamAt(0) == _T("1"))
mpData->mDbVerbosity = cTextDBViewer::CONCISE;
else if (iter.ParamAt(0) == _T("2"))
mpData->mDbVerbosity = cTextDBViewer::VERBOSE;
else
{
// They specified an illegal level, error.
TSTRING errStr = _T("Invalid Level: ");
errStr += iter.ParamAt(0);
throw eTWPrintInvalidDbPrintLevel(errStr);
}
break;
}
case cTWPrintCmdLine::PARAMS:
{
// pack all of these onto the files to check list...
mpData->mFilesToCheck.clear();
for (int i = 0; i < iter.NumParams(); i++)
{
mpData->mFilesToCheck.push_back(iter.ParamAt(i));
}
}
default:
// TODO: should I do anything, or just ignore this?
;
}
}
//----------------------------------------
// I require the following information:
//
// * local key file
// * report file
//-----------------------------------------
TEST_INIT_REQUIREMENT((!mpData->mLocalKeyFile.empty()), tw::STR_ERR_MISSING_LOCAL_KEY);
TEST_INIT_REQUIREMENT((!mpData->mDbFile.empty()), tw::STR_ERR_MISSING_DB);
// check that the config file and site key file are in sync...
//
if (!mpData->mConfigFilePath.empty())
try
{
if (cTWUtil::VerifyCfgSiteKey(mpData->mConfigFilePath, mpData->mSiteKeyFile) == false)
cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL | eError::SUPRESS_THIRD_MSG));
}
catch (eTWUtilCfgKeyMismatch& e)
{
e.SetFatality(false);
cTWUtil::PrintErrorMsg(e);
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Execute
///////////////////////////////////////////////////////////////////////////////
int cTWPrintDBMode::Execute(cErrorQueue* pQueue)
{
cDebug d("cTWPrintDBMode::Execute");
int ret = 0;
try
{
ASSERT(!mpData->mDbFile.empty());
// make sure the database file exists...
cFileUtil::TestFileExists(mpData->mDbFile);
cFCODatabaseFile db;
cKeyFile localKeyfile;
const cElGamalSigPublicKey* pKey = 0;
cTWUtil::OpenKeyFile(localKeyfile, mpData->mLocalKeyFile);
pKey = localKeyfile.GetPublicKey();
if (!cTWUtil::IsObjectEncrypted(
mpData->mDbFile.c_str(), cFCODatabaseFile::GetFileHeaderID(), TSS_GetString(cTW, tw::STR_ERR_DB_READ)))
{
// warn if the database is not encrytped
if (iUserNotify::GetInstance()->GetVerboseLevel() > iUserNotify::V_SILENT)
{
cTWUtil::PrintErrorMsg(eTWDbNotEncrypted(_T(""), eError::NON_FATAL | eError::SUPRESS_THIRD_MSG));
}
}
// open the database; note that ReadDatabase will set bEncrypted and open the
// key file if necessary
bool bDummy;
cTWUtil::ReadDatabase(mpData->mDbFile.c_str(), db, pKey, bDummy);
if (mpData->mFilesToCheck.size() > 0)
{
bool details = (mpData->mDbVerbosity == cTextDBViewer::VERBOSE);
//------------------------------------------------
// print specific FCOs from the database
//------------------------------------------------
cTWUtil::GenreObjList listOut;
cTWUtil::ParseObjectList(listOut, mpData->mFilesToCheck);
// now, iterate through the list of objects...
//
cFCODatabaseFile::iterator dbIter(db);
for (cTWUtil::GenreObjList::iterator genreIter = listOut.begin(); genreIter != listOut.end(); ++genreIter)
{
dbIter.SeekToGenre(genreIter->first);
if (!dbIter.Done())
{
cGenreSwitcher::GetInstance()->SelectGenre((cGenre::Genre)dbIter.GetGenre());
cDbDataSourceIter dsIter(&dbIter.GetDb());
dsIter.SetErrorBucket(pQueue);
iFCONameTranslator* pNT = cGenreSwitcher::GetInstance()
->GetFactoryForGenre((cGenre::Genre)dbIter.GetGenre())
->GetNameTranslator();
//
// iterate over all the objects in this genre....
//
for (cTWUtil::ObjList::iterator it = genreIter->second.begin(); it != genreIter->second.end(); ++it)
{
try
{
cFCOName name = cTWUtil::ParseObjectName(*it);
dsIter.SeekToFCO(name, false);
if ((!dsIter.Done()) && (dsIter.HasFCOData()))
{
cTextDBViewer::OutputFCO(
dsIter, dbIter.GetGenreHeader().GetPropDisplayer(), pNT, &TCOUT, details);
}
else
{
eTWUtilObjNotInDb e(*it);
e.SetFatality(false);
cTWUtil::PrintErrorMsg(e);
}
}
catch (eError& e)
{
e.SetFatality(false);
cTWUtil::PrintErrorMsg(e);
}
}
}
else
{
eTWDbDoesntHaveGenre e(
cGenreSwitcher::GetInstance()->GenreToString((cGenre::Genre)genreIter->first, true));
e.SetFatality(false);
cTWUtil::PrintErrorMsg(e);
}
}
}
else
{
//------------------------------------------------
// printing the entire db
//------------------------------------------------
cTextDBViewer::PrintDB(db, _T("-"), mpData->mDbVerbosity);
}
}
catch (eError& e)
{
cTWUtil::PrintErrorMsg(e);
return 1;
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
// GetModeUsage -- returns a mode-specific usage statement.
///////////////////////////////////////////////////////////////////////////////
TSTRING cTWPrintDBMode::GetModeUsage()
{
return TSS_GetString(cTWPrint, twprint::STR_TWPRINT_HELP_PRINT_DATABASE);
}
//#############################################################################
// cTWPrintHelpMode
//#############################################################################
class cTWPrintHelpMode_i
{
public:
cTWPrintHelpMode_i()
{
}
~cTWPrintHelpMode_i()
{
}
// A list of modes to output usage statements for:
std::set<TSTRING> mlModes;
std::set<TSTRING> mPrinted;
};
///////////////////////////////////////////////////////////////////////////////
// ctor, dtor
///////////////////////////////////////////////////////////////////////////////
cTWPrintHelpMode::cTWPrintHelpMode()
{
mpData = new cTWPrintHelpMode_i();
}
cTWPrintHelpMode::~cTWPrintHelpMode()
{
delete mpData;
}
void cTWPrintHelpMode::SetConfigFile(TSTRING configFilePath)
{
}
///////////////////////////////////////////////////////////////////////////////
// InitCmdLineParser
///////////////////////////////////////////////////////////////////////////////
void cTWPrintHelpMode::InitCmdLineParser(cCmdLineParser& cmdLine)
{
// We're only interested in one parameter, that being help. Anything else
// passed to this mode should be a cmdlineparser error.
cmdLine.AddArg(cTWPrintCmdLine::MODE, TSTRING(_T("m")), TSTRING(_T("")), cCmdLineParser::PARAM_MANY, true);
cmdLine.AddArg(cTWPrintCmdLine::MODE_HELP, TSTRING(_T("?")), TSTRING(_T("help")), cCmdLineParser::PARAM_MANY);
cmdLine.AddArg(cTWPrintCmdLine::MODE_HELP_ALL, TSTRING(_T("")), TSTRING(_T("all")), cCmdLineParser::PARAM_MANY);
cmdLine.AddArg(
cTWPrintCmdLine::MODE_REPORTPRINT, TSTRING(_T("r")), TSTRING(_T("print-report")), cCmdLineParser::PARAM_MANY);
cmdLine.AddArg(
cTWPrintCmdLine::MODE_DBPRINT, TSTRING(_T("d")), TSTRING(_T("print-dbfile")), cCmdLineParser::PARAM_MANY);
}
///////////////////////////////////////////////////////////////////////////////
// Init
///////////////////////////////////////////////////////////////////////////////
bool cTWPrintHelpMode::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
{
cCmdLineIter iter(cmdLine);
// Grab the arguments from the help parameter:
for (iter.SeekBegin(); !iter.Done(); iter.Next())
{
switch (iter.ArgId())
{
case cTWPrintCmdLine::MODE_HELP:
{
int i;
for (i = 0; i < iter.NumParams(); ++i)
mpData->mlModes.insert(iter.ParamAt(i));
}
break;
case cTWPrintCmdLine::MODE:
{
int i;
for (i = 0; i < iter.NumParams(); ++i)
{
mpData->mlModes.insert(iter.ParamAt(i));
}
}
break;
// Begin ugly hack so we can allow users to enter the mode
// names with "--" prepended. We have to do this, since
// the cmdlineparser treats them as switches.
case cTWPrintCmdLine::MODE_HELP_ALL: // fall through
case cTWPrintCmdLine::MODE_REPORTPRINT: // fall through
case cTWPrintCmdLine::MODE_DBPRINT:
{
int i;
TSTRING str = iter.ActualParam();
// Kill off the initial "--" or "-"
str.erase(0, 1);
if (str.length() != 1)
str.erase(0, 1);
// push back the parameter that was actually passed.
mpData->mlModes.insert(str);
// grab all the "parameters" following the mode/switch, since
// they may be valid modes without the "--" prepended.
for (i = 0; i < iter.NumParams(); ++i)
mpData->mlModes.insert(iter.ParamAt(i));
}
break;
default:
// should I do anything, or just ignore this?
;
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Execute
///////////////////////////////////////////////////////////////////////////////
int cTWPrintHelpMode::Execute(cErrorQueue* pQueue)
{
cDebug d("cTWPrintHelpMode::Execute");
// The iterator we will use to traverse the list of arguments:
std::set<TSTRING>::iterator it = mpData->mlModes.begin();
// We'll want to output the version information, regardless:
TCOUT << TSS_GetString(cTWPrint, twprint::STR_TWPRINT_VERSION) << std::endl;
TCOUT << TSS_GetString(cTW, tw::STR_VERSION) << std::endl;
if (it == mpData->mlModes.end()) // all that was passed was --help
{
// Output a short usage statement for each mode
TCOUT << TSS_GetString(cTWPrint, twprint::STR_TWPRINT_USAGE_SUMMARY);
//
// That's it. return
return 1;
}
for (; it != mpData->mlModes.end(); ++it)
{
if (_tcscmp((*it).c_str(), _T("all")) == 0)
{
//Since --help all was passed, emit all help messages and return.
TCOUT << TSS_GetString(cTWPrint, twprint::STR_TWPRINT_HELP_PRINT_REPORT);
TCOUT << TSS_GetString(cTWPrint, twprint::STR_TWPRINT_HELP_PRINT_DATABASE);
//We're done, return
return 1;
}
}
//We need some subset of the usage statements. Figure out which modes have
//been specified:
it = mpData->mlModes.begin();
for (; it != mpData->mlModes.end(); ++it)
{
if (_tcscmp((*it).c_str(), _T("print-report")) == 0 || _tcscmp((*it).c_str(), _T("r")) == 0)
{
// make sure we don't print the same help twice...
if (mpData->mPrinted.find(_T("print-report")) == mpData->mPrinted.end())
{
TCOUT << TSS_GetString(cTWPrint, twprint::STR_TWPRINT_HELP_PRINT_REPORT);
mpData->mPrinted.insert(_T("print-report"));
}
}
else if (_tcscmp((*it).c_str(), _T("print-dbfile")) == 0 || _tcscmp((*it).c_str(), _T("d")) == 0)
{
if (mpData->mPrinted.find(_T("print-dbfile")) == mpData->mPrinted.end())
{
TCOUT << TSS_GetString(cTWPrint, twprint::STR_TWPRINT_HELP_PRINT_DATABASE);
mpData->mPrinted.insert(_T("print-dbfile"));
}
}
else
{
cTWUtil::PrintErrorMsg(eTWPrintInvalidParamHelp((*it), eError::NON_FATAL));
TCOUT << std::endl;
// emit error/warning string, this mode does not exist
}
}
//Everything went okay
return 1;
}