E-MailRelay

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