Hi Jan,

Attached are the MailAutoConfigure class and header files. I will upload
to github later.

I wasn't aware of either the work that Boren is doing or RFC 6186.
I will contact Boren regarding his work.

Having just given RFC 6186 a cursory read it doesn't look too difficult
to add in to the existing DNS record checks.
I am wondering, though, whether it might be best to separate each
individual method of auto-configuration into classes, with a control
class running through each method (either simultaneously or
sequentially) to return the configuration in the shortest possible time.

Thanks
Matt

On 20/07/14 21:20, Jan Kundrát wrote:
> On Sunday, 20 July 2014 13:18:34 CEST, Matt Richardson wrote:
>> I have written a class which takes a users email address and uses the
>> domain or the DNS MX records for that domain to lookup the email server
>> settings from the Mozilla ISP Database.
>
> Sounds cool, looking forward for reviewing this. Quick question,
> because the referred Mozilla wiki page conspicuously misses RFC 6186
> [1] -- are you aware of that? Are you in touch with some of the work
> that Boren (IIRC) is doing in this area? Or am I mistaken and it's
> actually you?
>
>> I was wondering whereabouts in the Trojita source tree to put this
>> class?
>
> Sounds like a material for a standalone top-level directory.
>
>> I was also wondering about naming convention within Trojita. At the
>> moment the class is called MailAutoConfigure but I don't know if people
>> would prefer a different name.
>
> Depends on how the entire API looks like. Please show us the code and
> how the functionality is split into different classes, and then we can
> talk about proper naming conventions.
>
> With kind regards,
> Jan
>
> [1] http://tools.ietf.org/html/rfc6186
>

#include "mailautoconfigure.h"

MailAutoConfigure::MailAutoConfigure(QObject *parent, QString emailAddress) :
    QObject(parent)
{
    m_confInfo = new SettingsObject();
    m_isEmailDomain = true;
    m_emailDomain = emailAddress.remove(0,emailAddress.indexOf("@")+1);
    m_testDomain = m_emailDomain;
    qDebug() << "Domain:" << m_testDomain;
}

void MailAutoConfigure::getConf() {
    getServerName();
}

void MailAutoConfigure::getServerName()
{
    networkFileExists(QUrl(tr("https://autoconfig.thunderbird.net/v1.1/%1";).arg(m_testDomain)));
}

void MailAutoConfigure::networkFileExists(QUrl u)
{
    QNetworkAccessManager *nam = new QNetworkAccessManager();
    QNetworkRequest netRequest;
    netRequest.setUrl(u);
    m_netReply = nam->get(netRequest);
    connect(m_netReply,SIGNAL(metaDataChanged()),this,SLOT(fileExistsReply()));
}

void MailAutoConfigure::fileExistsReply()
{
    if(m_netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) {
        connect(m_netReply,SIGNAL(finished()),this,SLOT(getServerInfo()));
    }
    else {
        if(m_testDomain.contains(".")) {
            m_testDomain = stripSubdomain(m_testDomain);
            getServerName();
        }
        else {
            if(m_isEmailDomain) {
                m_isEmailDomain = false;
                m_testDomain = m_emailDomain;
                lookupServer();
            }
            else
                emit finished(m_confInfo);
        }
    }
}

QString MailAutoConfigure::stripSubdomain(QString dmn)
{
    return dmn.remove(0,dmn.indexOf(".")+1);
}

void MailAutoConfigure::lookupServer()
{
    QDnsLookup *dnsLookup = new QDnsLookup(this);
    connect(dnsLookup,SIGNAL(finished()),this,SLOT(handleServerResult()));
    dnsLookup->setType(QDnsLookup::MX);
    dnsLookup->setName(m_testDomain);
    dnsLookup->lookup();
}

void MailAutoConfigure::handleServerResult()
{
    QDnsLookup *dnsLookup = reinterpret_cast<QDnsLookup*>(sender());
    if (dnsLookup->error() != QDnsLookup::NoError) {
        qWarning("DNS lookup failed");
        dnsLookup->deleteLater();
        return;
    }

    QDnsMailExchangeRecord mxRecord = dnsLookup->mailExchangeRecords().at(0);
    m_testDomain = mxRecord.exchange();
    dnsLookup->deleteLater();
    getServerName();
}

QString MailAutoConfigure::getChildNodeValue(QDomNode node, QString nodeName)
{
    return node.namedItem(nodeName).firstChild().nodeValue();
}

void MailAutoConfigure::getServerInfo()
{
    QDomDocument *confDocument = new QDomDocument("confInfo");
    if (!confDocument->setContent(m_netReply->readAll())) {
        qDebug() << "Could not set xml content";
        return;
    }

    QDomNode inInfo;
    QDomNodeList inServers = confDocument->elementsByTagName("incomingServer");
    for(int i = 0; i < inServers.count(); i++) {
        if(inServers.at(i).attributes().namedItem("type").nodeValue() == "imap") {
            inInfo = inServers.at(i);
            break;
        }
    }

    QDomNodeList inElems = inInfo.childNodes();
    for(int i = 0; i < inElems.count(); i++) {
        if(!inElems.at(i).isComment()) {
            qDebug() << inElems.at(i).nodeName() << inElems.at(i).firstChild().nodeValue();
            m_confInfo->inSettings.setProperty(inElems.at(i).nodeName().toLatin1(),inElems.at(i).firstChild().nodeValue());
        }
    }

    QDomNode outInfo = confDocument->elementsByTagName("outgoingServer").at(0);
    QDomNodeList outElems = outInfo.childNodes();
    for(int i = 0; i < outElems.count(); i++) {
        if(!outElems.at(i).isComment()) {
            qDebug() << outElems.at(i).nodeName() << outElems.at(i).firstChild().nodeValue();
            m_confInfo->outSettings.setProperty(outElems.at(i).nodeName().toLatin1(),outElems.at(i).firstChild().nodeValue());
        }
    }

    emit finished(m_confInfo);
}
#ifndef MAILAUTOCONFIGURE_H
#define MAILAUTOCONFIGURE_H

#include <QObject>
#include <QDnsLookup>
#include <QUrl>

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

#include <QDomDocument>
#include <QDomElement>

class SettingsObject : public QObject
{
    Q_OBJECT
public:
    QObject inSettings;
    QObject outSettings;
};

class MailAutoConfigure : public QObject
{
    Q_OBJECT
public:
    explicit MailAutoConfigure(QObject *parent = 0, QString emailAddress = QString());

public slots:
    void getConf();

signals:
    void finished(SettingsObject*);

private slots:
    void handleServerResult();
    void fileExistsReply();
    void getServerInfo();

private:
    void getServerName();
    void lookupServer();
    QString stripSubdomain(QString dmn);
    void networkFileExists(QUrl u);
    QString getChildNodeValue(QDomNode node, QString nodeName);

    SettingsObject *m_confInfo;
    QString m_emailDomain;
    bool m_isEmailDomain;
    QNetworkReply *m_netReply;
    QString m_testDomain;
};

#endif // MAILAUTOCONFIGURE_H

Reply via email to