33 bool server_side ,
const std::string & path ,
unsigned int timeout ) :
34 m_file_store(file_store) ,
35 m_server_side(server_side) ,
36 m_prefix(server_side?
"filter":
"client filter") ,
37 m_exit(0,server_side) ,
41 m_task(*this,es,
"<<filter exec error: __strerror__>>",
G::Root::nobody())
48bool GSmtp::ExecutableFilter::simple()
const
53std::string GSmtp::ExecutableFilter::id()
const
58bool GSmtp::ExecutableFilter::special()
const
60 return m_exit.special ;
63std::string GSmtp::ExecutableFilter::response()
const
65 G_ASSERT( m_exit.ok() || m_exit.abandon() || !m_response.empty() ) ;
66 if( m_exit.ok() || m_exit.abandon() )
67 return std::string() ;
72std::string GSmtp::ExecutableFilter::reason()
const
74 G_ASSERT( m_exit.ok() || m_exit.abandon() || !m_reason.empty() ) ;
75 if( m_exit.ok() || m_exit.abandon() )
76 return std::string() ;
81void GSmtp::ExecutableFilter::start(
const MessageId & message_id )
83 G::Path cpath = m_file_store.contentPath( message_id ) ;
84 G::Path epath = m_file_store.envelopePath( message_id , m_server_side ?
".new" :
".busy" ) ;
87 args.push_back( cpath.
str() ) ;
88 args.push_back( epath.
str() ) ;
91 G_LOG(
"GSmtp::ExecutableFilter::start: " << m_prefix <<
": running " << commandline.displayString() ) ;
92 m_task.start( commandline ) ;
95 m_timer.startTimer( m_timeout ) ;
98void GSmtp::ExecutableFilter::onTimeout()
100 G_WARNING(
"GSmtp::ExecutableFilter::onTimeout: " << m_prefix <<
" timed out after " << m_timeout <<
"s" ) ;
102 m_exit = Exit( 1 , m_server_side ) ;
103 G_ASSERT( m_exit.fail() && !special() && !abandoned() ) ;
104 m_response =
"error" ;
105 m_reason =
"timeout" ;
106 m_done_signal.emit(
static_cast<int>(m_exit.result) ) ;
109void GSmtp::ExecutableFilter::onTaskDone(
int exit_code ,
const std::string & output )
111 m_timer.cancelTimer() ;
114 std::tie(m_response,m_reason) = parseOutput( output ,
"rejected" ) ;
115 if( m_response.find(
"filter exec error") == 0U )
117 m_reason = m_response ;
118 m_response =
"rejected" ;
121 m_exit = Exit( exit_code , m_server_side ) ;
124 G_WARNING(
"GSmtp::ExecutableFilter::onTaskDone: " << m_prefix <<
" failed: "
125 <<
"exit code " << exit_code <<
": [" << m_response <<
"]" ) ;
129 m_done_signal.emit(
static_cast<int>(m_exit.result) ) ;
132std::pair<std::string,std::string> GSmtp::ExecutableFilter::parseOutput( std::string s ,
133 const std::string & default_ )
const
135 G_DEBUG(
"GSmtp::ExecutableFilter::parseOutput: in: \"" <<
G::Str::printable(s) <<
"\"" ) ;
137 const std::string start_1(
"<<") ;
138 const std::string end_1(
">>") ;
139 const std::string start_2(
"[[") ;
140 const std::string end_2(
"]]") ;
147 for(
auto p = lines.begin() ; p != lines.end() ; )
149 std::string line = *p ;
150 std::size_t pos_start = line.find(start_1) ;
151 std::size_t pos_end = line.find(end_1) ;
152 if( pos_start != 0U )
154 pos_start = line.find(start_2) ;
155 pos_end = line.find(end_2) ;
157 if( pos_start == 0U && pos_end != std::string::npos )
163 p = lines.erase( p ) ;
167 G_DEBUG(
"GSmtp::ExecutableFilter::parseOutput: out: [" <<
G::Str::join(
"|",lines) <<
"]" ) ;
169 std::string response = ( !lines.empty() && !lines.at(0U).empty() ) ? lines.at(0U) : default_ ;
170 std::string reason = ( lines.size() > 1U && !lines.at(1U).empty() ) ? lines.at(1U) : response ;
171 return std::make_pair( response , reason ) ;
176 return m_done_signal ;
179void GSmtp::ExecutableFilter::cancel()
181 m_timer.cancelTimer() ;
185bool GSmtp::ExecutableFilter::abandoned()
const
187 return m_exit.abandon() ;
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
A Filter class that runs an external helper program.
ExecutableFilter(GNet::ExceptionSink, FileStore &, bool server_side, const std::string &path, unsigned int timeout)
Constructor.
~ExecutableFilter() override
Destructor.
A concrete implementation of the MessageStore interface dealing in paired flat files.
A structure representing an external program, holding a path and a set of arguments.
A Path object represents a file system path.
std::string str() const
Returns the path string.
static std::string join(const std::string &sep, const StringArray &strings)
Concatenates an array of strings with separators.
static void splitIntoFields(const std::string &in, StringArray &out, string_view ws, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
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 ...
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurrences of sub-string 'from' with 'to'.
std::vector< std::string > StringArray
A std::vector of std::strings.