46 const std::string & version ,
const std::string & capabilities ) ;
47 bool contains(
const std::string & switch_ )
const ;
48 std::string
value(
const std::string & switch_ )
const ;
52 void showHelp(
bool error_stream )
const ;
57 void showNoop(
bool error_stream =
false )
const ;
58 void showError( std::string reason ,
bool error_stream =
true )
const ;
59 void showVersion(
bool error_stream =
false )
const ;
60 void showBanner(
bool error_stream =
false ,
const std::string & = std::string() )
const ;
61 void showCopyright(
bool error_stream =
false ,
const std::string & = std::string() )
const ;
62 void showCapabilities(
bool error_stream =
false ,
const std::string & = std::string() )
const ;
63 static std::string
switchSpec(
bool is_windows ) ;
66 void showWarranty(
bool error_stream =
false ,
const std::string & = std::string() )
const ;
67 void showCredit(
bool error_stream =
false ,
const std::string & = std::string() )
const ;
68 void showTestFeatures(
bool error_stream =
false ,
const std::string & = std::string() )
const ;
78 std::string m_version ;
79 std::string m_capabilities ;
95 static Show * m_this ;
97 void operator=(
const Show & ) ;
98 std::ostringstream m_ss ;
110 std::ostringstream ss ;
113 "q!as-client!runs as a client, forwarding all spooled mail to <host>!: "
114 "equivalent to \"--log --no-syslog --no-daemon --dont-serve --forward --forward-to\"!"
116 "d!as-server!runs as a server, storing mail in the spool directory!: equivalent to \"--log --close-stderr\"!0!!1|"
117 "y!as-proxy!runs as a proxy server, forwarding each mail immediately to <host>!"
118 ": equivalent to \"--log --close-stderr --poll=0 --forward-to\"!"
120 "v!verbose!generates more verbose output! (works with --help and --log)!0!!1|"
121 "h!help!displays help text and exits!!0!!1|"
123 "p!port!specifies the smtp listening port number (default is 25)!!1!port!2|"
124 "r!remote-clients!allows remote clients to connect!!0!!2|"
125 "s!spool-dir!specifies the spool directory (default is \"" << dir <<
"\")!!1!dir!2|"
126 "V!version!displays version information and exits!!0!!2|"
128 "j!client-tls!enables negotiated tls/ssl for smtp client! (if openssl built in)!0!!3|"
129 "b!client-tls-connection!enables smtp over tls/ssl for smtp client! (if openssl built in)!0!!3|"
130 "K!server-tls!enables negotiated tls/ssl for smtp server using the given openssl certificate file! (which must be in the directory trusted by openssl)!1!pem-file!3|"
131 "9!tls-config!sets tls configuration flags! (eg. 2 for SSLv2/3 support)!1!flags!3|"
132 "g!debug!generates debug-level logging if built in!!0!!3|"
133 "C!client-auth!enables smtp authentication with the remote server, using the given secrets file!!1!file!3|"
134 "L!log-time!adds a timestamp to the logging output!!0!!3|"
135 "N!log-file!log to file instead of stderr! (%d replaced by the date)!1!file!3|"
136 "S!server-auth!enables authentication of remote clients, using the given secrets file!!1!file!3|"
137 "e!close-stderr!closes the standard error stream soon after start-up!!0!!3|"
138 "a!admin!enables the administration interface and specifies its listening port number!!"
140 "x!dont-serve!disables acting as a server on any port! (part of --as-client and usually used with --forward)!0!!3|"
141 "X!no-smtp!disables listening for smtp connections! (usually used with --admin or --pop)!0!!3|"
142 "z!filter!specifies an external program to process messages as they are stored!!1!program!3|"
143 "W!filter-timeout!sets the timeout (in seconds) for running the --filter processor (default is 300)!!1!time!3|"
144 "w!prompt-timeout!sets the timeout (in seconds) for getting an initial prompt from the server (default is 20)!!1!time!3|"
145 "D!domain!sets an override for the host's fully qualified domain name!!1!fqdn!3|"
146 "f!forward!forwards stored mail on startup! (requires --forward-to)!0!!3|"
147 "o!forward-to!specifies the remote smtp server! (required by --forward, --poll, --immediate and --admin)!1!host:port!3|"
148 "T!response-timeout!sets the response timeout (in seconds) when talking to a remote server "
149 "(default is 1800)!!1!time!3|"
150 "U!connection-timeout!sets the timeout (in seconds) when connecting to a remote server "
151 "(default is 40)!!1!time!3|"
152 "m!immediate!enables immediate forwarding of messages as soon as they are received! (requires --forward-to)!0!!3|"
153 "I!interface!defines the listening interface(s) for incoming connections! (comma-separated list with optional smtp=,pop=,admin= qualifiers)!1!ip-list!3|"
154 "i!pid-file!defines a file for storing the daemon process-id!!1!pid-file!3|"
155 "O!poll!enables polling of the spool directory for messages to be forwarded with the specified period (zero means on client disconnection)! (requires --forward-to)!1!period!3|"
156 "P!postmaster!!!0!!0|"
157 "Z!verifier!specifies an external program for address verification!!1!program!3|"
158 "Y!client-filter!specifies an external program to process messages when they are forwarded!!1!program!3|"
159 "Q!admin-terminate!enables the terminate command on the admin interface!!0!!3|"
160 "A!anonymous!disables the smtp vrfy command and sends less verbose smtp responses!!0!!3|"
161 "B!pop!enables the pop server!!0!!3|"
162 "E!pop-port!specifies the pop listening port number (default is 110)! (requires --pop)!1!port!3|"
163 "F!pop-auth!defines the pop server secrets file (default is \"" << pop_auth <<
"\")!!1!file!3|"
164 "G!pop-no-delete!disables message deletion via pop! (requires --pop)!0!!3|"
165 "J!pop-by-name!modifies the pop spool directory according to the pop user name! (requires --pop)!0!!3|"
166 "M!size!limits the size of submitted messages!!1!bytes!3|"
174 "l!log!writes log information on standard error and syslog! (but see --close-stderr and --no-syslog)!0!!2|"
175 "t!no-daemon!does not detach from the terminal!!0!!3|"
176 "u!user!names the effective user to switch to if started as root "
177 "(default is \"daemon\")!!1!username!3|"
178 "k!syslog!forces syslog output if logging is enabled (overrides --no-syslog)!!0!!3|"
179 "n!no-syslog!disables syslog output (always overridden by --syslog)!!0!!3" ;
185 "l!log!writes log information on stderr and to the event log! (but see --close-stderr and --no-syslog)!0!!2|"
186 "t!no-daemon!uses an ordinary window, not the system tray!!0!!3|"
187 "k!syslog!forces system event log output if logging is enabled (overrides --no-syslog)!!0!!3|"
188 "n!no-syslog!disables use of the system event log!!0!!3|"
189 "c!icon!does nothing!!1!0^|1^|2^|3!0|"
190 "H!hidden!hides the application window and suppresses message boxes (requires --no-daemon)!!0!!3|"
191 "R!peer-lookup!lookup the account names of local peers! to put in the envelope files!0!!3" ;
195 const std::string & version ,
const std::string & capabilities ) :
198 m_capabilities(capabilities) ,
200 m_getopt(m_arg,spec,
'|',
'!',
'^')
206 return m_getopt.args().c() ;
211 return m_getopt.hasErrors() ;
216 Show show( m_output , e ) ;
220 if( m_getopt.contains(
"verbose") )
223 introducer = std::string(
"abbreviated ") + introducer ;
226 bool extra = m_getopt.contains(
"verbose") ;
227 m_getopt.showUsage( show.
s() , m_arg.prefix() ,
"" , introducer , level , tab_stop ,
233 return m_getopt.contains( name ) ;
238 return m_getopt.value( name ) ;
250 return "the listening ports must be different" ;
253 if( ! m_getopt.contains(
"pop") && (
254 m_getopt.contains(
"pop-port") ||
255 m_getopt.contains(
"pop-auth") ||
256 m_getopt.contains(
"pop-by-name") ||
257 m_getopt.contains(
"pop-no-delete") ) )
259 return "pop options require --pop" ;
264 return "the --admin-terminate option requires --admin" ;
269 return "in daemon mode the spool-dir must be an absolute path" ;
277 return "in daemon mode the authorisation secrets file(s) must be absolute paths" ;
280 const bool forward_to =
281 m_getopt.contains(
"as-proxy") ||
282 m_getopt.contains(
"as-client") ||
283 m_getopt.contains(
"forward-to") ;
285 if( ! forward_to && (
286 m_getopt.contains(
"forward") ||
287 m_getopt.contains(
"poll") ||
288 m_getopt.contains(
"immediate") ) )
290 return "the --forward, --immediate and --poll options require --forward-to" ;
293 const bool forwarding =
294 m_getopt.contains(
"as-proxy") ||
295 m_getopt.contains(
"as-client") ||
296 m_getopt.contains(
"forward") ||
297 m_getopt.contains(
"immediate") ||
298 m_getopt.contains(
"poll") ;
300 if( m_getopt.contains(
"client-filter") && ! forwarding )
302 return "the --client-filter option requires --as-proxy, --as-client, --poll, --immediate or --forward" ;
305 const bool not_serving = m_getopt.contains(
"dont-serve") || m_getopt.contains(
"as-client") ;
309 if( m_getopt.contains(
"filter") )
310 return "the --filter option cannot be used with --as-client or --dont-serve" ;
312 if( m_getopt.contains(
"port") )
313 return "the --port option cannot be used with --as-client or --dont-serve" ;
315 if( m_getopt.contains(
"server-auth") )
316 return "the --server-auth option cannot be used with --as-client or --dont-serve" ;
318 if( m_getopt.contains(
"pop") )
319 return "the --pop option cannot be used with --as-client or --dont-serve" ;
321 if( m_getopt.contains(
"admin") )
322 return "the --admin option cannot be used with --as-client or --dont-serve" ;
324 if( m_getopt.contains(
"poll") )
325 return "the --poll option cannot be used with --as-client or --dont-serve" ;
328 if( m_getopt.contains(
"no-smtp") )
330 if( m_getopt.contains(
"filter") )
331 return "the --filter option cannot be used with --no-smtp" ;
333 if( m_getopt.contains(
"port") )
334 return "the --port option cannot be used with --no-smtp" ;
336 if( m_getopt.contains(
"server-auth") )
337 return "the --server-auth option cannot be used with --no-smtp" ;
341 m_getopt.contains(
"log") ||
342 m_getopt.contains(
"as-server") ||
343 m_getopt.contains(
"as-client") ||
344 m_getopt.contains(
"as-proxy") ;
346 if( m_getopt.contains(
"verbose") && ! ( m_getopt.contains(
"help") || log ) )
348 return "the --verbose option must be used with --log, --help, --as-client, --as-server or --as-proxy" ;
351 if( m_getopt.contains(
"debug") && !log )
353 return "the --debug option requires --log, --as-client, --as-server or --as-proxy" ;
356 const bool no_daemon =
357 m_getopt.contains(
"as-client") ||
358 m_getopt.contains(
"no-daemon") ;
360 if( m_getopt.contains(
"hidden") && ! no_daemon )
362 return "the --hidden option requires --no-daemon or --as-client" ;
365 if( m_getopt.contains(
"client-tls") && m_getopt.contains(
"client-tls-connection") )
367 return "the --client-tls and --client-tls-connection options cannot be used together" ;
370 if( m_getopt.contains(
"server-auth") && m_getopt.value(
"server-auth") ==
"/pam" &&
371 !m_getopt.contains(
"server-tls" ) )
373 return "--server-auth using pam requires --server-tls" ;
376 if( m_getopt.contains(
"pop-auth") && m_getopt.value(
"pop-auth") ==
"/pam" &&
377 !m_getopt.contains(
"server-tls" ) )
379 return "--pop-auth using pam requires --server-tls" ;
384 const bool no_syslog =
385 m_getopt.contains(
"no-syslog") ||
386 m_getopt.contains(
"as-client") ;
389 ! ( no_syslog && ! m_getopt.contains(
"syslog") ) ;
391 const bool close_stderr =
392 m_getopt.contains(
"close-stderr") ||
393 m_getopt.contains(
"as-server") ||
394 m_getopt.contains(
"as-proxy") ;
396 if( log && close_stderr && !syslog )
398 std::string close_stderr_switch =
399 ( m_getopt.contains(
"close-stderr") ?
"--close-stderr" :
400 ( m_getopt.contains(
"as-server") ?
"--as-server" :
403 std::string warning =
"logging is enabled but it has nowhere to go because " +
404 close_stderr_switch +
" closes the standard error stream soon after startup and " +
405 "output to the system log is disabled" ;
407 if( m_getopt.contains(
"as-server") && !m_getopt.contains(
"log") )
408 warning = warning +
": replace --as-server with --log" ;
409 else if( m_getopt.contains(
"as-server") )
410 warning = warning +
": remove --as-server" ;
411 else if( m_getopt.contains(
"as-proxy" ) )
412 warning = warning +
": replace --as-proxy with --log --poll 0 --forward-to" ;
419 return std::string() ;
425 bool error = ! semanticError(cfg,fatal).empty() ;
426 return error && fatal ;
431 Show show( m_output , e ) ;
433 show.
s() << m_arg.prefix() <<
": usage error: " << semanticError(cfg,fatal) << std::endl ;
439 std::string warning = semanticError( cfg , fatal ) ;
440 if( !warning.empty() && !fatal )
441 G_WARNING(
"CommandLine::logSemanticWarnings: " << warning ) ;
446 Show show( m_output , e ) ;
447 m_getopt.showErrors( show.
s() , m_arg.prefix() ) ;
453 Show show( m_output , e ) ;
454 show.
s() << m_arg.prefix() <<
": usage error: too many non-switch arguments" << std::endl ;
460 Show show( m_output , e ) ;
461 const std::string & exe = m_arg.prefix() ;
463 << std::string(exe.length()+2U,
' ')
464 <<
"try \"" << exe <<
" --help --verbose\" for more information" << std::endl ;
469 Show show( m_output , e ) ;
471 show.
s() << std::endl ;
479 Show show( m_output , e ) ;
480 const std::string & exe = m_arg.prefix() ;
482 show.
s() << std::endl ;
484 if( m_getopt.contains(
"verbose") )
487 <<
"To start a 'storage' daemon in background..." << std::endl
488 <<
" " << exe <<
" --as-server" << std::endl
492 <<
"To forward stored mail to \"mail.myisp.net\"..." << std::endl
493 <<
" " << exe <<
" --as-client mail.myisp.net:smtp" << std::endl
497 <<
"To run as a proxy (on port 10025) to a local server (on port 25)..." << std::endl
498 <<
" " << exe <<
" --port 10025 --as-proxy localhost:25" << std::endl
504 <<
"For complete usage information run \"" << exe
505 <<
" --help --verbose\"" << std::endl
512 Show show( m_output , e ) ;
513 show.
s() << m_arg.prefix() <<
": no messages to send" << std::endl ;
518 Show show( m_output , e ) ;
519 show.
s() << m_arg.prefix() <<
": " << reason << std::endl ;
524 Show show( m_output , e ) ;
526 <<
"E-MailRelay V" << m_version << std::endl << final ;
531 Show show( m_output , e ) ;
537 if( !m_capabilities.empty() )
539 Show show( m_output , e ) ;
540 show.
s() <<
"Build configuration [" << m_capabilities <<
"]" << std::endl << final ;
546 Show show( m_output , e ) ;
552 Show show( m_output , e ) ;
558 Show show( m_output , e ) ;
559 show.
s() <<
"Test features " << (
G::Test::enabled()?
"enabled":
"disabled") << std::endl <<
final ;
564 Show show( m_output , e ) ;
565 showBanner( e ,
"\n" ) ;
566 showCopyright( e ,
"\n" ) ;
567 if( contains(
"verbose") )
569 showCapabilities( e ,
"\n" ) ;
570 showTestFeatures( e ,
"\n" ) ;
572 showCredit( e ,
"\n" ) ;
590 return m_this->m_ss ;
598 m_output.output( m_ss.str() , m_e ) ;
610 const std::string & version ,
const std::string & capabilities ) :
627 return m_imp->contains( switch_ ) ;
632 return m_imp->value( switch_ ) ;
637 return m_imp->argc() ;
642 return m_imp->hasUsageErrors() ;
647 return m_imp->hasSemanticError( cfg() ) ;
652 m_imp->showHelp( error_stream ) ;
657 m_imp->showUsageErrors( error_stream ) ;
662 m_imp->showSemanticError( cfg() , error_stream ) ;
667 m_imp->logSemanticWarnings( cfg() ) ;
672 m_imp->showArgcError( error_stream ) ;
677 m_imp->showNoop( error_stream ) ;
682 m_imp->showError( reason , error_stream ) ;
687 m_imp->showVersion( error_stream ) ;
692 m_imp->showBanner( error_stream , s ) ;
697 m_imp->showCopyright( error_stream , s ) ;
702 m_imp->showCapabilities( error_stream , s ) ;
707 return m_imp->contains(switch_) ?
G::Str::toUInt(value(switch_)) : default_ ;
713 if( contains(switch_) )
722 return contains( std::string(switch_) ) ;
727 return value( std::string(switch_) ) ;
732 return value( std::string(switch_) , default_ ) ;
737 return value( std::string(switch_) , std::string(separators) ) ;
std::string str() const
Returns the path string.
Application-level classes.
static std::string copyright()
Returns the copyright text.
void showError(std::string reason, bool error_stream=true) const
void showSemanticError(const Configuration &cfg, bool error_stream) const
void showCopyright(bool error_stream=false, const std::string &=std::string()) const
Writes a copyright message.
static std::string switchSpec_windows()
Configuration cfg() const
Returns a Configuration object.
std::string value(const std::string &switch_) const
static std::string warranty(const std::string &prefix, const std::string &eol)
Returns the warranty text.
static unsigned int toUInt(const std::string &s, bool limited=false)
Converts string 's' to an unsigned int.
bool daemon() const
Returns true if running as a daemon.
std::list< std::string > Strings
A std::list of std::strings.
void showCopyright(bool error_stream=false, const std::string &=std::string()) const
static void splitIntoFields(const std::string &in, Strings &out, const std::string &seperators, char escape= '\0', bool discard_bogus_escapes=true)
Splits the string into fields.
void showCapabilities(bool error_stream=false, const std::string &=std::string()) const
Writes a capability line.
unsigned int popPort() const
Returns the pop port number.
void showError(const std::string &reason, bool error_stream=true) const
Writes a failed message.
A private implementation class used by Main::CommandLine.
std::string::size_type size_type
A std::size_t type.
CommandLine(Main::Output &output, const G::Arg &arg, const std::string &spec, const std::string &version, const std::string &capabilities)
Constructor.
void showNoop(bool error_stream=false) const
void showUsageErrors(bool error_stream) const
G::Path spoolDir() const
Returns the spool directory.
static std::string switchSpec(bool is_windows)
bool doAdmin() const
Returns true if listening for admin connections.
void showTestFeatures(bool error_stream=false, const std::string &=std::string()) const
~CommandLine()
Destructor.
void showBanner(bool error_stream=false, const std::string &=std::string()) const
Writes a startup banner.
void showExtraHelp(bool error_stream) const
An abstract interface for generating output on a command-line or a GUI.
void showVersion(bool error_stream=false) const
void logSemanticWarnings() const
Emits warnings about conflicting switches.
bool isRelative() const
Returns true if the path is a relative path.
bool hasSemanticError() const
Returns true if the command line has logical errors (eg. conflicting switches).
void showArgcError(bool error_stream=true) const
Writes a too-many-arguments error message.
A command line switch parser.
std::string value(const std::string &switch_) const
Returns the given switch's string value.
std::string semanticError(const Configuration &, bool &) const
static std::string switchSpec_unix()
bool contains(const std::string &switch_) const
Returns true if the command line contained the give switch.
std::string serverSecretsFile() const
Returns the server-side autentication secrets (password) file.
void showCapabilities(bool error_stream=false, const std::string &=std::string()) const
static bool enabled()
Returns true if test features are enabled.
Show(Main::Output &, bool e)
static std::string credit(const std::string &prefix, const std::string &eol, const std::string &final)
Returns a credit string.
void showBanner(bool error_stream=false, const std::string &=std::string()) const
static G::Path defaultDirectory()
Returns a default spool directory, such as "/usr/local/var/spool/emailrelay".
void showVersion(bool error_stream=false) const
Writes the version number.
void showUsage(bool e) const
static size_type wrapDefault()
Returns a default word-wrapping width.
bool hasUsageErrors() const
Returns true if the command line has usage errors (eg. invalid switch).
void showUsageErrors(bool error_stream=true) const
Writes the usage errors.
void showWarranty(bool error_stream=false, const std::string &=std::string()) const
G::Arg::size_type argc() const
void showHelp(bool error_stream) const
CommandLineImp(Main::Output &, const G::Arg &arg, const std::string &spec, const std::string &version, const std::string &capabilities)
bool withTerminate() const
Returns true if the admin interface should support the terminate command.
unsigned int port() const
Returns the main listening port number.
void showArgcError(bool error_stream) const
static Level levelDefault()
Returns the default level.
A class which holds a represention of the argc/argv command line array, and supports simple command-l...
void showCredit(bool error_stream=false, const std::string &=std::string()) const
unsigned int adminPort() const
Returns the admin port number.
void showHelp(bool error_stream=false) const
Writes help text.
std::string clientSecretsFile() const
Returns the client-side autentication secrets (password) file.
void logSemanticWarnings(const Configuration &cfg) const
static std::string introducerDefault()
Returns "usage: ".
A private implementation class used by Main::CommandLineImp.
static std::string defaultPath()
Returns the default path.
void showNoop(bool error_stream=false) const
Writes a nothing-to-do message.
A Path object represents a file system path.
Used by G::GetOpt for extra type safety.
An interface for returning application configuration information.
static std::string switchSpec(bool is_windows)
Returns an o/s-specific G::GetOpt switch specification string.
bool hasUsageErrors() const
void showShortHelp(bool error_stream) const
bool doPop() const
Returns true if listening for pop connections.
void showSemanticError(bool error_stream=true) const
Writes the logic errors.
bool contains(const std::string &switch_) const
G::Arg::size_type argc() const
Returns the number of non-switch arguments on the command line.
bool hasSemanticError(const Configuration &) const
std::string popSecretsFile() const
Returns the pop-server autentication secrets (password) file.