35 Filter::Type filter_type ,
const Filter::Config & filter_config ,
const std::string & spec ) :
38 m_filter_config(filter_config)
40 std::string_view spec_sv = spec ;
43 if( t() ==
"raw" ) m_raw = true ;
48GSmtp::Filter::Result GFilters::SplitFilter::run(
const GStore::MessageId & message_id ,
49 bool & , GStore::FileStore::State e_state )
51 G::Path content_path = m_store.contentPath( message_id ) ;
52 G::Path envelope_path = m_store.envelopePath( message_id , e_state ) ;
58 std::transform( envelope.to_remote.begin() , envelope.to_remote.end() ,
59 std::back_inserter(domains) , [](std::string &to_){return G::Str::tail(to_,
"@");} ) ;
61 std::for_each( domains.begin() , domains.end() , [raw](std::string &to_){normalise(to_,raw);} ) ;
62 std::sort( domains.begin() , domains.end() ) ;
63 domains.erase( std::unique(domains.begin(),domains.end()) , domains.end() ) ;
66 G_LOG(
"GFilters::SplitFilter::start: " << prefix() <<
": no remote domains: nothing to do" ) ;
72 ids.reserve( domains.size() ) ;
73 ids.push_back( message_id.
str() ) ;
74 for( std::size_t i = 1U ; i < domains.size() ; i++ )
75 ids.push_back( m_store.newId().str() ) ;
78 std::stringstream extra_headers ;
82 for(
const auto &
id : ids )
87 for( std::size_t i = 1U ; i < domains.size() ; i++ )
89 std::string domain = domains[i] ;
91 G::StringArray recipients = matching( envelope.to_remote , domain ) ;
92 G_ASSERT( !recipients.empty() ) ;
94 G::Path new_content_path = m_store.contentPath( new_id ) ;
95 G::Path new_envelope_path = m_store.envelopePath( new_id ) ;
97 G_LOG(
"GFilters::SplitFilter::start: " << prefix() <<
" creating "
98 <<
"[" << new_id.str() <<
"]: forward-to=[" << domain <<
"]" ) ;
101 new_envelope.to_local.clear() ;
102 new_envelope.to_remote = recipients ;
103 new_envelope.forward_to = forwardTo( recipients.at(0U) ) ;
105 if( !FileOp::hardlink( content_path , new_content_path ) )
108 G::ScopeExit clean_up_content( [new_content_path](){FileOp::remove(new_content_path);} ) ;
110 std::ofstream new_envelope_stream ;
111 FileOp::openOut( new_envelope_stream , new_envelope_path ) ;
114 extra_headers.clear() ;
115 extra_headers.seekg( 0 ) ;
117 new_envelope_stream.close() ;
118 if( !new_envelope_stream )
119 throw G::Exception(
"split: cannot create envelope file" ,
122 clean_up_content.release() ;
126 G_LOG(
"GFilters::SplitFilter::start: " << prefix() <<
" updating "
127 <<
"[" << message_id.
str() <<
"]: forward-to=[" << domains[0] <<
"]" ) ;
128 G_ASSERT( !domains.empty() ) ;
129 G::StringArray recipients = matching( envelope.to_remote , domains.at(0) ) ;
130 G_ASSERT( !recipients.empty() ) ;
131 std::string forward_to = forwardTo( recipients.at(0U) ) ;
134 env_.to_remote = recipients ;
135 env_.forward_to = forward_to ;
136 } , &extra_headers ) ;
145 std::copy_if( recipients.begin() , recipients.end() , std::back_inserter(result) ,
146 [domain,raw](
const std::string &to_){return match(G::Str::tail(to_,
"@"),domain,raw) ;} ) ;
150bool GFilters::SplitFilter::match(
const std::string & a ,
const std::string & b ,
bool raw )
155void GFilters::SplitFilter::normalise( std::string & domain ,
bool raw )
161std::string GFilters::SplitFilter::forwardTo(
const std::string & recipient )
const
164 return G::Str::tail(recipient,
"@").append(m_port.empty()?0U:1U,
':').append(m_port) ;
A GSmtp::Filter base class for filters that run synchronously.
SplitFilter(GNet::EventState es, GStore::FileStore &, Filter::Type, const Filter::Config &, const std::string &spec)
Constructor.
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
A structure containing the contents of an envelope file, with support for file reading,...
static void copyExtra(std::istream &, std::ostream &)
A convenience function to copy extra envelope lines from an envelope input stream to an output stream...
static std::size_t write(std::ostream &, const Envelope &)
Writes an envelope to a seekable stream.
A concrete implementation of the MessageStore interface dealing in paired flat files.
static std::string x()
Returns the prefix for envelope header lines.
static Envelope readEnvelope(const G::Path &, std::ifstream *=nullptr)
Used by FileStore sibling classes to read an envelope file.
A somewhat opaque identifer for a GStore::MessageStore message id.
std::string str() const
Returns the id string.
A concete class implementing the GStore::StoredMessage interface for separate envelope and content fi...
A general-purpose exception class derived from std::exception and containing an error message.
A Path object represents a file system path.
std::string str() const
Returns the path string.
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
A class that calls an exit function at the end of its scope.
static void toLower(std::string &s)
Replaces all seven-bit upper-case characters in string 's' by lower-case characters.
static bool imatch(char, char) noexcept
Returns true if the two characters are the same, ignoring seven-bit case.
static bool isNumeric(std::string_view s, bool allow_minus_sign=false) noexcept
Returns true if every character is a decimal digit.
static std::string tail(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the last part of the string after the given position.
A zero-copy string token iterator where the token separators are runs of whitespace characters,...
std::vector< std::string > StringArray
A std::vector of std::strings.