32 Forward( es , ff , forward_to_default , secrets , config )
36 m_continue_timer.startTimer( 0U ) ;
45 m_forward_to_default(forward_to_default) ,
46 m_forward_to_location(forward_to_default) ,
49 m_error_timer(*this,&
Forward::onErrorTimeout,m_es) ,
50 m_continue_timer(*this,&
Forward::onContinueTimeout,m_es) ,
52 m_has_connected(false) ,
62 if( m_client_ptr.get() )
63 m_client_ptr->messageDoneSignal().disconnect() ;
64 if( m_routing_filter )
65 m_routing_filter->doneSignal().disconnect() ;
66 m_client_ptr.deletedSignal().disconnect() ;
67 m_client_ptr.deleteSignal().disconnect() ;
68 m_client_ptr.eventSignal().disconnect() ;
71void GSmtp::Forward::onContinueTimeout()
73 G_ASSERT( m_store !=
nullptr ) ;
81bool GSmtp::Forward::sendNext()
86 std::unique_ptr<GStore::StoredMessage> message( ++m_iter ) ;
87 if( message ==
nullptr )
93 if( message->toCount() == 0U && m_config.fail_if_no_remote_recipients )
95 G_WARNING(
"GSmtp::Forward::sendNext: forwarding [" << message->id().str() <<
"]: failing message with no remote recipients" ) ;
96 message->fail(
"no remote recipients" , 0 ) ;
98 else if( message->toCount() == 0U )
100 G_DEBUG(
"GSmtp::Forward::sendNext: forwarding [" << message->id().str() <<
"]: skipping message with no remote recipients" ) ;
104 G_LOG(
"GSmtp::Forward::sendNext: forwarding [" << message->id().str() <<
"]" << messageInfo(*message) ) ;
105 start( std::move(message) ) ;
109 if( m_message_count != 0U )
110 G_LOG(
"GSmtp::Forward: forwarding: no more messages to send" ) ;
116 G_LOG(
"GSmtp::Forward::sendMessage: forwarding [" << message->id().str() <<
"]" << messageInfo(*message) ) ;
117 start( std::move(message) ) ;
120void GSmtp::Forward::start( std::unique_ptr<GStore::StoredMessage> message )
123 if( !message->forwardTo().empty() )
126 m_message = std::move( message ) ;
128 m_routing_filter = m_ff.newFilter( m_es , Filter::Type::routing , m_config.filter_config , m_config.filter_spec ) ;
129 G_LOG_MORE(
"GSmtp::Forward::start: routing-filter [" << m_routing_filter->id() <<
"]: [" << m_message->id().str() <<
"]" ) ;
130 m_routing_filter->doneSignal().connect(
G::Slot::slot(*
this,&Forward::routingFilterDone) ) ;
131 m_routing_filter->start( m_message->id() ) ;
133 else if( updateClient( *message ) )
135 m_client_ptr->sendMessage( std::move(message) ) ;
139 m_continue_timer.startTimer( 0U ) ;
143void GSmtp::Forward::routingFilterDone(
int filter_result )
145 G_ASSERT( m_routing_filter.get() !=
nullptr ) ;
146 G_ASSERT( m_message.get() !=
nullptr ) ;
147 G_ASSERT(
static_cast<int>(m_routing_filter->result()) == filter_result ) ;
148 G_DEBUG(
"GSmtp::Forward::routingFilterDone: result=" << filter_result ) ;
150 G_LOG_IF( !m_routing_filter->quiet() ,
"GSmtp::Forward::routingFilterDone: routing-filter "
151 "[" << m_routing_filter->id() <<
"]: [" << m_message->id().str() <<
"]: "
152 << m_routing_filter->str(Filter::Type::client) ) ;
154 const bool ok = filter_result == 0 && m_message ;
155 const bool abandon = filter_result == 1 ;
158 std::string reopen_error = ok ? m_message->reopen() : std::string() ;
159 bool continue_ = true ;
160 if( ok && reopen_error.empty() )
162 if( updateClient( *m_message ) )
165 m_client_ptr->sendMessage( std::move(m_message) ) ;
174 m_message->fail(
"routing filter failed" , 0 ) ;
180 if( m_store ==
nullptr )
181 m_message_done_signal.emit( { 0 , abandon?
"":
"routing failed" ,
false } ) ;
183 m_continue_timer.startTimer( 0U ) ;
193 G_LOG(
"GSmtp::Forward::updateClient: forwarding [" << message.
id().
str() <<
"]: "
194 "skipping message with unconnectable address [" << message.
forwardToAddress() <<
"]" ) ;
197 else if( m_client_ptr.get() ==
nullptr )
200 newClient( message ) ;
205 m_client_ptr->quitAndFinish() ;
207 std::ostringstream ss ;
209 if( new_address && new_selector ) ss <<
" and " ;
211 G_LOG(
"GSmtpForward::updateClient: forwarding [" << message.
id().
str() <<
"]: new connection for " << ss.str() ) ;
213 newClient( message ) ;
215 G_ASSERT( m_client_ptr.get() ) ;
221 m_has_connected = false ;
225 if( m_client_ptr.get() )
226 m_client_ptr->messageDoneSignal().disconnect() ;
228 if( m_forward_to_address.empty() )
229 m_forward_to_location = m_forward_to_default ;
233 m_client_ptr.reset( std::make_unique<GSmtp::Client>( m_es.eh(m_client_ptr) ,
234 m_ff , m_forward_to_location , m_secrets , m_config ) ) ;
236 m_client_ptr->messageDoneSignal().connect(
G::Slot::slot(*
this,&Forward::onMessageDoneSignal) ) ;
242 if( m_client_ptr.get() )
243 m_client_ptr->quitAndFinish() ;
246void GSmtp::Forward::onEventSignal(
const std::string & p1 ,
const std::string & p2 ,
const std::string & p3 )
248 m_event_signal.emit( std::string(p1) , std::string(p2) , std::string(p3) ) ;
251void GSmtp::Forward::onDeleteSignal(
const std::string & )
254 G_ASSERT( m_client_ptr.get() ) ;
255 m_has_connected = m_client_ptr->hasConnected() ;
258void GSmtp::Forward::onDeletedSignal(
const std::string & reason )
260 G_DEBUG(
"GSmtp::Forward::onDeletedSignal: [" << reason <<
"]" ) ;
261 if( m_store && !m_has_connected && !m_forward_to_address.empty() )
264 G_ASSERT( !reason.empty() ) ;
265 G_WARNING(
"GSmtp::Forward::onDeletedSignal: smtp connection failed: " << reason ) ;
266 insert( m_unconnectable , m_forward_to_address ) ;
267 m_client_ptr.reset() ;
268 m_continue_timer.startTimer( 0U ) ;
274 m_error_timer.startTimer( 0U ) ;
278void GSmtp::Forward::onErrorTimeout()
283void GSmtp::Forward::onMessageDoneSignal(
const Client::MessageDoneInfo & info )
286 G_ASSERT( m_client_ptr.get() ) ;
287 if( m_client_ptr.get() && m_client_ptr->hasConnected() && m_forward_to_address.empty() &&
288 !m_forward_to_default.resolved() && m_client_ptr->remoteLocation().resolved() )
290 m_forward_to_default = m_client_ptr->remoteLocation() ;
303 m_message_done_signal.emit( info ) ;
313void GSmtp::Forward::onDelete(
const std::string & reason )
315 G_WARNING_IF( !reason.empty() ,
"GSmtp::Forward::onDelete: smtp client error: " << reason ) ;
319 G_ASSERT( !reason.empty() ) ;
320 m_message->fail( reason , 0 ) ;
327 return m_client_ptr.get() ? m_client_ptr->peerAddressString() : std::string() ;
336bool GSmtp::Forward::unconnectable(
const std::string & forward_to )
const
338 return !forward_to.empty() && contains( m_unconnectable , forward_to ) ;
341void GSmtp::Forward::insert(
G::StringArray & array ,
const std::string & value )
343 G_ASSERT( !value.empty() ) ;
344 if( !contains( array , value ) )
345 array.insert( std::lower_bound(array.begin(),array.end(),value) , value ) ;
348bool GSmtp::Forward::contains(
const G::StringArray & array ,
const std::string & value )
350 return !value.empty() && std::binary_search( array.begin() , array.end() , value ) ;
355 std::ostringstream ss ;
367 return m_message_done_signal ;
372 return m_event_signal ;
An interface used by GAuth::SaslClient to obtain a client id and its authentication secret.
G::Slot::Signal< const std::string & > & deletedSignal() noexcept
A signal that is triggered after deleteSignal() once the client has been deleted and the ClientPtr is...
G::Slot::Signal< const std::string & > & deleteSignal() noexcept
A signal that is triggered as the client is deleted following an exception handled by this class.
G::Slot::Signal< const std::string &, const std::string &, const std::string & > & eventSignal() noexcept
A signal that is linked to the contained client's eventSignal().
An exception class that is caught separately by GNet::EventEmitter and GNet::TimerList so that onExce...
A class that sets the G::LogOuput::context() while in scope.
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
A class that represents the remote target for out-going client connections.
A factory interface for making GSmtp::Filter message processors.
A class for forwarding messages from a message store that manages a GSmtp::Client instance,...
G::Slot::Signal< const std::string &, const std::string &, const std::string & > & eventSignal() noexcept
See GNet::Client::eventSignal()
Forward(GNet::EventState, GStore::MessageStore &store, FilterFactoryBase &, const GNet::Location &forward_to_default, const GAuth::SaslClientSecrets &, const Config &config)
Constructor.
std::string peerAddressString() const
Returns the Client's peerAddressString() if currently connected.
void doOnDelete(const std::string &reason, bool done)
Used by owning ClientPtr when handling an exception.
bool finished() const
Returns true after quitAndFinish().
virtual ~Forward()
Destructor.
G::Slot::Signal< const Client::MessageDoneInfo & > & messageDoneSignal() noexcept
Returns a signal that indicates that sendMessage() has completed or failed.
void quitAndFinish()
Finishes a sendMessage() sequence.
void sendMessage(std::unique_ptr< GStore::StoredMessage > message)
Starts sending the given message.
std::string str() const
Returns the id string.
A class which allows SMTP messages to be stored and retrieved.
virtual std::unique_ptr< Iterator > iterator(bool lock)=0
Returns an iterator for stored messages.
An abstract interface for messages which have come from the store.
virtual std::string forwardToAddress() const =0
Returns the forwardTo() address or the empty string.
virtual std::string clientAccountSelector() const =0
Returns the client account selector or the empty string.
virtual MessageId id() const =0
Returns the message identifier.
virtual std::string forwardTo() const =0
Returns the routing override or the empty string.
A general-purpose exception class derived from std::exception and containing an error message.
static std::string printable(const std::string &in, char escape='\\')
Returns a printable representation of the given input string, using chacter code ranges 0x20 to 0x7e ...
Slot< Args... > slot(TSink &sink, void(TSink::*method)(Args...))
A factory function for Slot objects.
std::vector< std::string > StringArray
A std::vector of std::strings.
A structure containing GSmtp::Client configuration parameters.