//
// The developer of the original code and/or files is Tripwire, Inc.
// Portions created by Tripwire, Inc. are copyright (C) 2000 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.
//
///////////////////////////////////////////////////////////////////////////////
// twadmincl.cpp -- command line parsing for twadmin
//

#include "stdtwadmin.h"

#include "twadmincl.h"
#include "twadminstrings.h"
#include "keygeneration.h"
#include "core/errorgeneral.h"
#include "core/errorbucketimpl.h"	// needed for the error table
#include "core/archive.h"
#include "core/usernotify.h"
#include "core/cmdlineparser.h"
#include "core/usernotify.h"
#include "fco/fconame.h"
#include "tw/configfile.h"
#include "tw/twutil.h"
#include "tw/filemanipulator.h"
#include "tw/fcodatabasefile.h"
#include "tw/fcoreport.h"
#include "tw/policyfile.h"
#include "tw/systeminfo.h"
#include "tw/twerrors.h"
#include "tw/twstrings.h"
#include "twparser/policyparser.h"
#include "twcrypto/keyfile.h"
#include "core/stringutil.h"
#include "util/fileutil.h"
#include "twcrypto/crypto.h"
#include "core/displayencoder.h"

// forwards
static bool NotifyFileType(const cFileHeaderID& id, uint32 version, iUserNotify::VerboseLevel vl);
    // Calls UserNotify(V_VERBOSE, ...) to print out type of file specified in cFileHeaderID.
    // Returns false if cFileHeaderID not recognized.
    // Used in changing and removing encryption algorithms
static bool NotifyEncryptionType(cFileHeader::Encoding encoding, iUserNotify::VerboseLevel vl);
    // Calls UserNotify(V_VERBOSE, ...) to print out type of file specified in cFileHeaderID.
    // Returns false if encoding not recognized.
    // Used in changing and removing encryption algorithms


// error implementations

eTWACreateCfgMissingSitekey::eTWACreateCfgMissingSitekey( const TSTRING& msg, uint32 flags )
    : eTWA( TSTRING(), flags ) 
{ 
    mMsg = TSS_GetString(cTWAdmin, twadmin::STR_ERR2_CREATE_CFG_MISSING_KEYFILE) + msg; 
} 

eTWACreateCfgSitekeyMismatch::eTWACreateCfgSitekeyMismatch( const TSTRING& specifiedKeyfile, const TSTRING& configKeyfile, uint32 flags )
    : eTWA( TSTRING(), flags ) 
{ 
    mMsg = TSS_GetString(cTWAdmin, twadmin::STR_ERR2_CREATE_CFG_SITEKEY_MISMATCH1); 
    mMsg.append(specifiedKeyfile);
    mMsg.append(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_CREATE_CFG_SITEKEY_MISMATCH2)); 
    mMsg.append(configKeyfile);
    mMsg.append(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_CREATE_CFG_SITEKEY_MISMATCH3)); 
} 

///////////////////////////////////////////////////////////////////////////////
// cTWAModeCommon -- common modes that all iTWAMode implementations will
//      derive from.

class cTWAModeCommon : public iTWAMode
{
protected:
	int			mVerbosity;		// must be 0 <= n <= 2
	TSTRING		mPolFile;
	TSTRING		mSiteKeyFile;
    bool        mSiteKeyFileProvieded;
	TSTRING		mLocalKeyFile;
    bool        mLocalKeyFileProvieded;
    bool        mLatePassphrase;

	cTWAModeCommon() : mVerbosity(1), mSiteKeyFileProvieded(false), mLocalKeyFileProvieded(false), mLatePassphrase(false) {}

    void InitCmdLineCommon(cCmdLineParser& parser);
    void FillOutConfigInfo(const cConfigFile* cf);
    void FillOutCmdLineInfo(const cCmdLineParser& parser);
};

///////////////////////////////////////////////////////////////////////////////
// InitCmdLineCommon -- initializes the command line switches common to all
//		modes

void cTWAModeCommon::InitCmdLineCommon(cCmdLineParser& parser)
{
    parser.AddArg(cTWAdminCmdLine::HELP,			TSTRING(_T("?")),	TSTRING(_T("help")),            cCmdLineParser::PARAM_NONE);
	parser.AddArg(cTWAdminCmdLine::MODE,			TSTRING(_T("m")),	TSTRING(_T("")),				cCmdLineParser::PARAM_ONE);
	parser.AddArg(cTWAdminCmdLine::VERBOSE,			TSTRING(_T("v")),	TSTRING(_T("verbose")),			cCmdLineParser::PARAM_NONE);
	parser.AddArg(cTWAdminCmdLine::SILENT,			TSTRING(_T("s")),	TSTRING(_T("silent")),			cCmdLineParser::PARAM_NONE);
	parser.AddArg(cTWAdminCmdLine::SILENT,			TSTRING(_T("")),	TSTRING(_T("quiet")),			cCmdLineParser::PARAM_NONE);
	parser.AddArg(cTWAdminCmdLine::CFG_FILE,		TSTRING(_T("c")),	TSTRING(_T("cfgfile")),			cCmdLineParser::PARAM_ONE);
	parser.AddArg(cTWAdminCmdLine::POL_FILE,		TSTRING(_T("p")),	TSTRING(_T("polfile")),		    cCmdLineParser::PARAM_ONE);
	parser.AddMutEx(cTWAdminCmdLine::VERBOSE, cTWAdminCmdLine::SILENT);
}

///////////////////////////////////////////////////////////////////////////////
// FillOutConfigInfo -- fills out all the common info with config file information
///////////////////////////////////////////////////////////////////////////////
void cTWAModeCommon::FillOutConfigInfo(const cConfigFile* cf)
{
    if (cf == 0)
        return;

	TSTRING str;
	if(cf->Lookup(TSTRING(_T("POLFILE")), str))
		mPolFile = str;
	if(cf->Lookup(TSTRING(_T("SITEKEYFILE")), str))
		mSiteKeyFile = str;
	if(cf->Lookup(TSTRING(_T("LOCALKEYFILE")), str))
		mLocalKeyFile = str;
	if(cf->Lookup(TSTRING(_T("LATEPROMPTING")), str))
    {
		if (_tcsicmp(str.c_str(), _T("true")) == 0)
			mLatePassphrase = true;	
    }

    // 
	// turn all of the file names into full paths (they're relative to the exe dir)
	// 
	TSTRING fullPath;
	if(!mPolFile.empty() && iFSServices::GetInstance()->FullPath( fullPath, mPolFile, cSystemInfo::GetExeDir() ))
		mPolFile = fullPath;
	if(!mSiteKeyFile.empty() && iFSServices::GetInstance()->FullPath( fullPath, mSiteKeyFile, cSystemInfo::GetExeDir() ))
		mSiteKeyFile = fullPath;
	if(!mLocalKeyFile.empty() && iFSServices::GetInstance()->FullPath( fullPath, mLocalKeyFile, cSystemInfo::GetExeDir() ))
		mLocalKeyFile = fullPath;
}

///////////////////////////////////////////////////////////////////////////////
// FillOutCmdLineInfo -- fills out info common to all modes that appears on the 
//		command line.
///////////////////////////////////////////////////////////////////////////////
void cTWAModeCommon::FillOutCmdLineInfo(const cCmdLineParser& parser)
{    
	cCmdLineIter iter(parser);
	for(iter.SeekBegin(); ! iter.Done(); iter.Next())
	{
		switch(iter.ArgId())
		{
		case cTWAdminCmdLine::VERBOSE:
			mVerbosity = 2;
			break;
		case cTWAdminCmdLine::SILENT:
			mVerbosity = 0;
			break;
		case cTWAdminCmdLine::POL_FILE:
			ASSERT(iter.NumParams() > 0);	// should be caught by cmd line parser
			mPolFile = iter.ParamAt(0);
			break;
		case cTWAdminCmdLine::SITE_KEY_FILE:
			ASSERT(iter.NumParams() > 0);	// should be caught by cmd line parser
			mSiteKeyFile = iter.ParamAt(0);
            mSiteKeyFileProvieded = true;
			break;
		case cTWAdminCmdLine::LOCAL_KEY_FILE:
			ASSERT(iter.NumParams() > 0);	// should be caught by cmd line parser
			mLocalKeyFile = iter.ParamAt(0);
            mLocalKeyFileProvieded = true;
			break;
		}
	}

	// Turn all of the file names into full paths for nice presentation to the user.
    // Note: We depend later on the if one of these files is not specified, the string
    // is empty.  Currently FullPath() expands "" to the CWD.
	TSTRING fullPath;
	if(!mPolFile.empty() && iFSServices::GetInstance()->FullPath(fullPath, mPolFile))
		mPolFile = fullPath;
	if(!mSiteKeyFile.empty() && iFSServices::GetInstance()->FullPath(fullPath, mSiteKeyFile))
		mSiteKeyFile = fullPath;
	if(!mLocalKeyFile.empty() && iFSServices::GetInstance()->FullPath(fullPath, mLocalKeyFile))
		mLocalKeyFile = fullPath;

	// use the verbosity information
	ASSERT((mVerbosity >= 0) && (mVerbosity < 3));
	iUserNotify::GetInstance()->SetVerboseLevel(mVerbosity);
}

///////////////////////////////////////////////////////////////////////////////
// TWAdmin modes
// 
// No one else should need to see these classes, so we will keep them 
// localized to this file.
//

///////////////////////////////////////////////////////////////////////////////
// cTWAModeCreateCfg 

class cTWAModeCreateCfg : public cTWAModeCommon
{
public:
	cTWAModeCreateCfg();
	virtual ~cTWAModeCreateCfg();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual TSTRING GetModeUsage() { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CREATE_CFGFILE ); }
    virtual bool    LoadConfigFile() { return true; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_CREATE_CONFIG; }

private:
    TSTRING     mPlaintextConfig;
    TSTRING     mEncryptedConfig;
	wc16_string mPassPhrase;	// pass phrase for private key
    bool        mPassPhraseProvided;
    bool        mNoEncryption;
};

cTWAModeCreateCfg::cTWAModeCreateCfg()
{
    mNoEncryption = false;
    mPassPhraseProvided = false;
}

cTWAModeCreateCfg::~cTWAModeCreateCfg()
{
}

void cTWAModeCreateCfg::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

	parser.AddArg(cTWAdminCmdLine::MODE_CREATE_CONFIG, TSTRING(_T("")),	TSTRING(_T("create-cfgfile")),  cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::PASSPHRASE,		TSTRING(_T("Q")),	TSTRING(_T("site-passphrase")),	cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::SITE_KEY_FILE,	TSTRING(_T("S")),	TSTRING(_T("site-keyfile")),	cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::NO_ENCRYPTION,	TSTRING(_T("e")),	TSTRING(_T("no-encryption")),	cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::PARAMS,	        TSTRING(_T("")),	TSTRING(_T("")),	            cCmdLineParser::PARAM_ONE);
	parser.AddMutEx(cTWAdminCmdLine::NO_ENCRYPTION, cTWAdminCmdLine::SITE_KEY_FILE);
	parser.AddMutEx(cTWAdminCmdLine::NO_ENCRYPTION, cTWAdminCmdLine::PASSPHRASE);
}

bool cTWAModeCreateCfg::Init(const cConfigFile* cf, const cCmdLineParser& parser)
{
    TSTRING str;
    
    FillOutConfigInfo(cf);

    FillOutCmdLineInfo(parser);

    bool fConfigOnCmdLine = false;
	cCmdLineIter iter(parser);
	for(iter.SeekBegin(); ! iter.Done(); iter.Next())
	{
		switch(iter.ArgId())
		{
		case cTWAdminCmdLine::NO_ENCRYPTION:
            mNoEncryption = true;
			break;
		case cTWAdminCmdLine::PASSPHRASE:
			{
				ASSERT(iter.NumParams() > 0);	// should be caught by cmd line parser
				mPassPhrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
                mPassPhraseProvided = true;
			}
			break;
        case cTWAdminCmdLine::CFG_FILE:
            if (iter.NumParams() < 1)
            {
                cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_CONFIG)));
                return false;
            }
			mEncryptedConfig = iter.ParamAt(0);
            fConfigOnCmdLine = true;
            break;
        case cTWAdminCmdLine::PARAMS:
            ASSERT(iter.NumParams() == 1);
            mPlaintextConfig = iter.ParamAt(0);

            break;
		}
	}

    // get full path to files
    TSTRING strFullPath;
    if( iFSServices::GetInstance()->FullPath( strFullPath, mPlaintextConfig ) )
        mPlaintextConfig = strFullPath;

    // OK, now we need to figure out where to put the new config file.
    // If the location was specified on the command line, get the full path to it.
    // otherwise, the location is the dir that this exe is in.
    if( fConfigOnCmdLine )
    {
        TSTRING strFullPath;
        if( iFSServices::GetInstance()->FullPath( strFullPath, mEncryptedConfig ) )
            mEncryptedConfig = strFullPath;
    }
    else
    {
		iFSServices::GetInstance()->FullPath(	mEncryptedConfig, TSS_GetString(cTW, tw::STR_DEF_CFG_FILENAME ),
												cSystemInfo::GetExeDir() ) ;
    }    

    return true;
}

int cTWAModeCreateCfg::Execute(cErrorQueue* pQueue)
{
    if (mPlaintextConfig.empty())
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_PT_CONFIG)));
        return 1;
    }

    if (mEncryptedConfig.empty())
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_CONFIG)));
        return 1;
    }

    if (mSiteKeyFile.empty() && !mNoEncryption)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_SITE_KEY_NOENCRYPT_NOT_SPECIFIED)));
        return 1;
    }

    iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                                       TSS_GetString(cTWAdmin, twadmin::STR_UPCONFIG_VERBOSE_PT_CONFIG).c_str(),
                                       cDisplayEncoder::EncodeInline( mPlaintextConfig ).c_str()); 


    cFileArchive arch;
    arch.OpenRead(mPlaintextConfig.c_str(), cFileArchive::FA_OPEN_TEXT);  // Note: eArchive may be thrown
    
    // read in config text
    std::string narrowPlaintext;
    narrowPlaintext.resize(arch.Length());
    // NOTE: archive may write fewer than arch.Length() bytes since
    // it is converting CR/LF to CR.
    int cbRead = arch.ReadBlob((void*)narrowPlaintext.data(), arch.Length());
    narrowPlaintext.resize( cbRead ); // may have garbage after plaintext[cbRead] due to text mode conversion

    TSTRING plaintext = cStringUtil::StrToTstr(narrowPlaintext);

    // Try reading it to see if there are any problems.
    // Also open the keyfile so we can verify the keyfile specified in the plaintext
    // matches the key we intend to encrypt the config file with.
    cKeyFile plaintextKeyFile;
    TSTRING  plaintextKeyFileName;
    bool     plaintextKeyFileLoaded = false;
    try
    {
        cConfigFile cf;
        cf.ReadString(plaintext);

        if ( (plaintextKeyFileLoaded = cf.Lookup(_T("SITEKEYFILE"), plaintextKeyFileName)) == true &&
             (plaintextKeyFileLoaded = !plaintextKeyFileName.empty()) == true
           )
        {
	        TSTRING fullPath;
	        if (iFSServices::GetInstance()->FullPath( fullPath, plaintextKeyFileName, cSystemInfo::GetExeDir() ))
		        plaintextKeyFileName = fullPath;

            cTWUtil::OpenKeyFile(plaintextKeyFile, plaintextKeyFileName);
            plaintextKeyFileLoaded = true;
        }
    }
    catch (eConfigFile& e)
    {
        pQueue->AddError( e );
        return 1;
    }

    cKeyFile specifiedKeyFile;
    const cElGamalSigPrivateKey* pPrivateKey;

    if (!mNoEncryption)
    {
        cTWUtil::OpenKeyFile(specifiedKeyFile, mSiteKeyFile);
        if (!plaintextKeyFileLoaded)
        {
            // User wishes to create a config file using a key, but has not specified the key in the config file.
            // For safty and sanity reasons we do not let them do this.
            pQueue->AddError( eTWACreateCfgMissingSitekey(TSTRING()) );
            return false;
        }
        else if (!specifiedKeyFile.GetPublicKey()->IsEqual(*plaintextKeyFile.GetPublicKey()))
        {
            // The site key specified in this config file does not match the sitekey they are encrypting the
            // config file with.  This is likely to lead to problems so we try to catch it here.
            pQueue->AddError( eTWACreateCfgSitekeyMismatch(mSiteKeyFile, plaintextKeyFileName) );
            return false;
        }

        pPrivateKey = cTWUtil::CreatePrivateKey(specifiedKeyFile, mPassPhraseProvided ? mPassPhrase.c_str() : NULL, cTWUtil::KEY_SITE);
    }
    else
        pPrivateKey = 0;

    // Make sure we can create the file
    cFileUtil::TestFileWritable(mEncryptedConfig);

    // backup current file if it exists
    cFileUtil::BackupFile(mEncryptedConfig);

    if (!mNoEncryption)
    {
        cTWUtil::WriteConfigText(mEncryptedConfig.c_str(), plaintext, true, pPrivateKey);
        specifiedKeyFile.ReleasePrivateKey();
    }
    else
        cTWUtil::WriteConfigText(mEncryptedConfig.c_str(), plaintext, false, 0);

    return 0;
}

///////////////////////////////////////////////////////////////////////////////
// cTWAModeCreatePol

class cTWAModeCreatePol : public cTWAModeCommon
{
public:
	cTWAModeCreatePol();
	virtual ~cTWAModeCreatePol();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);	
	virtual TSTRING GetModeUsage() { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CREATE_POLFILE ); }
    virtual bool    LoadConfigFile() { return true; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_CREATE_POLICY; }

private:
    TSTRING     mPlaintextPolicy;
	wc16_string mPassPhrase;	// pass phrase for private key
    bool        mPassPhraseProvided;
    bool        mNoEncryption;
};

cTWAModeCreatePol::cTWAModeCreatePol()
{
    mNoEncryption = false;
    mPassPhraseProvided = false;
}

cTWAModeCreatePol::~cTWAModeCreatePol()
{
}

void cTWAModeCreatePol::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

	parser.AddArg(cTWAdminCmdLine::MODE_CREATE_POLICY, TSTRING(_T("")),	TSTRING(_T("create-polfile")),  cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::PASSPHRASE,		TSTRING(_T("Q")),	TSTRING(_T("site-passphrase")), cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::SITE_KEY_FILE,	TSTRING(_T("S")),	TSTRING(_T("site-keyfile")),	cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::NO_ENCRYPTION,	TSTRING(_T("e")),	TSTRING(_T("no-encryption")),	cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::PARAMS,	        TSTRING(_T("")),	TSTRING(_T("")),	            cCmdLineParser::PARAM_ONE);
	parser.AddMutEx(cTWAdminCmdLine::NO_ENCRYPTION, cTWAdminCmdLine::SITE_KEY_FILE);
	parser.AddMutEx(cTWAdminCmdLine::NO_ENCRYPTION, cTWAdminCmdLine::PASSPHRASE);
}

bool cTWAModeCreatePol::Init(const cConfigFile* cf, const cCmdLineParser& parser)
{
    TSTRING str;
    
    FillOutConfigInfo(cf);
    FillOutCmdLineInfo(parser);

	cCmdLineIter iter(parser);
	for(iter.SeekBegin(); ! iter.Done(); iter.Next())
	{
		switch(iter.ArgId())
		{
		case cTWAdminCmdLine::NO_ENCRYPTION:
            mNoEncryption = true;
			break;
		case cTWAdminCmdLine::PASSPHRASE:
			{
				ASSERT(iter.NumParams() > 0);	// should be caught by cmd line parser
				mPassPhrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
                mPassPhraseProvided = true;
			}
			break;
        case cTWAdminCmdLine::PARAMS:
            ASSERT(iter.NumParams() == 1);
            mPlaintextPolicy = iter.ParamAt(0);
            break;
		}
	}

    // get full path to files
    TSTRING strFullPath;
    if( iFSServices::GetInstance()->FullPath( strFullPath, mSiteKeyFile ) )
        mSiteKeyFile = strFullPath;
    if( iFSServices::GetInstance()->FullPath( strFullPath, mPlaintextPolicy ) )
        mPlaintextPolicy = strFullPath;

    if (mPlaintextPolicy.empty())
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_PT_POLICY)));
        return false;
    }

	// check that the config file and site key file are in sync...
	//
	if( ! mCfgFilePath.empty() )
        try 
        {
		    if (cTWUtil::VerifyCfgSiteKey( mCfgFilePath, mSiteKeyFile ) == false)
                cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
        }
        catch (eTWUtilCfgKeyMismatch& e)        
        {
            e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
        }

    return true;
}

int cTWAModeCreatePol::Execute(cErrorQueue* pQueue)
{
    if (mPlaintextPolicy.empty())
    {
		 cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_PT_POLICY)));
         return 1;
    }

    if (mPolFile.empty())
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_POLICY)));
        return 1;
    }

    if (mSiteKeyFile.empty() && !mNoEncryption)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_SITE_KEY_NOENCRYPT_NOT_SPECIFIED)));
        return 1;
    }


    iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                                       TSS_GetString(cTWAdmin, twadmin::STR_UPCONFIG_VERBOSE_PT_POLICY).c_str(), 
                                       cDisplayEncoder::EncodeInline( mPlaintextPolicy ).c_str());

    // open policy file as text
    cFileArchive arch;
    arch.OpenRead(mPlaintextPolicy.c_str(), cFileArchive::FA_OPEN_TEXT); // Note: eArchive may be thrown
    
    // read in policy text
    std::string plaintext;
    plaintext.resize(arch.Length());
    // NOTE: archive may write fewer than arch.Length() bytes since
    // it is converting CR/LF to CR.
    int cbRead = arch.ReadBlob((void*)plaintext.data(), arch.Length());
    plaintext.resize( cbRead ); // may have garbage after plaintext[cbRead] due to text mode conversion

	//
	// make sure the policy file parses correctly before we update the old one
	//
    std::istringstream in( plaintext );
    cPolicyParser parser( in );
	try
	{
        parser.Check( pQueue );
	}
	catch(eError& e)
	{
		cTWUtil::PrintErrorMsg(e);
		iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, 
											TSS_GetString(cTWAdmin, twadmin::STR_POL_NOT_UPDATED).c_str() );
		return 1;
	}

	//
	// open the key file...
	//
    cKeyFile keyfile;

    const cElGamalSigPrivateKey* pPrivateKey;

    if (!mNoEncryption)
    {
        cTWUtil::OpenKeyFile(keyfile, mSiteKeyFile);
        pPrivateKey = cTWUtil::CreatePrivateKey(keyfile, mPassPhraseProvided ? mPassPhrase.c_str() : NULL, cTWUtil::KEY_SITE);
    }
    else
        pPrivateKey = 0;

    // Make sure we can create the file
    cFileUtil::TestFileWritable(mPolFile);

    // backup current file if it exists
    cFileUtil::BackupFile(mPolFile);

    if (!mNoEncryption)
    {
        cTWUtil::WritePolicyText(mPolFile.c_str(), plaintext, true, pPrivateKey);
        keyfile.ReleasePrivateKey();
    }
    else
        cTWUtil::WritePolicyText(mPolFile.c_str(), plaintext, false, 0);

    return 0;
}

///////////////////////////////////////////////////////////////////////////////
// cTWAModePrintCfg 

class cTWAModePrintCfg : public cTWAModeCommon
{
public:
	cTWAModePrintCfg();
	virtual ~cTWAModePrintCfg();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual TSTRING GetModeUsage() { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_PRINT_CFGFILE ); }
    virtual bool    LoadConfigFile() { return true; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_PRINT_CONFIG; }

private:
    TSTRING     mEncryptedConfig;
};

cTWAModePrintCfg::cTWAModePrintCfg()
{
}

cTWAModePrintCfg::~cTWAModePrintCfg()
{
}

void cTWAModePrintCfg::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

    parser.AddArg(cTWAdminCmdLine::MODE_PRINT_CONFIG,	TSTRING(_T("")),	TSTRING(_T("print-cfgfile")),		cCmdLineParser::PARAM_NONE);
}

bool cTWAModePrintCfg::Init(const cConfigFile* cf, const cCmdLineParser& parser) //throw(eTWUTil)
{
    FillOutConfigInfo(cf);
    FillOutCmdLineInfo(parser);

    mEncryptedConfig = cTWUtil::GetCfgFilePath(parser, cTWAdminCmdLine::CFG_FILE);
    
	 // check that the config file and site key file are in sync...
	 //
	 if( ! mCfgFilePath.empty() )
        try 
        {
		    if (cTWUtil::VerifyCfgSiteKey( mCfgFilePath, mSiteKeyFile ) == false)
                cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
        }
        catch (eTWUtilCfgKeyMismatch& e)        
        {
            e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
        }

    return true;
}

int cTWAModePrintCfg::Execute(cErrorQueue* pQueue)
{
    try
    {
        TSTRING configText;
        cTWUtil::ReadConfigText(mEncryptedConfig.c_str(), configText);

        // Note: I believe print config and print policy are the only time we should 
        // print to standard out directly.
        TCOUT << cDisplayEncoder::EncodeInlineAllowWS( configText );
        TCOUT << std::endl;
    }
    catch (eError& e)
    {
        TSTRING extra;
        extra += TSS_GetString(cTW, tw::STR_NEWLINE);
        extra += TSS_GetString(cTW, tw::STR_ERR_TWCFG_CANT_READ);
        cTWUtil::PrintErrorMsg(e, extra); 
        return 1;
    }

    return 0;
}

///////////////////////////////////////////////////////////////////////////////
// cTWAModePrintPol 

class cTWAModePrintPol : public cTWAModeCommon
{
public:
	cTWAModePrintPol();
	virtual ~cTWAModePrintPol();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual TSTRING GetModeUsage() { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_PRINT_POLFILE ); }
    virtual bool    LoadConfigFile() { return true; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_PRINT_POLICY; }
private:
};

cTWAModePrintPol::cTWAModePrintPol()
{
}

cTWAModePrintPol::~cTWAModePrintPol()
{
}

void cTWAModePrintPol::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

    parser.AddArg(cTWAdminCmdLine::MODE_PRINT_POLICY,	TSTRING(_T("")),	TSTRING(_T("print-polfile")),		cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::SITE_KEY_FILE,	    TSTRING(_T("S")),	TSTRING(_T("site-keyfile")),		cCmdLineParser::PARAM_ONE);
}

bool cTWAModePrintPol::Init(const cConfigFile* cf, const cCmdLineParser& parser)
{
    FillOutConfigInfo(cf);
    FillOutCmdLineInfo(parser);

    return true;
}

int cTWAModePrintPol::Execute(cErrorQueue* pQueue)
{
    try
    {
        cKeyFile sitekey;

        bool policyEncrypted = cTWUtil::IsObjectEncrypted(mPolFile.c_str(), cPolicyFile::GetFileHeaderID(), TSS_GetString( cTWAdmin, twadmin::STR_ERR2_UNABLE_TO_PRINT_POLICY ) );

        if (policyEncrypted)
        {
	        // check that the config file and site key file are in sync...
	        //
	        if( ! mCfgFilePath.empty() )
                try 
                {
		            if (cTWUtil::VerifyCfgSiteKey( mCfgFilePath, mSiteKeyFile ) == false)
                        cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
                }
                catch (eTWUtilCfgKeyMismatch& e)        
                {
                    e.SetFatality(false);
                    cTWUtil::PrintErrorMsg(e);
                }

            cTWUtil::OpenKeyFile(sitekey, mSiteKeyFile);
        }
        else 
            cTWUtil::PrintErrorMsg(eTWUtilPolUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));

        std::string policyText;

        iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
										    TSS_GetString(cTW, tw::STR_OPEN_POLICY_FILE).c_str(), 
                                            cDisplayEncoder::EncodeInline( mPolFile ).c_str());

        cTWUtil::ReadPolicyText(mPolFile.c_str(), policyText, policyEncrypted ? sitekey.GetPublicKey() : 0);

        // Note: I believe print config and print policy are the only time we should 
        // print to standard out directly.
        TCOUT << cDisplayEncoder::EncodeInlineAllowWS( cStringUtil::StrToTstr( policyText ) );
        TCOUT << std::endl;
    }
    catch (eError& e)
    {
        cTWUtil::PrintErrorMsg(e);
        return 1;
    }

    return 0;
}

///////////////////////////////////////////////////////////////////////////////
// cTWAModeRemoveEncryption

class cTWAModeRemoveEncryption : public cTWAModeCommon
{
public:
	cTWAModeRemoveEncryption();
	virtual ~cTWAModeRemoveEncryption();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual TSTRING GetModeUsage () { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_REMOVE_ENCRYPTION ); }
    virtual bool    LoadConfigFile() { return true; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_REMOVE_ENCRYPTION; }
private:
    std::list<TSTRING> mFileList;
    wc16_string mSitePassphrase;
    wc16_string mLocalPassphrase;
    bool    mSitePassphraseProvided;
    bool    mLocalPassphraseProvided;
};

cTWAModeRemoveEncryption::cTWAModeRemoveEncryption()
{
    mSitePassphraseProvided = false;
    mLocalPassphraseProvided = false;
}

cTWAModeRemoveEncryption::~cTWAModeRemoveEncryption()
{
}

void cTWAModeRemoveEncryption::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

	parser.AddArg(cTWAdminCmdLine::MODE_REMOVE_ENCRYPTION, TSTRING(_T("")),	TSTRING(_T("remove-encryption")),	cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::SITE_KEY_FILE,	TSTRING(_T("S")),	TSTRING(_T("site-keyfile")),			cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCAL_KEY_FILE,	TSTRING(_T("L")),	TSTRING(_T("local-keyfile")),			cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::SITEPASSPHRASE,	TSTRING(_T("Q")),	TSTRING(_T("site-passphrase")),	        cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCALPASSPHRASE, TSTRING(_T("P")),	TSTRING(_T("local-passphrase")),	    cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::PARAMS,	        TSTRING(_T("")),	TSTRING(_T("")),						cCmdLineParser::PARAM_MANY);

    parser.AddMutEx(cTWAdminCmdLine::KEY_FILE, cTWAdminCmdLine::LOCAL_KEY_FILE);
    parser.AddMutEx(cTWAdminCmdLine::KEY_FILE, cTWAdminCmdLine::LOCAL_KEY_FILE);
    parser.AddMutEx(cTWAdminCmdLine::KEY_FILE, cTWAdminCmdLine::SITEPASSPHRASE);
}

bool cTWAModeRemoveEncryption::Init(const cConfigFile* cf, const cCmdLineParser& parser)
{
    int i;

    FillOutConfigInfo(cf);
    FillOutCmdLineInfo(parser);

	cCmdLineIter iter(parser);
	for(iter.SeekBegin(); ! iter.Done(); iter.Next())
	{
		switch(iter.ArgId())
		{
        case cTWAdminCmdLine::LOCALPASSPHRASE:
            ASSERT(iter.NumParams() == 1);
            mLocalPassphraseProvided = true;
            mLocalPassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
            break;
        case cTWAdminCmdLine::SITEPASSPHRASE:
            ASSERT(iter.NumParams() == 1);
            mSitePassphraseProvided = true;
            mSitePassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
            break;
        case cTWAdminCmdLine::PARAMS:
            for (i = 0; i < iter.NumParams(); ++i)
            {                
                // get full path to files
                TSTRING strFullPath;
                if( iFSServices::GetInstance()->FullPath( strFullPath, iter.ParamAt(i) ) )
                    mFileList.push_back( strFullPath );
                else
                    mFileList.push_back( iter.ParamAt(i) );
            }
            break;
		}
	}
    
	// check that the config file and site key file are in sync...
	//
	if( ! mCfgFilePath.empty() )
        try 
        {
		    if (cTWUtil::VerifyCfgSiteKey( mCfgFilePath, mSiteKeyFile ) == false)
                cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
        }
        catch (eTWUtilCfgKeyMismatch& e)
        {
            e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
        }

    return true;
}

int cTWAModeRemoveEncryption::Execute(cErrorQueue* pQueue)
{
    TSTRING keyfile;
    cTWUtil::KeyType keyType;
    bool userKnowsLocalPassphrase = false;
    bool userKnowsSitePassphrase = false;

	bool bResult = true;

    bool firstFile = true;
    bool warningGiven = false;
    bool lastMsgWasError = false; // used to send the separating newline to stderr instead of stdout

    if (mFileList.empty())
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_FILES_SPECIFIED)));
        return 1;
    }

    std::list<TSTRING>::iterator i;
    for (i = mFileList.begin(); i != mFileList.end(); ++i)
    {
        // These lines print out a blank line if necessary
        if (!firstFile)
            if (!lastMsgWasError)
                iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
            else
            {
                TCERR << std::endl;
                lastMsgWasError = false;
            }
        else 
            firstFile = false;

		if( cFileUtil::IsDir( i->c_str() ) )
		{
			// Ignore directories for this particular operation.
            cTWUtil::PrintErrorMsg(eTWASkippingDirectory(*i, eError::NON_FATAL));
            lastMsgWasError = true;
		}
        else 
        try
        {            
            cFileManipulator manip(i->c_str());
            manip.Init();

            iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL, 
                                               _T("%s %s\n"),
                                               TSS_GetString(cTWAdmin, twadmin::STR_EXAMINING_FILE).c_str(), 
                                               cDisplayEncoder::EncodeInline( manip.GetFileName() ).c_str());

            if (NotifyFileType(*manip.GetHeaderID(), manip.GetFileVersion(), iUserNotify::V_VERBOSE) == false)
            {
                throw eTWAFileTypeUnknown(manip.GetFileName());
            }

            // can't decrypt keyfiles
            if (*manip.GetHeaderID() == cKeyFile::GetFileHeaderID())
            {
                cTWUtil::PrintErrorMsg(eTWAEncryptionChange(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_CAN_NOT_DECRYPT_KEYFILE), manip.GetFileName(), eError::NON_FATAL));
                lastMsgWasError = true;
                bResult = false;
                continue;
            }

            // if this is a config file, make sure its embedded key is the
            // same as the provided keyfile
            if (*manip.GetHeaderID() == cConfigFile::GetFileHeaderID())
            {
                try 
                {
		            cTWUtil::VerifyCfgSiteKey( *i, mSiteKeyFile );
                }
                catch (eTWUtil& e)        
                {                        
                    e.SetSupressThird(true);
                    e.SetFatality(false);
                    cTWUtil::PrintErrorMsg(e);

                    if (e.GetID() == eError::CalcHash("eTWUtilCorruptedFile"))
                        cTWUtil::PrintErrorMsg( eTWADecryptCorrupt( manip.GetFileName(), eError::NON_FATAL ));
                    else
					    cTWUtil::PrintErrorMsg( eTWADecrypt( manip.GetFileName(), eError::NON_FATAL ));

                    //cTWUtil::PrintErrorMsg(eTWAEncryptionChange(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_REMOVE_ENCRYPTION_FAILED), manip.GetFileName(), eError::NON_FATAL));
                    lastMsgWasError = true;
                    bResult = false;
                    continue;
                }
            }

            if (cFileManipulator::UseSiteKey(*manip.GetHeaderID()))
            {
                keyType = cTWUtil::KEY_SITE;
                keyfile = mSiteKeyFile;
            }
            else
            {
                keyType = cTWUtil::KEY_LOCAL;
                keyfile = mLocalKeyFile;
            }

            if (NotifyEncryptionType(manip.GetEncoding(), iUserNotify::V_VERBOSE) == false)
            {
                cTWUtil::PrintErrorMsg(eTWAEncryptionChange(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_ENCODING_TYPE_UNKNOWN), manip.GetFileName(), eError::NON_FATAL));
                lastMsgWasError = true;
                bResult = false;
                continue;
            }
            else if (manip.GetEncoding() != cFileHeader::ASYM_ENCRYPTION)
            {
                cTWUtil::PrintErrorMsg(eTWAEncryptionChange(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_FILE_NOT_ENCRYPED), manip.GetFileName(), eError::NON_FATAL));
                lastMsgWasError = true;
				bResult = false;
                continue;
            }
            else
            {
                // If we got here we have an Asymmetrically encrypted file

                // warn user about removing encryption
                if (!warningGiven)
                {
                    iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTWAdmin, twadmin::STR_REMOVE_ENCRYPTION_WARNING).c_str());
					TCERR << std::endl;
                    warningGiven = true;
                }

                cKeyFile key;
                key.ReadFile( keyfile.c_str() );

                if (keyType == cTWUtil::KEY_LOCAL)
                {
                    if (!userKnowsLocalPassphrase)
                    {
						cTWUtil::CreatePrivateKey(key, mLocalPassphraseProvided ? mLocalPassphrase.c_str() : 0, keyType); // note: this throws an exception on failure
						key.ReleasePrivateKey();
						if (!mLatePassphrase) // force user to enter passphrase each time
							userKnowsLocalPassphrase = true;
                    }
                }
                else if (keyType == cTWUtil::KEY_SITE)
                {
                    if (!userKnowsSitePassphrase)
                    {
						// Check to see if we can even use the site key to decrypt this file.
						cTWUtil::CreatePrivateKey(key, mSitePassphraseProvided ? mSitePassphrase.c_str() : 0, keyType); // note: this throws an exception on failure
						key.ReleasePrivateKey();
						if (!mLatePassphrase) // force user to enter passphrase each time
							userKnowsSitePassphrase = true;
                    }
                }
                else
                    ASSERT(false);

                try 
                {
                    manip.ChangeEncryption(key.GetPublicKey(), NULL, false);
                }
                catch(eError& e)
                {
					// Let the user know the decryption failed
                    e.SetSupressThird( true );
                    e.SetFatality( false );
                    cTWUtil::PrintErrorMsg( e );

                    if (e.GetID() == eError::CalcHash("eArchiveCrypto"))
                        cTWUtil::PrintErrorMsg( eTWADecryptCorrupt( manip.GetFileName(), eError::NON_FATAL ));
                    else
					    cTWUtil::PrintErrorMsg( eTWADecrypt( manip.GetFileName(), eError::NON_FATAL ));

                    lastMsgWasError = true;
                    bResult = false;
					continue;
                }

                iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                            TSS_GetString(cTWAdmin, twadmin::STR_ENCRYPTION_REMOVED).c_str(), 
                            cDisplayEncoder::EncodeInline( manip.GetFileName() ).c_str());
            }
        }
        catch (eFileManip& e)
        {
			e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
            lastMsgWasError = true;
            bResult = false;
        }
        catch (eArchive& e)
        {
			e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
            lastMsgWasError = true;
            bResult = false;
        }
    }

    return bResult == false;
}

///////////////////////////////////////////////////////////////////////////////
// cTWAModeEncrypt

class cTWAModeEncrypt : public cTWAModeCommon
{
public:
	cTWAModeEncrypt();
	virtual ~cTWAModeEncrypt();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual TSTRING GetModeUsage() { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_ENCRYPT ); }
    virtual bool    LoadConfigFile() { return true; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_REMOVE_ENCRYPTION; }
private:
    std::list<TSTRING> mFileList;
    wc16_string mSitePassphrase;
    wc16_string mLocalPassphrase;
    bool    mSitePassphraseProvided;
    bool    mLocalPassphraseProvided;
	bool	mbLatePassphrase;
};

cTWAModeEncrypt::cTWAModeEncrypt()
{
    mSitePassphraseProvided = false;
    mLocalPassphraseProvided = false;
    mbLatePassphrase = false;
}

cTWAModeEncrypt::~cTWAModeEncrypt()
{
}

void cTWAModeEncrypt::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

	parser.AddArg(cTWAdminCmdLine::MODE_ENCRYPT,    TSTRING(_T("")),	TSTRING(_T("encrypt")),				cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::SITE_KEY_FILE,	TSTRING(_T("S")),	TSTRING(_T("site-keyfile")),		cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCAL_KEY_FILE,	TSTRING(_T("L")),	TSTRING(_T("local-keyfile")),		cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCALPASSPHRASE,	TSTRING(_T("P")),	TSTRING(_T("local-passphrase")),	cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::SITEPASSPHRASE,	TSTRING(_T("Q")),	TSTRING(_T("site-passphrase")),		cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::PARAMS,	        TSTRING(_T("")),	TSTRING(_T("")),					cCmdLineParser::PARAM_MANY);
}

bool cTWAModeEncrypt::Init(const cConfigFile* cf, const cCmdLineParser& parser)
{
    int i;

    FillOutConfigInfo(cf);

    TSTRING str;
	if(cf->Lookup(TSTRING(_T("LATEPROMPTING")), str))
	{
		if (_tcsicmp(str.c_str(), _T("true")) == 0)
			mbLatePassphrase = true;	
	}

    FillOutCmdLineInfo(parser);

	cCmdLineIter iter(parser);
	for(iter.SeekBegin(); ! iter.Done(); iter.Next())
	{
		switch(iter.ArgId())
		{
        case cTWAdminCmdLine::PARAMS:
            for (i = 0; i < iter.NumParams(); ++i)
            {
                TSTRING strFullPath;
                if( iFSServices::GetInstance()->FullPath( strFullPath, iter.ParamAt(i) ) )
                    mFileList.push_back( strFullPath );
                else
                    mFileList.push_back( iter.ParamAt(i) );
            }
            break;
        case cTWAdminCmdLine::LOCALPASSPHRASE:
            ASSERT(iter.NumParams() == 1);
            mLocalPassphraseProvided = true;
            mLocalPassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
            break;
        case cTWAdminCmdLine::SITEPASSPHRASE:
            ASSERT(iter.NumParams() == 1);
            mSitePassphraseProvided = true;
            mSitePassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
            break;
		}
	}

    
	// check that the config file and site key file are in sync...
	//
	if( ! mCfgFilePath.empty() )
        try 
        {
		    if (cTWUtil::VerifyCfgSiteKey( mCfgFilePath, mSiteKeyFile ) == false)
                cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
        }
        catch (eTWUtilCfgKeyMismatch& e)        
        {
            e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
        }

    return true;
}

int cTWAModeEncrypt::Execute(cErrorQueue* pQueue)
{
    cKeyFile         siteKeyFile, localKeyFile;
    cPrivateKeyProxy siteKey, localKey;

    if (mFileList.empty())
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_FILES_SPECIFIED)));
        return 1;
    }

    bool bResult = true;
    std::list<TSTRING>::iterator i;

    // We cycle through all the files twice.  This first time we 
    // check for file validity and open any keyfiles needed.
    for (i = mFileList.begin(); i != mFileList.end(); /* incrementing done below...*/)
    {
        try
        {
		    if( cFileUtil::IsDir( i->c_str() ) )
		    {
			    // Ignore directories for this particular operation.
                // Note: We don't throw here because we don't want to set bResult to false
                cTWUtil::PrintErrorMsg(eTWASkippingDirectory(*i, eError::NON_FATAL));
                TCERR << std::endl; // extra newline to separate filenames
		        i = mFileList.erase(i);
                continue;
		    }
            else if (!cFileUtil::FileExists(i->c_str()))
            {
                // tell user we could not open *i
                throw eTWAFileNotFound(*i, eError::NON_FATAL);
            }

            cFileManipulator manip(i->c_str());
            manip.Init();

            // can't encrypt keyfiles
            if (*manip.GetHeaderID() == cKeyFile::GetFileHeaderID())
            {
                throw eTWAEncryptionChange(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_CAN_NOT_DECRYPT_KEYFILE), manip.GetFileName(), eError::NON_FATAL);
            }

            if (cFileManipulator::UseSiteKey(*manip.GetHeaderID()))
            {
                if (!siteKeyFile.KeysLoaded())
                    cTWUtil::OpenKeyFile(siteKeyFile, mSiteKeyFile);
            }
            else
            {
                if (!localKeyFile.KeysLoaded())
                    cTWUtil::OpenKeyFile(localKeyFile, mLocalKeyFile);
            }

            // increment the iterator
		    ++i;
        }
        catch (eError& e)
        {
            e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
            TCERR << std::endl; // extra newline to separate filenames

            // erase this file so that it is skipped in the next round
			i = mFileList.erase(i);
            bResult = false;
			continue;
        }
    }
    
    // On this second pass we go through and convert all files            
    for (i = mFileList.begin(); i != mFileList.end(); ++i)
    {
		if( cFileUtil::IsDir( i->c_str() ) )
		{
			// Ignore directories for this particular operation.
		}
        else if (!cFileUtil::FileExists(i->c_str()))
        {
            // tell user we could not open *i
            bResult = false;
        }
        else
        try
        {
            cFileManipulator manip(i->c_str());
            manip.Init();

            if (*manip.GetHeaderID() == cKeyFile::GetFileHeaderID())
            {
                continue;
            }

            iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
            iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL, 
                                               _T("%s %s\n"),
											   TSS_GetString(cTWAdmin, twadmin::STR_EXAMINING_FILE).c_str(), 
                                               cDisplayEncoder::EncodeInline( manip.GetFileName() ).c_str());

            if (NotifyFileType(*manip.GetHeaderID(), manip.GetFileVersion(), iUserNotify::V_VERBOSE) == false)
            {
                cTWUtil::PrintErrorMsg(eTWAFileTypeUnknown(manip.GetFileName(), eError::NON_FATAL));
                TCERR << std::endl; // extra newline to separate filenames
                bResult = false;
            }

            if (NotifyEncryptionType(manip.GetEncoding(), iUserNotify::V_VERBOSE) == false)
            {
                cTWUtil::PrintErrorMsg(eTWAEncryptionChange(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_ENCODING_TYPE_UNKNOWN), manip.GetFileName(), eError::NON_FATAL));
                TCERR << std::endl; // extra newline to separate filenames
                bResult = false;
            }
            else if (manip.GetEncoding() == cFileHeader::ASYM_ENCRYPTION)
            {
                cTWUtil::PrintErrorMsg(eTWAEncryptionChange(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_FILE_ALREADY_ENCRYPTED), manip.GetFileName(), eError::NON_FATAL));
                TCERR << std::endl; // extra newline to separate filenames
                bResult = false;
            }
            else
            {
                cPrivateKeyProxy* pPrivateKey;

                if (cFileManipulator::UseSiteKey(*manip.GetHeaderID()))
                {
                    if (mbLatePassphrase || !siteKey.Valid())
                        cTWUtil::CreatePrivateKey(siteKey, siteKeyFile, mSitePassphraseProvided ? mSitePassphrase.c_str() : 0, cTWUtil::KEY_SITE);
                    
                    pPrivateKey = &siteKey;
                }
                else
                {
                    if (mbLatePassphrase || !localKey.Valid())
                        cTWUtil::CreatePrivateKey(localKey, localKeyFile, mLocalPassphraseProvided ? mLocalPassphrase.c_str() : 0, cTWUtil::KEY_LOCAL);

                    pPrivateKey = &localKey;
                }

                try 
                {
                    manip.ChangeEncryption(NULL, pPrivateKey->GetKey(), false);

                    iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                            TSS_GetString(cTWAdmin, twadmin::STR_ENCRYPTION_SUCCEEDED).c_str(), 
                            cDisplayEncoder::EncodeInline( manip.GetFileName() ).c_str());
                    iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL, 
                            TSS_GetString(cTW, tw::STR_NEWLINE).c_str(), 
                            cDisplayEncoder::EncodeInline( manip.GetFileName() ).c_str());
                }
                catch (eFileManip& e)
                {
                    cTWUtil::PrintErrorMsg(e);
                    TCERR << std::endl; // extra newline to separate filenames
                    bResult = false;
                }
            }
        }
        catch (eFileManip&)
        {
			continue;
        }
    }

    return bResult == false;
}

///////////////////////////////////////////////////////////////////////////////
// cTWAModeExamine

class cTWAModeExamine : public cTWAModeCommon
{
public:
	cTWAModeExamine();
	virtual ~cTWAModeExamine();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual TSTRING GetModeUsage() { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_EXAMINE ); }
    virtual bool    LoadConfigFile() { return true; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_REMOVE_ENCRYPTION; }
private:
    std::list<TSTRING> mFileList;
};

cTWAModeExamine::cTWAModeExamine()
{
}

cTWAModeExamine::~cTWAModeExamine()
{
}

void cTWAModeExamine::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

	parser.AddArg(cTWAdminCmdLine::MODE_EXAMINE,    TSTRING(_T("")),	TSTRING(_T("examine")),				cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::SITE_KEY_FILE,	TSTRING(_T("S")),	TSTRING(_T("site-keyfile")),		cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCAL_KEY_FILE,	TSTRING(_T("L")),	TSTRING(_T("local-keyfile")),		cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::PARAMS,	        TSTRING(_T("")),	TSTRING(_T("")),					cCmdLineParser::PARAM_MANY);
}

bool cTWAModeExamine::Init(const cConfigFile* cf, const cCmdLineParser& parser)
{
    int i;

    FillOutConfigInfo(cf);
    FillOutCmdLineInfo(parser);

	cCmdLineIter iter(parser);
	for(iter.SeekBegin(); ! iter.Done(); iter.Next())
	{
		switch(iter.ArgId())
		{
        case cTWAdminCmdLine::PARAMS:
            for (i = 0; i < iter.NumParams(); ++i)
            {
                TSTRING strFullPath;
                if( iFSServices::GetInstance()->FullPath( strFullPath, iter.ParamAt(i) ) )
                    mFileList.push_back( strFullPath );
                else
                    mFileList.push_back( iter.ParamAt(i) );
            }
            break;
		}
	}

	// check that the config file and site key file are in sync...
	//
	if( ! mCfgFilePath.empty() )
        try 
        {
		    if (cTWUtil::VerifyCfgSiteKey( mCfgFilePath, mSiteKeyFile ) == false)
                cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
        }
        catch (eTWUtilCfgKeyMismatch& e)        
        {
            e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
        }

    return true;
}

int cTWAModeExamine::Execute(cErrorQueue* pQueue)
{
    if (mFileList.empty())
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_NO_FILES_SPECIFIED)));
        return 1;
    }

    bool bResult = true;

    // Open site and local key up front so we can warn if they fail opening
    cKeyFile siteKey, localKey;
    try
    {
        siteKey.ReadFile(mSiteKeyFile.c_str());
    }
    catch (eKeyFile& e)
    {
        e.SetFatality(false);
        cTWUtil::PrintErrorMsg(e);
        bResult = false;
    }
    catch (eError&) 
    {
    }

    try
    {
        localKey.ReadFile(mLocalKeyFile.c_str());
    }
    catch (eKeyFile& e)
    {
        e.SetFatality(false);
        cTWUtil::PrintErrorMsg(e);
        bResult = false;
    }
    catch (eError&) 
    {
    }

    // now iteratate over files to examine
    std::list<TSTRING>::iterator i;
    for (i = mFileList.begin(); i != mFileList.end(); ++i)
    {
		if( cFileUtil::IsDir(i->c_str()))
		{
			//Ignore directories in examine encryption mode.
            cTWUtil::PrintErrorMsg(eTWASkippingDirectory(*i, eError::NON_FATAL));
            TCERR << std::endl; // extra newline to separate filenames
		}
        else if (!cFileUtil::FileExists(i->c_str()))
        {
            // tell user we could not open *i
            cTWUtil::PrintErrorMsg(eTWAFileNotFound(*i, eError::NON_FATAL));
            TCERR << std::endl; // extra newline to separate filenames
            bResult = false;
        }
        else
        try
        {
            cFileManipulator manip(i->c_str());
            manip.Init();

            // print out: "File: filename.ext"
			iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTWAdmin, twadmin::STR_FILE).c_str());
			iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, _T("%s"), cDisplayEncoder::EncodeInline( manip.GetFileName() ).c_str());
			iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTWAdmin, twadmin::STR_ENDQUOTE_NEWLINE).c_str());

            NotifyFileType(*manip.GetHeaderID(), manip.GetFileVersion(), iUserNotify::V_NORMAL);
            NotifyEncryptionType(manip.GetEncoding(), iUserNotify::V_NORMAL);

            // Try different keys to see if they decrypt this file
            if (manip.GetEncoding() == cFileHeader::ASYM_ENCRYPTION)
            {
                // Output the keys that decrypt the file.
				iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL, TSS_GetString(cTWAdmin, twadmin::STR_KEYS_DECRYPT ).c_str());
				iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL, TSS_GetString(cTW, tw::STR_NEWLINE ).c_str());

                bool siteDecrypts = false, localDecrypts = false;
        
                if (siteKey.KeysLoaded())
                try
                {
                    if (manip.TestDecryption(*siteKey.GetPublicKey(), false) != false)
                    {
                        siteDecrypts = true;

						iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTWAdmin, twadmin::STR_SITEKEYFILE ).c_str());

						iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, cDisplayEncoder::EncodeInline( mSiteKeyFile ).c_str());
						iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE ).c_str());
                    }
                }
                catch (eError&) {}

                if (localKey.KeysLoaded())
                try
                {
                    if (manip.TestDecryption(*localKey.GetPublicKey(), false) != false)
                    {
                        localDecrypts = true;
						iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTWAdmin, twadmin::STR_LOCALKEYFILE ).c_str());

						iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, cDisplayEncoder::EncodeInline( mLocalKeyFile ).c_str());
						iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE ).c_str());
                    }
                }
                catch (eError&) {}
            }
			TCOUT << std::endl;
        }
        catch (eFileManip& e)
        {
			e.SetFatality(false);
            cTWUtil::PrintErrorMsg(e);
            TCERR << std::endl;
            bResult = false;
        }
    }

    return bResult == false;
}

///////////////////////////////////////////////////////////////////////////////
// cTWAModeGenerateKeys 

class cTWAModeGenerateKeys : public cTWAModeCommon
{
public:
	cTWAModeGenerateKeys();
	virtual ~cTWAModeGenerateKeys();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual TSTRING GetModeUsage() { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_GENERATE_KEYS ); }
    virtual bool    LoadConfigFile() { return false; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_GENERATE_KEYS; }

private:
    bool        mSiteProvided;	// A site passphrase has been passed.
    wc16_string mSitePassphrase;
    bool        mLocalProvided;	// A local passphrase has been passed.
    wc16_string mLocalPassphrase;
    bool        mGenerateSite;	// A Site key has been specified.
    bool        mGenerateLocal;	// A Local key has been specified.
};

cTWAModeGenerateKeys::cTWAModeGenerateKeys()
{
    mLocalProvided = false;
    mSiteProvided = false;
    mGenerateSite = false;
    mGenerateLocal = false;
}

cTWAModeGenerateKeys::~cTWAModeGenerateKeys()
{
}

void cTWAModeGenerateKeys::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

    parser.AddArg(cTWAdminCmdLine::MODE_GENERATE_KEYS,  TSTRING(_T("")),	TSTRING(_T("generate-keys")),       cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::SITE_KEY_FILE,	    TSTRING(_T("S")),	TSTRING(_T("site-keyfile")),	    cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCAL_KEY_FILE,	    TSTRING(_T("L")),	TSTRING(_T("local-keyfile")),       cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::SITEPASSPHRASE,		TSTRING(_T("Q")),	TSTRING(_T("site-passphrase")),	    cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCALPASSPHRASE,		TSTRING(_T("P")),	TSTRING(_T("local-passphrase")),    cCmdLineParser::PARAM_ONE);
}

bool cTWAModeGenerateKeys::Init(const cConfigFile* cf, const cCmdLineParser& parser)
{
    TSTRING str;

    // Note: we don't use the config file for anything any more.

    FillOutCmdLineInfo(parser);

	cCmdLineIter iter(parser);
	for(iter.SeekBegin(); ! iter.Done(); iter.Next())
	{
		switch(iter.ArgId())
		{
		case cTWAdminCmdLine::SITEPASSPHRASE:
			ASSERT(iter.NumParams() == 1);
            mSitePassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
            mSiteProvided = true;
			break;
		case cTWAdminCmdLine::LOCALPASSPHRASE:
			ASSERT(iter.NumParams() == 1);
            mLocalPassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
            mLocalProvided = true;
			break;
		case cTWAdminCmdLine::SITE_KEY_FILE:
            mGenerateSite = true;
			break;
		case cTWAdminCmdLine::LOCAL_KEY_FILE:
            mGenerateLocal = true;
			break;
		}
	}

    if (mSiteProvided || mLocalProvided)
        iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_KEYGEN_VERBOSE_PASSPHRASES).c_str());

    return true;
}

int cTWAModeGenerateKeys::Execute(cErrorQueue* pQueue)
{
    int i;

    if (!mGenerateSite && !mGenerateLocal)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_KEYS_NOT_SPECIFIED)));
        return 1;
    }

    if ((mGenerateSite && mSiteKeyFile.empty()) ||
        (mGenerateLocal && mLocalKeyFile.empty()))
    {
        // This case should not occur (it should be caught by Init() logic), but in case it does we will spit out 
        // a generic error string.
        ASSERT(false);
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_KEYS_NOT_SPECIFIED)));
        return 1;
    }

    if (!mGenerateSite && mSiteProvided)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_LONE_SITE_PASSPHRASE)));
        return 1;
    }

    if (!mGenerateLocal && mLocalProvided)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_LONE_LOCAL_PASSPHRASE)));
        return 1;
    }

	if( (mSiteProvided && !mGenerateSite) || (mLocalProvided && !mGenerateLocal) )
	{
		//This is an error, a passphrase should not be specified if the corresponding key has not been passed.
		cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_PASSPHRASE_NOKEY)));
		return 1;
	}

    if (mSiteKeyFile == mLocalKeyFile)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_KEY_FILENAMES_IDENTICAL)));
        return 1;
    }

    if (mGenerateSite && cFileUtil::FileExists(mSiteKeyFile))
    {
        TSTRING prompt;
        prompt += TSS_GetString(cTWAdmin, twadmin::STR_SITEKEY_EXISTS_1);
        prompt += cDisplayEncoder::EncodeInline( mSiteKeyFile );
        prompt += TSS_GetString(cTWAdmin, twadmin::STR_SITEKEY_EXISTS_2);

        if (cTWUtil::ConfirmYN(prompt.c_str()) == false)
            return 1;
    }

    if (mGenerateLocal && cFileUtil::FileExists(mLocalKeyFile))
    {
        TSTRING prompt;
        prompt += TSS_GetString(cTWAdmin, twadmin::STR_LOCALKEY_EXISTS_1);
        prompt += cDisplayEncoder::EncodeInline( mLocalKeyFile );
        prompt += TSS_GetString(cTWAdmin, twadmin::STR_LOCALKEY_EXISTS_2);

        if (cTWUtil::ConfirmYN(prompt.c_str()) == false)
            return 1;
    }

	//
	// make sure that we can write to both of the files before we continue
	//
	if(mGenerateLocal)
		cFileUtil::TestFileWritable(mLocalKeyFile);
	if(mGenerateSite)
		cFileUtil::TestFileWritable(mSiteKeyFile);

    wc16_string verify;

	bool bPrintedPassphraseHint = false;

    if (mGenerateSite)
    {
        if (!mSiteProvided)
        {
			// give the user a passphrase hint...
			//
			if(! bPrintedPassphraseHint)
			{
				bPrintedPassphraseHint = true;
				iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, TSS_GetString(cTWAdmin, twadmin::STR_PASSPHRASE_HINT).c_str() );
			}

            for (i=1; ; i++)
            {
				cTWUtil::NoEcho noEcho;
                // Note: Since we are interacting directly with the user here, 
                // I think it is o.k. to use cout directly.
                TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_ENTER_SITE_PASS);
                cTWUtil::GetString(mSitePassphrase);
                TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);

                TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_VERIFY_SITE_PASS);
                cTWUtil::GetString(verify);
                TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);
                
                if ( 0 == verify.compare( mSitePassphrase ) )
                    break;

                TCOUT << TSS_GetString(cTW, tw::STR_ERR_WRONG_PASSPHRASE_SITE) << std::endl;

                if (i == 3)
                    return 1;
            }
        }

        iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_KEYGEN_VERBOSE_SITEKEY).c_str(),
                                           cDisplayEncoder::EncodeInline( mSiteKeyFile ).c_str());

        // backup current file if it exists
        cFileUtil::BackupFile(mSiteKeyFile);

        if (GenerateKey(mSiteKeyFile.c_str(), mSitePassphrase) == false)
            return 1;
    }

    if (mGenerateLocal)
    {
        if (!mLocalProvided)
        {
			// give the user a passphrase hint...
			//
			if(! bPrintedPassphraseHint)
			{
				bPrintedPassphraseHint = true;
				iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, TSS_GetString(cTWAdmin, twadmin::STR_PASSPHRASE_HINT).c_str() );
			}
            
			for (i=1; ; i++)
            {
				cTWUtil::NoEcho noEcho;
                // Note: Since we are interacting directly with the user here, 
                // I think it is o.k. to use cout directly.
                TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_ENTER_LOCAL_PASS);
                cTWUtil::GetString(mLocalPassphrase);
                TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);

                TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_VERIFY_LOCAL_PASS);
                cTWUtil::GetString(verify);
                TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);

                if ( 0 == verify.compare( mLocalPassphrase ) )
                    break;

                TCOUT << TSS_GetString(cTW, tw::STR_ERR_WRONG_PASSPHRASE_LOCAL) << std::endl;

                if (i == 3)
                    return 1;
            }
        }

        iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_KEYGEN_VERBOSE_LOCALKEY).c_str(), 
                                           cDisplayEncoder::EncodeInline( mLocalKeyFile ).c_str());

        // backup current file if it exists
        cFileUtil::BackupFile(mLocalKeyFile);

        if (GenerateKey(mLocalKeyFile.c_str(), mLocalPassphrase) == false)
            return 1;
    }

    return 0;
}

///////////////////////////////////////////////////////////////////////////////
// cTWAModeChangePassphrases 

static bool ChangePassphrase(
	const TCHAR* keyPath, wc16_string passphraseOld, wc16_string passphrase)
{
	// in order to leave original password data intact upon return,
	// we must allocate a BIGENDIAN copy
	// and delete it before we return.
	// auto_ptr does not help (won't work with arrays).
	size_t passphraseLenOld	= passphraseOld.length() * sizeof(WCHAR16);
	size_t passphraseLen	= passphrase   .length() * sizeof(WCHAR16);
	int8 * passphraseCopyOld	= new int8[passphraseLenOld];
	int8 * passphraseCopy		= new int8[passphraseLen];
#ifdef WORDS_BIGENDIAN
	memcpy(passphraseCopyOld,	passphraseOld.data(),	passphraseLenOld);
	memcpy(passphraseCopy,		passphrase   .data(),	passphraseLen);
#else
	swab(passphraseOld.data(),	passphraseCopyOld,		passphraseLenOld);
	swab(passphrase   .data(),	passphraseCopy,			passphraseLen);
#endif

	bool result;
	try {
		cKeyFile keyfile;
		keyfile.ReadFile(keyPath);
		keyfile.ChangePassphrase(
			passphraseCopyOld,	passphraseLenOld,
			passphraseCopy,		passphraseLen);
		keyfile.WriteFile(keyPath);
		result = true;
	}
	catch (eKeyFile & e)
	{
        cTWUtil::PrintErrorMsg(e);
		result = false;
	}
	delete[] passphraseCopyOld;
	delete[] passphraseCopy;
	return result;
}

class cTWAModeChangePassphrases : public cTWAModeCommon
{
public:
	cTWAModeChangePassphrases();
	virtual ~cTWAModeChangePassphrases();
	
	virtual void	InitCmdLineParser(cCmdLineParser& parser);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& parser);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual TSTRING GetModeUsage() { return TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CHANGE_PASSPHRASES ); }
    virtual bool    LoadConfigFile() { return false; }
    virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_CHANGE_PASSPHRASES; }

private:
    bool        mSiteProvidedOld;	// A site passphrase-old has been passed.
    wc16_string mSitePassphraseOld;
    bool        mLocalProvidedOld;	// A local passphrase-old has been passed.
    wc16_string mLocalPassphraseOld;
    bool        mSiteProvided;	// A site passphrase has been passed.
    wc16_string mSitePassphrase;
    bool        mLocalProvided;	// A local passphrase has been passed.
    wc16_string mLocalPassphrase;
    bool        mChangeSite;	// A Site key has been specified.
    bool        mChangeLocal;	// A Local key has been specified.
};

cTWAModeChangePassphrases::cTWAModeChangePassphrases()
{
    mLocalProvidedOld = false;
    mSiteProvidedOld = false;
    mLocalProvided = false;
    mSiteProvided = false;
    mChangeSite = false;
    mChangeLocal = false;
}

cTWAModeChangePassphrases::~cTWAModeChangePassphrases()
{
}

void cTWAModeChangePassphrases::InitCmdLineParser(cCmdLineParser& parser)
{
    InitCmdLineCommon(parser);

    parser.AddArg(cTWAdminCmdLine::MODE_CHANGE_PASSPHRASES,TSTRING(_T("")),	TSTRING(_T("change-passphrases")),   cCmdLineParser::PARAM_NONE);
    parser.AddArg(cTWAdminCmdLine::SITE_KEY_FILE,	    TSTRING(_T("S")),	TSTRING(_T("site-keyfile")),	    cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCAL_KEY_FILE,	    TSTRING(_T("L")),	TSTRING(_T("local-keyfile")),       cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::SITEPASSPHRASE,		TSTRING(_T("Q")),	TSTRING(_T("site-passphrase")),	    cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCALPASSPHRASE,		TSTRING(_T("P")),	TSTRING(_T("local-passphrase")),    cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::SITEPASSPHRASEOLD,	TSTRING(_T("")),	TSTRING(_T("site-passphrase-old")),	    cCmdLineParser::PARAM_ONE);
    parser.AddArg(cTWAdminCmdLine::LOCALPASSPHRASEOLD,	TSTRING(_T("")),	TSTRING(_T("local-passphrase-old")),    cCmdLineParser::PARAM_ONE);
}

bool cTWAModeChangePassphrases::Init(const cConfigFile* cf, const cCmdLineParser& parser)
{
    TSTRING str;

    // Note: we don't use the config file for anything any more.

    FillOutCmdLineInfo(parser);

	cCmdLineIter iter(parser);
	for(iter.SeekBegin(); ! iter.Done(); iter.Next())
	{
		switch(iter.ArgId())
		{
		case cTWAdminCmdLine::SITEPASSPHRASE:
			ASSERT(iter.NumParams() == 1);
            mSitePassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
            mSiteProvided = true;
			break;
		case cTWAdminCmdLine::LOCALPASSPHRASE:
			ASSERT(iter.NumParams() == 1);
            mLocalPassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
            mLocalProvided = true;
			break;
		case cTWAdminCmdLine::SITEPASSPHRASEOLD:
			ASSERT(iter.NumParams() == 1);
            mSitePassphraseOld = cStringUtil::TstrToWstr(iter.ParamAt(0));
            mSiteProvidedOld = true;
			break;
		case cTWAdminCmdLine::LOCALPASSPHRASEOLD:
			ASSERT(iter.NumParams() == 1);
            mLocalPassphraseOld = cStringUtil::TstrToWstr(iter.ParamAt(0));
            mLocalProvidedOld = true;
			break;
		case cTWAdminCmdLine::SITE_KEY_FILE:
            mChangeSite = true;
			break;
		case cTWAdminCmdLine::LOCAL_KEY_FILE:
            mChangeLocal = true;
			break;
		}
	}

    if ((mSiteProvidedOld && mSiteProvided) || (mLocalProvidedOld && mLocalProvided))
        iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_KEYGEN_VERBOSE_PASSPHRASES).c_str());

    return true;
}

int cTWAModeChangePassphrases::Execute(cErrorQueue* pQueue)
{
    int i;
	bool bSiteProvided	= mSiteProvided		|| mSiteProvidedOld;
	bool bLocalProvided	= mLocalProvided	|| mLocalProvidedOld;

    if (!mChangeSite && !mChangeLocal)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_KEYS_NOT_SPECIFIED)));
        return 1;
    }

    if ((mChangeSite && mSiteKeyFile.empty()) ||
        (mChangeLocal && mLocalKeyFile.empty()))
    {
        // This case should not occur (it should be caught by Init() logic), but in case it does we will spit out 
        // a generic error string.
        ASSERT(false);
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_KEYS_NOT_SPECIFIED)));
        return 1;
    }

    if (!mChangeSite && bSiteProvided)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_LONE_SITE_PASSPHRASE)));
        return 1;
    }

    if (!mChangeLocal && bLocalProvided)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_LONE_LOCAL_PASSPHRASE)));
        return 1;
    }

	if( (bSiteProvided && !mChangeSite) || (bLocalProvided && !mChangeLocal) )
	{
		//This is an error, a passphrase should not be specified if the corresponding key has not been passed.
		cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_PASSPHRASE_NOKEY)));
		return 1;
	}

    if (mSiteKeyFile == mLocalKeyFile)
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_KEY_FILENAMES_IDENTICAL)));
        return 1;
    }

    if (mChangeSite && !cFileUtil::FileExists(mSiteKeyFile))
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_SITE_KEY_DOESNT_EXIST)));
        return 1;
    }

    if (mChangeLocal && !cFileUtil::FileExists(mLocalKeyFile))
    {
        cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTWAdmin, twadmin::STR_ERR2_LOCAL_KEY_DOESNT_EXIST)));
        return 1;
    }

	//
	// make sure that we can write to both of the files before we continue
	//
	if(mChangeLocal)
		cFileUtil::TestFileWritable(mLocalKeyFile);
	if(mChangeSite)
		cFileUtil::TestFileWritable(mSiteKeyFile);

    wc16_string verify;

	bool bPrintedPassphraseHint = false;

    if (mChangeSite)
    {
        if (!mSiteProvidedOld)
        {
			cTWUtil::NoEcho noEcho;
			// Note: Since we are interacting directly with the user here, 
			// I think it is o.k. to use cout directly.
			TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_ENTER_SITE_PASS_OLD);
			cTWUtil::GetString(mSitePassphraseOld);
			TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);
        }
        if (!mSiteProvided)
        {
			// give the user a passphrase hint...
			//
			if(! bPrintedPassphraseHint)
			{
				bPrintedPassphraseHint = true;
				iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, TSS_GetString(cTWAdmin, twadmin::STR_PASSPHRASE_HINT).c_str() );
			}

            for (i=1; ; i++)
            {
				cTWUtil::NoEcho noEcho;
                // Note: Since we are interacting directly with the user here, 
                // I think it is o.k. to use cout directly.
                TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_ENTER_SITE_PASS);
                cTWUtil::GetString(mSitePassphrase);
                TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);

                TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_VERIFY_SITE_PASS);
                cTWUtil::GetString(verify);
                TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);
                
                if ( 0 == verify.compare( mSitePassphrase ) )
                    break;

                TCOUT << TSS_GetString(cTW, tw::STR_ERR_WRONG_PASSPHRASE_SITE) << std::endl;

                if (i == 3)
                    return 1;
            }
        }

        iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_KEYGEN_VERBOSE_SITEKEY).c_str(),
                                           cDisplayEncoder::EncodeInline( mSiteKeyFile ).c_str());

        // backup current file if it exists
        cFileUtil::BackupFile(mSiteKeyFile);

        if (ChangePassphrase(mSiteKeyFile.c_str(), mSitePassphraseOld, mSitePassphrase) == false)
            return 1;
    }

    if (mChangeLocal)
    {
        if (!mLocalProvidedOld)
        {
			cTWUtil::NoEcho noEcho;
			// Note: Since we are interacting directly with the user here, 
			// I think it is o.k. to use cout directly.
			TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_ENTER_LOCAL_PASS_OLD);
			cTWUtil::GetString(mLocalPassphraseOld);
			TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);
        }
        if (!mLocalProvided)
        {
			// give the user a passphrase hint...
			//
			if(! bPrintedPassphraseHint)
			{
				bPrintedPassphraseHint = true;
				iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, TSS_GetString(cTWAdmin, twadmin::STR_PASSPHRASE_HINT).c_str() );
			}
            
			for (i=1; ; i++)
            {
				cTWUtil::NoEcho noEcho;
                // Note: Since we are interacting directly with the user here, 
                // I think it is o.k. to use cout directly.
                TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_ENTER_LOCAL_PASS);
                cTWUtil::GetString(mLocalPassphrase);
                TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);

                TCOUT << TSS_GetString(cTWAdmin, twadmin::STR_VERIFY_LOCAL_PASS);
                cTWUtil::GetString(verify);
                TCOUT << TSS_GetString(cTW, tw::STR_NEWLINE);

                if ( 0 == verify.compare( mLocalPassphrase ) )
                    break;

                TCOUT << TSS_GetString(cTW, tw::STR_ERR_WRONG_PASSPHRASE_LOCAL) << std::endl;

                if (i == 3)
                    return 1;
            }
        }

        iUserNotify::GetInstance()->Notify(iUserNotify::V_VERBOSE, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_KEYGEN_VERBOSE_LOCALKEY).c_str(), 
                                           cDisplayEncoder::EncodeInline( mLocalKeyFile ).c_str());

        // backup current file if it exists
        cFileUtil::BackupFile(mLocalKeyFile);

        if (ChangePassphrase(mLocalKeyFile.c_str(), mLocalPassphraseOld, mLocalPassphrase) == false)
            return 1;
    }

    return 0;
}


//#############################################################################
// cTWAModeHelp : A mode for supplying mode specific usage statements
//#############################################################################

class cTWAModeHelp : public iTWAMode
{
public:
	cTWAModeHelp() {}
	virtual ~cTWAModeHelp() {}

	virtual void	InitCmdLineParser(cCmdLineParser& cmdLine);
	virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& cmdLine);
	virtual int		Execute	(cErrorQueue* pQueue);
	virtual cTWAdminCmdLine::CmdLineArgs GetModeID ( void ) const;
	virtual TSTRING GetModeUsage( ) { return _T(""); } //TODO: dra Output something here?
	
private:
	// A list of modes to output usage statements for:
	std::set< TSTRING > mModes;
	std::set< TSTRING > mPrinted;
};

///////////////////////////////////////////////////////////////////////////////
// GetModeID
///////////////////////////////////////////////////////////////////////////////
cTWAdminCmdLine::CmdLineArgs cTWAModeHelp::GetModeID( void ) const
{
	return cTWAdminCmdLine::MODE_HELP;
}

///////////////////////////////////////////////////////////////////////////////
// InitCmdLineParser
///////////////////////////////////////////////////////////////////////////////
void cTWAModeHelp::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(cTWAdminCmdLine::MODE,					TSTRING(_T("m")),	TSTRING(_T("")),				cCmdLineParser::PARAM_MANY, true );
	cmdLine.AddArg(cTWAdminCmdLine::MODE_HELP,				TSTRING(_T("?")),	TSTRING(_T("help")),			cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_HELP_ALL,			TSTRING(_T("")),	TSTRING(_T("all")),				cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_CREATE_CONFIG,		TSTRING(_T("F")),	TSTRING(_T("create-cfgfile")),	cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_PRINT_CONFIG,		TSTRING(_T("f")),	TSTRING(_T("print-cfgfile")),	cCmdLineParser::PARAM_MANY);
    cmdLine.AddArg(cTWAdminCmdLine::MODE_CREATE_POLICY,		TSTRING(_T("P")),	TSTRING(_T("create-polfile")),	cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_PRINT_POLICY,		TSTRING(_T("p")),	TSTRING(_T("print-polfile")),	cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_REMOVE_ENCRYPTION,	TSTRING(_T("R")),	TSTRING(_T("remove-encryption")),	cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_ENCRYPT,			TSTRING(_T("E")),	TSTRING(_T("encrypt")),			cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_EXAMINE,			TSTRING(_T("e")),	TSTRING(_T("examine")),			cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_GENERATE_KEYS,		TSTRING(_T("G")),	TSTRING(_T("generate-keys")),	cCmdLineParser::PARAM_MANY);
	cmdLine.AddArg(cTWAdminCmdLine::MODE_CHANGE_PASSPHRASES,TSTRING(_T("C")),	TSTRING(_T("change-passphrases")),	cCmdLineParser::PARAM_MANY);
}

///////////////////////////////////////////////////////////////////////////////
// Init
///////////////////////////////////////////////////////////////////////////////
bool cTWAModeHelp::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 cTWAdminCmdLine::MODE_HELP:
				{
					int i;
					for( i = 0; i < iter.NumParams(); ++i )
					{
						mModes.insert( iter.ParamAt(i) );
					}
				}
				break;
			case cTWAdminCmdLine::MODE:
				{
					int i;
					for( i = 0; i < iter.NumParams(); ++i )
					{
						mModes.insert( iter.ParamAt(i) );
					}
				}
				break;
			case cTWAdminCmdLine::MODE_HELP_ALL:	//fall through
			case cTWAdminCmdLine::MODE_CREATE_CONFIG: //fall through
			case cTWAdminCmdLine::MODE_PRINT_CONFIG: //fall through
            case cTWAdminCmdLine::MODE_CREATE_POLICY: //fall through
			case cTWAdminCmdLine::MODE_PRINT_POLICY: //fall through
			case cTWAdminCmdLine::MODE_REMOVE_ENCRYPTION: //fall through
			case cTWAdminCmdLine::MODE_ENCRYPT: //fall through
			case cTWAdminCmdLine::MODE_EXAMINE: //fall through
			case cTWAdminCmdLine::MODE_GENERATE_KEYS:
			case cTWAdminCmdLine::MODE_CHANGE_PASSPHRASES:
				{
					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.
					mModes.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 )
						mModes.insert( iter.ParamAt(i) );
				}
			break;
			default:
				// should I do anything, or just ignore this?
				// cmdlineparser will catch the bad args.
				;
		}
	}

    return true;
}

///////////////////////////////////////////////////////////////////////////////
// Execute
///////////////////////////////////////////////////////////////////////////////
int cTWAModeHelp::Execute(cErrorQueue* pQueue)
{
	cDebug d("cTWAModeHelp::Execute");

	// The iterator we will use to traverse the list of arguments:
	std::set< TSTRING >::iterator it = mModes.begin();

	// We'll want to output the version information, regardless:
	TCOUT<< TSS_GetString(cTWAdmin, twadmin::STR_TWADMIN_VERSION ) << std::endl;
	TCOUT<< TSS_GetString(cTW, tw::STR_VERSION ) << std::endl;

	if( it == mModes.end() ) // all that was passed was --help
	{
		// Output a shorter usage statement for each mode
		TCOUT<< TSS_GetString(cTWAdmin, twadmin::STR_TWADMIN_USAGE_SUMMARY);
		//
		//That's it, return
		return 1;
	}

	for( ; it != mModes.end(); ++it )
	{
		if( _tcscmp( (*it).c_str(), _T("all")) == 0 )
		{
			//Since --help all was passed, emit all help messages and return.
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CREATE_CFGFILE );
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_PRINT_CFGFILE );
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CREATE_POLFILE );
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_PRINT_POLFILE );
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_REMOVE_ENCRYPTION );
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_ENCRYPT );
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_EXAMINE );
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_GENERATE_KEYS );
			TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CHANGE_PASSPHRASES );

			//We're done, return
			return 1;
		}
	}
	
	//We need some subset of the usage statements.  Figure out which modes have
	//been specified:
	it = mModes.begin();
	for( ; it != mModes.end(); ++it )
	{
		if ( _tcscmp( (*it).c_str(), _T("create-cfgfile") ) == 0  || _tcscmp( (*it).c_str(), _T("F") ) == 0)
		{
			//make sure we don't print the same help twice...
			if( mPrinted.find(_T("create-cfgfile")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CREATE_CFGFILE );
				mPrinted.insert(_T("create-cfgfile"));
			}
		}
		else if( _tcscmp( (*it).c_str(), _T("print-cfgfile") ) == 0 || _tcscmp( (*it).c_str(), _T("f") ) == 0)
		{
			if( mPrinted.find(_T("print-cfgfile")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_PRINT_CFGFILE );
				mPrinted.insert(_T("print-cfgfile"));
			}
		}
		else if( _tcscmp( (*it).c_str(), _T("create-polfile") ) == 0 || _tcscmp( (*it).c_str(), _T("P") ) == 0)
		{
			if( mPrinted.find(_T("create-polfile")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CREATE_POLFILE );
				mPrinted.insert(_T("create-polfile"));
			}
		}
		else if( _tcscmp( (*it).c_str(), _T("print-polfile") ) == 0 || _tcscmp( (*it).c_str(), _T("p") ) == 0)
		{
			if( mPrinted.find(_T("print-polfile")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_PRINT_POLFILE );
				mPrinted.insert(_T("print-polfile"));
			}
		}
		else if( _tcscmp( (*it).c_str(), _T("remove-encryption") ) == 0 || _tcscmp( (*it).c_str(), _T("R") ) == 0)
		{
			if( mPrinted.find(_T("remove-encryption")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_REMOVE_ENCRYPTION );
				mPrinted.insert(_T("remove-encryption"));
			}
		}
		else if( _tcscmp( (*it).c_str(), _T("encrypt") ) == 0 || _tcscmp( (*it).c_str(), _T("E") ) == 0)
		{
			if( mPrinted.find(_T("encrypt")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_ENCRYPT );
				mPrinted.insert(_T("encrypt"));
			}
		}
		else if( _tcscmp( (*it).c_str(), _T("examine") ) == 0 || _tcscmp( (*it).c_str(), _T("e") ) == 0)
		{
			if( mPrinted.find(_T("examine")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_EXAMINE );
				mPrinted.insert(_T("examine"));
			}
		}
		else if( _tcscmp( (*it).c_str(), _T("generate-keys") ) == 0 || _tcscmp( (*it).c_str(), _T("G") ) == 0)
		{
			if( mPrinted.find(_T("generate-keys")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_GENERATE_KEYS );
				mPrinted.insert(_T("generate-keys"));
			}
		}
		else if( _tcscmp( (*it).c_str(), _T("change-passphrases") ) == 0 || _tcscmp( (*it).c_str(), _T("C") ) == 0)
		{
			if( mPrinted.find(_T("change-passphrases")) == mPrinted.end() )
			{
				TCOUT<< TSS_GetString( cTWAdmin, twadmin::STR_TWADMIN_HELP_CHANGE_PASSPHRASES );
				mPrinted.insert(_T("change-passphrases"));
			}
		}
		else
		{
			cTWUtil::PrintErrorMsg( eTWAInvalidHelpMode( (*it), eError::NON_FATAL ) );
			TCOUT << std::endl;
			// emit error string, this mode does not exist
		}
	}

	//Everything went okay
    return 1;
}

///////////////////////////////////////////////////////////////////////////////
// Version Mode
///////////////////////////////////////////////////////////////////////////////
class cTWAModeVersion : public iTWAMode
{
public:
    cTWAModeVersion() {}
    virtual ~cTWAModeVersion() {}
	
    virtual void	InitCmdLineParser(cCmdLineParser& cmdLine) { ASSERT(false); }
    virtual bool	Init	(const cConfigFile* cf, const cCmdLineParser& cmdLine) { ASSERT(false); return true; }
    virtual int		Execute	(cErrorQueue* pQueue) { ASSERT(false); return 0; }
	virtual TSTRING GetModeUsage( ) { ASSERT(false); return _T(""); }
	virtual cTWAdminCmdLine::CmdLineArgs GetModeID() const { return cTWAdminCmdLine::MODE_VERSION; }
private:
};



//#############################################################################

///////////////////////////////////////////////////////////////////////////////
// cTWAdminCmdLine::GetMode()
//

iTWAMode* cTWAdminCmdLine::GetMode(int argc, const TCHAR *const * argv)
{
	// note -- it is assumed the executable name is the first parameter
	if(argc < 2)
	{
        iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, _T("%s"), TSS_GetString(cTWAdmin, twadmin::STR_TWADMIN_VERSION).c_str());
        iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
        iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, _T("%s"), TSS_GetString(cTW, tw::STR_VERSION).c_str());
        iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
        iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, _T("%s"), TSS_GetString(cTW, tw::STR_GET_HELP).c_str());
        iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
		return NULL;
	}

	int mode = MODE;
	const TCHAR* pcMode;
	if(_tcscmp(argv[1], _T("-m")) == 0)
	{
		if(argc < 3)
		{
            iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, _T("%s"), TSS_GetString(cTWAdmin, twadmin::STR_TWADMIN_VERSION).c_str());
            iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
            iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, _T("%s"), TSS_GetString(cTW, tw::STR_VERSION).c_str());
            iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());

            cTWUtil::PrintErrorMsg(eBadCmdLine(TSS_GetString(cTW, tw::STR_ERR_NO_MODE), eError::SUPRESS_THIRD_MSG));

            iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, _T("%s"), TSS_GetString(cTW, tw::STR_GET_HELP).c_str());
            iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());

            return NULL;
		}
		pcMode = argv[2];
		if		(_tcscmp(argv[2], _T("F")) == 0)
			mode = MODE_CREATE_CONFIG;
		else if	(_tcscmp(argv[2], _T("f")) == 0)
			mode = MODE_PRINT_CONFIG;
		else if	(_tcscmp(argv[2], _T("P")) == 0)
            mode = MODE_CREATE_POLICY;
		else if	(_tcscmp(argv[2], _T("p")) == 0)
			mode = MODE_PRINT_POLICY;
		else if	(_tcscmp(argv[2], _T("R")) == 0)
			mode = MODE_REMOVE_ENCRYPTION;
		else if	(_tcscmp(argv[2], _T("E")) == 0)
			mode = MODE_ENCRYPT;
		else if	(_tcscmp(argv[2], _T("e")) == 0)
			mode = MODE_EXAMINE;
		else if	(_tcscmp(argv[2], _T("G")) == 0)
			mode = MODE_GENERATE_KEYS;
		else if	(_tcscmp(argv[2], _T("C")) == 0)
			mode = MODE_CHANGE_PASSPHRASES;
	}
	else
	{
		pcMode = argv[1];
		if		(_tcscmp(argv[1], _T("--create-cfgfile")) == 0)
			mode = MODE_CREATE_CONFIG;
		else if	(_tcscmp(argv[1], _T("--print-cfgfile")) == 0)
			mode = MODE_PRINT_CONFIG;
		else if	(_tcscmp(argv[1], _T("--create-polfile")) == 0)
			mode = MODE_CREATE_POLICY;
		else if	(_tcscmp(argv[1], _T("--print-polfile")) == 0)
			mode = MODE_PRINT_POLICY;
		else if	(_tcscmp(argv[1], _T("--remove-encryption")) == 0)
			mode = MODE_REMOVE_ENCRYPTION;
		else if	(_tcscmp(argv[1], _T("--encrypt")) == 0)
			mode = MODE_ENCRYPT;
		else if	(_tcscmp(argv[1], _T("--examine")) == 0)
			mode = MODE_EXAMINE;
		else if	(_tcscmp(argv[1], _T("--generate-keys")) == 0)
			mode = MODE_GENERATE_KEYS;
		else if	(_tcscmp(argv[1], _T("--change-passphrases")) == 0)
			mode = MODE_CHANGE_PASSPHRASES;
		else if	(_tcscmp(argv[1], _T("--version")) == 0)
			mode = MODE_VERSION;
	}

    // check for --help flag anywhere in the args
    int i;
    for (i = 1; i < argc; ++i)
        if (_tcscmp(argv[i], _T("--help")) == 0 || _tcscmp(argv[i], _T("-?")) == 0)
        {
			mode = MODE_HELP;
            break;
        }
	
	if(mode == MODE)
	{
		// unknown mode switch
		cDebug d("cTWAdminCmdLine::GetMode");
		d.TraceError("Error: Bad mode switch: %s\n", pcMode);

        TSTRING estr = TSS_GetString(cTW, tw::STR_ERR2_BAD_MODE_SWITCH);
        estr.append(pcMode);
        cTWUtil::PrintErrorMsg(eBadModeSwitch(estr, eError::SUPRESS_THIRD_MSG));
        
        iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, _T("%s"), TSS_GetString(cTW, tw::STR_GET_HELP).c_str());
        iUserNotify::GetInstance()->Notify(iUserNotify::V_SILENT, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
        return NULL;
	}


	iTWAMode* pRtn = 0;
	switch(mode)
	{
	case MODE_CREATE_CONFIG:
		pRtn = new cTWAModeCreateCfg;
		break;
	case MODE_CREATE_POLICY:
		pRtn = new cTWAModeCreatePol;
		break;
    case MODE_PRINT_CONFIG:
		pRtn = new cTWAModePrintCfg;
		break;
    case MODE_PRINT_POLICY:
		pRtn = new cTWAModePrintPol;
		break;
    case MODE_REMOVE_ENCRYPTION:
		pRtn = new cTWAModeRemoveEncryption;
		break;
    case MODE_ENCRYPT:
		pRtn = new cTWAModeEncrypt;
		break;
    case MODE_EXAMINE:
		pRtn = new cTWAModeExamine;
		break;
    case MODE_GENERATE_KEYS:
		pRtn = new cTWAModeGenerateKeys;
		break;
    case MODE_CHANGE_PASSPHRASES:
		pRtn = new cTWAModeChangePassphrases;
		break;
	case MODE_HELP:
		pRtn = new cTWAModeHelp;
		break;
    case MODE_VERSION:
		pRtn = new cTWAModeVersion;
		break;
    default:
		ASSERT(false);
	}

	return pRtn;
}

// Calls UserNotify(V_VERBOSE, ...) to print out type of file specified in cFileHeaderID.
// Returns false if cFileHeaderID not recognized.
// Used in changing and removing encryption algorithms
static bool NotifyFileType(const cFileHeaderID& id, uint32 version, iUserNotify::VerboseLevel vl)
{
    if (id == cFCODatabaseFile::GetFileHeaderID())
    {
        iUserNotify::GetInstance()->Notify(vl, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_FILE_TYPE_DB).c_str(), 
                                           (version & 0xff000000) >> 24,
                                           (version & 0x00ff0000) >> 16, 
                                           (version & 0x0000ff00) >> 8, 
                                           (version & 0x000000ff));
        return true;
    }
    else if (id == cFCOReport::GetFileHeaderID())
    {
        iUserNotify::GetInstance()->Notify(vl, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_FILE_TYPE_REP).c_str(), 
                                           (version & 0xff000000) >> 24,
                                           (version & 0x00ff0000) >> 16, 
                                           (version & 0x0000ff00) >> 8, 
                                           (version & 0x000000ff));
        return true;
    }
    else if (id == cConfigFile::GetFileHeaderID())
    {
        iUserNotify::GetInstance()->Notify(vl, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_FILE_TYPE_CFG).c_str(), 
                                           (version & 0xff000000) >> 24,
                                           (version & 0x00ff0000) >> 16, 
                                           (version & 0x0000ff00) >> 8, 
                                           (version & 0x000000ff));
        return true;
    }
    else if (id == cPolicyFile::GetFileHeaderID())
    {
        iUserNotify::GetInstance()->Notify(vl, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_FILE_TYPE_POL).c_str(), 
                                           (version & 0xff000000) >> 24,
                                           (version & 0x00ff0000) >> 16, 
                                           (version & 0x0000ff00) >> 8, 
                                           (version & 0x000000ff));
        return true;
    }
    else if (id == cKeyFile::GetFileHeaderID())
    {
        iUserNotify::GetInstance()->Notify(vl, 
                                           TSS_GetString(cTWAdmin, twadmin::STR_FILE_TYPE_KEY).c_str(), 
                                           (version & 0xff000000) >> 24,
                                           (version & 0x00ff0000) >> 16, 
                                           (version & 0x0000ff00) >> 8, 
                                           (version & 0x000000ff));
        return true;
    }

    iUserNotify::GetInstance()->Notify(vl, TSS_GetString(cTWAdmin, twadmin::STR_FILE_TYPE_UNK).c_str());
    return false;
}

// Calls UserNotify(V_VERBOSE, ...) to print out type of file specified in cFileHeaderID.
// Returns false if encoding not recognized.
// Used in changing and removing encryption algorithms
static bool NotifyEncryptionType(cFileHeader::Encoding encoding, iUserNotify::VerboseLevel vl)
{
    switch (encoding)
    {
    case cFileHeader::NO_ENCODING:
        iUserNotify::GetInstance()->Notify(vl, TSS_GetString(cTWAdmin, twadmin::STR_ENCRYPT_TYPE_NONE).c_str());
        return true;
    case cFileHeader::COMPRESSED:
        iUserNotify::GetInstance()->Notify(vl, TSS_GetString(cTWAdmin, twadmin::STR_ENCRYPT_TYPE_COMP).c_str());
        return true;
    case cFileHeader::ASYM_ENCRYPTION:
        iUserNotify::GetInstance()->Notify(vl, TSS_GetString(cTWAdmin, twadmin::STR_ENCRYPT_TYPE_ASYM).c_str());
        return true;
    }

    iUserNotify::GetInstance()->Notify(vl, TSS_GetString(cTWAdmin, twadmin::STR_ENCRYPT_TYPE_UNK).c_str());
    return false;
}

