[sddm] Added XDMCP support

Martin Briza mbriza at fedoraproject.org
Tue Oct 15 15:49:22 UTC 2013


commit 288ff57820dcfaa66134f5609167ec2e08cca784
Author: Martin Briza <mbriza at redhat.com>
Date:   Tue Oct 15 17:49:06 2013 +0200

    Added XDMCP support

 sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch | 1660 +++++++++++++++++++++++
 sddm.conf                                       |    1 +
 sddm.spec                                       |    9 +-
 3 files changed, 1669 insertions(+), 1 deletions(-)
---
diff --git a/sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch b/sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch
new file mode 100644
index 0000000..ab6ce8a
--- /dev/null
+++ b/sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch
@@ -0,0 +1,1660 @@
+diff --git a/data/sddm.conf.in b/data/sddm.conf.in
+index 9522ffd..204dc52 100644
+--- a/data/sddm.conf.in
++++ b/data/sddm.conf.in
+@@ -89,3 +89,6 @@ MinimumVT=7
+ # Valid values: on|off|none
+ # If property is set to none, numlock won't be changed
+ Numlock=none
++
++# Enables the XDMCP Server
++XDMCPServer=false
+\ No newline at end of file
+diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
+index a82ae45..1d6d117 100644
+--- a/src/CMakeLists.txt
++++ b/src/CMakeLists.txt
+@@ -20,6 +20,9 @@ set(DAEMON_SOURCES
+     daemon/Session.cpp
+     daemon/SignalHandler.cpp
+     daemon/SocketServer.cpp
++    daemon/xdmcp/Packet.cpp
++    daemon/xdmcp/Server.cpp
++    daemon/xdmcp/Utils.cpp
+ )
+ 
+ if(USE_QT5)
+diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp
+index 2095b05..4b780b3 100644
+--- a/src/common/Configuration.cpp
++++ b/src/common/Configuration.cpp
+@@ -63,6 +63,7 @@ namespace SDDM {
+         bool autoRelogin { false };
+ 
+         Configuration::NumState numlock { Configuration::NUM_NONE };
++        bool xdmcpServerEnabled { false };
+     };
+ 
+     Configuration::Configuration(const QString &configPath, QObject *parent) : QObject(parent), d(new ConfigurationPrivate()) {
+@@ -122,6 +123,7 @@ namespace SDDM {
+         } else {
+             d->numlock = Configuration::NUM_NONE;
+         }
++        d->xdmcpServerEnabled = settings.value("XDMCPServer", d->xdmcpServerEnabled).toBool();
+     }
+ 
+     void Configuration::save() {
+@@ -158,6 +160,8 @@ namespace SDDM {
+             settings.setValue("Numlock", "on");
+         else if (d->numlock == NUM_SET_OFF)
+             settings.setValue("Numlock", "off");
++
++        settings.setValue("XDMCPServer", d->xdmcpServerEnabled);
+     }
+ 
+     Configuration *Configuration::instance() {
+@@ -261,4 +265,9 @@ namespace SDDM {
+     const Configuration::NumState Configuration::numlock() const {
+         return d->numlock;
+     }
++
++    bool Configuration::xdmcpServerEnabled() const {
++        return d->xdmcpServerEnabled;
++    }
++
+ }
+diff --git a/src/common/Configuration.h b/src/common/Configuration.h
+index cbef261..4b610d8 100644
+--- a/src/common/Configuration.h
++++ b/src/common/Configuration.h
+@@ -79,6 +79,8 @@ namespace SDDM {
+         enum NumState { NUM_NONE, NUM_SET_ON, NUM_SET_OFF };
+         const NumState numlock() const;
+ 
++        bool xdmcpServerEnabled() const;
++
+         bool first { true };
+ 
+         bool testing { false };
+diff --git a/src/daemon/DaemonApp.cpp b/src/daemon/DaemonApp.cpp
+index c40cdea..616282e 100644
+--- a/src/daemon/DaemonApp.cpp
++++ b/src/daemon/DaemonApp.cpp
+@@ -25,6 +25,7 @@
+ #include "PowerManager.h"
+ #include "SeatManager.h"
+ #include "SignalHandler.h"
++#include "xdmcp/Server.h"
+ 
+ #ifdef USE_QT5
+ #include "MessageHandler.h"
+@@ -65,6 +66,12 @@ namespace SDDM {
+         // create seat manager
+         m_seatManager = new SeatManager(this);
+ 
++        // start the XDMCP server
++        if (configuration()->xdmcpServerEnabled()) {
++            m_xdmcpServer = XDMCP::Server::instance(this);
++            m_xdmcpServer->start();
++        }
++
+         // connect with display manager
+         connect(m_seatManager, SIGNAL(seatCreated(QString)), m_displayManager, SLOT(AddSeat(QString)));
+         connect(m_seatManager, SIGNAL(seatRemoved(QString)), m_displayManager, SLOT(RemoveSeat(QString)));
+diff --git a/src/daemon/DaemonApp.h b/src/daemon/DaemonApp.h
+index 81f955c..2088010 100644
+--- a/src/daemon/DaemonApp.h
++++ b/src/daemon/DaemonApp.h
+@@ -29,6 +29,9 @@ namespace SDDM {
+     class DisplayManager;
+     class PowerManager;
+     class SeatManager;
++    namespace XDMCP {
++        class Server;
++    }
+ 
+     class DaemonApp : public QCoreApplication {
+         Q_OBJECT
+@@ -57,6 +60,7 @@ namespace SDDM {
+         DisplayManager *m_displayManager { nullptr };
+         PowerManager *m_powerManager { nullptr };
+         SeatManager *m_seatManager { nullptr };
++        XDMCP::Server *m_xdmcpServer { nullptr };
+     };
+ }
+ 
+diff --git a/src/daemon/Display.cpp b/src/daemon/Display.cpp
+index 8517124..80aa95a 100644
+--- a/src/daemon/Display.cpp
++++ b/src/daemon/Display.cpp
+@@ -53,6 +53,19 @@ namespace SDDM {
+         return name;
+     }
+ 
++    Display::Display(const QString& hostname, const int displayId, QObject* parent)
++    : QObject(parent)
++    , m_displayId(displayId)
++    , m_authenticator(new Authenticator(this))
++    , m_displayServer(nullptr)
++    , m_socketServer(new SocketServer(this))
++    , m_greeter(new Greeter(this))
++    {
++        m_display = QString("%1:%2").arg(hostname).arg(displayId);
++
++        init();
++    }
++
+     Display::Display(const int displayId, const int terminalId, QObject *parent) : QObject(parent),
+         m_displayId(displayId), m_terminalId(terminalId),
+         m_authenticator(new Authenticator(this)),
+@@ -62,12 +75,17 @@ namespace SDDM {
+ 
+         m_display = QString(":%1").arg(m_displayId);
+ 
+-        // restart display after user session ended
+-        connect(m_authenticator, SIGNAL(stopped()), this, SLOT(stop()));
+-
+         // restart display after display server ended
+         connect(m_displayServer, SIGNAL(stopped()), this, SLOT(stop()));
+ 
++        init();
++    }
++
++    void Display::init()
++    {
++        // restart display after user session ended
++        connect(m_authenticator, SIGNAL(stopped()), this, SLOT(stop()));
++
+         // connect login signal
+         connect(m_socketServer, SIGNAL(login(QLocalSocket*,QString,QString,QString)), this, SLOT(login(QLocalSocket*,QString,QString,QString)));
+ 
+@@ -90,6 +108,22 @@ namespace SDDM {
+ 
+         // set socket name
+         m_socket = QString("sddm-%1-%2").arg(m_display).arg(generateName(6));
++
++        // generate cookie
++        std::random_device rd;
++        std::mt19937 gen(rd());
++        std::uniform_int_distribution<> dis(0, 15);
++
++        // resever 32 bytes
++        m_cookie.reserve(32);
++
++        // create a random hexadecimal number
++        const char *digits = "0123456789abcdef";
++        for (int i = 0; i < 32; ++i)
++            m_cookie[i] = digits[dis(gen)];
++
++        // generate auth file
++        addCookie(m_authPath);
+     }
+ 
+     Display::~Display() {
+@@ -112,6 +146,16 @@ namespace SDDM {
+         return m_cookie;
+     }
+ 
++    const QByteArray Display::rawCookie() const {
++        QByteArray cookie;
++        for (int i = 0; i < m_cookie.length() / 2; i++) {
++            // horrible, just horrible
++            quint8 byte = QString("%1%2").arg(m_cookie[i*2]).arg(m_cookie[i*2+1]).toUInt(nullptr, 16);
++            cookie.append(byte);
++        }
++        return cookie;
++    }
++
+     void Display::addCookie(const QString &file) {
+         // log message
+         qDebug() << " DAEMON: Adding cookie to" << file;
+@@ -139,28 +183,14 @@ namespace SDDM {
+         if (m_started)
+             return;
+ 
+-        // generate cookie
+-        std::random_device rd;
+-        std::mt19937 gen(rd());
+-        std::uniform_int_distribution<> dis(0, 15);
+-
+-        // resever 32 bytes
+-        m_cookie.reserve(32);
++        if (m_displayServer != nullptr) {
++            // set display server params
++            m_displayServer->setDisplay(m_display);
++            m_displayServer->setAuthPath(m_authPath);
+ 
+-        // create a random hexadecimal number
+-        const char *digits = "0123456789abcdef";
+-        for (int i = 0; i < 32; ++i)
+-            m_cookie[i] = digits[dis(gen)];
+-
+-        // generate auth file
+-        addCookie(m_authPath);
+-
+-        // set display server params
+-        m_displayServer->setDisplay(m_display);
+-        m_displayServer->setAuthPath(m_authPath);
+-
+-        // start display server
+-        m_displayServer->start();
++            // start display server
++            m_displayServer->start();
++        }
+ 
+         if ((daemonApp->configuration()->first || daemonApp->configuration()->autoRelogin()) &&
+             !daemonApp->configuration()->autoUser().isEmpty() && !daemonApp->configuration()->lastSession().isEmpty()) {
+@@ -216,9 +246,11 @@ namespace SDDM {
+         m_socketServer->stop();
+ 
+         // stop display server
+-        m_displayServer->blockSignals(true);
+-        m_displayServer->stop();
+-        m_displayServer->blockSignals(false);
++        if (m_displayServer != nullptr) {
++            m_displayServer->blockSignals(true);
++            m_displayServer->stop();
++            m_displayServer->blockSignals(false);
++        }
+ 
+         // remove authority file
+         QFile::remove(m_authPath);
+diff --git a/src/daemon/Display.h b/src/daemon/Display.h
+index 9d82678..9c475a9 100644
+--- a/src/daemon/Display.h
++++ b/src/daemon/Display.h
+@@ -34,6 +34,7 @@ namespace SDDM {
+         Q_OBJECT
+         Q_DISABLE_COPY(Display)
+     public:
++        explicit Display(const QString& hostname, const int displayId, QObject *parent = 0);
+         explicit Display(const int displayId, const int terminalId, QObject *parent = 0);
+         ~Display();
+ 
+@@ -43,6 +44,7 @@ namespace SDDM {
+         const QString &name() const;
+ 
+         const QString &cookie() const;
++        const QByteArray rawCookie() const;
+         void addCookie(const QString &file);
+ 
+     public slots:
+@@ -58,6 +60,8 @@ namespace SDDM {
+         void loginSucceeded(QLocalSocket *socket);
+ 
+     private:
++        void init();
++
+         bool m_relogin { true };
+         bool m_started { false };
+ 
+diff --git a/src/daemon/xdmcp/Packet.cpp b/src/daemon/xdmcp/Packet.cpp
+new file mode 100644
+index 0000000..90688d0
+--- /dev/null
++++ b/src/daemon/xdmcp/Packet.cpp
+@@ -0,0 +1,435 @@
++/*
++ * Packet type handling for X Display Control Protocol
++ * Copyright (C) 2013  Martin Bříza <mbriza at redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include "Packet.h"
++#include "Server.h"
++#include "../Display.h"
++
++namespace SDDM {
++namespace XDMCP {
++
++/*******************************************************************************
++*                                   PLUMBING
++ ******************************************************************************/
++
++    Packet::Packet(const QHostAddress& host, quint16 port)
++        : m_host(host)
++        , m_port(port)
++        , m_valid(true) {
++
++    }
++
++    Packet::Packet(const QHostAddress& host, quint16 port, Reader& r)
++        : m_host(host)
++        , m_port(port)
++        , m_valid(false) {
++
++    }
++
++    Packet::~Packet() {
++
++    }
++
++    bool Packet::isValid() const {
++        return m_valid;
++    }
++
++    // static
++    Packet *Packet::decode(const QByteArray& data, const QHostAddress& host, quint16 port) {
++        Reader reader(data);
++        uint16_t version, opcode, length;
++
++        reader >> version >> opcode >> length;
++
++        if (version != 1)
++            return nullptr;
++        if (length != data.size() - 6)
++            return nullptr;
++
++        switch (opcode) {
++        case _Query:
++            return new Query(host, port, reader);
++        case _BroadcastQuery:
++            return new BroadcastQuery(host, port, reader);
++        case _IndirectQuery:
++            return new IndirectQuery(host, port, reader);
++        case _ForwardQuery:
++            return new ForwardQuery(host, port, reader);
++        case _Willing:
++            return new Willing(host, port, reader);
++        case _Unwilling:
++            return new Unwilling(host, port, reader);
++        case _Request:
++            return new Request(host, port, reader);
++        case _Accept:
++            return new Accept(host, port, reader);
++        case _Decline:
++            return new Decline(host, port, reader);
++        case _Manage:
++            return new Manage(host, port, reader);
++        case _Refuse:
++            return new Refuse(host, port, reader);
++        case _Failed:
++            return new Failed(host, port, reader);
++        case _KeepAlive:
++            return new KeepAlive(host, port, reader);
++        case _Alive:
++            return new Alive(host, port, reader);
++        default:
++            qDebug() << " XDMCP: Got packet of an unknown type" << opcode;
++            return nullptr;
++        }
++    }
++
++    void Packet::setHost(const QHostAddress host) {
++        m_host = QHostAddress(host);
++    }
++
++    QHostAddress Packet::host() const {
++        return m_host;
++    }
++
++    void Packet::setPort(quint16 port) {
++        m_port = port;
++    }
++
++    quint16 Packet::port() const {
++        return m_port;
++    }
++
++    QByteArray Packet::encode() const {
++        return QByteArray();
++    }
++
++    Packet *Packet::onClientReceived() const {
++        qDebug() << " XDMCP: Client received a wrong packet type (no action assigned)";
++        return nullptr;
++    }
++
++    Packet *Packet::onServerReceived() const {
++        qDebug() << " XDMCP: Server received a wrong packet type (no action assigned)";
++        return nullptr;
++    }
++
++    Packet::Query::Query(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_authenticationNames;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Query::encode() const {
++        Writer w;
++        w << m_authenticationNames;
++        return w.finalize(Packet::_Query);
++    }
++
++    Packet::BroadcastQuery::BroadcastQuery(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_authenticationNames;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::BroadcastQuery::encode() const {
++        Writer w;
++        w << m_authenticationNames;
++        return w.finalize(Packet::_BroadcastQuery);
++    }
++
++    Packet::IndirectQuery::IndirectQuery(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_authenticationNames;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::IndirectQuery::encode() const {
++        Writer w;
++        w << m_authenticationNames;
++        return w.finalize(Packet::_IndirectQuery);
++    }
++
++    Packet::ForwardQuery::ForwardQuery(const QHostAddress& host, quint16 port, Reader& r) : Packet(host, port, r) {
++        r >> m_clientAddress >> m_clientPort >> m_authenticationNames;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::ForwardQuery::encode() const {
++        Writer w;
++        w << m_clientAddress << m_clientPort << m_authenticationNames;
++        return w.finalize(Packet::_ForwardQuery);
++    }
++
++    Packet::Willing::Willing(const QHostAddress& host, quint16 port, const QString& authenticationName, const QString& hostname, const QString& status)
++        : Packet(host, port)
++        , m_authenticationName(authenticationName.toLatin1())
++        , m_hostname(hostname.toLatin1())
++        , m_status(status.toLatin1()) {
++        qDebug() << " XDMCP: Prepared Willing reply for" << host << port << "with contents" << authenticationName << hostname << status;
++    }
++
++    Packet::Willing::Willing(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_authenticationName >> m_hostname >> m_status;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Willing::encode() const {
++        Writer w;
++        w << m_authenticationName << m_hostname << m_status;
++        return w.finalize(Packet::_Willing);
++    }
++
++    Packet::Unwilling::Unwilling(const QHostAddress& host, quint16 port, const QString& hostname, const QString& status)
++        : Packet(host, port)
++        , m_hostname(hostname.toLatin1())
++        , m_status(status.toLatin1()) {
++        qDebug() << " XDMCP: Prepared Unwilling reply for" << host << port << "with contents" << hostname << status;
++    }
++
++    Packet::Unwilling::Unwilling(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_hostname >> m_status;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Unwilling::encode() const {
++        Writer w;
++        w << m_hostname << m_status;
++        return w.finalize(Packet::_Unwilling);
++    }
++
++    Packet::Request::Request(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_displayNumber >> m_connectionTypes >> m_connectionAddresses
++        >> m_authenticationName >> m_authenticationData >> m_authorizationNames
++        >> m_manufacturerDisplayID;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Request::encode() const {
++        Writer w;
++        w << m_displayNumber << m_connectionTypes << m_connectionAddresses
++        << m_authenticationName << m_authenticationData << m_authorizationNames
++        << m_manufacturerDisplayID;
++        return w.finalize(Packet::_Request);
++    }
++
++    Packet::Accept::Accept(const QHostAddress& host, quint16 port, uint32_t sessionId, const QString authenticationName, const QByteArray authenticationData, const QString authorizationName, const QByteArray authorizationData)
++        : Packet(host, port)
++        , m_sessionID(sessionId)
++        , m_authenticationName(authenticationName.toLatin1())
++        , m_authenticationData(authenticationData)
++        , m_authorizationName(authorizationName.toLatin1())
++        , m_authorizationData(authorizationData) {
++        qDebug() << " XDMCP: Prepared Accept reply for" << host << port << "with contents" << sessionId << authenticationName << authenticationData << authorizationName << authorizationData;
++    }
++
++    Packet::Accept::Accept(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_sessionID >> m_authenticationName >> m_authenticationData
++        >> m_authorizationName >> m_authorizationData;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Accept::encode() const {
++        Writer w;
++        w << m_sessionID << m_authenticationName << m_authenticationData
++        << m_authorizationName << m_authorizationData;
++        return w.finalize(Packet::_Accept);
++    }
++
++    Packet::Decline::Decline(const QHostAddress& host, quint16 port, const QString status, const QString authenticationName, const QByteArray authenticationData)
++        : Packet(host, port)
++        , m_status(status.toLatin1())
++        , m_authenticationName(authenticationName.toLatin1())
++        , m_authenticationData(authenticationData) {
++        qDebug() << " XDMCP: Prepared Decline reply for" << host << port << "with contents" << status << authenticationName << authenticationData;
++    }
++
++    Packet::Decline::Decline(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_status >> m_authenticationName >> m_authenticationData;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Decline::encode() const {
++        Writer w;
++        w << m_status << m_authenticationName << m_authenticationData;
++        return w.finalize(Packet::_Decline);
++    }
++
++    Packet::Manage::Manage(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_sessionID >> m_displayNumber >> m_displayClass;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Manage::encode() const {
++        Writer w;
++        w << m_sessionID << m_displayNumber << m_displayClass;
++        return w.finalize(Packet::_Manage);
++    }
++
++    Packet::Refuse::Refuse(const QHostAddress& host, quint16 port, uint32_t sessionID)
++        : Packet(host, port)
++        , m_sessionID(sessionID) {
++        qDebug() << " XDMCP: Prepared Refuse reply for" << host << port << "with contents" << sessionID;
++    }
++
++    Packet::Refuse::Refuse(const QHostAddress& host, quint16 port, Reader& r) : Packet(host, port, r) {
++        r >> m_sessionID;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Refuse::encode() const {
++        Writer w;
++        w << m_sessionID;
++        return w.finalize(Packet::_Refuse);
++    }
++
++    Packet::Failed::Failed(const QHostAddress& host, quint16 port, uint32_t sessionID, const QString& status)
++        : Packet(host, port)
++        , m_sessionID(sessionID)
++        , m_status(status.toLatin1()) {
++        qDebug() << " XDMCP: Prepared Failed reply for" << host << port << "with contents" << sessionID << status;
++    }
++
++    Packet::Failed::Failed(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_sessionID >> m_status;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Failed::encode() const {
++        Writer w;
++        w << m_sessionID << m_status;
++        return w.finalize(Packet::_Failed);
++    }
++
++    Packet::KeepAlive::KeepAlive(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_displayNumber >> m_sessionID;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::KeepAlive::encode() const {
++        Writer w;
++        w << m_displayNumber << m_sessionID;
++        return w.finalize(Packet::_KeepAlive);
++    }
++
++    Packet::Alive::Alive(const QHostAddress& host, quint16 port, uint8_t sessionRunning, uint32_t sessionID)
++        : Packet(host, port)
++        , m_sessionRunning(sessionRunning)
++        , m_sessionID(sessionID) {
++        qDebug() << " XDMCP: Prepared Alive reply for" << host << port << "with contents" << sessionRunning << sessionID;
++    }
++
++    Packet::Alive::Alive(const QHostAddress& host, quint16 port, Reader& r)
++        : Packet(host, port, r) {
++        r >> m_sessionRunning >> m_sessionID;
++        if (r.isFinished()) {
++            m_valid = true;
++        }
++    }
++
++    QByteArray Packet::Alive::encode() const {
++        Writer w;
++        w << m_sessionRunning << m_sessionID;
++        return w.finalize(Packet::_Alive);
++    }
++
++/*******************************************************************************
++ *                            SERVER IMPLEMENTATIONS
++ ******************************************************************************/
++
++    Packet *Packet::Query::onServerReceived() const {
++        if (m_authenticationNames.isEmpty()) {
++            return new Willing(m_host, m_port, "", Server::instance()->hostname(), Server::instance()->status());
++        }
++        else {
++            return new Unwilling(m_host, m_port, Server::instance()->hostname(), "Server does not support authentication");
++        }
++    }
++
++    Packet* Packet::Request::onServerReceived() const {
++        qDebug() << " XDMCP: Server: Received Request" << m_displayNumber << m_connectionTypes << m_connectionAddresses << m_authenticationName << m_authenticationData << m_authorizationNames << m_manufacturerDisplayID;
++        if (m_authorizationNames.contains("MIT-MAGIC-COOKIE-1")) {
++            uint32_t sessionId = Server::instance()->newSessionId();
++            QHostAddress addr(QString("%1.%2.%3.%4").arg((uint) m_connectionAddresses.first()[0]).arg((uint) m_connectionAddresses.first()[1]).arg((uint) m_connectionAddresses.first()[2]).arg((uint) m_connectionAddresses.first()[3]));
++            Display *display = Server::instance()->newDisplay(sessionId, addr.toString(), m_displayNumber);
++            return new Accept(m_host, m_port, sessionId, m_authenticationName, m_authenticationData, "MIT-MAGIC-COOKIE-1", display->rawCookie());
++        } else {
++            return new Decline(m_host, m_port, Server::instance()->status(), m_authenticationName, m_authenticationData);
++        }
++    }
++
++    Packet* Packet::Manage::onServerReceived() const {
++        Display *display = Server::instance()->getDisplay(m_sessionID);
++        if (display != nullptr) {
++            display->start();
++            return nullptr;
++        } else {
++            return new Refuse(m_host, m_port, m_sessionID);
++        }
++    }
++
++    Packet* Packet::KeepAlive::onServerReceived() const {
++        Display *display = Server::instance()->getDisplay(m_sessionID);
++        if (display == nullptr)
++            return new Alive(m_host, m_port, 0, m_sessionID);
++        else if (display->displayId() != m_displayNumber)
++            return new Alive(m_host, m_port, 0, m_sessionID);
++        else {
++            return new Alive(m_host, m_port, 1, m_sessionID);
++        }
++    }
++
++/*******************************************************************************
++ *                            CLIENT IMPLEMENTATIONS
++ ******************************************************************************/
++
++};
++};
+diff --git a/src/daemon/xdmcp/Packet.h b/src/daemon/xdmcp/Packet.h
+new file mode 100644
+index 0000000..507b1b4
+--- /dev/null
++++ b/src/daemon/xdmcp/Packet.h
+@@ -0,0 +1,394 @@
++/*
++ * Packet type handling for X Display Control Protocol
++ * Copyright (C) 2013  Martin Bříza <mbriza at redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef SDDM_XDMCP_PACKET_H
++#define SDDM_XDMCP_PACKET_H
++
++#include <QtCore/QByteArray>
++#include <QtNetwork/QHostAddress>
++
++#include "Utils.h"
++
++namespace SDDM {
++namespace XDMCP {
++    class Reader;
++    /**
++    * XDMCP Packet main class
++    *
++    * Defines interface and static methods to work with the protocol data
++    */
++    class Packet {
++    public:
++        virtual ~Packet();
++
++        /**
++        * Get the packet's validity (especially for responses)
++        *
++        * \return validity
++        */
++        bool isValid() const;
++
++        /**
++        * Defines server behavior on receiving this packet
++        */
++        virtual Packet *onServerReceived() const;
++
++        /**
++        * Defines client behavior on receiving this packet
++        */
++        virtual Packet *onClientReceived() const;
++
++        /**
++        * Encode the packet to raw data according to the protocol
++        *
++        * \return Data byte array
++        */
++        virtual QByteArray encode() const;
++
++        /**
++        * Decode raw packet data and create a packet for further processing
++        *
++        * \param data Raw data from the socket
++        * \param host Source host of the packet
++        * \param port Source port of the packet
++        * \return Parsed packet
++        */
++        static Packet *decode(const QByteArray& data, const QHostAddress& host = QHostAddress(), quint16 port = 0);
++
++        /**
++         * Set the packet's source/destination host
++         *
++         * \param host The host
++         */
++        void setHost(const QHostAddress host);
++
++        /**
++         * Get the packet's source/destination host
++         *
++         * \return The host
++         */
++        QHostAddress host() const;
++
++        /**
++         * Set the packet's source/destination host
++         *
++         * \param port The port
++         */
++        void setPort(quint16 port);
++
++        /**
++         * Get the packet's source/destination host
++         *
++         * \return The port
++         */
++        quint16 port() const;
++
++        /**
++         * Redundancy for everyone!
++         */
++        enum Opcode {
++            _None = 0,
++            _BroadcastQuery = 1,
++            _Query,
++            _IndirectQuery,
++            _ForwardQuery,
++            _Willing,
++            _Unwilling,
++            _Request,
++            _Accept,
++            _Decline,
++            _Manage,
++            _Refuse,
++            _Failed,
++            _KeepAlive,
++            _Alive,
++        };
++
++        class BroadcastQuery;
++        class Query;
++        class IndirectQuery;
++        class ForwardQuery;
++        class Willing;
++        class Unwilling;
++        class Request;
++        class Accept;
++        class Decline;
++        class Manage;
++        class Refuse;
++        class Failed;
++        class KeepAlive;
++        class Alive;
++
++    protected:
++        /**
++         * C'tor targetted for creating response packets
++         *
++         * Automatically sets the packet to be valid
++         * \param host Destination host for the response
++         * \param port Destination port for the response
++         */
++        Packet(const QHostAddress& host, quint16 port);
++        /**
++         * C'tor targetted for parsing raw data
++         *
++         * \param host Destination host for the response
++         * \param port Destination port for the response
++         * \param r Reader containing the packet's raw data
++         */
++        Packet(const QHostAddress& host, quint16 port, Reader& r);
++
++        QHostAddress m_host;
++        quint16 m_port { 0 };
++        bool m_valid { false };
++    };
++
++    class Packet::BroadcastQuery : public Packet {
++    public:
++        BroadcastQuery(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++    private:
++        QVector<QByteArray> m_authenticationNames;
++    };
++
++    class Packet::Query : public Packet {
++    public:
++        Query(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++        /**
++         * Server side handling of Query packet
++         *
++         * Client sends a list of authorization names
++         *
++         * If the list is empty (and we are willing to continue without
++         * authorization), we reply with \ref Willing with empty
++         * authenticationName
++         *
++         * Otherwise, we choose the one name that complies to the supported ones
++         * in the server and use it as authenticationName for the \ref Willing
++         * packet
++         *
++         * If none of the names complies and/or we don't want to continue 
++         * without authorization, the reply is \ref Unwilling
++         *
++         * \return Response
++         */
++        virtual Packet *onServerReceived() const;
++    private:
++        QVector<QByteArray> m_authenticationNames;
++    };
++
++    class Packet::IndirectQuery : public Packet {
++    public:
++        IndirectQuery(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++    private:
++        QVector<QByteArray> m_authenticationNames;
++    };
++
++    class Packet::ForwardQuery : public Packet {
++    public:
++        ForwardQuery(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++    private:
++        QByteArray m_clientAddress;
++        QByteArray m_clientPort;
++        QVector<QByteArray> m_authenticationNames;
++    };
++
++    class Packet::Willing : public Packet {
++    public:
++        Willing(const QHostAddress& host, quint16 port, 
++                const QString& authenticationName, const QString& hostname,
++                const QString& status);
++        Willing(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++        /**
++         * Client side handling of Willing packet
++         *
++         * Description TBD
++         *
++         * Reply on success is \ref Request
++         *
++         * \return Response
++         */
++//         virtual Packet *onClientReceived() const;
++    private:
++        QByteArray m_authenticationName;
++        QByteArray m_hostname;
++        QByteArray m_status;
++    };
++
++    class Packet::Unwilling : public Packet {
++    public:
++        Unwilling(const QHostAddress& host, quint16 port,
++                  const QString& hostname, const QString& status);
++        Unwilling(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++    private:
++        QByteArray m_hostname;
++        QByteArray m_status;
++    };
++
++    class Packet::Request : public Packet {
++    public:
++        Request(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++        /**
++         * Server side handling of Request packet
++         *
++         * Client informs there will be displey displayNumber running on
++         * connectionAddresses accessible via connectionTypes.
++         * It also authorizes with the authenticationName and authenticationData.
++         * It sends a list of propsed authorizationNames for the server to choose
++         * one of them and reply using the \ref Accept packet where the chosen
++         * authorizationName will be stored along with the authorizationData for
++         * the client and the new sessionID.
++         *
++         * If the display cannot be used, the server replies using the \ref Decline
++         * packet with its status.
++         *
++         * \return Response
++         */
++        virtual Packet *onServerReceived() const;
++    private:
++        uint16_t m_displayNumber;
++        QVector<uint16_t> m_connectionTypes;
++        QVector<QByteArray> m_connectionAddresses;
++        QByteArray m_authenticationName;
++        QByteArray m_authenticationData;
++        QVector<QByteArray> m_authorizationNames;
++        QByteArray m_manufacturerDisplayID;
++    };
++
++    class Packet::Accept : public Packet {
++    public:
++        Accept(const QHostAddress& host, quint16 port, uint32_t sessionId,
++               const QString authenticationName, const QByteArray authenticationData,
++               const QString authorizationName, const QByteArray authorizationData);
++        Accept(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++        /**
++         * Client side handling of Accept packet
++         *
++         * Description TBD
++         *
++         * Reply on succes is \ref Manage
++         *
++         * \return Response
++         */
++//         virtual Packet *onClientReceived() const;
++    private:
++        uint32_t m_sessionID;
++        QByteArray m_authenticationName;
++        QByteArray m_authenticationData;
++        QByteArray m_authorizationName;
++        QByteArray m_authorizationData;
++    };
++
++    class Packet::Decline : public Packet {
++    public:
++        Decline(const QHostAddress& host, quint16 port, const QString status,
++                const QString authenticationName, const QByteArray authenticationData);
++        Decline(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++    private:
++        QByteArray m_status;
++        QByteArray m_authenticationName;
++        QByteArray m_authenticationData;
++    };
++
++    class Packet::Manage : public Packet {
++    public:
++        Manage(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++        /**
++         * Server side handling of Manage packet
++         *
++         * Client asks the server to open a connection to its opened display
++         * specified in the previous Request packet.
++         *
++         * There is no answer on success, just opening a connection.
++         *
++         * If the connection is specified wrong (erroneous sessionID, etc.), then
++         * the server replies with a \ref Refuse packet.
++         *
++         * If the connection cannot be opened due to an internal error, 
++         * \ref Failed packet is sent to the client.
++         *
++         * \return Response
++         */
++        virtual Packet *onServerReceived() const;
++    private:
++        uint32_t m_sessionID;
++        uint16_t m_displayNumber;
++        QByteArray m_displayClass;
++    };
++
++    class Packet::Refuse : public Packet {
++    public:
++        Refuse(const QHostAddress& host, quint16 port, uint32_t sessionID);
++        Refuse(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++    private:
++        uint32_t m_sessionID;
++    };
++
++    class Packet::Failed : public Packet {
++    public:
++        Failed(const QHostAddress& host, quint16 port, uint32_t sessionID, const QString& status);
++        Failed(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++    private:
++        uint32_t m_sessionID;
++        QByteArray m_status;
++    };
++
++    class Packet::KeepAlive : public Packet {
++    public:
++        KeepAlive(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++        /**
++         * Server side handling of KeepAlive packet
++         *
++         * Clients asks the server if the session is still alive.
++         *
++         * Server replies with \ref Alive packet with either sessionRunning == 0
++         * for a dead session or sessionRunning != 0 for a live one
++         */
++        virtual Packet *onServerReceived() const;
++    private:
++        uint16_t m_displayNumber;
++        uint32_t m_sessionID;
++    };
++
++    class Packet::Alive : public Packet {
++    public:
++        Alive(const QHostAddress& host, quint16 port, uint8_t sessionRunning, uint32_t sessionID);
++        Alive(const QHostAddress& host, quint16 port, Reader& r);
++        virtual QByteArray encode() const;
++    private:
++        uint8_t m_sessionRunning;
++        uint32_t m_sessionID;
++    };
++
++} // namespace XDMCP
++} // namespace SDDM
++
++#endif // SDDM_XDMCP_PACKET_H
+diff --git a/src/daemon/xdmcp/Server.cpp b/src/daemon/xdmcp/Server.cpp
+new file mode 100644
+index 0000000..edfdff4
+--- /dev/null
++++ b/src/daemon/xdmcp/Server.cpp
+@@ -0,0 +1,149 @@
++/*
++ * Server implementation for X Display Control Protocol
++ * Copyright (C) 2013  Martin Bříza <mbriza at redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include "Server.h"
++#include "Packet.h"
++#include "../DaemonApp.h"
++#include "../Display.h"
++
++#include <QtNetwork/QHostInfo>
++
++namespace SDDM {
++namespace XDMCP {
++
++    Server *Server::self = nullptr;
++
++    Server* Server::instance(DaemonApp* parent) {
++        if (self == nullptr) {
++            self = new Server(parent);
++        }
++        return self;
++    }
++
++    Server::Server(DaemonApp* parent)
++        : QUdpSocket(parent)
++        , m_hostname(QHostInfo::localHostName()) {
++
++    }
++
++    Server::~Server() {
++
++    }
++
++    bool Server::start() {
++        qDebug() << " XDMCP: Server: Starting...";
++        connect(this, SIGNAL(readyRead()), this, SLOT(newData()));
++        bool result = bind(m_address, m_port);
++        if (!result) {
++            qDebug() << " XDMCP: Server: Cannot bind" << m_address << m_port << errorString();
++        }
++        else {
++            m_started = true;
++            m_status = "online";
++            qDebug() << " XDMCP: Server: Started and listening on" << m_address << ":" << m_port;
++        }
++        return result;
++    }
++
++    void Server::socketError(QAbstractSocket::SocketError socketError) {
++        qDebug() << " XDMCP: Error:" << errorString();
++        // TODO: error recovery
++        m_started = false;
++        m_status = "error";
++    }
++
++    QString Server::hostname() const {
++        return m_hostname;
++    }
++
++    QString Server::status() const {
++        return m_status;
++    }
++
++    bool Server::isStarted() const {
++        return m_started;
++    }
++
++    uint32_t Server::newSessionId() {
++        // realistically, can this serve more than 4 billion clients to actually cause trouble in removeDisplay?
++        while (m_displays.keys().contains(m_lastSession))
++            m_lastSession++;
++        return m_lastSession++;
++    }
++
++    Display* Server::newDisplay(uint32_t sessionId, QString hostName, uint32_t displayNumber) {
++        if (m_displays.contains(sessionId))
++            return nullptr;
++        Display *display = new Display(hostName, displayNumber, this);
++        connect(display, SIGNAL(destroyed(QObject*)), SLOT(removeDisplay(QObject*)));
++        m_displays[sessionId] = display;
++        return display;
++    }
++
++    Display* Server::getDisplay(uint32_t id) {
++        if (m_displays.contains(id))
++            return m_displays[id];
++        else
++            return nullptr;
++    }
++
++    void Server::removeDisplay(QObject* obj) {
++        int key = m_displays.key(qobject_cast<Display*>(obj), -1);
++        if (key == -1)
++            return;
++
++        m_displays.remove(key);
++    }
++
++    void Server::setAddress(QHostAddress address) {
++        m_address = address;
++    }
++
++    void Server::setPort(int port) {
++        m_port = port;
++    }
++
++    void Server::newData() {
++        while (hasPendingDatagrams()) {
++            QByteArray data;
++            QHostAddress sender;
++            quint16 port;
++            data.resize(pendingDatagramSize());
++
++            readDatagram(data.data(), data.size(), &sender, &port);
++
++            Packet *toProcess = Packet::decode(data, sender, port);
++            if (toProcess && toProcess->isValid()) {
++                Packet *response = toProcess->onServerReceived();
++                if (response && response->isValid()) {
++                    writeDatagram(response->encode(), response->host(), response->port());
++                }
++                delete response;
++            } else {
++                qDebug() << " XDMCP: Server: Received packet wasn't decoded as valid";
++            }
++            delete toProcess;
++        }
++    }
++
++} // namespace XDMCP
++} // namespace SDDM
++
++#include "Server.moc"
+diff --git a/src/daemon/xdmcp/Server.h b/src/daemon/xdmcp/Server.h
+new file mode 100644
+index 0000000..2860bf9
+--- /dev/null
++++ b/src/daemon/xdmcp/Server.h
+@@ -0,0 +1,117 @@
++/*
++ * Server implementation for X Display Control Protocol
++ * Copyright (C) 2013  Martin Bříza <mbriza at redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef SDDM_XDMCP_SERVER_H
++#define SDDM_XDMCP_SERVER_H
++
++#include <QtCore/QObject>
++#include <QtCore/QMap>
++#include <QtCore/QTimer>
++#include <QtNetwork/QUdpSocket>
++
++#include <X11/Xdmcp.h>
++
++namespace SDDM {
++
++class Display;
++    class DaemonApp;
++namespace XDMCP {
++
++    class Server : protected QUdpSocket
++    {
++        Q_OBJECT
++    public:
++        /**
++         * Get an instance of the XDMCP server. If there isn't any, construct a
++         * new one
++         *
++         * \param parent Parent for the eventual construction
++         * \return Singleton XDMCP Server instance
++         */
++        static Server *instance(DaemonApp *parent = nullptr);
++        /**
++         * D'tor
++         */
++        virtual ~Server();
++
++        /**
++         * Set port to listen on
++         *
++         * \param port The port
++         */
++        void setPort(int port);
++
++        /**
++         * Set address to listen on
++         *
++         * \param address The address
++         */
++        void setAddress(QHostAddress address);
++
++        /**
++         * Start the server
++         *
++         * \return True if successful
++         */
++        bool start();
++
++        /**
++         * Get server online status
++         *
++         * \return True if running
++         */
++        bool isStarted() const;
++
++
++        /**
++         * Returns a new session ID for incoming requests
++         */
++        uint32_t newSessionId();
++
++        /**
++         * Create a new display
++         */
++        Display *newDisplay(uint32_t sessionId, QString hostName, uint32_t displayNumber);
++        Display *getDisplay(uint32_t id);
++        QString status() const;
++        QString hostname() const;
++
++    private slots:
++        void newData();
++        void socketError(QAbstractSocket::SocketError socketError);
++        void removeDisplay(QObject *obj);
++
++    private:
++        static Server *self;
++        explicit Server(DaemonApp *parent = nullptr);
++
++        QString m_status { "offline" };
++        QString m_hostname { "localhost" };
++        QHostAddress m_address { QHostAddress::Any };
++        quint16 m_port { XDM_UDP_PORT };
++        bool m_started { false };
++        uint32_t m_lastSession { 0 };
++        QMap<int, Display*> m_displays;
++        QMap<int, QTimer*> m_timers;
++    };
++}
++}
++
++#endif // SDDM_XDMCP_SERVER_H
+diff --git a/src/daemon/xdmcp/Utils.cpp b/src/daemon/xdmcp/Utils.cpp
+new file mode 100644
+index 0000000..92e1d6a
+--- /dev/null
++++ b/src/daemon/xdmcp/Utils.cpp
+@@ -0,0 +1,145 @@
++/*
++ * Utilities for X Display Control Protocol
++ * Copyright (C) 2013  Martin Bříza <mbriza at redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include "Utils.h"
++
++#include <QtCore/QVector>
++
++namespace SDDM {
++namespace XDMCP {
++
++    Reader::Reader(const QByteArray& data)
++        : m_data(data)
++        , m_stream(&m_data, QIODevice::ReadOnly | QIODevice::Unbuffered) {
++        m_stream.setByteOrder(QDataStream::BigEndian);
++    }
++
++    Reader& Reader::operator>>(uint8_t& byte) {
++        m_stream >> byte;
++        return *this;
++    }
++
++    Reader& Reader::operator>>(uint16_t& word) {
++        m_stream >> word;
++        return *this;
++    }
++
++    Reader& Reader::operator>>(uint32_t& doubleword) {
++        m_stream >> doubleword;
++        return *this;
++    }
++
++    Reader& Reader::operator>>(QByteArray& array) {
++        uint16_t arrayLen;
++        *this >> arrayLen;
++        while (arrayLen--) {
++            uint8_t byte;
++            *this >> byte;
++            array.append(byte);
++        }
++        return *this;
++    }
++
++    Reader& Reader::operator>>(QVector< uint16_t >& wordArray) {
++        uint8_t arrayLen;
++        *this >> arrayLen;
++        while (arrayLen--) {
++            uint16_t word;
++            *this >> word;
++            wordArray.append(word);
++        }
++        return *this;
++    }
++
++    Reader& Reader::operator>>(QVector< QByteArray >& arrayOfArrays) {
++        uint8_t arrayCount;
++        *this >> arrayCount;
++        while (arrayCount--) {
++            QByteArray array;
++            *this >> array;
++            arrayOfArrays.append(array);
++        }
++        return *this;
++    }
++
++    bool Reader::isFinished() const {
++        if ((m_stream.status() == QDataStream::Ok) && m_stream.atEnd())
++            return true;
++        else
++            return false;
++    }
++
++    Writer::Writer()
++        : m_data()
++        , m_stream(&m_data, QIODevice::WriteOnly | QIODevice::Unbuffered) {
++        m_stream.setByteOrder(QDataStream::BigEndian);
++    }
++
++    Writer& Writer::operator<<(const uint8_t byte) {
++        qDebug() << "Appending:" << byte << QChar(byte);
++        m_stream << byte;
++        return *this;
++    }
++
++    Writer& Writer::operator<<(const uint16_t word) {
++        m_stream << word;
++        return *this;
++    }
++
++    Writer& Writer::operator<<(const uint32_t doubleword) {
++        m_stream << doubleword;
++        return *this;
++    }
++
++    Writer& Writer::operator<<(const QByteArray& array) {
++        *this << (uint16_t) array.count();
++        for (uint8_t c : array)
++            m_stream << c;
++        return *this;
++    }
++
++    Writer& Writer::operator<<(const QVector< uint16_t >& wordArray) {
++        *this << (uint8_t) wordArray.count();
++        for (const uint16_t& i : wordArray)
++            *this << i;
++        return *this;
++    }
++
++    Writer& Writer::operator<<(const QVector< QByteArray >& arrayOfArrays) {
++        *this << (uint16_t) arrayOfArrays.count();
++        for (const QByteArray& i : arrayOfArrays)
++            *this << i;
++        return *this;
++    }
++
++    QByteArray Writer::finalize(uint16_t opcode) {
++        QByteArray result;
++        QDataStream finalStream(&result, QIODevice::WriteOnly | QIODevice::Unbuffered);
++        finalStream.setByteOrder(QDataStream::BigEndian);
++        finalStream << (uint16_t) 1;
++        finalStream << (uint16_t) opcode;
++        finalStream << (uint16_t) m_data.size();
++        for (uint8_t c : m_data)
++            finalStream << c;
++        return result;
++    }
++
++} // namespace XDMCP
++} // namespace SDDM
+\ No newline at end of file
+diff --git a/src/daemon/xdmcp/Utils.h b/src/daemon/xdmcp/Utils.h
+new file mode 100644
+index 0000000..9457ef1
+--- /dev/null
++++ b/src/daemon/xdmcp/Utils.h
+@@ -0,0 +1,93 @@
++/*
++ * Utilities for X Display Control Protocol
++ * Copyright (C) 2013  Martin Bříza <mbriza at redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef SDDM_XDMCP_UTILS_H
++#define SDDM_XDMCP_UTILS_H
++
++#include <QtCore/QByteArray>
++#include <QtCore/QDataStream>
++
++#include "Packet.h"
++
++namespace SDDM {
++namespace XDMCP {
++
++    /**
++     * Class for reading information from raw packets and setting the right byte order
++     *
++     * Workflow is as follows:
++     * * Construct Reader from the data received
++     * * Using the stream operator extract all required variables
++     * * Check if the stream is at its end by isFinished()
++     */
++    class Reader {
++        public:
++            Reader(const QByteArray &data);
++            ~Reader() {}
++            Reader& operator>>(uint8_t& byte);
++            Reader& operator>>(uint16_t& word);
++            Reader& operator>>(uint32_t& doubleword);
++            Reader& operator>>(QByteArray& array);
++            Reader& operator>>(QVector<uint16_t>& wordArray);
++            Reader& operator>>(QVector<QByteArray>& arrayOfArrays);
++            /**
++             * Returns true if the stream is at its end and no errors occured
++             *
++             * \return Finished status
++             */
++            bool isFinished() const;
++        private:
++            QByteArray m_data;
++            QDataStream m_stream;
++    };
++
++    /**
++     * Class for writing information to raw packets and setting the right byte order
++     *
++     * Workflow is as follows:
++     * * Construct empty writer
++     * * Using the stream operator insert all contained variables
++     * * Get a complete packet by the finalize(opcode) method
++     */
++    class Writer {
++        public:
++            Writer();
++            Writer& operator<<(const uint8_t byte);
++            Writer& operator<<(const uint16_t word);
++            Writer& operator<<(const uint32_t doubleword);
++            Writer& operator<<(const QByteArray& array);
++            Writer& operator<<(const QVector<uint16_t>& wordArray);
++            Writer& operator<<(const QVector<QByteArray>& arrayOfArrays);
++            /**
++             * Finalizes building of the packet
++             *
++             * \param opcode XDMCP protocol code of the packet type
++             * \return Raw packet data
++             */
++            QByteArray finalize(uint16_t opcode);
++        private:
++            QByteArray m_data;
++            QDataStream m_stream;
++    };
++
++} // namespace XDMCP
++} // namespace SDDM
++
++#endif // SDDM_XDMCP_UTILS_H
diff --git a/sddm.conf b/sddm.conf
index f1852dd..84914f1 100644
--- a/sddm.conf
+++ b/sddm.conf
@@ -23,3 +23,4 @@ HideShells=
 AutoRelogin=false
 MinimumVT=1
 Numlock=on
+XDMCPServer=false
diff --git a/sddm.spec b/sddm.spec
index da3b4e3..0e0a4f2 100644
--- a/sddm.spec
+++ b/sddm.spec
@@ -3,7 +3,7 @@
 
 Name:           sddm
 Version:        0.2.0
-Release:        0.14.20130914git%(echo %{sddm_commit} | cut -c-8)%{?dist}
+Release:        0.15.20130914git%(echo %{sddm_commit} | cut -c-8)%{?dist}
 # code GPLv2+, fedora theme CC-BY-SA
 License:        GPLv2+ and CC-BY-SA
 Summary:        QML based X11 desktop manager
@@ -28,6 +28,8 @@ Source23:       fedora-theme.conf
 # Patch setting a better order of the xsessions and hiding the custom one
 Patch2:         sddm-git.e707e229-session-list.patch
 
+Patch3:         sddm-0.2.0-0.11.20130914git50ca5b20-xdmcp.patch
+
 Provides: service(graphical-login) = sddm
 
 BuildRequires:  cmake
@@ -68,6 +70,7 @@ A collection of sddm themes, including: circles, elarun, maldives, maui.
 %setup -q -n %{name}-%{sddm_commit}
 
 %patch2 -p1 -b .session-list
+%patch3 -p1 -b .xdmcp
 
 # get rid of the architecture flag
 sed -i "s/-march=native//" CMakeLists.txt
@@ -137,6 +140,10 @@ install -Dpm 644 %{SOURCE23} %{buildroot}%{_datadir}/apps/sddm/themes/fedora/the
 %{_datadir}/apps/sddm/themes/maui/
 
 %changelog
+* Tue Oct 15 2013 Martin Briza <mbriza at redhat.com> - 0.2.0-0.15.20130914git50ca5b20
+- Added XDMCP support patch
+- Modified the config to reflect the added XDMCP support (disabled by default)
+
 * Tue Oct 15 2013 Rex Dieter <rdieter at fedoraproject.org> - 0.2.0-0.14.20130914git50ca5b20
 - sddm.conf: CurrentTheme=fedora
 


More information about the scm-commits mailing list