E-MailRelay
gfilterchain.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 gfilterchain.cpp
19///
20
21#include "gdef.h"
22#include "gfilterchain.h"
23#include "gslot.h"
24#include "gstringtoken.h"
25#include "gstr.h"
26#include "glog.h"
27#include <utility>
28#include <algorithm>
29
31 Filter::Type filter_type , const Filter::Config & filter_config ,
32 const GSmtp::FilterFactoryBase::Spec & spec ) :
33 m_filter_index(0U) ,
34 m_filter(nullptr) ,
35 m_running(false) ,
36 m_message_id(GStore::MessageId::none())
37{
39 G_ASSERT( spec.first == "chain" ) ;
40 for( G::StringToken t( spec.second , ","_sv ) ; t ; ++t )
41 {
42 std::string first = G::Str::head( t() , ":"_sv , false ) ;
43 std::string second = G::Str::tail( t() , ":"_sv ) ;
44 add( es , ff , filter_type , filter_config , Spec(first,second) ) ;
45 }
46
47 if( m_filters.empty() )
48 add( es , ff , filter_type , filter_config , {"exit","0"} ) ;
49}
50
51void GFilters::FilterChain::add( GNet::ExceptionSink es , GSmtp::FilterFactoryBase & ff ,
52 Filter::Type filter_type , const Filter::Config & filter_config ,
54{
55 m_filters.push_back( ff.newFilter( es , filter_type , filter_config , spec ) ) ;
56 m_filter_id.append(m_filter_id.empty()?0U:1U,',').append( m_filters.back()->id() ) ;
57}
58
60{
61 if( m_filter )
62 m_filter->doneSignal().disconnect() ;
63}
64
65std::string GFilters::FilterChain::id() const
66{
67 return m_filter_id ;
68}
69
70bool GFilters::FilterChain::quiet() const
71{
72 return std::all_of( m_filters.begin() , m_filters.end() ,
73 [](const std::unique_ptr<Filter> & ptr){ return ptr->quiet() ; } ) ;
74}
75
76G::Slot::Signal<int> & GFilters::FilterChain::doneSignal() noexcept
77{
78 return m_done_signal ;
79}
80
81void GFilters::FilterChain::start( const GStore::MessageId & id )
82{
83 if( m_running )
84 {
85 m_filter->cancel() ;
86 m_filter->doneSignal().disconnect() ;
87 }
88 m_running = true ;
89 m_message_id = id ;
90 m_filter_index = 0U ;
91 m_filter = m_filters.at(0U).get() ;
92 m_filter->doneSignal().connect( G::Slot::slot(*this,&FilterChain::onFilterDone) ) ;
93 m_filter->start( m_message_id ) ;
94}
95
96void GFilters::FilterChain::onFilterDone( int ok_abandon_fail )
97{
98 m_filter_index++ ;
99 m_filter->doneSignal().disconnect() ;
100 if( ok_abandon_fail == 0 ) // ok
101 {
102 G_ASSERT( m_filter_index <= m_filters.size() ) ;
103 if( m_filter_index >= m_filters.size() )
104 {
105 m_running = false ;
106 m_done_signal.emit( 0 ) ;
107 }
108 else
109 {
110 m_filter = m_filters.at(m_filter_index).get() ;
111 m_filter->doneSignal().connect( G::Slot::slot(*this,&FilterChain::onFilterDone) ) ;
112 m_filter->start( m_message_id ) ;
113 }
114 }
115 else // abandon/fail
116 {
117 m_running = false ;
118 m_done_signal.emit( ok_abandon_fail ) ;
119 }
120}
121
122void GFilters::FilterChain::cancel()
123{
124 if( m_running )
125 {
126 m_filter->cancel() ;
127 m_filter->doneSignal().disconnect() ;
128 }
129 m_running = false ;
130}
131
132GSmtp::Filter::Result GFilters::FilterChain::result() const
133{
134 return m_filter->result() ;
135}
136
137std::string GFilters::FilterChain::response() const
138{
139 return m_filter->response() ;
140}
141
142int GFilters::FilterChain::responseCode() const
143{
144 return m_filter->responseCode() ;
145}
146
147std::string GFilters::FilterChain::reason() const
148{
149 return m_filter->reason() ;
150}
151
152bool GFilters::FilterChain::special() const
153{
154 for( std::size_t i = 0U ; i < m_filter_index ; i++ ) // (new)
155 {
156 if( m_filters.at(i)->special() )
157 return true ;
158 }
159 return false ;
160}
161
FilterChain(GNet::ExceptionSink, GSmtp::FilterFactoryBase &, Filter::Type, const Filter::Config &, const GSmtp::FilterFactoryBase::Spec &spec)
Constructor.
~FilterChain() override
Destructor.
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
A factory interface for making GSmtp::Filter message processors.
virtual std::unique_ptr< Filter > newFilter(GNet::ExceptionSink, Filter::Type, const Filter::Config &, const Spec &spec)=0
Returns a Filter on the heap.
A somewhat opaque identifer for a GStore::MessageStore message id.
Definition: gmessagestore.h:43
static std::string tail(string_view in, std::size_t pos, string_view default_={})
Returns the last part of the string after the given position.
Definition: gstr.cpp:1325
static std::string head(string_view in, std::size_t pos, string_view default_={})
Returns the first part of the string up to just before the given position.
Definition: gstr.cpp:1297
A zero-copy string token iterator where the token separators are runs of whitespace characters,...
Definition: gstringtoken.h:54
Message store classes.
Definition: genvelope.cpp:30
Slot< Args... > slot(TSink &sink, void(TSink::*method)(Args...))
A factory function for Slot objects.
Definition: gslot.h:240
Filter specification tuple for GSmtp::FilterFactoryBase::newFilter().