start with the generic protocol state machine

LAS-10
Roker 2017-10-20 16:10:52 +02:00
parent ddb405d480
commit afbcf7421a
2 changed files with 81 additions and 6 deletions

View File

@ -43,6 +43,8 @@ typedef enum _AS_FLAGS
//! Combination of protocol, socket type & authentication type
typedef enum _AS_ACCESS
{
AS_ACCESS_UNKNOWN = 0, ///< unknown / undetermined authentication type. Used as error value.
/// protocols
AS_PROTO_POP3 = 0x00011, ///< incoming
AS_PROTO_IMAP = 0x00012, ///< incoming

View File

@ -14,21 +14,92 @@ public:
{}
};
namespace
{
namespace bio = boost::asio;
using bio::ip::tcp;
// TODO: implement!
class Protocol
{
public:
Protocol() = default;
Protocol() {}
virtual ~Protocol() {}
/// (re)initialize the protocol and thet the AS_Server to initial state
virtual void init(AS_Server& ass) = 0;
/// say something to the server. if nothing to say in this state, it returns empty string
virtual std::string put() = 0;
/// return true if guessing was successful
virtual bool get(const std::string& s) = 0;
};
AS_Server probe_server(const std::string& domain, std::initializer_list<std::string> names, Protocol p=Protocol() )
class Imap : public Protocol
{
AS_Server ass { "", -1, AS_ACCESS(-1), "" };
public:
Imap() {}
virtual ~Imap() {}
virtual void init(AS_Server& ass) override { /* TODO: implement! */ }
virtual std::string put() override { return ""; }
virtual bool get(const std::string& s) override { return s.empty(); }
};
AS_Server pingpong(const std::string& server, int port, Protocol& p)
{
AS_Server ass{ "", -1, AS_ACCESS_UNKNOWN, "" };
try{
std::vector<char> buffer(2048);
bio::io_service ios;
tcp::resolver res(ios);
tcp::resolver::query query( server, std::to_string(port) );
for(auto iter = res.resolve(query); iter != tcp::resolver::iterator(); ++iter)
{
p.init(ass);
tcp::socket s(ios);
bio::connect(s, iter);
boost::system::error_code err;
while(ass.access == AS_ACCESS_UNKNOWN)
{
const std::string output = p.put();
if(!output.empty())
{
bio::write(s, bio::buffer(output), err);
}
const size_t length = s.read_some( boost::asio::buffer(buffer), err);
if(!err || err == bio::error::eof)
{
if( p.get( std::string( buffer.data(), buffer.data()+length) ) )
{
return ass;
}
}
}
}
}catch(std::runtime_error&) { /* just return what we have so far */ }
throw protocol_error{};
return ass;
}
AS_Server probe_server(const std::string& domain, std::initializer_list<std::string> names, std::initializer_list<int> ports, Protocol& p )
{
for(auto port : ports)
for(auto name : names)
{
const std::string server = domain + "." + name;
const AS_Server ass = pingpong(server, port, p);
if(ass.access != AS_ACCESS_UNKNOWN)
return ass;
}
return AS_Server{ "", -1, AS_ACCESS_UNKNOWN, "" };
}
} //end of anonymous namespace
@ -43,7 +114,8 @@ AccountSettings* get_settings_from_heuristics(AccountSettings* as, const std::st
// fprintf(stderr, "== IMAP ==\n");
try{
as->incoming = probe_server( domain, {"imap", "mail", "imaps", "imapmail", "imap-mail", "mx", "", "mbox",} );
Imap imap_protocol;
as->incoming = probe_server( domain, {"imap", "mail", "imaps", "imapmail", "imap-mail", "mx", "", "mbox"}, {143, 993}, imap_protocol );
}catch( const protocol_error& )
{
// ignore protocol errors
@ -51,7 +123,8 @@ AccountSettings* get_settings_from_heuristics(AccountSettings* as, const std::st
// fprintf(stderr, "== SMTP ==\n");
try{
as->outgoing = probe_server( domain, {"smtp", "mail", "smtps", "smtpmail", "smtp-mail", "mx", "", "smtpauth",} );
Imap smtp_protocol;
as->outgoing = probe_server( domain, {"smtp", "mail", "smtps", "smtpmail", "smtp-mail", "mx", "", "smtpauth",}, {25, 587, 465}, smtp_protocol );
}catch( const protocol_error& )
{
// ignore protocol errors