浏览代码

Implemented PostfixMilterConf, class to updated the smtpd_milters line

in postfix main.cf.

Modified PostfixIntegrate to use PostfixMilterConf.

Need to implement unit test for PostfixMilterConf.


git-svn-id: https://svn.microneil.com/svn/SNFUtility/trunk@49 aa37657e-1934-4a5f-aa6d-2d8eab27ff7c
master
adeniz 12 年前
父节点
当前提交
0b7f4e41b2

+ 2
- 0
SNFMilterConfig/Makefile.am 查看文件

@@ -25,11 +25,13 @@ SNFMilterConfig_SOURCES = \
@top_srcdir@/SNFUtility/SNFMilterConfig/main.cpp \
@top_srcdir@/SNFUtility/SNFMilterConfig/SNFMilterConfig.cpp \
@top_srcdir@/SNFUtility/SNFMilterConfig/PostfixIntegrate.cpp \
@top_srcdir@/SNFUtility/SNFMilterConfig/PostfixMilterConf.cpp \
@top_srcdir@/SNFUtility/SNFMilterConfig/SendmailIntegrate.cpp

noinst_HEADERS = \
@top_srcdir@/SNFUtility/SNFMilterConfig/SNFMilterConfig.hpp \
@top_srcdir@/SNFUtility/SNFMilterConfig/PostfixIntegrate.hpp \
@top_srcdir@/SNFUtility/SNFMilterConfig/PostfixMilterConf.hpp \
@top_srcdir@/SNFUtility/SNFMilterConfig/SendmailIntegrate.hpp

EXTRA_DIST = \

+ 111
- 19
SNFMilterConfig/PostfixIntegrate.cpp 查看文件

@@ -20,6 +20,7 @@
#include <fstream>
#include "PostfixIntegrate.hpp"
#include "PostfixMilterConf.hpp"
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Configuration. ////////////////////////////////////////////////////////////////////////////////////////
@@ -27,7 +28,7 @@
const std::string SnfMilterMainCfSearchString("unix:/var/snf-milter/socket");
const std::string SnfMilterMainCfIntegrationString("smtpd_milters = unix:/var/snf-milter/socket");
const std::string SnfMilterMainCfMilterSpec("unix:/var/snf-milter/socket");
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// End of configuration. /////////////////////////////////////////////////////////////////////////////////
@@ -90,10 +91,11 @@ PostfixIntegrate::Integrate(FileBackup *SaveFile) {
}
std::ifstream Input;
if (Verbose()) {
std::cout << "Add to postfix file " << PostfixMainCfPath << ": '"
<< SnfMilterMainCfIntegrationString << "'...";
std::cout << "Integrate with postfix...\n";
}
@@ -101,38 +103,116 @@ PostfixIntegrate::Integrate(FileBackup *SaveFile) {
SaveFile->CreateBackupFile(PostfixMainCfPath); // Save any existing file.
std::ofstream Output; // Append the configuration.
Output.open(PostfixMainCfPath.c_str(), std::ios::app);
if (!Output) {
Input.open(PostfixMainCfPath.c_str()); // Read the contents.
if (!Input) {
std::string Temp;
Temp = "Error opening the postfix configuration file " + PostfixMainCfPath;
Temp += " for writing: ";
Temp += " for reading: ";
Temp += strerror(errno);
throw std::runtime_error(Temp);
}
Output << SnfMilterMainCfIntegrationString << "\n";
if (!Output) {
std::string Content;
std::string Line;
bool ModifiedLine = false;
PostfixMilterConf MilterConf; // Object to update the config line.
while (getline(Input, Line)) {
MilterConf.ConfLine(Line); // Load the object with the line.
if (MilterConf.IsMilterLine() && !ModifiedLine) { // Check for milter integration line.
// Ignore subsequence integration lines.
MilterConf.AddIntegration(); // Found milter line. Add integration.
if (Verbose()) {
std::cout << " Replace '" << Line << "' with '"
<< MilterConf.ConfLine() << "'...\n";
}
Line = MilterConf.ConfLine(); // Copy updated line.
ModifiedLine = true;
}
Content += Line + "\n"; // Copy this line.
}
if (!ModifiedLine) {
MilterConf.ConfLine("");
MilterConf.AddIntegration();
if (Verbose()) {
std::cout << " Add '" << MilterConf.ConfLine() << "'...\n";
}
Content += MilterConf.ConfLine() + "\n";
}
if (!Input.eof()) { // Should be at end-of-file.
std::string Temp;
Temp = "Error appending to the postfix configuration file " + PostfixMainCfPath;
Temp = "Error reading the postfix configuration file " + PostfixMainCfPath;
Temp += ": ";
Temp += strerror(errno);
throw std::runtime_error(Temp);
}
Output.close();
if (!Output) {
Input.close();
if (Input.bad()) {
std::string Temp;
Temp = "Error closing the postfix configuration file " + PostfixMainCfPath;
Temp += " after appending: ";
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();
@@ -180,16 +260,25 @@ PostfixIntegrate::Unintegrate(FileBackup *SaveFile) {
std::string Content;
std::string Line;
PostfixMilterConf MilterConf; // Object to update the config line.
while (getline(Input, Line)) {
if (std::string::npos != Line.find(SnfMilterMainCfSearchString)) { // Check for integration line.
MilterConf.ConfLine(Line); // Load the object with the line.
if (MilterConf.IsIntegrated()) { // Check for integration.
MilterConf.RemoveIntegration(); // Integrated. Remove the milter spec.
if (Verbose()) {
std::cout << " Remove '" << Line << "'...\n";
std::cout << " Replace '" << Line << "' with '"
<< MilterConf.ConfLine() << "'...\n";
}
continue; // Do not copy this line.
Content += MilterConf.ConfLine(); // Copy updated line.
continue;
}
@@ -218,7 +307,7 @@ PostfixIntegrate::Unintegrate(FileBackup *SaveFile) {
if (!Explain()) {
std::ofstream Output; // Write the updated contents.
std::ofstream Output; // Write the updated contents.
Output.open(PostfixMainCfPath.c_str(), std::ios::trunc);
if (!Output) {
@@ -363,11 +452,14 @@ PostfixIntegrate::IsIntegrated() {
throw std::runtime_error(Temp);
}
PostfixMilterConf MilterConf; // Object to update the config line.
std::string Line;
while (getline(Input, Line)) {
if (std::string::npos != Line.find(SnfMilterMainCfSearchString)) { // Check for integration line.
MilterConf.ConfLine(Line);
if (MilterConf.IsIntegrated()) { // Check for integration line.
Integrated = true; // Found it.

+ 246
- 0
SNFMilterConfig/PostfixMilterConf.cpp 查看文件

@@ -0,0 +1,246 @@
// /file PostfixMilterConf.cpp
//
// Copyright (C) 2011, ARM Research Labs, LLC.
// See www.armresearch.com for the copyright terms.
//
// This file contains the functions for PostfixMilterConf.
//
// $Id$
//
///////////////////////////////////////////////////////////////////////////////////////////////////
#include <exception>
#include <stdexcept>
#include <sstream>
#include "Utility.hpp"
#include "PostfixMilterConf.hpp"
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Configuration. ////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SNFMilter socket specification.
const std::string SnfMilterSocketSpec("unix:/var/snf-milter/socket");
/// Milter keyword in the postfix main.cf file.
const std::string SmtpdMilterKeyword("smtpd_milters");
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// End of configuration. /////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
void
PostfixMilterConf::ConfLine(std::string Line) {
ConfigurationLine = Utility::Trim(Line); // Remove leading and trailing whitespace.
}
bool
PostfixMilterConf::IsIntegrated() {
return (IsMilterLine() && ContainsSnfMilterSocketSpec());
}
void
PostfixMilterConf::AddIntegration() {
if (IsIntegrated()) {
return;
}
if (IsMilterLine()) { // Add to existing milter line.
std::string NewConfLine;
NewConfLine = SmtpdMilterKeyword + " =";
// Skip to "=" in configuration line.
std::string::size_type NextIndex;
NextIndex = ConfigurationLine.find("=");
if (std::string::npos == NextIndex) { // Check format.
std::ostringstream Temp;
Temp << "Error processing postfix main.cf file smtpd_milters line: '"
<< ConfigurationLine << "'";
throw std::runtime_error(Temp.str());
}
std::string ExistingMilters;
ExistingMilters = Utility::Trim(ConfigurationLine.substr(NextIndex + 1)); // Should contain existing milters.
while (ExistingMilters != "") {
NewConfLine += " ";
std::string NextMilter;
NextIndex = ExistingMilters.find_first_of(" ,");
NextMilter = Utility::Trim(ExistingMilters.substr(0, NextIndex));
ExistingMilters = Utility::Trim(ExistingMilters.substr(NextIndex + 1));
if (NextMilter == "") {
std::ostringstream Temp;
Temp << "Error processing postfix main.cf file smtpd_milters line: '"
<< ConfigurationLine << "'";
throw std::runtime_error(Temp.str());
}
NewConfLine += NextMilter;
}
ConfigurationLine = NewConfLine + " ";
ConfigurationLine += SnfMilterSocketSpec;
} else if (ConfigurationLine == "") { // Empty configuration line.
ConfigurationLine = SmtpdMilterKeyword + " = ";
ConfigurationLine += SnfMilterSocketSpec;
} else { // Unexpected non-empty line.
std::ostringstream Temp;
Temp << "Internal error: Attempted to modify a line in main.cf that does not begin with '"
<< SmtpdMilterKeyword << "'";
throw std::runtime_error(Temp.str());
}
}
void
PostfixMilterConf::RemoveIntegration() {
if (!IsIntegrated()) {
return;
}
if (IsMilterLine()) { // Remove from an existing milter line.
std::string NewConfLine;
NewConfLine = SmtpdMilterKeyword + " =";
// Skip to "=" in configuration line.
std::string::size_type NextIndex;
NextIndex = ConfigurationLine.find("=");
if (std::string::npos == NextIndex) { // Check format.
std::ostringstream Temp;
Temp << "Error processing postfix main.cf file smtpd_milters line: '"
<< ConfigurationLine << "'";
throw std::runtime_error(Temp.str());
}
std::string ExistingMilters;
bool AddedMilter = false;
ExistingMilters = Utility::Trim(ConfigurationLine.substr(NextIndex + 1)); // Should contain existing milters.
while (ExistingMilters != "") {
NewConfLine += " ";
std::string NextMilter;
NextIndex = ExistingMilters.find_first_of(" ,");
if (std::string::npos == NextIndex) {
NextMilter = ExistingMilters;
ExistingMilters = "";
} else {
NextMilter = Utility::Trim(ExistingMilters.substr(0, NextIndex));
ExistingMilters = Utility::Trim(ExistingMilters.substr(NextIndex + 1));
}
if (NextMilter == "") {
std::ostringstream Temp;
Temp << "Error processing postfix main.cf file smtpd_milters line: '"
<< ConfigurationLine << "'";
throw std::runtime_error(Temp.str());
}
if (NextMilter != SnfMilterSocketSpec) { // Copy if not for SNFMilter.
NewConfLine += NextMilter;
AddedMilter = true;
}
}
if (AddedMilter) {
ConfigurationLine = NewConfLine;
} else {
ConfigurationLine = "";
}
} else { // Unexpected non-empty line.
std::ostringstream Temp;
Temp << "Internal error: Attempted to modify a line in main.cf that does not begin with '"
<< SmtpdMilterKeyword << "'";
throw std::runtime_error(Temp.str());
}
}
std::string
PostfixMilterConf::ConfLine() {
return ConfigurationLine;
}
bool
PostfixMilterConf::IsMilterLine() {
return (ConfigurationLine.find(SmtpdMilterKeyword) == 0);
}
bool
PostfixMilterConf::ContainsSnfMilterSocketSpec() {
return (ConfigurationLine.find(SnfMilterSocketSpec) != std::string::npos);
}

+ 63
- 0
SNFMilterConfig/PostfixMilterConf.hpp 查看文件

@@ -0,0 +1,63 @@
// \file PostfixMilterConf.hpp
//
// Copyright (C) 2011 ARM Research Labs, LLC.
// See www.armresearch.com for the copyright terms.
//
// This file defines the PostfixMilterConf interface.
//
// $Id$
//
///////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef PostfixMilterConfhpp_included
#define PostfixMilterConfhpp_included
#include <string>
/// Class to update smtpd_milters line in the postfix main.cf file.
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
class PostfixMilterConf {
public:
/// Load a new configuration line.
void ConfLine(std::string Line);
/// Check whether the configuration line indicates that SNFMilter is integrated.
//
// \returns true if the line indicates integration, false otherwise.
//
bool IsIntegrated();
/// Update the configuration line to integrate with SNFMilter.
void AddIntegration();
/// Update the configuration line to remove integration with SNFMilter.
void RemoveIntegration();
/// Get a copy of the configuration line.
std::string ConfLine();
/// Check whether the configuration line is a milter specification.
//
// \returns true if the configuration line is a milter
// specification, false otherwise.
//
bool IsMilterLine();
private:
/// Check whether the configuration line contains a SNFMilter soecket specification.
//
// \returns true if the configuration line contains a SNFMilter
// socket specification, false otherwise.
//
bool ContainsSnfMilterSocketSpec();
/// Configuration line.
std::string ConfigurationLine;
};
#endif

正在加载...
取消
保存