Application.m


max21 Unternehmensgruppe
//	Aprica2
//	copyright Pirmin Braun 1997-2007 - pirmin@pirmin.de
//	all Rights reserved;
#define GPL_STRING @"\n\
 IntarS 5.1 - Unternehmenssoftware\n\
 Urheber (C) 1997-2007  Pirmin Braun\n\
 http://www.seat-1.com\n\
 Some rights reserved.\n\
 \n\
Redistribution and use in source and binary forms, with or without\n\
modification, are permitted provided that the following conditions\n\
are met:\n\
1. Redistributions of source code must retain the above copyright\n\
   notice, this list of conditions and the following disclaimer.\n\
2. Redistributions in binary form must reproduce the above copyright\n\
   notice, this list of conditions and the following disclaimer in the\n\
   documentation and/or other materials provided with the distribution.\n\
3. Neither the name of IntarS, Aprica nor the names of its contributors\n\
   may be used to endorse or promote products derived from this software\n\
   without specific prior written permission.\n\
 This program is free software; you can redistribute it and/or modify\n\
 it under the terms of the GNU General Public License as published by\n\
 the Free Software Foundation; either version 2 of the License, or\n\
 (at your option) any later version.\n\
 \n\
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n\
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n\
ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n\
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n\
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n\
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n\
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n\
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n\
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n\
SUCH DAMAGE.\n\
 This program is distributed in the hope that it will be useful,\n\
 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
 GNU General Public License for more details.\n\
 \n\
 You should have received a copy of the GNU General Public License\n\
 along with this program; if not, write to the Free Software\n\
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n\
 \n\
 info@seat-1.com\n\
 pb@seat-1.com\n\
 http://www.seat-1.com\n\
 pirmin@pirmin.de"
#define APPLICATION
#import "Aprica.h"
#import "konto_check.h"
#ifdef GNU_RUNTIME
#import <objc/objc-api.h>
#else
#import <objc/objc-class.h>
#endif
#import <math.h>
#ifdef GNUSTEP
static BOOL debugAllocation = NO;
#endif
/* Dummy protocol to let the compiler know how to do the right thing.  */
@protocol WOAP
-(NSNumber*)port;
@end
#define WOAppPort ([(id<WOAP>)[WOApp class]port])
@implementation Application
ACCESSClassm(configDict, setConfigDict, NSDictionary)
ACCESSm(currentTempName,setCurrentTempName)
ACCESSm(batchScriptName,setBatchScriptName)
ACCESSm(urlToOpenInNewBrowser,setUrlToOpenInNewBrowser)
ACCESSm(externalUrlToOpenInNewBrowser,setExternalUrlToOpenInNewBrowser)
ACCESSm(restString,setRestString)
ACCESSm(currentPDFName,setCurrentPDFName)
ACCESSm(lastSQLError,setLastSQLError)
ACCESSm(targetPath,setTargetPath)
ACCESSm(basePath,setBasePath)
ACCESSClassm(lastReload,setLastReload,NSDate)
ACCESSm(htdocs,setHtdocs)
- (NSMutableArray *)gma;{ return gma;}
- (NSMutableArray *)logs;{ return logs;}
- (Application *)application;
{
    return self; // f. Scripting
}
- (NSString *)browserTitle;
{
    return [NSSWF @"Aprica2 M=%@ DB=%@ U=%@",mandant,db_mandant,CURRENTUSER];
}
- (NSArray *)fontList;
{
    return fontList;
}
- (NSArray *)fontEncodings;
{
    return fontEncodings;
}
- (NSArray *)colorSpaces;
{
    return colorSpaces;
}
- (NSString *)mandant;
{
    return mandant;
}
- (NSString *)db_mandant;
{
    return db_mandant;
}
- (Session *)currentSession;
{
    return currentSession;
}
- (void)setCurrentSession:(Session *)se;
{
//nicht retainen! Unter Kontrolle von WO;
    currentSession = se;
}
- (PBWOEditor *)currentComponent;
{
    return currentComponent;
}
- (void)setCurrentComponent:(PBWOEditor *)e;
{
//nicht retainen! Unter Kontrolle der Session;
    currentComponent = e;
}
- (NSTimeInterval)timeStamp;
{
    return [[NSDate date]timeIntervalSince1970];
}
- (BOOL)logActions;
{
    return logActions;
}
- (BOOL)isSecure;
{
    return isSecure;
}
- (void)logActiveSessions;
{
//wie BOV4 machen;
}
- (NSString *)today;
{
//heute-datum im dbformat; einfacher als jedesmal ueber PBDate zu gehen
//koennte man aber auch als klassenmethode an PBDate machen
    return [[NSCalendarDate date]descriptionWithCalendarFormat:@"%Y%m%d000000"];
}
- (NSString *)now;
{
//heute-datum im dbformat; einfacher als jedesmal ueber PBDate zu gehen
//koennte man aber auch als klassenmethode an PBDate machen
    return [[NSCalendarDate date]descriptionWithCalendarFormat:ND_FORMAT];
}
- (NSArray *)systemtab;
{
// wird bei reloadScripts auch neu geladen
    return systemtab;
}
- (NSMutableDictionary *)transDict;
{
    return transDict;
}
- (int)fetchLimit;
{
    return fetchLimit;
}
- (BOOL)verifyDelete;
{
    return verifyDelete;
}
- (BOOL)orbDebug;
{
    return orbDebug;
}
- (BOOL)orbDebugStack;
{
    return orbDebugStack;
}
- (NSArray *)availableBundles;
{
    return [bundlesByName allValues];
}
- (PBDD *)myDD;
{
    return myDD;
}
- (BOOL)utf8;
{
    return utf8;
}
- (BOOL)utf8db;
{
    return utf8db;
}
- (NSMutableDictionary *)infiniteDetection;
{
    return infiniteDetection;
}
- (BOOL)isBatch;
{
    return isBatch;
}
- (BOOL)log_changes;
{
    return log_changes;
}
- (BOOL)fast_start;
{
    return fast_start;
}
- (BOOL)noModelToDB;
{
    return noModelToDB;
}
- (NSMutableDictionary *)staticDict;
{
    return staticDict;
}
- (void)sessionEnded:(NSString *)si;
{
// irgendwie festhalten, um uebersicht ueber laufende sessions zu haben
}
- (NSString *)number;
{
    return number;
}
- (NSString *)isGNUStep;
{
#ifdef GNUSTEP
    return @"J";
#else
    return @"N";
#endif
}
- (int)dbNr;
{
    return dbNr;
}
- (void)setDbNr:(int)i;
{
    dbNr = i;
}
- (void)setDbNrS:(NSString *)s;
{
    dbNr = [s intValue];
}
- (int)raster;
{
    return raster;
}
- (int)bezWidth;
{
    return bezWidth;
}
- (int)editWidth;
{
    return editWidth;
}
- (int)descrWidth;
{
    return descrWidth;
}
- (NSString *)companyImage;
{
    return [NSSWF @"/Aprica2_%@/Images/%@.jpg",mandant,_K];
}
- (NSFileHandle *)logfh;
{
    return logfh;
}
- (NSMutableDictionary *)scriptStatistic;
{
    return scriptStatistic;
}
- (void)openLogfh;
{
#ifdef WIN32
    {
        NSString *logpath = [NSSWF @"%@/Resources/Logs/log_%@.txt",MANDANTPATH,[self number]];
        if([myFM fileExistsAtPath:logpath]){
// den letzen umbenennen
            NSString *logpath_prev = [NSSWF @"%@/Resources/Logs/log_%@_bis_%@.txt",MANDANTPATH,[self number],[self now]];
            [myFM movePath:logpath toPath:logpath_prev handler:nil];
        }
        [[NSSWF @"%@ --- Start ---\n",[[NSCalendarDate date]descriptionWithCalendarFormat:ND_GUIDT_FORMAT]] WTF:logpath];
        logfh = [[NSFileHandle fileHandleForUpdatingAtPath:logpath]retain];
        [logfh seekToEndOfFile];
    }
#endif
}
- (void)getMandantAndPort;
{
// mandant von commandline holen, wenn nicht teil des programmnamens
// port berechnen; kann von commandline uebersteuert werden
    NSArray *commandLineArguments = [[NSProcessInfo processInfo] arguments];
    int i,myPort=0;
    NSString *an = [[NSProcessInfo processInfo] processName];
    i = [commandLineArguments indexOfObject:@"-secure"];
    if(NSNotFound != i){
        isSecure = YES;
	NSLog(@"secure mode; no tempscript;");
    }
// um startup zeit zu verkuerzen, modell nicht in DB schreiben; darf dann auch nicht dort editiert werden
    noModelToDB = NO;
    i = [commandLineArguments indexOfObject:@"-noModelToDB"];
    if(NSNotFound != i){
        noModelToDB = YES;
        NSLog(@"noModelToDB; editing prohibited;");
    }
//commandLineArguments interpretieren: batch
    isBatch = NO;
    i = [commandLineArguments indexOfObject:@"-batch"];
    if(NSNotFound != i){
        isBatch = YES;
        if (([commandLineArguments count] > i + 1)) {
            [self setBatchScriptName:[commandLineArguments objectAtIndex:i+1]];
        }else{
            NSLog(@"batch Script Name missing");
            exit(0);
        }
    }
    
    i = [commandLineArguments indexOfObject:@"-n"];
//optionale nummer der Instanz, Default 1
    if(NSNotFound == i){
        number = [@"1" retain];
    }else{
        if (([commandLineArguments count] > i + 1)) {
            number = [[commandLineArguments objectAtIndex:i+1] retain];
        }else{
            number = [@"1" retain];
        }
    }
    
// mandant von commandline hat vorrang
    i = [commandLineArguments indexOfObject:@"-mandant"];
    if(NSNotFound == i){
        mandant = [[an secureSubstringFromIndex:[an length]-6]retain];
        if(![mandant intValue]){
            NSLog(@"Paramenter -mandant nicht angegeben; Terminiere;");
            exit(0);
        }
    }else{
        if (([commandLineArguments count] > i + 1)) {
            mandant = [[commandLineArguments objectAtIndex:i+1] retain];
        }else{
            NSLog(@"Paramenter -mandant nicht angegeben; Terminiere;");
            exit(0);
        }
    }
    
// db_mandant
    i = [commandLineArguments indexOfObject:@"-db_mandant"];
    if(NSNotFound == i){
        db_mandant = mandant;
    }else{
        if (([commandLineArguments count] > i + 1)) {
            db_mandant = [[commandLineArguments objectAtIndex:i+1] retain];
        }else{
            db_mandant = mandant;
        }
    }
// nicht bei Batch Instanz
    if(!isBatch){
        i = [commandLineArguments indexOfObject:@"-port"];
        if ((NSNotFound != i) && ([commandLineArguments count] > i + 1)) {
            myPort = [[commandLineArguments objectAtIndex:i+1] intValue];
        }
        if(!myPort){
            i = [mandant intValue];
            myPort = 10000;
            myPort += ((i * 10) + [number intValue]);
        }
        [WOApplication setPort:[NSNumber numberWithInt:myPort]];
    }
}
- (WOAdaptor *)adaptorWithName:(NSString *)aName arguments:(NSDictionary *)someArguments;
{
// von WO aufgerufen beim Start der Application
#ifndef GNUSTEP
    NSString *an = [[NSProcessInfo processInfo] processName];
    NSString *woConfEntry;
    LMA;
#endif
    LMD;
    WOAdaptor *woa;
    [lmd addEntriesFromDictionary:someArguments];
    [self getMandantAndPort];
    [self configureAprica];
    
    [lmd setObject:NSS([WOAppPort intValue]) forKey:@"WOPort"];
    [lmd setObject:@"()" forKey:@"NSProjectSearchPath"];
    [lmd setObject:@"0" forKey:@"WOWorkerThreadCount"];
   
#ifndef GNUSTEP
// WebObjects.conf schreiben
// muss vor init passieren
// Aprica000001:1@localhost 3001
   if(!isBatch){
        NSString *woConfFile = [NSSWF @"%@/Library/WebObjects/Configuration/WebObjects.conf",[self nextRoot]];
        woConfEntry = [NSSWF @"%@:%i@localhost %i",an,[number intValue],[WOAppPort intValue]];
        [lma addObjectsFromArray:[[NSSWCOF woConfFile]componentsSeparatedByString:@"\n"]];
        if([lma indexOfObject:woConfEntry] == NSNotFound){
            [lma addObject:woConfEntry];
            [[lma componentsJoinedByString:@"\n"] WTF:woConfFile];
        }
    }
#endif
    woa = [super adaptorWithName:aName arguments:lmd]; // der Adaptor liest jetzt das woConfFile, um Bescheid zu wissen ueber die Applications
    return woa;
}
- (NSString *)frameSourceLink
{
#ifdef GNUSTEP
    return [NSSWF @"/GSWeb/Aprica2%@", mandant];
#else
    return [NSSWF @"/cgi-bin/WebObjects/Aprica2%@", mandant];
#endif
}
- (NSString *)frameSourceRedirect
{
  return [NSSWF @"<META HTTP-EQUIV=REFRESH CONTENT=\"1; URL=%@\">",[self frameSourceLink]];
}
- (void)configureDebian31;
{
    BOOL needToRestartApache = NO;
    NSString *sys;
    NSString *an = [[NSProcessInfo processInfo] processName];
    NSString *httpdConfPath = @"/etc/apache2/httpd.conf";
    NSString *path,*file,*fileNew,*line;
    NSString *serverSignature = @"ServerSignature Off";
    NSString *resources = [NSSWF @"Alias /Aprica2_%@/ \"%@/Resources/\"",mandant,MANDANTPATH];
    LMA;
    NSDictionary *confPlist = nil;
    LMD;
    LMDN(applications);
    LMDN(application);
    LMDN(instances);
    LMDN(instance);
    
// httpd.conf lesen und testen, ob aprica.conf drin ist; ggf. schreiben
    path = httpdConfPath;
    file = [NSSWCOF path];
    line = @"Include /etc/apache2/aprica2.conf";
    if(!file)file=@"";  //muss nicht da sein
    if(![file rangeOfString:line].length){
        file = [file stringByAppendingFormat:@"\n%@",line];
        [file WTF:path];
        needToRestartApache = YES;
    }
    [self setHtdocs:@"/var/www/apache2-default"];
// aprica.conf ggf. erstellen; mandantenunabh.
    path = @"/etc/apache2/aprica2.conf";
    file = [NSSWCOF path];
    if(!file)file=@"# aliases for Aprica2";
    [lma addObjectsFromArray:[file componentsSeparatedByString:@"\n"]];
    if(![file rangeOfString:serverSignature].length)[lma addObject:serverSignature];
    if(![file rangeOfString:resources].length)[lma addObject:resources];
    if(![file rangeOfString:RESOURCEPATH].length){
        [lma addObject:[NSSWF @"<Directory \"%@\">",RESOURCEPATH]];
        [lma addObject:@"        Order allow,deny"];
        [lma addObject:@"        Allow from all"];
        [lma addObject:@"</Directory>"];
    }
    fileNew = [lma componentsJoinedByString:@"\n"];
    if(![file iE:fileNew]){
        LOGS(([NSSWF @"writing %@",path]));
        [fileNew WTF:path];
        needToRestartApache = YES;
    }
    if(![self isBatch]){
// gsweb.conf; Plist, welche Applications enthaelt; liegt in /etc/apache2
        path = @"/etc/apache2/gsweb.conf";
	file = [NSSWCOF path];
	if(FILLED(file)){
	    NS_DURING;
	    confPlist = [file propertyList];
	    NS_HANDLER;
	    NS_ENDHANDLER;
	    [lmd addEntriesFromDictionary:confPlist];
	}
	if(![lmd count]){
	    [lmd setObject: @"Maintained by Aprica2; add entry manualConfiguration = YES for manual maintanance" forKey: @"Comment"];
	    [lmd setObject: @"YES" forKey: @"canDumpStatus"];
	    [lmd setObject: @"YES" forKey: @"manualConfiguration_off"];
	    [lmd setObject: @"/etc/apache2/htdocs" forKey: @"DocumentRoot"];
	    [lmd setObject: @"/GSW/GSWExtensions/WebServer/Resources" forKey: @"GSExtensionsFrameworkWebServerResources"];
	}
	if(![lmd ofk:@"manualConfiguration"]){ // Kennung, dass File manuell verwaltet wird;
	    [applications addEntriesFromDictionary:[lmd ofk:@"applications"]];
	    [lmd setObject:applications forKey:@"applications"];
	    [application addEntriesFromDictionary:[applications ofk:an]];
	    [application setObject: @"YES" forKey: @"canDump"];
	    [applications setObject:application forKey:an];
	    [instances addEntriesFromDictionary:[application ofk:@"instances"]];
	    [instance addEntriesFromDictionary:[instances ofk:NSS([number intValue])]];
	    [instance setObject:@"localhost" forKey:@"host"]; // muss bei Trennung von Web und App-Server angepasst werden
	    [instance setObject:[@"{transport = socket}" propertyList] forKey:@"parameters"];
	    [instance setObject:NSS([WOAppPort intValue]) forKey:@"port"];
	    [instances setObject:instance forKey:NSS([number intValue])];
	    [application setObject: instances forKey: @"instances"];
	    fileNew = [lmd description];
	    if(![fileNew iE:file]){
	      LOGS(([NSSWF @"writing %@",path]));
	      [fileNew WTF:path];
	      needToRestartApache = YES;
	    }
	}
    }
// mods-available: 2 Files; mod_gsweb.conf und gsweb.load
// mod_gsweb.conf:
    path = @"/etc/apache2/mods-available/mod_gsweb.conf";
    file = [NSSWCOF path];
    fileNew = @"GSWeb_ConfigFilePath /etc/apache2/gsweb.conf\n\
GSWeb_Alias /GSWeb\n\
<Location /GSWeb*>\n\
SetHandler GSWeb\n\
</Location>\n";
    if(![file iE:fileNew]){
        LOGS(([NSSWF @"writing %@",path]));
        [fileNew WTF:path];
        needToRestartApache = YES;
    }
// gsweb.load:
    path = @"/etc/apache2/mods-available/gsweb.load";
    file = [NSSWCOF path];
    fileNew = @"LoadModule gsweb_module /usr/lib/apache2/modules/mod_gsweb.so";
    if(![file iE:fileNew]){
        LOGS(([NSSWF @"writing %@",path]));
        [fileNew WTF:path];
        needToRestartApache = YES;
    }
// Verlinkungen: mods-available nach mods-enabled
    path = @"/etc/apache2/mods-enabled/mod_gsweb.conf";
    if(![myFM fileExistsAtPath:path]){
        sys = [NSSWF @"ln -s /etc/apache2/mods-available/mod_gsweb.conf %@",path];
        SYSTEM(sys);
        needToRestartApache = YES;
    }
    path = @"/etc/apache2/mods-enabled/gsweb.load";
    if(![myFM fileExistsAtPath:path]){
        sys = [NSSWF @"ln -s /etc/apache2/mods-available/gsweb.load %@",path];
        SYSTEM(sys);
        needToRestartApache = YES;
    }
    if(needToRestartApache){
        SYSTEM(@"/etc/init.d/apache2 restart");
    }
}
- (void)configureWO;
{
    LMA;
    NSString *httpdConf;
    NSString *serverSignature = @"ServerSignature Off";
    NSString *resources = [NSSWF @"Alias /Aprica2_%@/ \"%@/Resources/\"",mandant,MANDANTPATH];
    NSString *httpdConfPath;
    NSString *webServerConfigPath = [NSSWF @"%@/Library/WebObjects/Configuration/WebServerConfig.plist",[self nextRoot]];
    NSString *s,*s1 = [NSSWCOF webServerConfigPath];
    NSDictionary *d;
    if(!s1){
        LOGS(([NSSWF @"%@ nicht gefunden. Terminating.",webServerConfigPath]));
        exit(0);
    }
    d = [s1 propertyList];
    s = [d ofk:@"DocumentRoot"];
    if(!s){
        LOGS(@"DocumentRoot nicht gesetzt in WebServerConfig. Terminating.");
        exit(0);
    }
    if([s hasSecureSuffix:@"/"])s = [s substringToIndex:[s length]-1];
    [self setHtdocs:s];
    httpdConfPath = [NSSWF @"%@/conf/httpd.conf",[[s stringByDeletingLastPathComponent]stringWithForwardSlashes]];
    httpdConf = [NSSWCOF httpdConfPath];
    [lma addObjectsFromArray:[httpdConf componentsSeparatedByString:@"\n"]];
    if(![httpdConf rangeOfString:serverSignature].length)[lma addObject:serverSignature];
    if(![httpdConf rangeOfString:resources].length)[lma addObject:resources];
    if(![httpdConf rangeOfString:RESOURCEPATH].length){
        [lma addObject:[NSSWF @"<Directory \"%@\">",RESOURCEPATH]];
        [lma addObject:@"        Order allow,deny"];
        [lma addObject:@"        Allow from all"];
        [lma addObject:@"</Directory>"];
    }
    [[lma componentsJoinedByString:@"\n"]WTF:httpdConfPath];
}
- (void)configureAprica
{
    NSString *path = [NSSWF @"%@/Resources/Start.html",MANDANTPATH];
// dies dient dazu, eine konstante URL zu haben
    LOGS(([NSSWF @"writing %@",path]));
    [[NSSWF @"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\">\n"
        @"<html> <head> <title>Aprica2</title> </head>\n"
        @"<frameset id=\"fra0\" framespacing=0>\n"
        @"<frame frameborder=0 scrolling=auto noresize\n"
        @" src=\"%@\" name=\"Aprica2\">\n"
        @"<noframes><p>Your browser does not support frames.</p></noframes>\n"
        @"</frameset>\n"
        @"</html>\n", [self frameSourceLink]] WTF:path];
#ifdef GNUSTEP
// vereinfachte Konfiguration
// Debian
// evt. mal ueber cmdline parameter die Distri angeben oder selber ermitteln
    [self configureDebian31];
#else
    [self configureWO];
#endif
}
- (NSDictionary *)confDictFromString: (NSString *)s;
{
    NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity: 128];
    NSArray *ws, *ls = [s componentsSeparatedByString: @"\n"];
    NSString *l,*k,*v;
    unsigned i,n = [ls count];
    for (i=0;i<n;i++) {
        l = [[[ls oai: i]stringWithoutWindowsShit] replace:@"\\n" with:@"\n"];;
	ws = [l componentsSeparatedByString: @"\t"];
	if ([ws count]!=2) {
	    if ([l length]) LOGS(([NSSWF @"Fehler in der config Zeile %i:'%@'",i,l]));
	    continue;
	}
	k = [ws oai:0];
        v = [ws oai:1];
	[d setObject:v forKey:[k lowercaseString]];
    }
    if (![d count]) d=nil;
    return d;
}
- (NSString *)confStringFromDict: (NSDictionary *)d;
{
// von bu_aktiviere verwendet;
    NSMutableString *s=[NSMutableString stringWithCapacity: 4096];
    NSString *k,*v;
    NSArray *a = [[d allKeys]sortedArray];
    unsigned i,n = [a count];
    for (i=0;i<n;i++) {
        k = [a oai:i];
	v = [[[[d ofk:k] description]stringWithoutWindowsShit] replace:@"\n" with:@"\\n"];
	[s appendString: k];
	[s appendString: @"\t"];
	[s appendString: v];
	[s appendString: @"\n"];
    }
    return s;
}
- (id)init;
{
    utf8 = NO;
    dbNr = 0; //die Standard-DB mit Standard user/pwd
    if(!(self=[super init])){return nil;}
 // geht auch ohne   [OEObject setup];
    systemtab = nil;
    didDbToIDM = NO;
    isReload = NO;
    logfh = nil;
    [self setExternalUrlToOpenInNewBrowser:nil];
    
    MD(staticDict); // statisch, wird nie geleert;session-uebergreifend;
    MD(feiertagDict); // wird gefuellt von Script didStartup
    MD(seqAccesses);
    MA(channelPool);
    MA(gma);
    MA(logs);
    MA(h3eos);
    MD(matchingEndif);
    MD(matchingEndwhile);
    MD(matchingEndsub);
    MD(matchingWhile);
    MD(matchingEndfor);
    MD(matchingForeach);
    MD(subNamed);
    MD(bundlesByName);
    MD(scriptDict);
    MD(scriptDictAnalyzed);
    MD(infiniteDetection);
    MA(blz4Array);
    MD(blzDict);
    MD(transDict);
    MD(parmDict); // wird bei jedem request geleert
    MS(allLATeX);
    MA(scriptNames);
    MD(scriptStatistic);
    MA(scriptFileNames);
    MA(scriptFiles);
    MA(scriptErrors);
    MA(templateFileNames);
    MA(templateFiles);
    MD(templatesByName1);
    MD(templatesByName0);
    MD(lookup);
    [self createCodePage858Map];
    [self createAuxDirs];
    [self openLogfh];
    //div. Einstellungen fuer WO:
    //so gehts: defaults write $appname WOWorkerThreadCount '0'
    //in http.conf des apache ServerSignature auf "off";
    // die .jpg ins /Images verzeichnis; .jpg nicht von WO serven lassen, sondern absolute URL verwenden, so dass sie vom Apache direkt bereitgestellt werden;
    [WOApplication setDirectConnectEnabled:NO];
    [WOApplication setAutoOpenInBrowser:NO];
    // [WOApplication setMonitorEnabled:NO];
    [WOApplication setIncludeCommentsInResponses:NO];
/* When flag is YES, disables caching of pages by the client by setting the page's expiration-time header to the current date and time. (By default, this attribute is set to NO.) Disabling of client caching affects what happens during backtracking. With client caching turned off, the browser resends the URL to the server for the page requested by backtracking. The application must return a new page to the browser (corresponding to a new WOComponent instance). This behavior is desirable when you do not want the user to backtrack to a page that might be obsolete because of changes that have occurred in the session.
When this flag is turned on and a request corresponding to a client backtrack occurs, the retrieved page will only be asked to regenerate its response. The first two phases of a normal request-response loop (value extraction from the request and action invocation) do not occur.
*/
    [self setPageRefreshOnBacktrackEnabled:YES]; //scheint keinen unterschied zu machen; der browser  holt die seiten aus seinem Cache wie er will
// pages muessen manuell da rein gemacht werden [self setPermanentPageCacheSize:2];
    [self setPageCacheSize:20]; // pro Session; jedes Modul ist eine Page; werden aber eigentlich vom instanceDict in Session gehalten; dennoch muss hier mindestens 1 angegeben werden, sonst Absturz;
// wg. GNUstep mind. 2
    
//    LOGS([[[NSProcessInfo processInfo]environment]description]);
//    s = [[[NSProcessInfo processInfo]environment]ofk:@"TEMP"];
//    if(!FILLED(s))s = [[[NSProcessInfo processInfo]environment]ofk:@"TMP"];
// passt alles nicht;
// NSTemporaryDirectory();
    [self clearTempdir];
    [self createApricaCss];
    [self reloadEverything];
    firstAwake = YES;
    colorSpaces = [[NSArray arrayWithObjects:@"DeviceGray", @"DeviceGray", @"DeviceGray", @"DeviceRGB", @"DeviceCMYK",nil]retain];
    fontList = [[NSArray arrayWithObjects:
        @"Helvetica",
        @"Helvetica-Bold",
        @"Helvetica-Oblique",
        @"Helvetica-BoldOblique",
        @"Times-Roman",
        @"Times-Bold",
        @"Times-Italic",
        @"Times-BoldItalic",
        @"Courier",
        @"Courier-Bold",
        @"Courier-Oblique",
        @"Courier-BoldOblique",
        @"Symbol",
        @"ZapfDingbats",
        @"FrutigerCE-Roman",
        nil]retain];
    fontEncodings = [[NSArray arrayWithObjects:
        /* Roman chars */
        @"WinAnsiEncoding",
        @"MacRomanEncoding",
        @"MacExpertEncoding",
        @"StandardEncoding",
        nil]retain];
    mimeTypes = [[NSDictionary dictionaryWithObjectsAndKeys:
        @"application/msword",@"doc",
        @"application/pdf",@"pdf",
        @"application/postscript",@"ai",
        @"application/postscript",@"eps",
        @"application/postscript",@"ps",
        @"application/zip",@"zip",
        @"image/gif",@"gif",
        @"image/bmp",@"bmp",
        @"audio/x-wav",@"wav",
        @"image/jpeg",@"jpeg",
        @"image/jpeg",@"jpg",
        @"image/png",@"png",
        @"image/tiff",@"tif",
        @"image/tiff",@"tiff",
        @"text/html",@"html",
        @"text/html",@"htm",
        @"text/plain",@"txt",
        @"text/plain",@"asc",
        @"video/mpeg",@"mpeg",
        @"video/mpeg",@"mpg",
        @"video/mpeg",@"mpe",
        @"video/x-msvideo",@"avi",
        @"text/rtf",@"rtf",
        nil,nil]retain];
    weekdayNames = [[NSArray arrayWithObjects:@"So",@"Mo",@"Di",@"Mi",@"Do",@"Fr",@"Sa",nil]retain];
    weekdayFullNames = [[NSArray arrayWithObjects:@"Sonntag",@"Montag",@"Dienstag",@"Mittwoch",@"Donnerstag",@"Freitag",@"Samstag",nil]retain];
#ifdef GNUSTEP
    debugAllocation = [[NSUserDefaults standardUserDefaults] boolForKey: @"DebugAllocation"];
    if (debugAllocation) GSDebugAllocationActive(YES);
#endif
    return self;
}
- (NSArray *)weekdayNames;
{
    return weekdayNames;
}
- (NSArray *)weekdayFullNames;
{
    return weekdayFullNames;
}
- (void)adjustDB;
{
    NSArray *a;
    NSMutableString *sqlS;
    NSAutoreleasePool *p;
    PBDD *dbdd = [[PBDD alloc]init];
    LOG(@"adjustDB ...");
    SQL(@"drop table if exists xxx"); // temp table von Workbench weg;
    p = [NSAutoreleasePool new];
    [dbdd addTables:[[self freshChannel]describeDatabase]];
    a = [[self myDD] dbDifferencesToDDNew: dbdd];
    sqlS = [myDD sqlStatmentsForChanges: a];
    if(FILLED(sqlS)){
        NSString *fn = [NSSWF @"%@/autoadjustDB.sql",TEMPDIR];
        NSString *hostnameName = @"hostname";
        NSString *database = [NSSWF @"%@_%@",[NSAPPNAME lowercaseString],[_APP db_mandant]];
        NSString *userName = @"dbuser";
        NSString *passwordName = @"dbpw";
        NSString *hostname = [[_APP configDict]ofk:hostnameName];
        NSString *user = [[_APP configDict]ofk:userName];
        NSString *password = [[_APP configDict]ofk:passwordName];
        NSString *script, *sn = [NSSWF @"%@/autoadjustDB.bat",TEMPDIR],*dumpScript;
        NSString *dsn = [NSSWF @"%@/dumpDB.bat",TEMPDIR];
        NSString *dp = [NSSWF @"%@/DataArchiv/dumps",MANDANTPATH];
        NSString *date=[[NSCalendarDate calendarDate] descriptionWithCalendarFormat: @"%Y%m%d%H%M"];
        NSDictionary *att = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedInt: 0777] forKey: NSFilePosixPermissions];
        if (utf8db) sqlS = [NSSWF @"set names utf8;\n%@", sqlS];
        if(!FILLED(hostname))hostname = @"localhost";
        if(!FILLED(user))user = @"root";
        if(!FILLED(password))password = @"root";
        if([[self number]iE:@"1"]){
            // nur Instanz 1 darf SQL generieren;
            LOGS(([NSSWF @"Datenbank ist nicht auf aktuellem Stand. SQL generiert, um Anpassung durchzufuehren in %@",fn]));
            [sqlS WTF:fn];
            if (![myFM fileExistsAtPath: dp]) [myFM createDirectoryAtPath: dp attributes: att];
#ifdef GNUSTEP
            script = [NSSWF @"#!/bin/sh\nmysql -u%@ -p%@ -h%@ -D %@ < %@\n",user,password,hostname,database,fn];
            dumpScript = [NSSWF @"#!/bin/sh\nmysqldump -u%@ -p%@ -h%@ --opt %@ > %@/%@.%@.sql",user,password,hostname,database,dp,database,date];
#else
            script = [NSSWF @"mysql -u%@ -p%@ -h %@ -D %@ < %@\n",user,password,hostname,database,fn];
            dumpScript = [NSSWF @"mysqldump -u%@ -p%@ -h%@ --opt %@ > %@/%@.%@.sql\n",user,password,hostname,database,dp,database,date];
#endif
            [script WTF:sn];
            [dumpScript WTF:dsn];
            [myFM changeFileAttributes:att atPath: fn];
            [myFM changeFileAttributes:att atPath: sn];
            [myFM changeFileAttributes:att atPath: dsn];
            if(!isReload){
                LOG(@"Terminating.");
                exit(0);
            }else{
                LOGI(([NSSWF TRANSLATION(@"isReload: DB-Differenzen festgestellt und in Anpassungsscript in %@ gestellt"),fn]));
            }
        }else{
            LOGS(([NSSWF @"Datenbank ist nicht auf aktuellem Stand. Terminating."]));
            exit(0);
        }
    }else{
        LOG(@"no Differences;");
    }
    [p release];
    [dbdd release];
}
- (void)copyStdScript;
{
// wird per dateiverweis reingenommen; aus GLOBAL ins RESOURCEPATH kpieren, wenn noch nitch dort
    NSString *pathf =  @"%@/stdScript%i.js";
    NSString *tpath,*spath;
    tpath = [NSSWF pathf,RESOURCEPATH,0];
    if(![myFM fileExistsAtPath:tpath]){
        spath = [NSSWF pathf,GLOBALCONFIGPATH,0];
        [myFM copyPath:spath toPath:tpath handler:nil];
    }
    tpath = [NSSWF pathf,RESOURCEPATH,1];
    if(![myFM fileExistsAtPath:tpath]){
        spath = [NSSWF pathf,GLOBALCONFIGPATH,1];
        [myFM copyPath:spath toPath:tpath handler:nil];
    }
// layout des System-Reiters laden
    {
        NSString *s;
        if(systemtab)[systemtab release];
        s = [NSSWCOF [NSSWF @"%@/systemtab.txt",MANDANTPATH]];
        if(!FILLED(s))s = [NSSWCOF [NSSWF @"%@/systemtab.txt",GLOBALCONFIGPATH]];
        systemtab = [s componentsSeparatedByString:@","];
        [systemtab retain];
    }
}
- (void)loadLinkStylesheet;
{
//mandantenspez. Stylesheet
    linkStylesheet = [NSSWF @"<LINK rel=\"STYLESHEET\" type=\"text/css\" href=\"/Aprica2_%@/Aprica.css\">",mandant];
    [linkStylesheet retain];
}
- (NSString *)linkStylesheet; {return linkStylesheet;}
- (void)reloadEverything;
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    
// config.dict laden
    slowDBCount = 0;
    if(![self loadConfig]){
        LOGS(@"Kein config.txt gefunden oder fehlerhaft. System wird beendet...");
        exit(0);
    }
    
//---------------------------------------------------------------//
//  ab hier config verfuegbar                                    //
//---------------------------------------------------------------//
    if(!isReload)LOGS(GPL_STRING);
    LOGS([self version]);
    if(fast_start){
        LOGS(@"\n---------------------------------------------------------\n--       !!!!!!!!!!!!!   fast_start !!!!!!!!!!!          \n--       kein unicode Font, keine BLZ/Ktonr.             \n---------------------------------------------------------");
    }
    if(![self establishConnection]){
        LOGS(@"keine Verbindung zur Datenbank; Terminiere;");
        exit(0);
    }
    utf8db = [[self freshChannel]isUTF8];
//---------------------------------------------------------------//
//  ab hier DB verfuegbar                                        //
//---------------------------------------------------------------//
    [self copyStdScript]; //javascript
    if(![self loadDD]){ // Repository aus IDM oder archive; falls archive veraltet, neu erstellen
        exit(0);
    }
    [self reloadScripts]; // es gibt keine dynvl mehr
    [self loadTransdicts];
    [self adjustDB];
    isReload = YES; // das naechste mal ist es ein Reload; dann nicht die Anwendung beenden bei DB-Unterschieden
    if(!fast_start){
        LOG(@"loading Unicode Font Tables");
        [self readArialuni_cmap];
        [self readArialuni_hmtx];
    }else{
        LOG(@"fast_start: skipping loading Unicode Font Tables");
    }
    [self registerBundles];
    [self loadQueries];
    [self registerIndexes];
    if([[self number]iE:@"1"]){
// falls config tabelle noch leer, das gelesene config.txt als aktives default-Profil inserten
        if([singleValueSQL(@"select count(*) from config") intValue] == 0){
            PBEO *eo = NEW_EO(@"config");
            [eo takeValuesFromDictionary:configDict];
            [eo tvfk(@"default",@"pid")];
            [eo tvfk(@"J",@"aktiv")];
            INSRT(eo);
        }
    }
    if(!fast_start){
        [self readBlz5];
    }else{
        LOG(@"fast_start: skipping loading BLZ");
    }
    [self loadLinkStylesheet];
// parmDict uebergeben, damit scripts andere Scripts mit parametern aufrufen koennen
    if([[self number]iE:@"1"]){
    // nur Instanz 1 darf das Startup script aufrufen
        [_APP executeScriptNamed:@"_Application/didStartup"  datasource:(PBWOEditor *)self parmDict:parmDict];
    }
    if(isBatch){
// Session machen mit root
        PBEO *ueo = getEOPkValue(@"vid_benutzer",@"Batch");
        WOContext *context;
        Session *session;
        if(!ueo){
            LOGS(@"Batch-User nicht angelegt.");
            exit(0);
        }
        context = [[WOContext alloc]init]; //geht hoffentlich ohne request
        session = (Session *)[context session]; //erzeugt neue Session
        [_APP setCurrentSession:session];
        if(!([session initWithUserEO:ueo])){
            LOGS(@"konnte Session nicht starten.");
            exit(0);
        }
        [_APP executeScriptNamed:batchScriptName  datasource:(PBWOEditor *)self parmDict:parmDict];
        exit(0);
    }
    [pool release];
}
- (Session *)session;
{
// fuer scripting %session
    return currentSession;
}
- (NSDictionary *)firma;
{
    return configDict; //da sind jetzt die ganzen Mandanten-Eigenschaften drin
}
- (NSString *)resourcePath;
{
//enthaelt Resources
    static NSString *s;
    if(!s){
        s = [NSSWF @"%@/Resources",MANDANTPATH];
        [s retain];
    }
    return s;
}
- (NSString *)resourceURL;
{
//enthaelt Resources
    static NSString *s;
    if(!s){
        s = [NSSWF @"/Aprica2_%@",mandant];
        [s retain];
    }
    return s;
}
- (NSString *)mandantPath;
{
//enthaelt rein mandantenspezifische Files
    static NSString *s;
    if(!s){
        s = [NSSWF @"%@/%@/%@",LOCALLIBRARY,NSAPPNAME,_K];
        [s retain];
    }
    return s;
}
- (NSString *)globalConfigPath;
{
//darauf baut alles auf
    static NSString *s;
    if(!s){
        s = [NSSWF @"%@/%@/_GLOBAL",LOCALLIBRARY,NSAPPNAME];
        [s retain];
    }
    return s;
}
//Pfade...
- (NSString *)K_Image;
{
    return [self companyImage];
}
- (NSString *)nextRoot;
{
    static NSString *s;
    if(!s){
        /* Unfortunately the GNUstep semantics of
	   NSOpenStepRootDirectory() have changed.  */
        s = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
						 NSLocalDomainMask,
						 NO) lastObject];
	s = [s stringByDeletingLastPathComponent]; // Library
	s = [s stringByDeletingLastPathComponent]; // Local
        if([s iE:@"/"]){
	    s=EON;
        }
        s = [s stringWithForwardSlashes];
        [s retain];
    }
    return s;
}
- (NSString *)localLibrary;
{
//darauf baut alles auf
    static NSString *s;
    if(!s){
        s = [NSSWF @"%@/Local/Library",[self nextRoot]];
        [s retain];
    }
    return s;
}
- (NSString *)tempdir;
{
//fuer das ganze Aprica
    static NSString *s;
    if(!s){
        s = [NSSWF @"%@/temp",RESOURCEPATH];
        [s retain];
    }
    return s;
}
- (void)createAuxDirs;
{
// div. Directories autom. anlegen, die nicht im svn sind
    NSFileManager *fm = [NSFileManager defaultManager];
    NSDictionary *att = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedInt: 0777] forKey: NSFilePosixPermissions];
    LMA;
    int i,j;
    [lma addObject:[NSSWF @"%@/Projekt",MANDANTPATH]];
    [lma addObject:[NSSWF @"%@/DataArchiv",MANDANTPATH]];
    [lma addObject:[NSSWF @"%@/DataArchiv/dumps",MANDANTPATH]];
    [lma addObject:[NSSWF @"%@/DataArchiv/dumps/tables",MANDANTPATH]];
    [lma addObject:[NSSWF @"%@/Resources/temp",MANDANTPATH]];
    [lma addObject:[NSSWF @"%@/Resources/Logs",MANDANTPATH]];
    [lma addObject:[NSSWF @"%@/Resources/documents",MANDANTPATH]];
    [lma addObject:[NSSWF @"%@/Resources/documents/Mails",MANDANTPATH]];
    [lma addObject:[NSSWF @"%@/Resources/documents/PDFArchiv",MANDANTPATH]];
    for(i=0,j=[lma count];i<j;i++){
        NSString *path = [lma oai:i];
        if(![fm fileExistsAtPath:path]){
            [fm createDirectoryAtPath:path attributes: att];
        }
    }
}
- (void)createApricaCss;
{
// expandiert /Aprica2/Images zu [NSSWF @"/Aprica2_%@/Images",mandant] und schreibt Aprica.css
    NSString *images_url = [NSSWF @"/Aprica2_%@/Images",mandant];
    NSString *s =  [NSSWCOF [NSSWF @"%@/Resources/Aprica_template.css",MANDANTPATH]];
    if(FILLED(s)){
        s = [s replace:@"/Aprica2/Images" with:images_url];
        s = [NSSWF @"/* Dieses File nicht editieren; es wird generiert aus Aprica_template.css; alle Aenderungen dort vornehmen und Anwendung neu starten;*/\n%@",s];
        [s WTF:[NSSWF @"%@/Resources/Aprica.css",MANDANTPATH]];
    }
}
- (void)clearTempdir;
{
    NSFileManager *fm = [NSFileManager defaultManager];
    NSString *td =TEMPDIR,*s;
    
//aufraeumen:
//alles andere aelter als 1 Std loeschen: temp. gif u. pdf
    NSDictionary *d;
    NSArray *a = [fm directoryContentsAtPath:td];
    NSString *f;
    NSCalendarDate *d2 = [[NSCalendarDate date] dateByAddingYears:0 months:0 days:0 hours:-1 minutes:0 seconds:0],*fd;
    int i,j;
    for(i=0,j=[a count];i<j;i++){
        s = [a oai:i];
        f = [td stringByAppendingPathComponent:s];
        if(!(d = [myFM fileAttributesAtPath:f traverseLink:NO]))continue;
        fd = [d objectForKey:@"NSFileModificationDate"];
        if([d2 compare:fd]==NSOrderedAscending)continue;
        [fm removeFileAtPath:f handler:nil];
    }
}
- (NSString *)hostname;
{
    return @"localhost";
}
- (NSString *)namedIconsPath;
{
//f. Druck
    return [NSSWF @"%@/Images",RESOURCEPATH];
}
- (NSString *)htmlwodTranslation:(NSString *)s;
{
// was zwischen BEGIN_T und END_T steht, uebersetzen in Session-Sprache
    NSArray *a = [s componentsSeparatedByString:BEGIN_T];
    LMA;
    int i,j;
    if([a count]==1)return s;
    [lma addObject:[a firstObject]];
    for(i=1,j=[a count];i<j;i++){
        NSString *s1 = [a oai:i];
        if(![s1 rangeOfString:END_T].length){
            [lma addObject:s1]; //stimmt was nicht
            continue;
        }else{
            NSArray *a1 = [s1 componentsSeparatedByString:END_T];
            [lma addObject:[[TRANSLATION([a1 firstObject]) replace:@"\"" with:@"\\\""] stringWithoutCR]];
            if([a1 count]==1)continue; //ganzer string
            [lma addObject:[[a1 arrayFromIndex:1] componentsJoinedByString:@""]];
        }
    }
    return [lma componentsJoinedByString:@""];
}
- (NSString *)preProcessWOD:(NSString *)s;
{
    NSString	*images_url = [NSSWF @"/Aprica2_%@/Images",mandant];
    s = [s replace:@"/Aprica2/Images" with:images_url];
    return [self htmlwodTranslation:s];
}
- (NSString *)preProcessHTML:(NSString *)s;
{
    NSString	*images_url = [NSSWF @"/Aprica2_%@/Images",mandant];
// zur Schreiberleichterung:
// <pb bla>   statt   <webobject name=bla>
    s = [s replace:@"<pb " with:@"<webobject name="];
    s = [s replace:@"</pb>" with:@"</webobject>"];
    s = [s replace:@"/Aprica2/Images" with:images_url];
    return [self htmlwodTranslation:s];
}
- (WOElement *)getTemplateForName:(NSString *)templateName;
{
//beides in einem File wg. Editiererleichterung;
//importiert werden .htmlwod Files
//Syntax: #import blafasel[.htmlwod]\n
//zu importiertende Files werden gesplittet und ein wod-Teil an bestehenden wod angehaengt
//funktioniert rekursiv
//alles liegt in Templates;
//wird bei pageWithName aufgerufen; von Apple;
    WOElement *template;
    NSMutableDictionary *templatesByName;
    if([_SESSION lang]){
        templatesByName = templatesByName1;
    }else{
        templatesByName = templatesByName0;
    }
    template = [templatesByName ofk:templateName];
    if(template)return template;
    {
        NSArray *a;
        NSMutableString *wod=[NSMutableString stringWithCapacity:3*1024];
        [wod setString:EON];
        [infiniteDetection removeAllObjects]; //f. endlos-Schleifen detection
        
//loest rekursiv Imports auf;
        a = [self loadHtmlwodNamed:templateName wod:wod import:NO];
        if(![a count]){
            return nil;
        }
        template = [WOComponent templateWithHTMLString:[self preProcessHTML:[a componentsJoinedByString:@"\n"]] declarationString:[self preProcessWOD:wod] languages:[NSArray array]];
        if(template){
            [templatesByName setObject:template forKey:templateName];
            return template;
        }
    }
    return nil;
}
- (void)checkForNameClashes:(NSString *)wod name:(NSString *)dn;
{
//durch den import von htmlwod files kann es zu namens kollisionen kommen; diese werden dann hier erkannt
    NSArray *a = [[wod componentsSeparatedByString:@"\n"]sortedArray];
    int i,j;
    for(i=1,j=[a count];i<j;i++){
        NSString *s=[[a oai:i]stringWithoutWindowsShit];
        NSString *s1=[[a oai:i-1]stringWithoutWindowsShit];
        if(FILLED(s) && FILLED(s1)){
            NSString *n = [[[s componentsSeparatedByString:@":"]firstObject]stringWithoutSpace];
            NSString *n1 = [[[s1 componentsSeparatedByString:@":"]firstObject]stringWithoutSpace];
            if([n iE:n1])LOGS(([NSSWF @"wod name clash in %@:\n---%@\n---%@",dn,s1,s]));
        }
    }
}
- (NSArray *)loadHtmlwodNamed:(NSString *)dn wod:(NSMutableString *)wod import:(BOOL)import;
{
// dn ist einzelner filename ohne suffix
// flag import besagt, dass ein import aufgeloest wird
    NSString	*pathf,*pathf2use=nil;
    NSString	*htmlwod,*htmlwod2use=nil,*html,*s;
    LMA;
    NSArray *a;
    int	i,j;
    if([infiniteDetection ofk:dn]){
        LOGS(([NSSWF @"endlos-Import Schleife an %@.htmlwod",dn]));
        // PRINTCURRENTSTACK;
        return nil; //endlos-Schleife
    }
    [infiniteDetection setSecureObject:EON forKey:dn];
    pathf = [NSSWF @"%@/Templates/%@.htmlwod",MANDANTPATH,dn];
    htmlwod = [NSSWCOF pathf];
    if(htmlwod){
        a = [htmlwod componentsSeparatedByString:SPLITSTRING];
        if([a count]==2){ //optionales wod im import
            [wod appendString:[a oai:1]];
        }
        htmlwod2use = htmlwod;
        pathf2use = pathf;
    }
    if(!htmlwod2use){
        [infiniteDetection removeObjectForKey:dn];
        if(import){
            LOGS(([NSSWF @"import file %@.htmlwod nirgends gefunden",dn]));
        }
        return nil;
    }
    a = [htmlwod2use componentsSeparatedByString:SPLITSTRING];
    html=[a oai:0];
    a = [html componentsSeparatedByString:@"\n"];
    j = [a count];
    for(i=0;i<j;i++){
        s = [a oai:i];
        if([s hasSecurePrefix:@"#import"]){
            NSString *s1;
            NSArray *a1;
            a1 = [s componentsSeparatedByString:@" "];
            if([a1 count]<2){
                LOGS(([NSSWF @"falsches import-Statement: %@ in %@",s,pathf2use]));
                continue;
            }
            [lma addObject:[NSSWF @"<!---%@ --->",s]];
            s1 = [a1 oai:1]; //name der zu importierenden Datei relativ zum Templates ohne suffix
            s1 = [s1 stringWithoutWindowsShit];
            if((a1 = [self loadHtmlwodNamed:s1 wod:wod import:YES])){ //Rekursion; import ueberall suchen
                [lma addObjectsFromArray:a1];
            }
        }else{
            [lma addObject:s];
        }
    }
    [infiniteDetection removeObjectForKey:dn];
    return lma;
}
/***********************************************************************/
//WO hooks
- (void)awake;
    /* Called at the beginning of each request handling loop. */
{
    if(firstAwake){
        firstAwake = NO;
        if([NSThread isMultiThreaded]){
            LOGS(@"Diese Applikation ist fuer single-threading ausgelegt. Bitte WOWorkerThreadCount auf 0 setzen.");
            exit(0);
        }
    }
}
- (void)exit0;
{
    exit(0);
}
- (WOResponse *)errorResponse:(NSString *)err;
{
    WOResponse *resp = [[[WOResponse alloc]init]autorelease];
    LOGS(err);
    [resp setContentEncoding:NSUTF8StringEncoding];
//    [resp setHeader:@"text/html"  forKey:@"Content-Type"];
    [resp appendContentString:[NSSWF @"<Aprica_SOA_RC>Error</Aprica_SOA_RC><Aprica_SOA_RC_Detail>%@</Aprica_SOA_RC_Detail>",err]];
#ifdef GNUSTEP
    [resp _finalizeInContext:nil];
#endif
    return resp;
}
- (WOResponse *)successResponse:(NSString *)detail;
{
    WOResponse *resp = [[[WOResponse alloc]init]autorelease];
    [resp setContentEncoding:NSUTF8StringEncoding];
    [resp appendContentString:[NSSWF @"<Aprica_SOA_RC>Success</Aprica_SOA_RC><Aprica_SOA_RC_Detail>%@</Aprica_SOA_RC_Detail>",detail]];
    return resp;
}
- (WOResponse *)dispatchRequest:(WORequest *)aRequest;
{
    WOResponse *resp;
    NSString *soa;
    double ts;
    /* This is needed by GSWeb as it evaluates form values early
    and caches them.  Setting the encoding in
takeValuesFromRequest:inContext: would be too late.  */
    dbNr = 0; // zur Sicherheit; falls ein Script vergisst, die dbNr zurueckzusetzen;
    [parmDict removeAllObjects];
    [scriptNames removeAllObjects];
    if(!utf8){
        [aRequest setDefaultFormValueEncoding:NSWindowsCP1252StringEncoding];
    }else{
        [aRequest setDefaultFormValueEncoding:NSUTF8StringEncoding];
    }
    if(log_changes)LOGS([[aRequest vfk:@"_formValues"]description]);
    
// SOA
    soa = [aRequest headerForKey:@"soa"];
    if(FILLED(soa)){
// wird als Name eines Scripts interpretiert
// der content des Request sollte dann XML utf8-codiert sein, welches geparsed und dem Script ins parmDict gestellt wird unter dem Namen "p_soa"
// das Script erstellt ein NSMutableData mit name "soa_response", welches dann zurueckgeschickt wird
        if(![scriptDict ofk:soa]){
            return [self errorResponse:[NSSWF @"invalid soa script %@",soa]];
        }else{
            LMD;
            NSDictionary *p_soa;
            NSString *xml = [[[NSString alloc]initWithData:[aRequest content] encoding:NSUTF8StringEncoding]autorelease];
            if(log_changes)LOGS(xml);
            p_soa = [self objectFromXML:xml];
            if(p_soa){
                [lmd setObject:p_soa forKey:@"p_soa"];
                if(log_changes)LOGS([p_soa description]);
            }
            lmd = [_APP executeScriptNamed:soa datasource:(PBWOEditor *)self parmDict:parmDict];
            if([[lmd ofk:@"scriptRC"] iE:@"N"])return [self errorResponse:[NSSWF @"soa script %@ returned Error",soa]];
            resp = [[[WOResponse alloc]init]autorelease];
            [resp setContentEncoding:NSUTF8StringEncoding];
            [resp setContent:[lmd ofk:@"soa_response"]]; // muss ein NS(Mutable)Data sein
            if(log_changes)LOGS([[[NSString alloc]initWithData:[resp content] encoding:NSUTF8StringEncoding]autorelease]);
            [resp setHeader:NSS([[resp content] length]) forKey:@"Content-Length"];
            [resp setHeader:@"text/plain" forKey:@"Content-Type"];
#ifdef GNUSTEP
            [resp _finalizeInContext:nil];
#endif
        }
    }else{
        ts = [NSDate timeIntervalSinceReferenceDate];
        resp = [super dispatchRequest:aRequest];
        ts = [NSDate timeIntervalSinceReferenceDate] - ts;
        if(ts>4.0)LOG(([NSSWF @"%03f sec. ### long Request",ts]));
    }
    return resp;
}
- (void)takeValuesFromRequest:(WORequest *)aRequest inContext:(WOContext *)aContext;
{
    if(!utf8){
        [aRequest setDefaultFormValueEncoding:NSWindowsCP1252StringEncoding];
    }else{
        [aRequest setDefaultFormValueEncoding:NSUTF8StringEncoding];
    }
    [super takeValuesFromRequest:aRequest inContext:aContext];
}
/*
- (WOElement *)invokeActionForRequest:(WORequest*)aRequest inContext:(WOContext*)aContext
{
    return [super invokeActionForRequest:(WORequest*)aRequest inContext:(WOContext*)aContext];
}
*/
- (void)appendToResponse:(WOResponse *)aResponse inContext:(WOContext 
*)aContext;
{
    if(!utf8){
        [aResponse setContentEncoding:NSWindowsCP1252StringEncoding];
    }else{
        [aResponse setContentEncoding:NSUTF8StringEncoding];
    }
    [aResponse setHeader:@"Tue, 30 Jul 2002 00:00:00 GMT" forKey:@"Expires"];
    [super appendToResponse:aResponse inContext:aContext];
}
/* Called at the end of each request handling loop.
*/
- (void)sleep;
{
#ifdef WIN32
    [logfh synchronizeFile];
#endif
    [super sleep];
}
- (NSString *)metaContentString;
{
// wird in _browser_minimal.htmlwod verwendet;
    NSString *charset = @"iso-8859-1"; // std.
    if(utf8){
        charset = @"UTF-8";
    }
    return [NSSWF @"<meta http-equiv=\"content-type\" content=\"text/html; charset=%@\">",charset];
}
- (WOSession *)createSessionForRequest: (WORequest *)aRequest;
{
#warning configurierbar machen
/*
    NSString *s = [aRequest cookieValueForKey:@"wosid"];
    if(FILLED(s)){
        WOSession *session;
        LOG(s);
        NS_DURING;
        session = [self restoreSessionWithID:s inContext:nil];
        NS_HANDLER;
        return [super createSessionForRequest:aRequest];
        NS_ENDHANDLER;
        return session;
    }
*/
    return [super createSessionForRequest:aRequest];
}
- (WOComponent *)pageWithName:(NSString *)aName inContext:(WOContext *)aContext;
{
    if((!aName || [aName iE:@"Main"])){
        WORequest *r = [aContext request];
        NSString *zielmodul,*loginName,*pw,*csc,*buttonDbName;
        PBWOEditor *zielmodulInstance;
        if([_SESSION nextModul]){ // schon aktive Session
            zielmodul = [r formValueForKey:@"zielmodul"];
            if(!zielmodul)zielmodul = [r formValueForKey:@"modul"];
            if(!zielmodul){
                return [_SESSION nextModul];
            }else{
                zielmodulInstance = [_SESSION instanceForBundleNamed:zielmodul];
                if(zielmodulInstance){
                    return zielmodulInstance;
                }else{
                    return [_SESSION nextModul];
                }
            }
        }else{
            LoginUser *loginUser = [_SESSION instanceForAppBundleNamed:@"LoginUser"]; // die Defaultseite;
            buttonDbName = [r formValueForKey:@"button"];
            csc = [r formValueForKey:@"csc"];
            if(!csc)csc = [r formValueForKey:@"suche"];
            pw = [r formValueForKey:@"pw"];
            if(!pw)pw = [r formValueForKey:@"password"];
            loginName = [r formValueForKey:@"loginName"];
            if(!loginName)loginName = [r formValueForKey:@"loginname"];
            if(!loginName)loginName = [r formValueForKey:@"login"];
            if(!loginName)loginName = [r formValueForKey:@"user"];
            zielmodul = [r formValueForKey:@"zielmodul"];
            if(!zielmodul)zielmodul = [r formValueForKey:@"modul"];
            [loginUser setZielmodul:zielmodul];
            [loginUser setLoginName:loginName];
            [loginUser setPw:pw];
            zielmodulInstance = (PBWOEditor *)[loginUser login]; //verarbeiter loginName, pw, optional zielmodul u. liefert zielmodul oder Startx oder LoginUser mit Fehler
            if([zielmodulInstance isKindOfClass:[PBWOEditor class]]){
                if(FILLED(csc)){
                    [(PBWOEditor *)zielmodulInstance setCombiSuchContent:csc];
                    [(PBWOEditor *)zielmodulInstance combiSucheActed];
                }else{
                    if(FILLED(buttonDbName)){
                // Klick auf den Button simulieren
                        PBDDAttribute *pba = [[zielmodulInstance myTable]plainAttrNamed:buttonDbName];
                        if(pba && ([pba targetTyp]==ATBU) && [pba isAuthorized]){
                            [zielmodulInstance attributeButtonActed:buttonDbName];
                        }
                    }
                }
            }
            return zielmodulInstance;
        }
    }
    if([_APP logActions])LOGS(aName);
    return [super pageWithName:(NSString *)aName inContext:(WOContext *)aContext];
}
/***********************************************************************/
- (void)dealloc
{
    [self closeAllChannels]; 
    [restString release];
    [currentTempName release];
    [fontList release];
    [colorSpaces release];
    [fontEncodings release];
    [matchingEndif release];
    [mandant release];
    [matchingEndwhile release];
    [matchingEndsub release];
    [matchingEndfor release];
    [matchingForeach release];
    [matchingWhile release];
    [subNamed release];
    [urlToOpenInNewBrowser release];
    [externalUrlToOpenInNewBrowser release];
    [scriptDict release];
    [scriptDictAnalyzed release];
    [infiniteDetection release];
    [scriptFileNames release];
    [scriptFiles release];
    [scriptErrors release];
    [templateFileNames release];
    [configDict release];
    [transDict release];
    [bundlesByName release];
    [channelPool release];
    [myDD release];
    [seqAccesses release];
    [mimeTypes release];
    [h3eos release];
    [super dealloc];
}
- (void)sendSms:(NSString *)body to:(NSString *)to;
{
//Aufbau von subject u. to: sind auf den Gatewaybetreiber team-message abgestimmt; teammessage.de
    NSString *fn,*sys,*u,*pw,*auth=EON,*subj;
    if(!FILLED(body))return;
    if(!FILLED(to))return;
    subj = [[CURRENTUSEREO vfk:@"phonem"]onlyDigits];
    if([subj hasSecurePrefix:@"00"])subj = [@"+" stringByAppendingString:[subj substringFromIndex:2]];
    if(!FILLED(subj)){
        subj = [NSSWF @"%@ %@",[CURRENTUSEREO vfk:@"vorname"],[CURRENTUSEREO vfk:@"nachname"]];
    }
    subj = [NSSWF @"from-(%@)",subj];
    fn = [NSSWF @"%@/B_%@",TEMPDIR,[self tempName]]; //muss nicht gemerkt werden
    [body WTF:fn];
    to = [NSSWF @"%@.seat-1@tmsg.de",to];
    u=[configDict ofk:@"smsmailuser"];
    pw=[configDict ofk:@"smsmailpw"];
    if(FILLED(u) && FILLED(pw)){
        auth = [NSSWF @"-u \"%@\" -pw \"%@\"",u,pw];
    }
// wenn der smtp server auth erforder, ist zusaetzlich -u f. User und -pw fuer Passwort zu uebergeben
    sys = [NSSWF @"blat \"%@\" -t \"%@\" -s \"%@\"  %@ -server \"%@\" -f \"%@\"",fn,to,subj,auth,[[_APP configDict]ofk:@"smsmailserver"],[[_APP configDict]ofk:@"smsmailfrom"]];
    SYSTEM(sys);
}
- (void)sendMail:(NSString *)body to:(NSString *)to subject:(NSString *)subject;
{
    [self sendMail:body to:to subject:subject attachment:nil];
}
- (void)sendMail:(NSString *)body to:(NSString *)to subject:(NSString *)subject attachment:(NSString *)attachment;
{
//attachment ist filename;
    NSString *attach=EON,*fn,*sys,*from,*u,*pw;
    LMA;
#ifndef GNUSTEP
    NSString *auth=EON;
#endif
    if(!FILLED(body))return;
    if(!FILLED(to))return;
    if(!FILLED(subject))subject = @"zur Info";
    fn = [NSSWF @"%@/B_%@",TEMPDIR,[self tempName]]; //muss nicht gemerkt werden
    [body WTF:fn];
    from = [CURRENTUSEREO vfk:@"email"];
    if(!FILLED(from))from=[configDict ofk:@"emailsender"];
    u=[configDict ofk:@"mailuser"];
    pw=[configDict ofk:@"mailpw"];
#ifndef GNUSTEP
// attachment darf auch ein array sein
    if(attachment){
        if([attachment isKindOfClass:[NSArray class]]){
            int i,j;
            for(i=0,j=[(NSArray *)attachment count];i<j;i++){
                [lma addObject:[NSSWF @" -attach \"%@\" ",[[(NSArray *)attachment oai:i]stringWithBackSlashes]]];
            }
            attach = [lma componentsJoinedByString:@""];
        }else{
            if(FILLED(attachment)){
                attach = [NSSWF @" -attach \"%@\" ",[attachment stringWithBackSlashes]];
            }
        }
    }
    if(FILLED(u) && FILLED(pw)){
        auth = [NSSWF @"-u \"%@\" -pw \"%@\"",u,pw];
    }
// -f wird bei -install gesetzt u. ist aus config der email-sender; es ist der login-Name
// wenn der smtp server auth erforder, ist zusaetzlich -u f. User und -pw fuer Passwort zu uebergeben
    sys = [NSSWF @"blat \"%@\" %@ -t \"%@\" -s \"%@\" -replyto \"%@\" -charset UTF-8 %@",fn,attach,to,subject,from,auth];
#else
    if(attachment){
        if([attachment isKindOfClass:[NSArray class]]){
            int i,j;
            for(i=0,j=[(NSArray *)attachment count];i<j;i++){
                [lma addObject:[NSSWF @" -a \"%@\" ",[[(NSArray *)attachment oai:i]stringWithForwardSlashes]]];
            }
            attach = [lma componentsJoinedByString:@""];
        }else{
            if(FILLED(attachment)){
                attach = [NSSWF @" -a \"%@\" ",[attachment stringWithForwardSlashes]];
            }
        }
    }
    sys = [NSSWF @"EMAIL=\"%@ <%@>\" mutt -n -s \"%@\" %@ \"%@\" < \"%@\"",from,from,subject,attach, to, fn];
#endif
    SYSTEM(sys);
}
- (void)sendFaxMail:(NSString *)body to:(NSString *)to subject:(NSString *)subject attachment:(NSString *)attachment;
{
//attachment ist filename;
    NSString *fn,*sys,*from,*u,*pw;
#ifndef GNUSTEP
    NSString *attach=EON,*auth=EON;
#endif
    if(!FILLED(to))return;
    if(!FILLED(subject))return;
    fn = [NSSWF @"%@/B_%@",TEMPDIR,[self tempName]]; //muss nicht gemerkt werden
    [body WTF:fn];
    from = [CURRENTUSEREO vfk:@"email"];
    if(!FILLED(from))from=[configDict ofk:@"emailsender"];
    u=[configDict ofk:@"mailuser"];
    pw=[configDict ofk:@"mailpw"];
#ifndef GNUSTEP
    if(FILLED(attachment)){
        attach = [NSSWF @" -attach \"%@\" ",[attachment stringWithBackSlashes]];
    }
    if(FILLED(u) && FILLED(pw)){
        auth = [NSSWF @"-u \"%@\" -pw \"%@\"",u,pw];
    }
// -f wird bei -install gesetzt u. ist aus config der email-sender; es ist der login-Name
// wenn der smtp server auth erforder, ist zusaetzlich -u f. User und -pw fuer Passwort zu uebergeben
    sys = [NSSWF @"blat \"%@\" %@ -t \"%@\" -s \"%@\" -replyto \"%@\" -charset UTF-8 %@",fn,attach,to,subject,from,auth];
#else
    if(FILLED(attachment)){
        sys = [NSSWF @"mailm -t \"%@\" -s \"%@\" -f \"%@\" -mm -at \"%@\" -ad \"%@\"",to,subject,from,fn,[attachment stringWithForwardSlashes]];
    }else{
        sys = [NSSWF @"mailm -t \"%@\" -s \"%@\" -f \"%@\" -mm -at \"%@\"",to,subject,from,fn];
    }
#endif
    SYSTEM(sys);
}
- (void)sendFax:(NSString *)body to:(NSString *)to subject:(NSString *)subject attachment:(NSString *)attachment;
{
//body enthaelt die Nachricht bei Kurz-Faxen und kann sog. Macros (systemvariablen) enthalten, die RelayFax filtert
//to ist die FaxNr und optional zusaetzl. Name, company-Name des Empf.
//Subject ist der betreff
//attachment ist filename;
    NSString *fn,*sys,*macros=EON,*u,*pw,*auth=EON;
    PBEO *ueo = CURRENTUSEREO;
    if(!FILLED(body))return;
    if(!FILLED(to))return;
    if(!FILLED(subject))subject = @"zur Info";
    to = [[to componentsSeparatedByString:@"/"]componentsJoinedByString:EON]; // slashes vertraegt der relay fax nicht
    fn = [NSSWF @"%@/B_%@",TEMPDIR,[self tempName]]; //muss nicht gemerkt werden
    macros = [macros stringByAppendingFormat:@"FROMNAME: %@ %@\n",[ueo vfk:@"vorname"],[ueo vfk:@"nachname"]];
    macros = [macros stringByAppendingFormat:@"BUSFAX: %@\n",[ueo vfk:@"telefax"]];
    macros = [macros stringByAppendingFormat:@"BUSPHONE: %@\n",[ueo vfk:@"phone"]];
    macros = [macros stringByAppendingFormat:@"STREET1: %@\n",[ueo vfk:@"strasse"]];
    macros = [macros stringByAppendingFormat:@"CITY: %@\n",[ueo vfk:@"ortstrasse"]];
    macros = [macros stringByAppendingFormat:@"ZIP: %@\n",[ueo vfk:@"plzstrasse"]];
    macros = [macros stringByAppendingFormat:@"FROMCOMPANY: %@\n",[[_APP firma]vfk:@"firma"]];
    macros = [macros stringByAppendingFormat:@"FAXNUMBER: %@\n",to];
    if(FILLED(attachment)){
        macros = [macros stringByAppendingFormat:@"ATTACHMENT: %@\n",[attachment stringWithBackSlashes]];
    }
    body = [NSSWF @"%@\n%@",macros,body];
    [body WTF:fn];
    pw = [configDict ofk:@"faxmailpW"];
    u = [configDict ofk:@"faxmailuser"];
    if(FILLED(u) && FILLED(pw)){
        auth = [NSSWF @"-u \"%@\" -pw \"%@\"",u,pw];
    }
    sys = [NSSWF @"blat \"%@\" -t \"%@\" -s \"%@\" %@ -f \"%@\" -server %@ -charset UTF-8",fn,[configDict ofk:@"faxmailto"],subject,auth,[configDict ofk:@"faxmailfrom"],[configDict ofk:@"faxmailserver"]];
    SYSTEM(sys);
}
- (PBWOBundle *)bundleWithName:(NSString *)aName;
{
    return [bundlesByName ofk:aName];
}
- (void)loadModulesFN:(NSString *)fn inMD:(NSMutableDictionary *)modules;
{
// fn lesen, parsen, in modules stellen
    NSString *file = [NSSWCOF fn];
    NSArray *lines = [file componentsSeparatedByString:@"\n"];
    int i,j;
    for(i=0,j=[lines count];i<j;i++){
        NSMutableDictionary *properties;
        NSString *line = [lines oai:i];
        NSArray *fields = [line componentsSeparatedByString:@"\t"];
        NSString *modulName,*propertyName,*propertyValue;
        if([line hasSecurePrefix:@"#"] || !FILLED(line))continue;
        if([fields count]!=3){
            LOGS(([NSSWF @"malformed line in module.txt %@",line]));
            continue;
        }
        modulName = [fields oai:0];
        propertyName = [[fields oai:1]lowercaseString];
        propertyValue = [fields oai:2];
        properties = [modules ofk:modulName];
        if(!properties){
            properties = [NSMutableDictionary dictionaryWithCapacity:10];
            [modules setObject:properties forKey:modulName];
        }
        [properties setObject:[propertyValue stringByUnescapingCRTAB] forKey:propertyName];
    }
}
- (void)addDBIndexes:(NSMutableArray *)lma;
{
    NSArray *a = [_APP getArrayAsResultFrom:@"show tables"];
    int i,j;
    NSArray *soaInd = [NSArray soaFrom:@"Key_name,Seq_in_index"];
// die tables in der DB;
    for(i=0,j=[a count];i<j;i++){
        NSString *tn = [[[[a oai:i]allObjects]firstObject]lowercaseString];
        NSString *sql = [NSSWF @"show keys from %@",tn];
        NSArray *a1 = [[_APP getArrayAsResultFrom:sql]sortedArrayUsingKeyOrderArray:soaInd]; //einzelne Indexsaetze; pro Feld einer
        int i1,j1;
        LMDN(byKey_name);
	// felder f. attrlist zusammensammeln
        for(i1=0,j1=[a1 count];i1<j1;i1++){
            NSDictionary *d = [a1 oai:i1];
            PBEO *eo;
            NSString *tn = [[d ofk:@"Table"]lowercaseString];
            NSString *kn = [d ofk:@"Key_name"]; // damit die feldliste zusammenbauen
            NSString *fn = [[d ofk:@"Column_name"]lowercaseString];
            if([tn hasSecurePrefix:@"query_"] || [tn hasSecurePrefix:@"keyword_"])continue;
            eo = [byKey_name ofk:kn];
            if(!eo){
                eo = NEW_EO(@"r_indexe");
                [eo tvfk(@"J",@"dbonly")];
                [eo tvfk(tn,@"tablename")];
                [eo tvfk(kn,@"key_name")];
                [eo tvfk(fn,@"attrlist_db")];
                [eo tvfk(@"J",@"isexistant")];
                [byKey_name setObject:eo forKey:kn];
            }else{
                [eo tvfk(([NSSWF @"%@,%@",[eo vfk:@"attrlist_db"],fn]),@"attrlist_db")];
            }
        }
	// gefundene Indexe abgleichen mit manuellen u. autom.; ausschlaggebend ist tablename und attrlist
        a1 = [byKey_name allObjects];
        for(i1=0,j1=[a1 count];i1<j1;i1++){
            PBEO *eo = [a1 oai:i1];
            [eo tvfk([eo vfk:@"attrlist_db"],@"attrlist")];
            [self mergeIndex:eo intoIndexes:lma];
        }
    }
}
- (void)mergeIndex:(PBEO *)eo intoIndexes:(NSMutableArray *)lma;
{
    int i2,j2 = [lma count];
// ueber tablename und attrlist zusammenfinden
    for(i2=0;i2<j2;i2++){
        PBEO *eo1 = [lma oai:i2];
        if([[eo1 vfk:@"attrlist"] iE:[eo vfk:@"attrlist"]] && [[eo1 vfk:@"tablename"] iE:[eo vfk:@"tablename"]]){
            NSString *s;
            if([[eo vfk:@"isexistant"]iE:@"J"])[eo1 tvfk(@"J",@"isexistant")];
            if([[eo vfk:@"is_serial"]iE:@"J"])[eo1 tvfk(@"J",@"is_serial")];
            s = [eo vfk:@"attrlist_db"];
            if(FILLED(s))[eo1 tvfk(s,@"attrlist_db")];
            s = [eo vfk:@"key_name"];
            if(FILLED(s))[eo1 tvfk(s,@"key_name")];
            return;
        }
    }
    [lma addObject:eo];
}
- (void)addAutomaticIndexes:(NSMutableArray *)lma;
{
// von allen tables den pk dazu
// alle tables mit masterkey den mk dazu
// alle combi-such-Felder dazu
    NSArray *a = [MYDD tables];
    int i,j;
    for(i=0,j=[a count];i<j;i++){
        PBDDTable *t = [a oai:i];
        if([t isRealTable]){
            NSString *pk;
            PBEO *eo;
            if([t plainAttrNamed:@"masterkey"]){
                eo = NEW_EO(@"r_indexe");
                [eo tvfk([t dbName],@"tablename")];
                [eo tvfk(@"masterkey",@"attrlist")];
                [eo tvfk(@"J",@"automatic")];
                [self mergeIndex:eo intoIndexes:lma];
            }
            pk =[t primaryKeyName];
            if(pk){
                eo = NEW_EO(@"r_indexe");
                [eo tvfk([t dbName],@"tablename")];
                [eo tvfk(pk,@"attrlist")];
                [eo tvfk(@"J",@"automatic")];
                if([[t primaryKeyAttr] isSerialPK])[eo tvfk(@"J",@"is_serial")];
                [self mergeIndex:eo intoIndexes:lma];
            }
            {
                NSArray *ats = [t plainAttributes];
                int i1,j1;
                for(i1=0,j1=[ats count];i1<j1;i1++){
                    PBDDAttribute *at = [ats oai:i1];
                    NSString *rtn = [at refdTableName],*dbn = [at dbName];
                    if(([at isCombiSuch] || [rtn iE:@"vid_kunde"] || [rtn iE:@"vid_lager"] || [dbn iE:@"datum"] || [dbn iE:@"buchungsdatum"] || [dbn iE:@"ldate"]) && ![at isPK] && ![[at dbName]iE:@"masterkey"]){
                        eo = NEW_EO(@"r_indexe");
                        [eo tvfk([t dbName],@"tablename")];
                        [eo tvfk([at dbName],@"attrlist")];
                        [eo tvfk(@"J",@"automatic")];
                        [self mergeIndex:eo intoIndexes:lma];
                    }
                }
            }
        }
    }
}
- (NSArray *)indexesFromFile:(NSString *)fn;
{
    NSString *file = [NSSWCOF fn];
    NSArray *lines = [file componentsSeparatedByString:@"\n"];
    int i,j;
    LMA;
    for(i=0,j=[lines count];i<j;i++){
        PBEO *eo;
        NSString *line = [[lines oai:i]stringWithoutWindowsShit];
        NSArray *fields = [line componentsSeparatedByString:@"\t"];
        int fc = 0;
        int j1 = [fields count];
        PBDDTable *t;
        NSArray *attrs;
        BOOL use = YES;
        int i2,j2;
        if([line hasSecurePrefix:@"#"] || !FILLED(line))continue;
        if(j1<2){
            continue;
        }
        eo = NEW_EO(@"r_indexe");
        [eo tvfk([fields oai:fc++],@"tablename")];
        if(!(t=[MYDD tableNamedCheap:[eo vfk:@"tablename"]])){
// tabelle gibt es nicht mehr
            LOG(([NSSWF @"non-existant table in indexes: %@",[eo vfk:@"tablename"]]));
            continue;
        }
        if(j1 > 2){
            fc++;
        }
        [eo tvfk([fields oai:fc++],@"attrlist")];
        if(!FILLED([eo vfk:@"attrlist"]))continue;
        attrs = [[eo vfk:@"attrlist"]componentsSeparatedByString:@","];
        for(i2=0,j2=[attrs count];i2<j2;i2++){
            NSString *attr = [attrs oai:i2];
            if(![t plainAttrNamed:attr]){
                use = NO;
                LOG(([NSSWF @"non-existant attr %@ in table %@ in indexes;",attr,[eo vfk:@"tablename"]]));
                break;
            }
        }
        if(use){
            [eo tvfk(@"N",@"isexistant")];
            [lma addObject:eo];
        }
    }
    return lma;
}
- (void)registerIndexes;
{
// db-Tabelle r_indexe loeschen, mandanten-file lesen, abgleichen mit Indexen in DB, saetze erzeuegn
    LMA;
    int i,j;
    LOG(@"loading Index Information");
    [lma addObjectsFromArray:[self indexesFromFile:[NSSWF @"%@/Indexe.txt",MANDANTPATH]]]; // liefert EOs
    [self addAutomaticIndexes:lma]; // liefert EOs
    [self addDBIndexes:lma]; // liefert EOs
    singleValueSQL(@"delete from r_indexe");
    for(i=0,j=[lma count];i<j;i++){
        PBEO *eo = [lma oai:i];
        INSRT(eo);
    }
}
- (void)dbToIndexes;
{
// db-Tabelle r_indexe in mandanten-file indexe.txt schreiben
// muss ausgefuehrt werden, wenn in r_indexes editiert worden ist
    int i,j;
    NSMutableString *msm = [NSMutableString stringWithCapacity:10240];
    NSArray *propertyNames = [NSArray arrayWithObjects:@"tablename",@"attrlist",nil];
    NSArray *mda, *lsoa = [NSArray soaFrom: @"tablename,attrlist"];
    mda = getEOsQSoa(@"r_indexe",nil,lsoa);
    [msm setString:EON];
    for(i=0,j=[mda count];i<j;i++){
        PBEO *eo = [mda oai:i];
        int i1,j1;
        if([[eo vfk:@"automatic"]iE:@"J"])continue;
        if([[eo vfk:@"dbonly"]iE:@"J"])continue;
        for(i1=0,j1=[propertyNames count];i1<j1;i1++){
            if(i1)[msm appendString: @"\t"];
            [msm appendString:[eo vfk:[propertyNames oai:i1]]];
        }
        [msm appendString: @"\n"];
    }
    [msm WTF:[NSSWF @"%@/Indexe.txt",MANDANTPATH]];
}
- (void)loadTemplateFileNames;
{
    NSString *dirName = @"Templates";
    NSString *suffix = @".htmlwod";
    NSString *baseDir = [NSSWF @"%@/%@",MANDANTPATH,dirName];
    NSArray *filesToLoad = [myFM directoryDeepContentsAtPath:baseDir suffixes:[NSArray arrayWithObject:suffix] skips:nil fullName:YES];
    int i,j;
    NSString *s;
    [templateFileNames removeAllObjects];
    [templateFiles removeAllObjects];
    for(i=0,j=[filesToLoad count];i<j;i++){
        s = [[filesToLoad oai:i]stringWithForwardSlashes];
        if([s rangeOfString:@".svn"].length)continue; //keine svn Files laden
        [templateFileNames addObject:s];
    }
    [templateFileNames sortUsingSelector:@selector(compareCaseInsensitive:)];
}
- (void)loadQueries;
{
    if([[self number]iE:@"1"]){
        NSString *fn = [NSSWF @"%@/queries.txt",MANDANTPATH];
        NSString *file = [NSSWCOF fn];
        NSArray *a;
        LOG(@"loading Queries");
        if(!FILLED(file)){
            LOG(@"no queries.txt; leaving queries table;");
            return;
        }
        a = [PBEO eosFromString:file];
        if([a count]){
            int i,j;
            SQL(@"delete from queries");
            for(i=0,j=[a count];i<j;i++) {
                INSRT([a oai: i]);
            }
        }else{
            LOG(@"loading queries failed; leaving queries table;");
        }
    }
}
- (void)registerBundles;
{
// nur noch mandanten-module
    NSString *fn = [NSSWF @"%@/module.txt",MANDANTPATH];
    LMDN(modules);
    NSArray *a1;
    int i,j;
    PBWOBundle *b;
    BOOL hasSystem = NO;
    LOG(@"loading Bundle Information");
    [bundlesByName removeAllObjects];
    [templatesByName0 removeAllObjects];
    [templatesByName1 removeAllObjects];
    [self loadTemplateFileNames];
    if([[self number]iE:@"1"]){
        SQL(@"delete from module");
    }
    [self loadModulesFN:fn inMD:modules];
    
// daraus module erzeugen; module-records inserten;
    a1 = [modules allObjects];
    for(i=0,j=[a1 count];i<j;i++){
        NSMutableDictionary *properties=[a1 oai:i];
        NSString *s;
        PBDDTable *t;
        [properties removeObjectForKey:@"bereich"];
        [properties removeObjectForKey:@"is_mandant"];
        if([[self number]iE:@"1"]){
            PBEO *m = NEW_EO(@"module");
            [m takeValuesFromDictionary:properties];
            [_APP gruppenstringToFlags:m];
            if(![[[m values]ofk:@"is_unter_menu"]iE:@"J"] && !FILLED([[m values]ofk:@"super_menu"])){
                [[m values]sofk(@"System",@"super_menu")];
            }
            INSRT(m);
        }
// ausserdem: hidden, public
        s = [properties vfk:@"is_unter_menu"];
        if([s iE:@"J"]){ // Untermenues
            if([[properties vfk:@"name"]iE:@"System"])hasSystem = YES;
            continue;
        }
        s = [properties vfk:@"off"];
        if([s iE:@"J"])continue; // ausgeblendete Module
// fehlende Tabellen
        s = [properties vfk:@"entitynamemodul"];
        if(FILLED(s) && (!(t = [myDD tableNamedCheap:s]))){
            continue;
        }
        b = [[PBWOBundle alloc]init];
        s = [properties vfk:@"name"];
        [b setName:s];
        s = [properties vfk:@"doku0"];
        if(FILLED(s))[b setDoku0:s];
        s = [properties vfk:@"doku1"];
        if(FILLED(s))[b setDoku1:s];
        s = [properties vfk:@"kuerzel"];
        if(FILLED(s))[b setKuerzel:s];
        s = [properties vfk:@"guiname"];
        if(!FILLED(s))s=[b name];
        [b setGuiName:s];
        s = [properties vfk:@"guiname1"];
        if(!FILLED(s))s=[b guiName];
        [b setGuiName1:s];
        s = [properties vfk:@"classname"];
        [b setClassName:s];
        s = [properties vfk:@"entitynamemodul"];
        [b setEntityName:s];
        s = [properties vfk:@"initialsearch_off"];
        [b setInitialSearchOff:[s iE:@"J"]];
        s = [properties vfk:@"htmlwodname"];
        [b setHtmlwodName:s];
        s = [properties vfk:@"unterbereich"];
        if(!FILLED(s))s=@"System";
        [b setUnterBereich:s];
        s = [properties vfk:@"pos"];
        [b setPos:NSS([s intValue])];
        s = [properties vfk:@"hidden"];
        [b setHiddenModul:[s iE:@"J"]];
        s = [properties vfk:@"needsnomastereo"];
        [b setNeedsNoMasterEO:[s iE:@"J"]];
        s = [properties vfk:@"public"];
        [b setPublicModul:[s iE:@"J"]];
        s = [properties vfk:@"registerfielddbname"];
        [b setRegisterFieldDBName:s];
        s = [properties vfk:@"gruppenstring"];
        if(!FILLED(s))s=@"----------";
        [b setGruppenstring:s];
        [b buildMatchCode];
        [bundlesByName setSecureObject:b forKey:[b name]];
        [b release];
    }
// sicherstellen, dass es ein public default System-Menu gibt f. hierarchisches Menu
    if(!hasSystem){
        if([[self number]iE:@"1"]){
            PBEO *m = NEW_EO(@"module");
            [m tvfk(@"System",@"name")];
            [m tvfk(@"System",@"guiname")];
            [m tvfk(@"J",@"is_unter_menu")];
            [m tvfk(@"J",@"public")];
            [m tvfk(@"----------",@"gruppenstring")];
            [_APP gruppenstringToFlags:m];
            INSRT(m);
        }
    }
}
- (BOOL)loadConfig;
{
    NSDictionary *d = nil;
    NSString *fn,*s;
    BOOL rc = YES;
    
//config.txt; erforderlich; zuerst; f. Pfade;
    fn = [NSSWF @"%@/my_config.txt",MANDANTPATH];  // fuer vom kunde abweichende eigene Konfiguration; nicht ins svn!!
    if(!(s = [self readFileNamed:fn])){
        fn = [NSSWF @"%@/config.txt",MANDANTPATH]; // kunde darf kein my_config.txt haben
        if(!(s = [self readFileNamed:fn])) return NO;
    }
    d = [self confDictFromString: s];
    [self setConfigDict:d];
    
    logActions = [[configDict ofk:@"logactions"]iE:@"J"];
    orbDebug = [[configDict ofk:@"orbdebug"]iE:@"J"];
    orbDebugStack = [[configDict ofk:@"orbdebugstack"]iE:@"J"];
    fetchLimit = [[configDict ofk:@"fetchlimit"]intValue];
    utf8 = [[configDict ofk:@"utf8"]iE:@"J"];
    verifyDelete = [[configDict ofk:@"verifydelete"]iE:@"J"];
    if(!fetchLimit)fetchLimit=200;
    [self setCachingEnabled:YES];
    raster = MAX(30,[[configDict ofk:@"raster"]intValue]);
    bezWidth = MAX(1,[[configDict ofk:@"bezwraster"]intValue]);
    editWidth = [[configDict ofk:@"editwraster"]intValue];
    if(!editWidth)editWidth=4; //neues Feld sinnvollen Wert annehmen
    descrWidth = MAX(1,[[configDict ofk:@"descrwraster"]intValue]);
    fast_start = [[configDict ofk:@"fast_start"]iE:@"J"];
    log_changes = [[configDict ofk:@"log_changes"]iE:@"J"];   
#ifndef GNUSTEP
    SYSTEM(([NSSWF @"blat -install %@ %@",[configDict ofk:@"mailserver"],[configDict ofk:@"emailsender"]]));
#endif
    return rc;
}
- (BOOL)checkDependentFile:(NSString *)path date:(NSDate *)date;
{
    NSDate *fd;
    if(![myFM fileExistsAtPath:path])return YES;
    fd = [[myFM fileAttributesAtPath:path traverseLink:NO] fileModificationDate];
    return ([fd compare:date]==NSOrderedAscending);
}
- (void)fillPbaEO:(PBEO *)pbaeo pba:(PBDDAttribute *)pba;
{
    [pbaeo tvfk([pba dataTypS],@"datatyps")];
    [pbaeo tvfk([pba dbName],@"dbname")];
    [pbaeo tvfk([pba guiName],@"guiname")];
    [pbaeo tvfk([pba doku0],@"doku0")];
    [pbaeo tvfk([pba doku1],@"doku1")];
    [pbaeo tvfk([pba guiName1],@"guiname1")];
    [pbaeo tvfk([pba expression],@"expression")];
    [pbaeo tvfk([pba initialValue],@"initialvalue")];
    [pbaeo tvfk([pba isCombiSuchS],@"iscombisuchs")];
    [pbaeo tvfk([pba isRootS],@"isroots")];
    [pbaeo tvfk([pba isDBS],@"isdbs")];
    [pbaeo tvfk([pba isHtmlS],@"ishtmls")];
    [pbaeo tvfk([pba isDescriS],@"isdescris")];
    [pbaeo tvfk([pba isDuplicateS],@"isduplicates")];
    [pbaeo tvfk([pba isMandatoryS],@"ismandatorys")];
    [pbaeo tvfk([pba isProtectedS],@"isprotecteds")];
    [pbaeo tvfk([pba isVisibleS],@"isvisibles")];
    [pbaeo tvfk([pba alwaysOnS],@"alwaysons")];
    [pbaeo tvfk([pba gruppenstring],@"gruppenstring")];
    [pbaeo tvfk([pba keyTypS],@"keytyps")];
    [pbaeo tvfk([pba lengthS],@"lengths")];
    [pbaeo tvfk([pba nakS],@"naks")];
    [pbaeo tvfk([pba refdTableName],@"refdtablename")];
    [pbaeo tvfk([pba reference],@"reference")];
    [pbaeo tvfk([pba suffix],@"suffix")];
    [pbaeo tvfk([pba masterkey],@"tabelle")];
    [pbaeo tvfk([pba targetModulName],@"targetmodulname")];
    [pbaeo tvfk([pba targetTypS],@"targettyps")];
    [pbaeo tvfk([pba vlcontent],@"vlcontent")];
}
- (void)modelToDB;
{
// Modell in DB stellen; dort wird editiert;
    NSArray *ts = [myDD tables];
    BOOL hasPlainAttr = ([myDD tableNamedCheap:@"plainattributes"]!=nil);
    int i,j;
    int i1,j1;
    singleValueSQL(@"delete from pbddtable");
    singleValueSQL(@"delete from pbddattribute");
    for(i=0,j=[ts count];i<j;i++){
        PBDDTable *t = [ts oai:i];
        NSArray *pbas = [t attributes];
        PBEO *teo = NEW_EO(@"pbddtable");
//        LOGS([t dbName]);
        [teo tvfk([t bereich],@"bereich")];
        [teo tvfk([t dbName],@"dbname")];
        [teo tvfk([t guiName],@"guiname")];
        [teo tvfk([t type],@"type")];
        INSRT(teo);
        for(i1=0,j1=[pbas count];i1<j1;i1++){
            PBEO *pbaeo = NEW_EO(@"pbddattribute");
            PBDDAttribute *pba= [pbas oai:i1];
            [self fillPbaEO:pbaeo pba:pba];
            [pbaeo tvfk([pba pid],@"pid")];
            [_APP gruppenstringToFlags:pbaeo];
            INSRT(pbaeo);
        }
    }
    if(hasPlainAttr){
        ts = [myDD tablesIncludingAbstract:NO];
        singleValueSQL(@"delete from plainattributes");
        for(i=0,j=[ts count];i<j;i++){
            PBDDTable *t = [ts oai:i];
            NSArray *pbas = [t plainAttributes];
            NSString *tdbName = [t dbName];
            for(i1=0,j1=[pbas count];i1<j1;i1++){
                PBEO *pbaeo = NEW_EO(@"plainattributes");
                PBDDAttribute *pba= [pbas oai:i1];
                [self fillPbaEO:pbaeo pba:pba];
                [pbaeo tvfk(([NSSWF @"%@-%@",tdbName,[pba dbName]]),@"pid")];
                INSRT(pbaeo);
            }
        }
    }
}
- (void)dbToIDM;
{
// Modell aus DB in IDM Files schreiben; dauert 3 sec.;aufrufen nach aendern des Modells im PBDDTable/Attribute Editor;
    NSString *midm = [NSSWF @"%@/Mandant.idm",MANDANTPATH];
    NSMutableString *mand = [NSMutableString stringWithCapacity:100 * 1024];
    NSArray *tivs = [PBDDTable ivarNamesShort];
    NSArray *aivs = [PBDDAttribute ivarNames];
    LMAN(tivsdb);
    LMAN(aivsdb);
    int i,j,jt,ja;
    NSArray *soat = [NSArray soaFrom:@"dbname"];
    NSArray *soaa = [NSArray soaFrom:@"pid"];
    NSArray *ts;
    NSAutoreleasePool *pool = nil;
    NSMutableString *workstring=mand;
    if(noModelToDB){
        LOGI(@"-noModelToDB als Commandlineparameter; Model wurde nicht in DB geladen und darf jetzt nicht zurueckgeschrieben werden.");
	return;
    }
    for(i=0,jt=[tivs count];i<jt;i++){
        [tivsdb addObject:[[tivs oai:i]lowercaseString]];
    }
    for(i=0,ja=[aivs count];i<ja;i++){
        [aivsdb addObject:[[aivs oai:i]lowercaseString]];
    }
    ts = [getEOsQ(@"pbddtable",nil) sortedArrayUsingKeyOrderArray:soat]; // die DB sortiert leider anders, gibt dann im svn zuviele diff
    if(![ts count])return; // DB ist leer; dann nicht auch noch das idm wegmachen
    if(![self backupPath:midm])return;
    for(i=0,j=[ts count];i<j;i++){
        pool = [[NSAutoreleasePool alloc]init];
        {
            PBEO *t = [ts oai:i];
            NSString *tdbn = [t vfk:@"dbname"];
            int i1,i2,j2;
            PBSQLQualifier *q = [PBSQLQualifier qualifierWithString: [NSSWF @"tabelle = '%@'",tdbn]];
            NSArray *pbas;
    //        LOGS(tdbn);
            for(i1=0;i1<jt;i1++){
                NSString *tiv = [tivs oai:i1];
                NSString *tivdb = [tivsdb oai:i1];
                [workstring appendString:tdbn];
                [workstring appendString:@"\t-\t"];
                [workstring appendString:tiv];
                [workstring appendString:@"\t"];
                [workstring appendString:[[t vfk:tivdb]stringByEscapingCRTAB]];
                [workstring appendString:@"\n"];
            }
// attribute
            pbas = [getEOsQ(@"pbddattribute",q) sortedArrayUsingKeyOrderArray:soaa];
            for(i2=0,j2=[pbas count];i2<j2;i2++){
                PBEO *pba = [pbas oai:i2];
                NSString *pbadbn = [pba vfk:@"dbname"];
                for(i1=0;i1<ja;i1++){
                    NSString *an = [aivs oai:i1]; // attribute ivarname
                    NSString *aivdb = [aivsdb oai:i1]; // attribute ivarname db; lowercasestring
                    NSString *av = [pba vfk:aivdb]; // attribute value
                    if(FILLED(av)){
                        if([an iE:@"isDBS"] && [av iE:@"J"])continue; // Default
                        if([an iE:@"isVisibleS"] && [av iE:@"J"])continue; // Default
                        if([an iE:@"isDuplicateS"] && [av iE:@"J"])continue; // Default
                        if([an iE:@"isCombiSuchS"] && [av iE:@"N"])continue; // Default
                        if([an iE:@"isRootS"] && [av iE:@"N"])continue; // Default
                        if([an iE:@"isProtectedS"] && [av iE:@"N"])continue; // Default
                        if([an iE:@"isMandatoryS"] && [av iE:@"N"])continue; // Default
                        if([an iE:@"isDescriS"] && [av iE:@"N"])continue; // Default
                        if([an iE:@"alwaysOnS"] && [av iE:@"N"])continue; // Default
                        if([an iE:@"isHtmlS"] && [av iE:@"N"])continue; // Default
                        if([an iE:@"gruppenstring"] && [av iE:@"xxxxxxxxxx"])continue; // Default
                        [workstring appendString:tdbn];
                        [workstring appendString:@"\t"];
                        [workstring appendString:pbadbn];
                        [workstring appendString:@"\t"];
                        [workstring appendString:an];
                        [workstring appendString:@"\t"];
                        [workstring appendString:[av stringByEscapingCRTAB]];
                        [workstring appendString:@"\n"];
                    }
                }
            }
        }
        [pool release];
    }
    [mand WTF:midm];
    didDbToIDM = YES;
}
- (void)dbToTransdict;
{
// inhalt von translationsm sortiert ins .txt und .arc schreiben
// auch eigentliches Transdict neu versorgen
// manuell per Button, wenn man in Translationsmodul editiert hat
// vergisst man es, macht das nix, solange das .txt File nicht anderweitig geaendert wurde;
    NSArray *soa = [NSArray soaFrom:@"text0"];
    NSArray *a = getEOsQSoa(@"translationsm",nil,soa);
    NSMutableString *ms = [NSMutableString stringWithCapacity:100 * 1024];
    NSString *fn_txt = [NSSWF @"%@/translationsm.txt", MANDANTPATH];
    NSString *fn_arc = [NSSWF @"%@/translationsm.arc", MANDANTPATH];
    int i,j;
    [ms setString:@""];
    [transDict removeAllObjects];
    for(i=0,j=[a count];i<j;i++){
        PBEO *eo = [a oai:i];
        [eo encodeIntoString:ms];
        [transDict sofk([eo vfk:@"text1"],[eo vfk:@"text0"])];
    }
    [ms WTF:fn_txt];
    SYSTEM(@"sleep 1"); // archiv sollte neuer sein
    [NSArchiver archiveRootObject:a toFile:fn_arc];
}
- (void)encodeModuleEO:(PBEO *)eo intoString: (NSMutableString *)ms;
{
    NSString *propertyName, *propertyValue;
    NSArray *pNames = [[eo myTable] dbNamesDB];
    int i,j,v;
    for(i=0,j=[pNames count];i<j;i++){
        propertyName = [pNames oai:i];
        if([propertyName iE:@"cdate"])continue;
        if([propertyName iE:@"ldate"])continue;
        if([propertyName iE:@"cuser"])continue;
        if([propertyName iE:@"luser"])continue;
        if([propertyName iE:@"oldid"])continue;
        if([propertyName iE:@"pid"])continue;
        propertyValue = [[eo vfk:propertyName] stringByEscapingCRTAB];
        if(!FILLED(propertyValue))propertyValue=EON;
        if([propertyName hasSecurePrefix:@"gruppe"] && [propertyName length]==7)continue; // nur gruppenstring
        if([propertyName iE:@"classname"] && [propertyValue iE:@""])continue; // default
        if([propertyName iE:@"registerfielddbname"] && [propertyValue iE:@""])continue; // default
        if([propertyName iE:@"initialsearch_off"] && [propertyValue iE:@"N"])continue; // default
        if([propertyName iE:@"hidden"] && [propertyValue iE:@"N"])continue; // default
        if([propertyName iE:@"htmlwodname"] && [propertyValue iE:@""])continue; // default
        if([propertyName iE:@"needsnomastereo"] && [propertyValue iE:@"N"])continue; // default
        if([propertyName iE:@"off"] && [propertyValue iE:@"N"])continue; // default
        if([propertyName iE:@"pos"]){
            v = [propertyValue intValue];
            if(v == 0)continue; // default
        }
        if([propertyName iE:@"public"] && [propertyValue iE:@"N"])continue; // default
        if([propertyName iE:@"kuerzel"] && [propertyValue iE:@""])continue; // default
        if([propertyName iE:@"is_unter_menu"] && [propertyValue iE:@"N"])continue; // default
        if([propertyName iE:@"super_menu"] && (!FILLED(propertyValue) || ([propertyValue iE:@"System"] && ![[[eo values]ofk:@"is_unter_menu"]iE:@"J"])))continue; // default
        [ms appendString: [eo vfk:@"name"]];
        [ms appendString: @"\t"];
        [ms appendString: propertyName]; //propertyName
        [ms appendString: @"\t"];
        [ms appendString:propertyValue]; //propertyValue
        [ms appendString: @"\n"];
    }
}
- (void)encodeQueriesEO:(PBEO *)eo intoString: (NSMutableString *)ms;
{
    NSString *propertyName, *propertyValue;
    NSArray *pNames = [[eo myTable] dbNamesDB];
    int i,j;
    for(i=0,j=[pNames count];i<j;i++){
        propertyName = [pNames oai:i];
        if([propertyName iE:@"cdate"])continue;
        if([propertyName iE:@"ldate"])continue;
        if([propertyName iE:@"cuser"])continue;
        if([propertyName iE:@"luser"])continue;
        propertyValue = [[eo vfk:propertyName] stringByEscapingCRTAB];
        if(!FILLED(propertyValue))propertyValue=EON;
        if([propertyName iE:@"felder"] && [propertyValue iE:@""])continue; // default leer
        if([propertyName iE:@"gruppe"] && [propertyValue iE:@""])continue; // default leer
        if([propertyName iE:@"zwischensummen"] && [propertyValue iE:@"0"])continue; // default 0
        if([propertyName iE:@"listendruck"] && [propertyValue iE:@"N"])continue; // default N
        if([propertyName iE:@"nur_summen"] && [propertyValue iE:@"N"])continue; // default N
        if([propertyName iE:@"freies_sql"] && [propertyValue iE:@"N"])continue; // default N
        if([propertyName iE:@"parameter"] && [propertyValue iE:@""])continue; // default leer
        if([propertyName iE:@"zielmodul"] && [propertyValue iE:@""])continue; // default leer
        if([propertyName iE:@"sortierung"] && [propertyValue iE:@""])continue; // default leer
        if([propertyName iE:@"summen"] && [propertyValue iE:@""])continue; // default leer
        if([propertyName iE:@"where_cond"] && [propertyValue iE:@""])continue; // default leer
        [ms appendString: @"queries\t"];
        [ms appendString: [eo vfk:@"pid"]];
        [ms appendString: @"\t"];
        [ms appendString: propertyName]; //propertyName
        [ms appendString: @"\t"];
        [ms appendString:propertyValue]; //propertyValue
        [ms appendString: @"\n"];
    }
}
- (void)dbToModule;
{
// inhalt von module sortiert in module.txt schreiben
// manuell per Button, wenn man in Modulen editiert hat
// vergisst man es, macht das nix, solange das .txt File nicht anderweitig geaendert wurde;
// gibt nur noch mandanten-Module;
// Grund: auch std. module werden unterschiedlich einsortiert, benannt und berechtigt
    NSArray *soa = [NSArray soaFrom:@"name"];
    NSArray *a = getEOsQSoa(@"module",nil,soa);
    NSMutableString *ms_man = [NSMutableString stringWithCapacity:20 * 1024];
    NSString *fn = [NSSWF @"%@/module.txt",MANDANTPATH];
    int i,j;
    [ms_man setString:@""];
    for(i=0,j=[a count];i<j;i++){
        PBEO *eo = [a oai:i];
        [self encodeModuleEO:eo intoString:ms_man];
    }
    [ms_man WTF:fn];
}
- (void)dbToQueries;
{
// inhalt von queries sortiert in queries.txt schreiben
// manuell per Button, wenn man in Queries editiert hat
// vergisst man es, macht das nix, solange das .txt File nicht anderweitig geaendert wurde;
    NSArray *soa = [NSArray soaFrom:@"modul,name"];
    NSArray *a = getEOsQSoa(@"queries",nil,soa);
    NSMutableString *ms = [NSMutableString stringWithCapacity:20 * 1024];
    NSString *fn = [NSSWF @"%@/queries.txt",MANDANTPATH];
    int i,j;
    [ms setString:@""];
    for(i=0,j=[a count];i<j;i++){
        PBEO *eo = [a oai:i];
        [self encodeQueriesEO:eo intoString:ms];
    }
    [ms WTF:fn];
}
- (BOOL)backupPath:(NSString *)path;
{
    NSFileManager *fm = [NSFileManager defaultManager];
    NSString *bd = [path stringByAppendingString:@".bak"];
    if([fm fileExistsAtPath:bd]){
        if(![fm removeFileAtPath:bd handler:nil]){
            [NSException raise:NSGenericException format:@"Deleting old backup failed;"];
            return NO;
        }
    }
    if([fm fileExistsAtPath:path] && ![fm movePath:path toPath:bd handler:nil]){
        [NSException raise:NSGenericException format:@"Backup failed;"];
        return NO;
    }
    return YES;
}
- (BOOL)loadDD;
{
    BOOL rc = YES;
    NSString *fna = [NSSWF @"%@/mydd.archive",MANDANTPATH];
    //datadictionary; erforderlich
    LOG(@"loading Repository");
    [myDD release];
    myDD = nil;
    if([myFM fileExistsAtPath:fna]){
// es gibt ein archiv
// alle files pruefen, von denen das Archiv abhaengt: base.idm mandant.idm
// sind sie aelter, kann das archiv genommen werden
        NSDate *archivDate = [[myFM fileAttributesAtPath:fna traverseLink:NO] fileModificationDate];
        if(![self checkDependentFile:[MANDANTPATH stringByAppendingPathComponent:@"Mandant.idm"] date:archivDate])goto skipArchiv;
// alle dependencies aelter, archiv kann genommen werden:
        NS_DURING;
        myDD = [[NSUnarchiver unarchiveObjectWithFile:fna]retain];
        NS_HANDLER;
        myDD=nil;
        NS_ENDHANDLER;
        if(myDD){
            LOG(@"loaded Repository from Archive");
            return YES;
        }
// archiv hat sich nicht laden lassen oder dependencies sind neuer, daher loeschen und echtes modell laden
skipArchiv:
        [myFM removeFileAtPath:fna handler:nil];
    }
    if(![[self number]iE:@"1"]){
// Nur die Instanz 1 darf Archiv erstellen und DB versorgen; alle anderen Instanzen muessen mit dem Archiv arbeiten.
        LOG(@"Instanz > 1 konnte Archiv nicht laden.");
        return NO;
    }
    NS_DURING;
    LOG(@"loading Repository from IDM");
    myDD = [[PBDD alloc] initFromPath: MANDANTPATH];
// mal weglassen, damit es in DB geschrieben werden kann    [myDD shrink];
    NS_HANDLER;
    LOGS_Ex(EON);
    rc = NO;
    NS_ENDHANDLER;
    if(!(myDD) || !rc){
        LOGS((TRANSLATION(@"Repository  konnte nicht geladen werden.")));
        return NO;
    }
    //geladenes DD archivieren fuer schnellen start das naechste mal
    if(![myFM fileExistsAtPath:fna]){
        LOG(@"writing Archive");
        [NSArchiver archiveRootObject:myDD toFile:fna];
    }
// auch in DB schreiben; allerdings nicht, wenn IDM gerade aus der DB kam
    if(!didDbToIDM && !noModelToDB){
        LOG(@"writing Repository to DB");
        [self modelToDB]; // dauert 7 sec.
    }else{
        LOG(@"didDbToIDM or noModelToDB ==YES; NOT writing Repository to DB");
    }
    didDbToIDM = NO;
    return YES;
}
- (NSString *)readFileNamed:(NSString *)v;
{
    NSString	*s;
    
    //LOGI(v);
    s = [NSSWCOF v];
    if(!s){
        LOGS(([NSSWF @"konnte file %@ nicht laden.",v]));
        return nil;
    }
    return s;
}
- (NSString *)internalVersion;
{
    static NSString *s;
    if(!s){
        s = [[NSSWF @"5.1 V5 %s %s",__DATE__,__TIME__]retain];
    }
    return s;
}
- (NSString *)version;
{
    NSString *s = @"NAME_CHECKING     herauskompiliert (s. Aprica.h)";
#ifdef NAME_CHECKING
s = @"NAME_CHECKING    *** AKTIV *** (s. Aprica.h)";
#endif
    return [NSSWF @"\n\n V %@\n  http://www.seat-1.de\n  %@",[self internalVersion],s];
}
- (void)loadTransdicts;
{
// falls Archiv u. Archiv neuer als .txt, Archiv laden; sonst .txt laden, in DB schreiben und Archivieren;
// auf jeden Fall transDict fuellen
// nach Editieren in DB, DBtoTxt aufrufen;
    NSString *fn_txt, *fn_arc;
    NSDate *fd_txt = nil, *fd_arc = nil;
    NSArray *a = nil;
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    int i,j;
    [transDict removeAllObjects];
    fn_txt = [NSSWF @"%@/translationsm.txt", MANDANTPATH];
    fn_arc = [NSSWF @"%@/translationsm.arc", MANDANTPATH];
    if([myFM fileExistsAtPath: fn_txt]) fd_txt = [[myFM fileAttributesAtPath:fn_txt traverseLink:NO] fileModificationDate];
    if([myFM fileExistsAtPath: fn_arc]) fd_arc = [[myFM fileAttributesAtPath:fn_arc traverseLink:NO] fileModificationDate];
    if(fd_txt && fd_arc && [fd_txt compare:fd_arc] == NSOrderedAscending){
// Archiv vorhanden und neuer
        LOG(@"loading TransDict from Archiv");
        NS_DURING;
        a = [NSUnarchiver unarchiveObjectWithFile: fn_arc];
        NS_HANDLER;
// hat nicht geklappt
        [myFM removeFileAtPath:fn_arc handler:nil];
        LOG(@"loading TransDict from Archiv failed");
        a = nil;
        NS_ENDHANDLER;
        if(a){
            for(i=0,j=[a count];i<j;i++) {
                PBEO *eo = [a oai: i];
                [transDict sofk([eo vfk:@"text1"],[eo vfk:@"text0"])];
            }
            [pool release];
            LOGS(([NSSWF @"%i entries in transDict",[transDict count]]));
            return;
        }
    }
    LOG(@"loading TransDict from .txt");
    a = [PBEO eosFromString:[NSSWCOF fn_txt]];
    if([a count]){
        SQL(@"delete from translationsm;");
        for(i=0,j=[a count];i<j;i++) {
            PBEO *eo = [a oai: i];
            [transDict sofk([eo vfk:@"text1"],[eo vfk:@"text0"])];
// noch in DB stellen
            INSRT(eo);
        }
        [NSArchiver archiveRootObject:a toFile:fn_arc];
    }
    [pool release];
    return;
}
- (NSString *)iconForMimetype:(NSString *)mt;
{
    static NSDictionary *d;
    NSString *s1;
    if(!d){
        d = [NSDictionary dictionaryWithObjectsAndKeys:
            @"ext_doc.gif",@"application/msword",
            @"ext_rtf.gif",@"text/rtf",
            @"ext_txt.gif",@"text/plain",
            @"ext_html.gif",@"text/html",
            @"ext_tif.gif",@"image/tiff",
            @"ext_jpg.gif",@"image/jpeg",
            @"ext_wav.gif",@"audio/x-wav",
            @"ext_mpeg.gif",@"video/mpeg",
            @"ext_png.gif",@"image/png",
            @"ext_bmp.gif",@"image/bmp",
            @"ext_gif.gif",@"image/gif",
            @"ext_zip.gif",@"application/zip",
            @"ext_ps.gif",@"application/postscript",
            @"ext_pdf.gif",@"application/pdf",
            @"ext_eml.gif",@"message/rfc822",
            @"ext_csv.gif",@"application/vnd.ms-excel",
            nil,nil];
        [d retain];
    }
    if(!(s1=[d ofk:mt])){
        s1 = @"1a.gif";
    }
    return [NSSWF @"/Aprica2_%@/Images/%@",mandant,s1];
}
- (NSString *)mimetypeForExtension:(NSString *)ext;
{
    static NSDictionary *d;
    NSString *s1;
    if(!d){
        d = [NSDictionary dictionaryWithObjectsAndKeys:
            @"application/msword",@"doc",
            @"text/rtf",@"rtf",
            @"text/plain",@"txt",
            @"text/html",@"html",
            @"text/html",@"htm",
            @"image/tiff",@"tiff",
            @"image/tiff",@"tif",
            @"image/jpeg",@"jpeg",
            @"image/jpeg",@"jpg",
            @"audio/x-wav",@"wav",
            @"video/mpeg",@"mpeg",
            @"image/png",@"png",
            @"image/bmp",@"bmp",
            @"image/gif",@"gif",
            @"application/zip",@"zip",
            @"application/zip",@"gzip",
            @"application/zip",@"gz",
            @"application/postscript",@"ps",
            @"application/pdf",@"pdf",
            @"application/vnd.ms-excel",@"csv",
            nil,nil];
        [d retain];
    }
    if(!(s1=[d ofk:ext])){
        s1 = @"text/plain";
    }
    return s1;
}
- (NSString *)tempName;
{
    NSString *s = [NSSWF @"%010.0f",[[NSDate date]timeIntervalSince1970]*1000];
    return s;
}
- (WOResponse *)handlePageRestorationErrorInContext:(WOContext *)aContext;
{
    return [[self pageWithName:@"WOPageRestorationErrorPage" inContext:aContext]generateResponse];
}
- (WOResponse *)handleSessionRestorationErrorInContext: (WOContext *)aContext
{
    return [[self pageWithName:@"WOSessionRestorationErrorPage" inContext:aContext]generateResponse];
}
- (WOResponse *)handleException:(NSException *)anException inContext:(WOContext *)aContext;
{
    PBWOEditor *e=nil;
    e=MODUL(@"Home");
    return [e generateResponse];
}
- (PBDDTable *)tableNamed:(NSString *)value;
{
    return [myDD tableNamed:value];
}
- (void)determineMimeTyp:(PBEO *)eo url:(NSString *)url;
{
    NSString *ext = [[url pathExtension]lowercaseString];
    NSString *mt = [mimeTypes ofk:ext];
    if(!mt)mt = @"text/plain";
    [eo tvfk(mt,@"mimetype")];
}
- (NSDictionary *)mimeTypes;
{
    return mimeTypes;
}
- (BOOL)isValidKtonr:(NSString *)ktonr forBLZ:(NSString *)blz;
{
    if(fast_start){
        return YES;
    }else{
        int ret;
        char k[64];
        memset(k,0,sizeof(k));
        [ktonr getCString:k maxLength: sizeof(k)-1];
        ret = kto_check([blz lossyCString],k,[[NSSWF @"%@/blz.lut",GLOBALCONFIGPATH]lossyCString]);
        return (ret==OK || ret==OK_NO_CHK);
    }
}
- (NSArray *)instituteFuerBlz4:(NSString *)blz;
{
    if(![blzDict count])return nil;
    if(!FILLED(blz))return nil;
    return [blzDict ofk:blz];
}
- (BOOL)isValidInstitut:(NSString *)institut forBlz:(NSString *)blz;
{
    NSString *s;
    NSArray *a;
    int i,j;
    s = [institut lowercaseString];
    if(!FILLED(s) || !FILLED(blz))return NO;
    if(![blzDict count])return YES;
    a =  [self instituteFuerBlz4:blz];
    if(!a)return NO;
    for(i=0,j=[a count];i<j;i++){
        if([s iE:[[[a oai:i] institut]lowercaseString]])return YES;
    }
    return NO;
}
- (NSString *)institutFuerBlz4:(NSString *)blz;
{
    if(fast_start){
        return @"Schnellstart-Bank";
    }else{
        NSArray *a = [self instituteFuerBlz4:blz];
        BLZRecord *blzr;
        if(!a)return EON;
        blzr = [a firstObject];
        return [blzr institut];
    }
}
- (NSArray *)blzForInstitut4:(NSString *)institut;
{
//returned gefundene BLZRecords; max. 100
//institut freie Eingabe;
    if(fast_start){
        return [NSArray array];
    }else{
        NSString *s;
        NSArray *a = [institut componentsSeparatedByString:@" "];
        LMA;
        LMAN(begriffe);
        int i,j,ii,jj,count=0;
        if(!FILLED(institut))return nil;
        for(i=0,j=[a count];i<j;i++){ //Begriffe
            s = [[a oai:i] simplyfiedString];
            if(!FILLED(s))continue;
            [begriffe addObject:s];
        }
        for(ii=0,jj=[blz4Array count];ii<jj && count<100;ii++){
            BLZRecord *blzr=[blz4Array oai:ii];
            for(i=0,j=[begriffe count];i<j;i++){ //Begriffe
                s = [begriffe oai:i];
                if(![blzr matches:s])goto nextBLZRecord;
            }
            [lma addObject:blzr];
            count++;
nextBLZRecord:
                ;
        }
        return lma;
    }
}
- (void)readBlz5;
{
// neu 28.10.03 array der Filialen unter der BLZ halten
// neu: originalformat der Bundesbank verwenden
    NSAutoreleasePool *pool=nil,*pool1=nil;
    NSString	*fn,*s;
    NSArray *a;
    int i,j;
    LOG(@"loading BLZ");
    [blzDict removeAllObjects];
    [blz4Array removeAllObjects];
    fn=[NSSWF @"%@/blz5.txt",GLOBALCONFIGPATH];
    pool1 = [[NSAutoreleasePool alloc]init];
    s = [NSSWCOF fn];
    if(!FILLED(s)){
        LOGS(([NSSWF @"keine %@.\n",fn]));
        [pool1 release];
        return;
    }
    a = [s componentsSeparatedByString:@"\n"];
    j = [a count];
    LOGS(([NSSWF @"%i Saetze in %@",j,fn]));
    for(i=0;i<j;i++){
        BLZRecord *blzr;
        NSMutableArray *ma;
        NSString *blz;
        if(!(i%200)){
            [pool release];
            pool = [[NSAutoreleasePool alloc]init];
        }
        s = [a oai:i];
        blzr = [[BLZRecord alloc]initWithBLZ5row:s];
        if(!blzr)continue;
        blz = NSS([blzr blz]);
        ma =[blzDict ofk:blz];
        if(!ma){
            ma = [NSMutableArray arrayWithCapacity:10];
            [blzDict setObject:ma forKey:blz];
        }
        if([ma indexOfObject:blzr]==NSNotFound){
            [ma addObject:blzr];
            [blz4Array addObject:blzr];
        }
        [blzr release];
    }
    [pool release];
    [pool1 release];
}
- (BOOL)ConfirmChecksum:(NSString *) CardNumber; /*"Pruefsummenberechnung f. Kreditkartennr"*/
{
// von Delphi portiert, daher die namen...
    int CheckSum; // Holds the value of the operation
    BOOL Flag; // used to indicate when ready
    int Counter; // index counter
    NSString *PartNumber; // used to extract each digit ofnumber
    int Number; // used to convert each digit to integer
    
      // get the starting value for our counter 
    Counter = [CardNumber length];
    CheckSum = 0;
    PartNumber = EON;
    Number = 0;
    Flag = NO;
    while ( Counter >= 1 ) {
         // get the current digit 
        PartNumber =  [[CardNumber substringFromIndex:Counter-1]substringToIndex:1];
        Number = [PartNumber intValue]; // convert to integer 
        if( Flag ) { // only do every other digit 
            Number = Number * 2;
            if( Number >= 10 ) {
                Number = Number - 9;
            }
        }
        CheckSum = CheckSum + Number;
        Flag = !Flag;
        Counter = Counter - 1;
    }
    return ( ( CheckSum % 10 ) == 0 );
}
- (NSString *)CCVal:(NSString *)CardNumber :(NSString *)CardName;
{
//wenn ok, returned nil
//sonst fehlermeldung
// CardName kann sein:
// @"Master-/Eurocard"
// @"Visa"
// @"American Express"
// @"Diners"
//von Delphi portiert, daher die Namen...
    NSString *StrippedNumber;        // used to hold the number bereft of extra chars 
    NSString *TeilNumber;
    NSString *fullCardName=EON,*cnup;
    int i,snl,i1;
    if(!FILLED(CardName)) return @"Kartenname nicht gefuellt";
    if([CardName iE:@"-"])return nil; //nicht pruefen
    
   // first, get rid of spaces, dashes  etc
    StrippedNumber = [CardNumber onlyDigits];
    snl = [StrippedNumber length];
    cnup = CardName;
//    LOG(StrippedNumber);
    
//restliche Kartnarten mind. 4
    if([StrippedNumber length]<4){
        return @"Kartennr. zu kurz.";
    }
    TeilNumber = [StrippedNumber substringToIndex:4];
    i1 = [TeilNumber intValue];
    i = [[TeilNumber  substringToIndex:2]intValue];
    if([cnup iE:  @"Master-/Eurocard"]) {
        fullCardName = @"Master-/Eurocard-Kartennummer";
        if(snl  != 16 ){
            return [NSSWF @"%@ soll 16-stellig sein!",fullCardName];
        } 
        if(i<51 || i > 55){
            return [NSSWF @"%@ ungueltig!",fullCardName];
        }
    }else if([cnup iE:@"Visa"]) {
        fullCardName = @"Visa-Kartennummer";
        if((snl != 13 ) && snl != 16) {
            return [NSSWF @"%@ soll 13- oder 16-stellig sein!",fullCardName];
        }
    }else if([cnup iE:@"American Express"]) {
        fullCardName = @"American Express-Kartennummer";
        if(snl != 15 ) {
            return [NSSWF @"%@ soll 15-stellig sein!",fullCardName];
        }
        if(i!=34 && i!=37){
            return [NSSWF @"%@ ungueltig!",fullCardName];
        }
    }else if([cnup iE:@"Diners"]) {
        fullCardName = @"Diners Club-Kartennummer";
        if(snl != 14 ) {
            return [NSSWF @"%@ soll 14-stellig sein!",fullCardName];
        }
        if(!((i>=30 && i<=35) || i==36 || i==38)){
            return [NSSWF @"%@ ungueltig!",fullCardName];
        }  
    }else{
        return @"unbekannte Kartenart";
    }
    if(![self ConfirmChecksum:StrippedNumber]) {
        return [NSSWF @"%@ ungueltig!",fullCardName];
    }
    return nil;
}
#ifdef GNUSTEP
- (void)debugAdaptorThreadExited
{
    if (debugAllocation) {
        NSAutoreleasePool *pool = [NSAutoreleasePool new];
	LOGS(([NSSWF @"DebugAllocation\n%s",GSDebugAllocationList(YES)]));
	[pool release];
    }
}
#endif
- (NSString *)thumbCmd;
{
#ifdef GNUSTEP
    return [configDict ofk:@"thumbcmd"];
#else
    return [configDict ofk:@"thumbcmdw"];
#endif
}
- (int)system:(NSString *)sys;
{
    if(log_changes)LOG(sys);
    return system([sys lossyCString]);
}
- (SEL)secureSelectorFromString:(NSString *)s;
{
    SEL sel;
    NS_DURING;
// WO versucht den string in die Locale der Host-Maschine zu konvertieren, z.B. WinLatin1;
// klappt das nicht, wird eine exception geworfen;
    sel = NSSelectorFromString(s);
    NS_HANDLER;
    sel = 0;
    NS_ENDHANDLER;
    return sel;
}
- (void)log:(NSString *)s;
{
    NSString *s1 = [NSSWF @"%@ %@ %@\n",[[NSCalendarDate date]descriptionWithCalendarFormat:ND_GUIDT_FORMAT],CURRENTUSER,s];
#ifdef WIN32
    [logfh writeData:[s1 dataUsingEncoding:(utf8?NSUTF8StringEncoding:NSWindowsCP1252StringEncoding)]];
#else
    NSLog(([[s1 componentsSeparatedByString:@"%"]componentsJoinedByString:@"%%"]));
#endif
}
- (void)createCodePage858Map;
{
    NSMapTable *map;
    codePage858Map = NSCreateMapTable(NSIntMapKeyCallBacks, NSIntMapValueCallBacks, 256);
    map = codePage858Map;
    NSMapInsert(map, (void *)0x0000, (void *)0x00);
    NSMapInsert(map, (void *)0x263A, (void *)0x01);
    NSMapInsert(map, (void *)0x263B, (void *)0x02);
    NSMapInsert(map, (void *)0x2665, (void *)0x03);
    NSMapInsert(map, (void *)0x2666, (void *)0x04);
    NSMapInsert(map, (void *)0x2663, (void *)0x05);
    NSMapInsert(map, (void *)0x2660, (void *)0x06);
    NSMapInsert(map, (void *)0x2022, (void *)0x07);
    NSMapInsert(map, (void *)0x25D8, (void *)0x08);
    NSMapInsert(map, (void *)0x25CB, (void *)0x09);
    NSMapInsert(map, (void *)0x25D9, (void *)0x0A);
    NSMapInsert(map, (void *)0x2642, (void *)0x0B);
    NSMapInsert(map, (void *)0x2640, (void *)0x0C);
    NSMapInsert(map, (void *)0x266A, (void *)0x0D);
    NSMapInsert(map, (void *)0x266B, (void *)0x0E);
    NSMapInsert(map, (void *)0x263C, (void *)0x0F);
    NSMapInsert(map, (void *)0x25BA, (void *)0x10);
    NSMapInsert(map, (void *)0x25C4, (void *)0x11);
    NSMapInsert(map, (void *)0x2195, (void *)0x12);
    NSMapInsert(map, (void *)0x203C, (void *)0x13);
    NSMapInsert(map, (void *)0x00B6, (void *)0x14);
    NSMapInsert(map, (void *)0x00A7, (void *)0x15);
    NSMapInsert(map, (void *)0x25AC, (void *)0x16);
    NSMapInsert(map, (void *)0x21A8, (void *)0x17);
    NSMapInsert(map, (void *)0x2191, (void *)0x18);
    NSMapInsert(map, (void *)0x2193, (void *)0x19);
    NSMapInsert(map, (void *)0x2192, (void *)0x1A);
    NSMapInsert(map, (void *)0x2190, (void *)0x1B);
    NSMapInsert(map, (void *)0x221F, (void *)0x1C);
    NSMapInsert(map, (void *)0x2194, (void *)0x1D);
    NSMapInsert(map, (void *)0x25B2, (void *)0x1E);
    NSMapInsert(map, (void *)0x25BC, (void *)0x1F);
    NSMapInsert(map, (void *)0x0020, (void *)0x20);
    NSMapInsert(map, (void *)0x0021, (void *)0x21);
    NSMapInsert(map, (void *)0x0022, (void *)0x22);
    NSMapInsert(map, (void *)0x0023, (void *)0x23);
    NSMapInsert(map, (void *)0x0024, (void *)0x24);
    NSMapInsert(map, (void *)0x0025, (void *)0x25);
    NSMapInsert(map, (void *)0x0026, (void *)0x26);
    NSMapInsert(map, (void *)0x0027, (void *)0x27);
    NSMapInsert(map, (void *)0x0028, (void *)0x28);
    NSMapInsert(map, (void *)0x0029, (void *)0x29);
    NSMapInsert(map, (void *)0x002A, (void *)0x2A);
    NSMapInsert(map, (void *)0x002B, (void *)0x2B);
    NSMapInsert(map, (void *)0x002C, (void *)0x2C);
    NSMapInsert(map, (void *)0x002D, (void *)0x2D);
    NSMapInsert(map, (void *)0x002E, (void *)0x2E);
    NSMapInsert(map, (void *)0x002F, (void *)0x2F);
    NSMapInsert(map, (void *)0x0030, (void *)0x30);
    NSMapInsert(map, (void *)0x0031, (void *)0x31);
    NSMapInsert(map, (void *)0x0032, (void *)0x32);
    NSMapInsert(map, (void *)0x0033, (void *)0x33);
    NSMapInsert(map, (void *)0x0034, (void *)0x34);
    NSMapInsert(map, (void *)0x0035, (void *)0x35);
    NSMapInsert(map, (void *)0x0036, (void *)0x36);
    NSMapInsert(map, (void *)0x0037, (void *)0x37);
    NSMapInsert(map, (void *)0x0038, (void *)0x38);
    NSMapInsert(map, (void *)0x0039, (void *)0x39);
    NSMapInsert(map, (void *)0x003A, (void *)0x3A);
    NSMapInsert(map, (void *)0x003B, (void *)0x3B);
    NSMapInsert(map, (void *)0x003C, (void *)0x3C);
    NSMapInsert(map, (void *)0x003D, (void *)0x3D);
    NSMapInsert(map, (void *)0x003E, (void *)0x3E);
    NSMapInsert(map, (void *)0x003F, (void *)0x3F);
    NSMapInsert(map, (void *)0x0040, (void *)0x40);
    NSMapInsert(map, (void *)0x0041, (void *)0x41);
    NSMapInsert(map, (void *)0x0042, (void *)0x42);
    NSMapInsert(map, (void *)0x0043, (void *)0x43);
    NSMapInsert(map, (void *)0x0044, (void *)0x44);
    NSMapInsert(map, (void *)0x0045, (void *)0x45);
    NSMapInsert(map, (void *)0x0046, (void *)0x46);
    NSMapInsert(map, (void *)0x0047, (void *)0x47);
    NSMapInsert(map, (void *)0x0048, (void *)0x48);
    NSMapInsert(map, (void *)0x0049, (void *)0x49);
    NSMapInsert(map, (void *)0x004A, (void *)0x4A);
    NSMapInsert(map, (void *)0x004B, (void *)0x4B);
    NSMapInsert(map, (void *)0x004C, (void *)0x4C);
    NSMapInsert(map, (void *)0x004D, (void *)0x4D);
    NSMapInsert(map, (void *)0x004E, (void *)0x4E);
    NSMapInsert(map, (void *)0x004F, (void *)0x4F);
    NSMapInsert(map, (void *)0x0050, (void *)0x50);
    NSMapInsert(map, (void *)0x0051, (void *)0x51);
    NSMapInsert(map, (void *)0x0052, (void *)0x52);
    NSMapInsert(map, (void *)0x0053, (void *)0x53);
    NSMapInsert(map, (void *)0x0054, (void *)0x54);
    NSMapInsert(map, (void *)0x0055, (void *)0x55);
    NSMapInsert(map, (void *)0x0056, (void *)0x56);
    NSMapInsert(map, (void *)0x0057, (void *)0x57);
    NSMapInsert(map, (void *)0x0058, (void *)0x58);
    NSMapInsert(map, (void *)0x0059, (void *)0x59);
    NSMapInsert(map, (void *)0x005A, (void *)0x5A);
    NSMapInsert(map, (void *)0x005B, (void *)0x5B);
    NSMapInsert(map, (void *)0x005C, (void *)0x5C);
    NSMapInsert(map, (void *)0x005D, (void *)0x5D);
    NSMapInsert(map, (void *)0x005E, (void *)0x5E);
    NSMapInsert(map, (void *)0x005F, (void *)0x5F);
    NSMapInsert(map, (void *)0x0060, (void *)0x60);
    NSMapInsert(map, (void *)0x0061, (void *)0x61);
    NSMapInsert(map, (void *)0x0062, (void *)0x62);
    NSMapInsert(map, (void *)0x0063, (void *)0x63);
    NSMapInsert(map, (void *)0x0064, (void *)0x64);
    NSMapInsert(map, (void *)0x0065, (void *)0x65);
    NSMapInsert(map, (void *)0x0066, (void *)0x66);
    NSMapInsert(map, (void *)0x0067, (void *)0x67);
    NSMapInsert(map, (void *)0x0068, (void *)0x68);
    NSMapInsert(map, (void *)0x0069, (void *)0x69);
    NSMapInsert(map, (void *)0x006A, (void *)0x6A);
    NSMapInsert(map, (void *)0x006B, (void *)0x6B);
    NSMapInsert(map, (void *)0x006C, (void *)0x6C);
    NSMapInsert(map, (void *)0x006D, (void *)0x6D);
    NSMapInsert(map, (void *)0x006E, (void *)0x6E);
    NSMapInsert(map, (void *)0x006F, (void *)0x6F);
    NSMapInsert(map, (void *)0x0070, (void *)0x70);
    NSMapInsert(map, (void *)0x0071, (void *)0x71);
    NSMapInsert(map, (void *)0x0072, (void *)0x72);
    NSMapInsert(map, (void *)0x0073, (void *)0x73);
    NSMapInsert(map, (void *)0x0074, (void *)0x74);
    NSMapInsert(map, (void *)0x0075, (void *)0x75);
    NSMapInsert(map, (void *)0x0076, (void *)0x76);
    NSMapInsert(map, (void *)0x0077, (void *)0x77);
    NSMapInsert(map, (void *)0x0078, (void *)0x78);
    NSMapInsert(map, (void *)0x0079, (void *)0x79);
    NSMapInsert(map, (void *)0x007A, (void *)0x7A);
    NSMapInsert(map, (void *)0x007B, (void *)0x7B);
    NSMapInsert(map, (void *)0x007C, (void *)0x7C);
    NSMapInsert(map, (void *)0x007D, (void *)0x7D);
    NSMapInsert(map, (void *)0x007E, (void *)0x7E);
    NSMapInsert(map, (void *)0x2302, (void *)0x7F);
    NSMapInsert(map, (void *)0x00C7, (void *)0x80);
    NSMapInsert(map, (void *)0x00FC, (void *)0x81);
    NSMapInsert(map, (void *)0x00E9, (void *)0x82);
    NSMapInsert(map, (void *)0x00E2, (void *)0x83);
    NSMapInsert(map, (void *)0x00E4, (void *)0x84);
    NSMapInsert(map, (void *)0x00E0, (void *)0x85);
    NSMapInsert(map, (void *)0x00E5, (void *)0x86);
    NSMapInsert(map, (void *)0x00E7, (void *)0x87);
    NSMapInsert(map, (void *)0x00EA, (void *)0x88);
    NSMapInsert(map, (void *)0x00EB, (void *)0x89);
    NSMapInsert(map, (void *)0x00E8, (void *)0x8A);
    NSMapInsert(map, (void *)0x00EF, (void *)0x8B);
    NSMapInsert(map, (void *)0x00EE, (void *)0x8C);
    NSMapInsert(map, (void *)0x00EC, (void *)0x8D);
    NSMapInsert(map, (void *)0x00C4, (void *)0x8E);
    NSMapInsert(map, (void *)0x00C5, (void *)0x8F);
    NSMapInsert(map, (void *)0x00C9, (void *)0x90);
    NSMapInsert(map, (void *)0x00E6, (void *)0x91);
    NSMapInsert(map, (void *)0x00C6, (void *)0x92);
    NSMapInsert(map, (void *)0x00F4, (void *)0x93);
    NSMapInsert(map, (void *)0x00F6, (void *)0x94);
    NSMapInsert(map, (void *)0x00F2, (void *)0x95);
    NSMapInsert(map, (void *)0x00FB, (void *)0x96);
    NSMapInsert(map, (void *)0x00F9, (void *)0x97);
    NSMapInsert(map, (void *)0x00FF, (void *)0x98);
    NSMapInsert(map, (void *)0x00D6, (void *)0x99);
    NSMapInsert(map, (void *)0x00DC, (void *)0x9A);
    NSMapInsert(map, (void *)0x00F8, (void *)0x9B);
    NSMapInsert(map, (void *)0x00A3, (void *)0x9C);
    NSMapInsert(map, (void *)0x00D8, (void *)0x9D);
    NSMapInsert(map, (void *)0x00D7, (void *)0x9E);
    NSMapInsert(map, (void *)0x0192, (void *)0x9F);
    NSMapInsert(map, (void *)0x00E1, (void *)0xA0);
    NSMapInsert(map, (void *)0x00ED, (void *)0xA1);
    NSMapInsert(map, (void *)0x00F3, (void *)0xA2);
    NSMapInsert(map, (void *)0x00FA, (void *)0xA3);
    NSMapInsert(map, (void *)0x00F1, (void *)0xA4);
    NSMapInsert(map, (void *)0x00D1, (void *)0xA5);
    NSMapInsert(map, (void *)0x00AA, (void *)0xA6);
    NSMapInsert(map, (void *)0x00BA, (void *)0xA7);
    NSMapInsert(map, (void *)0x00BF, (void *)0xA8);
    NSMapInsert(map, (void *)0x00AE, (void *)0xA9);
    NSMapInsert(map, (void *)0x00AC, (void *)0xAA);
    NSMapInsert(map, (void *)0x00BD, (void *)0xAB);
    NSMapInsert(map, (void *)0x00BC, (void *)0xAC);
    NSMapInsert(map, (void *)0x00A1, (void *)0xAD);
    NSMapInsert(map, (void *)0x00AB, (void *)0xAE);
    NSMapInsert(map, (void *)0x00BB, (void *)0xAF);
    NSMapInsert(map, (void *)0x2591, (void *)0xB0);
    NSMapInsert(map, (void *)0x2592, (void *)0xB1);
    NSMapInsert(map, (void *)0x2593, (void *)0xB2);
    NSMapInsert(map, (void *)0x2502, (void *)0xB3);
    NSMapInsert(map, (void *)0x2524, (void *)0xB4);
    NSMapInsert(map, (void *)0x00C1, (void *)0xB5);
    NSMapInsert(map, (void *)0x00C2, (void *)0xB6);
    NSMapInsert(map, (void *)0x00C0, (void *)0xB7);
    NSMapInsert(map, (void *)0x00A9, (void *)0xB8);
    NSMapInsert(map, (void *)0x2563, (void *)0xB9);
    NSMapInsert(map, (void *)0x2551, (void *)0xBA);
    NSMapInsert(map, (void *)0x2557, (void *)0xBB);
    NSMapInsert(map, (void *)0x255D, (void *)0xBC);
    NSMapInsert(map, (void *)0x00A2, (void *)0xBD);
    NSMapInsert(map, (void *)0x00A5, (void *)0xBE);
    NSMapInsert(map, (void *)0x2510, (void *)0xBF);
    NSMapInsert(map, (void *)0x2514, (void *)0xC0);
    NSMapInsert(map, (void *)0x2534, (void *)0xC1);
    NSMapInsert(map, (void *)0x252C, (void *)0xC2);
    NSMapInsert(map, (void *)0x251C, (void *)0xC3);
    NSMapInsert(map, (void *)0x2500, (void *)0xC4);
    NSMapInsert(map, (void *)0x253C, (void *)0xC5);
    NSMapInsert(map, (void *)0x00E3, (void *)0xC6);
    NSMapInsert(map, (void *)0x00C3, (void *)0xC7);
    NSMapInsert(map, (void *)0x255A, (void *)0xC8);
    NSMapInsert(map, (void *)0x2554, (void *)0xC9);
    NSMapInsert(map, (void *)0x2569, (void *)0xCA);
    NSMapInsert(map, (void *)0x2566, (void *)0xCB);
    NSMapInsert(map, (void *)0x2560, (void *)0xCC);
    NSMapInsert(map, (void *)0x2550, (void *)0xCD);
    NSMapInsert(map, (void *)0x256C, (void *)0xCE);
    NSMapInsert(map, (void *)0x00A4, (void *)0xCF);
    NSMapInsert(map, (void *)0x00F0, (void *)0xD0);
    NSMapInsert(map, (void *)0x00D0, (void *)0xD1);
    NSMapInsert(map, (void *)0x00CA, (void *)0xD2);
    NSMapInsert(map, (void *)0x00CB, (void *)0xD3);
    NSMapInsert(map, (void *)0x00C8, (void *)0xD4);
    NSMapInsert(map, (void *)0x20AC, (void *)0xD5);
    NSMapInsert(map, (void *)0x00CD, (void *)0xD6);
    NSMapInsert(map, (void *)0x00CE, (void *)0xD7);
    NSMapInsert(map, (void *)0x00CF, (void *)0xD8);
    NSMapInsert(map, (void *)0x2518, (void *)0xD9);
    NSMapInsert(map, (void *)0x250C, (void *)0xDA);
    NSMapInsert(map, (void *)0x2588, (void *)0xDB);
    NSMapInsert(map, (void *)0x2584, (void *)0xDC);
    NSMapInsert(map, (void *)0x00A6, (void *)0xDD);
    NSMapInsert(map, (void *)0x00CC, (void *)0xDE);
    NSMapInsert(map, (void *)0x2580, (void *)0xDF);
    NSMapInsert(map, (void *)0x00D3, (void *)0xE0);
    NSMapInsert(map, (void *)0x00DF, (void *)0xE1);
    NSMapInsert(map, (void *)0x00D4, (void *)0xE2);
    NSMapInsert(map, (void *)0x00D2, (void *)0xE3);
    NSMapInsert(map, (void *)0x00F5, (void *)0xE4);
    NSMapInsert(map, (void *)0x00D5, (void *)0xE5);
    NSMapInsert(map, (void *)0x00B5, (void *)0xE6);
    NSMapInsert(map, (void *)0x00FE, (void *)0xE7);
    NSMapInsert(map, (void *)0x00DE, (void *)0xE8);
    NSMapInsert(map, (void *)0x00DA, (void *)0xE9);
    NSMapInsert(map, (void *)0x00DB, (void *)0xEA);
    NSMapInsert(map, (void *)0x00D9, (void *)0xEB);
    NSMapInsert(map, (void *)0x00FD, (void *)0xEC);
    NSMapInsert(map, (void *)0x00DD, (void *)0xED);
    NSMapInsert(map, (void *)0x00AF, (void *)0xEE);
    NSMapInsert(map, (void *)0x00B4, (void *)0xEF);
    NSMapInsert(map, (void *)0x00AD, (void *)0xF0);
    NSMapInsert(map, (void *)0x00B1, (void *)0xF1);
    NSMapInsert(map, (void *)0x2017, (void *)0xF2);
    NSMapInsert(map, (void *)0x00BE, (void *)0xF3);
    NSMapInsert(map, (void *)0x00B6, (void *)0xF4);
    NSMapInsert(map, (void *)0x00A7, (void *)0xF5);
    NSMapInsert(map, (void *)0x00F7, (void *)0xF6);
    NSMapInsert(map, (void *)0x00B8, (void *)0xF7);
    NSMapInsert(map, (void *)0x00B0, (void *)0xF8);
    NSMapInsert(map, (void *)0x00A8, (void *)0xF9);
    NSMapInsert(map, (void *)0x00B7, (void *)0xFA);
    NSMapInsert(map, (void *)0x00B9, (void *)0xFB);
    NSMapInsert(map, (void *)0x00B3, (void *)0xFC);
    NSMapInsert(map, (void *)0x00B2, (void *)0xFD);
    NSMapInsert(map, (void *)0x25A0, (void *)0xFE);
    NSMapInsert(map, (void *)0x00A0, (void *)0xFF);
}
- (NSMapTable *)codePage858Map;
{
    return codePage858Map;
}
@end
Foto