30 Forward( es , ff , forward_to_default , secrets , config )
34 m_continue_timer.startTimer( 0U ) ;
43 m_forward_to_default(forward_to_default) ,
44 m_forward_to_location(forward_to_default) ,
47 m_error_timer(*this,&
Forward::onErrorTimeout,m_es) ,
48 m_continue_timer(*this,&
Forward::onContinueTimeout,m_es) ,
50 m_has_connected(false) ,
60 if( m_client_ptr.get() )
61 m_client_ptr->messageDoneSignal().disconnect() ;
62 if( m_routing_filter )
63 m_routing_filter->doneSignal().disconnect() ;
64 m_client_ptr.deletedSignal().disconnect() ;
65 m_client_ptr.deleteSignal().disconnect() ;
66 m_client_ptr.eventSignal().disconnect() ;
69void GSmtp::Forward::onContinueTimeout()
71 G_ASSERT( m_store !=
nullptr ) ;
79bool GSmtp::Forward::sendNext()
84 std::unique_ptr<GStore::StoredMessage> message( ++m_iter ) ;
85 if( message ==
nullptr )
89 else if( message->toCount() == 0U && m_config.fail_if_no_remote_recipients )
91 G_WARNING(
"GSmtp::Forward::sendNext: forwarding [" << message->id().str() <<
"]: failing message with no remote recipients" ) ;
92 message->fail(
"no remote recipients" , 0 ) ;
94 else if( message->toCount() == 0U )
96 G_DEBUG(
"GSmtp::Forward::sendNext: forwarding [" << message->id().str() <<
"]: skipping message with no remote recipients" ) ;
100 G_LOG(
"GSmtp::Forward::sendNext: forwarding [" << message->id().str() <<
"]" << messageInfo(*message) ) ;
101 start( std::move(message) ) ;
105 if( m_message_count != 0U )
106 G_LOG(
"GSmtp::Forward: forwarding: no more messages to send" ) ;
112 G_LOG(
"GSmtp::Forward::sendMessage: forwarding [" << message->id().str() <<
"]" << messageInfo(*message) ) ;
113 start( std::move(message) ) ;
116void GSmtp::Forward::start( std::unique_ptr<GStore::StoredMessage> message )
119 if( !message->forwardTo().empty() )
122 m_message = std::move( message ) ;
124 m_routing_filter = m_ff.newFilter( m_es , Filter::Type::routing , m_config.filter_config , m_config.filter_spec ) ;
125 G_LOG_MORE(
"GSmtp::Forward::start: routing-filter [" << m_routing_filter->id() <<
"]: [" << m_message->id().str() <<
"]" ) ;
126 m_routing_filter->doneSignal().connect(
G::Slot::slot(*
this,&Forward::routingFilterDone) ) ;
127 m_routing_filter->start( m_message->id() ) ;
129 else if( updateClient( *message ) )
131 m_client_ptr->sendMessage( std::move(message) ) ;
135 m_continue_timer.startTimer( 0U ) ;
139void GSmtp::Forward::routingFilterDone(
int filter_result )
141 G_ASSERT( m_routing_filter.get() !=
nullptr ) ;
142 G_ASSERT( m_message.get() !=
nullptr ) ;
143 G_ASSERT(
static_cast<int>(m_routing_filter->result()) == filter_result ) ;
144 G_DEBUG(
"GSmtp::Forward::routingFilterDone: result=" << filter_result ) ;
146 G_LOG_IF( !m_routing_filter->quiet() ,
"GSmtp::Forward::routingFilterDone: routing-filter "
147 "[" << m_routing_filter->id() <<
"]: [" << m_message->id().str() <<
"]: "
148 << m_routing_filter->str(Filter::Type::client) ) ;
150 const bool ok = filter_result == 0 && m_message ;
151 const bool abandon = filter_result == 1 ;
154 std::string reopen_error = ok ? m_message->reopen() : std::string() ;
155 bool continue_ = true ;
156 if( ok && reopen_error.empty() )
158 if( updateClient( *m_message ) )
161 m_client_ptr->sendMessage( std::move(m_message) ) ;
170 m_message->fail(
"routing filter failed" , 0 ) ;
176 if( m_store ==
nullptr )
177 m_message_done_signal.emit( { 0 , abandon?
"":
"routing failed" ,
false } ) ;
179 m_continue_timer.startTimer( 0U ) ;
185 bool new_address = m_forward_to_address != message.forwardToAddress() ;
186 bool new_selector = m_selector != message.clientAccountSelector() ;
187 if( unconnectable( message.forwardToAddress() ) )
189 G_LOG(
"GSmtp::Forward::updateClient: forwarding [" << message.id().str() <<
"]: "
190 "skipping message with unconnectable address [" << message.forwardToAddress() <<
"]" ) ;
193 else if( m_client_ptr.get() ==
nullptr )
195 G_DEBUG(
"GSmtpForward::updateClient: new client [" << message.forwardToAddress() <<
"][" << message.clientAccountSelector() <<
"]" ) ;
196 newClient( message ) ;
198 else if( m_forward_to_address != message.forwardToAddress() ||
199 m_selector != message.clientAccountSelector() )
201 m_client_ptr->quitAndFinish() ;
203 std::ostringstream ss ;
204 if( new_address ) ss <<
"[" << message.forwardToAddress() <<
"]" ;
205 if( new_address && new_selector ) ss <<
" and " ;
206 if( new_selector ) ss <<
"account selector [" << message.clientAccountSelector() <<
"]" ;
207 G_LOG(
"GSmtpForward::updateClient: forwarding [" << message.id().str() <<
"]: new connection for " << ss.str() ) ;
209 newClient( message ) ;
211 G_ASSERT( m_client_ptr.get() ) ;
217 m_has_connected = false ;
218 m_forward_to_address = message.forwardToAddress() ;
219 m_selector = message.clientAccountSelector() ;
221 if( m_client_ptr.get() )
222 m_client_ptr->messageDoneSignal().disconnect() ;
224 if( m_forward_to_address.empty() )
225 m_forward_to_location = m_forward_to_default ;
229 m_client_ptr.reset( std::make_unique<GSmtp::Client>(
GNet::ExceptionSink(&m_client_ptr,
nullptr) ,
230 m_ff , m_forward_to_location , m_secrets , m_config ) ) ;
232 m_client_ptr->messageDoneSignal().connect(
G::Slot::slot(*
this,&Forward::onMessageDoneSignal) ) ;
238 if( m_client_ptr.get() )
239 m_client_ptr->quitAndFinish() ;
242void GSmtp::Forward::onEventSignal(
const std::string & p1 ,
const std::string & p2 ,
const std::string & p3 )
244 m_event_signal.emit( std::string(p1) , std::string(p2) , std::string(p3) ) ;
247void GSmtp::Forward::onDeleteSignal(
const std::string & )
250 G_ASSERT( m_client_ptr.get() ) ;
251 m_has_connected = m_client_ptr->hasConnected() ;
254void GSmtp::Forward::onDeletedSignal(
const std::string & reason )
256 G_DEBUG(
"GSmtp::Forward::onDeletedSignal: [" << reason <<
"]" ) ;
257 if( m_store && !m_has_connected && !m_forward_to_address.empty() )
260 G_ASSERT( !reason.empty() ) ;
261 G_WARNING(
"GSmtp::Forward::onDeletedSignal: smtp connection failed: " << reason ) ;
262 insert( m_unconnectable , m_forward_to_address ) ;
263 m_client_ptr.reset() ;
264 m_continue_timer.startTimer( 0U ) ;
270 m_error_timer.startTimer( 0U ) ;
274void GSmtp::Forward::onErrorTimeout()
279void GSmtp::Forward::onMessageDoneSignal(
const Client::MessageDoneInfo & info )
282 G_ASSERT( m_client_ptr.get() ) ;
283 if( m_client_ptr.get() && m_client_ptr->hasConnected() && m_forward_to_address.empty() &&
284 !m_forward_to_default.resolved() && m_client_ptr->remoteLocation().resolved() )
286 m_forward_to_default = m_client_ptr->remoteLocation() ;
299 m_message_done_signal.emit( info ) ;
309void GSmtp::Forward::onDelete(
const std::string & reason )
311 G_WARNING_IF( !reason.empty() ,
"GSmtp::Forward::onDelete: smtp client error: " << reason ) ;
312 if( m_message.get() )
315 G_ASSERT( !reason.empty() ) ;
316 m_message->fail( reason , 0 ) ;
323 return m_client_ptr.get() ? m_client_ptr->peerAddressString() : std::string() ;
332bool GSmtp::Forward::unconnectable(
const std::string & forward_to )
const
334 return !forward_to.empty() && contains( m_unconnectable , forward_to ) ;
337void GSmtp::Forward::insert(
G::StringArray & array ,
const std::string & value )
339 G_ASSERT( !value.empty() ) ;
340 if( !contains( array , value ) )
341 array.insert( std::lower_bound(array.begin(),array.end(),value) , value ) ;
344bool GSmtp::Forward::contains(
const G::StringArray & array ,
const std::string & value )
346 return !value.empty() && std::binary_search( array.begin() , array.end() , value ) ;
351 std::ostringstream ss ;
352 if( !message.clientAccountSelector().empty() )
353 ss <<
" selector=[" <<
G::Str::printable(message.clientAccountSelector()) <<
"]" ;
354 if( !message.forwardTo().empty() )
356 if( !message.forwardToAddress().empty() )
357 ss <<
" forward-to-address=[" <<
G::Str::printable(message.forwardToAddress()) <<
"]" ;
363 return m_message_done_signal ;
368 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 detected by GNet::EventHandlerList and results in onException() being call...
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
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()
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.
Forward(GNet::ExceptionSink, GStore::MessageStore &store, FilterFactoryBase &, const GNet::Location &forward_to_default, const GAuth::SaslClientSecrets &, const Config &config)
Constructor.
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.
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.
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.