E-MailRelay

gpopserverprotocol.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 gpopserverprotocol.cpp
19///
20
21#include "gdef.h"
22#include "gpopserverprotocol.h"
23#include "gsaslserverfactory.h"
24#include "gstr.h"
25#include "gstringtoken.h"
26#include "gtest.h"
27#include "gbase64.h"
28#include "gassert.h"
29#include "glog.h"
30#include <sstream>
31#include <algorithm>
32
33 GPop::ServerProtocol::ServerProtocol( Sender & sender , Security & security , Store & store ,
34 const GAuth::SaslServerSecrets & server_secrets , const std::string & sasl_server_config ,
35 const Text & text , const GNet::Address & peer_address , const Config & config ) :
36 m_text(text) ,
37 m_sender(sender) ,
38 m_security(security) ,
39 m_store(store) ,
40 m_config(config) ,
41 m_sasl(GAuth::SaslServerFactory::newSaslServer(server_secrets,true,sasl_server_config,config.sasl_server_challenge_domain)) ,
42 m_peer_address(peer_address) ,
43 m_fsm(State::sStart,State::sEnd,State::s_Same,State::s_Any)
44{
45 // (dont send anything to the peer from this ctor -- the Sender object is not fuly constructed)
46
47 m_fsm( Event::eStat , State::sActive , State::sActive , &ServerProtocol::doStat ) ;
48 m_fsm( Event::eList , State::sActive , State::sActive , &ServerProtocol::doList ) ;
49 m_fsm( Event::eRetr , State::sActive , State::sData , &ServerProtocol::doRetr , State::sActive ) ;
50 m_fsm( Event::eTop , State::sActive , State::sData , &ServerProtocol::doTop , State::sActive ) ;
51 m_fsm( Event::eDele , State::sActive , State::sActive , &ServerProtocol::doDele ) ;
52 m_fsm( Event::eNoop , State::sActive , State::sActive , &ServerProtocol::doNoop ) ;
53 m_fsm( Event::eRset , State::sActive , State::sActive , &ServerProtocol::doRset ) ;
54 m_fsm( Event::eUidl , State::sActive , State::sActive , &ServerProtocol::doUidl ) ;
55 m_fsm( Event::eSent , State::sData , State::sActive , &ServerProtocol::doNothing ) ;
56 m_fsm( Event::eUser , State::sStart , State::sStart , &ServerProtocol::doUser ) ;
57 m_fsm( Event::ePass , State::sStart , State::sActive , &ServerProtocol::doPass , State::sStart ) ;
58 m_fsm( Event::eApop , State::sStart , State::sActive , &ServerProtocol::doApop , State::sStart ) ;
59 m_fsm( Event::eQuit , State::sStart , State::sEnd , &ServerProtocol::doQuitEarly ) ;
60 m_fsm( Event::eCapa , State::sStart , State::sStart , &ServerProtocol::doCapa ) ;
61 m_fsm( Event::eCapa , State::sActive , State::sActive , &ServerProtocol::doCapa ) ;
62 if( m_security.securityEnabled() )
63 m_fsm( Event::eStls , State::sStart , State::sStart , &ServerProtocol::doStls , State::sStart ) ;
64 m_fsm( Event::eAuth , State::sStart , State::sAuth , &ServerProtocol::doAuth , State::sStart ) ;
65 m_fsm( Event::eAuthData , State::sAuth , State::sAuth , &ServerProtocol::doAuthData , State::sStart ) ;
66 m_fsm( Event::eAuthComplete , State::sAuth , State::sActive , &ServerProtocol::doAuthComplete ) ;
67 m_fsm( Event::eCapa , State::sActive , State::sActive , &ServerProtocol::doCapa ) ;
68 m_fsm( Event::eQuit , State::sActive , State::sEnd , &ServerProtocol::doQuit ) ;
69}
70
71 void GPop::ServerProtocol::init()
72{
73 sendInit() ;
74}
75
76 void GPop::ServerProtocol::sendInit()
77{
78 std::string greeting = std::string("+OK ",4U).append(m_text.greeting()) ;
79 if( m_sasl->init( m_secure , "APOP" ) )
80 {
81 m_sasl_init_apop = true ;
82 std::string apop_challenge = m_sasl->initialChallenge() ;
83 if( !apop_challenge.empty() )
84 {
85 greeting.append( 1U , ' ' ) ;
86 greeting.append( apop_challenge ) ;
87 }
88 }
89 sendLine( std::move(greeting) ) ;
90}
91
92 void GPop::ServerProtocol::sendOk()
93{
94 sendLine( "+OK\r\n"_sv , true ) ;
95}
96
97 void GPop::ServerProtocol::sendError( const std::string & more )
98{
99 if( more.empty() )
100 sendError() ;
101 else
102 sendLine( std::string("-ERR ",5U).append(more) ) ;
103}
104
105 void GPop::ServerProtocol::sendError()
106{
107 sendLine( "-ERR\r\n"_sv , true ) ;
108}
109
110 void GPop::ServerProtocol::apply( const std::string & line )
111{
112 // decode the event
113 Event event = m_fsm.state() == State::sAuth ? Event::eAuthData : commandEvent(commandWord(line)) ;
114
115 // log the input
116 std::string log_text = G::Str::printable(line) ;
117 if( event == Event::ePass )
118 log_text = (commandPart(line,0U)+" [password not logged]") ;
119 if( event == Event::eAuthData || event == Event::eAuthComplete )
120 log_text = "[authentication response not logged]" ;
121 if( event == Event::eAuth && !commandPart(line,1U).empty() )
122 log_text = commandPart(line,0U) + " " + commandPart(line,1U) ;
123 G_LOG( "GPop::ServerProtocol: rx<<: \"" << log_text << "\"" ) ;
124
125 // apply the event to the state machine
126 State new_state = m_fsm.apply( *this , event , line ) ;
127 const bool protocol_error = new_state == State::s_Any ;
128 if( protocol_error )
129 {
130 G_DEBUG( "GPop::ServerProtocol::apply: protocol error: " << static_cast<int>(event) << " " << static_cast<int>(m_fsm.state()) ) ;
131 sendError() ;
132 }
133
134 // squirt data down the pipe if appropriate
135 if( new_state == State::sData )
136 sendContent() ;
137}
138
139 void GPop::ServerProtocol::sendContent()
140{
141 // send until no more content or until blocked by flow-control
142 std::string line( 200 , '.' ) ;
143 std::size_t n = 0 ;
144 bool eot = false ;
145 while( sendContentLine(line,eot) && !eot )
146 n++ ;
147
148 G_LOG( "GPop::ServerProtocol: tx>>: [" << n << " line(s) of content]" ) ;
149 if( eot )
150 {
151 G_LOG( "GPop::ServerProtocol: tx>>: \".\"" ) ;
152 m_content.reset() ; // free up resources
153 m_fsm.apply( *this , Event::eSent , "" ) ; // State::sData -> State::sActive
154 }
155}
156
157 void GPop::ServerProtocol::resume()
158{
159 // flow control is not an issue for protocol responses because we
160 // always send a complete protocol response in one go -- however,
161 // message content is sent in chunks so the resume() has to send
162 // the next bit
163 G_DEBUG( "GPop::ServerProtocol::resume: flow control released" ) ;
164 if( m_fsm.state() == State::sData )
165 sendContent() ;
166}
167
168 bool GPop::ServerProtocol::sendContentLine( std::string & line , bool & eot )
169{
170 G_ASSERT( m_content != nullptr ) ;
171
172 bool limited = m_in_body && m_body_limit == 0L ;
173 if( m_body_limit > 0L && m_in_body )
174 m_body_limit-- ;
175
176 line.erase( 1U ) ; // leave "."
177 bool eof = !G::Str::readLine( *m_content , line ,
178 m_config.crlf_only ? G::Str::Eol::CrLf : G::Str::Eol::Cr_Lf_CrLf ,
179 /*pre_erase_result=*/false ) ;
180
181 eot = eof || limited ;
182 if( eot ) line.erase( 1U ) ;
183 line.append( "\r\n" , 2U ) ;
184 std::size_t offset = eot ? 0U : ( line.at(1U) == '.' ? 0U : 1U ) ;
185
186 if( !m_in_body && line.length() == (offset+2U) )
187 m_in_body = true ;
188
189 return m_sender.protocolSend( line , offset ) ;
190}
191
192 int GPop::ServerProtocol::commandNumber( const std::string & line , int default_ , std::size_t index ) const
193{
194 int number = default_ ;
195 try
196 {
197 number = G::Str::toInt( commandParameter(line,index) ) ;
198 }
199 catch( G::Str::Overflow & ) // defaulted
200 {
201 }
202 catch( G::Str::InvalidFormat & ) // defaulted
203 {
204 }
205 return number ;
206}
207
208std::string GPop::ServerProtocol::commandWord( const std::string & line ) const
209{
210 return G::Str::upper(commandPart(line,0U)) ;
211}
212
213std::string GPop::ServerProtocol::commandPart( const std::string & line , std::size_t index )
214{
215 std::string_view line_sv( line ) ;
216 G::StringTokenView t( line_sv , G::Str::ws() ) ;
217 for( std::size_t i = 0 ; i < index ; ++t , i++ )
218 {;}
219 return t.valid() ? G::sv_to_string(t()) : std::string() ;
220}
221
222std::string GPop::ServerProtocol::commandParameter( const std::string & line_in , std::size_t index ) const
223{
224 return commandPart( line_in , index ) ;
225}
226
227GPop::ServerProtocol::Event GPop::ServerProtocol::commandEvent( std::string_view command )
228{
229 if( command == "QUIT"_sv ) return Event::eQuit ;
230 if( command == "STAT"_sv ) return Event::eStat ;
231 if( command == "LIST"_sv ) return Event::eList ;
232 if( command == "RETR"_sv ) return Event::eRetr ;
233 if( command == "DELE"_sv ) return Event::eDele ;
234 if( command == "NOOP"_sv ) return Event::eNoop ;
235 if( command == "RSET"_sv ) return Event::eRset ;
236 //
237 if( command == "TOP"_sv ) return Event::eTop ;
238 if( command == "UIDL"_sv ) return Event::eUidl ;
239 if( command == "USER"_sv ) return Event::eUser ;
240 if( command == "PASS"_sv ) return Event::ePass ;
241 if( command == "APOP"_sv ) return Event::eApop ;
242 if( command == "AUTH"_sv ) return Event::eAuth ;
243 if( command == "CAPA"_sv ) return Event::eCapa ;
244 if( command == "STLS"_sv ) return Event::eStls ;
245
246 return Event::eUnknown ;
247}
248
249 void GPop::ServerProtocol::doQuitEarly( const std::string & , bool & )
250{
251 sendLine( std::string("+OK ",4).append(m_text.quit()) ) ;
252 throw ProtocolDone() ;
253}
254
255 void GPop::ServerProtocol::doQuit( const std::string & , bool & )
256{
257 m_store_list.commit() ;
258 sendLine( std::string("+OK ",4U).append(m_text.quit()) ) ;
259 throw ProtocolDone() ;
260}
261
262 void GPop::ServerProtocol::doStat( const std::string & , bool & )
263{
264 sendLine( std::string("+OK ",4U)
265 .append(std::to_string(m_store_list.messageCount()))
266 .append(1U,' ')
267 .append(std::to_string(m_store_list.totalByteCount())) ) ;
268}
269
270 void GPop::ServerProtocol::doUidl( const std::string & line , bool & )
271{
272 sendList( line , true ) ;
273}
274
275 void GPop::ServerProtocol::doList( const std::string & line , bool & )
276{
277 sendList( line , false ) ;
278}
279
280 void GPop::ServerProtocol::sendList( const std::string & line , bool uidl )
281{
282 std::string id_string = commandParameter( line ) ;
283
284 // parse and check the id if supplied
285 int id = -1 ;
286 if( !id_string.empty() )
287 {
288 id = commandNumber( line , -1 ) ;
289 if( !m_store_list.valid(id) )
290 {
291 sendError( "invalid id" ) ;
292 return ;
293 }
294 }
295
296 // send back the list with sizes or uidls
297 std::ostringstream ss ;
298 ss << "+OK " ;
299 bool multi_line = id == -1 ;
300 if( multi_line )
301 {
302 ss << m_store_list.messageCount() << " message(s)" << "\r\n" ;
303 std::size_t i = 1 ;
304 for( auto item_p = m_store_list.cbegin() ; item_p != m_store_list.cend() ; ++item_p , ++i )
305 {
306 const auto & item = *item_p ;
307 if( !item.deleted )
308 {
309 ss << i << " " ;
310 if( uidl ) ss << item.uidl() ;
311 if( !uidl ) ss << item.size ;
312 ss << "\r\n" ;
313 }
314 }
315 ss << "." ;
316 sendLines( ss ) ;
317 }
318 else
319 {
320 auto item = m_store_list.get( id ) ;
321 ss << id << " " ;
322 if( uidl ) ss << item.uidl() ;
323 if( !uidl ) ss << item.size ;
324 sendLine( ss.str() ) ;
325 }
326}
327
328 void GPop::ServerProtocol::doRetr( const std::string & line , bool & more )
329{
330 int id = commandNumber( line , -1 ) ;
331 if( id == -1 || !m_store_list.valid(id) )
332 {
333 more = false ; // stay in the same state
334 sendError() ;
335 }
336 else
337 {
338 m_content = m_store_list.content(id) ;
339 m_body_limit = -1L ;
340
341 std::ostringstream ss ;
342 ss << "+OK " << m_store_list.byteCount(id) << " octets" ;
343 sendLine( ss.str() ) ;
344 }
345}
346
347 void GPop::ServerProtocol::doTop( const std::string & line , bool & more )
348{
349 int id = commandNumber( line , -1 , 1U ) ;
350 int n = commandNumber( line , -1 , 2U ) ;
351 G_DEBUG( "ServerProtocol::doTop: " << id << ", " << n ) ;
352 if( id == -1 || !m_store_list.valid(id) || n < 0 )
353 {
354 more = false ; // stay in the same state
355 sendError() ;
356 }
357 else
358 {
359 m_content = m_store_list.content( id ) ;
360 m_body_limit = n ;
361 m_in_body = false ;
362 sendOk() ;
363 }
364}
365
366 void GPop::ServerProtocol::doDele( const std::string & line , bool & )
367{
368 int id = commandNumber( line , -1 ) ;
369 if( id == -1 || !m_store_list.valid(id) )
370 {
371 sendError() ;
372 }
373 else
374 {
375 m_store_list.remove( id ) ;
376 sendOk() ;
377 }
378}
379
380 void GPop::ServerProtocol::doRset( const std::string & , bool & )
381{
382 m_store_list.rollback() ;
383 sendOk() ;
384}
385
386 void GPop::ServerProtocol::doNoop( const std::string & , bool & )
387{
388 sendOk() ;
389}
390
391 void GPop::ServerProtocol::doNothing( const std::string & , bool & )
392{
393}
394
395 void GPop::ServerProtocol::doAuth( const std::string & line , bool & ok )
396{
397 std::string mechanism = G::Str::upper( commandParameter(line) ) ;
398
399 if( mechanism.empty() )
400 {
401 // non-standard, but some clients expect a list of mechanisms
402 ok = false ; // => stay in start state
403 std::string list = mechanisms() ;
404 G::Str::replaceAll( list , " "_sv , "\r\n"_sv ) ;
405 std::ostringstream ss ;
406 ss << "+OK\r\n" ;
407 if( !list.empty() )
408 ss << list << "\r\n" ;
409 ss << "." ;
410 sendLines( ss ) ;
411 }
412 else if( mechanisms().empty() )
413 {
414 ok = false ;
415 sendError( "must use STLS before authentication" ) ;
416 }
417 else
418 {
419 std::string initial_response = commandParameter(line,2) ;
420 if( initial_response == "=" )
421 initial_response.clear() ; // RFC-5034
422
423 m_sasl_init_apop = false ;
424 if( !m_sasl->init( m_secure , mechanism ) )
425 {
426 ok = false ;
427 sendError( "invalid mechanism" ) ;
428 }
429 else if( m_sasl->mustChallenge() && !initial_response.empty() )
430 {
431 ok = false ;
432 sendError( "invalid initial response" ) ;
433 }
434 else if( !initial_response.empty() )
435 {
436 m_fsm.apply( *this , Event::eAuthData , initial_response ) ;
437 }
438 else
439 {
440 std::string initial_challenge = m_sasl->initialChallenge() ;
441 sendLine( std::string("+ ",2U).append(G::Base64::encode(initial_challenge)) ) ;
442 }
443 }
444}
445
446 void GPop::ServerProtocol::doAuthData( const std::string & line , bool & ok )
447{
448 if( line == "*" )
449 {
450 ok = false ;
451 sendError() ;
452 return ;
453 }
454
455 bool done = false ;
456 std::string challenge = m_sasl->apply( G::Base64::decode(line) , done ) ;
457 if( done && m_sasl->authenticated() )
458 {
459 m_fsm.apply( *this , Event::eAuthComplete , "" ) ;
460 }
461 else if( done )
462 {
463 ok = false ; // => start
464 sendError() ;
465 }
466 else
467 {
468 sendLine( std::string("+ ",2U).append(G::Base64::encode(challenge)) ) ;
469 }
470}
471
472 void GPop::ServerProtocol::doAuthComplete( const std::string & , bool & )
473{
474 G_LOG_S( "GPop::ServerProtocol: pop authentication of " << m_sasl->id() << " connected from " << m_peer_address.displayString() ) ;
475 m_user = m_sasl->id() ;
476 m_store.prepare( m_user ) ;
477 readStore( m_user ) ;
478 sendOk() ;
479}
480
481 void GPop::ServerProtocol::readStore( const std::string & user )
482{
483 m_store_user = std::make_unique<StoreUser>( m_store , user ) ;
484 m_store_list = StoreList( *m_store_user , m_store.allowDelete() ) ;
485}
486
487 void GPop::ServerProtocol::doStls( const std::string & , bool & )
488{
489 G_ASSERT( m_security.securityEnabled() ) ;
490 sendOk() ; // "please start tls"
491 m_security.securityStart() ;
492}
493
494 void GPop::ServerProtocol::secure()
495{
496 m_secure = true ;
497 sendOk() ; // "hello (again)"
498}
499
500 bool GPop::ServerProtocol::mechanismsIncludePlain() const
501{
502 return mechanisms().find("PLAIN") != std::string::npos ;
503}
504
505std::string GPop::ServerProtocol::mechanisms() const
506{
507 G::StringArray m = m_sasl->mechanisms( m_secure ) ;
508 m.erase( std::remove( m.begin() , m.end() , "APOP" ) , m.end() ) ;
509 return G::Str::join( " " , m ) ;
510}
511
512 void GPop::ServerProtocol::doCapa( const std::string & , bool & )
513{
514 std::ostringstream ss ;
515 ss << "+OK " << m_text.capa() << "\r\n" ;
516
517 // USER/PASS POP3 authentication uses the PLAIN SASL mechanism
518 // so only advertise it if it is available
519 if( mechanismsIncludePlain() )
520 ss << "USER\r\n" ;
521
522 ss << "CAPA\r\nTOP\r\nUIDL\r\n" ;
523
524 if( m_security.securityEnabled() )
525 ss << "STLS\r\n" ;
526
527 if( !mechanisms().empty() )
528 ss << "SASL " << mechanisms() << "\r\n" ;
529
530 ss << "." ;
531 sendLines( ss ) ;
532}
533
534 void GPop::ServerProtocol::doUser( const std::string & line , bool & )
535{
536 if( mechanismsIncludePlain() )
537 {
538 m_user = commandParameter(line) ;
539 sendLine( std::string("+OK ",4U).append(m_text.user(commandParameter(line))) ) ;
540 }
541 else
542 {
543 sendError( "no SASL PLAIN mechanism to do USER/PASS authentication" ) ;
544 }
545}
546
547 void GPop::ServerProtocol::doPass( const std::string & line , bool & ok )
548{
549 m_sasl_init_apop = false ;
550 if( !m_user.empty() && m_sasl->init(m_secure,"PLAIN") ) // (USER/PASS uses SASL PLAIN)
551 {
552 std::string rsp = m_user + std::string(1U,'\0').append(m_user).append(1U,'\0').append(commandParameter(line)) ;
553 bool done = false ;
554 GDEF_IGNORE_RETURN m_sasl->apply( rsp , done ) ;
555 if( done && m_sasl->authenticated() )
556 {
557 m_store.prepare( m_user ) ;
558 readStore( m_user ) ;
559 sendOk() ;
560 }
561 else
562 {
563 ok = false ;
564 sendError() ;
565 }
566 }
567 else
568 {
569 ok = false ;
570 sendError() ;
571 }
572}
573
574 void GPop::ServerProtocol::doApop( const std::string & line , bool & ok )
575{
576 if( m_sasl_init_apop )
577 {
578 std::string rsp = commandParameter(line,1) + " " + commandParameter(line,2) ;
579 bool done = false ;
580 GDEF_IGNORE_RETURN m_sasl->apply( rsp , done ) ;
581 if( done && m_sasl->authenticated() )
582 {
583 m_user = m_sasl->id() ;
584 m_store.prepare( m_user ) ;
585 readStore( m_user ) ;
586 sendOk() ;
587 }
588 else
589 {
590 ok = false ;
591 sendError() ;
592 }
593 }
594 else
595 {
596 ok = false ;
597 sendError() ;
598 }
599}
600
601 void GPop::ServerProtocol::sendLine( std::string_view line , bool has_crlf )
602{
603 if( has_crlf )
604 {
605 G_LOG( "GPop::ServerProtocol: tx>>: \"" << G::Str::printable(G::Str::trimmedView(line,"\r\n"_sv)) << "\"" ) ;
606 m_sender.protocolSend( line , 0U ) ;
607 }
608 else
609 {
610 G_LOG( "GPop::ServerProtocol: tx>>: \"" << G::Str::printable(line) << "\"" ) ;
611 m_sender.protocolSend( std::string(line.data(),line.size()).append("\r\n",2U) , 0U ) ;
612 }
613}
614
615 void GPop::ServerProtocol::sendLine( std::string && line ) // NOLINT cppcoreguidelines-rvalue-reference-param-not-moved
616{
617 G_LOG( "GPop::ServerProtocol: tx>>: \"" << G::Str::printable(line) << "\"" ) ;
618 m_sender.protocolSend( line.append("\r\n",2U) , 0U ) ;
619}
620
621 void GPop::ServerProtocol::sendLines( std::ostringstream & ss )
622{
623 ss << "\r\n" ;
624 const std::string s = ss.str() ;
625 if( G::LogOutput::Instance::atVerbose() )
626 {
627 std::size_t lines = std::count( s.begin() , s.end() , '\n' ) ;
628 const std::size_t npos = std::string::npos ;
629 std::size_t p0 = 0U ;
630 std::size_t p1 = s.find( '\n' ) ;
631 for( std::size_t i = 0U ; i < lines ; i++ , p0 = p1+1U , p1 = s.find('\n',p0+1U) )
632 {
633 G_ASSERT( p0 != npos && p0 < s.size() ) ;
634 std::size_t n = p1 == npos ? (s.size()-p0) : (p1-p0) ;
635 if( n && p1 && p1 != npos && s.at(p1-1U) == '\r' ) --n ;
636 if( lines <= 7U || i < 4U || i > (lines-3U) )
637 G_LOG( "GPop::ServerProtocol: tx>>: \"" << G::Str::printable(s.substr(p0,n)) << "\"" ) ;
638 else if( i == 4U )
639 G_LOG( "GPop::ServerProtocol: tx>>: [" << (lines-6U) << " lines]" ) ;
640 if( p1 == npos || (p1+1U) == s.size() )
641 break ;
642 }
643 }
644 m_sender.protocolSend( s , 0U ) ;
645}
646
647// ===
648
649 GPop::ServerProtocolText::ServerProtocolText( const GNet::Address & )
650{
651}
652
653std::string GPop::ServerProtocolText::greeting() const
654{
655 return "POP3 server ready" ;
656}
657
658std::string GPop::ServerProtocolText::quit() const
659{
660 return "signing off" ;
661}
662
663std::string GPop::ServerProtocolText::capa() const
664{
665 return "capability list follows" ;
666}
667
668std::string GPop::ServerProtocolText::user( const std::string & id ) const
669{
670 return std::string("user: ",6U).append(id) ;
671}
672
GAuth::SaslServerSecrets
An interface used by GAuth::SaslServer to obtain authentication secrets.
Definition: gsaslserversecrets.h:40
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
GPop::ServerProtocolText::ServerProtocolText
ServerProtocolText(const GNet::Address &peer)
Constructor.
Definition: gpopserverprotocol.cpp:649
GPop::ServerProtocol::Security
An interface used by ServerProtocol to enable TLS.
Definition: gpopserverprotocol.h:80
GPop::ServerProtocol::Sender
An interface used by ServerProtocol to send protocol replies.
Definition: gpopserverprotocol.h:55
GPop::ServerProtocol::Text
An interface used by ServerProtocol to provide response text strings.
Definition: gpopserverprotocol.h:62
GPop::ServerProtocol::resume
void resume()
Called when the Sender can send again.
Definition: gpopserverprotocol.cpp:157
GPop::ServerProtocol::secure
void secure()
Called when the server connection becomes secure.
Definition: gpopserverprotocol.cpp:494
GPop::ServerProtocol::init
void init()
Starts the protocol.
Definition: gpopserverprotocol.cpp:71
GPop::ServerProtocol::apply
void apply(const std::string &line)
Called on receipt of a string from the client.
Definition: gpopserverprotocol.cpp:110
GPop::ServerProtocol::ServerProtocol
ServerProtocol(Sender &sender, Security &security, Store &store, const GAuth::SaslServerSecrets &server_secrets, const std::string &sasl_server_config, const Text &text, const GNet::Address &peer_address, const Config &config)
Constructor.
Definition: gpopserverprotocol.cpp:33
GPop::Store
A message store.
Definition: gpopstore.h:47
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::Base64::decode
static std::string decode(std::string_view, bool throw_on_invalid=false, bool strict=true)
Decodes the given string.
Definition: gbase64.cpp:84
G::Str::trimmedView
static std::string_view trimmedView(std::string_view s, std::string_view ws) noexcept
Returns a trim()med view of the input view.
Definition: gstr.cpp:351
G::Str::toInt
static int toInt(std::string_view s)
Converts string 's' to an int.
Definition: gstr.cpp:538
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::readLine
static std::istream & readLine(std::istream &stream, std::string &result, std::string_view eol={}, bool pre_erase_result=true, std::size_t limit=0U)
Reads a line from the stream using the given line terminator, which may be multi-character.
Definition: gstr.cpp:958
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::replaceAll
static unsigned int replaceAll(std::string &s, std::string_view from, std::string_view to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
Definition: gstr.cpp:247
G::Str::ws
static std::string_view ws() noexcept
Returns a string of standard whitespace characters.
Definition: gstr.cpp:1265
G::StringTokenT
A zero-copy string token iterator where the token separators are runs of whitespace characters,...
Definition: gstringtoken.h:54
gassert.h
gbase64.h
glog.h
gpopserverprotocol.h
gsaslserverfactory.h
gstr.h
gstringtoken.h
gtest.h
GAuth
SASL authentication classes.
Definition: gcram.cpp:38
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30
std
STL namespace.
GPop::ServerProtocol::Config
A structure containing configuration parameters for ServerProtocol.
Definition: gpopserverprotocol.h:72