Compare commits

...

5 Commits

@ -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

@ -2,6 +2,19 @@
CXX=c++ -Wall -O0 -std=c++11 -g -I../include/ -I/usr/local/include -L/usr/local/lib
###############
#
# Dear maintainer! Please set up this definition for your system:
# platform dependend libraries:
# Linux:
LIBS=-lldns -lpthread -lboost_system
#
############ end of platform-dependend config, I hope so ########
all: libAccountSettings.a test
test: accountSettings_test
@ -16,10 +29,12 @@ xml2cxx: xml2cxx.o tinyxml2.o account_settings_internal.o stringpool.o
${CXX} -o $@ $^
accountSettings_test: accountSettings_test.o libAccountSettings.a
${CXX} -o $@ $^ -lldns
${CXX} -o $@ $^ ${LIBS}
libAccountSettings.a: account_settings_internal.o implementation.o \
isp_db.o \
boost_asio.o \
from_heuristics.o \
from_srv.o
ar rcs $@ $^

@ -0,0 +1,5 @@
#include "boost_asio.hh"
// compile the whole boost.asio stuff here once, instead of in every header:
#include <boost/asio/impl/src.hpp>

@ -0,0 +1,9 @@
#ifndef LAS_BOOST_ASIO_HH
#define LAS_BOOST_ASIO_HH
// for separate compilation this macro must be defined before any boost.asio header is included
#define BOOST_ASIO_SEPARATE_COMPILATION
#include <boost/asio.hpp>
#endif

@ -0,0 +1,134 @@
#include "from_heuristics.hh"
#include "account_settings_internal.hh"
#include <ldns/ldns.h>
#include <stdexcept>
#include <memory>
#include "boost_asio.hh"
class protocol_error : public std::runtime_error
{
public:
protocol_error() : std::runtime_error("Protocol error!")
{}
};
namespace
{
namespace bio = boost::asio;
using bio::ip::tcp;
// TODO: implement!
class Protocol
{
public:
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;
};
class Imap : public Protocol
{
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 */ }
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
AccountSettings* get_settings_from_heuristics(AccountSettings* as, const std::string& accountName, const std::string& domain, const std::string& provider)
{
if(as==nullptr)
{
throw std::runtime_error("get_settings_from_heuristics shall not be called with NULL pointer!");
}
// fprintf(stderr, "== IMAP ==\n");
try{
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
}
// fprintf(stderr, "== SMTP ==\n");
try{
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
}
return as;
}

@ -0,0 +1,8 @@
#ifndef ACCOUNT_SETTINGS_FROM_HEURISTICS_HH
#define ACCOUNT_SETTINGS_FROM_HEURISTICS_HH
#include "account_settings_internal.hh"
AccountSettings* get_settings_from_heuristics(AccountSettings* as, const std::string& accountName, const std::string& domain, const std::string& provider);
#endif // ACCOUNT_SETTINGS_FROM_HEURISTICS_HH

@ -4,6 +4,7 @@
#include <stdexcept>
#include "from_srv.hh"
#include "from_heuristics.hh"
namespace
{
@ -97,6 +98,11 @@ const AccountSettings* get_account_settings(const char* accountName, const char*
{
get_settings_from_srv(dyn_as, accountName, domain, (provider?provider:"") );
}
if( dyn_as->status != AS_OK && (flags & AS_FLAG_USE_HEURISTICS) )
{
get_settings_from_heuristics(dyn_as, accountName, domain, provider );
}
return dyn_as;
}

Loading…
Cancel
Save