subclass of Utility. git-svn-id: https://svn.microneil.com/svn/SNFUtility/trunk@7 aa37657e-1934-4a5f-aa6d-2d8eab27ff7cmaster
-DSNF_OSTYPE=\"$(SNF_OSTYPE)\" -DDEFAULT_DATA_DIR=\"@datadir@/$(PACKAGE_NAME)\" \ | -DSNF_OSTYPE=\"$(SNF_OSTYPE)\" -DDEFAULT_DATA_DIR=\"@datadir@/$(PACKAGE_NAME)\" \ | ||||
-DSBIN_DIR=\"$(DESTDIR)$(sbindir)\" | -DSBIN_DIR=\"$(DESTDIR)$(sbindir)\" | ||||
noinst_LIBRARIES = \ | |||||
noinst_LIBRARIES = \ | |||||
libUtilityCommon.a | libUtilityCommon.a | ||||
libUtilityCommon_a_SOURCES = \ | |||||
@top_srcdir@/SNFUtility/Common/UtilityConfig.cpp \ | |||||
libUtilityCommon_a_SOURCES = \ | |||||
@top_srcdir@/SNFUtility/Common/Utility.cpp \ | |||||
@top_srcdir@/SNFUtility/Common/UtilityConfig.cpp \ | |||||
@top_srcdir@/SNFUtility/Common/MtaIntegrate.cpp \ | |||||
@top_srcdir@/SNFUtility/Common/FileBackup.cpp | @top_srcdir@/SNFUtility/Common/FileBackup.cpp | ||||
noinst_HEADERS = \ | |||||
@top_srcdir@/SNFUtility/Common/UtilityConfig.hpp \ | |||||
noinst_HEADERS = \ | |||||
@top_srcdir@/SNFUtility/Common/Utility.hpp \ | |||||
@top_srcdir@/SNFUtility/Common/UtilityConfig.hpp \ | |||||
@top_srcdir@/SNFUtility/Common/MtaIntegrate.hpp \ | |||||
@top_srcdir@/SNFUtility/Common/FileBackup.hpp | @top_srcdir@/SNFUtility/Common/FileBackup.hpp | ||||
EXTRA_DIST = \ | |||||
Makefile.am \ | |||||
EXTRA_DIST = \ | |||||
Makefile.am \ | |||||
ChangeLog | ChangeLog | ||||
clean-local: | clean-local: |
// /file MtaIntegrate.cpp | |||||
// | |||||
// Copyright (C) 2011, ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | |||||
// | |||||
// This file contains the functions for MtaIntegrate. | |||||
// | |||||
// $Id$ | |||||
// | |||||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
#include <iostream> | |||||
#include "MtaIntegrate.hpp" | |||||
MtaIntegrate::MtaIntegrate() { | |||||
SetExplain(false); | |||||
SetVerbose(false); | |||||
SetHelp(false); | |||||
} |
// \file MtaIntegrate.hpp | |||||
// | |||||
// Copyright (C) 2011 ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | |||||
// | |||||
// This file defines the MtaIntegrate interface. | |||||
// | |||||
// $Id$ | |||||
// | |||||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
#ifndef MtaIntegratehpp_included | |||||
#define MtaIntegratehpp_included | |||||
#include <string> | |||||
#include "Utility.hpp" | |||||
#include "FileBackup.hpp" | |||||
/// Base class to manage a Sniffer integration with an MTA. | |||||
// | |||||
// This class defines the interface to integrate and unintegrate with an MTA. | |||||
// | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
class MtaIntegrate : public Utility { | |||||
public: | |||||
/// Constructor. | |||||
MtaIntegrate(); | |||||
/// Specifies the operating system type. | |||||
// | |||||
// \param[in] OperatingSystemType is the value of SNF_OSTYPE | |||||
// specified when configuring sniffer for *nix, or "Windows". | |||||
// | |||||
virtual void SetOperatingSystem(std::string OperatingSystemType) = 0; | |||||
/// Integrate with the MTA. | |||||
// | |||||
// If the MTA is already integrated, this method does nothing. | |||||
// | |||||
// \param[in] SaveFile is the object to back up any configuration | |||||
// files. | |||||
// | |||||
virtual void Integrate(FileBackup *SaveFile) = 0; | |||||
/// Unintegrate with the MTA. | |||||
// | |||||
// If the MTA is not integrated, this method does nothing. | |||||
// | |||||
// \param[in] SaveFile is the object to back up any configuration | |||||
// files. | |||||
// | |||||
virtual void Unintegrate(FileBackup *SaveFile) = 0; | |||||
private: | |||||
/// Determine whether the MTA is integrated. | |||||
virtual bool IsIntegrated() = 0; | |||||
}; | |||||
#endif |
// Utility.cpp | |||||
// | |||||
// Copyright (C) 2011, ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | |||||
// | |||||
// This file implements the common functionality for the configuration | |||||
// utilities. | |||||
#include <cerrno> | |||||
#include <cstring> | |||||
#include <unistd.h> | |||||
#include <pwd.h> | |||||
#include <sys/types.h> | |||||
#include <sys/stat.h> | |||||
#include <stdexcept> | |||||
#include <sstream> | |||||
#include <iostream> | |||||
#include <fstream> | |||||
#include <vector> | |||||
#include "Utility.hpp" | |||||
using namespace std; | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
const std::string Utility::DirectorySeparator("/"); | |||||
/// SNF user name. | |||||
const string SNFUserName = "snfuser"; | |||||
/// SNF group name. | |||||
const string SNFGroupName = "snfuser"; | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
bool | |||||
Utility::FileExists(const std::string File) { | |||||
if (Verbose()) { | |||||
cout << "Check whether " << File << " exists..."; | |||||
} | |||||
bool Exists; | |||||
std::ifstream Input; | |||||
errno = 0; | |||||
Input.open(File.c_str()); | |||||
if (ENOENT == errno) { | |||||
Exists = false; | |||||
} else { | |||||
Exists = true; | |||||
} | |||||
Input.close(); | |||||
OutputVerboseEnd(); | |||||
return Exists; | |||||
} | |||||
void | |||||
Utility::Copy(std::string From, std::string To) { | |||||
if (Verbose()) { | |||||
cout << "Copy " << From << " to " << To << "..."; | |||||
} | |||||
if (!Explain()) { | |||||
std::ifstream Input; | |||||
Input.open(From.c_str()); | |||||
if (!Input) { | |||||
std::string Temp; | |||||
Temp = "Error opening the file " + From; | |||||
Temp += " to read from: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
std::ofstream Output; | |||||
Output.open(To.c_str(), std::ios::trunc); | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Error opening the file " + To; | |||||
Temp += " to copy to: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
if (!Input.eof()) { // Copy if there are characters. | |||||
// Copying an empty file causes | |||||
Output << Input.rdbuf(); // failbit to be set. | |||||
} | |||||
if (Output.bad() || Output.fail()) { | |||||
std::string Temp; | |||||
Temp = "Error copying " + From; | |||||
Temp += " to " + To; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Input.close(); | |||||
if (!Input) { | |||||
std::string Temp; | |||||
Temp = "Error closing the file " + From; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Output.close(); | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Error closing the file " + To; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
void | |||||
Utility::SetOwnerGroup(std::string &File) { | |||||
struct passwd *SNFPasswd; | |||||
uid_t SNFUid; | |||||
struct group *SNFGroup; | |||||
gid_t SNFGid; | |||||
if (Verbose()) { | |||||
cout << "Set owner:group of " << File << " to " | |||||
<< SNFUserName << ":" << SNFGroupName << "..."; | |||||
} | |||||
if (!Explain()) { | |||||
SNFPasswd = getpwnam(SNFUserName.c_str()); | |||||
if (SNFPasswd == 0) { | |||||
string Temp; | |||||
Temp = "Error getting info for Sniffer user " + SNFUserName; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
SNFUid = SNFPasswd->pw_uid; | |||||
SNFGid = SNFPasswd->pw_gid; | |||||
if (chown(File.c_str(), SNFUid, SNFGid) != 0) { | |||||
string Temp; | |||||
Temp = "Error changing group and owner of file " + File; | |||||
Temp += " to " + SNFUserName + ":" + SNFGroupName; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
void | |||||
Utility::SetMode(std::string &File, mode_t mode) { | |||||
if (Verbose()) { | |||||
cout << "Set mode of " << File << " to " | |||||
<< std::oct << mode << "..."; | |||||
} | |||||
if (!Explain()) { | |||||
if (chmod(File.c_str(), mode) != 0) { | |||||
ostringstream Temp; | |||||
Temp << "Error changing permissions of file " << File | |||||
<< " to " << mode << ": " << strerror(errno); | |||||
throw runtime_error(Temp.str()); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
void | |||||
Utility::MkDir(std::string &Dir) { | |||||
if (Verbose()) { | |||||
cout << "Create directory " << Dir << "..."; | |||||
} | |||||
if (!Explain()) { | |||||
if (mkdir(Dir.c_str(), 0) != 0) { | |||||
ostringstream Temp; | |||||
Temp << "Error creating directory " << Dir << ": " << strerror(errno); | |||||
throw runtime_error(Temp.str()); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
bool | |||||
Utility::CheckForString(std::string Line, std::string SearchString) { | |||||
string::size_type Indx; | |||||
Indx = Line.find_first_not_of(" \t"); // Trim leading whitespace. | |||||
if (string::npos != Indx) { | |||||
Line = Line.substr(Indx); | |||||
} | |||||
if (Line.substr(0, SearchString.length()) == SearchString) { | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
void | |||||
Utility::SetVerbose(bool Mode) { | |||||
VerboseRequested = Mode; | |||||
} | |||||
bool | |||||
Utility::Verbose() { | |||||
return (VerboseRequested || ExplainRequested); | |||||
} | |||||
void | |||||
Utility::SetExplain(bool Mode) { | |||||
ExplainRequested = Mode; | |||||
} | |||||
bool | |||||
Utility::Explain() { | |||||
return ExplainRequested; | |||||
} | |||||
void | |||||
Utility::SetHelp(bool Mode) { | |||||
HelpRequested = Mode; | |||||
} | |||||
bool | |||||
Utility::Help() { | |||||
return HelpRequested; | |||||
} | |||||
void | |||||
Utility::OutputVerboseEnd() { | |||||
if (Verbose() && !Explain()) { | |||||
cout << "done.\n"; | |||||
} else if (Explain()) { | |||||
cout << "\n"; | |||||
} | |||||
} |
// Utility.hpp | |||||
// | |||||
// Copyright (C) 2011 ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | |||||
// | |||||
// This file defines the interface used by the configuration utilities. | |||||
// | |||||
#ifndef Utilityhpp_included | |||||
#define Utilityhpp_included | |||||
#include <sys/stat.h> | |||||
#include <string> | |||||
/// Base class for the Sniffer configuration. | |||||
// | |||||
// This class provides capability common to the configuration classes. | |||||
// | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
class Utility { | |||||
public: | |||||
/// Default constructor. | |||||
Utility(); | |||||
/// Check whether a file exists. | |||||
// | |||||
// \returns true if the file exists, false otherwise. | |||||
// | |||||
bool FileExists(std::string File); | |||||
/// Copy a file. | |||||
// | |||||
// \param[in] From is the name of the source file. | |||||
// | |||||
// \param[in] To is the name of the destination file. | |||||
// | |||||
void Copy(std::string From, std::string To); | |||||
/// Set the owner and group of the specified file. | |||||
// | |||||
// This function sets the owner and group of the specified file to the | |||||
// value specified in Utility.cpp. | |||||
// | |||||
// \param[in] File is the specified file. | |||||
// | |||||
// \see SNFUserName. | |||||
// | |||||
// \see SNFGroupName. | |||||
// | |||||
void SetOwnerGroup(std::string &File); | |||||
/// Set the mode of a file. | |||||
// | |||||
// This function sets the mode of the specified file. If an error | |||||
// occurs, an exception is thrown. | |||||
// | |||||
// \param[in] File is the specified file. | |||||
// | |||||
// \param[in] is the mode. | |||||
// | |||||
void SetMode(std::string &File, mode_t mode); | |||||
/// Create a directory. | |||||
// | |||||
// This function creates the specified directory. If an error | |||||
// occurs, an exception is thrown. | |||||
// | |||||
// \param[in] Dir is the directory to create. | |||||
// | |||||
void MkDir(std::string &Dir); | |||||
/// Check for a specified string at the beginning of a line. | |||||
// | |||||
// This function checks for the specified string at the beginning of a | |||||
// line. Leading whitespace in the line is ignored. | |||||
// | |||||
// \param[in] Line is the line. | |||||
// | |||||
// \param[in] SearchString is the string to check for. | |||||
// | |||||
static bool CheckForString(std::string Line, std::string SearchString); | |||||
/// Store the Verbose mode. | |||||
// | |||||
// \param[in] Mode stores the Verbose mode. | |||||
// | |||||
void SetVerbose(bool Mode); | |||||
/// Provide verbose output? | |||||
// | |||||
// \returns true if the application is to provide verbose output. | |||||
// | |||||
bool Verbose(); | |||||
/// Store the Explain mode. | |||||
// | |||||
// \param[in] Mode stores the Explain mode. | |||||
// | |||||
void SetExplain(bool Mode); | |||||
/// Provide an explanation of the actions only? | |||||
// | |||||
// \returns true if the application is to provide an explanation | |||||
// of the actions without executing any commands. | |||||
// | |||||
bool Explain(); | |||||
/// Store the Help mode. | |||||
// | |||||
// \param[in] Mode stores the Help mode. | |||||
// | |||||
void SetHelp(bool Mode); | |||||
/// Provide help? | |||||
// | |||||
// \returns true if the application is to output a help message. | |||||
// | |||||
bool Help(); | |||||
/// Output the end of a verbose output line. | |||||
void OutputVerboseEnd(); | |||||
/// Directory separator. | |||||
static const std::string DirectorySeparator; | |||||
private: | |||||
bool VerboseRequested; ///< User requested verbose processing. | |||||
bool ExplainRequested; ///< User requested verbose processing but without actually executing the commands. | |||||
bool HelpRequested; ///< User requested help. | |||||
}; | |||||
#endif |
#ifdef WIN | #ifdef WIN | ||||
// Windows OS. | // Windows OS. | ||||
const std::string UtilityConfig::OperatingSystemType("Windows"); | const std::string UtilityConfig::OperatingSystemType("Windows"); | ||||
const std::string DirectorySeparator("\\"); | |||||
#else | #else | ||||
const std::string DirectorySeparator("/"); | |||||
#ifdef SNF_OSTYPE | #ifdef SNF_OSTYPE | ||||
// *nix, SNF_OSTYPE is specified on the compile command line. | // *nix, SNF_OSTYPE is specified on the compile command line. | ||||
const std::string UtilityConfig::OperatingSystemType(SNF_OSTYPE); | const std::string UtilityConfig::OperatingSystemType(SNF_OSTYPE); | ||||
#endif | #endif | ||||
#endif | #endif | ||||
/// SNF user name. | |||||
const string SNFUserName = "snfuser"; | |||||
/// SNF group name. | |||||
const string SNFGroupName = "snfuser"; | |||||
/// Verbose command-line input. | /// Verbose command-line input. | ||||
const string VerboseKey("-v"); | const string VerboseKey("-v"); | ||||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | // End of configuration. ///////////////////////////////////////////////////////////////////////////////// | ||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
UtilityConfig::UtilityConfig() : | |||||
ExplainRequested(false), VerboseRequested(false), HelpRequested(false) { | |||||
} | |||||
bool | |||||
UtilityConfig::FileExists(const std::string File) { | |||||
if (Verbose()) { | |||||
cout << "Check whether " << File << " exists..."; | |||||
} | |||||
struct stat StatBuf; | |||||
if (0 != stat(File.c_str(), &StatBuf)) { // Error checking whether file exists. | |||||
UtilityConfig::UtilityConfig() { | |||||
if (ENOENT == errno) { // Doesn't exist. | |||||
OutputVerboseEnd(); | |||||
return false; | |||||
} | |||||
string Temp; // Other error from stat(). | |||||
Temp = "Error getting info for file " + File; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
OutputVerboseEnd(); | |||||
SetExplain(false); | |||||
SetVerbose(false); | |||||
SetHelp(false); | |||||
return true; | |||||
} | |||||
} | |||||
void | void | ||||
UtilityConfig::CheckAndLoadConfigFile(const std::string DefaultFile[], int NumDefaultFiles) { | UtilityConfig::CheckAndLoadConfigFile(const std::string DefaultFile[], int NumDefaultFiles) { | ||||
} | } | ||||
void | |||||
UtilityConfig::Copy(std::string From, std::string To) { | |||||
if (Verbose()) { | |||||
cout << "Copy " << From << " to " << To << "..."; | |||||
} | |||||
if (!Explain()) { | |||||
ifstream Input; | |||||
Input.open(From.c_str()); // Read the contents. | |||||
if (!Input) { | |||||
string Temp; | |||||
Temp = "Error opening the file " + From; | |||||
Temp += " to copy from: "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
string Content; | |||||
string Line; | |||||
while (getline(Input, Line)) { | |||||
Content += Line + "\n"; // Copy this line. | |||||
} | |||||
if (!Input.eof()) { // Should be at end-of-file. | |||||
string Temp; | |||||
Temp = "Error reading the " + From; | |||||
Temp += " to copy from: "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
Input.close(); | |||||
if (Input.bad()) { | |||||
string Temp; | |||||
Temp = "Error closing the file " + From; | |||||
Temp += " to copy from: "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
ofstream Output; // Write the contents. | |||||
Output.open(To.c_str(), ios::trunc); | |||||
if (!Output) { | |||||
string Temp; | |||||
Temp = "Error opening the file " + To; | |||||
Temp += " to copy to: "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
Output << Content; | |||||
if (!Output) { | |||||
string Temp; | |||||
Temp = "Error writing the file " + To; | |||||
Temp += " to copy to: "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
Output.close(); | |||||
if (!Output) { | |||||
string Temp; | |||||
Temp = "Error closing the file " + To; | |||||
Temp += " to copy to: "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
void | |||||
UtilityConfig::SetOwnerGroup(std::string &File) { | |||||
struct passwd *SNFPasswd; | |||||
uid_t SNFUid; | |||||
struct group *SNFGroup; | |||||
gid_t SNFGid; | |||||
if (Verbose()) { | |||||
cout << "Set owner:group of " << File << " to " | |||||
<< SNFUserName << ":" << SNFGroupName << "..."; | |||||
} | |||||
if (!Explain()) { | |||||
SNFPasswd = getpwnam(SNFUserName.c_str()); | |||||
if (SNFPasswd == 0) { | |||||
string Temp; | |||||
Temp = "Error getting info for Sniffer user " + SNFUserName; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
SNFUid = SNFPasswd->pw_uid; | |||||
SNFGid = SNFPasswd->pw_gid; | |||||
if (chown(File.c_str(), SNFUid, SNFGid) != 0) { | |||||
string Temp; | |||||
Temp = "Error changing group and owner of file " + File; | |||||
Temp += " to " + SNFUserName + ":" + SNFGroupName; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw runtime_error(Temp); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
void | |||||
UtilityConfig::SetMode(std::string &File, mode_t mode) { | |||||
if (Verbose()) { | |||||
cout << "Set mode of " << File << " to " | |||||
<< std::oct << mode << "..."; | |||||
} | |||||
if (!Explain()) { | |||||
if (chmod(File.c_str(), mode) != 0) { | |||||
ostringstream Temp; | |||||
Temp << "Error changing permissions of file " << File | |||||
<< " to " << mode << ": " << strerror(errno); | |||||
throw runtime_error(Temp.str()); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
void | |||||
UtilityConfig::MkDir(std::string &Dir) { | |||||
if (Verbose()) { | |||||
cout << "Create directory " << Dir << "..."; | |||||
} | |||||
if (!Explain()) { | |||||
if (mkdir(Dir.c_str(), 0) != 0) { | |||||
ostringstream Temp; | |||||
Temp << "Error creating directory " << Dir << ": " << strerror(errno); | |||||
throw runtime_error(Temp.str()); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
void | void | ||||
UtilityConfig::StartOrRestartMta(std::string Mta) { | UtilityConfig::StartOrRestartMta(std::string Mta) { | ||||
} | } | ||||
bool | |||||
UtilityConfig::CheckForString(std::string Line, std::string SearchString) { | |||||
string::size_type Indx; | |||||
Indx = Line.find_first_not_of(" \t"); // Trim leading whitespace. | |||||
if (string::npos != Indx) { | |||||
Line = Line.substr(Indx); | |||||
} | |||||
if (Line.substr(0, SearchString.length()) == SearchString) { | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
void | void | ||||
UtilityConfig::LoadInfo(){ | UtilityConfig::LoadInfo(){ | ||||
IgnoreListFile = IgnoreListPath + DirectorySeparator; | IgnoreListFile = IgnoreListPath + DirectorySeparator; | ||||
IgnoreListFile += "GBUdbIgnoreList.txt"; | IgnoreListFile += "GBUdbIgnoreList.txt"; | ||||
SaveFile.CreateBackupFile(IgnoreListFile); // Save any existing file. | |||||
if (!FileExists(IgnoreListFile)) { | if (!FileExists(IgnoreListFile)) { | ||||
Copy(SampleIgnoreListFile, IgnoreListFile); // Use SNFMilter.xml.sample. | |||||
Copy(SampleIgnoreListFile, IgnoreListFile); // Use SNFMilter.xml.sample. | |||||
} | } | ||||
SetMode(IgnoreListFile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); // Set permissions. | |||||
SetOwnerGroup(IgnoreListFile); // Set to sniffer user. | |||||
SetMode(IgnoreListFile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); // Set permissions. | |||||
SetOwnerGroup(IgnoreListFile); // Set to sniffer user. | |||||
} | } | ||||
if (OneInput == VerboseKey) { | if (OneInput == VerboseKey) { | ||||
VerboseRequested = true; | |||||
SetVerbose(true); | |||||
ValidCommand = true; | ValidCommand = true; | ||||
} else if (OneInput == ExplainKey) { | } else if (OneInput == ExplainKey) { | ||||
ExplainRequested = true; | |||||
SetExplain(true); | |||||
ValidCommand = true; | ValidCommand = true; | ||||
} else if (OneInput == HelpKey) { | } else if (OneInput == HelpKey) { | ||||
HelpRequested = true; | |||||
SetHelp(true); | |||||
ValidCommand = true; | ValidCommand = true; | ||||
} | } | ||||
} | } | ||||
bool | |||||
UtilityConfig::Verbose() { | |||||
return (VerboseRequested || ExplainRequested); | |||||
} | |||||
bool | |||||
UtilityConfig::Explain() { | |||||
return ExplainRequested; | |||||
} | |||||
bool | |||||
UtilityConfig::Help() { | |||||
return HelpRequested; | |||||
} | |||||
std::string | std::string | ||||
UtilityConfig::HelpCommandLine() { | UtilityConfig::HelpCommandLine() { | ||||
return Desc; | return Desc; | ||||
} | } | ||||
void | |||||
UtilityConfig::OutputVerboseEnd() { | |||||
if (Verbose() && !Explain()) { | |||||
cout << "done.\n"; | |||||
} else if (Explain()) { | |||||
cout << "\n"; | |||||
} | |||||
} |
#ifndef UtilityConfighpp_included | #ifndef UtilityConfighpp_included | ||||
#define UtilityConfighpp_included | #define UtilityConfighpp_included | ||||
#include "SNFMulti.hpp" | |||||
#include <string> | #include <string> | ||||
#include "SNFMulti.hpp" | |||||
#include "Utility.hpp" | |||||
#include "FileBackup.hpp" | |||||
/// Base class for the Sniffer configuration. | /// Base class for the Sniffer configuration. | ||||
// | // | ||||
// This class provides capability common to the configuration applications. | // This class provides capability common to the configuration applications. | ||||
// | // | ||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
class UtilityConfig { | |||||
class UtilityConfig : public Utility { | |||||
public: | public: | ||||
/// Default constructor. | /// Default constructor. | ||||
UtilityConfig(); | UtilityConfig(); | ||||
/// Check whether a file exists. | |||||
// | |||||
// \returns true if the file exists, false otherwise. | |||||
// | |||||
bool FileExists(std::string File); | |||||
/// Object to back up and restore files. | |||||
FileBackup SaveFile; | |||||
/// Load the specified or default config file. | /// Load the specified or default config file. | ||||
// | // | ||||
// \returns the rulebase script file name. | // \returns the rulebase script file name. | ||||
std::string GetRulebaseScriptName(void); | std::string GetRulebaseScriptName(void); | ||||
/// Copy a file. | |||||
// | |||||
// \param[in] From is the name of the source file. | |||||
// | |||||
// \param[in] To is the name of the destination file. | |||||
// | |||||
void Copy(std::string From, std::string To); | |||||
/// Set the owner and group of the specified file. | |||||
// | |||||
// This function sets the owner and group of the specified file to the | |||||
// value specified in UtilityConfig.cpp. | |||||
// | |||||
// \param[in] File is the specified file. | |||||
// | |||||
// \see SNFUserName. | |||||
// | |||||
// \see SNFGroupName. | |||||
// | |||||
void SetOwnerGroup(std::string &File); | |||||
/// Set the mode of a file. | |||||
// | |||||
// This function sets the mode of the specified file. If an error | |||||
// occurs, an exception is thrown. | |||||
// | |||||
// \param[in] File is the specified file. | |||||
// | |||||
// \param[in] is the mode. | |||||
// | |||||
void SetMode(std::string &File, mode_t mode); | |||||
/// Create a directory. | |||||
// | |||||
// This function creates the specified directory. If an error | |||||
// occurs, an exception is thrown. | |||||
// | |||||
// \param[in] Dir is the directory to create. | |||||
// | |||||
void MkDir(std::string &Dir); | |||||
/// Restart the MTA. | /// Restart the MTA. | ||||
// | // | ||||
// This function starts or restarts the MTA. | // This function starts or restarts the MTA. | ||||
// | // | ||||
void StartOrRestartMta(std::string Mta); | void StartOrRestartMta(std::string Mta); | ||||
/// Check for a specified string at the beginning of a line. | |||||
// | |||||
// This function checks for the specified string at the beginning of a | |||||
// line. Leading whitespace in the line is ignored. | |||||
// | |||||
// \param[in] Line is the line. | |||||
// | |||||
// \param[in] SearchString is the string to check for. | |||||
// | |||||
static bool CheckForString(std::string Line, std::string SearchString); | |||||
/// Operating system specification. | /// Operating system specification. | ||||
enum OperatingSystemSpecEnum { | enum OperatingSystemSpecEnum { | ||||
OpenBSD, ///< OpenBSD OS. | OpenBSD, ///< OpenBSD OS. | ||||
/// Postfix main.cf file path. | /// Postfix main.cf file path. | ||||
std::string PostfixMainCfPath; | std::string PostfixMainCfPath; | ||||
/// Postfix main.cf file path. | |||||
/// Postfix master.cf file path. | |||||
std::string PostfixMasterCfPath; | std::string PostfixMasterCfPath; | ||||
/// Create or update the ignore list file. | /// Create or update the ignore list file. | ||||
// | // | ||||
bool ProcessCommandLineItem(std::string OneInput); | bool ProcessCommandLineItem(std::string OneInput); | ||||
/// Provide verbose output? | |||||
// | |||||
// \returns true if the application is to provide verbose output. | |||||
// | |||||
bool Verbose(); | |||||
/// Provide an explanation of the actions only? | |||||
// | |||||
// \returns true if the application is to provide an explanation | |||||
// of the actions without executing any commands. | |||||
// | |||||
bool Explain(); | |||||
/// Provide help? | |||||
// | |||||
// \returns true if the application is to output a help message. | |||||
// | |||||
bool Help(); | |||||
/// Output the legal command-line input. | /// Output the legal command-line input. | ||||
std::string HelpCommandLine(); | std::string HelpCommandLine(); | ||||
/// Output the description of the legal command-line input. | /// Output the description of the legal command-line input. | ||||
std::string HelpDescription(); | std::string HelpDescription(); | ||||
/// Output the end of a verbose output line. | |||||
void OutputVerboseEnd(); | |||||
private: | private: | ||||
bool VerboseRequested; ///< User requested verbose processing. | |||||
bool ExplainRequested; ///< User requested verbose processing but without actually executing the commands. | |||||
bool HelpRequested; ///< User requested help. | |||||
std::string ConfigFile; ///< Configuration file name. | std::string ConfigFile; ///< Configuration file name. | ||||
static const std::string SampleIgnoreListFile; ///< Sample ignore list file. | static const std::string SampleIgnoreListFile; ///< Sample ignore list file. | ||||
static const std::string SampleRulebaseScriptFile; ///< Sample rulebase script file. | static const std::string SampleRulebaseScriptFile; ///< Sample rulebase script file. |
SNFMilterConfig_SOURCES = \ | SNFMilterConfig_SOURCES = \ | ||||
@top_srcdir@/SNFUtility/SNFMilterConfig/main.cpp \ | @top_srcdir@/SNFUtility/SNFMilterConfig/main.cpp \ | ||||
@top_srcdir@/SNFUtility/SNFMilterConfig/SNFMilterConfig.cpp | |||||
@top_srcdir@/SNFUtility/SNFMilterConfig/SNFMilterConfig.cpp \ | |||||
@top_srcdir@/SNFUtility/SNFMilterConfig/PostfixIntegrate.cpp | |||||
noinst_HEADERS = \ | noinst_HEADERS = \ | ||||
@top_srcdir@/SNFUtility/SNFMilterConfig/SNFMilterConfig.hpp | |||||
@top_srcdir@/SNFUtility/SNFMilterConfig/SNFMilterConfig.hpp \ | |||||
@top_srcdir@/SNFUtility/SNFMilterConfig/PostfixIntegrate.hpp | |||||
EXTRA_DIST = \ | EXTRA_DIST = \ | ||||
Makefile.am \ | Makefile.am \ |
// /file PostfixIntegrate.cpp | |||||
// | |||||
// Copyright (C) 2011, ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | |||||
// | |||||
// This file contains the functions for PostfixIntegrate. | |||||
// | |||||
// $Id$ | |||||
// | |||||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
#include <errno.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | |||||
#include <sys/types.h> | |||||
#include <pwd.h> | |||||
#include <sys/types.h> | |||||
#include <sys/stat.h> | |||||
#include <unistd.h> | |||||
#include <iostream> | |||||
#include <exception> | |||||
#include <stdexcept> | |||||
#include <sstream> | |||||
#include <fstream> | |||||
#include <vector> | |||||
#include "PostfixIntegrate.hpp" | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
// Configuration. //////////////////////////////////////////////////////////////////////////////////////// | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
const std::string SnfMilterMainCfSearchString("Added by PostfixIntegrate"); | |||||
const std::string SnfMilterMainCfIntegrationString("smtpd_milters = unix:/var/snf-milter/socket $smtpd_milters # Added by PostfixIntegrate"); | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
// End of configuration. ///////////////////////////////////////////////////////////////////////////////// | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
void | |||||
PostfixIntegrate::SetOperatingSystem(std::string OperatingSystemType) { | |||||
if ("OpenBSD" == OperatingSystemType) { | |||||
PostfixMainCfPath = "/usr/local/etc/postfix/main.cf"; | |||||
PostfixMasterCfPath = "/usr/local/etc/postfix/master.cf"; | |||||
} else if ("FreeBSD" == OperatingSystemType) { | |||||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||||
} else if ("Ubuntu" == OperatingSystemType) { | |||||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||||
} else if ("RedHat" == OperatingSystemType) { | |||||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||||
} else if ("Suse" == OperatingSystemType) { | |||||
PostfixMainCfPath = "/etc/postfix/main.cf"; | |||||
PostfixMasterCfPath = "/etc/postfix/master.cf"; | |||||
} else { | |||||
std::ostringstream Temp; | |||||
Temp << "***Error from PostfixIntegrate::SetOperatingSystem: Invalid value of OperatingSystemType: " | |||||
<< OperatingSystemType; | |||||
throw std::runtime_error(Temp.str()); | |||||
} | |||||
} | |||||
void | |||||
PostfixIntegrate::Integrate(FileBackup *SaveFile) { | |||||
if (IsIntegrated()) { | |||||
return; | |||||
} | |||||
if (Verbose()) { | |||||
std::cout << "Add to postfix file " << PostfixMainCfPath << ": '" | |||||
<< SnfMilterMainCfIntegrationString << "'..."; | |||||
} | |||||
if (!Explain()) { | |||||
std::ofstream Output; // Append the configuration. | |||||
Output.open(PostfixMainCfPath.c_str(), std::ios::app); | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Error opening the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += " for writing: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Output << SnfMilterMainCfIntegrationString << "\n"; | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Error appending to the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Output.close(); | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Error closing the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += " after appending: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
void | |||||
PostfixIntegrate::Unintegrate(FileBackup *SaveFile) { | |||||
if (!IsIntegrated()) { | |||||
return; | |||||
} | |||||
std::ifstream Input; | |||||
if (Verbose()) { | |||||
std::cout << "Remove integration in postfix file " << PostfixMainCfPath << "--\n"; | |||||
} | |||||
Input.open(PostfixMainCfPath.c_str()); // Read the contents. | |||||
if (!Input) { | |||||
std::string Temp; | |||||
Temp = "Error opening the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += " for reading: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
std::string Content; | |||||
std::string Line; | |||||
while (getline(Input, Line)) { | |||||
if (std::string::npos != Line.find(SnfMilterMainCfSearchString)) { // Check for integration line. | |||||
if (Verbose()) { | |||||
std::cout << " Remove '" << Line << "'...\n"; | |||||
} | |||||
continue; // Do not copy this line. | |||||
} | |||||
Content += Line + "\n"; // Copy this line. | |||||
} | |||||
if (!Input.eof()) { // Should be at end-of-file. | |||||
std::string Temp; | |||||
Temp = "Error reading the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Input.close(); | |||||
if (Input.bad()) { | |||||
std::string Temp; | |||||
Temp = "Error closing the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += " after reading: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
if (!Explain()) { | |||||
std::ofstream Output; // Write the updated contents. | |||||
Output.open(PostfixMainCfPath.c_str(), std::ios::trunc); | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Error opening the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += " for writing: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Output << Content; | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Error writing the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += ": "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
Output.close(); | |||||
if (!Output) { | |||||
std::string Temp; | |||||
Temp = "Error closing the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += " after writing: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
} | |||||
OutputVerboseEnd(); | |||||
} | |||||
bool | |||||
PostfixIntegrate::IsIntegrated() { | |||||
if (!FileExists(PostfixMainCfPath)) { | |||||
return false; | |||||
} | |||||
bool Integrated = false; | |||||
if (Verbose()) { | |||||
std::cout << "Checking for any SNFMilter integration in the postfix file " << PostfixMainCfPath << "--\n"; | |||||
} | |||||
std::ifstream Input; | |||||
Input.open(PostfixMainCfPath.c_str()); // Read the contents. | |||||
if (!Input) { | |||||
std::string Temp; | |||||
Temp = "Error opening the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += " for reading: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
std::string Line; | |||||
while (getline(Input, Line)) { | |||||
if (std::string::npos != Line.find(SnfMilterMainCfSearchString)) { // Check for integration line. | |||||
Integrated = true; // Found it. | |||||
break; | |||||
} | |||||
} | |||||
Input.close(); | |||||
if (Input.bad()) { | |||||
std::string Temp; | |||||
Temp = "Error closing the postfix configuration file " + PostfixMainCfPath; | |||||
Temp += " after reading: "; | |||||
Temp += strerror(errno); | |||||
throw std::runtime_error(Temp); | |||||
} | |||||
OutputVerboseEnd(); | |||||
return Integrated; | |||||
} |
// \file PostfixIntegrate.hpp | |||||
// | |||||
// Copyright (C) 2011 ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | |||||
// | |||||
// This file defines the PostfixIntegrate interface. | |||||
// | |||||
// $Id$ | |||||
// | |||||
/////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
#ifndef PostfixIntegratehpp_included | |||||
#define PostfixIntegratehpp_included | |||||
#include "MtaIntegrate.hpp" | |||||
/// Class to manage the SNFMilter integration with postfix. | |||||
// | |||||
// This class implements the MtaIntegrate interface for postfix. | |||||
// | |||||
////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||||
class PostfixIntegrate : public MtaIntegrate { | |||||
public: | |||||
virtual void SetOperatingSystem(std::string OperatingSystemType); | |||||
virtual void Integrate(FileBackup *SaveFile); | |||||
virtual void Unintegrate(FileBackup *SaveFile); | |||||
private: | |||||
virtual bool IsIntegrated(); | |||||
/// Postfix main.cf file path. | |||||
std::string PostfixMainCfPath; | |||||
/// Postfix master.cf file path. | |||||
std::string PostfixMasterCfPath; | |||||
}; | |||||
#endif |
std::string ConfigFileName = GetConfigFileName(); | std::string ConfigFileName = GetConfigFileName(); | ||||
SaveFile.CreateBackupFile(ConfigFileName); // Save any existing file. | |||||
if (!FileExists(ConfigFileName)) { | if (!FileExists(ConfigFileName)) { | ||||
Copy(DefaultSampleConfigFile, ConfigFileName); // Use SNFMilter.xml.sample. | |||||
Copy(DefaultSampleConfigFile, ConfigFileName); // Use SNFMilter.xml.sample. | |||||
} | } | ||||
SetMode(ConfigFileName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); // Set permissions. | |||||
SetOwnerGroup(ConfigFileName); // Set to sniffer user. | |||||
SetMode(ConfigFileName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); // Set permissions. | |||||
SetOwnerGroup(ConfigFileName); // Set to sniffer user. | |||||
UpdateLogDir(); | UpdateLogDir(); | ||||
UpdateIgnoreListFile(); | UpdateIgnoreListFile(); | ||||
switch (Command) { | switch (Command) { | ||||
case IntegrateWithNoneCmd: | case IntegrateWithNoneCmd: | ||||
UnintegrateWithAll(); | |||||
UnintegrateWithAllExcept(); | |||||
break; | break; | ||||
case IntegrateWithPostfixCmd: | case IntegrateWithPostfixCmd: | ||||
IntegrateWithPostfix(); | |||||
UnintegrateWithAllExcept("postfix"); | |||||
Postfix.Integrate(&SaveFile); | |||||
break; | break; | ||||
case IntegrateWithSendmailCmd: | case IntegrateWithSendmailCmd: | ||||
IntegrateWithSendmail(); | |||||
UnintegrateWithAllExcept("sendmail"); | |||||
// Sendmail.Integrate(&SaveFile); | |||||
break; | break; | ||||
default: | default: | ||||
{ | { | ||||
ostringstream Temp; | ostringstream Temp; | ||||
Temp << "Internal error in SNFMilterConfig::DoCommand: Invalid value of command: " << Command; | |||||
Temp << "Internal error in SNFMilterConfig::DoIntegrationCommand: Invalid value of command: " | |||||
<< Command; | |||||
throw runtime_error(Temp.str()); | throw runtime_error(Temp.str()); | ||||
} | } | ||||
void | void | ||||
SNFMilterConfig::UnintegrateWithAll() { | |||||
SNFMilterConfig::UnintegrateWithAllExcept(std::string Except) { | |||||
if (Except != "postfix") { | |||||
Postfix.Unintegrate(&SaveFile); | |||||
UnintegrateWithPostfix(); | |||||
UnintegrateWithSendmail(); | |||||
} | |||||
#if 0 | |||||
if (Except != "sendmail") { | |||||
// TODO: Restart MTA. | |||||
Sendmail.Unintegrate(&SaveFile); | |||||
// Do not remove the socket directory; users might have placed | |||||
// files in it. This happened with the /tmp directory; it was | |||||
// supposed to be only for files that would be deleted on reboot. | |||||
// However, admins stored files that they wished to be persistent | |||||
// across reboots in /tmp. | |||||
} | |||||
#endif | |||||
} | } | ||||
void | void | ||||
SNFMilterConfig::IntegrateWithPostfix() { | SNFMilterConfig::IntegrateWithPostfix() { | ||||
UnintegrateWithAll(); // Remove any existing integration. | |||||
// UnintegrateWithAll(); // Remove any existing integration. | |||||
if (Verbose()) { | if (Verbose()) { | ||||
#include <string> | #include <string> | ||||
#include "UtilityConfig.hpp" | #include "UtilityConfig.hpp" | ||||
#include "PostfixIntegrate.hpp" | |||||
/// Class to manage the SNFMilter configuration. | /// Class to manage the SNFMilter configuration. | ||||
// | // | ||||
void CreateSocketDir(); | void CreateSocketDir(); | ||||
PostfixIntegrate Postfix; ///< Postfix integration object. | |||||
void IntegrateWithPostfix(); ///< Integrate with postfix. | void IntegrateWithPostfix(); ///< Integrate with postfix. | ||||
void UnintegrateWithPostfix(); ///< Unintegrate with postfix. | void UnintegrateWithPostfix(); ///< Unintegrate with postfix. | ||||
void UnintegrateWithSendmail(); ///< Unintegrate with sendmail. | void UnintegrateWithSendmail(); ///< Unintegrate with sendmail. | ||||
void UnintegrateWithAll(); ///< Unintegrate with all MTAs. | |||||
///< Unintegrate with MTAs. | |||||
// | |||||
// Unintegrate with all MTAs except the specified MTA. | |||||
// | |||||
// \param[in] Except is the MTA to not integrate with. The | |||||
// acceptable values are: | |||||
// | |||||
// <ol> | |||||
// <li> "postfix" </li> | |||||
// <li> "" </li> | |||||
// </ol> | |||||
// | |||||
// The default value is "", which specifies unintegration with all | |||||
// MTAs. | |||||
// | |||||
void UnintegrateWithAllExcept(std::string Except = ""); | |||||
CommandEnum Command; ///< Specified command. | CommandEnum Command; ///< Specified command. | ||||