You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PostfixMilterConf.cpp 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // /file PostfixMilterConf.cpp
  2. //
  3. // Copyright (C) 2011, ARM Research Labs, LLC.
  4. // See www.armresearch.com for the copyright terms.
  5. //
  6. // This file contains the functions for PostfixMilterConf.
  7. //
  8. // $Id$
  9. //
  10. ///////////////////////////////////////////////////////////////////////////////////////////////////
  11. #include <exception>
  12. #include <stdexcept>
  13. #include <sstream>
  14. #include "Utility.hpp"
  15. #include "PostfixMilterConf.hpp"
  16. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. // Configuration. ////////////////////////////////////////////////////////////////////////////////////////
  18. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  19. /// SNFMilter socket specification.
  20. const std::string SnfMilterSocketSpec("unix:/var/snf-milter/socket");
  21. /// Milter keyword in the postfix main.cf file.
  22. const std::string SmtpdMilterKeyword("smtpd_milters");
  23. const std::string Whitespace(", \t");
  24. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  25. // End of configuration. /////////////////////////////////////////////////////////////////////////////////
  26. //////////////////////////////////////////////////////////////////////////////////////////////////////////
  27. void
  28. PostfixMilterConf::ConfLine(std::string Line) {
  29. ConfigurationLine = Utility::Trim(Line); // Remove leading and trailing whitespace.
  30. }
  31. bool
  32. PostfixMilterConf::IsIntegrated() {
  33. return (IsMilterLine() && ContainsSnfMilterSocketSpec());
  34. }
  35. void
  36. PostfixMilterConf::AddIntegration() {
  37. if (IsIntegrated()) {
  38. return;
  39. }
  40. if (IsMilterLine()) { // Add to existing milter line.
  41. std::string NewConfLine;
  42. NewConfLine = SmtpdMilterKeyword + " =";
  43. // Skip to "=" in configuration line.
  44. std::string::size_type NextIndex;
  45. NextIndex = ConfigurationLine.find("=");
  46. if (std::string::npos == NextIndex) { // Check format.
  47. std::ostringstream Temp;
  48. Temp << "Error processing postfix main.cf file smtpd_milters line: '"
  49. << ConfigurationLine << "'";
  50. throw std::runtime_error(Temp.str());
  51. }
  52. std::string ExistingMilters;
  53. ExistingMilters = Utility::Trim(ConfigurationLine.substr(NextIndex + 1)); // Should contain existing milters.
  54. while (std::string::npos != NextIndex) {
  55. NewConfLine += " ";
  56. std::string NextMilter;
  57. NextIndex = ExistingMilters.find_first_of(Whitespace);
  58. NextMilter = Utility::Trim(ExistingMilters.substr(0, NextIndex));
  59. ExistingMilters = Utility::Trim(ExistingMilters.substr(NextIndex + 1));
  60. if (NextMilter == "") {
  61. std::ostringstream Temp;
  62. Temp << "Error processing postfix main.cf file smtpd_milters line: '"
  63. << ConfigurationLine << "'";
  64. throw std::runtime_error(Temp.str());
  65. }
  66. NewConfLine += NextMilter;
  67. }
  68. ConfigurationLine = NewConfLine + " ";
  69. ConfigurationLine += SnfMilterSocketSpec;
  70. } else if (ConfigurationLine == "") { // Empty configuration line.
  71. ConfigurationLine = SmtpdMilterKeyword + " = ";
  72. ConfigurationLine += SnfMilterSocketSpec;
  73. } else { // Unexpected non-empty line.
  74. std::ostringstream Temp;
  75. Temp << "Internal error: Attempted to modify a line in main.cf that does not begin with '"
  76. << SmtpdMilterKeyword << "'";
  77. throw std::runtime_error(Temp.str());
  78. }
  79. ConfigurationLine = Utility::Trim(ConfigurationLine);
  80. }
  81. void
  82. PostfixMilterConf::RemoveIntegration() {
  83. if (!IsIntegrated()) {
  84. return;
  85. }
  86. std::string NewConfLine;
  87. NewConfLine = SmtpdMilterKeyword + " =";
  88. // Skip to "=" in configuration line.
  89. std::string::size_type NextIndex;
  90. NextIndex = ConfigurationLine.find("=");
  91. if (std::string::npos == NextIndex) { // Check format.
  92. std::ostringstream Temp;
  93. Temp << "Error processing postfix main.cf file smtpd_milters line: '"
  94. << ConfigurationLine << "'";
  95. throw std::runtime_error(Temp.str());
  96. }
  97. std::string ExistingMilters;
  98. bool AddedMilter = false;
  99. ExistingMilters = Utility::Trim(ConfigurationLine.substr(NextIndex + 1)); // Should contain existing milters.
  100. while (std::string::npos != NextIndex) {
  101. NewConfLine += " ";
  102. std::string NextMilter;
  103. NextIndex = ExistingMilters.find_first_of(Whitespace);
  104. NextMilter = Utility::Trim(ExistingMilters.substr(0, NextIndex));
  105. ExistingMilters = Utility::Trim(ExistingMilters.substr(NextIndex + 1));
  106. if (NextMilter == "") {
  107. std::ostringstream Temp;
  108. Temp << "Error processing postfix main.cf file smtpd_milters line: '"
  109. << ConfigurationLine << "'";
  110. throw std::runtime_error(Temp.str());
  111. }
  112. if (NextMilter != SnfMilterSocketSpec) { // Copy if not for SNFMilter.
  113. NewConfLine += NextMilter;
  114. AddedMilter = true;
  115. }
  116. }
  117. if (AddedMilter) {
  118. ConfigurationLine = NewConfLine;
  119. } else {
  120. ConfigurationLine = "";
  121. }
  122. ConfigurationLine = Utility::Trim(ConfigurationLine);
  123. }
  124. std::string
  125. PostfixMilterConf::ConfLine() {
  126. return ConfigurationLine;
  127. }
  128. bool
  129. PostfixMilterConf::IsMilterLine() {
  130. bool StartsWithKeyword;
  131. bool KeywordEndsCorrectly;
  132. char NextChar;
  133. StartsWithKeyword = (ConfigurationLine.find(SmtpdMilterKeyword) == 0);
  134. NextChar = ConfigurationLine[SmtpdMilterKeyword.length()];
  135. KeywordEndsCorrectly =
  136. (' ' == NextChar) ||
  137. ('\t' == NextChar) ||
  138. ('=' == NextChar);
  139. return (StartsWithKeyword && KeywordEndsCorrectly);
  140. }
  141. bool
  142. PostfixMilterConf::ContainsSnfMilterSocketSpec() {
  143. std::string::size_type SpecIndex;
  144. SpecIndex = ConfigurationLine.find("=");
  145. if (std::string::npos == SpecIndex) {
  146. return false;
  147. }
  148. SpecIndex++;
  149. while (SpecIndex < ConfigurationLine.length()) {
  150. SpecIndex = ConfigurationLine.find_first_not_of(Whitespace, SpecIndex); // Find next specification.
  151. if (ConfigurationLine.substr(SpecIndex, SnfMilterSocketSpec.length()) == SnfMilterSocketSpec) {
  152. SpecIndex += SnfMilterSocketSpec.length(); // Skip to after the specification.
  153. if (SpecIndex >= ConfigurationLine.length()) {
  154. return true; // No characters after the specification.
  155. }
  156. if ( (ConfigurationLine[SpecIndex] == ' ') ||
  157. (ConfigurationLine[SpecIndex] == '\t') ||
  158. (ConfigurationLine[SpecIndex] == ',') ) {
  159. return true; // Found specification.
  160. }
  161. }
  162. SpecIndex = ConfigurationLine.find_first_of(Whitespace, SpecIndex); // Find next specification.
  163. }
  164. return false;
  165. }