run.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 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 // run.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gnet.h"
23 #include "gssl.h"
24 #include "gsmtp.h"
25 #include "run.h"
26 #include "admin.h"
27 #include "gsmtpserver.h"
28 #include "gsmtpclient.h"
29 #include "gsecrets.h"
30 #include "geventloop.h"
31 #include "garg.h"
32 #include "gdaemon.h"
33 #include "gpidfile.h"
34 #include "gfilestore.h"
35 #include "gnewfile.h"
36 #include "gmultiserver.h"
37 #include "gadminserver.h"
38 #include "gpopserver.h"
39 #include "gprocessorfactory.h"
40 #include "gverifierfactory.h"
41 #include "gslot.h"
42 #include "gmonitor.h"
43 #include "glocal.h"
44 #include "gfile.h"
45 #include "gpath.h"
46 #include "groot.h"
47 #include "gexception.h"
48 #include "gprocess.h"
49 #include "gmemory.h"
50 #include "gtest.h"
51 #include "glogoutput.h"
52 #include "gdebug.h"
53 #include "legal.h"
54 #include <iostream>
55 #include <exception>
56 #include <utility>
57 
58 #ifndef G_CAPABILITIES
59  #define G_CAPABILITIES ""
60 #endif
61 
62 std::string Main::Run::capabilities()
63 {
64  return G_CAPABILITIES ;
65 }
66 
68 {
69  return "1.9" ;
70 }
71 
72 Main::Run::Run( Main::Output & output , const G::Arg & arg , const std::string & switch_spec ) :
73  m_output(output) ,
74  m_switch_spec(switch_spec) ,
75  m_arg(arg) ,
76  m_client_resolver_info(std::string(),std::string()) ,
77  m_prepare_error(false)
78 {
79  m_client.doneSignal().connect( G::slot(*this,&Run::pollingClientDone) ) ;
80  m_client.eventSignal().connect( G::slot(*this,&Run::clientEvent) ) ;
81 }
82 
84 {
85  try
86  {
87  if( m_store.get() ) m_store->signal().disconnect() ;
88  if( m_smtp_server.get() ) m_smtp_server->eventSignal().disconnect() ;
89  m_client.doneSignal().disconnect() ;
90  m_client.eventSignal().disconnect() ;
91 
92  // there are no EventLoop or TimerList instances when this
93  // destuctor runs so delete the client with ..ForExit()
94  m_client.cleanupForExit() ;
95 
96  // call some more destructors early (in the correct order)
97  // within the scope of the catch
98  m_forwarding_timer <<= 0 ;
99  m_poll_timer <<= 0 ;
100  m_smtp_server <<= 0 ;
101  m_admin_server <<= 0 ;
102  m_pop_secrets <<= 0 ;
103  m_client_secrets <<= 0 ;
104  m_store <<= 0 ;
105  m_cfg <<= 0 ;
106  m_cl <<= 0 ;
107  m_log_output <<= 0 ;
108  }
109  catch(...)
110  {
111  }
112 }
113 
115 {
116  return m_prepare_error ;
117 }
118 
120 {
121  cl() ;
122  return *m_cfg.get() ;
123 }
124 
125 std::string Main::Run::smtpIdent() const
126 {
127  return std::string("E-MailRelay V") + versionNumber() ;
128 }
129 
130 void Main::Run::closeFiles()
131 {
132  if( config().daemon() )
133  {
134  const bool keep_stderr = true ;
135  G::Process::closeFiles( keep_stderr ) ;
136  }
137 }
138 
139 void Main::Run::closeMoreFiles()
140 {
141  if( config().closeStderr() )
143 }
144 
145 bool Main::Run::hidden() const
146 {
147  return cl().contains("hidden") ;
148 }
149 
151 {
152  #ifndef USE_SMALL_CONFIG
153  if( cl().contains("help") )
154  {
155  cl().showHelp( false ) ;
156  m_prepare_error = false ;
157  return false ;
158  }
159  else if( cl().hasUsageErrors() )
160  {
161  cl().showUsageErrors( true ) ;
162  m_prepare_error = true ;
163  return false ;
164  }
165  else if( cl().contains("version") )
166  {
167  cl().showVersion( false ) ;
168  m_prepare_error = false ;
169  return false ;
170  }
171  else if( cl().argc() > 1U )
172  {
173  cl().showArgcError( true ) ;
174  m_prepare_error = true ;
175  return false ;
176  }
177  else if( cl().hasSemanticError() )
178  {
179  cl().showSemanticError( true ) ;
180  m_prepare_error = true ;
181  return false ;
182  }
183  #endif
184 
185  // early singletons...
186  //
187  const Configuration & cfg = config() ;
188  m_log_output <<= new G::LogOutput( m_arg.prefix() ,
189  cfg.log() , // output
190  cfg.log() , // with-logging
191  cfg.verbose() , // with-verbose-logging
192  cfg.debug() , // with-debug
193  true , // with-level
194  cfg.logTimestamp() , // with-timestamp
195  !cfg.debug() , // strip-context
196  cfg.useSyslog() , // use-syslog
197  cfg.logFile() , // stderr-replacement
198  G::LogOutput::Mail // facility
199  ) ;
200 
201  #ifndef USE_SMALL_CONFIG
202  // emit warnings for dodgy switch combinations
203  cl().logSemanticWarnings() ;
204  #endif
205 
206  return true ;
207 }
208 
209 #ifndef USE_SMALL_CONFIG
210 void Main::Run::checkPort( bool check , const std::string & interface_ , unsigned int port )
211 {
212  if( check )
213  {
214  GNet::Address address =
215  interface_.length() ?
216  GNet::Address(interface_,port) :
217  GNet::Address(port) ;
218  GNet::Server::canBind( address , true ) ;
219  }
220 }
221 #endif
222 
223 void Main::Run::checkPorts() const
224 {
225  #ifndef USE_SMALL_CONFIG
226  const Configuration & cfg = config() ;
227  if( cfg.doServing() )
228  {
229  G::Strings smtp_interfaces = cfg.listeningInterfaces("smtp") ;
230  checkPort( cfg.doSmtp() && smtp_interfaces.empty() , std::string() , cfg.port() ) ;
231  for( G::Strings::iterator p1 = smtp_interfaces.begin() ; p1 != smtp_interfaces.end() ; ++p1 )
232  checkPort( cfg.doSmtp() , *p1 , cfg.port() ) ;
233 
234  G::Strings pop_interfaces = cfg.listeningInterfaces("pop") ;
235  checkPort( cfg.doPop() && pop_interfaces.empty() , std::string() , cfg.popPort() ) ;
236  for( G::Strings::iterator p2 = pop_interfaces.begin() ; p2 != pop_interfaces.end() ; ++p2 )
237  checkPort( cfg.doPop() , *p2 , cfg.popPort() ) ;
238 
239  G::Strings admin_interfaces = cfg.listeningInterfaces("admin") ;
240  checkPort( cfg.doAdmin() && admin_interfaces.empty() , std::string() , cfg.adminPort() ) ;
241  for( G::Strings::iterator p3 = admin_interfaces.begin() ; p3 != admin_interfaces.end() ; ++p3 )
242  checkPort( cfg.doAdmin() , *p3 , cfg.adminPort() ) ;
243  }
244  #endif
245 }
246 
248 {
249  try
250  {
251  runCore() ;
252  G_LOG( "Main::Run::run: done" ) ;
253  }
254  catch( std::exception & e )
255  {
256  G_ERROR( "Main::Run::run: " << e.what() ) ;
257  throw ;
258  }
259  catch(...)
260  {
261  G_ERROR( "Main::Run::run: unknown exception" ) ;
262  throw ;
263  }
264 }
265 
266 void Main::Run::runCore()
267 {
268  const Configuration & cfg = config() ;
269 
270  // fqdn override option
271  //
272  std::string nul( 1U , '\0' ) ;
273  if( cfg.fqdn(nul) != nul )
274  GNet::Local::fqdn( cfg.fqdn() ) ;
275 
276  // tighten the umask
277  //
279 
280  // close inherited file descriptors to avoid locking file
281  // systems when running as a daemon -- this has to be done
282  // early, before opening any sockets or message-store streams
283  //
284  if( cfg.daemon() )
285  {
286  closeFiles() ;
287  }
288 
289  // release root privileges and extra group memberships
290  //
291  G::Root::init( cfg.nobody() ) ;
292 
293  // event loop singletons
294  //
295  GNet::TimerList timer_list ;
296  std::auto_ptr<GNet::EventLoop> event_loop(GNet::EventLoop::create()) ;
297  if( ! event_loop->init() )
298  throw G::Exception( "cannot initialise network layer" ) ;
299 
300  // early check on socket bindability
301  //
302  checkPorts() ;
303 
304  #ifndef USE_NO_EXEC
305  // early check on script executablity
306  //
307  checkScripts() ;
308  #endif
309 
310  // ssl library singleton
311  //
312  bool ssl_active = cfg.clientTls() || cfg.clientOverTls() || !cfg.serverTlsFile().empty() ;
313  GSsl::Library ssl( ssl_active , cfg.serverTlsFile() , cfg.tlsConfig() ) ;
314  if( ssl_active && !ssl.enabled() )
315  throw G::Exception( "cannot do tls/ssl: openssl not built in: remove tls options from the command-line or rebuild the emailrelay executable with openssl" ) ;
316 
317  // network monitor singleton
318  //
319  GNet::Monitor monitor ;
320  monitor.signal().connect( G::slot(*this,&Run::raiseNetworkEvent) ) ;
321 
322  // message store singletons
323  //
324  m_store <<= new GSmtp::FileStore( cfg.spoolDir() , false , cfg.maxSize() ) ;
325  m_store->signal().connect( G::slot(*this,&Run::raiseStoreEvent) ) ;
326  GPop::Store pop_store( cfg.spoolDir() , cfg.popByName() , ! cfg.popNoDelete() ) ;
327 
328  // authentication secrets
329  //
330  m_client_secrets <<= new GAuth::Secrets( cfg.clientSecretsFile() , "client" ) ;
331  GAuth::Secrets server_secrets( cfg.serverSecretsFile() , "server" ) ;
332  if( cfg.doPop() )
333  m_pop_secrets <<= new GPop::Secrets( cfg.popSecretsFile() ) ;
334 
335  // daemonise
336  //
337  G::PidFile pid_file ;
338  if( cfg.usePidFile() ) pid_file.init( G::Path(cfg.pidFile()) ) ;
339  if( cfg.daemon() ) G::Daemon::detach( pid_file ) ;
340 
341  // run as forwarding agent
342  //
343  if( cfg.doForwardingOnStartup() )
344  {
345  if( m_store->empty() )
346  cl().showNoop( true ) ;
347  else
348  doForwardingOnStartup( *m_store.get() , *m_client_secrets.get() , *event_loop.get() ) ;
349  }
350 
351  // run as storage daemon
352  //
353  if( cfg.doServing() )
354  {
355  doServing( *m_client_secrets.get() , *m_store.get() , server_secrets ,
356  pop_store , *m_pop_secrets.get() , pid_file , *event_loop.get() ) ;
357  }
358 }
359 
360 void Main::Run::doServing( const GAuth::Secrets & client_secrets ,
361  GSmtp::MessageStore & store , const GAuth::Secrets & server_secrets ,
362  GPop::Store & pop_store , const GPop::Secrets & pop_secrets ,
363  G::PidFile & pid_file , GNet::EventLoop & event_loop )
364 {
365  const Configuration & cfg = config() ;
366  if( cfg.doSmtp() )
367  {
368  if( cfg.immediate() )
369  G_WARNING( "Run::doServing: using --immediate can result in client timeout errors: try --poll=0 instead" ) ;
370 
371  m_smtp_server <<= new GSmtp::Server(
372  store ,
373  client_secrets ,
374  server_secrets ,
375  serverConfig() ,
376  cfg.immediate() ? cfg.serverAddress() : std::string() ,
377  cfg.connectionTimeout() ,
378  clientConfig() ) ;
379 
380  m_smtp_server->eventSignal().connect( G::slot(*this,&Run::serverEvent) ) ;
381  }
382 
383  #ifndef USE_NO_POP
384  std::auto_ptr<GPop::Server> pop_server ;
385  if( cfg.doPop() )
386  {
387  pop_server <<= new GPop::Server( pop_store , pop_secrets , popConfig() ) ;
388  }
389  #endif
390 
391  #ifndef USE_NO_ADMIN
392  if( cfg.doAdmin() )
393  {
394  std::auto_ptr<GSmtp::AdminServer> admin_server = Admin::newServer( cfg , store , clientConfig() ,
395  client_secrets , versionNumber() ) ;
396  m_admin_server <<= admin_server.release() ;
397  }
398  #endif
399 
400  if( cfg.doPolling() )
401  {
402  m_poll_timer <<= new GNet::Timer<Run>(*this,&Run::onPollTimeout,*this) ;
403  m_poll_timer->startTimer( cfg.pollingTimeout() ) ;
404  }
405 
406  if( cfg.forwardingOnStore() || cfg.forwardingOnDisconnect() )
407  {
408  m_forwarding_timer <<= new GNet::Timer<Run>(*this,&Run::onForwardingTimeout,*this) ;
409  }
410 
411  {
412  // dont change the effective group id here -- create the pid file with the
413  // unprivileged group ownership so that it can be deleted more easily
414  G::Root claim_root(false) ;
415  pid_file.commit() ;
416  }
417 
418  closeMoreFiles() ;
419  if( m_smtp_server.get() ) m_smtp_server->report() ;
420  if( m_admin_server.get() ) Admin::report( *m_admin_server.get() ) ;
421  #ifndef USE_NO_POP
422  if( pop_server.get() ) pop_server->report() ;
423  #endif
424 
425  event_loop.run() ;
426 
427  if( m_smtp_server.get() ) m_smtp_server->eventSignal().disconnect() ;
428  m_smtp_server <<= 0 ;
429  m_admin_server <<= 0 ;
430 }
431 
432 void Main::Run::doForwardingOnStartup( GSmtp::MessageStore & store , const GAuth::Secrets & secrets ,
433  GNet::EventLoop & event_loop )
434 {
435  const Configuration & cfg = config() ;
436 
438  GNet::ResolverInfo(cfg.serverAddress()) , secrets , clientConfig() ) ) ;
439 
440  client_ptr->sendMessagesFrom( store ) ; // once connected
441 
442  // quit() the event loop when all done so that run() returns
443  client_ptr.doneSignal().connect( G::slot(*this,&Run::forwardingClientDone) ) ;
444 
445  // emit progress events
446  client_ptr.eventSignal().connect( G::slot(*this,&Run::clientEvent) ) ;
447 
448  closeMoreFiles() ;
449  std::string quit_reason = event_loop.run() ;
450  if( !quit_reason.empty() )
451  cl().showError( quit_reason ) ;
452 }
453 
454 GSmtp::Server::Config Main::Run::serverConfig() const
455 {
456  const Configuration & cfg = config() ;
457  return
459  cfg.allowRemoteClients() ,
460  cfg.port() ,
461  GNet::MultiServer::addressList( cfg.listeningInterfaces("smtp") , cfg.port() ) ,
462  smtpIdent() ,
463  cfg.anonymous() ,
464  cfg.filter() ,
465  cfg.filterTimeout() ,
466  cfg.verifier() ,
467  cfg.filterTimeout() , // verifier timeout - re-use filter timeout value
468  cfg.peerLookup() ) ; // use connection table to get username of local peers
469 }
470 
471 #ifndef USE_NO_POP
472 GPop::Server::Config Main::Run::popConfig() const
473 {
474  const Configuration & cfg = config() ;
475  return GPop::Server::Config( cfg.allowRemoteClients() , cfg.popPort() , cfg.listeningInterfaces("pop") ) ;
476 }
477 #endif
478 
479 GSmtp::Client::Config Main::Run::clientConfig() const
480 {
481  const Configuration & cfg = config() ;
482 
483  return
485  cfg.clientFilter() ,
486  cfg.filterTimeout() ,
487  clientBindAddress(cfg.clientInterface()) ,
490  cfg.responseTimeout() ,
491  cfg.promptTimeout() , // waiting for "service ready"
492  cfg.filterTimeout() ,
493  true , // (must-authenticate)
494  true , // (must-accept-all-recipients)
495  false ) , // (eight-bit-strict)
496  cfg.connectionTimeout() ,
497  cfg.secureConnectionTimeout() ,
498  cfg.clientOverTls() ) ;
499 }
500 
501 GNet::Address Main::Run::clientBindAddress( const std::string & s )
502 {
503  return s.empty() ?
504  GNet::Address(0U) : (
505  GNet::Address::validString( s ) ?
506  GNet::Address( s ) :
507  GNet::Address( s , 0U ) ) ;
508 }
509 
510 void Main::Run::onException( std::exception & e )
511 {
512  // gets here if onTimeout() throws
513  G_ERROR( "Main::Run::onException: exception while forwarding: " << e.what() ) ;
514 }
515 
516 void Main::Run::onPollTimeout()
517 {
518  G_DEBUG( "Main::Run::onPollTimeout" ) ;
519  m_poll_timer->startTimer( config().pollingTimeout() ) ;
520  doForwarding( "poll" ) ;
521 }
522 
523 void Main::Run::onForwardingTimeout()
524 {
525  G_DEBUG( "Main::Run::onForwardingTimeout" ) ;
526  doForwarding( "forward" ) ;
527 }
528 
529 void Main::Run::doForwarding( const std::string & event_key )
530 {
531  if( m_client.busy() )
532  {
533  G_LOG( "Main::Run::doForwarding: " << event_key << ": still busy from last time" ) ;
534  emit( event_key , "busy" , "" ) ;
535  }
536  else
537  {
538  emit( event_key , "start" , "" ) ;
539  std::string error = doForwardingCore() ;
540  emit( event_key , "end" , error ) ;
541  }
542 }
543 
544 std::string Main::Run::doForwardingCore()
545 {
546  try
547  {
548  const Configuration & cfg = config() ;
549 
550  G_DEBUG( "Main::Run::doForwarding: polling" ) ;
551  if( cfg.pollingLog() )
552  G_LOG( "Main::Run::doForwarding: polling" ) ;
553 
554  if( ! m_store->empty() )
555  {
556  m_client.reset( new GSmtp::Client( GNet::ResolverInfo(cfg.serverAddress()) ,
557  *m_client_secrets.get() , clientConfig() ) ) ;
558 
559  m_client->sendMessagesFrom( *m_store.get() ) ; // once connected
560  }
561  return std::string() ;
562  }
563  catch( std::exception & e )
564  {
565  G_ERROR( "Main::Run::doForwarding: polling: " << e.what() ) ;
566  return e.what() ;
567  }
568 }
569 
570 const Main::CommandLine & Main::Run::cl() const
571 {
572  // lazy evaluation so that the constructor doesnt throw
573  if( m_cl.get() == NULL )
574  {
575  const_cast<Run*>(this)->m_cl <<= new CommandLine( m_output , m_arg , m_switch_spec , versionNumber() , capabilities() ) ;
576  const_cast<Run*>(this)->m_cfg <<= new Configuration( cl().cfg() ) ;
577  }
578  return *m_cl.get() ;
579 }
580 
581 void Main::Run::forwardingClientDone( std::string reason , bool )
582 {
583  G_DEBUG( "Main::Run::forwardingClientDone: \"" << reason << "\"" ) ;
584  GNet::EventLoop::instance().quit( reason ) ;
585 }
586 
587 void Main::Run::pollingClientDone( std::string reason , bool )
588 {
589  G_DEBUG( "Main::Run::pollingClientDone: \"" << reason << "\"" ) ;
590  if( ! reason.empty() )
591  {
592  G_ERROR( "Main::Run::pollingClientDone: polling: " << reason ) ;
593  }
594 }
595 
596 void Main::Run::clientEvent( std::string s1 , std::string s2 )
597 {
598  emit( "client" , s1 , s2 ) ;
599 }
600 
601 void Main::Run::serverEvent( std::string s1 , std::string )
602 {
603  if( s1 == "done" && config().forwardingOnDisconnect() )
604  {
605  G_ASSERT( m_forwarding_timer.get() != NULL ) ;
606  m_forwarding_timer->cancelTimer() ;
607  m_forwarding_timer->startTimer( 0U ) ;
608  }
609 }
610 
611 void Main::Run::raiseStoreEvent( bool repoll )
612 {
613  emit( "store" , "update" , repoll ? std::string("poll") : std::string() ) ;
614 
615  const bool expiry_forced_by_filter = repoll ;
616  if( config().doPolling() && expiry_forced_by_filter )
617  {
618  G_ASSERT( m_poll_timer.get() != NULL ) ;
619  m_poll_timer->cancelTimer() ;
620  m_poll_timer->startTimer( 0U ) ;
621  }
622 
623  if( config().forwardingOnStore() )
624  {
625  G_ASSERT( m_forwarding_timer.get() != NULL ) ;
626  m_forwarding_timer->cancelTimer() ;
627  m_forwarding_timer->startTimer( 0U ) ;
628  }
629 }
630 
631 void Main::Run::raiseNetworkEvent( std::string s1 , std::string s2 )
632 {
633  emit( "network" , s1 , s2 ) ;
634 }
635 
636 void Main::Run::emit( const std::string & s0 , const std::string & s1 , const std::string & s2 )
637 {
638  #ifndef USE_NO_ADMIN
639  try
640  {
641  m_signal.emit( s0 , s1 , s2 ) ;
642  if( m_admin_server.get() != NULL )
643  {
644  Admin::notify( *m_admin_server.get() , s0 , s1 , s2 ) ;
645  }
646  }
647  catch( std::exception & e )
648  {
649  G_WARNING( "Main::Run::emit: " << e.what() ) ;
650  }
651  #endif
652 }
653 
655 {
656  return m_signal ;
657 }
658 
659 #ifndef USE_NO_EXEC
660 void Main::Run::checkScripts() const
661 {
662  const Configuration & cfg = config() ;
663  checkProcessorScript( cfg.filter() ) ;
664  checkProcessorScript( cfg.clientFilter() ) ;
665  checkVerifierScript( cfg.verifier() ) ;
666 }
667 void Main::Run::checkVerifierScript( const std::string & s ) const
668 {
669  std::string reason = GSmtp::VerifierFactory::check( s ) ;
670  if( !reason.empty() )
671  {
672  G_WARNING( "Main::Run::checkScript: invalid verifier \"" << s << "\": " << reason ) ;
673  }
674 }
675 void Main::Run::checkProcessorScript( const std::string & s ) const
676 {
677  std::string reason = GSmtp::ProcessorFactory::check( s ) ;
678  if( !reason.empty() )
679  {
680  G_WARNING( "Main::Run::checkScript: invalid preprocessor \"" << s << "\": " << reason ) ;
681  }
682 }
683 #endif
684 
void init(const Path &pid_file_path)
Used after default construction.
Definition: gpidfile.cpp:46
static AddressList addressList(const Address &)
A trivial convenience fuction that returns the given addresses as a single-element list...
bool prepare()
Prepares to run() typically by parsing the commandline.
Definition: run.cpp:150
bool clientOverTls() const
Returns true if using the SMTP over TLS (vs.
void connect(Slot1< P > slot)
Definition: gslot.h:221
std::string verifier() const
Returns the path of an external address verifier program.
static bool canBind(const Address &listening_address, bool do_throw)
Checks that the specified address can be bound.
Definition: gserver.cpp:172
A simple interface to a store of secrets as used in authentication.
Definition: gpopsecrets.h:44
void run()
Runs the application.
Definition: run.cpp:247
std::string filter() const
Returns the path to a server-side pre-processor.
Network classes.
virtual G::Signal1< bool > & signal()
Final override from GSmtp::MessageStore.
Definition: gfilestore.cpp:269
bool doServing() const
Returns true if running as a server (SMTP, POP, admin or COM).
bool daemon() const
Returns true if running as a daemon.
std::list< std::string > Strings
A std::list of std::strings.
Definition: gstrings.h:39
Run(Output &output, const G::Arg &arg, const std::string &switch_spec)
Constructor. Tries not to throw.
Definition: run.cpp:72
bool popNoDelete() const
Returns true if pop deletion is to be disabled.
const Configuration & config() const
Returns a configuration object.
Definition: run.cpp:119
static void closeStderr()
Closes stderr.
An abstract base class for a singleton that keeps track of open sockets and their associated handlers...
Definition: geventloop.h:51
The Address class encapsulates an IP transport address.
Definition: gaddress.h:48
bool hidden() const
Returns true if the program should run in hidden mode.
Definition: run.cpp:145
static std::string fqdn()
Returns the fully-qualified-domain-name.
Definition: glocal.cpp:67
G::Signal2< std::string, std::string > & eventSignal()
Returns a signal which indicates something interesting.
Definition: gclientptr.h:223
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:49
Slot0 slot(T &object, void(T::*fn)())
Part of the slot/signal system.
Definition: gslot.h:156
A class that holds a host/service name pair and optionally the results of a name-to-address lookup...
Definition: gresolverinfo.h:48
#define G_CAPABILITIES
Definition: run.cpp:59
G::Signal2< std::string, std::string > & signal()
Provides a callback signal which can be connect()ed to a slot.
Definition: gmonitor.cpp:110
A structure containing GSmtp::ClientProtocol configuration parameters.
G::Path spoolDir() const
Returns the spool directory.
A singleton which maintains a list of all Timer objects, and interfaces to the event loop on their be...
Definition: gtimerlist.h:42
A structure containing GPop::Server configuration parameters.
Definition: gpopserver.h:101
bool useSyslog() const
Returns true if generating syslog events.
A message store.
Definition: gpopstore.h:46
An abstract interface for generating output on a command-line or a GUI.
Definition: output.h:38
G::Signal2< std::string, std::string > & eventSignal()
Returns a signal that indicates that something has happened.
bool verbose() const
Returns true if doing verbose logging.
std::string serverTlsFile() const
Returns the tls certificate file if the server should support tls.
A POP server class.
Definition: gpopserver.h:96
A structure containing GSmtp::Server configuration parameters.
Definition: gsmtpserver.h:99
bool debug() const
Returns true if doing debug-level logging.
#define G_ASSERT(test)
Definition: gassert.h:30
virtual ~Run()
Destructor.
Definition: run.cpp:83
virtual std::string run()=0
Runs the main event loop.
A class which allows SMTP messages (envelope+content) to be stored and retrieved. ...
Definition: gmessagestore.h:45
A simple interface to a store of secrets as used in authentication.
Definition: gsecrets.h:44
std::string serverSecretsFile() const
Returns the server-side autentication secrets (password) file.
socklen_t length() const
Returns the size of the sockaddr address.
A singleton for monitoring SimpleClient and ServerPeer connections.
Definition: gmonitor.h:43
static std::auto_ptr< GSmtp::AdminServer > newServer(const Configuration &, GSmtp::MessageStore &store, const GSmtp::Client::Config &, const GAuth::Secrets &client_secrets, const std::string &version_number)
A factory function for creating a new GSmtp::AdminServer instance on the heap.
static std::string check(const std::string &address)
Checks an address.
#define G_ERROR(expr)
Definition: glog.h:108
bool prepareError() const
Returns true if prepare() failed.
Definition: run.cpp:114
#define G_LOG(expr)
Definition: glog.h:98
std::string nobody() const
Returns the name of an unprivileged user.
A class which deals with the command-line interface to the process, both input and output...
Definition: commandline.h:44
bool log() const
Returns true if doing logging.
An SMTP server class.
Definition: gsmtpserver.h:92
void commit()
Creates the file.
Definition: gpidfile.cpp:98
G::Signal2< std::string, bool > & doneSignal()
Returns a signal which indicates that client processing is complete and the client instance has delet...
Definition: gclientptr.h:217
std::string fqdn(std::string default_=std::string()) const
Returns the fully-qualified-domain-name override.
#define G_DEBUG(expr)
Definition: glog.h:95
std::string logFile() const
Returns the path of a stderr replacement for logging.
A structure containing GSmtp::Client configuration parameters.
Definition: gsmtpclient.h:61
unsigned int maxSize() const
Returns the maximum size of submitted messages, or zero.
std::string clientFilter() const
Returns the path to a client-side pre-processor.
std::string pidFile() const
Returns the pid file's path.
A class which acts as an SMTP client, extracting messages from a message store and forwarding them to...
Definition: gsmtpclient.h:55
virtual void onException(std::exception &)
Final override from GNet::EventHandler.
Definition: run.cpp:510
Controls and implements low-level logging output, as used by the Log interface.
Definition: glogoutput.h:41
static std::string versionNumber()
Returns the application version number string.
Definition: run.cpp:67
bool logTimestamp() const
Returns true if logging output should be timestamped.
A general-purpose exception class derived from std::exception and containing a std::string.
Definition: gexception.h:44
bool popByName() const
Returns true if the pop spool directory is modified according to the client name. ...
A concrete implementation of the MessageStore interface dealing in paired flat files and with an opti...
Definition: gfilestore.h:62
static void report(const GSmtp::AdminServer &server)
Calls report() on the given server.
A RAII class for initialising the underlying ssl library.
Definition: gssl.h:147
static void detach()
Detaches from the parent environment.
bool doForwardingOnStartup() const
Returns true if running as a client.
static std::string check(const std::string &address)
Checks an address.
A class which holds a represention of the argc/argv command line array, and supports simple command-l...
Definition: garg.h:46
static EventLoop * create()
A factory method which creates an instance of a derived class on the heap.
static void closeFiles(bool keep_stderr=false)
Closes all open file descriptors.
unsigned int tlsConfig() const
Returns TLS configuration flags.
std::string clientSecretsFile() const
Returns the client-side autentication secrets (password) file.
A class for creating pid files.
Definition: gpidfile.h:56
void connect(Slot2< P1, P2 > slot)
Definition: gslot.h:295
G::Signal3< std::string, std::string, std::string > & signal()
Provides a signal which is activated when something changes.
Definition: run.cpp:654
bool usePidFile() const
Returns true if writing a pid file.
static void init(const std::string &nobody)
Initialises this class on process start-up by releasing root or suid privileges.
Definition: groot.cpp:74
A Path object represents a file system path.
Definition: gpath.h:44
An interface for returning application configuration information.
Definition: configuration.h:45
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:43
virtual void quit(std::string reason)=0
Causes run() to return (once the call stack has unwound).
bool doPop() const
Returns true if listening for pop connections.
#define G_WARNING(expr)
Definition: glog.h:107
static void notify(GSmtp::AdminServer &server, const std::string &, const std::string &, const std::string &)
Calls notify() on the given server.
static void set(Mode)
bool clientTls() const
Returns true if the client protocol should take account of the server's tls capability.
std::string popSecretsFile() const
Returns the pop-server autentication secrets (password) file.