28std::string GSmtp::SpamClient::m_username ;
31 unsigned int connect_timeout ,
unsigned int response_timeout ) :
32 GNet::
Client(es,location,netConfig(connect_timeout,response_timeout)) ,
38 G_LOG(
"GSmtp::SpamClient::ctor: spam connection to [" << location <<
"]" ) ;
39 G_DEBUG(
"GSmtp::SpamClient::ctor: spam read/only=" << read_only ) ;
40 G_DEBUG(
"GSmtp::SpamClient::ctor: spam connection timeout " << connect_timeout ) ;
41 G_DEBUG(
"GSmtp::SpamClient::ctor: spam response timeout " << response_timeout ) ;
44GNet::Client::Config GSmtp::SpamClient::netConfig(
unsigned int connect_timeout ,
unsigned int response_timeout )
47 net_config.connection_timeout = connect_timeout ;
48 net_config.response_timeout = response_timeout ;
54 m_username = username ;
64 G_DEBUG(
"GSmtp::SpamClient::request: path=" << path ) ;
66 throw Error(
"protocol error" ) ;
69 m_timer.startTimer( 0U ) ;
72void GSmtp::SpamClient::onTimeout()
74 G_DEBUG(
"GSmtp::SpamClient::onTimeout: connected=" << connected() ) ;
79void GSmtp::SpamClient::onDelete(
const std::string & )
83void GSmtp::SpamClient::onSecure(
const std::string & ,
const std::string & ,
const std::string & )
87void GSmtp::SpamClient::onConnect()
93void GSmtp::SpamClient::start()
95 m_request.send( m_path , m_username ) ;
98void GSmtp::SpamClient::onSendComplete()
100 while( m_request.sendMore() )
106bool GSmtp::SpamClient::onReceive(
const char * line_data , std::size_t line_size , std::size_t , std::size_t ,
char )
108 m_response.add( m_path , std::string(line_data,line_size) ) ;
109 if( m_response.complete() )
110 eventSignal().emit(
"spam" , m_response.result() , std::string() ) ;
116GSmtp::SpamClient::Request::Request( Client & client ) :
122void GSmtp::SpamClient::Request::send(
const std::string & path ,
const std::string & username )
124 G_LOG(
"GSmtp::SpamClient::Request::send: spam request for [" << path <<
"]" ) ;
126 if( !m_stream.good() )
127 throw SpamClient::Error(
"cannot read content file" , path ) ;
130 G_DEBUG(
"GSmtp::SpamClient::Request::send: spam request file size: " << file_size ) ;
132 std::ostringstream ss ;
133 std::string eol =
"\r\n" ;
134 ss <<
"PROCESS SPAMC/1.4" << eol ;
135 if( !username.empty() )
136 ss <<
"User: " << username << eol ;
137 ss <<
"Content-length: " << file_size << eol ;
140 bool sent = m_client->send( ss.str() ) ;
145 G_DEBUG(
"GSmtp::SpamClient::Request::send: spam sent" ) ;
148bool GSmtp::SpamClient::Request::sendMore()
150 m_stream.read( &m_buffer[0] , m_buffer.size() ) ;
151 std::streamsize n = m_stream.gcount() ;
154 G_LOG(
"GSmtp::SpamClient::Request::sendMore: spam request done" ) ;
159 G_DEBUG(
"GSmtp::SpamClient::Request::sendMore: spam request sending " << n <<
" bytes" ) ;
160 return m_client->send( std::string(&m_buffer[0],
static_cast<std::size_t
>(n)) ) ;
166GSmtp::SpamClient::Response::Response(
bool read_only ) :
167 m_read_only(read_only) ,
169 m_content_length(0U) ,
174GSmtp::SpamClient::Response::~Response()
176 if( m_stream.is_open() )
183void GSmtp::SpamClient::Response::add(
const std::string & path ,
const std::string & line )
185 if( m_state == 0 && !ok(line) )
189 else if( m_state == 0 )
191 G_DEBUG(
"GSmtp::SpamClient::Request::sendMore: spam response" ) ;
192 m_path_final = path ;
193 m_path_tmp = path +
".spamd" ;
194 if( !m_read_only && !m_stream.is_open() )
197 if( !m_stream.good() )
198 throw SpamClient::Error(
"cannot write temporary content file" , m_path_tmp ) ;
200 m_content_length = m_size = 0U ;
205 G_LOG(
"GSmtp::SpamClient::Response::add: spam response line: ["
207 if( line.find(
"Spam:") == 0U )
211 else if( ( line.empty() || line ==
"\r" ) && m_content_length == 0U )
212 throw SpamClient::Error(
"invalid response headers" ) ;
213 else if( line.empty() || line ==
"\r" )
216 else if( m_state == 2 )
218 m_size += ( line.size() + 1U ) ;
220 if( m_stream.is_open() )
221 m_stream << line <<
"\n" ;
223 if( m_size >= m_content_length )
225 if( m_size != m_content_length )
226 G_WARNING(
"GSmtp::SpamClient::Response::add: incorrect content length in spam response" ) ;
227 G_LOG(
"GSmtp::SpamClient::add: spam response size: " << m_content_length ) ;
229 if( m_stream.is_open() )
232 if( m_stream.fail() )
233 throw SpamClient::Error(
"cannot write temporary content file" , m_path_tmp ) ;
244bool GSmtp::SpamClient::Response::complete()
const
246 return m_state == 3 ;
249bool GSmtp::SpamClient::Response::ok(
const std::string & line )
const
252 if( line.empty() )
return false ;
253 if( line.find(
"SPAMD/") != 0U )
return false ;
255 if( parts.size() < 2U )
return false ;
256 return parts.at(1U) ==
"0" ;
259std::string GSmtp::SpamClient::Response::result()
const
262 return std::string() ;
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
static LineBufferConfig newline()
Convenience factory function.
A class that represents the remote target for out-going client connections.
A class which acts as an SMTP client, extracting messages from a message store and forwarding them to...
A client class that interacts with a remote process using a protocol somewhat similar to the spamassa...
static void username(const std::string &)
Sets the username used in the network protocol.
SpamClient(GNet::ExceptionSink, const GNet::Location &host_and_service, bool read_only, unsigned int connect_timeout, unsigned int response_timeout)
Constructor.
void request(const std::string &file_path)
Starts sending a request that comprises a few http-like header lines followed by the contents of the ...
bool busy() const
Returns true after request() and before the subsequent event signal.
static void open(std::ofstream &, const Path &)
Calls open() on the given output file stream.
static std::string sizeString(const Path &file)
Returns the file's size in string format.
static bool rename(const Path &from, const Path &to, std::nothrow_t) noexcept
Renames the file.
static bool remove(const Path &path, std::nothrow_t) noexcept
Deletes the file or directory. Returns false on error.
static bool imatch(char, char)
Returns true if the two characters are the same, ignoring Latin-1 case.
static string_view ws()
Returns a string of standard whitespace characters.
static void splitIntoTokens(const std::string &in, StringArray &out, string_view ws, char esc='\0')
Splits the string into 'ws'-delimited tokens.
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 toUInt(const std::string &s)
Converts string 's' to an unsigned int.
static std::string trimmed(const std::string &s, string_view ws)
Returns a trim()med version of s.
std::vector< std::string > StringArray
A std::vector of std::strings.
A structure containing GNet::Client configuration parameters.