E-MailRelay
gprotocolmessageforward.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gprotocolmessageforward.cpp
19///
20
21#include "gdef.h"
24#include "gnullfilter.h"
25#include "gexecutablefilter.h"
26#include "gmessagestore.h"
27#include "gstr.h"
28#include "glog.h"
29
31 MessageStore & store , FilterFactory & ff , std::unique_ptr<ProtocolMessage> pm ,
32 const GSmtp::Client::Config & client_config ,
33 const GAuth::SaslClientSecrets & client_secrets , const std::string & server ) :
34 m_es(es) ,
35 m_store(store) ,
36 m_ff(ff) ,
37 m_client_location(server) ,
38 m_client_config(client_config) ,
39 m_client_secrets(client_secrets) ,
40 m_pm(pm.release()) ,
41 m_id(MessageId::none()) ,
42 m_done_signal(true) // one-shot, but reset()able
43{
44 // signal plumbing to receive 'done' events
45 m_pm->doneSignal().connect( G::Slot::slot(*this,&ProtocolMessageForward::processDone) ) ;
46 m_client_ptr.deleteSignal().connect( G::Slot::slot(*this,&ProtocolMessageForward::clientDone) ) ;
47}
48
50{
51 m_pm->doneSignal().disconnect() ;
52 m_client_ptr.deleteSignal().disconnect() ;
53 if( m_client_ptr.get() != nullptr )
54 m_client_ptr->messageDoneSignal().disconnect() ;
55}
56
58{
59 return m_pm->doneSignal() ;
60}
61
62GSmtp::ProtocolMessage::DoneSignal & GSmtp::ProtocolMessageForward::doneSignal()
63{
64 return m_done_signal ;
65}
66
67void GSmtp::ProtocolMessageForward::reset()
68{
69 m_pm->reset() ;
70 m_client_ptr.reset() ;
71}
72
73void GSmtp::ProtocolMessageForward::clear()
74{
75 m_pm->clear() ;
76}
77
78GSmtp::MessageId GSmtp::ProtocolMessageForward::setFrom( const std::string & from , const std::string & from_auth )
79{
80 return m_pm->setFrom( from , from_auth ) ;
81}
82
83bool GSmtp::ProtocolMessageForward::addTo( VerifierStatus to_status )
84{
85 return m_pm->addTo( to_status ) ;
86}
87
88void GSmtp::ProtocolMessageForward::addReceived( const std::string & line )
89{
90 m_pm->addReceived( line ) ;
91}
92
93bool GSmtp::ProtocolMessageForward::addText( const char * line_data , std::size_t line_size )
94{
95 return m_pm->addText( line_data , line_size ) ;
96}
97
98std::string GSmtp::ProtocolMessageForward::from() const
99{
100 return m_pm->from() ;
101}
102
103void GSmtp::ProtocolMessageForward::process( const std::string & auth_id , const std::string & peer_socket_address ,
104 const std::string & peer_certificate )
105{
106 m_done_signal.reset() ; // one-shot reset
107 m_pm->process( auth_id , peer_socket_address , peer_certificate ) ;
108}
109
110void GSmtp::ProtocolMessageForward::processDone( bool success , const MessageId & id , const std::string & response ,
111 const std::string & reason )
112{
113 G_DEBUG( "ProtocolMessageForward::processDone: " << (success?1:0) << " "
114 << id.str() << " [" << response << "] [" << reason << "]" ) ;
115 G::CallFrame this_( m_call_stack ) ;
116 if( success && id.valid() )
117 {
118 m_id = id ;
119
120 // the message is now stored -- start the forwarding using the Client object
121 bool nothing_to_do = false ;
122 std::string error = forward( id , nothing_to_do ) ;
123 if( this_.deleted() ) return ; // just in case
124 if( !error.empty() || nothing_to_do )
125 {
126 // immediate failure or no recipients
127 m_done_signal.emit( success , id , "forwarding failed" , error ) ;
128 }
129 }
130 else
131 {
132 // filter fail-or-abandon, or message storage failed
133 m_done_signal.emit( success , id , std::string(response) , std::string(reason) ) ;
134 }
135}
136
137std::string GSmtp::ProtocolMessageForward::forward( const MessageId & id , bool & nothing_to_do )
138{
139 try
140 {
141 nothing_to_do = false ;
142 G_DEBUG( "GSmtp::ProtocolMessageForward::forward: forwarding message " << id.str() ) ;
143
144 std::unique_ptr<StoredMessage> message = m_store.get( id ) ;
145 G_LOG( "GSmtp::ProtocolMessageForward::forward: processing message \"" << message->location() << "\"" ) ;
146
147 if( message->toCount() == 0U )
148 {
149 // use our local delivery mechanism, not the downstream server's
150 nothing_to_do = true ;
151 message->destroy() ; // (already copied to "*.local")
152 }
153 else
154 {
155 if( m_client_ptr.get() == nullptr )
156 {
157 m_client_ptr.reset( std::make_unique<Client>( GNet::ExceptionSink(m_client_ptr,m_es.esrc()),
158 m_ff , m_client_location , m_client_secrets , m_client_config ) ) ;
159 m_client_ptr->messageDoneSignal().connect( G::Slot::slot( *this ,
160 &GSmtp::ProtocolMessageForward::messageDone ) ) ;
161 }
162 m_client_ptr->sendMessage( std::unique_ptr<StoredMessage>(message.release()) ) ;
163 }
164 return std::string() ;
165 }
166 catch( std::exception & e ) // send forwarding errors back to the remote client via the server protocol
167 {
168 G_WARNING( "GSmtp::ProtocolMessageForward::forward: forwarding exception: " << e.what() ) ;
169 std::string e_what = e.what() ;
170 if( e_what.empty() )
171 e_what = "exception" ;
172 return e_what ;
173 }
174}
175
176void GSmtp::ProtocolMessageForward::messageDone( const std::string & reason )
177{
178 G_DEBUG( "GSmtp::ProtocolMessageForward::messageDone: \"" << reason << "\"" ) ;
179 const bool ok = reason.empty() ;
180 m_done_signal.emit( ok , m_id , ok?"":"forwarding failed" , std::string(reason) ) ; // one-shot
181}
182
183void GSmtp::ProtocolMessageForward::clientDone( const std::string & reason )
184{
185 G_DEBUG( "GSmtp::ProtocolMessageForward::clientDone: \"" << reason << "\"" ) ;
186 const bool ok = reason.empty() ;
187 m_done_signal.emit( ok , m_id , ok?"":"forwarding failed" , std::string(reason) ) ; // one-shot
188}
189
An interface used by GAuth::SaslClient to obtain a client id and its authentication secret.
G::Slot::Signal< const std::string & > & deleteSignal()
A signal that is triggered as the client is deleted following an exception handled by this class.
Definition: gclientptr.cpp:42
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
A factory interface for GSmtp::Filter message processors.
A somewhat opaque identifer for a MessageStore message.
Definition: gmessagestore.h:43
A class which allows SMTP messages to be stored and retrieved.
Definition: gmessagestore.h:73
void processDone(bool, const MessageId &, const std::string &, const std::string &)
Called by derived classes that have intercepted the storageDoneSignal() when their own post-storage p...
ProtocolMessageForward(GNet::ExceptionSink, MessageStore &store, FilterFactory &, std::unique_ptr< ProtocolMessage > pm, const GSmtp::Client::Config &client_config, const GAuth::SaslClientSecrets &client_secrets, const std::string &remote_server_address)
Constructor.
~ProtocolMessageForward() override
Destructor.
ProtocolMessage::DoneSignal & storageDoneSignal()
Returns the signal which is used to signal that the storage is complete.
An object to represent a nested execution context.
Definition: gcall.h:87
Slot< Args... > slot(TSink &sink, void(TSink::*method)(Args...))
A factory function for Slot objects.
Definition: gslot.h:201
A structure containing GSmtp::Client configuration parameters.
Definition: gsmtpclient.h:57