Compare commits

..

5 Commits

Author SHA1 Message Date
Roker 5a49f837a1 merge "default" into my branch 2017-12-12 15:55:37 +01:00
Roker afbcf7421a start with the generic protocol state machine 2017-10-20 16:10:52 +02:00
Roker ddb405d480 add boost.asio as dependency 2017-10-13 16:36:54 +02:00
Roker 85565bbd79 add from_heuristics.?? as a stub 2017-10-13 16:21:37 +02:00
Roker c2c1e0d67c start branch LAS-10 2017-10-13 15:48:19 +02:00
33 changed files with 2091 additions and 3358 deletions

70
.gitignore vendored
View File

@ -1,70 +0,0 @@
# Xcode
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
## Swift Package Manager
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
.build/
## Xcode Patch ###
**/xcshareddata/WorkspaceSettings.xcsettings
# macOS
## General
.DS_Store
.AppleDouble
.LSOverride
## Icon must end with two \r
Icon
## Thumbnails
._*
## Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
## Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

6
.hgignore Normal file
View File

@ -0,0 +1,6 @@
regexp
\.DS_Store
xcuserdata/.*
\.orig$
\.git/
\.gitkeep

View File

@ -1,23 +0,0 @@
<clientConfig version="1.1">
<emailProvider id="e-foundation">
<domain>e.email</domain>
<domain>ecloud.global</domain>
<displayName>e Foundation</displayName>
<displayShortName>e Foundation</displayShortName>
<incomingServer type="imap">
<hostname>mail.ecloud.global</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>mail.ecloud.global</hostname>
<port>587</port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</outgoingServer>
</emailProvider>
</clientConfig>

View File

@ -1,61 +0,0 @@
<clientConfig version="1.1">
<emailProvider id="M-net">
<domain>16000-kbits.de</domain>
<domain>7fun.de</domain>
<domain>a-city.de</domain>
<domain>alpenbazi.de</domain>
<domain>amberg-mail.de</domain>
<domain>augustakom.net</domain>
<domain>bayern-mail.de</domain>
<domain>club-goes-uefacup.de</domain>
<domain>dachau-mail.de</domain>
<domain>erding-mail.de</domain>
<domain>es-laendle.de</domain>
<domain>familien-postfach.de</domain>
<domain>fcn-cluberer.de</domain>
<domain>frankenbeutel-mail.de</domain>
<domain>franken-ist-cool.de</domain>
<domain>franken-online.de</domain>
<domain>ich-liebe-franken.de</domain>
<domain>ich-mag-net.de</domain>
<domain>ingolstadt-mail.de</domain>
<domain>loewen-mail.de</domain>
<domain>maxi-allgaeu.de</domain>
<domain>maxi-bayern.de</domain>
<domain>maxi-dsl.de</domain>
<domain>maxi-schwaben.de</domain>
<domain>mnet-mail.de</domain>
<domain>mnet-online.de</domain>
<domain>muenchen-ist-toll.de</domain>
<domain>muenchen-mail.de</domain>
<domain>muenchen-surf.de</domain>
<domain>myway.de</domain>
<domain>nefkom.info</domain>
<domain>nefkom.net</domain>
<domain>neumarkt-mail.de</domain>
<domain>post-ist-da.de</domain>
<domain>regensburg-mail.de</domain>
<domain>rotgruenweiss.de</domain>
<domain>starnberg-mail.de</domain>
<domain>unser-postfach.de</domain>
<domain>weissblautsv.de</domain>
<domain>wir-datschiburger.de</domain>
<displayName>M-net Telekommunikations GmbH</displayName>
<displayShortName>M-net</displayShortName>
<incomingServer type="imap">
<hostname>imap.mnet-online.de</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>mail.mnet-online.de</hostname>
<port>587</port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</outgoingServer>
</emailProvider>
</clientConfig>

View File

@ -1,22 +0,0 @@
<clientConfig version="1.1">
<emailProvider id="Mailfence">
<domain>mailfence.com</domain>
<displayName>Mailfence</displayName>
<displayShortName>Mailfence</displayShortName>
<incomingServer type="imap">
<hostname>imap.mailfence.com</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>smtp.mailfence.com</hostname>
<port>465</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</outgoingServer>
</emailProvider>
</clientConfig>

View File

@ -1,21 +0,0 @@
<clientConfig version="1.1">
<emailProvider id="pep-security.net">
<domain>pep-security.net</domain>
<displayName>pEp Security S.A.</displayName>
<displayShortName>pEp Security S.A.</displayShortName>
<incomingServer type="imap">
<hostname>mail.pep-security.net</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>mail.pep-security.net</hostname>
<port>587</port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</outgoingServer>
</emailProvider>
</clientConfig>

View File

@ -1,21 +0,0 @@
<clientConfig version="1.1">
<emailProvider id="pep.digital">
<domain>pep.digital</domain>
<displayName>p≡p Security S.A.</displayName>
<displayShortName>p≡p Security S.A.</displayShortName>
<incomingServer type="imap">
<hostname>mail.peptest.ch</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>mail.peptest.ch</hostname>
<port>465</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</outgoingServer>
</emailProvider>
</clientConfig>

View File

@ -1,21 +0,0 @@
<clientConfig version="1.1">
<emailProvider id="pep.security">
<domain>pep.security</domain>
<displayName>p≡p Security S.A.</displayName>
<displayShortName>p≡p Security S.A.</displayShortName>
<incomingServer type="imap">
<hostname>mail.pep.security</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</incomingServer>
<outgoingServer type="smtp">
<hostname>mail.pep.security</hostname>
<port>465</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
<authentication>password-cleartext</authentication>
</outgoingServer>
</emailProvider>
</clientConfig>

View File

@ -52,15 +52,6 @@ const struct AccountSettings* get_account_settings(const char* accountName, cons
AS_STATUS AS_get_status(const struct AccountSettings* account_settings);
/** get the privder id string of the account_settings
*
* @param account_settings the account settings your want to get provider id
* @return the provider id, if any. Might be NULL or empty string.
The pointer points to internal r/o data in accountSettings, do not delete it!
*/
const char* AS_get_provider_id(const struct AccountSettings* account_settings);
/** get the server settings for "incoming" messages (e.g. IMAP or POP3)
* @param accountSettings guess what
* @return the server for incoming messages associated with the accountSettings.

View File

@ -31,27 +31,21 @@ typedef enum _AS_STATUS
typedef enum _AS_FLAGS
{
AS_FLAG_USE_LOCAL_ISP_DB = 0x0010, ///< use local ISP database
// FIXME: local-only heuristics? Is that possible/sensible?
// AS_FLAG_USE_HEURISTICS = 0x0020, ///< use heuristics from account's domain name
AS_FLAG_USE_ANY_LOCAL = 0x000F, ///< use all local (without communication to 3rd parties) methods in ascending order
AS_FLAG_USE_MOZ_AUTOCONFIG = 0x0100, ///< fetch account config via Mozilla's "autoconfig" method
AS_FLAG_USE_MS_AUTODISCOVER = 0x0200, ///< fetch account config via Microsoft's "autodiscover" method
AS_FLAG_USE_DNS_SRV = 0x0400, ///< use DNS SRV records for the mail domain
AS_FLAG_USE_ONLINE_ISP_DB = 0x0800, ///< ask https://live.mozillamessaging.com/autoconfig/v1.1/$DOMAINNAME
AS_FLAG_USE_ANY_ONLINE = 0x0F00, ///< try all (almost) reliable online configuration methods in ascending order
AS_FLAG_USE_GUESSING = 0x1000, ///< guess server names and try to detect its login methods. MAY BE DANGEROUS!
AS_FLAG_USE_ANY = 0xFFFF ///< try first local, than network methods
AS_FLAG_USE_HEURISTICS = 0x0020, ///< use heuristics from account's domain name
AS_FLAG_USE_ANY_LOCAL = 0x00FF, ///< use all local (without communication to 3rd parties) methods in ascending order
AS_FLAG_USE_DNS_AUTOCONFIG = 0x0100, ///< fetch account config from "autodiscover/autoconfig" servers
AS_FLAG_USE_DNS_SRV = 0x0110, ///< use DNS SRV records for the mail domain
AS_FLAG_USE_ONLINE_ISP_DB = 0x0800, ///< ask https://live.mozillamessaging.com/autoconfig/v1.1/$DOMAINNAME
AS_FLAG_USE_ANY = 0xFFFF ///< try first local, than network methods
} 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_EXCHANGE = 0x00008, ///< both (?) - selected with very low precedence
AS_PROTO_POP3 = 0x00011, ///< incoming
AS_PROTO_IMAP = 0x00012, ///< incoming
AS_PROTO_SMTP = 0x00021, ///< outgoing

View File

@ -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
@ -10,18 +23,20 @@ test: accountSettings_test
isp_db: isp_db.cc
isp_db.cc: xml2cxx
./xml2cxx ../../autoconfig/* ../example/* > $@
./xml2cxx ../../autoconfig/* > $@
xml2cxx: xml2cxx.o tinyxml2.o account_settings_internal.o stringpool.o
${CXX} -o $@ $^
accountSettings_test: accountSettings_test.o libAccountSettings.a
${CXX} -o $@ $^ -lldns -lcrypto -lssl
${CXX} -o $@ $^ ${LIBS}
libAccountSettings.a: account_settings_internal.o implementation.o \
isp_db.o http_client.o \
isp_db.o \
boost_asio.o \
from_heuristics.o \
from_srv.o
${AR} rcs $@ $^
ar rcs $@ $^
%.o : %.cc %.hh
${CXX} -o $@ -c $<

View File

@ -1,9 +1,7 @@
// unit test program for libAccountSettings
#include "../include/account_settings_c.h"
#include "account_settings_internal.hh"
#include "from_srv.hh"
#include "http_client.hh"
#include <string>
#include <vector>
#include <iostream>
@ -21,26 +19,25 @@ struct TestHost
{
std::string name;
int port;
unsigned access;
};
// stored in ISP DB
const std::vector< KeyValue< TestHost> > incomingServer =
{
{ "lib_as@peptest.ch", {"peptest.ch" , 993, AS_PROTO_IMAP | AS_SOCK_SSL | AS_AUTH_PW_CLEARTEXT} },
{ "example@gmx.de" , {"imap.gmx.net" , 993, AS_PROTO_IMAP | AS_SOCK_SSL | AS_AUTH_PW_CLEARTEXT} },
{ "example@yandex.ua", {"imap.yandex.com", 993, AS_PROTO_IMAP | AS_SOCK_SSL | AS_AUTH_PW_CLEARTEXT} },
{ "example@yahoo.com", {"imap.mail.yahoo.com", 993, AS_PROTO_IMAP | AS_SOCK_SSL | AS_AUTH_OAUTH2} },
{ "lib_as@peptest.ch", {"peptest.ch", 993} },
{ "example@gmx.de" , {"imap.gmx.net", 993} },
{ "example@yandex.ua", {"imap.yandex.com", 993} },
};
// stored in ISP DB
const std::vector< KeyValue< TestHost> > outgoingServer =
{
{ "lib_as@peptest.ch", {"peptest.ch" , 587, AS_PROTO_SMTP | AS_SOCK_STARTTLS | AS_AUTH_PW_CLEARTEXT} },
{ "example@gmx.de" , {"mail.gmx.net" , 465, AS_PROTO_SMTP | AS_SOCK_SSL | AS_AUTH_PW_CLEARTEXT} },
{ "example@yandex.ua", {"smtp.yandex.com", 465, AS_PROTO_SMTP | AS_SOCK_SSL | AS_AUTH_PW_CLEARTEXT} },
{ "lib_as@peptest.ch", {"peptest.ch", 587} },
{ "example@gmx.de" , {"mail.gmx.net", 465} },
{ "example@yandex.ua", {"smtp.yandex.com", 465} },
};
//
template<class TestData, class Function >
bool testServers( const TestData& testData, Function testFunc )
@ -69,14 +66,6 @@ bool testServers( const TestData& testData, Function testFunc )
okay = false;
}
const AS_ACCESS acc = AS_get_access_method(srv);
if( acc != AS_ACCESS(t.value.access) )
{
std::cerr << "Got access method " << std::hex << acc << ", expected " << t.value.access << " for account " << t.key << std::dec << "!\n";
okay = false;
}
free_account_settings(as);
}
@ -93,49 +82,22 @@ bool testSRV()
}
bool testHttp()
{
using account_settings::http_get_file;
bool okay = true;
okay &= (http_get_file("autoconfig.peptest.ch", 80, "/mail/config-v1.1.xml", false).size() > 0);
bool invalid_host = false;
try
{
http_get_file("invalid-host.pep.lol", 80, "/dontmatter", false);
}catch(...)
{
invalid_host = true;
}
okay &= invalid_host;
return okay;
}
int main(int argc, char** argv)
try{
if(argc>1)
{
for(int a=1; a<argc; ++a)
{
std::cout << a << ": " << std::endl;
printf("#%d : ", a);
auto as = std::unique_ptr<AccountSettings>{ new AccountSettings };
get_settings_from_srv( as.get(), "foo@bar.com", argv[a], "dummy");
if( AS_get_status( as.get() ) == AS_OK )
{
std::cout << *as.get() << std::endl;
}else{
std::cout << "No SRV record for \"" << argv[a] << "\". :-(" << std::endl;
}
printf("\n");
}
}
bool all_okay = true;
all_okay &= testServers( incomingServer, &AS_get_incoming );
all_okay &= testServers( outgoingServer, &AS_get_outgoing );
all_okay &= testHttp();
all_okay &= testSRV();
std::cout << "***\t" << (all_okay ? "All tests are okay." : "ERROS happened") << std::endl;

View File

@ -9,7 +9,6 @@
#include <set>
#include <ostream>
// public names, must be accessible from C, so no namespace here:
struct AS_Server
{
std::string name;
@ -31,7 +30,6 @@ std::ostream& operator<<(std::ostream& o, const AS_Server& srv);
std::ostream& operator<<(std::ostream& o, const AccountSettings& as);
namespace account_settings {
// for static ISP DB:
struct AS_Server_DB
{
@ -49,6 +47,4 @@ struct AccountSettings_DB
AS_Server_DB outgoing;
};
} // end of namespace account_settings
#endif // ACCOUNT_SETTINGS_INTERNAL_HH

5
src/boost_asio.cc Normal file
View File

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

9
src/boost_asio.hh Normal file
View File

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

134
src/from_heuristics.cc Normal file
View File

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

8
src/from_heuristics.hh Normal file
View File

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

View File

@ -131,15 +131,10 @@ SRV get_srv_server(const std::string& domain, const std::string& service)
ldns_buffer* buf_host = ldns_buffer_new(128);
ldns_rdf2buffer_str_dname( buf_host, rdf_host);
std::string host = ldns_rdf_get_type(rdf_host)==LDNS_RDF_TYPE_DNAME ? std::string( (const char*)buf_host->_data, buf_host->_position) : "{°?°}";
const std::string host = ldns_rdf_get_type(rdf_host)==LDNS_RDF_TYPE_DNAME ? std::string( (const char*)buf_host->_data, buf_host->_limit) : "{°?°}";
ldns_buffer_free(buf_host);
buf_host=nullptr;
while( (host.size() > 0) && (host.back() == '.') )
{
host.pop_back();
}
// printf("***\tPrio: %u, Weight: %u, Port: %u, Host: \"%s\".\n", priority, weight, port, host.c_str());
return SRV{ priority, weight, port, host };
@ -154,35 +149,14 @@ AccountSettings* get_settings_from_srv(AccountSettings* as, const std::string& a
{
throw std::runtime_error("get_settings_from_srv shall not be called with NULL pointer!");
}
bool imap_okay = false;
bool smtp_okay = false;
// fprintf(stderr, "== IMAPS ==\n");
try{
const SRV imap_srv = get_srv_server( domain, "_imaps._tcp" );
if(imap_srv.is_valid())
{
as->incoming.name = imap_srv.hostname;
as->incoming.port = imap_srv.port;
as->incoming.access = AS_ACCESS(AS_PROTO_IMAP | AS_SOCK_SSL);
imap_okay = true;
}
}catch( const DNS_error& )
{
// ignore unsuccessful DNS queries
}
// fprintf(stderr, "== IMAP ==\n");
if( !imap_okay ) // let's try with plain IMAP nexr (with possibly STARTTLS later)
try{
const SRV imap_srv = get_srv_server( domain, "_imap._tcp" );
if(imap_srv.is_valid())
{
as->incoming.name = imap_srv.hostname;
as->incoming.port = imap_srv.port;
as->incoming.access = AS_PROTO_IMAP;
imap_okay = true;
}
}catch( const DNS_error& )
{
@ -196,18 +170,11 @@ AccountSettings* get_settings_from_srv(AccountSettings* as, const std::string& a
{
as->outgoing.name = smtp_srv.hostname;
as->outgoing.port = smtp_srv.port;
as->outgoing.access = AS_PROTO_SMTP;
smtp_okay = true;
}
}catch( const DNS_error& )
{
// ignore unsuccessful DNS queries
}
if(imap_okay && smtp_okay)
{
as->status = AS_OK;
}
return as;
}

View File

@ -1,102 +0,0 @@
#include "http_client.hh"
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
namespace account_settings
{
using boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
// returns the content of the given http://host:port/path as string
// might throw HttpError
// implementation based on https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/example/cpp03/http/client/sync_client.cpp
// (Boost license 1.0)
std::string http_get_file(const std::string& host, int port, const std::string& path, bool tls)
{
boost::asio::io_context io_context;
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_context);
tcp::resolver::results_type endpoints = resolver.resolve(host, std::to_string(port));
tcp::socket* socket = nullptr;
if(tls)
{
ssl::context ctx(ssl::context::sslv23);
}else{
// Try each endpoint until we successfully establish a connection.
socket = new tcp::socket(io_context);
boost::asio::connect(*socket, endpoints);
}
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " << path << " HTTP/1.0\r\n"
<< "Host: " << host << "\r\n"
<< "Accept: */*\r\n"
<< "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(*socket, request);
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
boost::asio::streambuf response;
boost::asio::read_until(*socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
throw HttpError(host, port, path, -1, http_version);
}
if (status_code != 200)
{
throw HttpError(host, port, path, status_code, status_message);
}
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(*socket, response, "\r\n\r\n");
/*
// Process the response headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r")
std::cout << header << "\n";
std::cout << "\n";
// Write whatever content we already have to output.
if (response.size() > 0)
std::cout << &response;
*/
// Read until EOF, writing data to output as we go.
std::string content;
boost::system::error_code error;
while (boost::asio::read(*socket, response,
boost::asio::transfer_at_least(1), error))
{
auto bufs = response.data();
auto begin = boost::asio::buffers_begin(bufs);
content.append(begin, begin + bufs.size());
}
if (error != boost::asio::error::eof)
throw boost::system::system_error(error);
return content;
}
} // end of namespace account_settings

View File

@ -1,39 +0,0 @@
#ifndef ACCOUNT_SETTINGS_HTTP_CLIENT_HH
#define ACCOUNT_SETTINGS_HTTP_CLIENT_HH
#include <string>
#include <stdexcept>
namespace account_settings
{
class HttpError : public std::runtime_error
{
public:
HttpError(const std::string& _host, int _port, const std::string& _path,
int _error_code, const std::string& _error_message)
: std::runtime_error{ "HTTP Error for http://" + _host + ":" + std::to_string(_port) + _path
+ " : Status=" + std::to_string(_error_code) + (_error_message.empty() ? "" : (": " + _error_message) )}
, host{_host}
, port{_port}
, path{_path}
, error_code{_error_code}
, error_message{_error_message}
{}
// are public by intention
const std::string host;
const int port;
const std::string path;
const int error_code;
const std::string error_message;
};
// returns the content of the given http://host:port/path as string
// might throw HttpError
std::string http_get_file(const std::string& host, int port, const std::string& path, bool tls);
} // end of namespace account_settings
#endif // ACCOUNT_SETTINGS_HTTP_CLIENT_HH

View File

@ -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;
}
@ -108,12 +114,6 @@ AS_STATUS AS_get_status(const struct AccountSettings* account_settings)
}
const char* AS_get_provider_id(const struct AccountSettings* account_settings)
{
return account_settings ? account_settings->id.c_str() : nullptr;
}
const AS_Server* AS_get_incoming(const AccountSettings* as)
{
return &as->incoming;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -47,15 +47,15 @@ distribution.
*/
/*
gcc:
g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
Formatting, Artistic Style:
AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
*/
#if defined( _DEBUG ) || defined (__DEBUG__)
# ifndef TINYXML2_DEBUG
# define TINYXML2_DEBUG
#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
# ifndef DEBUG
# define DEBUG
# endif
#endif
@ -79,7 +79,7 @@ distribution.
#endif
#if defined(TINYXML2_DEBUG)
#if defined(DEBUG)
# if defined(_MSC_VER)
# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); }
@ -98,20 +98,9 @@ distribution.
/* Versioning, past 1.0.14:
http://semver.org/
*/
static const int TIXML2_MAJOR_VERSION = 7;
static const int TIXML2_MINOR_VERSION = 1;
static const int TIXML2_PATCH_VERSION = 0;
#define TINYXML2_MAJOR_VERSION 7
#define TINYXML2_MINOR_VERSION 1
#define TINYXML2_PATCH_VERSION 0
// A fixed element depth limit is problematic. There needs to be a
// limit to avoid a stack overflow. However, that limit varies per
// system, and the capacity of the stack. On the other hand, it's a trivial
// attack that can result from ill, malicious, or even correctly formed XML,
// so there needs to be a limit in place.
static const int TINYXML2_MAX_ELEMENT_DEPTH = 100;
static const int TIXML2_MAJOR_VERSION = 4;
static const int TIXML2_MINOR_VERSION = 0;
static const int TIXML2_PATCH_VERSION = 1;
namespace tinyxml2
{
@ -129,10 +118,8 @@ class XMLPrinter;
pointers into the XML file itself, and will apply normalization
and entity translation if actually read. Can also store (and memory
manage) a traditional char[]
Isn't clear why TINYXML2_LIB is needed; but seems to fix #719
*/
class TINYXML2_LIB StrPair
class StrPair
{
public:
enum {
@ -192,7 +179,7 @@ private:
char* _end;
StrPair( const StrPair& other ); // not supported
void operator=( const StrPair& other ); // not supported, use TransferTo()
void operator=( StrPair& other ); // not supported, use TransferTo()
};
@ -205,11 +192,10 @@ template <class T, int INITIAL_SIZE>
class DynArray
{
public:
DynArray() :
_mem( _pool ),
_allocated( INITIAL_SIZE ),
_size( 0 )
{
DynArray() {
_mem = _pool;
_allocated = INITIAL_SIZE;
_size = 0;
}
~DynArray() {
@ -278,19 +264,12 @@ public:
return _allocated;
}
void SwapRemove(int i) {
TIXMLASSERT(i >= 0 && i < _size);
TIXMLASSERT(_size > 0);
_mem[i] = _mem[_size - 1];
--_size;
}
const T* Mem() const {
TIXMLASSERT( _mem );
return _mem;
}
T* Mem() {
T* Mem() {
TIXMLASSERT( _mem );
return _mem;
}
@ -303,9 +282,8 @@ private:
TIXMLASSERT( cap > 0 );
if ( cap > _allocated ) {
TIXMLASSERT( cap <= INT_MAX / 2 );
const int newAllocated = cap * 2;
int newAllocated = cap * 2;
T* newMem = new T[newAllocated];
TIXMLASSERT( newAllocated >= _size );
memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs
if ( _mem != _pool ) {
delete [] _mem;
@ -336,6 +314,7 @@ public:
virtual void* Alloc() = 0;
virtual void Free( void* ) = 0;
virtual void SetTracked() = 0;
virtual void Clear() = 0;
};
@ -346,16 +325,16 @@ template< int ITEM_SIZE >
class MemPoolT : public MemPool
{
public:
MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
~MemPoolT() {
MemPoolT< ITEM_SIZE >::Clear();
Clear();
}
void Clear() {
// Delete the blocks.
while( !_blockPtrs.Empty()) {
Block* lastBlock = _blockPtrs.Pop();
delete lastBlock;
Block* b = _blockPtrs.Pop();
delete b;
}
_root = 0;
_currentAllocs = 0;
@ -396,14 +375,14 @@ public:
++_nUntracked;
return result;
}
virtual void Free( void* mem ) {
if ( !mem ) {
return;
}
--_currentAllocs;
Item* item = static_cast<Item*>( mem );
#ifdef TINYXML2_DEBUG
#ifdef DEBUG
memset( item, 0xfe, sizeof( *item ) );
#endif
item->next = _root;
@ -526,8 +505,10 @@ enum XMLError {
XML_ERROR_FILE_NOT_FOUND,
XML_ERROR_FILE_COULD_NOT_BE_OPENED,
XML_ERROR_FILE_READ_ERROR,
XML_ERROR_ELEMENT_MISMATCH,
XML_ERROR_PARSING_ELEMENT,
XML_ERROR_PARSING_ATTRIBUTE,
XML_ERROR_IDENTIFYING_TAG,
XML_ERROR_PARSING_TEXT,
XML_ERROR_PARSING_CDATA,
XML_ERROR_PARSING_COMMENT,
@ -538,7 +519,6 @@ enum XMLError {
XML_ERROR_PARSING,
XML_CAN_NOT_CONVERT_TEXT,
XML_NO_TEXT_NODE,
XML_ELEMENT_DEPTH_EXCEEDED,
XML_ERROR_COUNT
};
@ -571,7 +551,7 @@ public:
static bool IsWhiteSpace( char p ) {
return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
}
inline static bool IsNameStartChar( unsigned char ch ) {
if ( ch >= 128 ) {
// This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
@ -582,7 +562,7 @@ public:
}
return ch == ':' || ch == '_';
}
inline static bool IsNameChar( unsigned char ch ) {
return IsNameStartChar( ch )
|| isdigit( ch )
@ -599,7 +579,7 @@ public:
TIXMLASSERT( nChar >= 0 );
return strncmp( p, q, nChar ) == 0;
}
inline static bool IsUTF8Continuation( char p ) {
return ( p & 0x80 ) != 0;
}
@ -617,7 +597,6 @@ public:
static void ToStr( float v, char* buffer, int bufferSize );
static void ToStr( double v, char* buffer, int bufferSize );
static void ToStr(int64_t v, char* buffer, int bufferSize);
static void ToStr(uint64_t v, char* buffer, int bufferSize);
// converts strings to primitive types
static bool ToInt( const char* str, int* value );
@ -626,7 +605,7 @@ public:
static bool ToFloat( const char* str, float* value );
static bool ToDouble( const char* str, double* value );
static bool ToInt64(const char* str, int64_t* value);
static bool ToUnsigned64(const char* str, uint64_t* value);
// Changes what is serialized for a boolean value.
// Default to "true" and "false". Shouldn't be changed
// unless you have a special testing or compatibility need.
@ -878,21 +857,6 @@ public:
*/
virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
/**
Make a copy of this node and all its children.
If the 'target' is null, then the nodes will
be allocated in the current document. If 'target'
is specified, the memory will be allocated is the
specified XMLDocument.
NOTE: This is probably not the correct tool to
copy a document, since XMLDocuments can have multiple
top level XMLNodes. You probably want to use
XMLDocument::DeepCopy()
*/
XMLNode* DeepClone( XMLDocument* target ) const;
/**
Test if 2 nodes are the same, but don't test children.
The 2 nodes do not need to be in the same Document.
@ -925,8 +889,8 @@ public:
*/
virtual bool Accept( XMLVisitor* visitor ) const = 0;
/**
Set user data into the XMLNode. TinyXML-2 in
/**
Set user data into the XMLNode. TinyXML-2 in
no way processes or interprets user data.
It is initially 0.
*/
@ -940,10 +904,10 @@ public:
void* GetUserData() const { return _userData; }
protected:
explicit XMLNode( XMLDocument* );
XMLNode( XMLDocument* );
virtual ~XMLNode();
virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
virtual char* ParseDeep( char*, StrPair*, int* );
XMLDocument* _document;
XMLNode* _parent;
@ -1008,10 +972,10 @@ public:
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
virtual ~XMLText() {}
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr );
private:
bool _isCData;
@ -1039,10 +1003,10 @@ public:
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
explicit XMLComment( XMLDocument* doc );
XMLComment( XMLDocument* doc );
virtual ~XMLComment();
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr);
private:
XMLComment( const XMLComment& ); // not supported
@ -1078,10 +1042,10 @@ public:
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
explicit XMLDeclaration( XMLDocument* doc );
XMLDeclaration( XMLDocument* doc );
virtual ~XMLDeclaration();
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr );
private:
XMLDeclaration( const XMLDeclaration& ); // not supported
@ -1113,10 +1077,10 @@ public:
virtual bool ShallowEqual( const XMLNode* compare ) const;
protected:
explicit XMLUnknown( XMLDocument* doc );
XMLUnknown( XMLDocument* doc );
virtual ~XMLUnknown();
char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr );
private:
XMLUnknown( const XMLUnknown& ); // not supported
@ -1165,12 +1129,6 @@ public:
return i;
}
uint64_t Unsigned64Value() const {
uint64_t i = 0;
QueryUnsigned64Value(&i);
return i;
}
/// Query as an unsigned integer. See IntValue()
unsigned UnsignedValue() const {
unsigned i=0;
@ -1205,8 +1163,6 @@ public:
XMLError QueryUnsignedValue( unsigned int* value ) const;
/// See QueryIntValue
XMLError QueryInt64Value(int64_t* value) const;
/// See QueryIntValue
XMLError QueryUnsigned64Value(uint64_t* value) const;
/// See QueryIntValue
XMLError QueryBoolValue( bool* value ) const;
/// See QueryIntValue
@ -1222,9 +1178,7 @@ public:
void SetAttribute( unsigned value );
/// Set the attribute to value.
void SetAttribute(int64_t value);
/// Set the attribute to value.
void SetAttribute(uint64_t value);
/// Set the attribute to value.
/// Set the attribute to value.
void SetAttribute( bool value );
/// Set the attribute to value.
void SetAttribute( double value );
@ -1234,7 +1188,7 @@ public:
private:
enum { BUF_SIZE = 200 };
XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
XMLAttribute() : _parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
virtual ~XMLAttribute() {}
XMLAttribute( const XMLAttribute& ); // not supported
@ -1312,8 +1266,6 @@ public:
unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
/// See IntAttribute()
int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
/// See IntAttribute()
uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const;
/// See IntAttribute()
bool BoolAttribute(const char* name, bool defaultValue = false) const;
/// See IntAttribute()
@ -1360,15 +1312,6 @@ public:
return a->QueryInt64Value(value);
}
/// See QueryIntAttribute()
XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const {
const XMLAttribute* a = FindAttribute(name);
if(!a) {
return XML_NO_ATTRIBUTE;
}
return a->QueryUnsigned64Value(value);
}
/// See QueryIntAttribute()
XMLError QueryBoolAttribute( const char* name, bool* value ) const {
const XMLAttribute* a = FindAttribute( name );
@ -1394,25 +1337,14 @@ public:
return a->QueryFloatValue( value );
}
/// See QueryIntAttribute()
XMLError QueryStringAttribute(const char* name, const char** value) const {
const XMLAttribute* a = FindAttribute(name);
if (!a) {
return XML_NO_ATTRIBUTE;
}
*value = a->Value();
return XML_SUCCESS;
}
/** Given an attribute name, QueryAttribute() returns
XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
can't be performed, or XML_NO_ATTRIBUTE if the attribute
doesn't exist. It is overloaded for the primitive types,
and is a generally more convenient replacement of
QueryIntAttribute() and related functions.