E-MailRelay
gfilterchain.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 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_message_id(GStore::MessageId::none())
34{
36 G_ASSERT( spec.first == "chain" ) ;
37 for( G::StringToken t( spec.second , "," ) ; t ; ++t )
38 {
39 std::string first = G::Str::head( t() , ":" , false ) ;
40 std::string second = G::Str::tail( t() , ":" ) ;
41 add( es , ff , filter_type , filter_config , Spec(first,second) ) ;
42 }
43
44 if( m_filters.empty() )
45 add( es , ff , filter_type , filter_config , {"exit","0"} ) ;
46}
47
48void GFilters::FilterChain::add( GNet::EventState es , GSmtp::FilterFactoryBase & ff ,
49 Filter::Type filter_type , const Filter::Config & filter_config ,
51{
52 m_filters.push_back( ff.newFilter( es , filter_type , filter_config , spec ) ) ;
53 m_filter_id.append(m_filter_id.empty()?0U:1U,',').append( m_filters.back()->id() ) ;
54}
55
57{
58 if( m_filter )
59 m_filter->doneSignal().disconnect() ;
60}
61
62std::string GFilters::FilterChain::id() const
63{
64 return m_filter_id ;
65}
66
67bool GFilters::FilterChain::quiet() const
68{
69 return std::all_of( m_filters.begin() , m_filters.end() ,
70 [](const std::unique_ptr<Filter> & ptr){ return ptr->quiet() ; } ) ;
71}
72
73G::Slot::Signal<int> & GFilters::FilterChain::doneSignal() noexcept
74{
75 return m_done_signal ;
76}
77
78void GFilters::FilterChain::start( const GStore::MessageId & id )
79{
80 if( m_running )
81 {
82 m_filter->cancel() ;
83 m_filter->doneSignal().disconnect() ;
84 }
85 m_running = true ;
86 m_message_id = id ;
87 m_filter_index = 0U ;
88 m_filter = m_filters.at(0U).get() ;
89 m_filter->doneSignal().connect( G::Slot::slot(*this,&FilterChain::onFilterDone) ) ;
90 m_filter->start( m_message_id ) ;
91}
92
93void GFilters::FilterChain::onFilterDone( int ok_abandon_fail )
94{
95 m_filter_index++ ;
96 m_filter->doneSignal().disconnect() ;
97 if( ok_abandon_fail == 0 ) // ok
98 {
99 G_ASSERT( m_filter_index <= m_filters.size() ) ;
100 if( m_filter_index >= m_filters.size() )
101 {
102 m_running = false ;
103 m_done_signal.emit( 0 ) ;
104 }
105 else
106 {
107 m_filter = m_filters.at(m_filter_index).get() ;
108 m_filter->doneSignal().connect( G::Slot::slot(*this,&FilterChain::onFilterDone) ) ;
109 m_filter->start( m_message_id ) ;
110 }
111 }
112 else // abandon/fail
113 {
114 m_running = false ;
115 m_done_signal.emit( ok_abandon_fail ) ;
116 }
117}
118
119void GFilters::FilterChain::cancel()
120{
121 if( m_running )
122 {
123 m_filter->cancel() ;
124 m_filter->doneSignal().disconnect() ;
125 }
126 m_running = false ;
127}
128
129GSmtp::Filter::Result GFilters::FilterChain::result() const
130{
131 return m_filter->result() ;
132}
133
134std::string GFilters::FilterChain::response() const
135{
136 return m_filter->response() ;
137}
138
139int GFilters::FilterChain::responseCode() const
140{
141 return m_filter->responseCode() ;
142}
143
144std::string GFilters::FilterChain::reason() const
145{
146 return m_filter->reason() ;
147}
148
149bool GFilters::FilterChain::special() const
150{
151 for( std::size_t i = 0U ; i < m_filter_index ; i++ ) // (new)
152 {
153 if( m_filters.at(i)->special() )
154 return true ;
155 }
156 return false ;
157}
158
FilterChain(GNet::EventState, GSmtp::FilterFactoryBase &, Filter::Type, const Filter::Config &, const GSmtp::FilterFactoryBase::Spec &spec)
Constructor.
~FilterChain() override
Destructor.
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
Definition: geventstate.h:131
A factory interface for making GSmtp::Filter message processors.
virtual std::unique_ptr< Filter > newFilter(GNet::EventState, 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(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the last part of the string after the given position.
Definition: gstr.cpp:1322
static std::string head(std::string_view in, std::size_t pos, std::string_view default_={})
Returns the first part of the string up to just before the given position.
Definition: gstr.cpp:1294
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().