E-MailRelay
gnetworkverifier.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 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_location(server) ,
32 m_connection_timeout(config.timeout) ,
33 m_response_timeout(config.timeout) ,
34 m_command(Command::VRFY)
35{
36 G_DEBUG( "GVerifiers::NetworkVerifier::ctor: " << server ) ;
37 m_client_ptr.eventSignal().connect( G::Slot::slot(*this,&GVerifiers::NetworkVerifier::clientEvent) ) ;
38 m_client_ptr.deletedSignal().connect( G::Slot::slot(*this,&GVerifiers::NetworkVerifier::clientDeleted) ) ;
39}
40
42{
43 m_client_ptr.eventSignal().disconnect() ;
44 m_client_ptr.deletedSignal().disconnect() ;
45}
46
47void GVerifiers::NetworkVerifier::verify( Command command , const std::string & mail_to_address ,
48 const GSmtp::Verifier::Info & info )
49{
50 m_command = command ;
51 if( m_client_ptr.get() == nullptr )
52 {
53 unsigned int idle_timeout = 0U ;
54 m_client_ptr.reset( std::make_unique<GSmtp::RequestClient>(
55 GNet::ExceptionSink(m_client_ptr,m_es.esrc()),
56 "verify" , "" ,
57 m_location , m_connection_timeout , m_response_timeout ,
58 idle_timeout ) ) ;
59 }
60
61 G_LOG( "GVerifiers::NetworkVerifier: verification request: ["
62 << G::Str::printable(mail_to_address) << "] (" << info.client_ip.displayString() << ")" ) ;
63
64 G::StringArray args ;
65 args.push_back( mail_to_address ) ;
66 args.push_back( info.mail_from_parameter ) ;
67 args.push_back( info.client_ip.displayString() ) ;
68 args.push_back( info.domain ) ;
69 args.push_back( G::Str::lower(info.auth_mechanism) ) ;
70 args.push_back( info.auth_extra ) ;
71
72 m_to_address = mail_to_address ;
73 m_client_ptr->request( G::Str::join("|",args) ) ;
74}
75
76void GVerifiers::NetworkVerifier::clientDeleted( const std::string & reason )
77{
78 G_DEBUG( "GVerifiers::NetworkVerifier::clientDeleted: reason=[" << reason << "]" ) ;
79 if( !reason.empty() )
80 {
81 std::string to_address = m_to_address ;
82 m_to_address.erase() ;
83
84 auto status = GSmtp::VerifierStatus::invalid( to_address , true , "cannot verify" , reason ) ;
85 doneSignal().emit( m_command , status ) ;
86 }
87}
88
89void GVerifiers::NetworkVerifier::clientEvent( const std::string & s1 , const std::string & s2 , const std::string & )
90{
91 G_DEBUG( "GVerifiers::NetworkVerifier::clientEvent: [" << s1 << "] [" << s2 << "]" ) ;
92 if( s1 == "verify" )
93 {
94 G_LOG( "GVerifiers::NetworkVerifier: verification response: [" << G::Str::printable(s2) << "]" ) ;
95
96 // parse the output from the remote verifier using pipe-delimited
97 // fields based on the script-based verifier interface, but backwards
98 //
99 G::string_view s2_sv( s2 ) ;
100 G::StringFieldView f( s2_sv , '|' ) ;
101 std::size_t part_count = f.count() ;
102 G::string_view part_0 = f() ;
103 G::string_view part_1 = (++f)() ;
104 G::string_view part_2 = (++f)() ;
105
106 auto status = GSmtp::VerifierStatus::invalid( m_to_address ) ;
107 if( part_count && part_0 == "100"_sv )
108 {
109 status.is_valid = false ;
110 status.abort = true ;
111 }
112 else if( part_count >= 2U && part_0 == "1"_sv )
113 {
114 std::string address = G::sv_to_string( part_1 ) ;
115 status = GSmtp::VerifierStatus::remote( m_to_address , address ) ;
116 }
117 else if( part_count >= 3U && part_0 == "0"_sv )
118 {
119 std::string mbox = G::sv_to_string( part_1 ) ;
120 std::string full_name = G::sv_to_string( part_2 ) ;
121 status = GSmtp::VerifierStatus::local( m_to_address , full_name , mbox ) ;
122 }
123 else if( part_count >= 2U && ( part_0 == "2"_sv || part_0 == "3"_sv ) )
124 {
125 bool temporary = part_0 == "3"_sv ;
126 std::string response = G::sv_to_string( part_1 ) ;
127 std::string reason ;
128 if( part_count >= 3U ) reason = G::sv_to_string( part_2 ) ;
129 status = GSmtp::VerifierStatus::invalid( m_to_address ,
130 temporary , response , reason ) ;
131 }
132
133 doneSignal().emit( m_command , status ) ;
134 }
135}
136
137G::Slot::Signal<GSmtp::Verifier::Command,const GSmtp::VerifierStatus&> & GVerifiers::NetworkVerifier::doneSignal()
138{
139 return m_done_signal ;
140}
141
142void GVerifiers::NetworkVerifier::cancel()
143{
144 m_to_address.erase() ;
145 m_client_ptr.reset() ;
146}
147
G::Slot::Signal< const std::string & > & deletedSignal() noexcept
A signal that is triggered after deleteSignal() once the client has been deleted and the ClientPtr is...
Definition: gclientptr.cpp:27
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 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.
NetworkVerifier(GNet::ExceptionSink, const GSmtp::Verifier::Config &config, const std::string &server)
Constructor.
~NetworkVerifier() override
Destructor.
static std::string join(string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
Definition: gstr.cpp:1224
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 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
A zero-copy string field iterator where the field separators are short fixed strings.
Definition: gstringfield.h:53
A class like c++17's std::string_view.
Definition: gstringview.h:51
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:55
Extra information passed to GSmtp::Verifier::verify().
Definition: gverifier.h:47