#!/usr/bin/perl -w

#
#       MoreTV-Commander
#
#       Version 0.1 
#
#       Datum: 09/2011
#
#       Autor: Markus Latzel
#
#
#

my $Version = "0.1";

# todo: 

# - ordner loeschen (Warnung bei abhaengigen Files) ; remote loeschen mit rm
# - Aufnahmen loeschen, verlinktes ziel auch loeschen
# - Tree sortieren (Nach Name, Datum oder Filename?
# - geaenderte Eintraege im Tree markieren
# - Drag_n_Drop
# - wenn workdir existiert, workdir nicht loeschen (in cleanup)




# Format eines Eintrags in @Dateien
# ---------------------------------
#
# index   Typ          Bedeutung
#---------------------------------
# 0       String       Dateiname
# 1       numerisch    dateiname als nummer (aus Filesystem)
# 2       char         Filetyp
# 3       int          Groesse-14
# 4       int          Dateiname (aus dem File gelesen)
# 5       String       Sendername (nur bei Aufzeichnungen)
# 6       String       Name
# 7       String       Beschreibung der Aufzeichnung
# 8       int          Parent-Ordner
# 9       String       kompletter Pfad
#10       int          Sendergroesse
#11       int          Namengroesse
#12       int          Descriptiongroesse
#13       int          Triggergroesse
#14       int          Linkgroesse
#15       String       Link
#16       char         schon gesehen
#17       char         behalten
#18       String       Ursprung
#19       char         ausgeblendet (nur [System]ordner ?) obsolete !!
#20       char         eintrag geaendert
#21       char         neu erzeugen
#22       long         Startzeit
#23       long         Endezeit


use strict;
use Tk;
use utf8;
use Cwd;
use Net::FTP ;
use Net::Ping ;
use Tk::Tree ;


#use Tk::DragDrop ;
#use Tk::DropSite ;


#globale Variablen

#konfiguration
my $appdir = cwd();

my $workdir = "/home/markus/Projekte/MoreTV_Commander/work";
my $workfile = "$workdir/workfile" ;


my $remotedir = "HardDisk/moreTV.persistent/tbArchProgramEvents.xbc";
my $targetip = "192.168.0.100";
my $username="root";
my $password="root";


#my $remotedir = "zwsp/Pollin_Board/ftp_testdir";
#my $targetip = "localhost";
#my $username="***";             # Benutzername auf dem FTP-Server
#my $password="***";             # Passwort für den Benutzer anonymous



my $view_filenames=0; #tut's das noch ?  dateinamen anstelle von  namen im Baum anzeigen

my $entryfont = "Courier 12";


my $ftp; #ftp-handle
my @dateien = ();
my $selected_entry;

my @ordnerliste =(); 

my @changed_files = (); #dateien, die uebertragen werden muessen
my @new_files = ();     #dateien, die uebertragen werden muessen aber auf dem Ziel noch nicht existieren


#checkboxvariablen
my $form_gesehen=0;
my $form_behalten=0;
my $form_changed=0;

my $form_parentordner;
my $form_parentordner_name;


my $bypass_callback=0;


#konstanten
my $xbc_header = "\x02\x05\x00\x00\x04\x00\x00\x01\x04\x00\x00\x18";
my $xbc_tail = "\xff\xff\xff";


# Ende variablen




#mainform
my $main = new MainWindow;
$main->geometry("800x600");
#$main->geometry("640x480");
$main->resizable( 0, 0 );
$main->title("MoreTV-Commander Version ".$Version);




#----------- Menue---------------
my $menue = $main->Menu;
$main->configure(-menu => $menue);

#Datei
my $datei = $menue->cascade(-label => 'Datei');
$datei->command(-label => 'Beenden', -command => \&exit);

#----------- Ende Menue---------------


#Treeview
my $recordtree = $main->Scrolled ('Tree' , -scrollbars=>'ose');
$recordtree->configure(font=> 'Courier 12', wideselection=> 0, -itemtype=>'text', background=>'white',selectbackground => 'grey', -command=>\&tree_command);
$recordtree->place( -x=>15, -y=>25 , -width=>270, -height=>520);


# Dateieigenschaften
my $fileframe = $main->Labelframe(-text=>"Eigenschaften");
$fileframe->place(-x => "300" , -y => "25", -width=>465, -height=>510);


my $lab_typ = $fileframe->Label(-text =>"Typ:");
my $labent_typ = $fileframe->Label(-relief=>"sunken", -width=>"20", -font=> $entryfont);
my $lab_sender = $fileframe->Label(-text =>"Sender:");
my $labent_sender = $fileframe->Label(-relief=>"sunken", -width=>"19", -font=> $entryfont);


my $lab_name = $fileframe->Label(-text =>"Name:");
my $ent_name = $fileframe->Entry(-width=>49, -font=> $entryfont);
$ent_name->bind("<FocusIn>", \&cb_name); #copy mit doppelklick
$ent_name->bind("<Key>", \&cb_name);

my $lab_record = $fileframe->Label(-text =>"Aufzeichnung:");
my $labent_record = $fileframe->Label(-relief=>"sunken", -width=>"44", -font=> $entryfont);


my $lab_desc = $fileframe->Label(-text =>"Beschreibung:");
my $txt_desc = $fileframe->Scrolled ('Text' , -scrollbars=>'ose');
$txt_desc->configure(font=> 'Courier 12');
$txt_desc->bind("<FocusIn>", \&cb_desc); #copy mit doppelklick
$txt_desc->bind("<Key>", \&cb_desc);

my $lab_trigger = $fileframe->Label(-text =>"Ursprung:");
my $labent_trigger = $fileframe->Label(-relief=>"sunken", -width=>"25", -font=> $entryfont);

my $lab_filename = $fileframe->Label(-text =>"Datei:");
my $labent_filename = $fileframe->Label(-relief=>"sunken", -width=>"25", -font=> $entryfont);

my $aufzframe = $fileframe->Labelframe(-text=>"Aufzeichnung");
my $chk_gesehen = $aufzframe->Checkbutton(-text =>"gesehen", -variable=>\$form_gesehen, -command=>\&cb_gesehen);
my $chk_behalten = $aufzframe->Checkbutton(-text =>"behalten", -variable=>\$form_behalten, -command=>\&cb_behalten);

my $lab_pfad = $fileframe->Label(-text =>"Pfad:");
my $labent_pfad = $fileframe->Label(-relief=>"sunken", -width=>"25", -font=> $entryfont);

my $lab_link = $fileframe->Label(-text =>"Link:");
my $labent_link = $fileframe->Label(-relief=>"sunken", -width=>"45", -font=> $entryfont);

my $chk_changed = $fileframe->Checkbutton(-text =>"Eintrag geändert", -state=>'disabled', -variable=>\$form_changed, -disabledforeground=>"Black");

my $lab_parentordner = $fileframe->Label(-text =>"Parentordner:");
my $opt_parentordner = $fileframe->Optionmenu(-width=>"20", -variable=>\$form_parentordner, -textvariable=>\$form_parentordner_name, -command=>\&cb_parentoption);


my $grframe = $fileframe->Labelframe(-text=>"gespeicherte Längen");
my $lab_filegr = $grframe->Label(-text =>"Datei:");
my $labent_filegr = $grframe->Label(-relief=>"sunken", -width=>"7", -font=> $entryfont);

my $lab_sendergr = $grframe->Label(-text =>"Sender:");
my $labent_sendergr = $grframe->Label(-relief=>"sunken", -width=>"7", -font=> $entryfont);

my $lab_namegr = $grframe->Label(-text =>"Name:");
my $labent_namegr = $grframe->Label(-relief=>"sunken", -width=>"7", -font=> $entryfont);

my $lab_descgr = $grframe->Label(-text =>"Beschreibung:");
my $labent_descgr = $grframe->Label(-relief=>"sunken", -width=>"7", -font=> $entryfont);

my $lab_triggergr = $grframe->Label(-text =>"Ursprung:");
my $labent_triggergr = $grframe->Label(-relief=>"sunken", -width=>"7", -font=> $entryfont);

my $lab_linkgr = $grframe->Label(-text =>"Link:");
my $labent_linkgr = $grframe->Label(-relief=>"sunken", -width=>"7", -font=> $entryfont);



$lab_typ->place(-x => "15" , -y => "15");
$labent_typ->place(-x => "70" , -y => "15");
$lab_sender->place(-x => "225" , -y => "15");
$labent_sender->place(-x => "280" , -y => "15");

$lab_name->place(-x => "15" , -y => "45");
$ent_name->place(-x => "70" , -y => "45");

$lab_record->place(-x => "15" , -y => "78");
$labent_record ->place(-x => "110" , -y => "80");



$lab_desc->place(-x => "15" , -y => "110");
$txt_desc->place(-x => "110" , -y => "110", -width=>312, -height=>90);

$lab_trigger->place(-x => "15" , -y => "215");
$labent_trigger->place(-x => "110" , -y => "215");

$lab_filename->place(-x => "15" , -y => "245");
$labent_filename->place(-x => "110" , -y => "245");

$aufzframe->place(-x => "320" , -y => "218", -width=>100, -height=>75);
$chk_gesehen->place(-x => "5" , -y => "5");
$chk_behalten->place(-x => "5" , -y => "26");

$lab_pfad->place(-x => "15" , -y => "285");
$labent_pfad->place(-x => "110" , -y => "285");

$lab_link->place(-x => "15" , -y => "315");
$labent_link->place(-x => "110" , -y => "315");

$chk_changed->place(-x => "15" , -y => "348");

$lab_parentordner ->place(-x => "160" , -y => "348");
$opt_parentordner ->place(-x => "255" , -y => "345");


$grframe->place(-x => "50" , -y => "375", -width=>340, -height=>110);
$lab_filegr->place(-x => "10" , -y => "10");
$labent_filegr->place(-x => "75" , -y => "10");

$lab_sendergr->place(-x => "10" , -y => "35");
$labent_sendergr->place(-x => "75" , -y => "35");

$lab_namegr->place(-x => "10" , -y => "60");
$labent_namegr->place(-x => "75" , -y => "60");

$lab_descgr->place(-x => "155" , -y => "10");
$labent_descgr->place(-x => "255" , -y => "10");

$lab_triggergr->place(-x => "155" , -y => "35");
$labent_triggergr->place(-x => "255" , -y => "35");

$lab_linkgr->place(-x => "155" , -y => "60");
$labent_linkgr->place(-x => "255" , -y => "60");


#globale Buttons
my $connbutton = $main->Button(-text => "Download", -command=>\&connect_download);
$connbutton->place(-x => "50" , -y => "555");

my $uploadbutton = $main->Button(-text => "Upload", -command=>\&upload_files);
$uploadbutton->place(-x => "250" , -y => "555");

my $storebutton = $main->Button(-text => "Änderungen speichern", -command=>\&patch_files);
$storebutton->place(-x => "420" , -y => "555");


my $testbutton = $main->Button(-text => "neuer Ordner", -command=>\&create_folder);
$testbutton->place(-x => "620" , -y => "555");



#callback's

sub tree_command { #bei doppelklick auf einen treeeintrag
#    logger("Treecommand");


    my @pfad = $recordtree->infoSelection;
    my $search = $pfad[0];
    
    foreach my $entry (@dateien) {     
   
        if ("@$entry[9]" eq  $search) {
            $selected_entry=\@$entry;
        }
    }

    #$opt_parentordner->configure(-options=>[ (@ordnerliste) ]);

    struct_to_form($selected_entry);
}


#callback's vom Formular

sub cb_name {
    #logger("name cb");
    if ( defined($selected_entry)) {
        if (($ent_name->get) ne $selected_entry->[6]) {
#            logger("name changed");
            $selected_entry->[6] = $ent_name->get;
            #$selected_entry->[20]=1;
            form_changed();
        }
    }
}

sub cb_desc {
#    logger("desc cb");
    if ( defined($selected_entry)) {
        if (($txt_desc->get("0.0", 'end')) ne $selected_entry->[7]) {
 #           logger("desc changed");
            #logger($txt_desc->get("0.0", 'end'));           
            $selected_entry->[7] = $txt_desc->get("0.0", 'end');

            #$selected_entry->[20]=1;
            form_changed();
        }
    }

}

sub cb_gesehen {
#    logger("gesehen cb");
    if ( defined($selected_entry)) {
        if ($form_gesehen != $selected_entry->[16]) {
 #           logger("gesehen changed");
            $selected_entry->[16] = $form_gesehen;
            #$selected_entry->[20]=1;
            form_changed();
        }
    }
}

sub cb_behalten { #0x03:behalten 0x02:loeschen
#    logger("behalten cb");
    if ( defined($selected_entry)) {
        if (($form_behalten && $selected_entry->[17] != 0x03) || (!$form_behalten && $selected_entry->[17] != 0x02) ) {
 #           logger("behalten changed");
            if ($form_behalten) {
                $selected_entry->[17]=0x03;
            } else {
                $selected_entry->[17]=0x02;
            }
            #$selected_entry->[20]=1;
            form_changed();
        }
    }
}

sub cb_parentoption {
    logger("cb Parentordner");


    if ($bypass_callback) {
        return;
    }

#    print  ("got $_[0]: ");
#    print ($form_parentordner);


    my $changed=0;

    if ( defined($selected_entry)) {

        if ($selected_entry->[8] != $_[0]) {
            if ($_[0] != $selected_entry->[1]) { #ordner in "sich selbst" legen verhindern
                $selected_entry->[8] = $_[0]; 
            }
            $changed=1;   
        }
    }

    if ($changed) {
        rebuild_tree();
        form_changed();
        struct_to_form($selected_entry);
    }
}


sub form_changed {
    $form_changed=1;
    
    if ($selected_entry->[21]==0) { # wenn der eintrag nicht neu ist
        $selected_entry->[20]=1;    # Flag "geaendert" setzen 
    }

    $storebutton->configure(-foreground=>"Red",-activeforeground=>"Red"  );   
    
    $recordtree->selectionSet($selected_entry->[9]);
    $recordtree->see($selected_entry->[9]);

}


# -----------------------  M A I N L O O P -----------------------

MainLoop;

# diverse Funktionen

my $ftpwindow;
my $txt_ftplog;

sub connect_log {
    $txt_ftplog->insert('end', $_[0]);
    $txt_ftplog->see('end');    
    $main->update();
}

sub ftp_connect {
    #Verbindung aufbauen

    $ftpwindow = $main->Toplevel();
    $ftpwindow->geometry("400x300");
    $ftpwindow->resizable( 0, 0 );
    $ftpwindow->title("Connect...");

    $txt_ftplog = $ftpwindow->Scrolled ('Text' , -scrollbars=>'ose');
    $txt_ftplog->configure(font=> 'Courier 12');
    $txt_ftplog->pack();

    my $pingretry=0;

    #erstmal anpingen

    my $ping = Net::Ping->new( "tcp", 5, 64 );
    my @pingresult;

    while ($pingretry<5){
        connect_log ("Ping $targetip...");

        @pingresult = $ping->ping($targetip);

        if ($pingresult[0] == 1) {
            connect_log ("ok. Time:$pingresult[1]  $pingresult[2]\n\n");
            $pingretry=5;
        } else {
            connect_log ( "no connection.\n");   
            $pingretry++;
        }
    }
          
    if ($pingresult[0])  { # enthaelt: sucessflag, time, returnstring
        #Verbinden

        connect_log ( "Connect to FTP...");   

        $ftp = Net::FTP->new($targetip, Debug=>0, Passive =>0);

        if (defined($ftp) != 1) {
            connect_log ("no connection.\n");   

            logger ("keine Verbindung zu $targetip (Ftp)");
            sleep(2); # 3 Selkunden warten
            $ftpwindow->destroy();
            return(1);
        }
    } else {
        connect_log ( "\n gebe auf.");   

        logger ("keine Verbindung zu $targetip (Ping)");
        sleep(2); # 3 Selkunden warten
        $ftpwindow->destroy();
        return(1);
    }

    my $loginresult = $ftp->login($username, $password);
    if (!$loginresult) {
        connect_log ( "login failed.");   

        logger ("Loginfehler.");
        sleep(2); # 3 Selkunden warten
        $ftpwindow->destroy();
        return(1);
    } else {
        connect_log ("ok.\n\n");   
    }

    #Verzeichnise wechseln

    #$ftp->lcd($workdir);
    chdir($workdir);
    $ftp->cwd($remotedir);
    return(0);
}



#verbinden und alle Files runterladen
sub connect_download {
    my $filenum=0;
    #logger("connect_download");

    #verzeichnis vorhanden?
    if (-e $workdir) { 
        logger("workdir exist");
        if (-d $workdir) { #Eintrag ein verzeichnis?
            opendir(DIR, $workdir); #verzeichnis leer?
            while(my $datei = readdir(DIR)) {
#                logger("$datei");
                if ($datei ne "." && $datei ne "..") {
                    $filenum++;
                }
            }
            closedir(DIR);
            if ($filenum==0) {
                logger("workdir empty");
            } else {
                logger("workdir NOT empty");
                if (ok_cancel_box("Im Arbeitsverzeichnis sind Dateien vorhanden. Sollen diese gelöscht werden?")) {
                    logger("delete files...");
                    cleanup(0);
                    logger("ok.");
                    # exit;
                } else {
                    logger("cancled");
                    return;
                }
            }
        } else {
            logger("ERROR: workdir exist, but it's not a Directory.");
        }
    } else {
        mkdir($workdir,0777);
        logger("created workdir ($workdir)");
    }

   
    if (ftp_connect()) {
        return;
        logger("exit!");
    }


    my @files = $ftp->dir();
    my $fileanzahl = @files;

    $ftp->binary;


    
    for (my $i=0;$i<$fileanzahl;$i++) {
        $files[$i] =~ s/(.*) ([0-9]+\.xbc$)/$2/ ;
        connect_log("get $files[$i]...");
#        logger("get $files[$i]");
        $ftp->get($files[$i]);
        if ($ftp) {
            connect_log("ok.\n");
        }
    }
    
    connect_log("all files downloaded.");
    $ftp->quit();
    
    sleep(1);
    $ftpwindow->destroy();

    parse_files();  

}


sub parse_files {
    #logger("parse files");
    
    chdir($workdir);
    @dateien = (); #alt loeschen

    
    my @fileliste = glob("*.xbc");
    foreach my $filename (@fileliste) {
        my @entry = [];
            
        $entry[0] = $filename; #filename   (als string)
        $filename =~ s/.xbc// ;
        $entry[1] = 0; #nummer 
        $entry[1] = $filename;

        get_properties(\@entry);
       
        #in die struktur einhaengen
        @dateien = (@dateien, \@entry);
    }  

# gesammelte infos in den Baum einhaengen    

    $selected_entry = $dateien[0]; #1. Eintrag selektieren

    rebuild_tree();

    tree_command(); #form mit selektiertem eintrag fuellen

    $storebutton->configure(-foreground=>"Black", -activeforeground=>"Black");
}


sub patch_files {
    logger("patch files");


    if ((@changed_files)  || (@new_files)) {
        if (ok_cancel_box("Es sind Änderungen vorhanden, die noch nicht Übertragen wurden. Sollen die Änderungen wirklich verworfen werden ?") == 0) {
            logger("canceld");
            return;
        }
        @changed_files = ();
        @new_files = ();

    }

    foreach my $entry (@dateien) {
        if (@$entry[20]) { #Eintrag geaendert
            patch_file(\@$entry);

            @changed_files = (@changed_files, @$entry[0]);
        }
        if (@$entry[21]) { #Eintrag neu
            create_file(\@$entry);

            @new_files = (@new_files, @$entry[0]);
        }

    }

    $storebutton->configure(-foreground=>"Black", -activeforeground=>"Black");
    $uploadbutton->configure(-foreground=>"Red", -activeforeground=>"Red" );


    rebuild_tree(); # aenderungen auch im Tree anzeigen
    struct_to_form($selected_entry);
}


sub create_file {
    logger("create $_[0]->[0].");
    
    my $len_file=59; #typ 0x0b
    my $len_name;
    my $buffer;

    my $unknown1 = "\x00\x00\x06";
    my $unknown2 = "\x07\x00\x00\x00\x00\x08\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x18\x00\x1a\x7f\x1e";
    my $unknown3 = "\x00\x00\x1f\x02\x20\x01\x24\x00\x00\x00\x00";


    open(OUTFILE, ">$workfile");
    binmode(OUTFILE);

    #header schreiben
    print(OUTFILE $xbc_header);

    #laenge des namens zur filelaenge addieren
    $buffer = $_[0]->[6]; #name
    $buffer = string_2_dat($buffer);

    $len_name = length($buffer);            
    $len_file += $len_name;


    #dateigroesse schreiben
    $len_file -= 14;
    $buffer = unsignedint_2_dat($len_file);
    print(OUTFILE $buffer);

    #dateityp schreiben (2 Bytes)
    $buffer = unsignedint_2_dat($_[0]->[2]);
    print(OUTFILE $buffer);
    
    #dateiname (int) schreiben
    $buffer = unsignedint_2_dat($_[0]->[1]);
    print(OUTFILE $buffer);
   
    #unbekannte bytes zwischen dateiname und namensgroesse
    print(OUTFILE $unknown1);
    

    #namensgroesse
    $buffer=$len_name;
    $buffer = unsignedint_2_dat($buffer);
    print ( OUTFILE $buffer); #namensgroesse speichern
        
    #name speichern
    $buffer = $_[0]->[6];
    $buffer = string_2_dat($buffer);
    print ( OUTFILE $buffer);

    
    #unbekannte bytes zwischen Name und parentordner
    print(OUTFILE $unknown2);

    #parentordner speichern
    $buffer = $_[0]->[8];
    $buffer = unsignedint_2_dat($buffer);
    print(OUTFILE $buffer);
        
    #unbekannte bytes zwischen Parentordner und Tail kopieren
    print(OUTFILE $unknown3);
       

    #ende speichern
    print(OUTFILE $xbc_tail); 
    close(OUTFILE);


    #rename
    unlink($_[0]->[0]);
    rename($workfile, "$workdir/$_[0]->[0]");
    
    $_[0]->[21]=0; #neu-flag loeschen
}


sub patch_file {
#    logger("Patching $_[0]->[0].");
    
    my $readpointer;

    my $buffer;

    my $len_file;

    my $len_sender;
    my $len_name;
    my $len_desc;
    my $len_trigger;
    my $len_link;

    open(INFILE, $_[0]->[0]);
    open(OUTFILE, ">$workfile");

    binmode(INFILE);
    binmode(OUTFILE);

    
    #header schreiben
    print(OUTFILE $xbc_header);

    #neue Dateilaenge berechnen
    if ($_[0]->[2] == 0x0d) { #systemordner
        $len_file = 73;
    } 
    elsif ($_[0]->[2] == 0x0b) { #eigene Ordner
        $len_file = 59;
    }
    elsif ($_[0]->[2] == 0x23) { #Aufnahme
        $len_file = 0x8f;
    }
    elsif ($_[0]->[2] == 0x1d) { #Aufnahme
        $len_file = 0x7d;
    }
    elsif ($_[0]->[2] == 0x1c) { #Aufnahme
        $len_file = 0x7a;
    }

    else {
        logger("Filetype $_[0]->[2] unsupported");
    }

    #laenge des namens zur filelaenge addieren
    $buffer = $_[0]->[6]; #name
    $buffer = string_2_dat($buffer);

    $len_name = length($buffer);            
    $len_file += $len_name;
    #logger ("name: $len_name");
   
    #laenge des Sendernamens zur filelaenge addieren
    if (($_[0]->[2] == 0x23) || ($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c))   { #Aufnahme
        $buffer = $_[0]->[5]; #Sendername
        $buffer = string_2_dat($buffer);

        $len_sender = length($buffer);            
        $len_file += $len_sender;
     #   logger ("sender: $len_sender");

    
    #laenge der Beschreibung zur filelaenge addieren
        $buffer = $_[0]->[7]; #Beschreibung
        $buffer = string_2_dat($buffer);

        $len_desc = length($buffer);            
        $len_file += $len_desc;
 #       logger ("desc: $len_desc");
   
    #laenge des Triggers zur filelaenge addieren
        $len_trigger = $_[0]->[13]; #wird nicht geaendert, daher aus dem Quellfile nehmen
        $len_file += $len_trigger;
#        logger ("trigger: $len_trigger");

    #laenge des Links zur filelaenge addieren
        $buffer = $_[0]->[15]; #Link
        $buffer = string_2_dat($buffer);

        $len_link = length($buffer);            
        $len_file += $len_link;
#        logger ("link: $len_link");
    }
    
#    logger("dateigroesse: $len_file");

    #dateigroesse schreiben
    $len_file -= 14;
    $buffer = unsignedint_2_dat($len_file);
    print(OUTFILE $buffer);

    #dateityp schreiben (2 Bytes)
    $buffer = unsignedint_2_dat($_[0]->[2]);
    print(OUTFILE $buffer);
    
    #dateiname (int) schreiben
    $buffer = unsignedint_2_dat($_[0]->[1]);
    print(OUTFILE $buffer);
    
    
    if (($_[0]->[2] == 0x0d) ||($_[0]->[2] == 0x0b)) {  # Ordner
        #unbekannte bytes zwischen dateiname und namensgroesse
        $readpointer = 18;
    
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 3);
        print(OUTFILE $buffer);

        #namensgroesse
        if ($_[0]->[2] == 0x0d) { #systemordner
            $buffer = char_2_dat($len_name);
            $readpointer=0x16;
        } else { #eigener ordner
            $buffer = unsignedint_2_dat($len_name);
            $readpointer=0x17;
        } 
        print ( OUTFILE $buffer); #namensgroesse speichern
        
        #name speichern
        $buffer = $_[0]->[6];
        $buffer = string_2_dat($buffer);
        print ( OUTFILE $buffer);

        $readpointer += $_[0]->[11]; #redpointer um gespeicherte namenlaenge erhoehen
        seek(INFILE, $readpointer, 0);

        #unbekannte bytes zwischen Name und parentordner kopieren
        if ($_[0]->[2] == 0x0b) {
            read(INFILE, $buffer, 20);
            $readpointer +=20;
        } else {
            read(INFILE, $buffer, 35);
            $readpointer +=35;
        }
        print(OUTFILE $buffer);


        #parentordner speichern
        $buffer = unsignedint_2_dat($_[0]->[8]);
        print(OUTFILE $buffer);
        
        $readpointer +=2;

        #unbekannte bytes zwischen Parentordner und Tail kopieren
        
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 11);
        print(OUTFILE $buffer);
       
    }
    elsif ($_[0]->[2] == 0x23) { # Aufnahme Typ 0x23

        #unbekannte bytes zwischen dateiname und Sendergroesse
        $readpointer = 0x12;
    
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 8);
        print(OUTFILE $buffer);
        $readpointer +=8;

        #sendergroesse
        $buffer = char_2_dat($len_sender);
        print(OUTFILE $buffer);
        $readpointer++; #senderlaenge ist 1 byte
        
        #sendername schreiben
        $buffer = $_[0]->[5];
        $buffer = string_2_dat($buffer);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[10]; #gespeicherte senderlaenge

        #unbekannte bytes zwischen Sender und NAme
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 16);
        print ( OUTFILE $buffer);
        $readpointer += 16;

        #namengroesse
        $buffer = unsignedint_2_dat($len_name);
        print(OUTFILE $buffer);
        $readpointer +=2;
        
        #name
        $buffer = $_[0]->[6];
        $buffer = string_2_dat($buffer);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[11]; #gespeicherte namengroesse
        
        #unbekannte bytes zwischen name und beschreibung kopieren (Zeitstempel)
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 13);
        print ( OUTFILE $buffer);
        $readpointer +=13;
        
        #desc-groesse
        $buffer = unsignedint_2_dat($len_desc);
        print(OUTFILE $buffer);
        $readpointer +=2;

        #Beschreibung
        $buffer = $_[0]->[7];
        $buffer = string_2_dat($buffer);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[12]; #gespeicherte desc-groesse
        
        #unbekannte bytes zwischen Beschreibung und behalten-flag 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 17);
        print ( OUTFILE $buffer);
        $readpointer += 17;

        #behalten-flag
        $buffer = $_[0]->[17];
        $buffer = char_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer++;

        #unbekanntes bytes zwischen den flags 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 1);
        print ( OUTFILE $buffer);
        $readpointer ++;

        #gesehen-flag
        $buffer = $_[0]->[16];
        $buffer = char_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer++;
        
        #unbekanntes byte zwischen  gesehen-flag und triggergroesse 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 1);
        print ( OUTFILE $buffer);
        $readpointer ++;
        
        #triggergroesse
        $buffer = char_2_dat($len_trigger);
        print(OUTFILE $buffer);
        $readpointer++;
        
        #trigger (wird aus dem Quellfile uebernommen)
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, $len_trigger);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[13]; #gespeicherte trigger-groesse;

        #unbekannte bytes zwischen Trigger und Parentordner 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 26);
        print ( OUTFILE $buffer);
        $readpointer += 26;

        #parentordner
        $buffer = $_[0]->[8];
        $buffer = unsignedint_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer +=2;
        
        #unbekannte bytes zwischen Parentordner und link
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 7);
        print ( OUTFILE $buffer);
        $readpointer += 7;
           
        #linkgroesse
        $buffer = unsignedint_2_dat($len_link);
        print(OUTFILE $buffer);
        $readpointer +=2;
    
        #link
        $buffer = $_[0]->[15];
        $buffer = string_2_dat($buffer);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[14]; #gespeicherte linkgroesse
        
        #unbekannte bytes zwischen Link und Ende kopieren 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 21);
        print ( OUTFILE $buffer);
       
    }

    elsif ( ($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c) ) { #Aufnahme

        #unbekannte bytes zwischen dateiname und Sendergroesse
        $readpointer = 0x12;
    
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 8);
        print(OUTFILE $buffer);
        $readpointer +=8;

        #sendergroesse
        $buffer = $len_sender;
        $buffer = char_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer++;
        
        #sendername schreiben
        $buffer = $_[0]->[5];
        $buffer = string_2_dat($buffer);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[10]; #gesp. sendergroesse

        #unbekannte bytes zwischen Sender und NAme
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 16);
        print ( OUTFILE $buffer);
        $readpointer += 16;

        #namengroesse
        $buffer = $len_name;
        $buffer = unsignedint_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer +=2;
        
        #name
        $buffer = $_[0]->[6];
        $buffer = string_2_dat($buffer);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[11]; #gesp. namengroesse
        
        #unbekannte bytes zwischen name und beschreibung kopieren (Zeitstempel)
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 11);
        print ( OUTFILE $buffer);
        $readpointer +=11;
        
        #desc-groesse
        $buffer = $len_desc;
        $buffer = unsignedint_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer +=2;

        #Beschreibung
        $buffer = $_[0]->[7];
        $buffer = string_2_dat($buffer);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[12]; #gesp. desc-groesse
        
        #unbekannte bytes zwischen Beschreibung und behalten-flag  kopieren 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 8);
        print ( OUTFILE $buffer);
        $readpointer += 8;

        #behalten-flag
        $buffer = $_[0]->[17];
        $buffer = char_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer++;

        #unbekanntes bytes zwischen den flags 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 1);
        print ( OUTFILE $buffer);
        $readpointer ++;

        #gesehen-flag
        $buffer = $_[0]->[16];
        $buffer = char_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer++;
        
        #unbekanntes byte zwischen  gesehen-flag und triggergroesse 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 1);
        print ( OUTFILE $buffer);
        $readpointer ++;

        #triggergroesse
        $buffer = $len_trigger;
        $buffer = char_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer++;
        
        #trigger (wird aus dem Quellfile uebernommen)
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, $len_trigger);
        
        print (OUTFILE $buffer);
        $readpointer += $_[0]->[13]; #gesp. triggergroesse;


        #unbekannte bytes zwischen Trigger und Parentordner 
        if ($_[0]->[2] == 0x1d) {
            seek(INFILE, $readpointer, 0);
            read(INFILE, $buffer, 23);
            print (OUTFILE  $buffer);
            $readpointer += 23;
        } else {
            seek(INFILE, $readpointer, 0);
            read(INFILE, $buffer, 20);
            print (OUTFILE  $buffer);
            $readpointer += 20;
        }
        
        #parentordner speichern
        $buffer = $_[0]->[8];
        $buffer = unsignedint_2_dat($buffer);
        print(OUTFILE $buffer);
        $readpointer +=2;
         
        #unbekannte bytes zwischen Parentordner und link 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 7);
        print (OUTFILE  $buffer);
        $readpointer += 7;


        #linkgroesse
        $buffer = unsignedint_2_dat($len_link);
        print(OUTFILE $buffer);
        $readpointer +=2;
       
        #link
        $buffer = string_2_dat($_[0]->[15]);
        print ( OUTFILE $buffer);
        $readpointer += $_[0]->[14]; #gesp. linkgroesse;;
        
        #unbekannte bytes zwischen Link und Ende kopieren 
        seek(INFILE, $readpointer, 0);
        read(INFILE, $buffer, 17);
        print ( OUTFILE $buffer);
 
    
    } else {
        logger("Typ $_[0]->[2] unsupported");
        close(INFILE);
        close(OUTFILE);
        return;
    }

    #ende speichern
    print(OUTFILE $xbc_tail);
    
    $_[0]->[20]=0; #geaendert-flag loeschen

    close(INFILE);
    close(OUTFILE);

    unlink($_[0]->[0]);
    rename($workfile, "$workdir/$_[0]->[0]");
}


sub upload_files {
    logger ("upload");

    if ((@changed_files == 0) && (@new_files == 0) ) {
        logger ("nothing changed/new.");
        return;
    }

    if (ftp_connect()) {
        return;
    }

    $ftp->binary();


    connect_log("Upload @new_files new files:\n");

    foreach  my $file (@new_files) {
        connect_log("$file...");
        $ftp->put($file);
        connect_log("ok.\n");
    }

    connect_log("Upload @changed_files changed files:\n");

    foreach  my $file (@changed_files) {
        connect_log("$file...");
        $ftp->delete($file);
        $ftp->put($file);
        connect_log("ok.\n");
    }
    

    connect_log("\nAll files uploaded.\n\n Please reset receiver immediatly !");

    $ftp->quit();
    $uploadbutton->configure(-foreground=>"Black", -activeforeground=>"Black");
    
    @changed_files = ();
    @new_files = ();
    

    sleep(3);
    $ftpwindow->destroy();
}




sub rebuild_tree {
 #   logger("TreeRebuild");
    
    $bypass_callback=1;

    $recordtree->selectionClear();
    $recordtree->deleteAll();
    
    @ordnerliste =();

    foreach my $entry (@dateien) {

        @$entry[9]="";  # in allen Eintraegen kompletten pfad loeschen

        if (@$entry[2]==0x0d) { #systemordner
            create_treeentry(\@$entry);
            @ordnerliste = ( @ordnerliste, [@$entry[6] => @$entry[1]]);
        }
    }

    foreach my $entry (@dateien) {
        if (@$entry[2]==0x0b) { #eigene ordner
            create_treeentry(\@$entry);
            @ordnerliste = ( @ordnerliste, [@$entry[6] => @$entry[1]]);
        }
    }

    foreach my $entry (@dateien) {
        if ((@$entry[2]!=0x0d) && (@$entry[2]!=0x0b)) { #der rest
            create_treeentry(\@$entry);
        }
    }      

    $recordtree->autosetmode();

    $opt_parentordner->configure(-options=>[ (@ordnerliste) ]);

    $bypass_callback=0;

    $recordtree->selectionSet($selected_entry->[9]);


#    logger("TreeEnd");

}



sub create_treeentry {

#    logger(" | create $_[0]->[1]: ");


    my $entrycolor;

    if ($_[0]->[1] == 0) {
        
        if ($_[0]->[20]) {
            $entrycolor= "Red";
        } else {
            $entrycolor= "Black";
        }

        if ($view_filenames) {
                $recordtree->add( $_[0]->[1], -text=>$_[0]->[0] );
        } else {
                $recordtree->add( $_[0]->[1], -text=>$_[0]->[6] );
        }
        #$recordtree->itemConfigure(-textcolor=>$entrycolor);
        $_[0]->[9] = "0";
        return;
    }
    
    # parent-entry suchen
    my $parententry;
    foreach my $entry (@dateien) {
        if (@$entry[1] == $_[0]->[8]) {
            $parententry=$entry;
 #           logger ("pfad:  $_[0]->[9]");
        }
    }

    if ($recordtree->infoExists(@$parententry[9])) {

        #logger("parent $_[0]->[8] exist. ");
        $_[0]->[9] = "@$parententry[9].$_[0]->[1]";
        
        if ($recordtree->infoExists($_[0]->[9])) { # wurde schon erzeugt
            return;
        }

        if ($view_filenames) {
            $recordtree->add( "$_[0]->[9]", -text=>$_[0]->[0] );
        } else {
            $recordtree->add( "$_[0]->[9]", -text=>$_[0]->[6] );
        }        

    } else {
        #logger("parent $_[0]->[8] exist NOT. ");
        
        #erstmal parent einhaengen
        create_treeentry(\@$parententry);
        
        # jetzt nochmal probieren
        create_treeentry($_[0]);

    }
}



#liest die bekannten eigenschaften aus einem File
sub get_properties {
    
    my $readfile;
    my $buffer=0;

    my $laenge_sender=0; #laenge des Sendernamens
    my $laenge_name=0;   #laenge des namens der Aufzeichnung bzw. des Ordners
    my $laenge_desc=0;   # laenge der Beschreibung
    my $laenge_trigger=0; #laenge der Ursprungsbezeichnung
    my $laenge_link=0; #filename der Aufzeichnung (mit Pfad)

    my $breakflag;

    # logger("get props for $_[0]->[0]");

    #datei zum lesen oeffnen

    $readfile = open(FILE, $_[0]->[0]);
    binmode(FILE);

    if(not defined($readfile)) {
        logger("Fehler beim ¨Offnen der Datei: $readfile!");
        return;
    }

    #filetyp
    seek(FILE, 14, 0);
    read(FILE, $buffer, 1); 
    $buffer = dat_2_char($buffer);
    $_[0]->[2] = $buffer;
    
    #dateigroesse-14
    seek(FILE, 12, 0);
    read(FILE, $buffer, 2); 
    $buffer=dat_2_unsignedint($buffer);
    $_[0]->[3] = $buffer;
    
    #dateiname als int
    seek(FILE, 16, 0);
    read(FILE, $buffer, 2); 
    $buffer=dat_2_unsignedint($buffer);
    $_[0]->[4] = $buffer;
    #printf(" FileName: %d", $buffer);
    if ($_[0]->[4] != $_[0]->[1]) {
        logger("Warnung: Dateiname und Name im File ungleich !");
    }
    
    #Sendername
    if (($_[0]->[2] == 0x23) || ($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c))  {
        seek(FILE, 0x1a, 0);
        read(FILE, $laenge_sender, 1);
        $laenge_sender = dat_2_char($laenge_sender);
        $_[0]->[10] =  $laenge_sender;
        seek(FILE, 0x1b, 0);
        read(FILE, $buffer, $laenge_sender-1);
        #printf(" Sender: %s", $buffer);
        $_[0]->[5]=dat_2_string($buffer);#$buffer;
    } else {
        $_[0]->[5] = "-";
        $_[0]->[10] =  0;
    }
    
    #Eintragsname (Ordnername oder Aufzeichnungsname) 
    $breakflag=1;
    if ($_[0]->[2] == 0x0d) { #systemordner
        seek(FILE, 0x15, 0);
        read(FILE, $laenge_name, 1);
        $laenge_name = dat_2_char($laenge_name);
        $_[0]->[11]=$laenge_name;

        seek(FILE, 0x16, 0);
        $breakflag=0;
    }
    if ($_[0]->[2] == 0x0b) { #eigener ordner
        seek(FILE, 0x15, 0);
        read(FILE, $laenge_name, 2);
        $laenge_name = dat_2_unsignedint($laenge_name);
        $_[0]->[11]=$laenge_name;

        seek(FILE, 0x17, 0);
        $breakflag=0;
    }
    if (($_[0]->[2] == 0x23) || ($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c)) { #Aufzeichnung
        seek(FILE, 0x2b+$laenge_sender, 0);
        read(FILE, $laenge_name, 2);
        $laenge_name = dat_2_unsignedint($laenge_name);
        $_[0]->[11]=$laenge_name;
 
        seek(FILE, 0x2d+$laenge_sender, 0);
        $breakflag=0;
    }
    
    if (!$breakflag) { #name eintragen
        read(FILE, $buffer, $laenge_name-1);
        #printf(" Name: %s", $buffer);
        $_[0]->[6]=dat_2_string($buffer);#$buffer; 

    } else { #unsupported
        $_[0]->[6]="unsupported!"; 
        $_[0]->[11]=0;
    }
    
    #zeitstempel
    if (($_[0]->[2] == 0x23) || ($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c)) {
        #logger ("File: $_[0]->[0]");
        #startzeit
        seek(FILE, 0x2e+$laenge_sender+$laenge_name, 0);
        read(FILE, $buffer, 4);
        $_[0]->[22] = dat_2_unsignedlong($buffer);
#        logger("Start: $_[0]->[22]");

        #endzeit
        seek(FILE, 0x33+$laenge_sender+$laenge_name, 0);
        read(FILE, $buffer, 4);
        $_[0]->[23] = dat_2_unsignedlong($buffer);
 #       logger("Ende: $_[0]->[23]");
    }

    #Beschreibung
    $breakflag=1;
    if (($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c)) { #Aufzeichnung
        seek(FILE, 0x38+$laenge_sender+$laenge_name, 0);
        read(FILE, $laenge_desc, 2);
        $laenge_desc = dat_2_unsignedint($laenge_desc);
        $_[0]->[12]=$laenge_desc;

        seek(FILE, 0x3a+$laenge_sender+$laenge_name, 0);
        $breakflag=0;
    }
    if ($_[0]->[2] == 0x23) { #Aufzeichnung
        seek(FILE, 0x3a+$laenge_sender+$laenge_name, 0);
        read(FILE, $laenge_desc, 2);
        $laenge_desc = dat_2_unsignedint($laenge_desc);
        $_[0]->[12]=$laenge_desc;

        seek(FILE, 0x3c+$laenge_sender+$laenge_name, 0);
        $breakflag=0;
    }

    if (!$breakflag) { #desc eintragen
        read(FILE, $buffer, $laenge_desc-1);
        
        $_[0]->[7]=dat_2_string($buffer); #$buffer; 
        #printf(" Desc: %s", $buffer);
        #dat_2_string($buffer);

    } else { #unsupported
        $_[0]->[7]=""; 
        $_[0]->[12]=0;
    }
    

    #trigger
    $breakflag=1;
    if ($_[0]->[2] == 0x1d) { #Aufzeichnung
        seek(FILE, 0x46+$laenge_sender+$laenge_name+$laenge_desc, 0);
        read(FILE, $laenge_trigger, 1);
        $laenge_trigger=dat_2_char($laenge_trigger);
        $_[0]->[13]=$laenge_trigger;

        $breakflag=0;
    }
    if ($_[0]->[2] == 0x1c) { #Aufzeichnung
        seek(FILE, 0x46+$laenge_sender+$laenge_name+$laenge_desc, 0);
        read(FILE, $laenge_trigger, 1);
        $laenge_trigger=dat_2_char($laenge_trigger);
        $_[0]->[13]=$laenge_trigger;

        $breakflag=0;
    }
    if ($_[0]->[2] == 0x23) { #Aufzeichnung
        seek(FILE, 0x51+$laenge_sender+$laenge_name+$laenge_desc, 0);
        read(FILE, $laenge_trigger, 1);
        $laenge_trigger=dat_2_char($laenge_trigger);
        $_[0]->[13]=$laenge_trigger;

        $breakflag=0;
    }

    if (!$breakflag) {
        read(FILE, $buffer, $laenge_trigger-1); 
        $buffer=dat_2_string($buffer);
        $_[0]->[18] = $buffer;
    } else {
        $_[0]->[18] = "-";#error
    }
    
    #Parent-Ordner
    $breakflag=1;
    if ($_[0]->[2] == 0x0b) { #eigener Ordner
        seek(FILE, 0x2b+$laenge_name, 0);
        $_[0]->[13]=0; #triggergroesse
        $breakflag=0;
    }
    if ($_[0]->[2] == 0x0d) { #System-Ordner
        seek(FILE, 0x39+$laenge_name, 0);
        $_[0]->[13]=0; #triggergroesse
        $breakflag=0;
    }

    if ($_[0]->[2] == 0x1d) { #Aufzeichnung
        seek(FILE, 0x5e+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        $breakflag=0;
    }
    if ($_[0]->[2] == 0x1c) { #Aufzeichnung
        seek(FILE, 0x5b+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        $breakflag=0;
    }
    if ($_[0]->[2] == 0x23) { #Aufzeichnung
        seek(FILE, 0x6c+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        $breakflag=0;
    }
    if (!$breakflag) {
        read(FILE, $buffer, 2); 
        $buffer=dat_2_unsignedint($buffer);
        $_[0]->[8] = $buffer;
        # printf("Parent %d\r\n", $_[0]->[8]);
    } else {
        $_[0]->[8] = 0;#error
        logger("konnte Parent-Ordner nicht identifizieren! Typ (noch) nicht supported?");
    }


    #behalten
    if ($_[0]->[2] == 0x23) { #Aufzeichnung
        seek(FILE, 0x4d+$laenge_sender+$laenge_name+$laenge_desc, 0);
    }
    elsif (($_[0]->[2] == 0x1c) || ($_[0]->[2] == 0x1d)) {
        seek(FILE, 0x42+$laenge_sender+$laenge_name+$laenge_desc, 0);
    }
    read(FILE, $buffer, 2);
    $buffer = dat_2_char($buffer);
    $_[0]->[17]=$buffer; #behalten

    if ($_[0]->[2] == 0x23) { #Aufzeichnung
        seek(FILE, 0x4f+$laenge_sender+$laenge_name+$laenge_desc, 0);
    }
    elsif (($_[0]->[2] == 0x1c) || ($_[0]->[2] == 0x1d)) {
        seek(FILE, 0x44+$laenge_sender+$laenge_name+$laenge_desc, 0);
    }
    read(FILE, $buffer, 2);
    $buffer = dat_2_char($buffer);
    $_[0]->[16]=$buffer; #gesehen


    #link
    $breakflag=1;
    if ($_[0]->[2] == 0x23) { #Aufzeichnung
        seek(FILE, 0x75+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        read(FILE, $laenge_link, 2);
        $laenge_link=dat_2_char($laenge_link);
        $_[0]->[14]=$laenge_link;

        seek(FILE, 0x77+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        $breakflag=0;
    }

    if ($_[0]->[2] == 0x1d) { #Aufzeichnung
        seek(FILE, 0x67+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        read(FILE, $laenge_link, 2);
        $laenge_link=dat_2_char($laenge_link);
        $_[0]->[14]=$laenge_link;

        seek(FILE, 0x69+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        $breakflag=0;
    }
    if ($_[0]->[2] == 0x1c) { #Aufzeichnung
        seek(FILE, 0x64+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        read(FILE, $laenge_link, 2);
        $laenge_link=dat_2_char($laenge_link);
        $_[0]->[14]=$laenge_link;

        seek(FILE, 0x66+$laenge_sender+$laenge_name+$laenge_desc+$laenge_trigger, 0);
        $breakflag=0;
    }

    if (!$breakflag) {
        read(FILE, $buffer, $laenge_link-1); 
        $buffer=dat_2_string($buffer);
        $_[0]->[15] = $buffer;
    } else {
        $_[0]->[15] = "-";
        # logger("kein link");
    }

    $_[0]->[20]=0; #geaendert
    $_[0]->[21]=0; #neu erzeugen


    $_[0]->[19]=0; # (obsolete) ausgeblendet


    close(FILE);
}

sub dat_2_unsignedlong {
    unpack('L', shift);
}
sub dat_2_unsignedint {
    unpack('S', shift);
}
sub dat_2_char {
    ord(shift);
}
sub dat_2_string { #umlaute behandeln
    $_[0] =~ s/\xc3\x84/Ä/;
    $_[0] =~ s/\xc3\x96/Ö/;
    $_[0] =~ s/\xc3\x9c/Ü/;

    $_[0] =~ s/\xc3\xa4/ä/;
    $_[0] =~ s/\xc3\xb6/ö/;
    $_[0] =~ s/\xc3\xbc/ü/;

    $_[0] =~ s/\xc3\x9f/ß/;
    
    chomp($_[0]);
    return($_[0]);
}


sub unsignedlong_2_dat {
    pack('L', shift);
}
sub unsignedint_2_dat {
    pack('S', shift);
}
sub char_2_dat {
    chr(shift);
}
sub string_2_dat { #umlaute behandeln
    $_[0] =~ s/Ä/\xc3\x84/;
    $_[0] =~ s/Ö/\xc3\x96/;
    $_[0] =~ s/Ü/\xc3\x9c/;

    $_[0] =~ s/ä/\xc3\xa4/;
    $_[0] =~ s/ö/\xc3\xb6/;
    $_[0] =~ s/ü/\xc3\xbc/;

    $_[0] =~ s/ß/\xc3\x9f/;
    

    $_[0] .= "\0";
    return($_[0]);
}



#uebernimmt eine arrayspalte ins formular
sub struct_to_form {

    logger("fill form with $_[0]->[6] ($_[0]->[0])");

    #widgets enablen
    if (($_[0]->[2] != 0x0d) && ($_[0]->[2] != 0x0b)) { # nicht Ordner
        $txt_desc -> configure(-state => 'normal');
        $lab_desc->configure(-state => 'normal');
        $chk_gesehen->configure(-state => 'normal');
        $chk_behalten->configure(-state => 'normal');
        $lab_trigger->configure(-state => 'normal');
        $labent_trigger->configure(-state => 'normal');
        $lab_link->configure(-state => 'normal');
        $labent_link->configure(-state => 'normal');
        $lab_record->configure(-state => 'normal');
        $labent_record->configure(-state => 'normal');
    }

    #typ
    if ($_[0]->[2] == 0x0d) {
        $labent_typ->configure(-text=>"Systemordner (0x0d)");        
    } 
    elsif ($_[0]->[2] == 0x0b) {
        $labent_typ->configure(-text=>"Ordner (0x0b)");        
    }

    elsif ($_[0]->[2] == 0x23) {
        $labent_typ->configure(-text=>"Aufzeichnung (0x23)");        
    }
    elsif ($_[0]->[2] == 0x1d) {
        $labent_typ->configure(-text=>"Aufzeichnung (0x1d)");        
    }
    elsif ($_[0]->[2] == 0x1c) {
        $labent_typ->configure(-text=>"Aufzeichnung (0x1c)");        
    }
    elsif ($_[0]->[2] == 0x1b) {
        $labent_typ->configure(-text=>"Assistent? (0x1b)");        
        logger("Assistent not implemented.");
        return;
    }
    elsif ($_[0]->[2] == 0x21) {
        $labent_typ->configure(-text=>"vorgemerkt? (0x21)");        
        logger("vorgemerkt not implemented.");

        return;
    }

    else {
        logger("filetyp not implemented");
        $labent_typ->configure(-text=>"Error."); 
        return;
    }

    #sender
    if (($_[0]->[2] == 0x23) || ($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c)) {
        $labent_sender->configure(-text=>$_[0]->[5]);
    } else {
        $labent_sender->configure(-text=>"-");
    }
    #name
    $ent_name->configure(-text=>$_[0]->[6]);

    #beschreibung
    $txt_desc->delete('0.0', 'end');
    if (($_[0]->[2] == 0x23) || ($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c)) {
        $txt_desc->insert('0.0', $_[0]->[7]);
    }
    
    #ursprung
    $labent_trigger->configure(-text=>$_[0]->[18]);
    
    #dateiname
    $labent_filename->configure(-text=>$_[0]->[0]);
    
    #pfad
    $labent_pfad->configure(-text=>$_[0]->[9]);

    #link
    $labent_link->configure(-text=>$_[0]->[15]);

    #dateigroesse
    $labent_filegr->configure(-text=>$_[0]->[3]);

    #sendergroesse
    $labent_sendergr->configure(-text=>$_[0]->[10]);

    #namegroesse
    $labent_namegr->configure(-text=>$_[0]->[11]);

    #beschreibunggroesse
    $labent_descgr->configure(-text=>$_[0]->[12]);

    #ursprunggroesse
    $labent_triggergr->configure(-text=>$_[0]->[13]);

    #linkgroesse
    $labent_linkgr->configure(-text=>$_[0]->[14]);

    #gesehen
    #logger("gesehen: $_[0]->[16]");
    if ($_[0]->[16] == 0x01) {
        $form_gesehen=1;
    } else {
        $form_gesehen=0;
    }

    #behalten
    #logger("behalten: $_[0]->[17]");

    if ($_[0]->[17] == 0x03) {
        $form_behalten=1;
    } else {
        $form_behalten=0;
    }

    #changed
    if ($_[0]->[20] == 1) {
        $form_changed=1;
    } else {
        $form_changed=0;
    }


#        my $teststring = `date "+%a,%d.%m.20%y %H:%M:%S" -d \@1315584000`;
 #   print($teststring);
    #print(`date +%a,\ %d.%m.20%y\ %H:%M:%S -d @1315584000`);

    #start- und endezeit
   # my @result="";

    if (($_[0]->[2] == 0x23) || ($_[0]->[2] == 0x1d) || ($_[0]->[2] == 0x1c)) {
        my $result = `date "+%a, %d.%m.20%y  %H:%M:%S" -d \@$_[0]->[22]`;
        chomp($result);
        $result .= " - ";
        $result .= `date "+%H:%M:%S" -d \@$_[0]->[23]`;
        chomp($result);
        $labent_record->configure(-text=>"$result");

    } else {
        $labent_record->configure(-text=>"-");
    }

    #parentordner    
    #print ("set to $_[0]->[8]");
    $form_parentordner = $_[0]->[8];

    foreach my $entry (@ordnerliste) {
        if (@$entry[1] == $form_parentordner) { #parentordner gefunden
            $form_parentordner_name = @$entry[0];
        }
    }


    #widgets deisablen
    if (($_[0]->[2] == 0x0d) || ($_[0]->[2] == 0x0b)) { # Ordner
        $txt_desc -> configure(-state => 'disabled');
        $lab_desc->configure(-state => 'disabled');
        $chk_gesehen->configure(-state => 'disabled');
        $chk_behalten->configure(-state => 'disabled');
        $lab_trigger->configure(-state => 'disabled');
        $labent_trigger->configure(-state => 'disabled');
        $lab_link->configure(-state => 'disabled');
        $labent_link->configure(-state => 'disabled');
        $lab_record->configure(-state => 'disabled');
        $labent_record->configure(-state => 'disabled');
    }
}



sub create_folder {
    logger("create folder");

    #freien dateinamen suchen
    chdir($workdir);

    if  (@ordnerliste == 0) {
        $main->messageBox(-message=>"Bitte zuerst Daten downloaden!",  -type=>'ok');
        return;
    }

    my $newfile=1000;

    until (not -e "$newfile.xbc") {
            $newfile++;
    }
    
    logger("Fileneme: $newfile");

    open(OUTFILE, ">$newfile.xbc");
    close(OUTFILE); #datei schonmal anlegen


    my @entry = [];
            
    $entry[0] = $newfile.".xbc"; #filename   (als string)
    $entry[1] = $newfile; #nummer 
    $entry[2] = 0x0b; #filetyp
    $entry[3] = 59; #groesse-14
    $entry[4] = $newfile; #nummer (nochmal) 
    $entry[5] = ""; #Sendername 
    $entry[6] = "neuer Ordner"; #NAme 
    $entry[7] = ""; #Description 
    $entry[8] = 0; #Parent-Ordner 
    $entry[9] = ""; #kompletter pfad 
    $entry[10] = 0; #Sendergroesse 
    $entry[11] = 13; #NAme groesse 
    $entry[12] = 0; #Desc groesse 
    $entry[13] = 0; #Trigger groesse 
    $entry[14] = 0; #link groesse 
    $entry[15] = ""; #Link 
    $entry[16] = 0; #gesehen 
    $entry[17] = 0; #behalten 
    $entry[18] = ""; #Trigger 
    $entry[19] = 0; #ausgeblended (obsolete) 
    $entry[20] = 0; #eintrag geaendert 
    $entry[21] = 1; #neu erzeugen
    
    
    #in die struktur einhaengen
    @dateien = (@dateien, \@entry);


    $recordtree->selectionClear();
    rebuild_tree();

    $storebutton->configure(-foreground=>"Red",-activeforeground=>"Red");


    $selected_entry=\@entry; #neuen ordner selektieren
    $recordtree->selectionSet("0.$newfile"); 
    $recordtree->see("0.$newfile"); #zum neuen ordner hinscrollen

    tree_command();
}


# temporaere dateien loeschen
# Eingabe 0: nur Inhalt loeschen
#         1: komplett loeschen (auch Directory)
sub cleanup {

    if (-e $workdir && -d $workdir) {
        chdir($workdir);
        opendir(DIR, $workdir);
        while(my $datei = readdir(DIR)) {
            logger("delete $datei");
            if ($datei ne "." && $datei ne "..") {
                unlink($datei);
            }
        }
        closedir(DIR);

        #verzeichnis auch loeschen
        if ($_[0] == 1) {
            #rmdir($workdir);
            logger("komplett loeschen deaktiviert!");
        }
    }
}

sub logger {
    print($_[0] . "\r\n");
}


sub ok_cancel_box {
    my $response = $main->messageBox(-message=>"$_[0]",-type=>'okcancel',-icon=>'question');

    if ($response eq "Ok") {
        return 1;
    } else {
        return 0;
    }
}

