58 #ifndef G_CAPABILITIES
59 #define G_CAPABILITIES ""
62 std::string Main::Run::capabilities()
74 m_switch_spec(switch_spec) ,
76 m_client_resolver_info(std::string(),std::string()) ,
77 m_prepare_error(false)
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() ;
94 m_client.cleanupForExit() ;
98 m_forwarding_timer <<= 0 ;
100 m_smtp_server <<= 0 ;
101 m_admin_server <<= 0 ;
102 m_pop_secrets <<= 0 ;
103 m_client_secrets <<= 0 ;
116 return m_prepare_error ;
122 return *m_cfg.get() ;
125 std::string Main::Run::smtpIdent()
const
127 return std::string(
"E-MailRelay V") + versionNumber() ;
130 void Main::Run::closeFiles()
132 if( config().daemon() )
134 const bool keep_stderr = true ;
139 void Main::Run::closeMoreFiles()
141 if( config().closeStderr() )
147 return cl().contains(
"hidden") ;
152 #ifndef USE_SMALL_CONFIG
153 if( cl().contains(
"help") )
155 cl().showHelp(
false ) ;
156 m_prepare_error = false ;
159 else if( cl().hasUsageErrors() )
161 cl().showUsageErrors(
true ) ;
162 m_prepare_error = true ;
165 else if( cl().contains(
"version") )
167 cl().showVersion(
false ) ;
168 m_prepare_error = false ;
171 else if( cl().argc() > 1U )
173 cl().showArgcError(
true ) ;
174 m_prepare_error = true ;
177 else if( cl().hasSemanticError() )
179 cl().showSemanticError(
true ) ;
180 m_prepare_error = true ;
201 #ifndef USE_SMALL_CONFIG
203 cl().logSemanticWarnings() ;
209 #ifndef USE_SMALL_CONFIG
210 void Main::Run::checkPort(
bool check ,
const std::string & interface_ ,
unsigned int port )
217 GNet::Address(port) ;
223 void Main::Run::checkPorts()
const
225 #ifndef USE_SMALL_CONFIG
226 const Configuration & cfg = config() ;
227 if( cfg.doServing() )
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() ) ;
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() ) ;
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() ) ;
252 G_LOG(
"Main::Run::run: done" ) ;
254 catch( std::exception & e )
256 G_ERROR(
"Main::Run::run: " << e.what() ) ;
261 G_ERROR(
"Main::Run::run: unknown exception" ) ;
266 void Main::Run::runCore()
272 std::string nul( 1U ,
'\0' ) ;
273 if( cfg.
fqdn(nul) != nul )
297 if( ! event_loop->init() )
298 throw G::Exception(
"cannot initialise network layer" ) ;
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" ) ;
345 if( m_store->empty() )
346 cl().showNoop(
true ) ;
348 doForwardingOnStartup( *m_store.get() , *m_client_secrets.get() , *event_loop.get() ) ;
355 doServing( *m_client_secrets.get() , *m_store.get() , server_secrets ,
356 pop_store , *m_pop_secrets.get() , pid_file , *event_loop.get() ) ;
360 void Main::Run::doServing(
const GAuth::Secrets & client_secrets ,
365 const Configuration & cfg = config() ;
368 if( cfg.immediate() )
369 G_WARNING(
"Run::doServing: using --immediate can result in client timeout errors: try --poll=0 instead" ) ;
376 cfg.immediate() ? cfg.serverAddress() : std::string() ,
377 cfg.connectionTimeout() ,
384 std::auto_ptr<GPop::Server> pop_server ;
387 pop_server <<=
new GPop::Server( pop_store , pop_secrets , popConfig() ) ;
394 std::auto_ptr<GSmtp::AdminServer> admin_server =
Admin::newServer( cfg , store , clientConfig() ,
395 client_secrets , versionNumber() ) ;
396 m_admin_server <<= admin_server.release() ;
400 if( cfg.doPolling() )
402 m_poll_timer <<= new GNet::Timer<Run>(*
this,&Run::onPollTimeout,*
this) ;
403 m_poll_timer->startTimer( cfg.pollingTimeout() ) ;
406 if( cfg.forwardingOnStore() || cfg.forwardingOnDisconnect() )
408 m_forwarding_timer <<= new GNet::Timer<Run>(*
this,&Run::onForwardingTimeout,*
this) ;
419 if( m_smtp_server.get() ) m_smtp_server->report() ;
420 if( m_admin_server.get() )
Admin::report( *m_admin_server.get() ) ;
422 if( pop_server.get() ) pop_server->report() ;
427 if( m_smtp_server.get() ) m_smtp_server->eventSignal().disconnect() ;
428 m_smtp_server <<= 0 ;
429 m_admin_server <<= 0 ;
435 const Configuration & cfg = config() ;
440 client_ptr->sendMessagesFrom( store ) ;
443 client_ptr.doneSignal().connect(
G::slot(*
this,&Run::forwardingClientDone) ) ;
446 client_ptr.eventSignal().connect(
G::slot(*
this,&Run::clientEvent) ) ;
449 std::string quit_reason = event_loop.
run() ;
450 if( !quit_reason.empty() )
451 cl().showError( quit_reason ) ;
456 const Configuration & cfg = config() ;
459 cfg.allowRemoteClients() ,
465 cfg.filterTimeout() ,
467 cfg.filterTimeout() ,
474 const Configuration & cfg = config() ;
475 return GPop::Server::Config( cfg.allowRemoteClients() , cfg.popPort() , cfg.listeningInterfaces(
"pop") ) ;
481 const Configuration & cfg = config() ;
486 cfg.filterTimeout() ,
487 clientBindAddress(cfg.clientInterface()) ,
490 cfg.responseTimeout() ,
491 cfg.promptTimeout() ,
492 cfg.filterTimeout() ,
496 cfg.connectionTimeout() ,
497 cfg.secureConnectionTimeout() ,
498 cfg.clientOverTls() ) ;
501 GNet::Address Main::Run::clientBindAddress(
const std::string & s )
505 GNet::Address::validString( s ) ?
507 GNet::Address( s , 0U ) ) ;
513 G_ERROR(
"Main::Run::onException: exception while forwarding: " << e.what() ) ;
516 void Main::Run::onPollTimeout()
518 G_DEBUG(
"Main::Run::onPollTimeout" ) ;
519 m_poll_timer->startTimer( config().pollingTimeout() ) ;
520 doForwarding(
"poll" ) ;
523 void Main::Run::onForwardingTimeout()
525 G_DEBUG(
"Main::Run::onForwardingTimeout" ) ;
526 doForwarding(
"forward" ) ;
529 void Main::Run::doForwarding(
const std::string & event_key )
531 if( m_client.busy() )
533 G_LOG(
"Main::Run::doForwarding: " << event_key <<
": still busy from last time" ) ;
534 emit( event_key ,
"busy" ,
"" ) ;
538 emit( event_key ,
"start" ,
"" ) ;
539 std::string error = doForwardingCore() ;
540 emit( event_key ,
"end" , error ) ;
544 std::string Main::Run::doForwardingCore()
548 const Configuration & cfg = config() ;
550 G_DEBUG(
"Main::Run::doForwarding: polling" ) ;
551 if( cfg.pollingLog() )
552 G_LOG(
"Main::Run::doForwarding: polling" ) ;
554 if( ! m_store->empty() )
557 *m_client_secrets.get() , clientConfig() ) ) ;
559 m_client->sendMessagesFrom( *m_store.get() ) ;
561 return std::string() ;
563 catch( std::exception & e )
565 G_ERROR(
"Main::Run::doForwarding: polling: " << e.what() ) ;
573 if( m_cl.get() == NULL )
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() ) ;
581 void Main::Run::forwardingClientDone( std::string reason ,
bool )
583 G_DEBUG(
"Main::Run::forwardingClientDone: \"" << reason <<
"\"" ) ;
587 void Main::Run::pollingClientDone( std::string reason ,
bool )
589 G_DEBUG(
"Main::Run::pollingClientDone: \"" << reason <<
"\"" ) ;
590 if( ! reason.empty() )
592 G_ERROR(
"Main::Run::pollingClientDone: polling: " << reason ) ;
596 void Main::Run::clientEvent( std::string s1 , std::string s2 )
598 emit(
"client" , s1 , s2 ) ;
601 void Main::Run::serverEvent( std::string s1 , std::string )
603 if( s1 ==
"done" && config().forwardingOnDisconnect() )
605 G_ASSERT( m_forwarding_timer.get() != NULL ) ;
606 m_forwarding_timer->cancelTimer() ;
607 m_forwarding_timer->startTimer( 0U ) ;
611 void Main::Run::raiseStoreEvent(
bool repoll )
613 emit(
"store" ,
"update" , repoll ? std::string(
"poll") : std::string() ) ;
615 const bool expiry_forced_by_filter = repoll ;
616 if( config().doPolling() && expiry_forced_by_filter )
618 G_ASSERT( m_poll_timer.get() != NULL ) ;
619 m_poll_timer->cancelTimer() ;
620 m_poll_timer->startTimer( 0U ) ;
623 if( config().forwardingOnStore() )
625 G_ASSERT( m_forwarding_timer.get() != NULL ) ;
626 m_forwarding_timer->cancelTimer() ;
627 m_forwarding_timer->startTimer( 0U ) ;
631 void Main::Run::raiseNetworkEvent( std::string s1 , std::string s2 )
633 emit(
"network" , s1 , s2 ) ;
636 void Main::Run::emit(
const std::string & s0 ,
const std::string & s1 ,
const std::string & s2 )
641 m_signal.emit( s0 , s1 , s2 ) ;
642 if( m_admin_server.get() != NULL )
647 catch( std::exception & e )
649 G_WARNING(
"Main::Run::emit: " << e.what() ) ;
660 void Main::Run::checkScripts()
const
663 checkProcessorScript( cfg.
filter() ) ;
665 checkVerifierScript( cfg.
verifier() ) ;
667 void Main::Run::checkVerifierScript(
const std::string & s )
const
670 if( !reason.empty() )
672 G_WARNING(
"Main::Run::checkScript: invalid verifier \"" << s <<
"\": " << reason ) ;
675 void Main::Run::checkProcessorScript(
const std::string & s )
const
678 if( !reason.empty() )
680 G_WARNING(
"Main::Run::checkScript: invalid preprocessor \"" << s <<
"\": " << reason ) ;
void init(const Path &pid_file_path)
Used after default construction.
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.
bool clientOverTls() const
Returns true if using the SMTP over TLS (vs.
void connect(Slot1< P > slot)
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.
A simple interface to a store of secrets as used in authentication.
void run()
Runs the application.
std::string filter() const
Returns the path to a server-side pre-processor.
virtual G::Signal1< bool > & signal()
Final override from GSmtp::MessageStore.
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.
Run(Output &output, const G::Arg &arg, const std::string &switch_spec)
Constructor. Tries not to throw.
bool popNoDelete() const
Returns true if pop deletion is to be disabled.
const Configuration & config() const
Returns a configuration object.
static void closeStderr()
Closes stderr.
An abstract base class for a singleton that keeps track of open sockets and their associated handlers...
The Address class encapsulates an IP transport address.
bool hidden() const
Returns true if the program should run in hidden mode.
static std::string fqdn()
Returns the fully-qualified-domain-name.
G::Signal2< std::string, std::string > & eventSignal()
Returns a signal which indicates something interesting.
A class which acquires the process's special privileges on construction and releases them on destruct...
Slot0 slot(T &object, void(T::*fn)())
Part of the slot/signal system.
A class that holds a host/service name pair and optionally the results of a name-to-address lookup...
G::Signal2< std::string, std::string > & signal()
Provides a callback signal which can be connect()ed to a slot.
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...
A structure containing GPop::Server configuration parameters.
bool useSyslog() const
Returns true if generating syslog events.
An abstract interface for generating output on a command-line or a GUI.
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 structure containing GSmtp::Server configuration parameters.
bool debug() const
Returns true if doing debug-level logging.
virtual ~Run()
Destructor.
virtual std::string run()=0
Runs the main event loop.
A class which allows SMTP messages (envelope+content) to be stored and retrieved. ...
A simple interface to a store of secrets as used in authentication.
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.
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.
bool prepareError() const
Returns true if prepare() failed.
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...
bool log() const
Returns true if doing logging.
void commit()
Creates the file.
G::Signal2< std::string, bool > & doneSignal()
Returns a signal which indicates that client processing is complete and the client instance has delet...
std::string fqdn(std::string default_=std::string()) const
Returns the fully-qualified-domain-name override.
std::string logFile() const
Returns the path of a stderr replacement for logging.
A structure containing GSmtp::Client configuration parameters.
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...
virtual void onException(std::exception &)
Final override from GNet::EventHandler.
Controls and implements low-level logging output, as used by the Log interface.
static std::string versionNumber()
Returns the application version number string.
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.
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...
static void report(const GSmtp::AdminServer &server)
Calls report() on the given server.
A RAII class for initialising the underlying ssl library.
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...
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.
void connect(Slot2< P1, P2 > slot)
G::Signal3< std::string, std::string, std::string > & signal()
Provides a signal which is activated when something changes.
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.
A Path object represents a file system path.
An interface for returning application configuration information.
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
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.
static void notify(GSmtp::AdminServer &server, const std::string &, const std::string &, const std::string &)
Calls notify() on the given server.
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.