E-MailRelay
gexecutableverifier.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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 gexecutableverifier.cpp
19///
20
21#include "gdef.h"
22#include "gexecutableverifier.h"
23#include "gexecutablecommand.h"
24#include "gprocess.h"
25#include "gnewprocess.h"
26#include "gfile.h"
27#include "groot.h"
28#include "gstr.h"
29#include "glocal.h"
30#include "glog.h"
31
33 m_timer(*this,&ExecutableVerifier::onTimeout,es) ,
34 m_command(GSmtp::Verifier::Command::VRFY) ,
35 m_path(path) ,
36 m_timeout(timeout) ,
37 m_task(*this,es,"<<verifier exec error: __strerror__>>",G::Root::nobody())
38{
39}
40
41void GVerifiers::ExecutableVerifier::verify( GSmtp::Verifier::Command command , const std::string & to_address ,
42 const GSmtp::Verifier::Info & info )
43{
44 m_command = command ;
45 G_DEBUG( "GVerifiers::ExecutableVerifier::verify: to=[" << to_address << "]" ) ;
46
47 G::ExecutableCommand commandline( m_path.str() , G::StringArray() ) ;
48 commandline.add( to_address ) ;
49 commandline.add( info.mail_from_parameter ) ;
50 commandline.add( info.client_ip.displayString() ) ;
51 commandline.add( info.domain ) ;
52 commandline.add( G::Str::lower(info.auth_mechanism) ) ;
53 commandline.add( info.auth_extra ) ;
54
55 G_LOG( "GVerifiers::ExecutableVerifier: address verifier: executing " << commandline.displayString() ) ;
56 m_to_address = to_address ;
57 m_task.start( commandline ) ;
58 if( m_timeout )
59 m_timer.startTimer( m_timeout ) ;
60}
61
62void GVerifiers::ExecutableVerifier::onTimeout()
63{
64 m_task.stop() ;
65
66 auto result = GSmtp::VerifierStatus::invalid( m_to_address , true , "timeout" , "timeout" ) ;
67
68 m_done_signal.emit( m_command , result ) ;
69}
70
71void GVerifiers::ExecutableVerifier::onTaskDone( int exit_code , const std::string & result_in )
72{
73 m_timer.cancelTimer() ;
74 auto status = GSmtp::VerifierStatus::invalid( m_to_address ) ;
75 if( exit_code == 127 && G::Str::headMatch(result_in,"<<verifier exec error") )
76 {
77 G_WARNING( "GVerifiers::ExecutableVerifier: address verifier: exec error" ) ;
78 status = GSmtp::VerifierStatus::invalid( m_to_address , false , "error" , "exec error" ) ;
79 }
80 else
81 {
82 std::string result( result_in ) ;
83 G::Str::trimRight( result , {" \n\t",3U} ) ;
84 G::Str::replaceAll( result , "\r\n" , "\n" ) ;
85 G::Str::replaceAll( result , "\r" , "" ) ;
86
87 G::StringArray result_parts ;
88 result_parts.reserve( 2U ) ;
89 G::Str::splitIntoFields( result , result_parts , '\n' ) ;
90 std::size_t parts = result_parts.size() ;
91 result_parts.resize( 2U ) ;
92
93 G_LOG( "GVerifiers::ExecutableVerifier: address verifier: exit code " << exit_code << ": "
94 << "[" << G::Str::printable(result_parts[0]) << "] [" << G::Str::printable(result_parts[1]) << "]" ) ;
95
96 if( exit_code == 0 && parts >= 2 )
97 {
98 std::string full_name = G::Str::printable( result_parts.at(0U) ) ;
99 std::string mbox = G::Str::printable( result_parts.at(1U) ) ;
100 status = GSmtp::VerifierStatus::local( m_to_address , full_name , mbox ) ;
101 }
102 else if( exit_code == 1 && parts >= 2 )
103 {
104 std::string address = G::Str::printable( result_parts.at(1U) ) ;
105 status = GSmtp::VerifierStatus::remote( m_to_address , address ) ;
106 }
107 else if( exit_code == 100 )
108 {
109 status.abort = true ;
110 }
111 else
112 {
113 bool temporary = exit_code == 3 ;
114
115 std::string response = parts > 0U ?
116 G::Str::printable(result_parts.at(0U)) :
117 std::string("mailbox unavailable") ;
118
119 std::string reason = parts > 1U ?
120 G::Str::printable(result_parts.at(1U)) :
121 ( "exit code " + G::Str::fromInt(exit_code) ) ;
122
123 status = GSmtp::VerifierStatus::invalid( m_to_address ,
124 temporary , response , reason ) ;
125 }
126 }
127 doneSignal().emit( m_command , status ) ;
128}
129
130G::Slot::Signal<GSmtp::Verifier::Command,const GSmtp::VerifierStatus&> & GVerifiers::ExecutableVerifier::doneSignal()
131{
132 return m_done_signal ;
133}
134
135void GVerifiers::ExecutableVerifier::cancel()
136{
137}
138
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
static VerifierStatus local(const std::string &recipient, const std::string &full_name, const std::string &mbox)
Constructor for a valid local mailbox.
static VerifierStatus invalid(const std::string &recipient, bool temporary=false, const std::string &response={}, const std::string &reason={})
Factory function for an invalid address.
static VerifierStatus remote(const std::string &recipient, const std::string &address={})
Constructor for a valid remote mailbox.
A Verifier that runs an executable.
ExecutableVerifier(GNet::ExceptionSink, const G::Path &, unsigned int timeout)
Constructor.
A structure representing an external program, holding a path and a set of arguments.
A Path object represents a file system path.
Definition: gpath.h:73
static unsigned int replaceAll(std::string &s, string_view from, string_view to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
Definition: gstr.cpp:247
static std::string lower(string_view)
Returns a copy of 's' in which all seven-bit upper-case characters have been replaced by lower-case c...
Definition: gstr.cpp:827
static std::string & trimRight(std::string &s, string_view ws, std::size_t limit=0U)
Trims the rhs of s, taking off up to 'limit' of the 'ws' characters.
Definition: gstr.cpp:313
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:916
static void splitIntoFields(string_view in, StringArray &out, char sep, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
Definition: gstr.cpp:1194
static bool headMatch(const std::string &in, string_view head) noexcept
Returns true if the string has the given start (or head is empty).
Definition: gstr.cpp:1362
SMTP classes.
Definition: gadminserver.h:42
Low-level classes.
Definition: garg.h:30
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30
STL namespace.
Extra information passed to GSmtp::Verifier::verify().
Definition: gverifier.h:47