Browse Source

Projektdateien hinzufügen.

Kolja Strohm 7 years ago
parent
commit
3ba4a8a4ec

+ 30 - 0
Karten Server.sln

@@ -0,0 +1,30 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26020.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KartenServer", "KartenServer\KartenServer.vcxproj", "{D67B61D4-E858-4D71-8BE6-A64561CD757C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|ARM = Debug|ARM
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|ARM = Release|ARM
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D67B61D4-E858-4D71-8BE6-A64561CD757C}.Debug|ARM.ActiveCfg = Debug|x64
+		{D67B61D4-E858-4D71-8BE6-A64561CD757C}.Debug|x64.ActiveCfg = Debug|x64
+		{D67B61D4-E858-4D71-8BE6-A64561CD757C}.Debug|x64.Build.0 = Debug|x64
+		{D67B61D4-E858-4D71-8BE6-A64561CD757C}.Debug|x86.ActiveCfg = Debug|x64
+		{D67B61D4-E858-4D71-8BE6-A64561CD757C}.Release|ARM.ActiveCfg = Release|x64
+		{D67B61D4-E858-4D71-8BE6-A64561CD757C}.Release|x64.ActiveCfg = Release|x64
+		{D67B61D4-E858-4D71-8BE6-A64561CD757C}.Release|x64.Build.0 = Release|x64
+		{D67B61D4-E858-4D71-8BE6-A64561CD757C}.Release|x86.ActiveCfg = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 463 - 0
KartenServer/Datenbank.cpp

@@ -0,0 +1,463 @@
+#include "Datenbank.h"
+#include <Zeit.h>
+
+// Inhalt der LSDatenbank Klasse aus Datenbank.h
+// Konstruktor
+KSDatenbank::KSDatenbank( InitDatei *zIni )
+{
+    if( !zIni->wertExistiert( "DBBenutzer" ) )
+        zIni->addWert( "DBBenutzer", "kartenserveru" );
+    if( !zIni->wertExistiert( "DBPasswort" ) )
+        zIni->addWert( "DBPasswort", "LTKitorServerPW" );
+    if( !zIni->wertExistiert( "DBName" ) )
+        zIni->addWert( "DBName", "koljadb" );
+    if( !zIni->wertExistiert( "DBIP" ) )
+        zIni->addWert( "DBIP", "127.0.0.1" );
+    if( !zIni->wertExistiert( "DBPort" ) )
+        zIni->addWert( "DBPort", "5432" );
+    datenbank = new Datenbank( zIni->zWert( "DBBenutzer" )->getText(), zIni->zWert( "DBPasswort" )->getText(),
+                               zIni->zWert( "DBName" )->getText(), zIni->zWert( "DBIP" )->getText(),
+                               (unsigned short)TextZuInt( zIni->zWert( "DBPort" )->getText(), 10 ) );
+    InitializeCriticalSection( &cs );
+    ref = 1;
+}
+
+// Destruktor
+KSDatenbank::~KSDatenbank()
+{
+    datenbank->release();
+    DeleteCriticalSection( &cs );
+}
+
+// nicht constant
+void KSDatenbank::lock()
+{
+    EnterCriticalSection( &cs );
+}
+
+void KSDatenbank::unlock()
+{
+    LeaveCriticalSection( &cs );
+}
+
+int KSDatenbank::istAdministrator( const char *name, const char *passwort )
+{
+    Text *befehl = new Text( "SELECT id FROM benutzer WHERE name = '" );
+    befehl->append( name );
+    befehl->append( "' AND passwort = '" );
+    befehl->append( passwort );
+    befehl->append( "'" );
+    lock();
+    datenbank->befehl( befehl->getText() );
+    Result res = datenbank->getResult();
+    unlock();
+    befehl->release();
+    int ret = 0;
+    if( res.zeilenAnzahl > 0 )
+        ret = TextZuInt( res.values[ 0 ].getText(), 10 );
+    res.destroy();
+    return ret;
+}
+
+bool KSDatenbank::adminHatRecht( int id, int recht )
+{
+    Text *befehl = new Text( "SELECT * FROM benutzer_rechte WHERE benutzer_id = " );
+    befehl->append( id );
+    befehl->append( " AND rechte_id = " );
+    befehl->append( recht );
+    lock();
+    datenbank->befehl( befehl->getText() );
+    int ret = datenbank->getZeilenAnzahl();
+    unlock();
+    befehl->release();
+    return ret != 0;
+}
+
+bool KSDatenbank::proveKlient( int num, int sNum )
+{
+    Text *befehl = new Text( "SELECT * FROM server_karten_clients WHERE server_karten_id = " );
+    befehl->append( sNum );
+    befehl->append( " AND client_id = " );
+    befehl->append( num );
+    lock();
+    datenbank->befehl( befehl->getText() );
+    Result res = datenbank->getResult();
+    unlock();
+    befehl->release();
+    bool ret = 0;
+    if( res.zeilenAnzahl == 1 )
+        ret = 1;
+    res.destroy();
+    return ret;
+}
+
+Text *KSDatenbank::getKlientKey( int cId )
+{
+    lock();
+    if( !datenbank->befehl( Text( "SELECT schluessel FROM clients WHERE id = " ) += cId ) )
+    {
+        unlock();
+        return 0;
+    }
+    Result res = datenbank->getResult();
+    unlock();
+    if( !res.zeilenAnzahl )
+    {
+        res.destroy();
+        return 0;
+    }
+    Text *ret = new Text( res.values[ 0 ].getText() );
+    res.destroy();
+    return ret;
+}
+
+void KSDatenbank::unregisterKlient( int num, int sNum )
+{
+    Text *befehl = new Text( "DELETE FROM server_karten_clients WHERE client_id = " );
+    befehl->append( num );
+    befehl->append( " AND server_karten_id = " );
+    befehl->append( sNum );
+    lock();
+    datenbank->befehl( befehl->getText() );
+    unlock();
+    befehl->release();
+}
+
+bool KSDatenbank::serverAnmelden( InitDatei *zIni )
+{
+    if( !zIni->wertExistiert( "ServerId" ) )
+        zIni->addWert( "ServerId", "0" );
+    if( !zIni->wertExistiert( "ServerName" ) )
+        zIni->addWert( "ServerName", "Name" );
+    if( !zIni->wertExistiert( "ServerPort" ) )
+        zIni->addWert( "ServerPort", "49144" );
+    if( !zIni->wertExistiert( "ServerIP" ) )
+        zIni->addWert( "ServerIP", "127.0.0.1" );
+    if( !zIni->wertExistiert( "AdminServerPort" ) )
+        zIni->addWert( "AdminServerPort", "49143" );
+    if( !zIni->wertExistiert( "Aktiv" ) )
+        zIni->addWert( "Aktiv", "FALSE" );
+    if( !zIni->wertExistiert( "MaxKarten" ) )
+        zIni->addWert( "MaxKarten", "50" );
+    bool insert = 0;
+    int id = *zIni->zWert( "ServerId" );
+    if( id )
+    {
+        lock();
+        if( !datenbank->befehl( Text( "SELECT id FROM server_karten WHERE id = " ) += id ) )
+        {
+            unlock();
+            return 0;
+        }
+        int anz = datenbank->getZeilenAnzahl();
+        unlock();
+        insert = anz == 0;
+        if( !insert )
+        {
+            lock();
+            if( !datenbank->befehl( Text( "SELECT id FROM server_karten WHERE server_status_id = 1 AND id = " ) += id ) )
+            {
+                unlock();
+                return 0;
+            }
+            int anz = datenbank->getZeilenAnzahl();
+            unlock();
+            if( !anz ) // Server läuft bereits
+                return 0;
+        }
+    }
+    if( insert || !id )
+    { // Neuer Eintrag in Tabelle server_karten
+        Text *befehl = new Text( "INSERT INTO server_karten( " );
+        if( id )
+            *befehl += "id, ";
+        *befehl += "name, ip, port, admin_port, server_status_id, max_karten ) VALUES( ";
+        if( id )
+        {
+            *befehl += id;
+            *befehl += ", ";
+        }
+        *befehl += "'";
+        *befehl += zIni->zWert( "ServerName" )->getText();
+        *befehl += "', '";
+        *befehl += zIni->zWert( "ServerIP" )->getText();
+        *befehl += "', ";
+        *befehl += zIni->zWert( "ServerPort" )->getText();
+        *befehl += ", ";
+        *befehl += zIni->zWert( "AdminServerPort" )->getText();
+        *befehl += ", 1, ";
+        *befehl += zIni->zWert( "MaxKarten" )->getText();
+        *befehl += " ) RETURNING id";
+        lock();
+        if( !datenbank->befehl( *befehl ) )
+        {
+            unlock();
+            befehl->release();
+            return 0;
+        }
+        Result res = datenbank->getResult();
+        unlock();
+        befehl->release();
+        if( !res.zeilenAnzahl )
+        {
+            res.destroy();
+            return 0;
+        }
+        zIni->setWert( "ServerId", res.values[ 0 ] );
+        return 1;
+    }
+    else
+    { // Alten Eintrag aus Tabelle server_karten ändern
+        Text *befehl = new Text( "UPDATE server_karten SET name = '" );
+        *befehl += zIni->zWert( "ServerName" )->getText();
+        *befehl += "', port = ";
+        *befehl += zIni->zWert( "ServerPort" )->getText();
+        *befehl += ", ip = '";
+        *befehl += zIni->zWert( "ServerIP" )->getText();
+        *befehl += "', max_karten = ";
+        *befehl += zIni->zWert( "MaxKarten" )->getText();
+        *befehl += ", admin_port = ";
+        *befehl += zIni->zWert( "AdminServerPort" )->getText();
+        *befehl += " WHERE id = ";
+        *befehl += id;
+        lock();
+        bool ret = datenbank->befehl( *befehl );
+        unlock();
+        befehl->release();
+        return ret;
+    }
+}
+
+bool KSDatenbank::setServerStatus( int id, int status )
+{
+    Text *befehl = new Text( "UPDATE server_karten SET server_status_id = " );
+    *befehl += status;
+    *befehl += "WHERE id = ";
+    *befehl += id;
+    lock();
+    if( !datenbank->befehl( befehl->getText() ) )
+    {
+        unlock();
+        befehl->release();
+        return 0;
+    }
+    bool ret = datenbank->getZeilenAnzahl() != 0;
+    unlock();
+    befehl->release();
+    return ret;
+}
+
+bool KSDatenbank::setMaxKarten( int id, int maxK )
+{
+    Text *befehl = new Text( "UPDATE server_karten SET max_karten = " );
+    befehl->append( maxK );
+    befehl->append( " WHERE id = " );
+    befehl->append( id );
+    lock();
+    if( !datenbank->befehl( befehl->getText() ) )
+    {
+        unlock();
+        befehl->release();
+        return 0;
+    }
+    bool ret = datenbank->getZeilenAnzahl() > 0;
+    unlock();
+    befehl->release();
+    return ret;
+}
+
+int KSDatenbank::getAdminPort( int id )
+{
+    Text *befehl = new Text( "SELECT admin_port FROM server_karten WHERE id = " );
+    befehl->append( id );
+    lock();
+    if( !datenbank->befehl( befehl->getText() ) )
+    {
+        unlock();
+        befehl->release();
+        return 0;
+    }
+    Result res = datenbank->getResult();
+    unlock();
+    befehl->release();
+    if( !res.zeilenAnzahl )
+    {
+        res.destroy();
+        return 0;
+    }
+    int ret = TextZuInt( res.values[ 0 ].getText(), 10 );
+    res.destroy();
+    return ret;
+}
+
+bool KSDatenbank::serverIstNichtPausiert( int id )
+{
+    Text *befehl = new Text( "SELECT server_status_id FROM server_karten WHERE id = " );
+    befehl->append( id );
+    lock();
+    if( !datenbank->befehl( befehl->getText() ) )
+    {
+        unlock();
+        befehl->release();
+        return 0;
+    }
+    Result res = datenbank->getResult();
+    unlock();
+    befehl->release();
+    if( !res.zeilenAnzahl )
+    {
+        res.destroy();
+        return 0;
+    }
+    bool ret = (int)res.values[ 0 ] == 3;
+    res.destroy();
+    return ret;
+}
+
+bool KSDatenbank::proveKarte( int id, int sNum )
+{
+    Text befehl = "SELECT id FROM karte WHERE id = ";
+    befehl += id;
+    befehl += " AND server_karten_id = ";
+    befehl += sNum;
+    lock();
+    if( !datenbank->befehl( befehl ) )
+    {
+        unlock();
+        return 0;
+    }
+    bool ret = datenbank->getZeilenAnzahl() != 0;
+    unlock();
+    return ret;
+}
+
+int KSDatenbank::getUpdateKarte( int serverId )
+{
+    Text befehl = "SELECT id FROM karte WHERE erlaubt = FALSE AND server_karten_id = ";
+    befehl += serverId;
+    lock();
+    if( !datenbank->befehl( befehl ) )
+    {
+        unlock();
+        return 0;
+    }
+    Result r = datenbank->getResult();
+    unlock();
+    for( int i = 0; i < r.zeilenAnzahl; i++ )
+    {
+        int karte = r.values[ i ];
+        befehl = "SELECT karte_update_warten( ";
+        befehl += karte;
+        befehl += " )";
+        lock();
+        if( !datenbank->befehl( befehl ) )
+        {
+            unlock();
+            continue;
+        }
+        Result res = datenbank->getResult();
+        unlock();
+        if( !res.zeilenAnzahl )
+        {
+            res.destroy();
+            continue;
+        }
+        if( res.values[ 0 ].istGleich( "f" ) )
+        {
+            res.destroy();
+            r.destroy();
+            return karte;
+        }
+        res.destroy();
+    }
+    r.destroy();
+    return 0;
+}
+
+bool KSDatenbank::endUpdateKarte( int karteId )
+{
+    Text befehl = "SELECT karte_update_ende( ";
+    befehl += karteId;
+    befehl += " )";
+    lock();
+    if( !datenbank->befehl( befehl ) )
+    {
+        unlock();
+        return 0;
+    }
+    Result r = datenbank->getResult();
+    unlock();
+    if( !r.zeilenAnzahl )
+    {
+        r.destroy();
+        return 0;
+    }
+    bool ret = r.values[ 0 ].istGleich( "t" );
+    r.destroy();
+    return ret;
+}
+
+bool KSDatenbank::getEditorServerPortIp( int karteId, int *port, Text *ip )
+{
+    if( !port || !ip )
+        return 0;
+    Text befehl = "SELECT a.port, a.ip FROM server_editor a, karte b WHERE a.id = b.server_editor_id AND b.id = ";
+    befehl += karteId;
+    lock();
+    if( !datenbank->befehl( befehl ) )
+    {
+        unlock();
+        return 0;
+    }
+    Result r = datenbank->getResult();
+    unlock();
+    if( !r.zeilenAnzahl )
+    {
+        r.destroy();
+        return 0;
+    }
+    *port = r.values[ 0 ];
+    ip->setText( r.values[ 1 ] );
+    r.destroy();
+    return 1;
+}
+
+bool KSDatenbank::setKarteSpielerAnzahl( int karteId, int sAnz )
+{
+    Text befehl = "UPDATE karte SET max_spieler = ";
+    befehl += sAnz;
+    befehl += " WHERE id = ";
+    befehl += karteId;
+    lock();
+    if( !datenbank->befehl( befehl ) )
+    {
+        unlock();
+        return 0;
+    }
+    int anz = datenbank->getZeilenAnzahl();
+    unlock();
+    if( !anz )
+        return 0;
+    return 1;
+}
+
+// constant
+Text *KSDatenbank::getLetzterFehler() const
+{
+    return datenbank->getLetzterFehler();
+}
+
+// Reference Counting
+KSDatenbank *KSDatenbank::getThis()
+{
+    ref++;
+    return this;
+}
+
+KSDatenbank *KSDatenbank::release()
+{
+    ref--;
+    if( !ref )
+        delete this;
+    return 0;
+}

+ 59 - 0
KartenServer/Datenbank.h

@@ -0,0 +1,59 @@
+#ifndef Datenbank_H
+#define Datenbank_H
+
+#include <sql.h>
+#include <Text.h>
+#include <Array.h>
+#include <InitDatei.h>
+
+using namespace Framework;
+using namespace sql;
+
+namespace Admin_Recht
+{
+	const int KSStarten = 0x00000036;
+	const int KSBeenden = 0x00000037;
+	const int KSPausieren = 0x00000038;
+	const int KSMKChange = 0x00000039;
+}
+
+struct AHDaten;
+
+class KSDatenbank
+{
+private:
+	Datenbank *datenbank;
+	CRITICAL_SECTION cs;
+	int ref;
+
+public:
+	// Konstruktor
+	KSDatenbank( InitDatei *zIni );
+	// Destruktor
+	~KSDatenbank();
+	// nicht constant
+	void lock();
+	void unlock();
+	int istAdministrator( const char *name, const char *passwort );
+	bool adminHatRecht( int id, int recht );
+	bool proveKlient( int num, int sNum );
+	Text *getKlientKey( int cId );
+	void unregisterKlient( int num, int sNum );
+	bool serverAnmelden( InitDatei *zIni );
+	bool setServerStatus( int id, int status );
+	bool setMaxKarten( int id, int maxK );
+	int getAdminPort( int id );
+	bool serverIstNichtPausiert( int id );
+	bool proveKarte( int id, int sNum );
+    int getUpdateKarte( int serverId );
+    bool endUpdateKarte( int karteId );
+    bool getEditorServerPortIp( int karteId, int *port, Text *ip );
+    bool setKarteSpielerAnzahl( int karteId, int sAnz );
+	// constant
+	Text *getLetzterFehler() const;
+	// Reference Counting
+	KSDatenbank *getThis();
+	KSDatenbank *release();
+};
+
+#endif

+ 1107 - 0
KartenServer/KartenServer.cpp

@@ -0,0 +1,1107 @@
+#include "KartenServer.h"
+#include <iostream>
+#include <Klient.h>
+#include <Globals.h>
+
+// Inhalt der KartenServer Klasse aus KartenServer.h
+// Konstruktor 
+KartenServer::KartenServer( InitDatei *zIni )
+    : Thread()
+{
+    Network::Start( 100 );
+    std::cout << "KS: Verbindung mit Datenbank wird hergestellt...\n";
+    db = new KSDatenbank( zIni );
+    klientAnzahl = 0;
+    klients = new RCArray< KSKlient >();
+    empfangen = 0;
+    gesendet = 0;
+    fehler = new Text();
+    ini = zIni->getThis();
+    if( !db->serverAnmelden( zIni ) )
+    {
+        std::cout << "KS: Der Server konnte nicht in die Datenbank eingetragen werden:\n";
+        Text *txt = db->getLetzterFehler();
+        std::cout << txt->getText() << "\nDas Programm wird beendet.";
+        txt->release();
+        exit( 1 );
+    }
+    id = *zIni->zWert( "ServerId" );
+    server = new Server();
+    aServer = new Server();
+    std::cout << "KS: Starten des Admin Servers...\n";
+    if( !aServer->verbinde( (unsigned short)db->getAdminPort( id ), 10 ) )
+    {
+        std::cout << "KS: Der Admin Server konnte nicht gestartet werden. Das Programm wird beendet.\n";
+        exit( 1 );
+    }
+    db->setServerStatus( id, 2 );
+    end = 0;
+    nichtPausiert = 0;
+    updateKarte = 0;
+    InitializeCriticalSection( &cs );
+    ref = 1;
+    if( zIni->zWert( "Aktiv" )->istGleich( "TRUE" ) )
+    {
+        serverStarten();
+        serverFortsetzen();
+    }
+    updater = new Updater( getThis() );
+}
+
+// Destruktor 
+KartenServer::~KartenServer()
+{
+    updater->release();
+    fehler->release();
+    server->trenne();
+    server->release();
+    aServer->trenne();
+    aServer->release();
+    if( klients )
+        klients->release();
+    ini->release();
+    db->release();
+    DeleteCriticalSection( &cs );
+}
+
+// nicht constant 
+void KartenServer::runn()
+{
+    while( !end )
+    {
+        SKlient *klient;
+        klient = aServer->getKlient();
+        if( end && klient )
+        {
+            klient->trenne();
+            klient = klient->release();
+            Sleep( 1000 );
+            return;
+        }
+        if( !klient )
+            return;
+        KSAKlient *clHandle = new KSAKlient( klient, getThis() );
+        clHandle->start();
+    }
+}
+
+void KartenServer::thread()
+{
+    while( 1 )
+    {
+        SKlient *klient;
+        klient = server->getKlient();
+        if( !klient )
+            break;
+		Framework::getThreadRegister()->cleanUpClosedThreads();
+        KSKlient *clHandle = new KSKlient( klient, getThis() );
+        EnterCriticalSection( &cs );
+        klients->set( clHandle, klientAnzahl );
+        klientAnzahl++;
+        LeaveCriticalSection( &cs );
+        clHandle->start();
+    }
+}
+
+void KartenServer::close()
+{
+    db->setServerStatus( id, 1 );
+    server->trenne();
+#ifdef WIN32
+    warteAufThread( 1000 );
+#endif
+    EnterCriticalSection( &cs );
+    for( int i = 0; i < klientAnzahl; i++ )
+        klients->z( i )->absturz();
+    klients = klients->release();
+    klientAnzahl = 0;
+    LeaveCriticalSection( &cs );
+    ende();
+    run = 0;
+    end = 1;
+    Klient *klient = new Klient();
+    klient->verbinde( aServer->getPort(), "127.0.0.1" );
+    Sleep( 500 );
+    aServer->trenne();
+    klient->release();
+}
+
+bool KartenServer::serverStarten()
+{
+    if( nichtPausiert )
+    {
+        fehler->setText( "Der Server konnte nicht gestartet werden: Der Server läuft bereits." );
+        return 0;
+    }
+    if( server )
+        server->release();
+    server = new Server();
+    if( server->verbinde( (unsigned short)TextZuInt( ini->zWert( "ServerPort" )->getText(), 10 ), 10 ) )
+    {
+        nichtPausiert = 1;
+        start();
+        return 1;
+    }
+    else
+    {
+        serverBeenden();
+        fehler->setText( "Der Server konnte nicht gestartet werden: Eventuell ist der Port in benutzung." );
+        return 0;
+    }
+}
+
+bool KartenServer::serverPause()
+{
+    if( !nichtPausiert )
+    {
+        fehler->setText( "Der Server konnte nicht pausiert werden: Der Server läuft nicht." );
+        return 0;
+    }
+    if( !db->setServerStatus( id, 2 ) )
+    {
+        fehler->setText( "Der Server konnte nicht pausiert werden: " );
+        fehler->append( db->getLetzterFehler() );
+        return 0;
+    }
+    return 1;
+}
+
+bool KartenServer::serverFortsetzen()
+{
+    if( !nichtPausiert )
+    {
+        fehler->setText( "Der Server konnte nicht fortgesetzt werden: Der Server läuft nicht." );
+        return 0;
+    }
+    if( !db->setServerStatus( id, 3 ) )
+    {
+        fehler->setText( "Der Server konnte nicht fortgesetzt werden: " );
+        fehler->append( db->getLetzterFehler() );
+        return 0;
+    }
+    return 1;
+}
+
+bool KartenServer::serverBeenden()
+{
+    if( !nichtPausiert )
+    {
+        fehler->setText( "Der Server konnte nicht beendet werden: Der Server läuft nicht." );
+        return 0;
+    }
+    if( db->serverIstNichtPausiert( id ) )
+    {
+        fehler->setText( "Der Server konnte nicht beendet werden: Der Server muss erst pausiert werden." );
+        return 0;
+    }
+    nichtPausiert = 0;
+    ende();
+    if( server )
+        server->trenne();
+    return 1;
+}
+
+bool KartenServer::setMaxKarten( int mk )
+{
+    if( !db->setMaxKarten( id, mk ) )
+    {
+        fehler->setText( "Die maximale Anzahl der Karten konnte nicht gesetzt werden:\n" );
+        fehler->append( db->getLetzterFehler() );
+        return 0;
+    }
+    ini->setWert( "MaxKarten", Text() += mk );
+    return 1;
+}
+
+bool KartenServer::absturzKlient( int klientId )
+{
+    bool gefunden = 0;
+    EnterCriticalSection( &cs );
+    for( int i = 0; i < klientAnzahl; i++ )
+    {
+        if( klients->z( i )->getKlientNummer() == klientId )
+        {
+            klients->z( i )->absturz();
+            klients->remove( i );
+            klientAnzahl--;
+            gefunden = 1;
+            break;
+        }
+    }
+    LeaveCriticalSection( &cs );
+    return gefunden;
+}
+
+bool KartenServer::removeKlient( KSKlient *zKlient )
+{
+    bool gefunden = 0;
+    EnterCriticalSection( &cs );
+    for( int i = 0; i < klientAnzahl; i++ )
+    {
+        if( klients->z( i ) == zKlient )
+        {
+            klients->remove( i );
+            klientAnzahl--;
+            gefunden = 1;
+            break;
+        }
+    }
+    LeaveCriticalSection( &cs );
+    return gefunden;
+}
+
+void KartenServer::addGesendet( int bytes )
+{
+    gesendet += bytes;
+}
+
+void KartenServer::addEmpfangen( int bytes )
+{
+    empfangen += bytes;
+}
+
+void KartenServer::karteUpdateStart( int karteId )
+{
+    updateKarte = karteId;
+}
+
+void KartenServer::karteUpdateEnde()
+{
+    updateKarte = 0;
+}
+
+// constant 
+bool KartenServer::istAn() const
+{
+    return db->serverIstNichtPausiert( id );
+}
+
+Server *KartenServer::zServer() const
+{
+    return server;
+}
+
+KSDatenbank *KartenServer::zDB() const
+{
+    return db;
+}
+
+InitDatei *KartenServer::zIni() const
+{
+    return ini;
+}
+
+bool KartenServer::hatClients() const
+{
+    return klientAnzahl > 0;
+}
+
+int KartenServer::getId() const
+{
+    return id;
+}
+
+char *KartenServer::getLetzterFehler() const
+{
+    return fehler->getText();
+}
+
+bool KartenServer::wirdKarteGeupdatet( int id ) const
+{
+    return id == updateKarte;
+}
+
+// Reference Counting
+KartenServer *KartenServer::getThis()
+{
+    ref++;
+    return this;
+}
+
+KartenServer *KartenServer::release()
+{
+    ref--;
+    if( !ref )
+        delete this;
+    return 0;
+}
+
+
+// Inhalt der KSAKlient Klasse aus KartenServer.h
+// Konstruktor 
+KSAKlient::KSAKlient( SKlient *klient, KartenServer *ks )
+    : Thread()
+{
+    this->klient = klient;
+    unsigned char key[ 20 ] = { 179, 126, 247, 108, 30, 201, 180, 160, 131, 216, 16, 47, 42, 31, 193, 200, 157, 86, 175, 133 };
+    klient->setSendeKey( (char*)key, 20 );
+    klient->setEmpfangKey( (char*)key, 20 );
+    name = new Text( "" );
+    passwort = new Text( "" );
+    adminId = 0;
+    this->ks = ks;
+}
+
+// Destruktor 
+KSAKlient::~KSAKlient()
+{
+    klient->trenne();
+    klient->release();
+    ks->release();
+    name->release();
+    passwort->release();
+}
+
+// nicht constant 
+void KSAKlient::thread()
+{
+    while( 1 )
+    {
+        char c = 0;
+        if( !klient->getNachrichtEncrypted( &c, 1 ) )
+            break;
+        else
+        {
+            bool br = 0;
+            switch( c )
+            {
+            case 1: // Login
+                if( 1 )
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    char nLen = 0;
+                    klient->getNachrichtEncrypted( &nLen, 1 );
+                    char *n = new char[ nLen + 1 ];
+                    n[ (int)nLen ] = 0;
+                    if( nLen )
+                        klient->getNachrichtEncrypted( n, nLen );
+                    char pLen = 0;
+                    klient->getNachrichtEncrypted( &pLen, 1 );
+                    char *p = new char[ pLen + 1 ];
+                    p[ (int)pLen ] = 0;
+                    if( pLen )
+                        klient->getNachrichtEncrypted( p, pLen );
+                    int adminId = ks->zDB()->istAdministrator( n, p );
+                    if( adminId )
+                    {
+                        klient->sendeEncrypted( "\1", 1 );
+                        name->setText( n );
+                        passwort->setText( p );
+                        this->adminId = adminId;
+                    }
+                    else
+                        errorZuKlient( "Falsche Kombination aus Name und Passwort." );
+                    delete[] n;
+                    delete[] p;
+                }
+                break;
+            case 2: // Logout
+                adminId = 0;
+                name->setText( "" );
+                passwort->setText( "" );
+                klient->sendeEncrypted( "\1", 1 );
+                break;
+            case 3: // Trennen
+                br = 1;
+                klient->sendeEncrypted( "\1", 1 );
+                break;
+            case 4: // Server starten
+                if( !adminId )
+                    errorZuKlient( "Du musst dich einloggen." );
+                else
+                {
+                    if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSStarten ) )
+                    {
+                        if( !ks->serverStarten() )
+                        {
+                            Text *err = new Text();
+                            err->append( ks->getLetzterFehler() );
+                            errorZuKlient( err->getText() );
+                            err->release();
+                        }
+                        else
+                            klient->sendeEncrypted( "\1", 1 );
+                    }
+                    else
+                        errorZuKlient( "Du bist nicht berechtigt den Server zu starten." );
+                }
+                break;
+            case 5: // Server beenden
+                if( !adminId )
+                    errorZuKlient( "Du musst dich einloggen." );
+                else
+                {
+                    if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSBeenden ) )
+                    {
+                        if( ks->serverBeenden() )
+                            klient->sendeEncrypted( "\1", 1 );
+                        else
+                        {
+                            Text *err = new Text();
+                            err->append( ks->getLetzterFehler() );
+                            errorZuKlient( err->getText() );
+                            err->release();
+                        }
+                    }
+                    else
+                        errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
+                }
+                break;
+            case 6: // Programm Schließen
+                if( !adminId )
+                    errorZuKlient( "Du musst dich einloggen." );
+                else
+                {
+                    bool ok = 0;
+                    if( ks->isRunning() )
+                    {
+                        if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSBeenden ) )
+                        {
+                            if( ks->serverBeenden() )
+                                ok = 1;
+                            else
+                            {
+                                Text *err = new Text();
+                                err->append( ks->getLetzterFehler() );
+                                errorZuKlient( err->getText() );
+                                err->release();
+                            }
+                        }
+                        else
+                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
+                    }
+                    else
+                        ok = 1;
+                    if( ok && ks->hatClients() )
+                    {
+                        errorZuKlient( "Es sind noch Klients Online. Bitte versuche es später erneut." );
+                        break;
+                    }
+                    if( ok )
+                    {
+                        klient->sendeEncrypted( "\1", 1 );
+                        std::cout << "KS: Der Server wird von Benutzer " << adminId << " heruntergefahren.\n";
+                        ks->close();
+                        br = 1;
+                    }
+                }
+                break;
+            case 7: // Progtamm abstürzen
+                if( !adminId )
+                    errorZuKlient( "Du musst dich einloggen." );
+                else
+                {
+                    bool ok = 0;
+                    if( ks->isRunning() )
+                    {
+                        if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSBeenden ) )
+                        {
+                            ks->serverBeenden();
+                            ok = 1;
+                        }
+                        else
+                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
+                    }
+                    else
+                        ok = 1;
+                    if( ok )
+                    {
+                        klient->sendeEncrypted( "\1", 1 );
+                        std::cout << "KS: Der Server wurde von Benutzer " << adminId << " terminiert.\n";
+                        ks->close();
+                        br = 1;
+                    }
+                }
+                break;
+            case 8: // Status Frage
+                if( 1 )
+                {
+                    char status = 0;
+                    if( ks->isRunning() )
+                    {
+                        status = 1;
+                        if( ks->istAn() )
+                            status = 2;
+                    }
+                    klient->sendeEncrypted( "\1", 1 );
+                    klient->sendeEncrypted( &status, 1 );
+                }
+                break;
+            case 9: // Server pausieren
+                if( !adminId )
+                    errorZuKlient( "Du musst dich einloggen." );
+                else
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    char pause = 0;
+                    klient->getNachrichtEncrypted( &pause, 1 );
+                    if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSPausieren ) )
+                    {
+                        bool ok = 0;
+                        if( pause )
+                            ok = ks->serverPause();
+                        else
+                            ok = ks->serverFortsetzen();
+                        if( ok )
+                            klient->sendeEncrypted( "\1", 1 );
+                        else
+                        {
+                            Text *err = new Text();
+                            err->append( ks->getLetzterFehler() );
+                            errorZuKlient( err->getText() );
+                            err->release();
+                        }
+                    }
+                    else
+                    {
+                        if( pause )
+                            errorZuKlient( "Du bist nicht berechtigt den Server zu pausieren." );
+                        else
+                            errorZuKlient( "Du bist nicht berechtigt den Server fortzusetzen." );
+                    }
+                }
+                break;
+            case 0xA: // maximale Anzahl der Clients setzen
+                if( !adminId )
+                    errorZuKlient( "Du musst dich einloggen." );
+                else
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    int maxK = 0;
+                    klient->getNachrichtEncrypted( (char*)&maxK, 4 );
+                    if( ks->zDB()->adminHatRecht( adminId, Admin_Recht::KSMKChange ) )
+                    {
+                        if( ks->setMaxKarten( maxK ) )
+                            klient->sendeEncrypted( "\1", 1 );
+                        else
+                        {
+                            Text *err = new Text();
+                            err->append( ks->getLetzterFehler() );
+                            errorZuKlient( err->getText() );
+                            err->release();
+                        }
+                    }
+                    else
+                        errorZuKlient( "Du bist nicht berechtigt die maximale Anzahl der Karten zu verändern." );
+                }
+                break;
+            case 0xC: // klient absturtz
+                if( 1 )
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    int klientId = 0;
+                    klient->getNachrichtEncrypted( (char*)&klientId, 4 );
+                    if( klientId && ks->absturzKlient( klientId ) )
+                        klient->sendeEncrypted( "\1", 1 );
+                    else
+                        klient->sendeEncrypted( "\0", 1 );
+                }
+                break;
+            default:
+                errorZuKlient( "Unbekannte Nachricht!" );
+                break;
+            }
+            if( br )
+                break;
+            ks->addEmpfangen( klient->getDownloadBytes( 1 ) );
+            ks->addGesendet( klient->getUploadBytes( 1 ) );
+        }
+    }
+    ks->addEmpfangen( klient->getDownloadBytes( 1 ) );
+    ks->addGesendet( klient->getUploadBytes( 1 ) );
+    delete this;
+}
+
+void KSAKlient::errorZuKlient( const char *nachricht ) const // sendet eine Fehlernachricht zum Klient
+{
+    klient->sendeEncrypted( "\3", 1 );
+    char len = (char)textLength( nachricht );
+    klient->sendeEncrypted( &len, 1 );
+    klient->sendeEncrypted( nachricht, len );
+}
+
+
+// Inhalt der KSKlient aus KartenServer.h
+// Konstruktor 
+KSKlient::KSKlient( SKlient *klient, KartenServer *ks )
+    : Thread()
+{
+    this->klient = klient;
+    unsigned char key[ 20 ] = { 24, 15, 53, 87, 38, 73, 154, 38, 246, 90, 39, 133, 11, 199, 22, 80, 26, 132, 95, 54 };
+    klient->setSendeKey( (char*)key, 20 );
+    klient->setEmpfangKey( (char*)key, 20 );
+    klientNummer = 0;
+    this->ks = ks;
+    ref = 1;
+}
+
+// Destruktor 
+KSKlient::~KSKlient()
+{
+    klient->release();
+    ks->release();
+}
+
+// privat
+void KSKlient::suchDateien( const char *pf, RCArray< Text > *zDL, const char *rem )
+{
+    Datei d;
+    d.setDatei( pf );
+    if( d.istOrdner() )
+    {
+        RCArray< Text > *list = d.getDateiListe();
+        if( list )
+        {
+            int anz = list->getEintragAnzahl();
+            for( int i = 0; i < anz; i++ )
+            {
+                Text pfad = pf;
+                pfad += "/";
+                pfad += list->z( i )->getText();
+                suchDateien( pfad, zDL, rem );
+            }
+            list->release();
+        }
+    }
+    else
+    {
+        Text *pfad = new Text( pf );
+        pfad->remove( 0, textLength( rem ) );
+        zDL->add( pfad );
+    }
+}
+
+// nicht constant
+void KSKlient::absturz()
+{
+    ende();
+    klient->trenne();
+    ks->zDB()->unregisterKlient( klientNummer, ks->getId() );
+}
+
+void KSKlient::thread()
+{
+    while( 1 )
+    {
+        char c = 0;
+        if( !klient->getNachrichtEncrypted( &c, 1 ) )
+            break;
+        else
+        {
+            bool br = 0;
+            switch( c )
+            {
+            case 1: // Klient identifikation
+                klient->getNachrichtEncrypted( (char*)&klientNummer, 4 );
+                if( !ks->zDB()->proveKlient( klientNummer, ks->getId() ) )
+                {
+                    klientNummer = 0;
+                    errorZuKlient( "Du bist nicht für diesen Server eingetragen" );
+                }
+                else
+                {
+                    Text *key = ks->zDB()->getKlientKey( klientNummer );
+                    if( !key )
+                        errorZuKlient( "Es konnte kein Schlüssel ermittelt werden." );
+                    else
+                    {
+                        klient->sendeEncrypted( "\1", 1 );
+                        klient->setEmpfangKey( *key, key->getLength() );
+                        klient->setSendeKey( *key, key->getLength() );
+                        key->release();
+                    }
+                }
+                break;
+            case 2: // Main / Erhaltung Server message
+                if( 1 )
+                {
+                    char befehl = 0;
+                    klient->getNachrichtEncrypted( &befehl, 1 );
+                    switch( befehl )
+                    {
+                    case 2: // klient absturtz
+                        if( 1 )
+                        {
+                            int klientId = 0;
+                            klient->getNachrichtEncrypted( (char*)&klientId, 4 );
+                            if( klientId && ks->absturzKlient( klientId ) )
+                                klient->sendeEncrypted( "\1", 1 );
+                            else
+                                klient->sendeEncrypted( "\0", 1 );
+                        }
+                        break;
+                    default:
+                        errorZuKlient( "Befehl nicht bekannt!" );
+                        break;
+                    }
+                }
+                break;
+            case 3: // Verbindungsende
+                br = 1;
+                klient->sendeEncrypted( "\1", 1 );
+                break;
+            case 4: // unregister Klient
+                if( !klientNummer )
+                {
+                    errorZuKlient( "Du bist nicht Identifiziert." );
+                    break;
+                }
+                ks->zDB()->unregisterKlient( klientNummer, ks->getId() );
+                klient->sendeEncrypted( "\1", 1 );
+                break;
+            case 5: // keep alive
+                if( !klientNummer )
+                {
+                    errorZuKlient( "Du bist nicht Identifiziert." );
+                    break;
+                }
+                klient->sendeEncrypted( "\1", 1 );
+                break;
+            case 6: // download Karte (Klient)
+                if( !klientNummer )
+                {
+                    errorZuKlient( "Du bist nicht Identifiziert." );
+                    break;
+                }
+                else
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    int id = 0;
+                    klient->getNachrichtEncrypted( (char*)&id, 4 );
+                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
+                    {
+                        errorZuKlient( "Die Karte wurde nicht gefunden." );
+                        break;
+                    }
+                    if( ks->wirdKarteGeupdatet( id ) )
+                    {
+                        char c = 2;
+                        klient->sendeEncrypted( &c, 1 );
+                        break;
+                    }
+                    klient->sendeEncrypted( "\1", 1 );
+                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
+                    pfad += "/";
+                    pfad += id;
+                    pfad += "/client/map";
+                    RCArray< Text > *dList = new RCArray< Text >();
+                    suchDateien( pfad, dList, pfad );
+                    int anz = dList->getEintragAnzahl();
+                    klient->sendeEncrypted( (char*)&anz, 4 );
+                    for( int i = 0; i < anz; i++ )
+                    {
+                        Text pf = dList->z( i )->getText();
+                        unsigned char len = (unsigned char)pf.getLength();
+                        Text dp = pf.getText();
+                        dp.insert( 0, (char*)pfad );
+                        Datei d;
+                        d.setDatei( dp );
+                        if( !len || !d.open( Datei::Style::lesen ) )
+                        {
+                            klient->sendeEncrypted( "\0", 1 );
+                            continue;
+                        }
+                        klient->sendeEncrypted( (char*)&len, 1 );
+                        klient->sendeEncrypted( pf, len );
+                        __int64 size = d.getSize();
+                        klient->sendeEncrypted( (char*)&size, 8 );
+                        char *buffer = new char[ 2048 ];
+                        while( size )
+                        {
+                            int l = size >= 2048 ? 2048 : (int)size;
+                            d.lese( buffer, l );
+                            klient->sende( buffer, l );
+                            size -= l;
+                        }
+                        delete[] buffer;
+                        d.close();
+                    }
+                    dList->release();
+                }
+                break;
+            case 7: // download Karte (Server)
+                if( klientNummer )
+                {
+                    errorZuKlient( "Du bist nicht berechtigt." );
+                    break;
+                }
+                else
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    int id = 0;
+                    klient->getNachrichtEncrypted( (char*)&id, 4 );
+                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
+                    {
+                        errorZuKlient( "Die Karte wurde nicht gefunden." );
+                        break;
+                    }
+                    if( ks->wirdKarteGeupdatet( id ) )
+                    {
+                        char c = 2;
+                        klient->sendeEncrypted( &c, 1 );
+                        break;
+                    }
+                    klient->sendeEncrypted( "\1", 1 );
+                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
+                    pfad += "/";
+                    pfad += id;
+                    pfad += "/server";
+                    RCArray< Text > *dList = new RCArray< Text >();
+                    suchDateien( pfad, dList, pfad );
+                    int anz = dList->getEintragAnzahl();
+                    klient->sendeEncrypted( (char*)&anz, 4 );
+                    for( int i = 0; i < anz; i++ )
+                    {
+                        Text pf = dList->z( i )->getText();
+                        unsigned char len = (unsigned char)pf.getLength();
+                        Text dp = pf.getText();
+                        dp.insert( 0, (char*)pfad );
+                        Datei d;
+                        d.setDatei( dp );
+                        if( !len || !d.open( Datei::Style::lesen ) )
+                            continue;
+                        klient->sendeEncrypted( (char*)&len, 1 );
+                        klient->sendeEncrypted( pf, len );
+                        __int64 size = d.getSize();
+                        klient->sendeEncrypted( (char*)&size, 8 );
+                        char *buffer = new char[ 2048 ];
+                        while( size )
+                        {
+                            int l = size >= 2048 ? 2048 : (int)size;
+                            d.lese( buffer, l );
+                            klient->sende( buffer, l );
+                            size -= l;
+                        }
+                        delete[] buffer;
+                        d.close();
+                    }
+                    dList->release();
+                }
+                break;
+            case 8: // Karte Titel Bild laden
+                if( !klientNummer )
+                {
+                    errorZuKlient( "Du bist nicht Identifiziert." );
+                    break;
+                }
+                else
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    int id = 0;
+                    klient->getNachrichtEncrypted( (char*)&id, 4 );
+                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
+                    {
+                        errorZuKlient( "Die Karte wurde nicht gefunden." );
+                        break;
+                    }
+                    if( ks->wirdKarteGeupdatet( id ) )
+                    {
+                        char c = 2;
+                        klient->sendeEncrypted( &c, 1 );
+                        break;
+                    }
+                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
+                    pfad += "/";
+                    pfad += id;
+                    pfad += "/client/titel.ltdb";
+                    Datei d;
+                    d.setDatei( pfad );
+                    if( d.open( Datei::Style::lesen ) )
+                        klient->sendeEncrypted( "\1", 1 );
+                    else
+                        errorZuKlient( "Fehler beim lesen der Datei." );
+                    __int64 size = d.getSize();
+                    klient->sendeEncrypted( (char*)&size, 8 );
+                    char *buffer = new char[ 2048 ];
+                    while( size )
+                    {
+                        int l = size >= 2048 ? 2048 : (int)size;
+                        d.lese( buffer, l );
+                        klient->sende( buffer, l );
+                        size -= l;
+                    }
+                    delete[] buffer;
+                    d.close();
+                }
+                break;
+            case 9: // Karte Beschreibung
+                if( !klientNummer )
+                {
+                    errorZuKlient( "Du bist nicht Identifiziert." );
+                    break;
+                }
+                else
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    int id = 0;
+                    klient->getNachrichtEncrypted( (char*)&id, 4 );
+                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
+                    {
+                        errorZuKlient( "Die Karte wurde nicht gefunden." );
+                        break;
+                    }
+                    if( ks->wirdKarteGeupdatet( id ) )
+                    {
+                        char c = 2;
+                        klient->sendeEncrypted( &c, 1 );
+                        break;
+                    }
+                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
+                    pfad += "/";
+                    pfad += id;
+                    pfad += "/client/beschreibung.ksgs";
+                    Datei d;
+                    d.setDatei( pfad );
+                    if( d.open( Datei::Style::lesen ) )
+                        klient->sendeEncrypted( "\1", 1 );
+                    else
+                        errorZuKlient( "Fehler beim lesen der Datei." );
+                    __int64 size = d.getSize();
+                    klient->sendeEncrypted( (char*)&size, 8 );
+                    char *buffer = new char[ 2048 ];
+                    while( size )
+                    {
+                        int l = size >= 2048 ? 2048 : (int)size;
+                        d.lese( buffer, l );
+                        klient->sende( buffer, l );
+                        size -= l;
+                    }
+                    delete[] buffer;
+                    d.close();
+                }
+                break;
+            case 10: // Karte Minimap
+                if( !klientNummer )
+                {
+                    errorZuKlient( "Du bist nicht Identifiziert." );
+                    break;
+                }
+                else
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    int id = 0;
+                    klient->getNachrichtEncrypted( (char*)&id, 4 );
+                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
+                    {
+                        errorZuKlient( "Die Karte wurde nicht gefunden." );
+                        break;
+                    }
+                    if( ks->wirdKarteGeupdatet( id ) )
+                    {
+                        char c = 2;
+                        klient->sendeEncrypted( &c, 1 );
+                        break;
+                    }
+                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
+                    pfad += "/";
+                    pfad += id;
+                    pfad += "/client/minimap.ltdb";
+                    Datei d;
+                    d.setDatei( pfad );
+                    if( d.open( Datei::Style::lesen ) )
+                        klient->sendeEncrypted( "\1", 1 );
+                    else
+                        errorZuKlient( "Fehler beim lesen der Datei." );
+                    __int64 size = d.getSize();
+                    klient->sendeEncrypted( (char*)&size, 8 );
+                    char *buffer = new char[ 2048 ];
+                    while( size )
+                    {
+                        int l = size >= 2048 ? 2048 : (int)size;
+                        d.lese( buffer, l );
+                        klient->sende( buffer, l );
+                        size -= l;
+                    }
+                    delete[] buffer;
+                    d.close();
+                }
+                break;
+            case 11: // Karte Ladebild
+                if( !klientNummer )
+                {
+                    errorZuKlient( "Du bist nicht Identifiziert." );
+                    break;
+                }
+                else
+                {
+                    klient->sendeEncrypted( "\1", 1 );
+                    int id = 0;
+                    klient->getNachrichtEncrypted( (char*)&id, 4 );
+                    if( !ks->zDB()->proveKarte( id, ks->getId() ) )
+                    {
+                        errorZuKlient( "Die Karte wurde nicht gefunden." );
+                        break;
+                    }
+                    if( ks->wirdKarteGeupdatet( id ) )
+                    {
+                        char c = 2;
+                        klient->sendeEncrypted( &c, 1 );
+                        break;
+                    }
+                    Text pfad = ks->zIni()->zWert( "KartenPfad" )->getText();
+                    pfad += "/";
+                    pfad += id;
+                    pfad += "/client/ladebild.ltdb";
+                    Datei d;
+                    d.setDatei( pfad );
+                    if( d.open( Datei::Style::lesen ) )
+                        klient->sendeEncrypted( "\1", 1 );
+                    else
+                        errorZuKlient( "Fehler beim lesen der Datei." );
+                    __int64 size = d.getSize();
+                    klient->sendeEncrypted( (char*)&size, 8 );
+                    char *buffer = new char[ 2048 ];
+                    while( size )
+                    {
+                        int l = size >= 2048 ? 2048 : (int)size;
+                        d.lese( buffer, l );
+                        klient->sende( buffer, l );
+                        size -= l;
+                    }
+                    delete[] buffer;
+                    d.close();
+                }
+                break;
+            default:
+                errorZuKlient( "Unbekannte Nachricht!" );
+                break;
+            }
+            if( br )
+                break;
+            ks->addEmpfangen( klient->getDownloadBytes( 1 ) );
+            ks->addGesendet( klient->getUploadBytes( 1 ) );
+        }
+    }
+    ks->addEmpfangen( klient->getDownloadBytes( 1 ) );
+    ks->addGesendet( klient->getUploadBytes( 1 ) );
+    ks->removeKlient( this ); // delete this
+}
+
+// constant
+void KSKlient::errorZuKlient( const char *nachricht ) const // sendet eine Fehlernachricht zum Klient
+{
+    klient->sendeEncrypted( "\3", 1 );
+    char len = (char)textLength( nachricht );
+    klient->sendeEncrypted( &len, 1 );
+    klient->sendeEncrypted( nachricht, len );
+}
+
+int KSKlient::getKlientNummer() const // gibt die KlientId zurück
+{
+    return klientNummer;
+}
+
+// Reference Counting
+KSKlient *KSKlient::getThis()
+{
+    ref++;
+    return this;
+}
+
+KSKlient *KSKlient::release()
+{
+    ref--;
+    if( !ref )
+        delete this;
+    return 0;
+}

+ 116 - 0
KartenServer/KartenServer.h

@@ -0,0 +1,116 @@
+#ifndef KartenServer_H
+#define KartenServer_H
+
+#include <Server.h>
+#include <Thread.h>
+#include <Datei.h>
+#include <Text.h>
+#include <InitDatei.h>
+#include "Datenbank.h"
+#include "Updater.h"
+
+using namespace Framework;
+using namespace Network;
+
+class KSKlient;
+
+class KartenServer : public Thread
+{
+private:
+	Server *server;
+	Server *aServer;
+	InitDatei *ini;
+	KSDatenbank *db;
+	CRITICAL_SECTION cs;
+	RCArray< KSKlient > *klients;
+    Text *fehler;
+    Updater *updater;
+    int updateKarte;
+	int klientAnzahl;
+	int id;
+	bool nichtPausiert;
+	int empfangen;
+	int gesendet;
+	bool end;
+	int ref;
+
+public:
+	// Konstruktor 
+	KartenServer( InitDatei *zIni );
+	// Destruktor 
+	virtual ~KartenServer();
+	// nicht constant 
+	void runn();
+	void thread();
+	void close();
+	bool serverStarten();
+	bool serverPause();
+	bool serverFortsetzen();
+	bool serverBeenden();
+	bool setMaxKarten( int mk );
+	bool absturzKlient( int klientId );
+	bool removeKlient( KSKlient *zKlient );
+	void addGesendet( int bytes );
+	void addEmpfangen( int bytes );
+    void karteUpdateStart( int karteId );
+    void karteUpdateEnde();
+	// conatant 
+	bool istAn() const;
+	Server *zServer() const;
+	KSDatenbank *zDB() const;
+	InitDatei *zIni() const;
+	bool hatClients() const;
+	int getId() const;
+	char *getLetzterFehler() const;
+    bool wirdKarteGeupdatet( int id ) const;
+	// Reference Counting
+	KartenServer *getThis();
+	KartenServer *release();
+};
+
+class KSAKlient : public Thread
+{
+private:
+	SKlient *klient;
+	Text *name;
+	Text *passwort;
+	int adminId;
+	KartenServer *ks;
+
+public:
+	// Konstruktor 
+	KSAKlient( SKlient *klient, KartenServer *ks );
+	// Destruktor 
+	virtual ~KSAKlient();
+	// nicht constant
+	void thread();
+	void errorZuKlient( const char *nachricht ) const; // sendet eine Fehlernachricht zum AKlient
+};
+
+class KSKlient : public Thread
+{
+private:
+	SKlient *klient;
+	unsigned int klientNummer;
+	KartenServer *ks;
+	int ref;
+
+    void suchDateien( const char *pf, RCArray< Text > *zDL, const char *rem );
+
+public:
+	// Konstruktor 
+	KSKlient( SKlient *klient, KartenServer *ks );
+	// Destruktor 
+	virtual ~KSKlient();
+	// nicht constant
+	void absturz();
+	void thread();
+	// constant
+	void errorZuKlient( const char *nachricht ) const; // sendet eine Fehlernachricht zum Klient
+	int getKlientNummer() const;
+	// Reference Counting
+	KSKlient *getThis();
+	KSKlient *release();
+};
+
+#endif

+ 74 - 0
KartenServer/KartenServer.vcxproj

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{d67b61d4-e858-4d71-8be6-a64561cd757c}</ProjectGuid>
+    <Keyword>Linux</Keyword>
+    <RootNamespace>KartenServer</RootNamespace>
+    <MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
+    <ApplicationType>Linux</ApplicationType>
+    <ApplicationTypeRevision>1.0</ApplicationTypeRevision>
+    <TargetLinuxPlatform>Generic</TargetLinuxPlatform>
+    <LinuxProjectType>{D51BCBC9-82E9-4017-911E-C93873C4EA2B}</LinuxProjectType>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <RemoteRootDir>/home/kolja/projects</RemoteRootDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <RemoteRootDir>/home/kolja/projects</RemoteRootDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings" />
+  <ImportGroup Label="Shared" />
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <TargetExt />
+    <RemoteProjectDir>$(RemoteRootDir)/Server/$(ProjectName)/Release</RemoteProjectDir>
+    <IncludePath>..\..\..\..\Allgemein\Framework;../../../Framework/Release;..\..\..\..\Allgemein\Network\Network;../../../Network/Release;..\..\..\..\Allgemein\sql\sql;../../../sql/Release;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <TargetExt />
+    <RemoteProjectDir>$(RemoteRootDir)/Server/$(ProjectName)/Debug</RemoteProjectDir>
+    <IncludePath>..\..\..\..\Allgemein\Framework;../../../Framework/Debug;..\..\..\..\Allgemein\Network\Network;../../../Network/Debug;..\..\..\..\Allgemein\sql\sql;../../../sql/Debug;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <ItemGroup>
+    <ClInclude Include="Datenbank.h" />
+    <ClInclude Include="KartenServer.h" />
+    <ClInclude Include="Updater.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="Datenbank.cpp" />
+    <ClCompile Include="KartenServer.cpp" />
+    <ClCompile Include="main.cpp" />
+    <ClCompile Include="Updater.cpp" />
+  </ItemGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Link>
+      <AdditionalLibraryDirectories>$(RemoteRootDir)/sql/Release/bin/x64/release;$(RemoteRootDir)/Network/Release/bin/x64/release;$(RemoteRootDir)/Framework/Release/bin/x64/release;/usr/lib/;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <LibraryDependencies>Framework;Network;SQL;pq;pthread</LibraryDependencies>
+      <AdditionalOptions>-Wl,-rpath,../lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Link>
+      <AdditionalLibraryDirectories>$(RemoteRootDir)/sql/Debug/bin/x64/debug;$(RemoteRootDir)/Network/Debug/bin/x64/debug;$(RemoteRootDir)/Framework/Debug/bin/x64/debug;/usr/lib/;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <LibraryDependencies>dbgFramework;dbgNetwork;dbgSQL;pq;pthread</LibraryDependencies>
+      <AdditionalOptions>-Wl,-rpath,../lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets" />
+</Project>

+ 36 - 0
KartenServer/KartenServer.vcxproj.filters

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Quelldateien">
+      <UniqueIdentifier>{5e581c00-491b-4fcf-bc57-54bd78586254}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Headerdateien">
+      <UniqueIdentifier>{9bc8f476-6b14-42ff-b1ab-00e6c352d9e1}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="Datenbank.h">
+      <Filter>Headerdateien</Filter>
+    </ClInclude>
+    <ClInclude Include="KartenServer.h">
+      <Filter>Headerdateien</Filter>
+    </ClInclude>
+    <ClInclude Include="Updater.h">
+      <Filter>Headerdateien</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="Datenbank.cpp">
+      <Filter>Quelldateien</Filter>
+    </ClCompile>
+    <ClCompile Include="KartenServer.cpp">
+      <Filter>Quelldateien</Filter>
+    </ClCompile>
+    <ClCompile Include="main.cpp">
+      <Filter>Quelldateien</Filter>
+    </ClCompile>
+    <ClCompile Include="Updater.cpp">
+      <Filter>Quelldateien</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

+ 169 - 0
KartenServer/Updater.cpp

@@ -0,0 +1,169 @@
+#include "KartenServer.h"
+#include <Klient.h>
+#include <iostream>
+
+// Inhalt der Updater Klasse aus Updater.h
+// Konstruktor
+Updater::Updater( KartenServer *kServ )
+    : Thread()
+{
+    ks = kServ;
+    beenden = 0;
+    ref = 1;
+    start();
+}
+
+// Destruktor
+Updater::~Updater()
+{
+    beenden = 1;
+    warteAufThread( 5000 );
+    if( isRunning() )
+        ende();
+    ks->release();
+}
+
+// nicht constant
+void Updater::thread()
+{
+    while( !beenden )
+    {
+        for( int i = 0; i < 60; i++ )
+        {
+            if( beenden )
+                break;
+            Sleep( 1000 );
+        }
+        if( beenden )
+            break;
+        int kId = ks->zDB()->getUpdateKarte( ks->getId() );
+        if( kId )
+        {
+            Text updatePf = ks->zIni()->zWert( "KartenPfad" )->getText();
+            updatePf += "/update";
+            DateiRemove( updatePf );
+            ks->karteUpdateStart( kId );
+            int port = 0;
+            Text ip = "";
+            if( !ks->zDB()->getEditorServerPortIp( kId, &port, &ip ) )
+            {
+                ks->karteUpdateEnde();
+                continue;
+            }
+            Klient *k = new Klient();
+            unsigned char key[ 20 ] = { 55, 124, 19, 204, 23, 5, 59, 75, 247, 138, 119, 111, 57, 250, 206, 187, 165, 6, 247, 151 };
+            k->setEmpfangKey( (char*)key, 20 );
+            k->setSendeKey( (char*)key, 20 );
+            char ret = 0;
+            if( !k->verbinde( (unsigned short)port, ip ) )
+            {
+                ks->karteUpdateEnde();
+                k = k->release();
+                std::cout << "KS: Updater: Fehler beim Updaten von Karte " << kId << ".\n Verbindung zum Editorserver konnte nicht hergestellt werden.\n";
+                continue;
+            }
+            k->sendeEncrypted( "\x9", 1 );
+            k->getNachrichtEncrypted( &ret, 1 );
+            if( ret == 1 )
+            {
+                k->sendeEncrypted( (char*)&kId, 4 );
+                k->getNachrichtEncrypted( &ret, 1 );
+                if( ret == 1 )
+                {
+                    int anz = 0;
+                    k->getNachrichtEncrypted( (char*)&anz, 4 );
+                    for( int i = 0; i < anz && !beenden; i++ )
+                    {
+                        char len = 0;
+                        k->getNachrichtEncrypted( &len, 1 );
+                        if( !len )
+                            continue;
+                        char *pfa = new char[ len + 1 ];
+                        pfa[ (int)len ] = 0;
+                        k->getNachrichtEncrypted( pfa, len );
+                        __int64 size = 0;
+                        k->getNachrichtEncrypted( (char*)&size, 8 );
+                        char *buffer = new char[ 2048 ];
+                        Text pfad = updatePf;
+                        pfad += pfa;
+                        delete[] pfa;
+                        Datei d;
+                        d.setDatei( pfad );
+                        d.erstellen();
+                        d.open( Datei::Style::schreiben );
+                        while( size )
+                        {
+                            int l = size >= 2048 ? 2048 : (int)size;
+                            k->getNachricht( buffer, l );
+                            d.schreibe( buffer, l );
+                            size -= l;
+                        }
+                        d.close();
+                        delete[] buffer;
+                    }
+                    if( beenden )
+                    {
+                        ks->karteUpdateEnde();
+                        k->sendeEncrypted( "\3", 1 );
+                        k->getNachrichtEncrypted( &ret, 1 );
+                        k->trenne();
+                        k->release();
+                        break;
+                    }
+                    Text neuPfad = ks->zIni()->zWert( "KartenPfad" )->getText();
+                    neuPfad += "/";
+                    neuPfad += kId;
+                    DateiRemove( neuPfad );
+                    DateiUmbenennen( updatePf, neuPfad );
+                    Text stsPf = neuPfad.getText();
+                    stsPf += "/server/sts.ltgd";
+                    Datei sts;
+                    sts.setDatei( stsPf );
+                    sts.open( Datei::Style::lesen );
+                    int sAnz = 0;
+                    sts.lese( (char*)&sAnz, 4 );
+                    sts.close();
+                    ks->zDB()->setKarteSpielerAnzahl( kId, sAnz );
+                }
+            }
+            if( ret == 3 )
+            {
+                ks->karteUpdateEnde();
+                char byte = 0;
+                k->getNachrichtEncrypted( &byte, 1 );
+                char *f = new char[ byte + 1 ];
+                f[ (int)byte ] = 0;
+                k->getNachrichtEncrypted( f, byte );
+                std::cout << "KS: Updater: Fehler beim Update von Karte " << kId << ".\n Meldung: " << f << "\n";
+                delete[] f;
+                k->sendeEncrypted( "\3", 1 );
+                k->getNachrichtEncrypted( &ret, 1 );
+                k->trenne();
+                k->release();
+                continue;
+            }
+            k->sendeEncrypted( "\3", 1 );
+            k->getNachrichtEncrypted( &ret, 1 );
+            k->trenne();
+            k->release();
+            ks->zDB()->endUpdateKarte( kId );
+            ks->karteUpdateEnde();
+        }
+    }
+    run = 0;
+}
+
+// Reference Counting
+Updater *Updater::getThis()
+{
+    ref++;
+    return this;
+}
+
+Updater *Updater::release()
+{
+    ref--;
+    if( !ref )
+        delete this;
+    return 0;
+}

+ 29 - 0
KartenServer/Updater.h

@@ -0,0 +1,29 @@
+#ifndef UPDATER_H
+#define UPDATER_H
+
+#include <Thread.h>
+
+using namespace Framework;
+
+class KartenServer;
+
+class Updater : private Thread
+{
+private:
+    KartenServer *ks;
+    bool beenden;
+    int ref;
+
+public:
+    // Konstruktor
+    Updater( KartenServer *kServ );
+    // Destruktor
+    virtual ~Updater();
+    // nicht constant
+    void thread() override;
+    // Reference Counting
+    Updater *getThis();
+    Updater *release();
+};
+
+#endif

+ 64 - 0
KartenServer/main.cpp

@@ -0,0 +1,64 @@
+#ifdef WIN32
+#include <main.h>
+#endif
+#include "KartenServer.h"
+#include <Zeit.h>
+#include <iostream>
+#include <fstream>
+#include <Globals.h>
+
+#ifdef WIN32
+int KSGStart Framework::Start( Startparam p )
+{
+#else
+int main()
+{
+    Framework::initFramework();
+#endif
+	Zeit *z = getZeit();
+	Text *pfad = new Text( "../log/karten/" );
+	pfad->append( z->getZeit( "y-m-d h-i-s.log" ) );
+	z->release();
+	DateiPfadErstellen( pfad->getThis() );
+	std::ofstream file;
+	file.open( pfad->getText() );
+	std::streambuf* sbuf = std::cout.rdbuf();
+	std::cout.rdbuf( file.rdbuf() );
+	pfad->release();
+
+	std::cout << "KS: Startet...\n";
+	std::cout << "KS: Lese init Datei ../data/ksInit.ini ...\n";
+	InitDatei *dat = new InitDatei( "../data/ksInit.ini" );
+	if( !dat->laden() )
+	{
+		std::cout << "KS: error: Datei konnte nicht gelesen werden. Das Programm wird geschlossen.\n";
+		dat->release();
+		exit( 1 );
+	}
+
+	if( dat->wertExistiert( "KartenPfad" ) )
+		dat->addWert( "KartenPfad", "karten" );
+	if( !DateiExistiert( dat->zWert( "KartenPfad" )->getText() ) )
+	{
+		Text pf = dat->zWert("KartenPfad")->getText();
+		pf += "/";
+		DateiPfadErstellen( pf );
+	}
+
+	KartenServer *kServer = new KartenServer( dat );
+
+	std::cout << "KS: Der Admin Server läuft. Startforgang beendet.\n";
+	kServer->runn();
+
+	kServer->ende();
+	kServer->release();
+	dat->speichern();
+	dat->release();
+	std::cout << "KS: Der Server ist heruntergefahren.\n";
+	file.close();
+	std::cout.rdbuf( sbuf );
+#ifndef WIN32
+    Framework::releaseFramework();
+#endif
+	return 0;
+}

BIN
KartenServer/readme/images/ArchOptions.gif


BIN
KartenServer/readme/images/ChangeRemote.gif


BIN
KartenServer/readme/images/ManageConnections.gif


BIN
KartenServer/readme/images/OutputTypes.gif


BIN
KartenServer/readme/images/debuggerexport.png


BIN
KartenServer/readme/images/firstconnection.png


BIN
KartenServer/readme/images/linker.png


BIN
KartenServer/readme/images/postbuild.png


+ 85 - 0
KartenServer/readme/readme.html

@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset='utf-8'>
+
+    <link rel="stylesheet" type="text/css" href="stylesheet.css" media="screen">
+
+    <title>Getting Started</title>
+  </head>
+
+<body>
+
+    <div class="container">
+        <div id="header">
+            <h1>Getting Started</h1>
+            <h2>Visual C++ for Linux Development extension</h2>
+        </div>
+    
+    <table>
+    <tr>    
+    <div id="main_content">
+        
+        <td>
+        <div id="lpanel">
+            <h1>Setting up your project for Linux Development</h1>
+
+            <p>With this extension you can author C++ code for Linux servers, desktops and devices. You can manage your connections to these machines from within VS. VS will automatically copy and remote build your sources and can launch your application with the debugger. Our project system supports targeting specific architectures, including ARM.</p>
+            <img src="images\ArchOptions.gif"/>
+            
+            <h1>Connecting to Linux</h1>
+            <h2>Prerequisites</h2>
+            <p>Today we only support building remotely on the Linux target machine. We are not limited by specific Linux distros but we do have dependencies on the presence of some tools. Specifically, we need openssh-server, g++, gdb and gdbserver. Use your favorite package manager to install them, e.g. on Debian based systems: sudo apt-get install openssh-server g++ gdb gdbserver</p>
+            
+            <h2>First connection</h2>
+            <p>The first time you target a Linux machine you will be prompted for connection information.  This is triggered by building the project.</p>
+            <img src="images\firstconnection.png"/>
+                
+            <h2>Adding and removing connections</h2>
+            <p>To add a new connection, go to Tools > Options and search for Linux. From here you can add and remove connections.</p>
+            <img src="images\ManageConnections.gif"/>
+            
+            <p>To change which connection a project is using go to the project properties remote settings and update the target machine.</p>
+            <img src="images\ChangeRemote.gif"/>
+            
+            <h1>Project Properties</h1>
+            <p>All of the options necessary to control C++ compilation are exposed on the project properies pages. We'll cover a few specific to how things work for Linux. First under remote settings, you will see the remote root is set to ~/projects/ by default and that we are setting the remote project directory to match our project name in that location. </p>
+            <img src="images\OutputTypes.gif"/>
+            
+            <p>Looking at the General settings for the project, you can see how our output and intermediate directories were configured. Additionally, you’ll see that this project was configured as an application – thus our executable is under bin/x64/Debug/ as ConsoleApplication1.out. Notice that for configuration types we also support static and dynamic libraries.</p>
+            
+            <p>Add additional library dependencies on the Linker > Input property page.</p>
+            <img src="images\linker.png"/>
+            
+            <p>You can pass additional pre launch commands to the debugger to do things like launch graphical apps on the remote linux machine.</p>
+            <img src="images\debuggerexport.png"/>
+            
+            <p>You can also send post build events to control remote behavior, as in this example that exports a gpio pin for use without requiring the executable run as super user.</p>
+            <img src="images\postbuild.png"/>
+            
+        </div>
+        </td>
+        <td>
+        <div id="rpanel">
+
+            <h1>Resources</h1>
+
+            <p>Check out the <a href="http://aka.ms/vslinuxext">VS Gallery VC++ for Linux Development page</a> where we will keep updates posted. You can also check out our <a href="https://blogs.msdn.microsoft.com/vcblog/2016/03/30/visual-c-for-linux-development">announcment blog post</a> for more in depth details on configuring the project properties.</p>
+            
+            <p>Here are other utilities you will find useful in connection with this extension.</p>
+            <ul>
+                <li>Learn more about <a href="http://aka.ms/vsiot">IoT Development</a></li>
+                <li><a href="http://aka.ms/vsiotext">VC++ for IoT Development Tools</a></li>
+                <li><a href="https://github.com/Azure/azure-iot-sdks">Azure IoT SDK</a>, includes a C API for connecting small devices to the Azure IoT Hub</li>
+            </ul>
+
+            <h1>Give us feedback</h1>
+            <p><a href="http://aka.ms/vslinux-feedback">UserVoice</a></p>
+        </div>
+        </td>   
+    </div>
+    </tr>
+    </table>
+    </div>
+</body>
+</html>

+ 119 - 0
KartenServer/readme/stylesheet.css

@@ -0,0 +1,119 @@
+body {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  color: #1E1E1E;
+  font-size: 13px;
+  font-family: "Segoe UI", Helvetica, Arial, sans-serif;
+  line-height: 1.45;
+  word-wrap: break-word;
+}
+
+/* General & 'Reset' Stuff */
+
+
+.container {
+  width: 1100px;
+  margin: 0 auto;
+}
+
+section {
+  display: block;
+  margin: 0;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  margin: 0;
+}
+
+table, tr {
+    width: 1100px;
+    padding: 0px;
+    vertical-align: top;
+  }
+
+/* Header, <header>
+   header   - container
+   h1       - project name
+   h2       - project description
+*/
+
+#header {
+  color: #FFF;
+  background: #68217a;
+  position:relative;
+}
+h1, h2 {
+  font-family: "Segoe UI Light", "Segoe UI", Helvetica, Arial, sans-serif;
+  line-height: 1;
+  margin: 0 18px;;
+  padding: 0;
+}
+#header h1 {
+  font-size: 3.4em;
+  padding-top: 18px;
+  font-weight: normal;
+  margin-left: 15px;
+}
+
+#header h2 {
+  font-size: 1.5em;
+  margin-top: 10px;
+  padding-bottom: 18px;
+  font-weight: normal;
+}
+
+#main_content {
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+}
+
+
+h1, h2, h3, h4, h5, h6 {
+  font-weight: bolder;
+}
+
+#main_content h1 {
+  font-size: 1.8em;
+  margin-top: 34px;
+}
+
+    #main_content h1:first-child {
+        margin-top: 30px;
+    }
+
+#main_content h2 {
+  font-size: 1.8em;
+}
+p, ul {
+    margin: 11px 18px;
+}
+
+#main_content a {
+    color: #06C;
+    text-decoration: none;
+}
+ul {
+        margin-top: 13px;
+    margin-left: 18px;
+    padding-left: 0;
+}
+    ul li {
+        margin-left: 18px;
+        padding-left: 0;
+    }
+#lpanel {
+    width: 870px;
+    float: left;
+}
+#rpanel ul {
+    list-style-type: none;
+}
+    #rpanel ul li {
+        line-height: 1.8em;
+    }
+#rpanel {
+    background: #e7e7e7;
+    width: 230px;
+}

+ 2 - 0
build.bat

@@ -0,0 +1,2 @@
+"D:\Visual Studio 2017\MSBuild\15.0\Bin\MSBuild.exe" "Karten Server.sln" /t:rebuild /p:configuration=debug /p:platform=x64
+"D:\Visual Studio 2017\MSBuild\15.0\Bin\MSBuild.exe" "Karten Server.sln" /t:rebuild /p:configuration=release /p:platform=x64