E-MailRelay
gsmtpserversend.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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 gsmtpserversend.cpp
19///
20
21#include "gdef.h"
22#include "gsmtpserversend.h"
23#include "gstringfield.h"
24#include "gstringview.h"
25#include "gbase64.h"
26#include "gstr.h"
27
29 m_sender(sender)
30{
31}
32
34{
35 m_sender = sender ;
36}
37
38void GSmtp::ServerSend::sendChallenge( const std::string & challenge )
39{
40 send( "334 " + G::Base64::encode(challenge) ) ;
41}
42
43void GSmtp::ServerSend::sendGreeting( const std::string & text , bool enabled )
44{
45 if( enabled )
46 send( "220 " + text ) ;
47 else
48 sendDisabled() ;
49}
50
51void GSmtp::ServerSend::sendReadyForTls()
52{
53 send( "220 ready to start tls" , /*go-secure=*/ true ) ;
54}
55
56void GSmtp::ServerSend::sendInvalidArgument()
57{
58 send( "501 invalid argument" ) ;
59}
60
61void GSmtp::ServerSend::sendAuthenticationCancelled()
62{
63 send( "501 authentication cancelled" ) ;
64}
65
66void GSmtp::ServerSend::sendInsecureAuth( bool with_starttls_help )
67{
68 if( with_starttls_help )
69 send( "504 unsupported authentication mechanism: use starttls" ) ;
70 else
71 send( "504 unsupported authentication mechanism" ) ;
72}
73
74void GSmtp::ServerSend::sendBadMechanism( const std::string & preferred )
75{
76 if( preferred.empty() )
77 send( "504 unsupported authentication mechanism" ) ;
78 else
79 send( "432 " + G::Str::upper(preferred) + " password transition needed" ) ; // RFC-4954 6
80}
81
82void GSmtp::ServerSend::sendAuthDone( bool ok )
83{
84 if( ok )
85 send( "235 authentication successful" ) ;
86 else
87 send( "535 authentication failed" ) ;
88}
89
90void GSmtp::ServerSend::sendBadDataOutOfSequence()
91{
92 send( "503 invalid data command with binarymime -- use RSET to resynchronise" ) ;
93}
94
95void GSmtp::ServerSend::sendOutOfSequence()
96{
97 send( "503 command out of sequence -- use RSET to resynchronise" ) ;
98}
99
100void GSmtp::ServerSend::sendMissingParameter()
101{
102 send( "501 parameter required" ) ;
103}
104
105void GSmtp::ServerSend::sendQuitOk()
106{
107 send( "221 OK" ) ;
108}
109
110void GSmtp::ServerSend::sendVerified( const std::string & user )
111{
112 send( "250 " + user ) ;
113}
114
115void GSmtp::ServerSend::sendCannotVerify()
116{
117 send( "252 cannot vrfy" ) ; // RFC-5321 7.3
118}
119
120void GSmtp::ServerSend::sendNotVerified( const std::string & response , bool temporary )
121{
122 send( (temporary?"450":"550") + std::string(1U,' ') + response ) ;
123}
124
125void GSmtp::ServerSend::sendWillAccept( const std::string & user )
126{
127 send( "252 cannot verify but will accept: " + user ) ;
128}
129
130void GSmtp::ServerSend::sendUnrecognised( const std::string & )
131{
132 send( "500 command unrecognized" ) ;
133}
134
135void GSmtp::ServerSend::sendNotImplemented()
136{
137 send( "502 command not implemented" ) ;
138}
139
140void GSmtp::ServerSend::sendAuthRequired( bool with_starttls_help )
141{
142 if( with_starttls_help )
143 send( "530 authentication required: use starttls" ) ;
144 else
145 send( "530 authentication required" ) ;
146}
147
148void GSmtp::ServerSend::sendDisabled()
149{
150 send( "421 service not available" ) ;
151}
152
153void GSmtp::ServerSend::sendEncryptionRequired( bool with_starttls_help )
154{
155 if( with_starttls_help )
156 send( "530 encryption required: use starttls" ) ; // 530 sic
157 else
158 send( "530 encryption required" ) ;
159}
160
161void GSmtp::ServerSend::sendNoRecipients()
162{
163 send( "554 no valid recipients" ) ;
164}
165
166void GSmtp::ServerSend::sendTooBig()
167{
168 send( "552 message size exceeds fixed maximum message size" ) ; // RFC-1427
169}
170
171void GSmtp::ServerSend::sendDataReply()
172{
173 send( "354 start mail input -- end with <CRLF>.<CRLF>" ) ;
174}
175
176void GSmtp::ServerSend::sendRsetReply()
177{
178 send( "250 state reset" ) ;
179}
180
181void GSmtp::ServerSend::sendMailReply( const std::string & from )
182{
183 sendOk( "sender <" + from + "> OK" ) ; // RFC-2920 3.2 (10)
184}
185
186void GSmtp::ServerSend::sendCompletionReply( bool ok , int response_code , const std::string & response )
187{
188 if( ok )
189 sendOk( "message processed" ) ;
190 else if( response_code >= 400 && response_code < 600 )
191 send( G::Str::fromInt(response_code).append(1U,' ').append(response) ) ;
192 else
193 send( "452 " + response ) ; // 452=>"action not taken"
194}
195
196void GSmtp::ServerSend::sendFailed()
197{
198 send( "554 transaction failed" ) ;
199}
200
201void GSmtp::ServerSend::sendRcptReply( const std::string & to , bool is_local )
202{
203 // RFC-2920 3.2 (10)
204 sendOk( std::string("recipient <").append(to).append(is_local?"> ":"> ").append("OK") ) ;
205}
206
207void GSmtp::ServerSend::sendBadFrom( const std::string & response_extra )
208{
209 std::string response = "553 mailbox name not allowed" ;
210 if( !response_extra.empty() )
211 {
212 response.append( ": " ) ;
213 response.append( response_extra ) ;
214 }
215 send( response ) ;
216}
217
218void GSmtp::ServerSend::sendBadTo( const std::string & to , const std::string & text , bool temporary )
219{
220 send( G::Str::join( " " ,
221 std::string(temporary?"450":"550") ,
222 to.empty() || G::Str::isPrintableAscii(to) ? std::string() : ("recipient <" + to + ">") ,
223 text ) ) ;
224}
225
226void GSmtp::ServerSend::sendEhloReply( const Advertise & advertise )
227{
228 static constexpr G::string_view crlf( "\015\012" , 2U ) ;
229
230 std::ostringstream ss ;
231 ss << "250-" << G::Str::printable(advertise.hello) << crlf ;
232
233 if( advertise.max_size != 0U )
234 ss << "250-SIZE " << advertise.max_size << crlf ; // RFC-1427
235
236 if( !advertise.mechanisms.empty() )
237 ss << "250-AUTH " << G::Str::join(" ",advertise.mechanisms) << crlf ;
238
239 if( advertise.starttls )
240 ss << "250-STARTTLS" << crlf ;
241
242 if( advertise.vrfy )
243 ss << "250-VRFY" << crlf ; // RFC-2821 3.5.2
244
245 if( advertise.chunking )
246 ss << "250-CHUNKING" << crlf ; // RFC-3030
247
248 if( advertise.binarymime )
249 ss << "250-BINARYMIME" << crlf ; // RFC-3030
250
251 if( advertise.pipelining )
252 ss << "250-PIPELINING" << crlf ; // RFC-2920
253
254 if( advertise.smtputf8 )
255 ss << "250-SMTPUTF8" << crlf ; // RFC-6531
256
257 ss << "250 8BITMIME" ;
258
259 send( ss ) ;
260}
261
262void GSmtp::ServerSend::sendHeloReply()
263{
264 sendOk( "hello" ) ;
265}
266
267void GSmtp::ServerSend::sendOk( const std::string & text )
268{
269 send( std::string("250 ").append(text) ) ;
270}
271
272#ifndef G_LIB_SMALL
273void GSmtp::ServerSend::sendOk()
274{
275 send( "250 OK" ) ;
276}
277#endif
278
279void GSmtp::ServerSend::send( const char * line )
280{
281 send( std::string(line) ) ;
282}
283
284void GSmtp::ServerSend::send( std::string line_in , bool go_secure )
285{
286 G_LOG( "GSmtp::ServerSend: tx>>: \"" << G::Str::printable(line_in) << "\"" ) ;
287 static const char * crlf = "\015\012" ;
288 m_sender->protocolSend( G::Str::printable(line_in).append(crlf,2U) , go_secure || sendFlush() ) ;
289 if( go_secure )
290 m_sender->protocolSecure() ;
291}
292
293void GSmtp::ServerSend::send( const std::ostringstream & ss )
294{
295 std::string s = ss.str() ;
296 for( G::StringField f(s,"\r\n",2U) ; f ; ++f )
297 G_LOG( "GSmtp::ServerSend: tx>>: \"" << f() << "\"" ) ;
298 static const char * crlf = "\015\012" ;
299 m_sender->protocolSend( s.append(crlf,2U) , sendFlush() ) ;
300}
301
ServerSend(ServerSender *)
Constructor.
void setSender(ServerSender *)
Sets the sender interface pointer.
An interface used by ServerProtocol to send protocol responses.
static std::string encode(string_view, string_view line_break={})
Encodes the given string, optionally inserting line-breaks to limit the line length.
Definition: gbase64.cpp:82
static bool isPrintableAscii(string_view s) noexcept
Returns true if every character is a 7-bit, non-control character (ie.
Definition: gstr.cpp:416
static std::string join(string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
Definition: gstr.cpp:1224
static std::string fromInt(int i)
Converts int 'i' to a string.
Definition: gstr.h:598
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 ...
Definition: gstr.cpp:916
static std::string upper(string_view)
Returns a copy of 's' in which all seven-bit lower-case characters have been replaced by upper-case c...
Definition: gstr.cpp:839
A zero-copy string field iterator where the field separators are short fixed strings.
Definition: gstringfield.h:53
A class like c++17's std::string_view.
Definition: gstringview.h:51
bool enabled() noexcept
Returns true if pop code is built in.