E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gpopserverprotocol.cpp
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 // gpopserverprotocol.cpp
19 //
20
21 #include "gdef.h"
22 #include "gpop.h"
23 #include "gpopserverprotocol.h"
24 #include "gstr.h"
25 #include "gbase64.h"
26 #include "gassert.h"
27 #include "glog.h"
28 #include <sstream>
29
30 GPop::ServerProtocol::ServerProtocol( Sender & sender , Security & security , Store & store , const Secrets & secrets ,
31 const Text & text , GNet::Address peer_address , Config ) :
32 m_text(text) ,
33 m_sender(sender) ,
34 m_security(security) ,
35 m_store(store) ,
36 m_store_lock(m_store) ,
37 m_secrets(secrets) ,
38 m_auth(m_secrets) ,
39 m_peer_address(peer_address) ,
40 m_fsm(sStart,sEnd,s_Same,s_Any) ,
41 m_body_limit(-1L) ,
42 m_in_body(false) ,
43 m_secure(false)
44 {
45 // (dont send anything to the peer from this ctor -- the Sender object is not fuly constructed)
46
47 m_fsm.addTransition( eStat , sActive , sActive , &GPop::ServerProtocol::doStat ) ;
48 m_fsm.addTransition( eList , sActive , sActive , &GPop::ServerProtocol::doList ) ;
49 m_fsm.addTransition( eRetr , sActive , sData , &GPop::ServerProtocol::doRetr , sActive ) ;
50 m_fsm.addTransition( eTop , sActive , sData , &GPop::ServerProtocol::doTop , sActive ) ;
51 m_fsm.addTransition( eDele , sActive , sActive , &GPop::ServerProtocol::doDele ) ;
52 m_fsm.addTransition( eNoop , sActive , sActive , &GPop::ServerProtocol::doNoop ) ;
53 m_fsm.addTransition( eRset , sActive , sActive , &GPop::ServerProtocol::doRset ) ;
54 m_fsm.addTransition( eUidl , sActive , sActive , &GPop::ServerProtocol::doUidl ) ;
55 m_fsm.addTransition( eSent , sData , sActive , &GPop::ServerProtocol::doNothing ) ;
56 m_fsm.addTransition( eUser , sStart , sStart , &GPop::ServerProtocol::doUser ) ;
57 m_fsm.addTransition( ePass , sStart , sActive , &GPop::ServerProtocol::doPass , sStart ) ;
58 m_fsm.addTransition( eApop , sStart , sActive , &GPop::ServerProtocol::doApop , sStart ) ;
59 m_fsm.addTransition( eQuit , sStart , sEnd , &GPop::ServerProtocol::doQuitEarly ) ;
60 m_fsm.addTransition( eCapa , sStart , sStart , &GPop::ServerProtocol::doCapa ) ;
61 m_fsm.addTransition( eCapa , sActive , sActive , &GPop::ServerProtocol::doCapa ) ;
62 if( m_security.securityEnabled() )
63 m_fsm.addTransition( eStls , sStart , sStart , &GPop::ServerProtocol::doStls , sStart ) ;
64 m_fsm.addTransition( eAuth , sStart , sAuth , &GPop::ServerProtocol::doAuth , sStart ) ;
65 m_fsm.addTransition( eAuthData , sAuth , sActive , &GPop::ServerProtocol::doAuthData , sStart ) ;
66 m_fsm.addTransition( eCapa , sActive , sActive , &GPop::ServerProtocol::doCapa ) ;
67 m_fsm.addTransition( eQuit , sActive , sEnd , &GPop::ServerProtocol::doQuit ) ;
68 }
69
70 void GPop::ServerProtocol::init()
71 {
72 sendInit() ;
73 }
74
75 GPop::ServerProtocol::~ServerProtocol()
76 {
77 }
78
79 void GPop::ServerProtocol::sendInit()
80 {
81 std::string greeting = std::string() + "+OK " + m_text.greeting() ;
82 std::string apop_challenge = m_auth.challenge() ;
83 if( ! apop_challenge.empty() )
84 {
85 greeting.append( " " ) ;
86 greeting.append( apop_challenge ) ;
87 }
88 send( greeting ) ;
89 }
90
91 void GPop::ServerProtocol::sendOk()
92 {
93 send( "+OK" ) ;
94 }
95
96 void GPop::ServerProtocol::sendError( const std::string & more )
97 {
98 if( more.empty() )
99 sendError() ;
100 else
101 send( std::string() + "-ERR " + more ) ;
102 }
103
104 void GPop::ServerProtocol::sendError()
105 {
106 send( "-ERR" ) ;
107 }
108
109 void GPop::ServerProtocol::apply( const std::string & line )
110 {
111 // decode the event
112 Event event = m_fsm.state() == sAuth ? eAuthData : commandEvent(commandWord(line)) ;
113
114 // log the input
115 std::string log_text = G::Str::printable(line) ;
116 if( event == ePass )
117 log_text = (commandPart(line,0U)+" [password not logged]") ;
118 if( event == eAuthData )
119 log_text = ("[password not logged]") ;
120 if( event == eAuth && !commandPart(line,1U).empty() )
121 log_text = commandPart(line,0U) + " " + commandPart(line,1U) ;
122 G_LOG( "GPop::ServerProtocol: rx<<: \"" << log_text << "\"" ) ;
123
124 // apply the event to the state machine
125 State new_state = m_fsm.apply( *this , event , line ) ;
126 const bool protocol_error = new_state == s_Any ;
127 if( protocol_error )
128 sendError() ;
129
130 // squirt data down the pipe if appropriate
131 if( new_state == sData )
132 sendContent() ;
133 }
134
135 void GPop::ServerProtocol::sendContent()
136 {
137 // send until no more content or until blocked by flow-control
138 std::string line( 200 , '.' ) ;
139 size_t n = 0 ;
140 bool end_of_content = false ;
141 while( sendContentLine(line,end_of_content) )
142 n++ ;
143
144 G_LOG( "GPop::ServerProtocol: tx>>: [" << n << " line(s) of content]" ) ;
145
146 if( end_of_content )
147 {
148 G_LOG( "GPop::ServerProtocol: tx>>: ." ) ;
149 m_content.reset() ; // free up resources
150 m_fsm.apply( *this , eSent , "" ) ; // sData -> sActive
151 }
152 }
153
154 void GPop::ServerProtocol::resume()
155 {
156 G_DEBUG( "GPop::ServerProtocol::resume: flow control released" ) ;
157 if( m_fsm.state() == sData )
158 sendContent() ;
159 }
160
161 bool GPop::ServerProtocol::sendContentLine( std::string & line , bool & stop )
162 {
163 G_ASSERT( m_content.get() != nullptr ) ;
164
165 // maintain the line limit
166 bool limited = m_in_body && m_body_limit == 0L ;
167 if( m_body_limit > 0L && m_in_body )
168 m_body_limit-- ;
169
170 // read the line of text
171 line.erase( 1U ) ; // leave "."
172 G::Str::readLineFrom( *(m_content.get()) , crlf() , line , false/*erase*/ ) ;
173
174 // add crlf and choose an offset
175 bool eof = m_content->fail() || m_content->bad() ;
176 size_t offset = 0U ;
177 if( eof || limited )
178 {
179 line.erase( 1U ) ;
180 line.append( crlf() ) ;
181 }
182 else
183 {
184 line.append( crlf() ) ;
185 offset = line.at(1U) == '.' ? 0U : 1U ;
186 }
187
188 // maintain the in-body flag
189 if( !m_in_body && line.length() == (offset+2U) )
190 m_in_body = true ;
191
192 // send it
193 bool line_fully_sent = m_sender.protocolSend( line , offset ) ;
194
195 // continue to send while not finished or blocked by flow-control
196 stop = ( limited || eof ) && line_fully_sent ;
197 const bool pause = limited || eof || ! line_fully_sent ;
198 return !pause ;
199 }
200
201 int GPop::ServerProtocol::commandNumber( const std::string & line , int default_ , size_t index ) const
202 {
203 int number = default_ ;
204 try
205 {
206 number = G::Str::toInt( commandParameter(line,index) ) ;
207 }
208 catch( G::Str::Overflow & ) // defaulted
209 {
210 }
211 catch( G::Str::InvalidFormat & ) // defaulted
212 {
213 }
214 return number ;
215 }
216
217 std::string GPop::ServerProtocol::commandWord( const std::string & line ) const
218 {
219 return G::Str::upper(commandPart(line,0U)) ;
220 }
221
222 std::string GPop::ServerProtocol::commandPart( const std::string & line , size_t index ) const
223 {
224 G::StringArray part ;
225 G::Str::splitIntoTokens( line , part , G::Str::ws() ) ;
226 return index >= part.size() ? std::string() : part.at(index) ;
227 }
228
229 std::string GPop::ServerProtocol::commandParameter( const std::string & line_in , size_t index ) const
230 {
231 return commandPart( line_in , index ) ;
232 }
233
234 GPop::ServerProtocol::Event GPop::ServerProtocol::commandEvent( const std::string & command ) const
235 {
236 if( command == "QUIT" ) return eQuit ;
237 if( command == "STAT" ) return eStat ;
238 if( command == "LIST" ) return eList ;
239 if( command == "RETR" ) return eRetr ;
240 if( command == "DELE" ) return eDele ;
241 if( command == "NOOP" ) return eNoop ;
242 if( command == "RSET" ) return eRset ;
243 //
244 if( command == "TOP" ) return eTop ;
245 if( command == "UIDL" ) return eUidl ;
246 if( command == "USER" ) return eUser ;
247 if( command == "PASS" ) return ePass ;
248 if( command == "APOP" ) return eApop ;
249 if( command == "AUTH" ) return eAuth ;
250 if( command == "CAPA" ) return eCapa ;
251 if( command == "STLS" ) return eStls ;
252
253 return eUnknown ;
254 }
255
256 void GPop::ServerProtocol::doQuitEarly( const std::string & , bool & )
257 {
258 send( std::string() + "+OK " + m_text.quit() ) ;
259 throw ProtocolDone() ;
260 }
261
262 void GPop::ServerProtocol::doQuit( const std::string & , bool & )
263 {
264 m_store_lock.commit() ;
265 send( std::string() + "+OK " + m_text.quit() ) ;
266 throw ProtocolDone() ;
267 }
268
269 void GPop::ServerProtocol::doStat( const std::string & , bool & )
270 {
271 std::ostringstream ss ;
272 ss << "+OK " << m_store_lock.messageCount() << " " << m_store_lock.totalByteCount() ;
273 send( ss.str() ) ;
274 }
275
276 void GPop::ServerProtocol::doUidl( const std::string & line , bool & )
277 {
278 sendList( line , true ) ;
279 }
280
281 void GPop::ServerProtocol::doList( const std::string & line , bool & )
282 {
283 sendList( line , false ) ;
284 }
285
286 void GPop::ServerProtocol::sendList( const std::string & line , bool uidl )
287 {
288 std::string id_string = commandParameter( line ) ;
289
290 // parse and check the id if supplied
291 int id = -1 ;
292 if( ! id_string.empty() )
293 {
294 id = commandNumber( line , -1 ) ;
295 if( !m_store_lock.valid(id) )
296 {
297 sendError( "invalid id" ) ;
298 return ;
299 }
300 }
301
302 // send back the list with sizes or uidls
303 bool multi_line = id == -1 ;
304 GPop::StoreLock::List list = m_store_lock.list( id ) ;
305 std::ostringstream ss ;
306 ss << "+OK " ;
307 if( multi_line ) ss << list.size() << " message(s)" << crlf() ;
308 for( GPop::StoreLock::List::iterator p = list.begin() ; p != list.end() ; ++p )
309 {
310 ss << (*p).id << " " ;
311 if( uidl ) ss << (*p).uidl ;
312 if( !uidl ) ss << (*p).size ;
313 if( multi_line ) ss << crlf() ;
314 }
315 if( multi_line ) ss << "." ;
316 send( ss.str() ) ;
317 }
318
319 void GPop::ServerProtocol::doRetr( const std::string & line , bool & more )
320 {
321 int id = commandNumber( line , -1 ) ;
322 if( id == -1 || ! m_store_lock.valid(id) )
323 {
324 more = false ; // stay in the same state
325 sendError() ;
326 }
327 else
328 {
329 m_content.reset( m_store_lock.get(id).release() ) ;
330 m_body_limit = -1L ;
331
332 std::ostringstream ss ;
333 ss << "+OK " << m_store_lock.byteCount(id) << " octets" ;
334 send( ss.str() ) ;
335 }
336 }
337
338 void GPop::ServerProtocol::doTop( const std::string & line , bool & more )
339 {
340 int id = commandNumber( line , -1 , 1U ) ;
341 int n = commandNumber( line , -1 , 2U ) ;
342 G_DEBUG( "ServerProtocol::doTop: " << id << ", " << n ) ;
343 if( id == -1 || ! m_store_lock.valid(id) || n < 0 )
344 {
345 more = false ; // stay in the same state
346 sendError() ;
347 }
348 else
349 {
350 m_content.reset( m_store_lock.get(id).release() ) ;
351 m_body_limit = n ;
352 m_in_body = false ;
353 sendOk() ;
354 }
355 }
356
357 void GPop::ServerProtocol::doDele( const std::string & line , bool & )
358 {
359 int id = commandNumber( line , -1 ) ;
360 if( id == -1 || ! m_store_lock.valid(id) )
361 {
362 sendError() ;
363 }
364 else
365 {
366 m_store_lock.remove( id ) ;
367 sendOk() ;
368 }
369 }
370
371 void GPop::ServerProtocol::doRset( const std::string & , bool & )
372 {
373 m_store_lock.rollback() ;
374 sendOk() ;
375 }
376
377 void GPop::ServerProtocol::doNoop( const std::string & , bool & )
378 {
379 sendOk() ;
380 }
381
382 void GPop::ServerProtocol::doNothing( const std::string & , bool & )
383 {
384 }
385
386 void GPop::ServerProtocol::doAuth( const std::string & line , bool & ok )
387 {
388 std::string mechanism = G::Str::upper( commandParameter(line) ) ;
389
390 if( mechanism.empty() )
391 {
392 // completely non-standard behaviour, but required by some clients
393 ok = false ; // dont change state
394 std::string list = m_auth.mechanisms() ;
395 G::Str::replaceAll(list," ",crlf()) ;
396 send( "+OK" ) ;
397 send( list ) ;
398 send( "." ) ;
399 }
400 else if( m_auth.sensitive() && ! m_secure )
401 {
402 // reject authentication over an unencrypted transport
403 // if authentication is sensitive
404 ok = false ;
405 sendError( "must use STLS before authentication" ) ;
406 }
407 else
408 {
409 std::string initial_response = commandParameter(line,2) ;
410 if( initial_response == "=" )
411 initial_response = std::string() ; // RFC-5034
412
413 // reject the LOGIN mechanism here since we did not avertise it
414 // and we only want a one-step challenge-response dialogue
415
416 bool supported = mechanism != "LOGIN" && m_auth.init( mechanism ) ;
417 if( !supported )
418 {
419 ok = false ;
420 sendError( "invalid mechanism" ) ;
421 }
422 else if( m_auth.mustChallenge() && !initial_response.empty() )
423 {
424 ok = false ;
425 sendError( "invalid initial response" ) ;
426 }
427 else if( !initial_response.empty() )
428 {
429 m_fsm.apply( *this , eAuthData , initial_response ) ;
430 }
431 else
432 {
433 std::string initial_challenge = m_auth.challenge() ;
434 send( std::string() + "+ " + G::Base64::encode(initial_challenge) ) ;
435 }
436 }
437 }
438
439 void GPop::ServerProtocol::doAuthData( const std::string & line , bool & ok )
440 {
441 // (only one-step sasl authentication supported for now)
442 ok = m_auth.authenticated( G::Base64::decode(line) , std::string() ) ;
443 if( ok )
444 {
445 sendOk() ;
446 m_user = m_auth.id() ;
447 lockStore() ;
448 }
449 else
450 {
451 sendError() ;
452 }
453 }
454
455 void GPop::ServerProtocol::lockStore()
456 {
457 m_store_lock.lock( m_user ) ;
458 G_LOG_S( "GPop::ServerProtocol: pop authentication of " << m_user
459 << " connected from " << m_peer_address.displayString() ) ;
460 }
461
462 void GPop::ServerProtocol::doStls( const std::string & , bool & )
463 {
464 G_ASSERT( m_security.securityEnabled() ) ;
465 sendOk() ; // "please start tls"
466 m_security.securityStart() ;
467 }
468
469 void GPop::ServerProtocol::secure()
470 {
471 m_secure = true ;
472 sendOk() ; // "hello (again)"
473 }
474
475 bool GPop::ServerProtocol::mechanismsIncludePlain() const
476 {
477 return m_auth.valid() && m_auth.mechanisms().find("PLAIN") != std::string::npos ;
478 }
479
480 std::string GPop::ServerProtocol::mechanismsWithoutLogin() const
481 {
482 std::string result ;
483 if( m_auth.valid() )
484 {
485 result = m_auth.mechanisms() ;
486 G::Str::replace( result , "LOGIN" , "" ) ;
487 result = G::Str::trimmed( G::Str::unique(result) , G::Str::ws() ) ;
488 }
489 return result ;
490 }
491
492 void GPop::ServerProtocol::doCapa( const std::string & , bool & )
493 {
494 send( std::string() + "+OK " + m_text.capa() ) ;
495
496 // USER/PASS POP3 authentication uses the PLAIN SASL mechanism
497 // so only advertise it if it is available
498 if( mechanismsIncludePlain() )
499 send( "USER" ) ;
500
501 send( "CAPA" ) ;
502 send( "TOP" ) ;
503 send( "UIDL" ) ;
504
505 if( m_security.securityEnabled() )
506 send( "STLS" ) ;
507
508 // don't advertise LOGIN since we cannot do multi-challenge
509 // mechanisms and USER/PASS provides the same functionality
510 //
511 std::string mechanisms = std::string(1U,' ') + mechanismsWithoutLogin() ;
512 if( mechanisms.length() > 1U )
513 send( std::string() + "SASL" + mechanisms ) ;
514
515 send( "." ) ;
516 }
517
518 void GPop::ServerProtocol::doUser( const std::string & line , bool & )
519 {
520 if( mechanismsIncludePlain() )
521 {
522 m_user = commandParameter(line) ;
523 send( std::string() + "+OK " + m_text.user(commandParameter(line)) ) ;
524 }
525 else
526 {
527 sendError( "no SASL PLAIN mechanism to do USER/PASS authentication" ) ;
528 }
529 }
530
531 void GPop::ServerProtocol::doPass( const std::string & line , bool & ok )
532 {
533 // note that USER/PASS POP3 authentication uses the PLAIN SASL mechanism
534 std::string rsp = m_user + std::string(1U,'\0') + m_user + std::string(1U,'\0') + commandParameter(line) ;
535 ok = !m_user.empty() && m_auth.valid() && m_auth.init("PLAIN") &&
536 m_auth.authenticated( rsp , std::string() ) ;
537 if( ok )
538 {
539 lockStore() ;
540 sendOk() ;
541 }
542 else
543 {
544 sendError() ;
545 }
546 }
547
548 void GPop::ServerProtocol::doApop( const std::string & line , bool & ok )
549 {
550 m_user = commandParameter(line,1) ;
551 std::string rsp = m_user + " " + commandParameter(line,2) ;
552 ok = m_auth.valid() && m_auth.init("APOP") && m_auth.authenticated(rsp,std::string()) ;
553 if( ok )
554 {
555 lockStore() ;
556 sendOk() ;
557 }
558 else
559 {
560 m_user = std::string() ;
561 sendError() ;
562 }
563 }
564
565 void GPop::ServerProtocol::send( std::string line )
566 {
567 G_LOG( "GPop::ServerProtocol: tx>>: \"" << G::Str::printable(line) << "\"" ) ;
568 line.append( crlf() ) ;
569 m_sender.protocolSend( line , 0U ) ;
570 }
571
572 const std::string & GPop::ServerProtocol::crlf()
573 {
574 static const std::string s( "\015\012" ) ;
575 return s ;
576 }
577
578 // ===
579
580 GPop::ServerProtocolText::ServerProtocolText( GNet::Address )
581 {
582 }
583
584 std::string GPop::ServerProtocolText::greeting() const
585 {
586 return "POP3 server ready" ;
587 }
588
589 std::string GPop::ServerProtocolText::quit() const
590 {
591 return "signing off" ;
592 }
593
594 std::string GPop::ServerProtocolText::capa() const
595 {
596 return "capability list follows" ;
597 }
598
599 std::string GPop::ServerProtocolText::user( const std::string & id ) const
600 {
601 return std::string() + "user: " + id ;
602 }
603
604 // ===
605
606 GPop::ServerProtocol::Text::~Text()
607 {
608 }
609
610 // ===
611
612 GPop::ServerProtocol::Sender::~Sender()
613 {
614 }
615
616 // ===
617
618 GPop::ServerProtocol::Config::Config()
619 {
620 }
621
622 // ===
623
624 GPop::ServerProtocol::Security::~Security()
625 {
626 }
627
628 /// \file gpopserverprotocol.cpp
G::Str::printable
static std::string printable(const std::string &in, char escape= '\\')
Returns a printable represention of the given input string.
Definition: gstr.cpp:701
GPop::Secrets
A simple interface to a store of secrets as used in authentication.
Definition: gpopsecrets.h:43
glog.h
G::Str::toInt
static int toInt(const std::string &s)
Converts string 's' to an int.
Definition: gstr.cpp:406
GPop::ServerProtocolText::greeting
virtual std::string greeting() const override
Final override from GPop::ServerProtocol::Text.
Definition: gpopserverprotocol.cpp:584
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:54
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:33
G::Base64::decode
static std::string decode(const std::string &, bool strict=false)
Decodes the given string.
Definition: gbase64.cpp:57
G::Str::replace
static bool replace(std::string &s, const std::string &from, const std::string &to, size_type *pos_p=nullptr)
Replaces 'from' with 'to', starting at offset '*pos_p'.
Definition: gstr.cpp:172
G::Str::splitIntoTokens
static void splitIntoTokens(const std::string &in, StringArray &out, const std::string &ws)
Splits the string into 'ws'-delimited tokens.
Definition: gstr.cpp:908
GPop::ServerProtocolText::user
virtual std::string user(const std::string &id) const override
Final override from GPop::ServerProtocol::Text.
Definition: gpopserverprotocol.cpp:599
GPop::ServerProtocol::init
void init()
Starts the protocol.
Definition: gpopserverprotocol.cpp:70
GPop::ServerProtocol::~ServerProtocol
virtual ~ServerProtocol()
Destructor.
Definition: gpopserverprotocol.cpp:75
GPop::ServerProtocol::Sender
An interface used by ServerProtocol to send protocol replies.
Definition: gpopserverprotocol.h:52
GPop::Store
A message store.
Definition: gpopstore.h:45
GPop::ServerProtocol::Security
An interface used by ServerProtocol to enable TLS.
Definition: gpopserverprotocol.h:72
GPop::ServerProtocolText::ServerProtocolText
ServerProtocolText(GNet::Address peer)
Constructor.
Definition: gpopserverprotocol.cpp:580
gstr.h
gassert.h
G::Str::replaceAll
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurances of sub-string 'from' with 'to'...
Definition: gstr.cpp:195
G::Str::unique
static std::string unique(std::string s, char c= ' ', char r= ' ')
Returns a string with repeated 'c' characters replaced by one 'r' character.
Definition: gstr.cpp:1268
GPop::ServerProtocol::Text
An interface used by ServerProtocol to provide response text strings.
Definition: gpopserverprotocol.h:58
gpopserverprotocol.h
G::Str::upper
static std::string upper(const std::string &s)
Returns a copy of 's' in which all Latin-1 lowercase characters have been replaced by uppercase chara...
Definition: gstr.cpp:619
G::Str::trimmed
static std::string trimmed(const std::string &s, const std::string &ws)
Returns a trim()med version of s.
Definition: gstr.cpp:251
G::Str::readLineFrom
static std::string readLineFrom(std::istream &stream, const std::string &eol=std::string())
Reads a line from the stream using the given line terminator.
Definition: gstr.cpp:733
gpop.h
GPop::ServerProtocolText::quit
virtual std::string quit() const override
Final override from GPop::ServerProtocol::Text.
Definition: gpopserverprotocol.cpp:589
GPop::ServerProtocol::ServerProtocol
ServerProtocol(Sender &sender, Security &security, Store &store, const Secrets &secrets, const Text &text, GNet::Address peer_address, Config config)
Constructor.
Definition: gpopserverprotocol.cpp:30
GPop::ServerProtocol::Config
A structure containing configuration parameters for ServerProtocol. NOT USED.
Definition: gpopserverprotocol.h:67
GPop::ServerProtocolText::capa
virtual std::string capa() const override
Final override from GPop::ServerProtocol::Text.
Definition: gpopserverprotocol.cpp:594
gbase64.h
G::StateMachine::addTransition
void addTransition(Event event, State from, State to, Action action)
Adds a transition.
Definition: gstatemachine.h:177
GPop::ServerProtocol::secure
void secure()
Called when the server connection becomes secure.
Definition: gpopserverprotocol.cpp:469
GPop::ServerProtocol::apply
void apply(const std::string &line)
Called on receipt of a string from the client.
Definition: gpopserverprotocol.cpp:109
G::Base64::encode
static std::string encode(const std::string &s, const std::string &line_break)
Encodes the given string.
Definition: gbase64.cpp:52
G::Str::ws
static std::string ws()
Returns a string of standard whitespace characters.
Definition: gstr.cpp:1078
GPop::ServerProtocol::resume
void resume()
Called when the Sender can send again.
Definition: gpopserverprotocol.cpp:154