E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gclientprotocol.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2018 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 gclientprotocol.h
19 ///
20
21 #ifndef G_SMTP_CLIENT_PROTOCOL_H
22 #define G_SMTP_CLIENT_PROTOCOL_H
23
24 #include "gdef.h"
25 #include "gsmtp.h"
26 #include "gmessagestore.h"
27 #include "gsaslclient.h"
28 #include "gsecrets.h"
29 #include "gslot.h"
30 #include "gstrings.h"
31 #include "gtimer.h"
32 #include "gexception.h"
33 #include <memory>
34 #include <iostream>
35
36 namespace GSmtp
37 {
38 class ClientProtocol ;
39 class ClientProtocolReply ;
40 }
41
42 /// \class GSmtp::ClientProtocolReply
43 /// A private implementation class used
44 /// by ClientProtocol.
45 ///
46 class GSmtp::ClientProtocolReply
47 {
48 public:
49 enum Type
50 {
51 PositivePreliminary = 1 ,
52 PositiveCompletion = 2 ,
53 PositiveIntermediate = 3 ,
54 TransientNegative = 4 ,
55 PermanentNegative = 5
56 } ;
57 enum SubType
58 {
59 Syntax = 0 ,
60 Information = 1 ,
61 Connections = 2 ,
62 MailSystem = 3 ,
63 Invalid_SubType = 4
64 } ;
65 enum Value
66 {
67 Internal_filter_ok = 222 ,
68 Internal_filter_abandon = 223 ,
69 Internal_secure = 224 ,
70 ServiceReady_220 = 220 ,
71 Ok_250 = 250 ,
72 Authenticated_235 = 235 ,
73 Challenge_334 = 334 ,
74 OkForData_354 = 354 ,
75 SyntaxError_500 = 500 ,
76 SyntaxError_501 = 501 ,
77 NotImplemented_502 = 502 ,
78 BadSequence_503 = 503 ,
79 Internal_filter_error = 590 ,
80 NotAuthenticated_535 = 535 ,
81 NotAvailable_454 = 454 ,
82 Invalid = 0
83 } ;
84
85 static ClientProtocolReply ok() ;
86 ///< Factory function for an ok reply.
87
88 static ClientProtocolReply ok( Value , const std::string & = std::string() ) ;
89 ///< Factory function for an ok reply with a specific 2xx value.
90
91 static ClientProtocolReply error( Value , const std::string & response , const std::string & error_reason ) ;
92 ///< Factory function for an error reply with a specific 5xx value.
93
94 explicit ClientProtocolReply( const std::string & line = std::string() ) ;
95 ///< Constructor for one line of text.
96
97 bool add( const ClientProtocolReply & other ) ;
98 ///< Adds more lines to this reply. Returns false if the
99 ///< numeric values are different.
100
101 bool incomplete() const ;
102 ///< Returns true if the reply is incomplete.
103
104 bool validFormat() const ;
105 ///< Returns true if a valid format.
106
107 bool positive() const ;
108 ///< Returns true if the numeric value of the
109 ///< reply is less that four hundred.
110
111 bool is( Value v ) const ;
112 ///< Returns true if the reply value is 'v'.
113
114 int value() const ;
115 ///< Returns the numeric value of the reply.
116
117 std::string text() const ;
118 ///< Returns the text of the reply, excluding the numeric part,
119 ///< and with embedded newlines.
120
121 std::string errorText() const ;
122 ///< Returns the text() string, plus any error reason, but with
123 ///< the guarantee that the returned string is empty if and only
124 ///< if the reply value is 2xx.
125
126 std::string errorReason() const ;
127 ///< Returns an error reason string, as passed to error().
128
129 bool textContains( std::string s ) const ;
130 ///< Returns true if the text() contains the given substring.
131
132 std::string textLine( const std::string & prefix ) const ;
133 ///< Returns a line of text() which starts with
134 ///< prefix.
135
136 Type type() const ;
137 ///< Returns the reply type (category).
138
139 SubType subType() const ;
140 ///< Returns the reply sub-type.
141
142 private:
143 static bool is_digit( char ) ;
144
145 private:
146 bool m_complete ;
147 bool m_valid ;
148 int m_value ;
149 std::string m_text ;
150 std::string m_reason ; // additional error reason
151 } ;
152
153 /// \class GSmtp::ClientProtocol
154 /// Implements the client-side SMTP protocol.
155 ///
156 class GSmtp::ClientProtocol : private GNet::TimerBase
157 {
158 public:
159 G_EXCEPTION( NotReady , "not ready" ) ;
160 G_EXCEPTION( SmtpError , "smtp error" ) ;
161 G_EXCEPTION( TlsError , "tls/ssl error" ) ;
162 typedef ClientProtocolReply Reply ;
163
164 class Sender /// An interface used by ClientProtocol to send protocol messages.
165 {
166 public: virtual bool protocolSend( const std::string & , size_t offset , bool go_secure ) = 0 ;
167 ///< Called by the Protocol class to send network data to
168 ///< the peer.
169 ///<
170 ///< The offset gives the location of the payload within the
171 ///< string buffer.
172 ///<
173 ///< Returns false if not all of the string was send due to
174 ///< flow control. In this case ClientProtocol::sendDone() should
175 ///< be called as soon as the full string has been sent.
176 ///<
177 ///< Throws on error, eg. if disconnected.
178
179 private: void operator=( const Sender & ) ; // not implemented
180 public: virtual ~Sender() ;
181 } ;
182
183 struct Config /// A structure containing GSmtp::ClientProtocol configuration parameters.
184 {
185 std::string thishost_name ; // EHLO parameter
186 unsigned int response_timeout ;
187 unsigned int ready_timeout ;
188 unsigned int filter_timeout ;
189 bool use_starttls_if_possible ;
190 bool must_use_tls ;
191 bool must_authenticate ;
192 bool anonymous ; // MAIL..AUTH=
193 bool must_accept_all_recipients ;
194 bool eight_bit_strict ; // fail 8bit messages to 7bit server
195 Config( const std::string & name , unsigned int response_timeout ,
196 unsigned int ready_timeout , unsigned int filter_timeout ,
197 bool use_starttls_if_possible , bool must_use_tls ,
198 bool must_authenticate , bool anonymous ,
199 bool must_accept_all_recipients , bool eight_bit_strict ) ;
200 } ;
201
202 ClientProtocol( GNet::ExceptionHandler & , Sender & sender ,
203 const GAuth::Secrets & secrets , Config config , bool in_secure_tunnel ) ;
204 ///< Constructor. The Sender interface is used to send protocol
205 ///< messages to the peer. The references are kept.
206
207 G::Slot::Signal3<int,std::string,std::string> & doneSignal() ;
208 ///< Returns a signal that is raised once the protocol has finished
209 ///< with a given message. The first signal parameter is the SMTP response
210 ///< value, or 0 for an internal error, or -1 for filter-abandon, or -2
211 ///< for a filter-fail. The second parameter is the empty string on success
212 ///< or a non-empty response string. The third parameter contains
213 ///< any additional error reason text.
214
215 G::Slot::Signal0 & filterSignal() ;
216 ///< Returns a signal that is raised when the protocol
217 ///< needs to do message filtering. The callee must call
218 ///< filterDone() when finished.
219
220 void start( const std::string & from , const G::StringArray & to , bool eight_bit ,
221 std::string mail_from_auth , unique_ptr<std::istream> content ) ;
222 ///< Starts transmission of the given message.
223 ///<
224 ///< The doneSignal() is used to indicate that the
225 ///< message has been processed.
226
227 void finish() ;
228 ///< Called after the last message has been sent. Sends a quit
229 ///< command and shuts down the socket.
230
231 void sendDone() ;
232 ///< To be called when a blocked connection becomes unblocked.
233 ///< See ClientProtocol::Sender::protocolSend().
234
235 void filterDone( bool ok , const std::string & response , const std::string & reason ) ;
236 ///< To be called when the Filter interface has done its thing.
237 ///< If ok then the message processing continues; if not ok
238 ///< then the message processing fails with a done signal
239 ///< code of -1 if the response is empty, or -2.
240
241 void secure() ;
242 ///< To be called when the secure socket protocol has been
243 ///< successfully established.
244
245 bool apply( const std::string & rx ) ;
246 ///< Called on receipt of a line of text from the server.
247 ///< Returns true if the protocol is done and the doneSignal()
248 ///< has been emited.
249
250 protected:
251 virtual void onTimeout() override ;
252 ///< Override from GNet::TimerBase.
253
254 private:
255 struct AuthError : public SmtpError
256 {
257 AuthError( const GAuth::SaslClient & , const ClientProtocolReply & ) ;
258 std::string str() const ;
259 } ;
260
261 private:
262 void send( const char * ) ;
263 void send( const char * , const std::string & ) ;
264 void send( const char * , const std::string & , const char * ) ;
265 bool send( const std::string & , bool eot , bool sensitive = false ) ;
266 bool sendLine( std::string & ) ;
267 size_t sendLines() ;
268 void sendEhlo() ;
269 void sendHelo() ;
270 void sendMail() ;
271 void sendMailCore() ;
272 bool endOfContent() const ;
273 bool applyEvent( const Reply & event , bool is_start_event = false ) ;
274 static bool parseReply( Reply & , const std::string & , std::string & ) ;
275 void raiseDoneSignal( int , const std::string & , const std::string & = std::string() ) ;
276 bool serverAuth( const ClientProtocolReply & reply ) const ;
277 G::StringArray serverAuthMechanisms( const ClientProtocolReply & reply ) const ;
278 void startFiltering() ;
279
280 private:
281 enum State {
282 sInit ,
283 sStarted ,
284 sServiceReady ,
285 sSentEhlo ,
286 sSentHelo ,
287 sAuth1 ,
288 sAuth2 ,
289 sSentMail ,
290 sFiltering ,
291 sSentRcpt ,
292 sSentData ,
293 sSentDataStub ,
294 sData ,
295 sSentDot ,
296 sStartTls ,
297 sSentTlsEhlo ,
298 sMessageDone ,
299 sQuitting
300 } ;
301
302 private:
303 Sender & m_sender ;
304 const GAuth::Secrets & m_secrets ;
305 std::string m_thishost ;
306 State m_state ;
307 std::string m_from ;
308 G::StringArray m_to ;
309 size_t m_to_index ;
310 size_t m_to_accepted ;
311 unique_ptr<std::istream> m_content ;
312 bool m_server_has_starttls ;
313 bool m_server_has_auth ;
314 G::StringArray m_server_auth_mechanisms ;
315 bool m_server_secure ;
316 bool m_server_has_8bitmime ;
317 bool m_message_is_8bit ;
318 std::string m_message_mail_from_auth ;
319 Reply m_reply ;
320 bool m_authenticated_with_server ;
321 std::string m_auth_mechanism ;
322 unique_ptr<GAuth::SaslClient> m_sasl ;
323 bool m_must_authenticate ;
324 bool m_anonymous ;
325 bool m_must_accept_all_recipients ;
326 bool m_use_starttls_if_possible ;
327 bool m_must_use_tls ;
328 bool m_in_secure_tunnel ;
329 bool m_strict ;
330 bool m_warned ;
331 unsigned int m_response_timeout ;
332 unsigned int m_ready_timeout ;
333 unsigned int m_filter_timeout ;
334 G::Slot::Signal3<int,std::string,std::string> m_done_signal ;
335 G::Slot::Signal0 m_filter_signal ;
336 } ;
337
338 #endif
GSmtp::ClientProtocol::secure
void secure()
To be called when the secure socket protocol has been successfully established.
Definition: gclientprotocol.cpp:95
gstrings.h
GSmtp
SMTP and message-store classes.
Definition: gadminserver.h:39
GSmtp::ClientProtocolReply::type
Type type() const
Returns the reply type (category).
Definition: gclientprotocol.cpp:797
gsaslclient.h
GSmtp::ClientProtocolReply::error
static ClientProtocolReply error(Value, const std::string &response, const std::string &error_reason)
Factory function for an error reply with a specific 5xx value.
Definition: gclientprotocol.cpp:728
GSmtp::ClientProtocolReply::incomplete
bool incomplete() const
Returns true if the reply is incomplete.
Definition: gclientprotocol.cpp:741
GSmtp::ClientProtocolReply::errorText
std::string errorText() const
Returns the text() string, plus any error reason, but with the guarantee that the returned string is ...
Definition: gclientprotocol.cpp:761
GSmtp::ClientProtocol::ClientProtocol
ClientProtocol(GNet::ExceptionHandler &, Sender &sender, const GAuth::Secrets &secrets, Config config, bool in_secure_tunnel)
Constructor.
Definition: gclientprotocol.cpp:36
GSmtp::ClientProtocol::filterSignal
G::Slot::Signal0 & filterSignal()
Returns a signal that is raised when the protocol needs to do message filtering.
Definition: gclientprotocol.cpp:683
GSmtp::ClientProtocolReply::validFormat
bool validFormat() const
Returns true if a valid format.
Definition: gclientprotocol.cpp:736
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:33
GSmtp::ClientProtocol::doneSignal
G::Slot::Signal3< int, std::string, std::string > & doneSignal()
Returns a signal that is raised once the protocol has finished with a given message.
Definition: gclientprotocol.cpp:678
GSmtp::ClientProtocol::onTimeout
virtual void onTimeout() override
Override from GNet::TimerBase.
Definition: gclientprotocol.cpp:520
GSmtp::ClientProtocol::Config
A structure containing GSmtp::ClientProtocol configuration parameters.
Definition: gclientprotocol.h:183
gslot.h
GSmtp::ClientProtocol::Sender
An interface used by ClientProtocol to send protocol messages.
Definition: gclientprotocol.h:164
GNet::ExceptionHandler
An abstract interface for handling exceptions thrown out of event-loop callbacks (socket events...
Definition: gexceptionhandler.h:44
GSmtp::ClientProtocolReply::is
bool is(Value v) const
Returns true if the reply value is 'v'.
Definition: gclientprotocol.cpp:756
GSmtp::ClientProtocol
Implements the client-side SMTP protocol.
Definition: gclientprotocol.h:156
GSmtp::ClientProtocol::filterDone
void filterDone(bool ok, const std::string &response, const std::string &reason)
To be called when the Filter interface has done its thing.
Definition: gclientprotocol.cpp:568
gsecrets.h
GSmtp::ClientProtocol::finish
void finish()
Called after the last message has been sent.
Definition: gclientprotocol.cpp:87
GSmtp::ClientProtocolReply::ClientProtocolReply
ClientProtocolReply(const std::string &line=std::string())
Constructor for one line of text.
Definition: gclientprotocol.cpp:690
GAuth::Secrets
A simple interface for a store of secrets used in authentication.
Definition: gsecrets.h:40
gtimer.h
GSmtp::ClientProtocolReply::ok
static ClientProtocolReply ok()
Factory function for an ok reply.
Definition: gclientprotocol.cpp:713
GSmtp::ClientProtocolReply::textLine
std::string textLine(const std::string &prefix) const
Returns a line of text() which starts with prefix.
Definition: gclientprotocol.cpp:777
GSmtp::ClientProtocol::sendDone
void sendDone()
To be called when a blocked connection becomes unblocked.
Definition: gclientprotocol.cpp:101
GSmtp::ClientProtocolReply::errorReason
std::string errorReason() const
Returns an error reason string, as passed to error().
Definition: gclientprotocol.cpp:767
gmessagestore.h
GSmtp::ClientProtocolReply::value
int value() const
Returns the numeric value of the reply.
Definition: gclientprotocol.cpp:751
G::Slot::Signal0
A signal class for zero-parameter callbacks.
Definition: gslot.h:193
gexception.h
GSmtp::ClientProtocolReply::subType
SubType subType() const
Returns the reply sub-type.
Definition: gclientprotocol.cpp:803
GSmtp::ClientProtocol::start
void start(const std::string &from, const G::StringArray &to, bool eight_bit, std::string mail_from_auth, unique_ptr< std::istream > content)
Starts transmission of the given message.
Definition: gclientprotocol.cpp:67
GSmtp::ClientProtocol::apply
bool apply(const std::string &rx)
Called on receipt of a line of text from the server.
Definition: gclientprotocol.cpp:141
GAuth::SaslClient
A class that implements the client-side SASL challenge/response concept.
Definition: gsaslclient.h:39
GNet::TimerBase
An interface used by GNet::TimerList to keep track of pending timeouts and to deliver timeout events...
Definition: gtimer.h:40
gsmtp.h
GSmtp::ClientProtocolReply::textContains
bool textContains(std::string s) const
Returns true if the text() contains the given substring.
Definition: gclientprotocol.cpp:824
GSmtp::ClientProtocolReply::add
bool add(const ClientProtocolReply &other)
Adds more lines to this reply.
Definition: gclientprotocol.cpp:813
GSmtp::ClientProtocol::Sender::protocolSend
virtual bool protocolSend(const std::string &, size_t offset, bool go_secure)=0
Called by the Protocol class to send network data to the peer.
GSmtp::ClientProtocolReply::positive
bool positive() const
Returns true if the numeric value of the reply is less that four hundred.
Definition: gclientprotocol.cpp:746
G::Slot::Signal3< int, std::string, std::string >
GSmtp::ClientProtocolReply
A private implementation class used by ClientProtocol.
Definition: gclientprotocol.h:46
GSmtp::ClientProtocolReply::text
std::string text() const
Returns the text of the reply, excluding the numeric part, and with embedded newlines.
Definition: gclientprotocol.cpp:772