# coding=utf-8
#
#

import random, json, os, base64, subprocess, sys, re
import shutil, pwd, grp, distutils.dir_util

from myconst import *
from datetime import datetime
from operator import xor
from threading import Timer, Thread

debug   = False
UseLog  = True
printlog = False
verbose = 0
UseAuth = 1 ; MDUseAuth = True
UseToken = 1
onlyCL = True
InternetSperreClients = False
SocketTimeout_CL = defSocketTimeout_CL
DelayTime=defDelayTime
LogPfad = DefLog_Pfad
TokenTime = defTokenTime
BesetztTime = defBesetztTime
TerminateCollectTime = defTerminateCollectTime
TerminateTransferTime = defTerminateTransferTime
UseLineFeed = True ; useLF = lf

Thread_Nr = 0          # Nummer der MD-Client Thread
MDPfad = ''  ;  VNCTextPfad = ''  ; VNCPassPfad = ''  ; MD5Pfad = ''
ResetTime=0
LastIP = ''
LastRaum=''
Workstations_Pfad=''
MenuePass = False
Akt_Classrooms = ''
AdminUsers = ''
ExtraTeachers = ''
DisableTeacherSperre = True
SchoolBasisPfad = DefSchoolBasisPfad
UseSophomorix = DefUseSophomorix
UseTeacherPrefix=True ; AE_BasisPfad= DefAE_BasisPfad
AusZuPfad = '' ; AusGePfad = '' ; EinZuPfad = ''; EinGePfad = ''
Teacher_Pfad7  = ''
Schueler_Pfad7 = ''
WolCommand = ''  ;   WolDelay = 500
MDPort = DefMDPort
SKPort = DefSKPort
ResetList = []         # Liste:      Typ ; Wer ; now.strftime("%d/%m/%Y %H:%M:%S") ; User
KeyList   = {}         # Dictionary: Keylist[IP] = GKEY
TokenList = []         # Liste:      Wer ; Token ; +now.strftime("%d/%m/%Y %H:%M:%S") ; Raum
StopSKTimer = False
tzone = 2
TimerIntervall = 60

def logmessage (s):
    # TODO: print Befehl auskommentieren
    if UseLog:
        dt_string = datetime.now().strftime("%d.%m.%Y-%H:%M:%S ")
        if s.find('ldapwhoami') == 0 :
            # Lehrer-Passwort entfernen fuer log obsolet???
            p1 = s.find('" -w "')
            s1 = s[p1+6:]
            p2 = s1.find('"')
            s = s[:p1 + 6] + '****' + s1[p2:]
        p1 = s.find('"PASS": "')
        if p1>0:
            # MD-Passwort entfernen bei Befehl zum Client
            s1 = s[p1+9:]
            p2 = s1.find('"')
            s = s[:p1 + 9] + '****' + s1[p2:]
        p1 = s.find('--pam-logon=')
        if p1>0:
            # Passwort entfernen bei wbinfo-Befehl
            s1 = s[p1+12:]
            p2 = s1.find('"')
            s = s[:p1 + 12] + '****' + s1[p2:]
        if printlog:
            print(s)
        try:
            f = open(LogPfad,'a')
            f.write(dt_string + s + lf)
            f.close()
        except Exception as e:
            print('????? FEHLER: Logdatei nicht schreibbar? '+str(e))
    pass

def debugmessage(s):
    if debug:
        logmessage(s)

def Befehl_exec(Befehl):
    if verbose > 2:
        debugmessage('Befehl_exec -> Start')
    #    debugmessage('subprocess.run("' + ' '.join(Befehl) + '")')
        Befehllog = Befehl
        for i in Befehllog:
            if i == '--password':
                Befehllog.pop()
                Befehllog.append('***')
                break
        debugmessage('subprocess.Popen("' + ' '.join(Befehllog) + '")')
    try:
        #Ausgabe = subprocess.run(Befehl, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        proc = subprocess.Popen(Befehl, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        Ausgabe,err = proc.communicate()
        if verbose > 2:
        #    debugmessage('subprocess Ausgabe: '+Ausgabe.stdout.decode())
        #    debugmessage('subprocess stderr: ' + Ausgabe.stderr.decode())
            debugmessage('subprocess Ausgabe: <'+ Ausgabe.decode()+'>')
            debugmessage('subprocess stderr: <' + err.decode()+'>')
            pass
    except Exception as e:
        logmessage('Befehl_exec: '+str(e))
        Ausgabe=''.encode()
    #return Ausgabe.stdout.decode()
    if verbose > 2:
        debugmessage('Befehl_exec -> Ende')
    return Ausgabe.decode('utf-8')

def Befehl_execF(Befehl):                  # liefert stderr als Ausgabe
    if verbose > 2:
        debugmessage('Befehl_execF -> Start')
    #    debugmessage('subprocess.run("' + ' '.join(Befehl) + '")')
        Befehllog = Befehl
        for i in Befehllog:
            if i == '--password':
                Befehllog.pop()
                Befehllog.append('***')
                break
        debugmessage('subprocess.Popen("' + ' '.join(Befehllog) + '")')
    try:
        #Ausgabe = subprocess.run(Befehl, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        proc = subprocess.Popen(Befehl, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        Ausgabe,err = proc.communicate()
        if verbose > 2:
        #    debugmessage('subprocess Ausgabe: '+Ausgabe.stdout.decode())
        #    debugmessage('subprocess stderr: ' + Ausgabe.stderr.decode())
            debugmessage('subprocess Ausgabe: <'+ Ausgabe.decode()+'>')
            debugmessage('subprocess stderr: <<' +'unterdrueckt'+'>>')
        #return Ausgabe.stdout.decode()
        err_text = err.decode('utf-8')
    except Exception as e:
        logmessage('Befehl_execF: ' + str(e))
        err_text=''
    if verbose >2 :
        debugmessage('Befehl_execF -> Ende')
    return err_text.strip()

def Befehl_execTimeout(Befehl,timeout_sec):
    if verbose > 1:
        debugmessage('%%%%% Befehl_execTimeout '+str(timeout_sec)+'sec -> Start')
        debugmessage('%%%%% subprocess.Popen("' + ' '.join(Befehl) + '")')
    try:
        proc = subprocess.Popen(Befehl, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        timer = Timer(timeout_sec, proc.kill)
        try:
            timer.start()
            Ausgabe, err = proc.communicate()
            if proc.returncode != 0 :
                Ausgabe = ('WARNUNG: Process Timeout mit Returncode = '+str(proc.returncode)).encode()
                debugmessage('%%%%% ' + Ausgabe.decode('utf-8'))
        finally:
            timer.cancel()
    except Exception as e:
        Ausgabe = ('ERROR: Befehl_execTimeout: '+str(e)).encode()
    if verbose > 1:
        debugmessage('%%%%% Befehl_execTimeout -> Ende')
    return Ausgabe.decode('utf-8')

def Befehl_execTimeout2(Befehl, timeout_sec):
    if verbose > 1:
        debugmessage('%%%%% Befehl_execTimeout2 '+str(timeout_sec)+'sec -> Start')
        debugmessage('%%%%% subprocess.Popen("' + ' '.join(Befehl) + '")')
    Ausgabe='Befehl_execTimeout2 beendet'
    try:
        proc = subprocess.Popen(Befehl, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        proc_thread = Thread(target=proc.communicate)
        proc_thread.start()
        proc_thread.join(timeout_sec)
        if proc_thread.is_alive():
            # Process still running - kill it and raise timeout error
            try:
                proc.kill()
                Ausgabe = ('ERROR: Process Timeout mit Returncode = ' + str(proc.returncode))
            except OSError as e:
                # The process finished between the `is_alive()` and `kill()`
                Ausgabe = ('ERROR: Returncode = '+str(proc.returncode)+'   '+str(e))
    except Exception as e:
        Ausgabe = ('ERROR: '+str(e))
    # Process completed naturally - return exit code
    debugmessage('%%%%% ' + Ausgabe)
    if verbose > 1:
        debugmessage('%%%%% Befehl_execTimeout -> Ende')
    return Ausgabe

def GetUserServerHomePfad(u):
    if verbose > 1:
        debugmessage('GetUserServerHomePfad -> Start')
    Gruppe = GetGroup(u)
    Pfad = ''
    if Gruppe == 'teachers':
        Pfad = SchoolBasisPfad + 'teachers/' + u + '/'
    elif Gruppe != '':
        Pfad = SchoolBasisPfad + 'students/' + Gruppe + '/' + u + '/'
    if verbose > 1:
        debugmessage('GetUserServerHomePfad -> Ende')
    return Pfad

def Austeilen(Teacher, FromPfad, UserList, ToPfad):
    if verbose > 0:
        debugmessage('Austeilen -> Start')
    QuellPfad = GetUserServerHomePfad(Teacher) + FromPfad
    gid = grp.getgrnam('users').gr_gid
    for u in UserList.split(','):
        uid = pwd.getpwnam(u).pw_uid
        ZielPfad = GetUserServerHomePfad(u) + ToPfad
        if ZielPfad !='' :
            if not os.path.isdir(ZielPfad):
                try:
                    os.makedirs(ZielPfad)
                    os.chown(ZielPfad, uid, gid)
                except Exception as e:
                    logmessage('FEHLER: Austeilen-Pfad: ' + str(e))
            if os.path.isdir(QuellPfad):
                try:
                    debugmessage('QuellPfad: '+QuellPfad+'\nZielPfad: ' + ZielPfad)
                    # distutils.dir_util.copy_tree(QuellPfad, ZielPfad)
                    CopyTree(QuellPfad, ZielPfad,uid,gid,False)
                except Exception as e:
                    logmessage('FEHLER bei CopyTree: '+str(e))
            else:
                logmessage('FEHLER: Der Pfad "' + QuellPfad + '" existiert nicht!')
        else:
            logmessage('FEHLER: Austeilen-Zielpfad nicht ermittelbar!')
    if verbose > 0:
        debugmessage('Austeilen -> Ende')

def Einsammeln(Teacher, FromPfad, UserList, ToPfad, Option):
    if verbose > 0:
        debugmessage('Einsammeln -> Start')
    gid = grp.getgrnam('users').gr_gid
    for u in UserList.split(','):
        uid = pwd.getpwnam(u).pw_uid
        QuellPfad = GetUserServerHomePfad(u) + FromPfad
        ZielPfad0 = GetUserServerHomePfad(Teacher) + ToPfad
        ZielPfad = ZielPfad0 + u +'/'
        if not os.path.isdir(ZielPfad):
            try:
                os.makedirs(ZielPfad)
                t_uid = pwd.getpwnam(Teacher).pw_uid
                os.chown(ZielPfad0, t_uid, gid)
                os.chown(ZielPfad , t_uid, gid)
            except Exception as e:
                logmessage('FEHLER: ' + str(e))
        if QuellPfad !='':
            #debugmessage('QuellPfad: ' + QuellPfad + '\nZielPfad: ' + ZielPfad)
            if os.path.isdir(QuellPfad):
                try:
                    CopyTree(QuellPfad, ZielPfad, t_uid, gid,Option == '--move')
                except Exception as e:
                    logmessage('FEHLER bei CopyTree: '+str(e))
            else:
                debugmessage('INFO: Der Pfad "' + FromPfad + '" existiert nicht, wird angelegt')
                try:
                    os.makedirs(QuellPfad)
                    os.chown(QuellPfad, uid, gid)
                except Exception as e:
                    logmessage('FEHLER: '+str(e))
        else:
            logmessage('FEHLER: Einsammeln Quellpfad nicht ermittelbar!')
    if verbose > 0:
        debugmessage('Einsammeln -> Ende')

def CopyTree(QuellPfad,ZielPfad,uid,gid,Move):
    Art = 'move: ' if Move else  'copy: '
    for file in os.listdir(QuellPfad):
        QuellDatei = os.path.join(QuellPfad, file)
        ZielDatei = os.path.join(ZielPfad, file)
        if os.path.isdir(QuellDatei):
            try:
                if os.path.isfile(ZielDatei):
                    logmessage('ABBRUCH: Datei identisch Verzeichnisname: '+ZielDatei)
                else:
                    if not os.path.isdir(ZielDatei):
                        os.makedirs(ZielDatei)
                    CopyTree(QuellDatei,ZielDatei,uid,gid,Move)
                #if os.path.isdir(ZielDatei):
                #    shutil.rmtree(ZielDatei, ignore_errors=True)
                #    if verbose > 1:
                #        debugmessage('rmtree: ' + ZielDatei)
                #shutil.copytree(QuellDatei, ZielDatei)
                    if Move:
                        shutil.rmtree(QuellDatei, ignore_errors=True)
                    debugmessage(Art + file)
            except Exception as e:
                logmessage('FEHLER bei Copy Tree: ' + str(e))
        else:
            try:
                if Move :
                    shutil.move(QuellDatei,ZielDatei)
                else:
                    shutil.copy(QuellDatei, ZielPfad)
                debugmessage(Art + file)
            except Exception as e:
                logmessage('FEHLER bei Copy Datei: '+ Art + str(e))
    for dirpath, dirs, files in os.walk(ZielPfad):
        for file in dirs:
            os.chown(os.path.join(dirpath, file), uid, gid)
        for file in files:
            os.chown(os.path.join(dirpath, file), uid, gid)


#############################################################
#  Aufbau der ResetList
#           Typ    Wer
#           RAUM;zell;Zeit;<userlist>

def TimerAdd(Typ,Wer,User):
    if verbose >1 :
        debugmessage('TimerAdd ('+Typ+','+Wer+','+User+') -> Start')
    if (Wer == '') or (isValidIP(Wer) and not (Typ == 'DATEI')) :
        return
    if Typ == 'PROCESS' :
        pass
    else:
        UserOld = TimerDel(Typ, Wer).strip()
        if verbose > 1:
            debugmessage('Reset-Timer-UserOld: <'+UserOld+'>')
        if UserOld != '' :
            Liste = list(set(User.split(',')) | set(UserOld.split(',')))
            User = ','.join(Liste)
        now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
        ResetList.append(Typ + ';' + Wer + ';' + now + ';' + User)
        debugmessage('Reset-Timer-Gesetzt: ' + Typ + ' ' + Wer)
    if verbose > 1 :
        debugmessage('ResetList:\n'+'\n'.join(ResetList))
        debugmessage('TimerAdd (' + Typ + ',' + Wer + ',' + User + ') -> Ende')

def TimerDel(Typ,Wer):
    User = ''
    if (Wer == '') or (isValidIP(Wer)and not (Typ == 'DATEI')) :
        return User
    for z in ResetList:
        Daten = z.split(';')
        if (len(Daten) >= 3) and (Daten[0] == Typ) and (Daten[1] == Wer):
            User = Daten[3]
            ResetList.remove(z)
            debugmessage('Reset-Timer-Geloescht: ' + Typ + ' ' + Wer)
    return User

def TimerExec(n):
    if (n < len(ResetList)):
        Daten=ResetList[n].split(';')
        if len(Daten) > 2 :
            typ = Daten[0]
            wer = Daten[1]
            if (typ == 'RAUM') and (wer != '') and not (isValidIP(wer)) :
                SetDefaultRaumStatus(wer, Daten[3])
        else:
            logmessage('INTERNER FEHLER: TimerExec-Eintrag')
    else:
        logmessage('INTERNER FEHLER: TimerExec-Nummer')

def GetTimerUserList(Typ,Wer):
    if verbose > 1 :
        debugmessage('GetTimerUserList -> Start')
    User = ''
    if (Wer == '') or (isValidIP(Wer)) :
        return User
    for z in ResetList :
        Daten = z.split(';')
        if (len(Daten) >= 3) and (Daten[0] == Typ) and (Daten[1] == Wer) :
            User = Daten[3]
    if verbose > 1 :
        debugmessage('GetTimerUserList -> Ende')
    return User

def GetNewToken(Wer, Raum):
    now = datetime.now()
    for Zeile in TokenList:
        Daten=Zeile.split(';')
        Diff = now - datetime.strptime(Daten[2], "%d/%m/%Y %H:%M:%S")
        if (Daten[3] == Raum) and (Daten[0] != Wer ) and (Diff.total_seconds() < BesetztTime * 60):
            logmessage("Raum besetzt durch: "+Daten[0]+", Benutzer "+Wer+" wird abgewiesen!")
            return 'BESETZT'
    bu = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz'
    result = ''
    random.seed()
    L = len(bu)
    for n in range(0, defTokenLaenge):
        z = random.randint(0, L - 1)
        result = result + bu[z]
    return result

def ChangeToken(Wer,Raum):
    now = datetime.now()
    for Zeile in TokenList:
        Daten = Zeile.split(';')
        Diff = now - datetime.strptime(Daten[2], "%d/%m/%Y %H:%M:%S")
        if (Daten[3] == Raum) and (Daten[0] != Wer ) and (Diff.total_seconds() < BesetztTime * 60):
            logmessage("Raum besetzt durch: " + Daten[0] + ", Benutzer " + Wer + " wird abgewiesen!")
            return 'BESETZT'
    for Zeile in TokenList:
        Daten = Zeile.split(';')
        if (Daten[0] == Wer) and ((Daten[3]=='-') or (Daten[3]!=Raum)):
            AddToken(Wer, Daten[1], Raum)
            return 'OK'
    return ''

def AddToken(Wer, Token, Raum):
    if Wer != '':
        DelToken(Wer)
        if Raum=='':
            Raum = '-'
        now=datetime.now().strftime("%d/%m/%Y %H:%M:%S")
        TokenList.append(Wer + ';' + Token + ';' +now+';'+Raum)
        logmessage('Token-Timer-Gesetzt: ' + Wer)
        if verbose > 0 :
            debugmessage('\n'.join(TokenList))

def DelToken(Wer):
    for Zeile in TokenList:
        Daten = Zeile.split(';')
        if (Daten[0]==Wer):
            TokenList.remove(Zeile)

def CheckTeacherToken(Teacher,Token) :
    #debugmessage('CheckTeacherToken -> Start')
    result = False
    if Teacher != '' :
        for z in TokenList:
            Zeile = z.split(';')
            if (len(Zeile) == 4) and (Zeile[0] == Teacher) and (Zeile[1] == Token):
                result = True
                raum = Zeile[3]
                TokenList.remove(z)
                now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
                TokenList.append(Teacher + ';' + Token + ';' + now + ';' + raum)

    #debugmessage('CheckTeacherToken -> Ende')
    return result

def GetNewKey(IP) :
    bu = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz'
    result = ''
    random.seed()
    L = len(bu)
    for n in range(0,defKeyLaenge):
        z = random.randint(0,L-1)
        result = result + bu[z]
    KeyList[IP] = result
    debugmessage('KeyList: '+json.dumps(KeyList))
    return result

def GetKey(IP):
    return KeyList.get(IP,'')

def DelKey(IP):
    KeyList.pop(IP,None)

def GetClassrooms():
    Raeume = []
    if os.path.isfile(Classrooms_Pfad):
        debugmessage('Classrooms_pfad gefunden')
        try:
            f = open(Classrooms_Pfad, "r")
            Datei = f.read()
            f.close()
        except Exception as e:
            logmessage(str(e))
            Datei = ''
        Zeilen = Datei.splitlines()
        for z in Zeilen:
            z = z.strip()
            if (len(z) > 0):
                if (z[0] != '#') :
                    if  z not in Raeume:
                        Raeume.append(z)
        if len(Raeume)==0:
            logmessage('WARNING: Keine Klassenraeume in der Datei '+Classrooms_Pfad+' gefunden.')
    else:
        logmessage('INFO: Die Datei ' + Classrooms_Pfad + ' existiert nicht.')
    if len(Raeume)==0:
        if os.path.isfile(Workstations_Pfad):
            debugmessage('Workstations_pfad gefunden')
            try:
                f = open(Workstations_Pfad, "r")
                Datei = f.read()
                f.close()
            except Exception as e:
                logmessage(str(e))
                Datei = ''
            Zeilen = Datei.splitlines()
            for z in Zeilen:
                Zeile = z.strip()
                if (len(Zeile)>0) and (Zeile[0] !='#'):
                    Daten = Zeile.split(';')
                    if (len(Daten) > 8):
                        if (Daten[8] == Attribut_studentcomputer) :
                            if  Daten[0] not in Raeume:
                                Raeume.append(Daten[0])
        else:
            logmessage('ERROR: Die Datei ' + Workstations_Pfad + ' existiert nicht.')
    global Akt_Classrooms
    if len(Raeume)==0:
        Akt_Classrooms = ''
        logmessage('WARNING: Insgesamt keine Klassenraeume gefunden.')
    else:
        Akt_Classrooms = ','.join(Raeume)
        logmessage('Klassenraeume geladen: '+Akt_Classrooms)
    return Akt_Classrooms

def isClassroom(Raum):
    Raeume = Akt_Classrooms.split(',')
    if (Raum !='') and (Raum in Raeume):
        return True
    else:
        return False

def GetRaum(IP):
    if verbose > 1 :
        debugmessage('GetRaum zur IP = ' + IP+' - Start' )
    global LastIP
    global LastRaum
    if (IP==LastIP) and (LastRaum !=''):
        debugmessage('  LastRaum erkannt: ' + IP + ' -> ' + LastRaum)
        return LastRaum
    result = ''
    if os.path.isfile(Workstations_Pfad):
        try:
            f = open(Workstations_Pfad, "r")
            Workstations = f.read()
            f.close()
            zeilen = Workstations.splitlines()
            for z in zeilen:
                Zeile = z.strip()
                if (len(Zeile) >11) and (Zeile[0] != '#'):
                    Daten = Zeile.split(';')
                    if (len(Daten) > 4) and (Daten[4]==IP):
                        result = Daten[0]
                        LastIP = IP
                        LastRaum = result
                        logmessage('Raum erkannt: ' + IP + ' -> ' + result)
                        return result
        except Exception as e:
                logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei ' + Workstations_Pfad + ' existiert nicht.')
    logmessage('Raum zur IP nicht erkannt: ' + IP )
    return result

def GetRaumPCs(Raum): # Liefert Namen
    PCList = []
    if os.path.isfile(Workstations_Pfad):
        try:
            f = open(Workstations_Pfad, "r")
            Workstations = f.read()
            f.close()
            zeilen = Workstations.splitlines()
            for z in zeilen:
                Zeile = z.strip()
                if (len(Zeile) >11) and (Zeile[0] != '#'):
                    Daten = Zeile.split(';')
                    if (len(Daten) > 8) and (Daten[0]==Raum):
                        if ((Daten[8]==Attribut_studentcomputer) or (Daten[8]==Attribut_teachercomputer)):
                            PCList.append(Daten[1])
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei ' + Workstations_Pfad + ' existiert nicht.')
    return ','.join(PCList)

def GetRaumPCInfos(Raum):  # liefert: Name,IP,MAC
    anz = 0
    PCList = []
    if os.path.isfile(Workstations_Pfad):
        try:
            f = open(Workstations_Pfad, "r")
            Workstations = f.read()
            f.close()
            zeilen = Workstations.splitlines()
            for z in zeilen:
                Zeile = z.strip()
                if (len(Zeile) >11) and (Zeile[0] != '#'):
                    Daten = Zeile.split(';')
                    if (len(Daten) > 8) and (Daten[0]==Raum):
                        if ((Daten[8]==Attribut_studentcomputer) or (Daten[8]==Attribut_teachercomputer)):
                            s = Daten[1]+','+Daten[4]+','+Daten[3]
                            anz +=1
                            PCList.append(s)
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei ' + Workstations_Pfad + ' existiert nicht.')
    return ' '.join(PCList), anz

def GetRaumIPs(IP,Raum):
    IPList = []
    if os.path.isfile(Workstations_Pfad):
        try:
            f = open(Workstations_Pfad, "r")
            Workstations = f.read()
            f.close()
            zeilen = Workstations.splitlines()
            for z in zeilen:
                Zeile = z.strip()
                if (len(Zeile) >11) and (Zeile[0] != '#') and (Zeile[4]!=IP):
                    Daten = Zeile.split(';')
                    if (len(Daten) > 8) and (Daten[0]==Raum):
                        if ((Daten[8]==Attribut_studentcomputer) or (Daten[8]==Attribut_teachercomputer)):
                            IPList.append(Daten[4])
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei ' + Workstations_Pfad + ' existiert nicht.')
    return ','.join(IPList)

def GetRaumMACs(IP,Raum):
    MACList = []
    if os.path.isfile(Workstations_Pfad):
        try:
            f = open(Workstations_Pfad, "r")
            Workstations = f.read()
            f.close()
            zeilen = Workstations.splitlines()
            for z in zeilen:
                Zeile = z.strip()
                if (len(Zeile) >11) and (Zeile[0] != '#'):
                    Daten = Zeile.split(';')
                    if (len(Daten) > 8) and (Daten[0]==Raum):
                        if ((Daten[8]==Attribut_studentcomputer) or (Daten[8]==Attribut_teachercomputer)):
                            MACList.append(Daten[3])
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei ' + Workstations_Pfad + ' existiert nicht.')
    return ','.join(MACList)

def GetRaumStatus(Raum):
    DruckerStatus = ''
    d = 'on,on,on'
    r = ''
    if (onlyCL and not isClassroom(Raum)) :
        if Raum != '' :
            result ='NO'
            return result,DruckerStatus
    if os.path.isfile(Room_Defaults_Pfad):
        debugmessage('RoomDefaults_Pfad gefunden ...')
        try:
            f = open(Room_Defaults_Pfad, "r")
            Datei = f.read()
            f.close()
            zeilen = Datei.splitlines()
            for z in zeilen:
                Zeile = z.strip()
                if (len(Zeile) >1) and (Zeile[0] != '#'):
                    Daten = Zeile.split()
                    if len(Daten) >=4 :
                        if Daten[0]==Raum:
                            r = Daten[1]+','+Daten[2]+','+Daten[3]
                            if len(Daten) >= 5:
                                DruckerStatus = Daten[4]
                                break
                        else:
                            if 'default' == Daten[0].lower():
                                d = Daten[1] + ',' + Daten[2] + ',' + Daten[3]
                                if len(Daten) >= 5:
                                    DruckerStatus = Daten[4]
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei ' + Room_Defaults_Pfad + ' existiert nicht.')
        logmessage('... Default-Raum-Status "on,on,on" wird fuer Raum ' + Raum + ' verwendet')
    result = Raum + ',' + r + ',' + str(ResetTime) if (r !='') else Raum + ',' + d + ',' + str(ResetTime)
    return result, DruckerStatus

def GetDefaultRaumDruckerStatus(Raum):
    RST, DRST = GetRaumStatus(Raum)
    if DRST == 'on' :
        result = 'ACCEPT'
    elif DRST == 'off':
        result = 'REJECT'
    else:
        RaumDrucker = GetRaumDrucker(Raum)
        result = 'ACCEPT' if (RaumDrucker != '') else ''
    return result

def GetDefaultInternetStatus(RaumStatus):
    Daten = RaumStatus.split(',')
    if len(Daten)>3 :
        result = Daten[1]
    else:
        result = ''
    return result

def SetDefaultRaumStatus(Raum, UserList):
    if verbose > 1 :
        debugmessage('SetDefaultRaumStatus -> Start')
    if os.path.isfile(Soph_mana_script_Pfad):
        option = ''
        RST, DRST = GetRaumStatus(Raum)
        if GetDefaultInternetStatus(RST) == 'on'  :
            option = '--internet'
        if GetDefaultInternetStatus(RST) == 'off' :
            option = '--nointernet'
        if (UserList != '') and (option != '') :
            debugmessage('SetDefaultRaumStatus: Option ' + option + ' fuer: ' + UserList)
            Befehl = [Soph_mana_script_Pfad, option, UserList]
            Befehl_exec(Befehl)
            logmessage('Reset-Timer-Internet-ausgefuehrt fuer Raum: ' + Raum + ' ' + UserList)
        else:
            logmessage('ABBRUCH: Reset-Timer-Internet - unvollstaendige Daten')
    else:
        logmessage('ABBRUCH: Script fehlt: ' + Soph_mana_script_Pfad)
    if verbose > 1 :
        debugmessage('SetDefaultRaumStatus -> Ende')

def GetRaumDrucker(Raum):
    if verbose > 1:
        debugmessage('GetRaumDrucker: ' + Raum+' -> Start')
    Liste=[]
    if os.path.isfile(Workstations_Pfad):
        try:
            f = open(Workstations_Pfad, "r")
            Workstations = f.read()
            f.close()
            zeilen = Workstations.splitlines()
            for z in zeilen:
                Zeile = z.strip()
                if (len(Zeile) >11) and (Zeile[0] != '#'):
                    Daten = Zeile.split(';')
                    if (len(Daten) > 8) and (Daten[0]==Raum) and (Daten[8] == Attribut_printer):
                        Liste.append(Daten[1])
            if len(Liste)==0:
                debugmessage('Keine Drucker im Raum vorhanden.')
            else:
                debugmessage('Raumdrucker: ' + ','.join(Liste))
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei ' + Workstations_Pfad + ' existiert nicht.')
    if verbose > 1:
        debugmessage('GetRaumDrucker: -> Ende')
    return ','.join(Liste)

def GetUserLogins(Raum):
    Liste = []
    PCName = GetRaumPCs(Raum).split(',')
    PCLogin=[]
    PC_PID =[]
    if len(PCName)>0 :
        Befehl = ["smbstatus","-b"]
        Ausgabe = Befehl_exec(Befehl)
        # f = open("smb05.txt", "r")
        # Ausgabe = f.read()
        # f.close()
        PCIPs = GetRaumIPs('',Raum).split(',')
        if len(PCIPs) != len(PCName):
            logmessage('ERROR: len(PCIP) <> len(PCName)')
            return ''
        else:
            for x in PCName:
                PCLogin.append('-')
                PC_PID.append(0)
        zeilen = Ausgabe.splitlines()
        for z in zeilen:
            Zeile = z.strip()
            Daten = Zeile.split()
            pid = 0
            if len(Daten) >=4 :
                try:
                    pid = int(Daten[0])
                except ValueError:
                    pid = 0
            if (len(Daten) >= 4) and (pid > 0) :
                if Daten[2]=='users' :
                    URL = Daten[3].strip()
                    i = 0
                    for IP in PCIPs:
                        if URL == IP :
                            p = Daten[1].find('\\')+1
                            LoginName = Daten[1][p:]
                            if (PCLogin[i] == '-'):
                                PCLogin[i]= LoginName
                                PC_PID[i] = Daten[0]
                            else:
                                if (PCLogin[i] != LoginName):
                                    if pid > strtointdef(PC_PID[i],0):
                                        if verbose>0:
                                            debugmessage('WARNUNG smbstatus: PC '+IP+' mit mehreren Logins: ' + PCLogin[i] + ',' + LoginName+ ' -> Tausch')
                                        PCLogin[i]= LoginName
                                        PC_PID[i] = Daten[0]
                                    else:
                                        if verbose>0:
                                            debugmessage('WARNUNG smbstatus: PC '+IP+' mit mehreren Logins: ' + PCLogin[i] + ',' + LoginName)
                        i += 1
        i = 0
        for PC in PCName:
            Liste.append(PC+','+PCLogin[i])
            i +=1
    else:
        debugmessage('Keine Raum-PC gefunden!')
    return ' '.join(Liste)

def GetUsersRaum(AktBenutzer, Raum):
    result = []
    Liste = GetUserLogins(Raum).split()
    for z in Liste:
        Daten = z.split(',')
        if (len(Daten) == 2) and (Daten[1] != '-') :
            # Daten[1]=Daten[1]
            if Daten[1]!= AktBenutzer:
                result.append(Daten[1])
    return ','.join(result)

def GetUserGroups(Benutzer):
    if verbose > 1:
        debugmessage ('GetUserGroups -> Start')
    B = NoScriptTrim(Benutzer)
    result = ''
    if debug :
        Befehl = [Soph_query_script_Pfad, '--json', B]
    else:
        Befehl = [Soph_query_script_Pfad , '-jj', ' --sam', B]
    jsontxt = Befehl_execF(Befehl)
    jDATA, isValid = SophD_create(jsontxt)
    if isValid :
        result = SophD_getMemberOf(jDATA, Benutzer)
    if verbose > 1:
        debugmessage('GetUserGroups -> Ende')
    return result

def GetKlassenliste(Klasse):
    if verbose > 1:
        debugmessage('GetKlassenliste -> Start')
    result = ''
    if (Klasse == 'teachers') or (Klasse == 'admins'):
        logmessage('Fehler: Gruppe = ' + Klasse + ' liefert keine Klassenliste!')
    else :
        if debug :
            Befehl = [Soph_query_script_Pfad, '--json', '--sam', Klasse, '--group-members', '--user-minimal', '--group-minimal']
        else:
            Befehl = [Soph_query_script_Pfad, '-jj', '--sam', Klasse, '--group-members', '--user-minimal', '--group-minimal']
        jsontxt = Befehl_execF(Befehl)
        jDATA, isValid = SophD_create(jsontxt)
        if isValid :
            result = SophD_getSchuelerList(jDATA, Klasse)
        else :
            debugmessage('Fehler: sophomorix-JSON-DATA not valid')
    if verbose > 1:
        debugmessage('GetKlassenliste -> Ende')
    return result

def GetTeacherliste_L():
    if verbose > 1:
        debugmessage('GetTeacherliste_L -> Start')
    result = []
    if debug :
        Befehl = [Soph_query_script_Pfad, '--json', '--sam', 'teachers', '--group-members', '--user-minimal', '--group-minimal']
    else:
        Befehl = [Soph_query_script_Pfad, '-jj', '--sam', 'teachers', '--group-members', '--user-minimal', '--group-minimal']
    jsontxt = Befehl_execF(Befehl)
    jDATA, isValid = SophD_create(jsontxt)
    if isValid :
        result = SophD_getMemberList_L(jDATA, 'teachers')
    else :
        debugmessage('Fehler: sophomorix-JSON-DATA not valid')
    if verbose > 1:
        debugmessage('GetTeacherliste_L -> Ende')
    return result

def GetAllClasses():
    if verbose > 1 :
        debugmessage('GetAllClasses -> Start')
    result = ''
    if debug :
        Befehl = [Soph_query_script_Pfad, '--json', '--adminclass', '--group-minimal']
    else :
        Befehl = [Soph_query_script_Pfad, '-jj', '--adminclass', '--group-minimal']
    jsontxt = Befehl_execF(Befehl)
    jDATA, isValid = SophD_create(jsontxt)
    if isValid:
        result = SophD_getListsGroup(jDATA)
        if (result != '') and (verbose >0):
            debugmessage('Alle Klassen: '+result)
        elif (result == '') and (verbose >0):
            debugmessage('WARNUNG: Keine Klassen gefunden.')
    else:
        debugmessage('FFEHLER: sophomorix-JSON-DATA not valid')
    if verbose > 1 :
        debugmessage('GetAllClasses -> Ende')
    return result

def GetMDPass():
    result = ''
    if os.path.isfile(MDPfad):
        try:
            f = open(MDPfad, "r")
            result = f.read()
            f.close()
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei "' + MDPfad + '" existiert nicht!')
        result = 'md.pass - DATEI NICHT VORHANDEN!'
    return result

def GetMD5():
    result = ''
    if os.path.isfile(MD5Pfad):
        try:
            f = open(MD5Pfad, "r")
            result = f.read()
            f.close()
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei "' + MD5Pfad + '" existiert nicht!')
        result = 'md.md5 - DATEI NICHT VORHANDEN!'
    return result.strip()

def GetVNCText():
    result = ''
    if os.path.isfile(VNCTextPfad):
        try:
            f = open(VNCTextPfad, "r")
            result = f.read()
            f.close()
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei "' + VNCTextPfad + '" existiert nicht!')
        result = 'VNC.text - DATEI NICHT VORHANDEN!'
    return result

def GetVNCPass():
    result = ''
    if os.path.isfile(VNCPassPfad):
        try:
            f = open(VNCPassPfad, "r")
            result = f.read()
            f.close()
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Die Datei "' + VNCPassPfad + '" existiert nicht!')
        result = 'VNC.pass - DATEI NICHT VORHANDEN!'
    return result

def GetVNCPass64():
    return base64.b64encode(GetVNCPass().encode()).decode()

def GetAusteilenDateien(Teacher):
    debugmessage('GetAusteilenDateien -> Start')
    files = []
    AusteilPfad = Teacher_Pfad7 + Teacher + '/' + AE_BasisPfad + AusZuPfad
    if os.path.isdir(AusteilPfad):
        try:
            for file in os.listdir(AusteilPfad):
                if os.path.isdir(AusteilPfad+file):
                    files.append('['+file+']')
                else :
                    files.append(file)
        except Exception as e:
            logmessage(str(e))
    else:
        logmessage('ERROR: Der Pfad "' + AE_BasisPfad + AusteilPfad + '" existiert nicht!')
    debugmessage('GetAusteilenDateien -> Ende')
    if len(files) > 0 :
        return '|'+'|'.join(files)+'|'
    else:
        return ''

def enCrypt(PW,key):
    # print(PW + '   ' + key)
    C = PW
    if len(key) > 1:
        C = ''
        L = len(PW)
        i = 0
        for n in range(0,L):
            # print ('n='+str(n)+'   i='+str(i))
            C= C + chr(xor (ord(PW[n]),ord(key[i])))
            i += 1
            if i>=len(key):
                i = 0
    # print('C='+C)
    return base64.b64encode(C.encode()).decode()

def deCrypt(B64,key):
    try:
        C = base64.b64decode(B64.encode()).decode()
    except Exception as e:
        logmessage(str(e))
        C = B64
    L = len(C)
    i = 0
    PW = ''
    for n in range(0,L):
        PW = PW + chr(xor (ord(C[n]),ord(key[i])))
        i += 1
        if i >= len(key):
            i = 0
    return PW

def vtr(t):
    r = ''
    s = t
    l = len(t)
    if (l % 2) == 1 :
        r = t[l-1]
        l = l-1
        s = s[0:l]
    l = l // 2
    for n in range(l) :
        r = s[n * 2 ] + s[n * 2+1] + r
    return r

def NoScriptTrim(s):
    SonderZeichen='&/\"|;()[]{}*:<> `'''
    s = s.strip()
    for x in range(len(SonderZeichen)):
        s = s.replace(SonderZeichen[x], "")
    return s

def stripComments(code):
    code = str(code)
    return re.sub(r'(?m)^ *#.*\n?', '', code)

def is_Admin(Benutzer):
  Namen = AdminUsers.split(',')
  if (Benutzer in Namen):
      return True
  else:
      return False

def is_ExtraTeacher(Benutzer):
  Namen = ExtraTeachers.split(',')
  if (Benutzer in Namen):
      return True
  else:
      return False

def isValidIP(IP):
    parts = IP.split(".")
    if len(parts) != 4:
        return False
    for part in parts:
        if not isinstance(int(part), int):
            return False
        if int(part) < 0 or int(part) > 255:
            return False
    return True

def isValidIPList(Liste):
    for IP in Liste:
        if not isValidIP(IP):
            return False
    return True

def strtointdef(s,d):
    try:
        i = int(s)
    except ValueError:
        i = d
    return i

def GetLMN7():
    return True

def getAntwortJson(Wert):
    return json.dumps({tag_Antwort : Wert}).encode()+useLF.encode()

def getAntwortJson_TK(Wert, Token):
    return json.dumps({tag_Antwort: Wert, tag_Token: Token, tag_TokenTime: TokenTime, tag_lmn7: "TRUE"}).encode()+useLF.encode()

def getAntwortJson_R(Wert,R):
    return json.dumps({tag_Antwort: Wert, tag_Raum: R}).encode()+useLF.encode()

def getAntwortJson_anz(Wert,anz):
    return json.dumps({tag_Antwort: Wert, tag_Anzahl: str(anz)}).encode()+useLF.encode()

def getMDJson(Befehl, BText):
    result = dict()
    result[tag_Befehl] = Befehl
    if BText != '':
        result[tag_Text] = BText
    if MDUseAuth :
        result[tag_Pass]= vtr(GetMDPass())
    return json.dumps(result).encode()

def SophD_create( s ):
    if verbose>1:
        debugmessage ('SophD_create -> Start, Datenlaenge: '+str(len(s)))
    jDATA = '{}'
    jbegin = '# JSON-begin'
    jend   = '# JSON-end'
    isValid = False
    p1 = s.find(jbegin)
    p2 = s.find(jend)
    if (p1 > -1) and (p2 > p1):
        s = s[p1 + len(jbegin):p2]
    s=s.strip()
    # s = stripComments(s)  ??? Fehler wg. decoding?
    if len(s) > 1 :
        try:
            jDATA = json.loads(s)
            if len(jDATA)>0 :
              isValid = True
        except Exception as e:
            isValid = False
            logmessage('json-ERROR: '+str(e))
    if verbose > 1:
        debugmessage('SophD_create -> Ende')
    return jDATA, isValid

def SophD_getMemberOf(jDATA, Teacher):
    debugmessage('SophD_getMemberOf -> Start')
    result = []
    try:
        Memberliste = jDATA.get('USER').get(Teacher).get('memberOf')
        for zeile in Memberliste:
            Daten = zeile.split(',')
            if len(Daten)>2 :
                if (Daten[1]=='OU=Projects') or (Daten[2]=='OU=Students'):
                    result.append(Daten[0][3:])
    except Exception as e:
        logmessage('json-ERROR: '+str(e))
    debugmessage('SophD_getMemberOf -> Ende')
    return ','.join(result)

def SophD_getLoginTest(jDATA, Teacher):
    debugmessage('SophD_getLoginTest -> Start')
    try:
        result = jDATA.get('LOGINTEST').get(Teacher).get('LOGIN_OK')
    except Exception as e:
        logmessage('json-ERROR: '+str(e))
        result = False
    debugmessage('SophD_getLoginTest -> Ende')
    return result

def SophD_getListsGroup(jDATA):
    if verbose > 0:
        debugmessage('SophD_getListsGroup -> Start')
    # sophomorix-query -j --adminclass --group-minimal
    try:
        Liste = jDATA.get('LISTS').get('GROUP')
        result = ','.join(Liste)
    except Exception as e:
        logmessage('json-ERROR: '+str(e))
        result = ''
    if verbose > 0:
        debugmessage('SophD_getListsGroup -> Ende')
    return result

def SophD_getMemberList_L(jDATA, Klasse) :           # ergibt ggf. Schülerliste + Lehrer zusammen
    # sophomorix-query -j --adminclass --group-members
    debugmessage('SophD_getMemberList_L -> Start')
    try:
        result = jDATA.get('LISTS').get('MEMBERLIST').get(Klasse)
    except Exception as e:
        logmessage('json-ERROR: ' + str(e))
        result = []
    debugmessage('SophD_getMemberList_L -> Ende')
    return result

def SophD_getSchuelerList(jDATA, Klasse) :
    if verbose > 0:
        debugmessage('SophD_getSchuelerList -> Start')
    result = []
    try:
        s = jDATA.get('LISTS').get('MEMBERLIST').get(Klasse)
        for Member in s :
            DN = jDATA.get('MEMBERS').get(Klasse).get(Member).get('DN')
            Daten = DN.split(',')
            if (len(Daten)) > 2 and (Daten[2]=='OU=Students'):
                result.append(Member)
    except Exception as e:
        logmessage('json-ERROR: ' + str(e))
    if verbose > 0:
        debugmessage('SophD_getSchuelerList -> Ende')
    return ','.join(result)

def SophD_getCountersUser(jDATA):
    debugmessage('SophD_getCountersUser -> start')
    try:
        result = jDATA.get('COUNTERS').get('USER')
    except Exception as e:
        logmessage('json-ERROR: ' + str(e))
        result = 0
    debugmessage('SophD_getCountersUser -> Ende')
    return result

def CheckTeacher(Teacher):
    debugmessage ('CheckTeacher -> Start')
    T = NoScriptTrim(Teacher)
    if T != Teacher :
        logmessage('WARNUNG: Unerlaubte Sonderzeichen im Lehrername: <'+Teacher+'> ... <'+T+'>')
    result = False
    if is_ExtraTeacher(T):
        result = True
        if verbose > 1:
            debugmessage('Benutzer ' + T + ' ist Extra-Lehrer.')
    else:
        if debug :
            Befehl = [Soph_query_script_Pfad, '--json', '--sam', T, '--teacher',  '--user-minimal']
        else:
            Befehl = [Soph_query_script_Pfad, '-jj', '--sam', T, '--teacher', '--user-minimal']
        jsontxt = Befehl_execF(Befehl)
        jDATA, isValid = SophD_create(jsontxt)
        if isValid:
            if SophD_getCountersUser(jDATA) == 1:
                result = True
                if verbose >1 :
                    if result:
                        debugmessage('AD Benutzer ' + T + ' ist Lehrer.')
                    else:
                        debugmessage('AD Benutzer ' + T + ' ist kein Lehrer.')
        else:
            logmessage('Fehler: sophomorix-JSON-DATA is not valid')
    debugmessage('CheckTeacher -> Ende')
    return result

def CheckTeacherPW(Teacher,PW):
    debugmessage('CheckTeacherPW -> Start')
    T = NoScriptTrim(Teacher)
    if T != Teacher:
        logmessage('WARNUNG: Unerlaubte Sonderzeichen im Lehrername: <' + Teacher + '> ... <' + T + '>')
    result = False
    if (is_Admin(Teacher)) or (CheckTeacher(Teacher)):
        if UseSophPasswd:   # Option wird in myconst.py hart gesetzt !
            if debug :
                Befehl = [Soph_passwd_script_Pfad, '--json', '--test-login', Teacher, '--password', PW]
            else :
                Befehl = [Soph_passwd_script_Pfad, '-jj', '--test-login', Teacher, '--password', PW]
            jsontxt = Befehl_execF(Befehl)
            jDATA, isValid = SophD_create(jsontxt)
            if isValid:
                result = SophD_getLoginTest(jDATA,Teacher)
        else:
            Befehl = ['/usr/bin/wbinfo', '--pam-logon='+Teacher+'%'+PW]
            Ausgabe = Befehl_exec(Befehl)
            if Ausgabe.find('authentication succeeded') >=0 :
                result = True
    if result :
       logmessage('AD Authentifizierung mit credentials OK: '+Teacher)
    else :
        logmessage('AD Authentifizierung fehlgeschlagen: Invalid teacher credentials.')
    debugmessage('CheckTeacherPW -> Start')
    return result

def CheckTeacherHost(Teacher, IP):
    debugmessage('CheckTeacherHost -> Start')
    result = False
    if not ((is_Admin(Teacher)) or CheckTeacher(Teacher)) :
        if verbose > 0 :
            debugmessage('LDAP Authentifizierung fehlgeschlagen: '+Teacher+' ist kein Lehrer.')
    else:
        Raum = GetRaum(IP)
        AllePC, anz = GetRaumPCInfos(Raum)    # liefert Liste mit PCName,IP,MAC
        PCName = ''
        for PC in AllePC.split(' '):
            Daten = PC.split(',')
            if (len(Daten)>1) and (Daten[1]==IP):
                PCName = Daten[0]
                break
        AlleLogin = GetUserLogins(Raum).split(' ')   # liefert Liste mit PCName,login
        for Login in AlleLogin:
            Daten = Login.split(',')
            if (len(Daten)>1) and (Daten[0] == PCName) and (Daten[1] == Teacher):
                result = True
                break
        if verbose > 1:
           if result:
               debugmessage('smbstatus-Authentifizierung per Client-PC OK: ' + Teacher + ',' + PCName)
           else:
               debugmessage('Authentifizierung fehlgeschlagen: Kein PC mit Lehrer-Login (' + Teacher + ',' + IP + ',' + PCName + ').')
    debugmessage('CheckTeacherHost -> Ende')
    return result

def CheckTeacherHostIP(Teacher,IP):
    debugmessage('CheckTeacherHostIP -> Start')
    result = False
    if not ((is_Admin(Teacher)) or CheckTeacher(Teacher)) :
        if verbose > 0 :
            debugmessage('LDAP Authentifizierung fehlgeschlagen: '+Teacher+' ist kein Lehrer.')
    else:
        Befehl = ["smbstatus", "-b"]
        Ausgabe = Befehl_exec(Befehl)
        # f = open("smb30.txt", "r")
        # Ausgabe = f.read()
        # f.close()
        zeilen = Ausgabe.splitlines()
        # Zeilen:
        # PID  Username          Group  Maschine                              Protokoll Version Encryption Signing
        # 5807 LINUXMUSTER\zell  users  10.32.100.3 (ipv4:10.32.100.3:49161)  SMB2_10           -   HMAC-SHA256
        #
        if verbose > 1 :
            debugmessage('Starte Analyse der "smbstatus -b" Ausgabe ...')
        for z in zeilen:
            Zeile = z.strip()
            Daten = Zeile.split()
            d = 0
            if len(Daten) >= 4:
                try:
                    d = int(Daten[0])
                except ValueError:
                    d = 0
            if (len(Daten) >= 4) and (d > 0):
                if Daten[2] == 'users':
                    if IP == Daten[3].strip():
                        p = Daten[1].find('\\') + 1
                        LoginName = Daten[1][p:]
                        if Teacher == LoginName:
                            result = True
                            break
        if verbose > 1:
           if result:
               debugmessage('smbstatus-Authentifizierung per Client-IP OK: ' + Teacher + ',' + IP)
           else:
               debugmessage('Authentifizierung fehlgeschlagen: Keine IP mit Lehrer-Login (' + Teacher + ',' + IP + ').')
    debugmessage('CheckTeacherHostIP -> Ende')
    return result

def GetGroup(Benutzer):
    if verbose>1:
        debugmessage('GetGroup -> Start')
    B = NoScriptTrim(Benutzer)
    if B != Benutzer:
        logmessage('WARNUNG: Unerlaubte Sonderzeichen im Lehrername: <' + Benutzer + '> ... <' + B + '>')
    Gruppe= ''
    if debug:
        Befehl = [Soph_query_script_Pfad, '-j', '--sam', B,  '--group-minimal']
    else:
        Befehl = [Soph_query_script_Pfad, '-jj', '--sam', B,  '--group-minimal']
    jsontxt = Befehl_execF(Befehl)
    jDATA, isValid = SophD_create(jsontxt)
    if isValid:
        try:
            anz = jDATA.get('COUNTERS').get('USER')
            if anz == 1:
                Gruppe = jDATA.get('USER').get(B).get('sophomorixAdminClass')
                debugmessage('AD Benutzer ' + B + ' ist in Gruppe ' + Gruppe)
            else:
                logmessage('FEHLER: GetGroup: Benutzer existiert nicht: '+Benutzer)
        except Exception as e:
            logmessage('json-ERROR: ' + str(e))
            Gruppe = ''
    else:
        logmessage('Fehler: sophomorix-JSON-DATA is not valid')
    if verbose>1:
        debugmessage('GetGroup -> Ende')
    return Gruppe
