E-MailRelay
gnetworkverifier.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 gnetworkverifier.cpp
19///
20
21#include "gdef.h"
22#include "gnetworkverifier.h"
23#include "glocal.h"
24#include "gstr.h"
25#include "gstringfield.h"
26#include "glog.h"
27
29 const std::string & server ) :
30 m_es(es) ,
31 m_config(config) ,
32 m_location(server) ,
33 m_connection_timeout(config.timeout) ,
34 m_response_timeout(config.timeout)
35{
36 G_DEBUG( "GVerifiers::NetworkVerifier::ctor: " << server ) ;
37 m_client_ptr.eventSignal().connect( G::Slot::slot(*this,&GVerifiers::NetworkVerifier::clientEvent) ) ;
38}
39
41{
42 m_client_ptr.eventSignal().disconnect() ;
43 m_client_ptr.deletedSignal().disconnect() ;
44}
45
46void GVerifiers::NetworkVerifier::verify( const GSmtp::Verifier::Request & request )
47{
48 m_command = request.command ;
49 if( m_client_ptr.get() == nullptr )
50 {
51 unsigned int idle_timeout = 0U ;
52 m_client_ptr.reset( std::make_unique<GSmtp::RequestClient>(
53 m_es.eh(this) ,
54 "verify" , "" ,
55 m_location , m_connection_timeout , m_response_timeout ,
56 idle_timeout ) ) ;
57 }
58
59 G_LOG( "GVerifiers::NetworkVerifier: verification request: ["
60 << G::Str::printable(request.address) << "] (" << request.client_ip.displayString() << ")" ) ;
61
62 G::StringArray args ;
63 args.push_back( request.address ) ;
64 args.push_back( request.from_address ) ;
65 args.push_back( request.client_ip.displayString() ) ;
66 args.push_back( m_config.domain ) ;
67 args.push_back( G::Str::lower(request.auth_mechanism) ) ;
68 args.push_back( request.auth_extra ) ;
69
70 m_to_address = request.address ;
71 m_client_ptr->request( G::Str::join("|",args) ) ;
72}
73
74void GVerifiers::NetworkVerifier::onException( GNet::ExceptionSource * , std::exception & e , bool done )
75{
76 bool was_busy = m_client_ptr.get() && m_client_ptr->busy() ;
77 if( m_client_ptr.get() )
78 m_client_ptr->doOnDelete( e.what() , done ) ;
79 m_client_ptr.reset() ;
80
81 if( was_busy )
82 {
83 std::string to_address = m_to_address ;
84 m_to_address.erase() ;
85 auto status = GSmtp::VerifierStatus::invalid( to_address , true , "cannot verify" , "network verifier peer disconnected" ) ;
86 doneSignal().emit( m_command , status ) ;
87 }
88}
89
90void GVerifiers::NetworkVerifier::clientEvent( const std::string & s1 , const std::string & s2 , const std::string & )
91{
92 G_DEBUG( "GVerifiers::NetworkVerifier::clientEvent: [" << s1 << "] [" << s2 << "]" ) ;
93 if( s1 == "verify" )
94 {
95 G_LOG( "GVerifiers::NetworkVerifier: verification response: [" << G::Str::printable(s2) << "]" ) ;
96
97 // parse the output from the remote verifier using pipe-delimited
98 // fields based on the script-based verifier interface, but backwards
99 //
100 std::string_view s2_sv( s2 ) ;
101 G::StringFieldView f( s2_sv , '|' ) ;
102 std::size_t part_count = f.count() ;
103 std::string_view part_0 = f() ;
104 std::string_view part_1 = (++f)() ;
105 std::string_view part_2 = (++f)() ;
106
107 auto status = GSmtp::VerifierStatus::invalid( m_to_address ) ;
108 if( part_count && part_0 == "100"_sv )
109 {
110 status.is_valid = false ;
111 status.abort = true ;
112 }
113 else if( part_count >= 2U && part_0 == "1"_sv )
114 {
115 std::string address = G::sv_to_string( part_1 ) ;
116 status = GSmtp::VerifierStatus::remote( m_to_address , address ) ;
117 }
118 else if( part_count >= 3U && part_0 == "0"_sv )
119 {
120 std::string mbox = G::sv_to_string( part_1 ) ;
121 std::string full_name = G::sv_to_string( part_2 ) ;
122 status = GSmtp::VerifierStatus::local( m_to_address , full_name , mbox ) ;
123 }
124 else if( part_count >= 2U && ( part_0 == "2"_sv || part_0 == "3"_sv ) )
125 {
126 bool temporary = part_0 == "3"_sv ;
127 std::string response = G::sv_to_string( part_1 ) ;
128 std::string reason ;
129 if( part_count >= 3U ) reason = G::sv_to_string( part_2 ) ;
130 status = GSmtp::VerifierStatus::invalid( m_to_address ,
131 temporary , response , reason ) ;
132 }
133
134 doneSignal().emit( m_command , status ) ;
135 }
136}
137
138G::Slot::Signal<GSmtp::Verifier::Command,const GSmtp::VerifierStatus&> & GVerifiers::NetworkVerifier::doneSignal()
139{
140 return m_done_signal ;
141}
142
143void GVerifiers::NetworkVerifier::cancel()
144{
145 m_to_address.erase() ;
146 m_client_ptr.reset() ;
147}
148
G::Slot::Signal< const std::string &, const std::string &, const std::string & > & eventSignal() noexcept
A signal that is linked to the contained client's eventSignal().
Definition: gclientptr.cpp:32
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
Definition: geventstate.h:131
A mixin base class that identifies the source of an exception when delivered to GNet::ExceptionHandle...
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.
~NetworkVerifier() override
Destructor.
NetworkVerifier(GNet::EventState, const GSmtp::Verifier::Config &config, const std::string &server)
Constructor.
std::string displayString() const
Returns a printable string that represents the transport address.
Definition: gbasicaddress.h:57
static std::string lower(std::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:824
static std::string join(std::string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
Definition: gstr.cpp:1221
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
A zero-copy string field iterator where the field separators are short fixed strings.
Definition: gstringfield.h:53
Slot< Args... > slot(TSink &sink, void(TSink::*method)(Args...))
A factory function for Slot objects.
Definition: gslot.h:240
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30
Configuration passed to address verifier constructors.
Definition: gverifier.h:57
Verification request passed to various GSmtp::Verifier::verify() overrides.
Definition: gverifier.h:47