E-MailRelay
gprotocolmessagestore.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 gprotocolmessagestore.cpp
19///
20
21#include "gdef.h"
23#include "gmessagestore.h"
24#include "gstr.h"
25#include "gassert.h"
26#include "glog.h"
27
28GSmtp::ProtocolMessageStore::ProtocolMessageStore( MessageStore & store , std::unique_ptr<Filter> filter ) :
29 m_store(store) ,
30 m_filter(std::move(filter))
31{
32 m_filter->doneSignal().connect( G::Slot::slot(*this,&ProtocolMessageStore::filterDone) ) ;
33}
34
36{
37 m_filter->doneSignal().disconnect() ;
38}
39
41{
42 G_DEBUG( "GSmtp::ProtocolMessageStore::reset" ) ;
43 clear() ;
44}
45
47{
48 G_DEBUG( "GSmtp::ProtocolMessageStore::clear" ) ;
49 m_new_msg.reset() ;
50 m_from.erase() ;
51 m_filter->cancel() ;
52}
53
54GSmtp::MessageId GSmtp::ProtocolMessageStore::setFrom( const std::string & from , const std::string & from_auth )
55{
56 G_DEBUG( "GSmtp::ProtocolMessageStore::setFrom: " << from ) ;
57
58 if( from.length() == 0U ) // => probably a failure notification message
59 G_WARNING( "GSmtp::ProtocolMessageStore: empty MAIL-FROM return path" ) ;
60
61 G_ASSERT( m_new_msg == nullptr ) ;
62 clear() ; // just in case
63
64 m_new_msg = m_store.newMessage( from , from_auth , "" ) ;
65
66 m_from = from ;
67 return m_new_msg->id() ;
68}
69
71{
72 G_DEBUG( "GSmtp::ProtocolMessageStore::addTo: " << to_status.recipient ) ;
73 G_ASSERT( m_new_msg != nullptr ) ;
74 if( to_status.recipient.empty() )
75 {
76 return false ;
77 }
78 else if( !to_status.is_valid )
79 {
80 G_WARNING( "GSmtp::ProtocolMessage: rejecting recipient \"" << to_status.recipient << "\": "
81 << to_status.response << (to_status.reason.empty()?"":": ") << to_status.reason ) ;
82 return false ;
83 }
84 else
85 {
86 m_new_msg->addTo( to_status.address , to_status.is_local ) ;
87 return true ;
88 }
89}
90
91void GSmtp::ProtocolMessageStore::addReceived( const std::string & received_line )
92{
93 G_DEBUG( "GSmtp::ProtocolMessageStore::addReceived" ) ;
94 if( m_new_msg != nullptr )
95 m_new_msg->addTextLine( received_line ) ;
96}
97
98bool GSmtp::ProtocolMessageStore::addText( const char * line_data , std::size_t line_size )
99{
100 G_ASSERT( m_new_msg != nullptr ) ;
101 if( m_new_msg == nullptr )
102 return true ;
103 return m_new_msg->addText( line_data , line_size ) ;
104}
105
107{
108 return m_new_msg ? m_from : std::string() ;
109}
110
111void GSmtp::ProtocolMessageStore::process( const std::string & session_auth_id ,
112 const std::string & peer_socket_address , const std::string & peer_certificate )
113{
114 try
115 {
116 G_DEBUG( "GSmtp::ProtocolMessageStore::process: \""
117 << session_auth_id << "\", \"" << peer_socket_address << "\"" ) ;
118 G_ASSERT( m_new_msg != nullptr ) ;
119 if( m_new_msg == nullptr )
120 throw G::Exception( "internal error" ) ; // never gets here
121
122 // write ".new" envelope
123 bool local_only = m_new_msg->prepare( session_auth_id , peer_socket_address , peer_certificate ) ;
124 if( local_only )
125 {
126 // local-mailbox only -- handle a bit like filter-abandonded
127 m_done_signal.emit( true , MessageId::none() , std::string() , std::string() ) ;
128 }
129 else
130 {
131 // start the filter
132 if( !m_filter->simple() )
133 G_LOG( "GSmtp::ProtocolMessageStore::process: filter start: [" << m_filter->id() << "] "
134 << "[" << m_new_msg->location() << "]" ) ;
135 m_filter->start( m_new_msg->id() ) ;
136 }
137 }
138 catch( std::exception & e ) // catch filtering errors
139 {
140 G_WARNING( "GSmtp::ProtocolMessageStore::process: message processing exception: " << e.what() ) ;
141 clear() ;
142 m_done_signal.emit( false , MessageId::none() , "failed" , e.what() ) ;
143 }
144}
145
146void GSmtp::ProtocolMessageStore::filterDone( int filter_result )
147{
148 try
149 {
150 G_DEBUG( "GSmtp::ProtocolMessageStore::filterDone: " << filter_result ) ;
151 G_ASSERT( m_new_msg != nullptr ) ;
152 if( m_new_msg == nullptr )
153 throw G::Exception( "internal error" ) ; // never gets here
154
155 const bool ok = filter_result == 0 ;
156 const bool abandon = filter_result == 1 ;
157 const bool rescan = m_filter->special() ;
158 G_ASSERT( m_filter->reason().empty() == (ok || abandon) ) ; // filter post-condition
159
160 if( !m_filter->simple() )
161 G_LOG( "GSmtp::ProtocolMessageStore::filterDone: filter done: " << m_filter->str(true) ) ;
162
164 if( ok )
165 {
166 // commit the message to the store
167 m_new_msg->commit( true ) ;
168 id = m_new_msg->id() ;
169 }
170 else if( abandon )
171 {
172 // make a token effort to commit the message
173 // but ignore errors and dont set the id
174 m_new_msg->commit( false ) ;
175 }
176 else
177 {
178 G_LOG_S( "GSmtp::ProtocolMessageStore::filterDone: rejected by filter: [" << m_filter->reason() << "]" ) ;
179 }
180
181 if( rescan )
182 {
183 // pick up any new messages create by the filter
184 m_store.rescan() ;
185 }
186
187 // save the filter output before it is clear()ed
188 std::string filter_response = (ok||abandon) ? std::string() : m_filter->response() ;
189 std::string filter_reason = (ok||abandon) ? std::string() : m_filter->reason() ;
190
191 clear() ;
192 m_done_signal.emit( ok || abandon , id , filter_response , filter_reason ) ;
193 }
194 catch( std::exception & e ) // catch filtering errors
195 {
196 G_WARNING( "GSmtp::ProtocolMessageStore::filterDone: filter exception: " << e.what() ) ;
197 clear() ;
198 m_done_signal.emit( false , MessageId::none() , "rejected" , e.what() ) ;
199 }
200}
201
203{
204 return m_done_signal ;
205}
206
A somewhat opaque identifer for a MessageStore message.
Definition: gmessagestore.h:43
static MessageId none()
Returns an in-valid() id.
A class which allows SMTP messages to be stored and retrieved.
Definition: gmessagestore.h:73
void clear() override
Override from GSmtp::ProtocolMessage.
ProtocolMessage::DoneSignal & doneSignal() override
Override from GSmtp::ProtocolMessage.
void reset() override
Override from GSmtp::ProtocolMessage.
~ProtocolMessageStore() override
Destructor.
std::string from() const override
Override from GSmtp::ProtocolMessage.
ProtocolMessageStore(MessageStore &store, std::unique_ptr< Filter >)
Constructor.
void process(const std::string &auth_id, const std::string &peer_socket_address, const std::string &peer_certificate) override
Override from GSmtp::ProtocolMessage.
void addReceived(const std::string &) override
Override from GSmtp::ProtocolMessage.
bool addTo(VerifierStatus to_status) override
Override from GSmtp::ProtocolMessage.
MessageId setFrom(const std::string &from_user, const std::string &) override
Override from GSmtp::ProtocolMessage.
bool addText(const char *, std::size_t) override
Override from GSmtp::ProtocolMessage.
A structure returned by GSmtp::Verifier to describe the status of a 'rcpt-to' or 'vrfy' recipient.
A general-purpose exception class derived from std::exception and containing an error message.
Definition: gexception.h:45
Slot< Args... > slot(TSink &sink, void(TSink::*method)(Args...))
A factory function for Slot objects.
Definition: gslot.h:201