E-MailRelay
gverifierfactory.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 gverifierfactory.cpp
19///
20
21#include "gdef.h"
22#include "gverifierfactory.h"
23#include "ginternalverifier.h"
24#include "gexecutableverifier.h"
25#include "gnetworkverifier.h"
26#include "guserverifier.h"
27#include "gfile.h"
28#include "gstr.h"
29#include "gstringtoken.h"
30#include "grange.h"
31#include "gexception.h"
32
34= default ;
35
37 const G::Path & base_dir , const G::Path & app_dir , G::StringArray * warnings_p )
38{
39 std::string_view tail = G::Str::tailView( spec_in , ":" ) ;
40 Spec result ;
41 if( spec_in.empty() )
42 {
43 result = Spec( "exit" , "0" ) ;
44 checkExit( result ) ;
45 }
46 else if( G::Str::headMatch( spec_in , "exit:" ) )
47 {
48 result = Spec( "exit" , tail ) ;
49 checkExit( result ) ;
50 }
51 else if( G::Str::headMatch( spec_in , "net:" ) )
52 {
53 result = Spec( "net" , tail ) ;
54 checkNet( result ) ;
55 }
56 else if( G::Str::headMatch( spec_in , "account:" ) )
57 {
58 result = Spec( "account" , tail ) ;
59 checkRange( result ) ;
60 }
61 else if( G::Str::headMatch( spec_in , "file:" ) )
62 {
63 result = Spec( "file" , tail ) ;
64 fixFile( result , base_dir , app_dir ) ;
65 checkFile( result , warnings_p ) ;
66 }
67 else
68 {
69 result = Spec( "file" , spec_in ) ;
70 fixFile( result , base_dir , app_dir ) ;
71 checkFile( result , warnings_p ) ;
72 }
73 return result ;
74}
75
76std::unique_ptr<GSmtp::Verifier> GVerifiers::VerifierFactory::newVerifier( GNet::EventState es ,
77 const GSmtp::Verifier::Config & config , const Spec & spec )
78{
79 if( spec.first == "exit" )
80 {
81 return std::make_unique<InternalVerifier>() ;
82 }
83 else if( spec.first == "net" )
84 {
85 return std::make_unique<NetworkVerifier>( es , config , spec.second ) ;
86 }
87 else if( spec.first == "account" )
88 {
89 return std::make_unique<UserVerifier>( es , config , spec.second ) ;
90 }
91 else if( spec.first == "file" )
92 {
93 return std::make_unique<ExecutableVerifier>( es , config , G::Path(spec.second) ) ;
94 }
95
96 throw G::Exception( "invalid verifier" , spec.second ) ;
97}
98
99void GVerifiers::VerifierFactory::checkExit( Spec & result )
100{
101 if( !G::Str::isUInt(result.second) )
102 {
103 result.first.clear() ;
104 result.second = "not a numeric exit code: " + G::Str::printable(result.second) ;
105 }
106}
107
108void GVerifiers::VerifierFactory::checkNet( Spec & result )
109{
110 try
111 {
112 GNet::Location::nosocks( result.second ) ;
113 }
114 catch( std::exception & e )
115 {
116 result.first.clear() ;
117 result.second = e.what() ;
118 }
119}
120
121void GVerifiers::VerifierFactory::checkRange( Spec & result )
122{
123 try
124 {
125 std::string_view spec_view( result.second ) ;
126 for( G::StringTokenView t( spec_view , ";" , 1U ) ; t ; ++t )
127 {
128 if( !t().empty() && G::Str::isNumeric(t().substr(0U,1U)) )
129 G::Range::check( t() ) ;
130 }
131 }
132 catch( std::exception & e )
133 {
134 result.first.clear() ;
135 result.second = e.what() ;
136 }
137}
138
139void GVerifiers::VerifierFactory::fixFile( Spec & result , const G::Path & base_dir , const G::Path & app_dir )
140{
141 if( !app_dir.empty() && result.second.find("@app") == 0U )
142 G::Str::replace( result.second , "@app" , app_dir.str() ) ;
143 else if( !base_dir.empty() && G::Path(result.second).isRelative() )
144 result.second = (base_dir/result.second).str() ;
145}
146
147void GVerifiers::VerifierFactory::checkFile( Spec & result , G::StringArray * warnings_p )
148{
149 if( result.second.empty() )
150 {
151 result.first.clear() ;
152 result.second = "empty file path" ;
153 }
154 else if( warnings_p && !G::File::exists(result.second) )
155 {
156 warnings_p->push_back( std::string("verifier program does not exist: ").append(result.second) ) ;
157 }
158 else if( warnings_p && G::File::isDirectory(result.second,std::nothrow) )
159 {
160 warnings_p->push_back( std::string("invalid program: ").append(result.second) ) ;
161 }
162}
163
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
Definition: geventstate.h:131
static Location nosocks(const std::string &spec, int family=AF_UNSPEC)
Factory function for a remote location but not allowing the extended syntax for socks.
Definition: glocation.cpp:77
static Spec parse(std::string_view spec, const G::Path &base_dir={}, const G::Path &app_dir={}, G::StringArray *warnings_p=nullptr)
Parses a verifier specification string like "/usr/bin/foo" or "net:127.0.0.1:99" or "net:/run/spamd....
std::unique_ptr< GSmtp::Verifier > newVerifier(GNet::EventState, const GSmtp::Verifier::Config &config, const GSmtp::VerifierFactoryBase::Spec &spec) override
Returns a Verifier on the heap.
A general-purpose exception class derived from std::exception and containing an error message.
Definition: gexception.h:64
static bool isDirectory(const Path &path, std::nothrow_t)
Returns true if the path exists() and is a directory.
Definition: gfile.cpp:179
static bool exists(const Path &file)
Returns true if the file (directory, device etc.) exists.
Definition: gfile.cpp:136
A Path object represents a file system path.
Definition: gpath.h:82
bool isRelative() const noexcept
Returns true if the path is a relative path or empty().
Definition: gpath.cpp:334
std::string str() const
Returns the path string.
Definition: gpath.h:243
bool empty() const noexcept
Returns true if the path is empty.
Definition: gpath.h:237
static bool isUInt(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
Definition: gstr.cpp:446
static bool headMatch(std::string_view in, std::string_view head) noexcept
Returns true if the string has the given start (or head is empty).
Definition: gstr.cpp:1359
static bool isNumeric(std::string_view s, bool allow_minus_sign=false) noexcept
Returns true if every character is a decimal digit.
Definition: gstr.cpp:400
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
static std::string_view tailView(std::string_view in, std::size_t pos, std::string_view default_={}) noexcept
Like tail() but returning a view into the input string.
Definition: gstr.cpp:1337
static bool replace(std::string &s, std::string_view from, std::string_view to, std::size_t *pos_p=nullptr)
A std::string_view overload.
Definition: gstr.cpp:226
A zero-copy string token iterator where the token separators are runs of whitespace characters,...
Definition: gstringtoken.h:54
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30
Verifier specification tuple for GSmtp::VerifierFactoryBase::newVerifier().
Configuration passed to address verifier constructors.
Definition: gverifier.h:57