#include "PatchServer.h"
#include <iostream>
#include <Klient.h>
#include <Globals.h>

// Inhalt der PatchServer Klasse aus PatchServer.h
// Konstruktor 
PatchServer::PatchServer( InitDatei* zIni )
    : Thread()
{
    Network::Start( 100 );
    std::cout << "PS: Verbindung mit Datenbank wird hergestellt...\n";
    db = new PSDatenbank( zIni );
    klients = new RCArray< PSKlient >();
    empfangen = 0;
    gesendet = 0;
    fehler = new Text();
    ini = dynamic_cast<InitDatei*>(zIni->getThis());
    id = *zIni->zWert( "ServerId" );
    Text* dgInitPfad = new Text( ini->zWert( "SystemPfad" )->getText() );
    dgInitPfad->append( "/datei_gruppe.ini" );
    InitDatei* dgInit = new InitDatei( dgInitPfad );
    dgInit->laden();
    for( int i = 0; i < dgInit->getWertAnzahl(); i++ )
        db->setDateiGruppe( id, TextZuInt( dgInit->zName( i )->getText(), 10 ), (int)TextZuInt( dgInit->zWert( i )->getText(), 10 ) );
    dgInit->release();
    server = new Server();
    aServer = new SSLServer();
    aServer->setPrivateKeyPassword( zIni->zWert( "SSLPasswort" )->getText() );
    aServer->setCertificateFile( zIni->zWert( "SSLCert" )->getText() );
    aServer->setPrivateKeyFile( zIni->zWert( "SSLKey" )->getText() );
    std::cout << "PS: Starten des Admin Servers...\n";
    if( !aServer->verbinde( (unsigned short)TextZuInt( ini->zWert( "AdminServerPort" )->getText(), 10 ), 10 ) )
    {
        std::cout << "PS: Der Admin Server konnte nicht gestartet werden. Das Programm wird beendet.\n";
        exit( 1 );
    }
    db->setServerStatus( id, 2 );
    end = 0;
    nichtPausiert = 0;
    InitializeCriticalSection( &cs );
    updateAnzahl = 0;
    updateGruppe = new Array< int >();
    if( zIni->zWert( "Aktiv" )->istGleich( "TRUE" ) )
    {
        serverStarten();
        serverFortsetzen();
    }
}

// Destruktor 
PatchServer::~PatchServer()
{
    fehler->release();
    server->trenne();
    server->release();
    aServer->trenne();
    aServer->release();
    if( klients )
        klients->release();
    ini->release();
    db->release();
    updateGruppe->release();
    DeleteCriticalSection( &cs );
}

// nicht constant 
void PatchServer::runn()
{
    while( !end && aServer->isConnected() )
    {
        SSLSKlient* klient;
        klient = aServer->getKlient();
        if( end && klient )
        {
            klient->trenne();
            klient = (SSLSKlient*)klient->release();
            Sleep( 1000 );
            return;
        }
        if( !klient )
            continue;
        PSAKlient* clHandle = new PSAKlient( klient, dynamic_cast<PatchServer*>(getThis()), dynamic_cast<InitDatei*>(ini->getThis()) );
        clHandle->start();
    }
}

void PatchServer::thread()
{
    while( server->isConnected() )
    {
        SKlient* klient;
        klient = server->getKlient();
        if( !klient )
            continue;
        Framework::getThreadRegister()->cleanUpClosedThreads();
        PSKlient* clHandle = new PSKlient( klient, dynamic_cast<PatchServer*>(getThis()), dynamic_cast<InitDatei*>(ini->getThis()) );
        EnterCriticalSection( &cs );
        klients->add( clHandle );
        LeaveCriticalSection( &cs );
        clHandle->start();
    }
}

void PatchServer::close()
{
    db->setServerStatus( id, 1 );
    server->trenne();
#ifdef WIN32
    warteAufThread( 1000 );
#endif
    EnterCriticalSection( &cs );
    for( int i = 0; i < klients->getEintragAnzahl(); i++ )
        klients->z( i )->absturz();
    klients = (RCArray<PSKlient>*) klients->release();
    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 PatchServer::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 PatchServer::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 PatchServer::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 PatchServer::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 PatchServer::setMaxKlients( int mc )
{
    if( !db->setMaxClients( id, mc ) )
    {
        fehler->setText( "Die maximale Anzahl der Clients konnte nicht gesetzt werden:\n" );
        fehler->append( db->getLetzterFehler() );
        return 0;
    }
    ini->setWert( "MaxClients", Text() += mc );
    return 1;
}

bool PatchServer::absturzKlient( int klientId )
{
    bool gefunden = 0;
    EnterCriticalSection( &cs );
    for( int i = 0; i < klients->getEintragAnzahl(); i++ )
    {
        if( klients->z( i )->getKlientNummer() == klientId )
        {
            klients->z( i )->absturz();
            klients->remove( i );
            gefunden = 1;
            break;
        }
    }
    LeaveCriticalSection( &cs );
    return gefunden;
}

bool PatchServer::removeKlient( PSKlient* zKlient )
{
    bool gefunden = 0;
    EnterCriticalSection( &cs );
    for( int i = 0; i < klients->getEintragAnzahl(); i++ )
    {
        if( klients->z( i ) == zKlient )
        {
            klients->remove( i );
            gefunden = 1;
            break;
        }
    }
    LeaveCriticalSection( &cs );
    return gefunden;
}

void PatchServer::addGesendet( int bytes )
{
    gesendet += bytes;
}

void PatchServer::addEmpfangen( int bytes )
{
    empfangen += bytes;
}

bool PatchServer::beginnUpdate( int gruppe )
{
    bool update = 0;
    for( int i = 0; i < updateAnzahl; i++ )
    {
        if( updateGruppe->get( i ) == gruppe )
        {
            update = 1;
            break;
        }
    }
    if( update || proveVersion( gruppe ) )
        return 0;
    if( !db->supportedDateiGruppe( id, gruppe ) )
    {
        db->setDateiGruppe( id, gruppe, 0 );
    }
    if( !db->setDateiGruppe( id, gruppe, true ) )
        return 0;
    Text* gruppeN = db->getDateiGruppeName( gruppe );
    if( !gruppeN )
        return 0;
    Result systemT = db->getSystemListe();
    for( int i = 0; i < systemT.zeilenAnzahl; i++ )
    {
        Text* pfad = new Text( ini->zWert( "SystemPfad" )->getText() );
        pfad->append( "/" );
        pfad->append( gruppeN->getText() );
        pfad->append( "/" );
        pfad->append( systemT.values[ i * 2 + 1 ].getText() );
        pfad->append( "/version.ini" );
        InitDatei* vIni = new InitDatei( pfad->getText() );
        vIni->laden();
        pfad->remove( pfad->getLength() - 11, pfad->getLength() );
        Result dateiT = db->getDeletedFiles( TextZuInt( systemT.values[ i * 2 ].getText(), 10 ), gruppe );
        for( int j = 0; j < dateiT.zeilenAnzahl; j++ )
        {
            if( vIni->wertExistiert( dateiT.values[ j ].getText() ) )
            {
                Text* pf = new Text( pfad->getText() );
                pf->append( dateiT.values[ j ].getText() );
                DateiRemove( pf );
                vIni->removeWert( dateiT.values[ j ].getText() );
            }
        }
        dateiT.destroy();
        DateiPfadErstellen( vIni->getPfad() );
        vIni->speichern();
        vIni->release();
        pfad->release();
    }
    gruppeN->release();
    systemT.destroy();
    return 1;
}

void PatchServer::endUpdate( int gruppe )
{
    Text* dgInitPfad = new Text( ini->zWert( "SystemPfad" )->getText() );
    dgInitPfad->append( "/datei_gruppe.ini" );
    InitDatei* dgInit = new InitDatei( dgInitPfad );
    dgInit->laden();
    Text* gT = new Text();
    gT->append( gruppe );
    Text* vT = new Text();
    vT->append( db->getDateiGruppeVersion( gruppe ) );
    if( !dgInit->wertExistiert( gT->getText() ) )
        dgInit->addWert( gT->getText(), vT->getText() );
    else
        dgInit->setWert( gT->getText(), vT->getText() );
    gT->release();
    vT->release();
    dgInit->speichern();
    dgInit->release();
    db->dateiGruppeUpdateFertig( id, gruppe );
    for( int i = 0; i < updateAnzahl; i++ )
    {
        if( updateGruppe->get( i ) == gruppe )
        {
            updateAnzahl--;
            updateGruppe->remove( i );
            break;
        }
    }
}

void PatchServer::updateAbbruch( int gruppe )
{
    db->setDateiGruppe( id, gruppe, (bool)0 );
    for( int i = 0; i < updateAnzahl; i++ )
    {
        if( updateGruppe->get( i ) == gruppe )
        {
            updateAnzahl--;
            updateGruppe->remove( i );
            break;
        }
    }
}

// constant
bool PatchServer::istAn() const
{
    return db->serverIstNichtPausiert( id );
}

Server* PatchServer::zServer() const
{
    return server;
}

PSDatenbank* PatchServer::zDB() const
{
    return db;
}

bool PatchServer::hatClients() const
{
    return klients->hat( 0 );
}

int PatchServer::getId() const
{
    return id;
}

char* PatchServer::getLetzterFehler() const
{
    return fehler->getText();
}

bool PatchServer::proveVersion( int gruppe ) const
{
    Result systemT = db->getSystemListe();
    for( int i = 0; i < systemT.zeilenAnzahl; i++ )
    {
        int system = TextZuInt( systemT.values[ i * 2 ].getText(), 10 );
        Result dateiT = db->getDateiListeOhneOrdner( system, gruppe );
        Text* gruppeN = db->getDateiGruppeName( gruppe );
        if( !gruppeN )
            continue;
        Text* pfad = new Text( ini->zWert( "SystemPfad" )->getText() );
        pfad->append( "/" );
        pfad->append( gruppeN );
        pfad->append( "/" );
        pfad->append( systemT.values[ i * 2 + 1 ].getText() );
        pfad->append( "/version.ini" );
        InitDatei* vIni = new InitDatei( pfad );
        vIni->laden();
        int dAnz = vIni->getWertAnzahl();
        if( dAnz != dateiT.zeilenAnzahl ) // nicht aktuell
        {
            systemT.destroy();
            dateiT.destroy();
            vIni->release();
            return 0;
        }
        for( int j = 0; j < dAnz; j++ )
        {
            if( !vIni->wertExistiert( dateiT.values[ j * 2 ].getText() ) ) // nicht aktuell
            {
                systemT.destroy();
                dateiT.destroy();
                vIni->release();
                return 0;
            }
            if( !vIni->zWert( dateiT.values[ j * 2 ].getText() )->istGleich( dateiT.values[ j * 2 + 1 ].getText() ) ) // nicht aktuell
            {
                systemT.destroy();
                dateiT.destroy();
                vIni->release();
                return 0;
            }
        }
        dateiT.destroy();
        dateiT = db->getDeletedFiles( system, gruppe );
        for( int j = 0; j < dateiT.zeilenAnzahl; j++ )
        {
            if( vIni->wertExistiert( dateiT.values[ j ].getText() ) ) // nicht aktuell
            {
                systemT.destroy();
                dateiT.destroy();
                vIni->release();
                return 0;
            }
        }
        dateiT.destroy();
        vIni->release();
    }
    systemT.destroy();
    return 1;
}

bool PatchServer::proveVersion() const
{
    Result gruppeT = db->getGruppeIds();
    for( int g = 0; g < gruppeT.zeilenAnzahl; g++ )
    {
        int gruppe = TextZuInt( gruppeT.values[ g ].getText(), 10 );
        Result systemT = db->getSystemListe();
        for( int i = 0; i < systemT.zeilenAnzahl; i++ )
        {
            int system = TextZuInt( systemT.values[ i * 2 ].getText(), 10 );
            Result dateiT = db->getDateiListeOhneOrdner( system, gruppe );
            Text* gruppeN = db->getDateiGruppeName( gruppe );
            if( !gruppeN )
                continue;
            Text* pfad = new Text( ini->zWert( "SystemPfad" )->getText() );
            pfad->append( "/" );
            pfad->append( gruppeN );
            pfad->append( "/" );
            pfad->append( systemT.values[ i * 2 + 1 ].getText() );
            pfad->append( "/version.ini" );
            InitDatei* vIni = new InitDatei( pfad );
            vIni->laden();
            int dAnz = vIni->getWertAnzahl();
            if( dAnz != dateiT.zeilenAnzahl ) // nicht aktuell
            {
                gruppeT.destroy();
                systemT.destroy();
                dateiT.destroy();
                vIni->release();
                return 0;
            }
            for( int j = 0; j < dAnz; j++ )
            {
                if( !vIni->wertExistiert( dateiT.values[ j * 2 ].getText() ) ) // nicht aktuell
                {
                    gruppeT.destroy();
                    systemT.destroy();
                    dateiT.destroy();
                    vIni->release();
                    return 0;
                }
                if( !vIni->zWert( dateiT.values[ j * 2 ].getText() )->istGleich( dateiT.values[ j * 2 + 1 ].getText() ) ) // nicht aktuell
                {
                    gruppeT.destroy();
                    systemT.destroy();
                    dateiT.destroy();
                    vIni->release();
                    return 0;
                }
            }
            dateiT.destroy();
            dateiT = db->getDeletedFiles( system, gruppe );
            for( int j = 0; j < dateiT.zeilenAnzahl; j++ )
            {
                if( vIni->wertExistiert( dateiT.values[ j ].getText() ) ) // nicht aktuell
                {
                    gruppeT.destroy();
                    systemT.destroy();
                    dateiT.destroy();
                    vIni->release();
                    return 0;
                }
                Text tmp = vIni->zPfad()->getText();
                tmp.remove( "version.ini" );
                tmp += dateiT.values[ j ].getText();
                if( DateiExistiert( tmp ) ) // nicht aktuell
                {
                    gruppeT.destroy();
                    systemT.destroy();
                    dateiT.destroy();
                    vIni->release();
                    return 0;
                }
            }
            dateiT.destroy();
            vIni->release();
        }
        systemT.destroy();
    }
    gruppeT.destroy();
    return 1;
}


// Inhalt der PSAKlient Klasse aus PatchServer.h
// Konstruktor 
PSAKlient::PSAKlient( SSLSKlient* klient, PatchServer* ps, InitDatei* ini )
    : Thread()
{
    this->klient = klient;
    name = new Text( "" );
    passwort = new Text( "" );
    adminId = 0;
    updateGruppe = 0;
    gruppeN = 0;
    this->ps = ps;
    this->ini = ini;
}

// Destruktor 
PSAKlient::~PSAKlient()
{
    klient->trenne();
    klient->release();
    ps->release();
    name->release();
    passwort->release();
    ini->release();
    if( gruppeN )
        gruppeN->release();
}

// nicht constant 
void PSAKlient::thread()
{
    while( 1 )
    {
        char c = 0;
        if( !klient->getNachricht( &c, 1 ) )
            break;
        else
        {
            bool br = 0;
            switch( c )
            {
            case 1: // Login
                if( 1 )
                {
                    klient->sende( "\1", 1 );
                    unsigned char len = 0;
                    klient->getNachricht( (char*)&len, 1 );
                    char* n = new char[ len + 1 ];
                    n[ (int)len ] = 0;
                    if( len )
                        klient->getNachricht( n, len );
                    unsigned char pLen = 0;
                    klient->getNachricht( (char*)&pLen, 1 );
                    char* p = new char[ pLen + 1 ];
                    p[ (int)pLen ] = 0;
                    if( pLen )
                        klient->getNachricht( p, pLen );
                    int adminId = ps->zDB()->istAdministrator( n, p );
                    if( adminId )
                    {
                        klient->sende( "\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->sende( "\1", 1 );
                break;
            case 3: // Trennen
                br = 1;
                klient->sende( "\1", 1 );
                break;
            case 4: // Server starten
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( ps->zDB()->adminHatRecht( adminId, Admin_Recht::PSStarten ) )
                    {
                        if( !ps->serverStarten() )
                        {
                            Text* err = new Text();
                            err->append( ps->getLetzterFehler() );
                            errorZuKlient( err->getText() );
                            err->release();
                        }
                        else
                            klient->sende( "\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( ps->zDB()->adminHatRecht( adminId, Admin_Recht::PSBeenden ) )
                    {
                        if( ps->serverBeenden() )
                            klient->sende( "\1", 1 );
                        else
                        {
                            Text* err = new Text();
                            err->append( ps->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( ps->isRunning() )
                    {
                        if( ps->zDB()->adminHatRecht( adminId, Admin_Recht::PSBeenden ) )
                        {
                            if( ps->serverBeenden() )
                                ok = 1;
                            else
                            {
                                Text* err = new Text();
                                err->append( ps->getLetzterFehler() );
                                errorZuKlient( err->getText() );
                                err->release();
                            }
                        }
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                    }
                    else
                        ok = 1;
                    if( ok && ps->hatClients() )
                    {
                        errorZuKlient( "Es sind noch Klients Online. Bitte versuche es später erneut." );
                        break;
                    }
                    if( ok )
                    {
                        klient->sende( "\1", 1 );
                        std::cout << "PS: Der Server wird von Benutzer " << adminId << " heruntergefahren.\n";
                        ps->close();
                        br = 1;
                    }
                }
                break;
            case 7: // Progtamm abstürzen
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    bool ok = 0;
                    if( ps->isRunning() )
                    {
                        if( ps->zDB()->adminHatRecht( adminId, Admin_Recht::PSBeenden ) )
                        {
                            ps->serverBeenden();
                            ok = 1;
                        }
                        else
                            errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." );
                    }
                    else
                        ok = 1;
                    if( ok )
                    {
                        klient->sende( "\1", 1 );
                        std::cout << "PS: Der Server wurde von Benutzer " << adminId << " terminiert.\n";
                        ps->close();
                        br = 1;
                    }
                }
                break;
            case 8: // Status Frage
                if( 1 )
                {
                    char status = 0;
                    if( ps->isRunning() )
                    {
                        status = 1;
                        if( ps->istAn() )
                            status = 2;
                    }
                    if( !ps->proveVersion() )
                        status = 3;
                    klient->sende( "\1", 1 );
                    klient->sende( &status, 1 );
                }
                break;
            case 9: // Server pausieren
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    klient->sende( "\1", 1 );
                    char pause = 0;
                    klient->getNachricht( &pause, 1 );
                    if( ps->zDB()->adminHatRecht( adminId, Admin_Recht::PSPausieren ) )
                    {
                        bool ok = 0;
                        if( pause )
                            ok = ps->serverPause();
                        else
                            ok = ps->serverFortsetzen();
                        if( ok )
                            klient->sende( "\1", 1 );
                        else
                        {
                            Text* err = new Text();
                            err->append( ps->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->sende( "\1", 1 );
                    int maxC = 0;
                    klient->getNachricht( (char*)&maxC, 4 );
                    if( ps->zDB()->adminHatRecht( adminId, Admin_Recht::PSMCChange ) )
                    {
                        if( ps->setMaxKlients( maxC ) )
                            klient->sende( "\1", 1 );
                        else
                        {
                            Text* err = new Text();
                            err->append( ps->getLetzterFehler() );
                            errorZuKlient( err->getText() );
                            err->release();
                        }
                    }
                    else
                        errorZuKlient( "Du bist nicht berechtigt die maximale Anzahl der Clients zu verändern." );
                }
                break;
            case 0xB: // frage nach geänderten Dateien
                if( !adminId )
                {
                    errorZuKlient( "Du musst dich einloggen." );
                    break;
                }
                if( updateGruppe )
                {
                    klient->sende( "\1", 1 );
                    Result systemT = ps->zDB()->getSystemListe();
                    for( int i = 0; i < systemT.zeilenAnzahl; i++ )
                    {
                        int len = systemT.values[ i * 2 + 1 ].getLength();
                        klient->sende( (char*)&len, 4 );
                        klient->sende( systemT.values[ i * 2 + 1 ].getText(), len );
                        Result dateiT = ps->zDB()->getDateiListeOhneOrdner( TextZuInt( systemT.values[ i * 2 ].getText(), 10 ), updateGruppe );
                        Text* pfad = new Text( ini->zWert( "SystemPfad" )->getText() );
                        pfad->append( "/" );
                        pfad->append( gruppeN->getText() );
                        pfad->append( "/" );
                        pfad->append( systemT.values[ i * 2 + 1 ].getText() );
                        pfad->append( "/version.ini" );
                        InitDatei* vIni = new InitDatei( pfad );
                        vIni->laden();
                        for( int j = 0; j < dateiT.zeilenAnzahl; j++ )
                        {
                            bool veraltet = 0;
                            if( !vIni->wertExistiert( dateiT.values[ j * 2 ].getText() ) )
                                veraltet = 1;
                            if( !veraltet && !vIni->zWert( dateiT.values[ j * 2 ].getText() )->istGleich( dateiT.values[ j * 2 + 1 ].getText() ) )
                                veraltet = 1;
                            if( veraltet )
                            {
                                int len = dateiT.values[ j * 2 ].getLength();
                                klient->sende( (char*)&len, 4 );
                                klient->sende( dateiT.values[ j * 2 ].getText(), len );
                            }
                        }
                        klient->sende( "\0\0\0\0", 4 );
                        dateiT.destroy();
                        vIni->release();
                    }
                    klient->sende( "\0\0\0\0", 4 );
                    systemT.destroy();
                }
                else
                    errorZuKlient( "Du musst zunächst den Aktualisierungsvorgang starten." );
                break;
            case 0xC: // Update Beendet
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( !updateGruppe )
                    {
                        errorZuKlient( "Du musst zunächst den Aktualisierungsvorgang starten." );
                        break;
                    }
                    ps->endUpdate( updateGruppe );
                    updateGruppe = 0;
                    if( gruppeN )
                        gruppeN = (Text*)gruppeN->release();
                    std::cout << "PS: Update erfolgreich abgeschlossen.\n";
                    klient->sende( "\1", 1 );
                }
                break;
            case 0xD: // Update Vorgang starten
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( updateGruppe )
                    {
                        errorZuKlient( "Du musst die Aktualisierung erst beenden." );
                        break;
                    }
                    klient->sende( "\1", 1 );
                    int dg = 0;
                    klient->getNachricht( (char*)&dg, 4 );
                    gruppeN = ps->zDB()->getDateiGruppeName( dg );
                    if( !gruppeN )
                    {
                        updateGruppe = 0;
                        errorZuKlient( "Die Dateigruppe existiert nicht." );
                        break;
                    }
                    if( !ps->proveVersion() )
                    {
                        if( ps->zDB()->adminHatRecht( adminId, Admin_Recht::KSGCUpdate ) )
                        {
                            if( ps->beginnUpdate( dg ) )
                            {
                                klient->sende( "\1", 1 );
                                std::cout << "PS: Die Dateigruppe " << dg << " wird von Benutzer " << adminId << " geupdatet.\n";
                                updateGruppe = dg;
                            }
                            else
                                errorZuKlient( "Es läuft bereits eine andere Aktualisierung." );
                        }
                        else
                            errorZuKlient( "Die Version ist bereits aktuel." );
                    }
                    else
                        errorZuKlient( "Dir fehlt die Berechtigung für diesen Vorgang." );
                }
                break;
            case 0xE: // Datei übertragen
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( !updateGruppe )
                    {
                        errorZuKlient( "Du musst zunächst den Aktualisierungsvorgang starten." );
                        break;
                    }
                    klient->sende( "\1", 1 );
                    int system = 0;
                    klient->getNachricht( (char*)&system, 4 );
                    int version = 0;
                    klient->getNachricht( (char*)&version, 4 );
                    Text* sName = ps->zDB()->getSystemName( system );
                    unsigned short len = 0;
                    klient->getNachricht( (char*)&len, 2 );
                    char* pfad = new char[ len + 1 ];
                    pfad[ len ] = 0;
                    if( len )
                        klient->getNachricht( pfad, len );
                    if( !len || !sName )
                    {
                        errorZuKlient( "Die Datei konnte nicht angelegt werden." );
                        delete[] pfad;
                        if( sName )
                            sName->release();
                        break;
                    }
                    Text* pf = new Text( ini->zWert( "SystemPfad" )->getText() );
                    pf->append( "/" );
                    pf->append( gruppeN->getText() );
                    pf->append( "/" );
                    pf->append( sName->getText() );
                    sName->release();
                    pf->append( "/version.ini" );
                    InitDatei* vIni = new InitDatei( pf->getText() );
                    vIni->laden();
                    pf->remove( pf->getLength() - 11, pf->getLength() );
                    pf->append( pfad );
                    Datei* d = new Datei();
                    d->setDatei( pf );
                    d->erstellen();
                    if( d->open( Datei::Style::schreiben ) )
                    {
                        klient->sende( "\1", 1 );
                        klient->getNachricht( (char*)&len, 2 );
                        while( len )
                        {
                            char* buff = new char[ len ];
                            klient->getNachricht( buff, len );
                            d->schreibe( buff, len );
                            delete[] buff;
                            klient->getNachricht( (char*)&len, 2 );
                            ps->addEmpfangen( klient->getDownloadBytes( 1 ) );
                            ps->addGesendet( klient->getUploadBytes( 1 ) );
                        }
                        klient->sende( "\1", 1 );
                        Text* vT = new Text();
                        vT->append( version );
                        if( !vIni->wertExistiert( pfad ) )
                            vIni->addWert( pfad, vT->getText() );
                        else
                            vIni->setWert( pfad, vT->getText() );
                        vIni->speichern();
                        vT->release();
                    }
                    else
                        errorZuKlient( "Die Datei konnte nicht zum schreiben geöffnet werden." );
                    d->close();
                    d->release();
                    vIni->release();
                    delete[] pfad;
                }
                break;
            case 0xF: // klient absturtz
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    klient->sende( "\1", 1 );
                    int klientId = 0;
                    klient->getNachricht( (char*)&klientId, 4 );
                    if( klientId && ps->absturzKlient( klientId ) )
                        klient->sende( "\1", 1 );
                    else
                        klient->sende( "\0", 1 );
                }
                break;
            case 0x10: // SMP Frage nach Datei Gruppen Status
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( !ps->zDB()->adminHatRecht( adminId, Admin_Recht::KSGCUpdate ) )
                        errorZuKlient( "Du hast kein Recht diese Operation durchzuführen." );
                    else
                    {
                        Array< FileGroupInfo* > list;
                        if( ps->zDB()->getFileGroupInfoList( ps->getId(), &list ) )
                        {
                            klient->sende( "\1", 1 );
                            int anz = list.getEintragAnzahl();
                            klient->sende( (char*)&anz, 4 );
                            for( int i = 0; i < anz; i++ )
                            {
                                FileGroupInfo* info = list.get( i );
                                klient->sende( (char*)&info->id, 4 );
                                unsigned char len = (unsigned char)info->name.getLength();
                                klient->sende( (char*)&len, 1 );
                                klient->sende( info->name, len );
                                len = (unsigned char)info->status.getLength();
                                klient->sende( (char*)&len, 1 );
                                klient->sende( info->status, len );
                                unsigned short l = (unsigned short)info->pfad.getLength();
                                klient->sende( (char*)&l, 2 );
                                klient->sende( info->pfad, l );
                                klient->sende( (char*)&info->version, 4 );
                                delete info;
                            }
                        }
                        else
                            errorZuKlient( "Fehler beim abrufen der Datei Gruppen Informationen." );
                    }
                }
                break;
            case 0x11: // SMP Get System List
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( !ps->zDB()->adminHatRecht( adminId, Admin_Recht::KSGCUpdate ) )
                        errorZuKlient( "Du hast kein Recht diese Operation durchzuführen." );
                    else
                    {
                        klient->sende( "\1", 1 );
                        Result res = ps->zDB()->getSystemListe();
                        klient->sende( (char*)&res.zeilenAnzahl, 4 );
                        for( int i = 0; i < res.zeilenAnzahl; i++ )
                        {
                            int id = res.values[ i * 2 ];
                            klient->sende( (char*)&id, 4 );
                            unsigned char len = (unsigned char)res.values[ i * 2 + 1 ].getLength();
                            klient->sende( (char*)&len, 1 );
                            klient->sende( res.values[ i * 2 + 1 ], len );
                        }
                        res.destroy();
                    }
                }
                break;
            case 0x12: // SMP Get File List
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( !ps->zDB()->adminHatRecht( adminId, Admin_Recht::KSGCUpdate ) )
                        errorZuKlient( "Du hast kein Recht diese Operation durchzuführen." );
                    else
                    {
                        klient->sende( "\1", 1 );
                        int system, group;
                        klient->getNachricht( (char*)&system, 4 );
                        klient->getNachricht( (char*)&group, 4 );
                        Result res = ps->zDB()->getDateiListeSMP( system, group );
                        klient->sende( (char*)&res.zeilenAnzahl, 4 );
                        for( int i = 0; i < res.zeilenAnzahl; i++ )
                        {
                            int id = res.values[ i * 4 ];
                            klient->sende( (char*)&id, 4 );
                            unsigned short len = (unsigned short)res.values[ i * 4 + 1 ].getLength();
                            klient->sende( (char*)&len, 2 );
                            klient->sende( res.values[ i * 4 + 1 ], len );
                            int version = res.values[ i * 4 + 2 ];
                            klient->sende( (char*)&version, 4 );
                            unsigned char l = (unsigned char)res.values[ i * 4 + 3 ].getLength();
                            klient->sende( (char*)&l, 1 );
                            klient->sende( res.values[ i * 4 + 3 ], l );
                        }
                        res.destroy();
                    }
                }
                break;
            case 0x13: // Get File Version
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( !ps->zDB()->adminHatRecht( adminId, Admin_Recht::KSGCUpdate ) )
                        errorZuKlient( "Du hast kein Recht diese Operation durchzuführen." );
                    else
                    {
                        klient->sende( "\1", 1 );
                        int group, system;
                        unsigned short len;
                        klient->getNachricht( (char*)&len, 2 );
                        char* path = new char[ len + 1 ];
                        klient->getNachricht( path, len );
                        path[ len ] = 0;
                        klient->getNachricht( (char*)&group, 4 );
                        klient->getNachricht( (char*)&system, 4 );
                        int version = ps->zDB()->getDateiVersion( path, system, group );
                        delete[] path;
                        klient->sende( (char*)&version, 4 );
                    }
                }
                break;
            case 0x14: // Update File
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( !ps->zDB()->adminHatRecht( adminId, Admin_Recht::KSGCUpdate ) )
                        errorZuKlient( "Du hast kein Recht diese Operation durchzuführen." );
                    else
                    {
                        klient->sende( "\1", 1 );
                        unsigned short len;
                        klient->getNachricht( (char*)&len, 2 );
                        char* path = new char[ len + 1 ];
                        klient->getNachricht( path, len );
                        path[ len ] = 0;
                        char status = 0; // 0: delete, 1: update, 2: new
                        klient->getNachricht( &status, 1 );
                        unsigned char l;
                        klient->getNachricht( (char*)&l, 1 );
                        char* time = 0;
                        if( l > 0 )
                        {
                            time = new char[ l + 1 ];
                            klient->getNachricht( time, l );
                            time[ l ] = 0;
                        }
                        int system, gruppe;
                        klient->getNachricht( (char*)&system, 4 );
                        klient->getNachricht( (char*)&gruppe, 4 );
                        if( ps->zDB()->updateDatei( path, status, time, system, gruppe ) )
                            klient->sende( "\1", 1 );
                        else
                            errorZuKlient( "Fehler beim updaten der Datei." );
                    }
                }
                break;
            case 0x15: // Update Gruppe
                if( !adminId )
                    errorZuKlient( "Du musst dich einloggen." );
                else
                {
                    if( !ps->zDB()->adminHatRecht( adminId, Admin_Recht::KSGCUpdate ) )
                        errorZuKlient( "Du hast kein Recht diese Operation durchzuführen." );
                    else
                    {
                        klient->sende( "\1", 1 );
                        int gruppe;
                        klient->getNachricht( (char*)&gruppe, 4 );
                        if( ps->zDB()->dateiGruppeUpdate( gruppe ) )
                            klient->sende( "\1", 1 );
                        else
                            errorZuKlient( "Fehler beim updaten der Gruppe." );
                    }
                }
                break;
            default:
                errorZuKlient( "Unbekannte Nachricht!" );
                break;
            }
            if( br )
                break;
            ps->addEmpfangen( klient->getDownloadBytes( 1 ) );
            ps->addGesendet( klient->getUploadBytes( 1 ) );
        }
    }
    ps->addEmpfangen( klient->getDownloadBytes( 1 ) );
    ps->addGesendet( klient->getUploadBytes( 1 ) );
    if( updateGruppe )
        ps->updateAbbruch( updateGruppe );
    delete this;
}

void PSAKlient::errorZuKlient( const char* nachricht ) const // sendet eine Fehlernachricht zum Klient
{
    klient->sende( "\3", 1 );
    char len = (char)textLength( nachricht );
    klient->sende( &len, 1 );
    klient->sende( nachricht, len );
}


// Inhalt der PSKlient aus PatchServer.h
// Konstruktor 
PSKlient::PSKlient( SKlient* klient, PatchServer* ps, InitDatei* ini )
    : Thread()
{
    this->klient = klient;
    unsigned char key[ 20 ] = { 102, 139, 140, 143, 52, 52, 194, 167, 97, 106, 23, 72, 170, 121, 213, 178, 28, 28, 124, 185 };
    klient->setSendeKey( (char*)key, 20 );
    klient->setEmpfangKey( (char*)key, 20 );
    klientNummer = 0;
    system = 0;
    this->ps = ps;
    this->ini = ini;
    encrypted = 0;
}

// Destruktor 
PSKlient::~PSKlient()
{
    ps->release();
    klient->release();
    ini->release();
}

// nicht constant 
void PSKlient::absturz()
{
    ende();
    klient->trenne();
    ps->zDB()->unregisterKlient( klientNummer, ps->getId() );
}

void PSKlient::thread()
{
    int hack = 0;
    while( 1 )
    {
        char c = 0;
        if( (!encrypted && !klient->getNachricht( &c, 1 )) || (encrypted && !klient->getNachrichtEncrypted( &c, 1 )) )
            break;
        else
        {
            bool br = 0;
            switch( c )
            {
            case 0:
                encrypted = 1;
                break;
            case 1: // Klient identifikation
                if( encrypted )
                {
                    klient->getNachrichtEncrypted( (char*)&klientNummer, 4 );
                    klient->getNachrichtEncrypted( (char*)&system, 1 );
                }
                else
                {
                    klient->getNachricht( (char*)&klientNummer, 4 );
                    klient->getNachricht( (char*)&system, 1 );
                }
                if( !ps->zDB()->proveKlient( klientNummer, ps->getId() ) )
                {
                    klientNummer = 0;
                    errorZuKlient( "Du bist nicht für diesen Server eingetragen" );
                }
                else
                {
                    if( encrypted )
                    {
                        Text* key = ps->zDB()->getKlientKey( klientNummer );
                        if( !key )
                            errorZuKlient( "Es konnte kein Key ermittelt werden." );
                        else
                        {
                            klient->sendeEncrypted( "\1", 1 );
                            klient->setEmpfangKey( *key, key->getLength() );
                            klient->setSendeKey( *key, key->getLength() );
                            key->release();
                        }
                    }
                    else
                        klient->sende( "\1", 1 );
                }
                break;
            case 2: // Erhaltung Server message
                if( 1 )
                {
                    char befehl = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( &befehl, 1 );
                    else
                        klient->getNachricht( &befehl, 1 );
                    switch( befehl )
                    {
                    case 2: // Klient absturz
                        if( 1 )
                        {
                            int klientId = 0;
                            if( encrypted )
                            {
                                klient->getNachrichtEncrypted( (char*)&klientId, 4 );
                                if( klientId && ps->absturzKlient( klientId ) )
                                    klient->sendeEncrypted( "\1", 1 );
                                else
                                    klient->sendeEncrypted( "\0", 1 );
                            }
                            else
                            {
                                klient->getNachricht( (char*)&klientId, 4 );
                                if( klientId && ps->absturzKlient( klientId ) )
                                    klient->sende( "\1", 1 );
                                else
                                    klient->sende( "\0", 1 );
                            }
                        }
                        break;
                    default:
                        errorZuKlient( "Befehl nicht bekannt!" );
                        break;
                    }
                }
                break;
            case 3: // Verbindungsende
                br = 1;
                if( encrypted )
                    klient->sendeEncrypted( "\1", 1 );
                else
                    klient->sende( "\1", 1 );
                break;
            case 4: // unregister Klient
                if( klientNummer )
                {
                    ps->zDB()->unregisterKlient( klientNummer, ps->getId() );
                    if( encrypted )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\1", 1 );
                }
                else
                    errorZuKlient( "Du bist nicht Identifiziert." );
                break;
            case 5: // update anfrage ****Altes Update System
                if( klientNummer )
                { // Keine Verkeyung bei den alten Clients
                    klient->sende( "\1", 1 );
                    char version[ 4 ];
                    klient->getNachricht( version, 4 );
                    //int v = ( ( version[ 3 ] << 24 ) & 0xFF000000 ) | ( ( version[ 2 ] << 16 ) & 0x00FF0000 ) | ( ( version[ 1 ] << 8 ) & 0x0000FF00 ) | ( version[ 0 ] & 0x000000FF );
                    //Result änderungen = ps->zDB()->getGeänderteDateien( v, (int)X64 + 1 );
                    char byte = 0;
                    // ********neu beginn*********
                    klient->sende( "\2", 1 );
                    Text* pfad = new Text( "start.exe" );
                    byte = (char)pfad->getLength();
                    klient->sende( &byte, 1 );
                    klient->sende( pfad->getText(), byte );
                    klient->sende( "\2", 1 );
                    pfad->setText( "framework.dll" );
                    byte = (char)pfad->getLength();
                    klient->sende( &byte, 1 );
                    klient->sende( pfad->getText(), byte );
                    klient->sende( "\2", 1 );
                    pfad->setText( "network.dll" );
                    byte = (char)pfad->getLength();
                    klient->sende( &byte, 1 );
                    klient->sende( pfad->getText(), byte );
                    klient->sende( "\2", 1 );
                    pfad->setText( "data/patch/bin/patcher.exe" );
                    byte = (char)pfad->getLength();
                    klient->sende( &byte, 1 );
                    klient->sende( pfad->getText(), byte );
                    klient->sende( "\2", 1 );
                    pfad->setText( "data/patch/bin/übernehmen.exe" );
                    byte = (char)pfad->getLength();
                    klient->sende( &byte, 1 );
                    klient->sende( pfad->getText(), byte );
                    klient->sende( "\2", 1 );
                    pfad->setText( "data/start/icon.exe" );
                    byte = (char)pfad->getLength();
                    klient->sende( &byte, 1 );
                    klient->sende( pfad->getText(), byte );
                    klient->sende( "\2", 1 );
                    pfad->setText( "data/optionen.ini" );
                    byte = (char)pfad->getLength();
                    klient->sende( &byte, 1 );
                    klient->sende( pfad->getText(), byte );
                    pfad->release();
                    klient->sende( "\4", 1 );
                    // ********neu ende********
                    //for( int i = 0; i < änderungen.zeilenAnzahl; i++ )
                    //{
                    //	if( änderungen.values[ i * 2 + 1 ].istGleich( "t" ) )
                    //		byte = 1;
                    //	else
                    //		byte = 2;
                    //	klient->sende( &byte, 1 );
                    //	byte = änderungen.values[ i * 2 ].getLength();
                    //	klient->sende( &byte, 1 );
                    //	klient->sende( änderungen.values[ i * 2 ].getText(), byte );
                    //}
                    //änderungen.destroy();
                    //Result remove = ps->zDB()->getGelöschteDateien( v, (int)X64 + 1 );
                    //for( int i = 0; i < remove.zeilenAnzahl; i++ )
                    //{
                    //	klient->sende( "\3", 1 );
                    //	byte = remove.values[ i * 2 ].getLength();
                    //	klient->sende( &byte, 1 );
                    //	klient->sende( remove.values[ i * 2 ].getText(), byte );
                    //}
                    //klient->sende( "\4", 1 );
                    //remove.destroy();
                }
                else
                    errorZuKlient( "Du bist nicht Identifiziert." );
                break;
            case 6: // Frage nach Datei ****Altes Update System
                if( 1 )
                { // Keine Verkeyung bei den alten Clients
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    klient->sende( "\1", 1 );
                    unsigned char byte = 0;
                    klient->getNachricht( (char*)&byte, 1 );
                    Text* pfad = new Text( "" );
                    pfad->fillText( ' ', byte );
                    klient->getNachricht( pfad->getText(), byte );
                    __int64 pos = 0;
                    klient->getNachricht( (char*)&pos, 8 );
                    if( system )
                        pfad->insert( 0, "../versions/x64/live/" );
                    else
                        pfad->insert( 0, "../versions/x32/live/" );
                    pfad->ersetzen( "ü", "ue" );
                    Datei* datei = new Datei();
                    datei->setDatei( pfad );
                    datei->open( Datei::Style::lesen );
                    if( pos )
                        datei->setLPosition( pos, 0 );
                    __int64 length = datei->getSize();
                    length -= pos;
                    char* bytes = new char[ 2048 ];
                    unsigned short byteLen = 0;
                    while( 1 )
                    {
                        if( !length )
                        {
                            klient->sende( "\0\0", 2 );
                            break;
                        }
                        byteLen = 2048;
                        if( length < 2048 )
                            byteLen = (unsigned short)length;
                        klient->sende( (char*)&byteLen, 2 );
                        datei->lese( bytes, byteLen );
                        klient->sende( bytes, byteLen );
                        length -= byteLen;
                        char ret = 0;
                        if( byteLen != 2048 )
                            break;
                        klient->getNachricht( (char*)&ret, 1 );
                        ps->addEmpfangen( klient->getDownloadBytes( 1 ) );
                        ps->addGesendet( klient->getUploadBytes( 1 ) );
                        if( ret == 1 )
                            continue;
                        if( !ret )
                            break;
                        if( ret == 2 )
                        {
                            pos = 0;
                            klient->getNachricht( (char*)&pos, 8 );
                            if( pos > length )
                                pos = length;
                            datei->setLPosition( pos, 0 );
                            length = datei->getSize();
                            length -= pos;
                        }
                    }
                    delete[]bytes;
                    datei->close();
                    datei->release();
                }
                break;
            case 7: // Frage nach neuster Version ****Altes Update System
                if( 1 )
                { // Keine Verkeyung bei den alten Clients
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    klient->sende( "\1", 1 );
                    int version = 30;
                    klient->sende( (char*)&version, 4 );
                }
                break;
            case 8: // Frage nach Dateigröße ****Altes Update System
                if( 1 )
                { // Keine Verkeyung bei den alten Clients
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    klient->sende( "\1", 1 );
                    char byte = 0;
                    klient->getNachricht( &byte, 1 );
                    Text* pfad = new Text( "" );
                    pfad->fillText( ' ', byte );
                    klient->getNachricht( pfad->getText(), byte );
                    if( system )
                        pfad->insert( 0, "../versions/x64/live/" );
                    else
                        pfad->insert( 0, "../versions/x32/live/" );
                    pfad->ersetzen( "ü", "ue" );
                    Datei* datei = new Datei();
                    datei->setDatei( pfad );
                    __int64 size = datei->getSize();
                    datei->release();
                    klient->sende( (char*)&size, 8 );
                }
                break;
            case 9: // Frage nach Dateiliste ****Neues Update System
                if( 1 )
                {
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    if( encrypted )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\1", 1 );
                    int updateGruppe = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( (char*)&updateGruppe, 4 );
                    else
                        klient->getNachricht( (char*)&updateGruppe, 4 );
                    Result dateien = ps->zDB()->getDateiListeOhneOrdner( system, updateGruppe );
                    if( !dateien.zeilenAnzahl )
                    {
                        dateien.destroy();
                        errorZuKlient( "Dein System wird nicht unterstützt." );
                        break;
                    }
                    Result deleted = ps->zDB()->getDeletedFiles( system, updateGruppe );
                    if( encrypted )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\1", 1 );
                    for( int i = 0; i < dateien.zeilenAnzahl; i++ )
                    {
                        int len = dateien.values[ i * 2 ].getLength();
                        if( !len )
                            break;
                        if( encrypted )
                        {
                            klient->sendeEncrypted( (char*)&len, 4 );
                            klient->sendeEncrypted( dateien.values[ i * 2 ].getText(), len );
                            int version = TextZuInt( dateien.values[ i * 2 + 1 ].getText(), 10 );
                            klient->sendeEncrypted( (char*)&version, 4 );
                        }
                        else
                        {
                            klient->sende( (char*)&len, 4 );
                            klient->sende( dateien.values[ i * 2 ].getText(), len );
                            int version = TextZuInt( dateien.values[ i * 2 + 1 ].getText(), 10 );
                            klient->sende( (char*)&version, 4 );
                        }
                    }
                    if( encrypted )
                        klient->sendeEncrypted( "\0\0\0\0", 4 );
                    else
                        klient->sende( "\0\0\0\0", 4 );
                    for( int i = 0; i < deleted.zeilenAnzahl; i++ )
                    {
                        int len = deleted.values[ i ].getLength();
                        if( !len )
                            break;
                        if( encrypted )
                        {
                            klient->sendeEncrypted( (char*)&len, 4 );
                            klient->sendeEncrypted( deleted.values[ i ].getText(), len );
                        }
                        else
                        {
                            klient->sende( (char*)&len, 4 );
                            klient->sende( deleted.values[ i ].getText(), len );
                        }
                    }
                    if( encrypted )
                        klient->sendeEncrypted( "\0\0\0\0", 4 );
                    else
                        klient->sende( "\0\0\0\0", 4 );
                    deleted.destroy();
                    dateien.destroy();
                }
                break;
            case 10: // Frage nach Dateigröße ****Neues Update System
                if( 1 )
                {
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    if( encrypted )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\1", 1 );
                    int updateGruppe = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( (char*)&updateGruppe, 4 );
                    else
                        klient->getNachricht( (char*)&updateGruppe, 4 );
                    if( !ps->zDB()->supportedDateiGruppe( ps->getId(), updateGruppe ) )
                    {
                        int s = ps->zDB()->getDateiGruppePatchServer( klientNummer, updateGruppe );
                        int port = 0;
                        Text* ip = new Text();
                        bool ok = ps->zDB()->getPatchServerPortIp( s, &port, ip );
                        if( !s || !ok )
                            errorZuKlient( "Es ist momentan nicht möglich diese Datei herunterzuladen." );
                        else
                        {
                            if( encrypted )
                            {
                                klient->sendeEncrypted( "\2", 1 );
                                klient->sendeEncrypted( (char*)&port, 4 );
                                int len = ip->getLength();
                                klient->sendeEncrypted( (char*)&len, 4 );
                                klient->sendeEncrypted( (char*)ip->getText(), len );
                            }
                            else
                            {
                                klient->sende( "\2", 1 );
                                klient->sende( (char*)&port, 4 );
                                int len = ip->getLength();
                                klient->sende( (char*)&len, 4 );
                                klient->sende( (char*)ip->getText(), len );
                            }
                        }
                        ip->release();
                        break;
                    }
                    Text* gruppeN = ps->zDB()->getDateiGruppeName( updateGruppe );
                    if( !gruppeN )
                    {
                        errorZuKlient( "Dein System wird nicht unterstützt." );
                        break;
                    }
                    Text* pfad = new Text( ini->zWert( "SystemPfad" )->getText() );
                    pfad->append( "/" );
                    pfad->append( gruppeN );
                    pfad->append( "/" );
                    Text* tmp = ps->zDB()->getSystemName( system );
                    if( !tmp )
                    {
                        errorZuKlient( "Dein System wird nicht unterstützt." );
                        pfad->release();
                        break;
                    }
                    pfad->append( tmp );
                    pfad->append( "/" );
                    if( encrypted )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\1", 1 );
                    int len = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( (char*)&len, 4 );
                    else
                        klient->getNachricht( (char*)&len, 4 );
                    char* pf = new char[ len + 1 ];
                    pf[ len ] = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( pf, len );
                    else
                        klient->getNachricht( pf, len );
                    pfad->append( pf );
                    delete[] pf;
                    Datei* datei = new Datei();
                    datei->setDatei( pfad );
                    __int64 size = datei->getSize();
                    datei->release();
                    if( encrypted )
                        klient->sendeEncrypted( (char*)&size, 8 );
                    else
                        klient->sende( (char*)&size, 8 );
                }
                break;
            case 11: // Frage nach Datei ****Neues Update System
                if( 1 )
                {
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    if( encrypted )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\1", 1 );
                    int updateGruppe = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( (char*)&updateGruppe, 4 );
                    else
                        klient->getNachricht( (char*)&updateGruppe, 4 );
                    if( !ps->zDB()->supportedDateiGruppe( ps->getId(), updateGruppe ) )
                    {
                        int s = ps->zDB()->getDateiGruppePatchServer( klientNummer, updateGruppe );
                        int port = 0;
                        Text* ip = new Text();
                        bool ok = ps->zDB()->getPatchServerPortIp( s, &port, ip );
                        if( !s || !ok )
                            errorZuKlient( "Es ist momentan nicht möglich diese Datei herunterzuladen." );
                        else
                        {
                            if( encrypted )
                            {
                                klient->sendeEncrypted( "\2", 1 );
                                klient->sendeEncrypted( (char*)&port, 4 );
                                int len = ip->getLength();
                                klient->sendeEncrypted( (char*)&len, 4 );
                                klient->sendeEncrypted( (char*)ip->getText(), len );
                            }
                            else
                            {
                                klient->sende( "\2", 1 );
                                klient->sende( (char*)&port, 4 );
                                int len = ip->getLength();
                                klient->sende( (char*)&len, 4 );
                                klient->sende( (char*)ip->getText(), len );
                            }
                        }
                        ip->release();
                        break;
                    }
                    Text* gruppeN = ps->zDB()->getDateiGruppeName( updateGruppe );
                    if( !gruppeN )
                    {
                        errorZuKlient( "Dein System wird nicht unterstützt." );
                        break;
                    }
                    Text* pfad = new Text( ini->zWert( "SystemPfad" )->getText() );
                    pfad->append( "/" );
                    pfad->append( gruppeN );
                    pfad->append( "/" );
                    Text* tmp = ps->zDB()->getSystemName( system );
                    if( !tmp )
                    {
                        errorZuKlient( "Dein System wird nicht unterstützt." );
                        pfad->release();
                        break;
                    }
                    pfad->append( tmp );
                    pfad->append( "/" );
                    if( encrypted )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\1", 1 );
                    int len = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( (char*)&len, 4 );
                    else
                        klient->getNachricht( (char*)&len, 4 );
                    char* pf = new char[ len + 1 ];
                    pf[ len ] = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( pf, len );
                    else
                        klient->getNachricht( pf, len );
                    pfad->append( pf );
                    delete[] pf;
                    __int64 pos = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( (char*)&pos, 8 );
                    else
                        klient->getNachricht( (char*)&pos, 8 );
                    Datei* datei = new Datei();
                    datei->setDatei( pfad );
                    datei->open( Datei::Style::lesen );
                    if( pos )
                        datei->setLPosition( pos, 0 );
                    __int64 length = datei->getSize();
                    length -= pos;
                    char* bytes = new char[ 2048 ];
                    unsigned short byteLen = 0;
                    while( 1 )
                    {
                        if( !length )
                        {
                            klient->sende( "\0\0", 2 );
                            break;
                        }
                        byteLen = 2048;
                        if( length < 2048 )
                            byteLen = (unsigned short)length;
                        if( !klient->sende( (char*)&byteLen, 2 ) )
                            break;
                        datei->lese( bytes, byteLen );
                        if( !klient->sende( bytes, byteLen ) )
                            break;
                        length -= byteLen;
                        if( byteLen != 2048 )
                            break;
                        ps->addEmpfangen( klient->getDownloadBytes( 1 ) );
                        ps->addGesendet( klient->getUploadBytes( 1 ) );
                    }
                    char ret = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( &ret, 1 );
                    else
                        klient->getNachricht( &ret, 1 );
                    delete[] bytes;
                    datei->close();
                    datei->release();
                }
                break;
            case 12: // Frage nach Datei Gruppen Liste ****Neues Update System
                if( 1 )
                {
                    if( !klientNummer )
                    {
                        errorZuKlient( "Du bist nicht Identifiziert." );
                        break;
                    }
                    if( encrypted )
                        klient->sendeEncrypted( "\1", 1 );
                    else
                        klient->sende( "\1", 1 );
                    Result dgl = ps->zDB()->getDateiGruppeListe();
                    for( int i = 0; i < dgl.zeilenAnzahl; i++ )
                    {
                        if( encrypted )
                        {
                            int id = TextZuInt( dgl.values[ i * 3 ].getText(), 10 );
                            klient->sendeEncrypted( (char*)&id, 4 );
                            int len = dgl.values[ i * 3 + 1 ].getLength();
                            klient->sendeEncrypted( (char*)&len, 4 );
                            if( len )
                                klient->sendeEncrypted( dgl.values[ i * 3 + 1 ].getText(), len );
                            int vs = TextZuInt( dgl.values[ i * 3 + 2 ].getText(), 10 );
                            klient->sendeEncrypted( (char*)&vs, 4 );
                        }
                        else
                        {
                            int id = TextZuInt( dgl.values[ i * 3 ].getText(), 10 );
                            klient->sende( (char*)&id, 4 );
                            int len = dgl.values[ i * 3 + 1 ].getLength();
                            klient->sende( (char*)&len, 4 );
                            if( len )
                                klient->sende( dgl.values[ i * 3 + 1 ].getText(), len );
                            int vs = TextZuInt( dgl.values[ i * 3 + 2 ].getText(), 10 );
                            klient->sende( (char*)&vs, 4 );
                        }
                    }
                    if( encrypted )
                        klient->sendeEncrypted( "\0\0\0\0", 4 );
                    else
                        klient->sende( "\0\0\0\0", 4 );
                    dgl.destroy();
                    char ret = 0;
                    if( encrypted )
                        klient->getNachrichtEncrypted( &ret, 1 );
                    else
                        klient->getNachricht( &ret, 1 );
                }
                break;
            default:
                hack++;
                if( !errorZuKlient( "Unbekannte Nachricht!" ) )
                    br = 1;
                break;
            }
            if( br || hack >= 10 )
                break;
        }
        ps->addEmpfangen( klient->getDownloadBytes( 1 ) );
        ps->addGesendet( klient->getUploadBytes( 1 ) );
    }
    ps->addEmpfangen( klient->getDownloadBytes( 1 ) );
    ps->addGesendet( klient->getUploadBytes( 1 ) );
    ps->removeKlient( this ); // delete this
}

// constant
bool PSKlient::errorZuKlient( const char* nachricht ) const // sendet eine Fehlernachricht zum Klient
{
    if( encrypted )
    {
        if( !klient->sendeEncrypted( "\3", 1 ) )
            return 0;
        char len = (char)textLength( nachricht );
        if( !klient->sendeEncrypted( &len, 1 ) )
            return 0;
        if( !klient->sendeEncrypted( nachricht, len ) )
            return 0;
    }
    else
    {
        if( !klient->sende( "\3", 1 ) )
            return 0;
        char len = (char)textLength( nachricht );
        if( !klient->sende( &len, 1 ) )
            return 0;
        if( !klient->sende( nachricht, len ) )
            return 0;
    }
    return 1;
}

int PSKlient::getKlientNummer() const // gibt die KlientId zurück
{
    return klientNummer;
}