{ 
    SemTel version 1.0.0 ... comfortable telnet client
    Copyright (C) 1995-2000 Jan Tomasek <jan@tomasek.cz>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
}
{-------------------------------------------------------------------------------
Version  : 0.885
Date     : 10.08.1998
Dialog   : none
History  :
 function LoadList should be obsolete !!!
 21.05.1998 Pridano lokalni echo, radkovy rezim
 07.07.1998 Ukladani/nahravani barev lokalniho echa
 21.07.1998 Přidán dialog SelectIP
 22.07.1998 Umožněno spojení podle příkazové řádky
 10.08.1998 Konecne vyresen main form.
TODO     :
 * Zjistit zda je fOpenANSI visible
 * Pri nacitani konfigurace overovat zda je pozadovana kodovaci tabulka dostupna
-------------------------------------------------------------------------------}

unit STConfig;

interface
Uses
  SysUtils, Graphics, INIFiles, Classes,
  Dialogs,  Forms,    StdCtrls, xFTPSrv,
  WinTypes, kUnits;

Type {data}
  TCFGPages = (cpConnection, cpCharset, cpSecurity, cpSecuritySSL, cpConsole,
               cpConsoleWindow, cpConsoleColors, cpUserAcounts, cpFTP,
               cpPrinters);
  TDialogType = (_fOTPCalc,_fOpenANSI,_fEnterOneLineDlg,_fSelectConnection,
                 _fPrinterSetupDialog,_fConnectionParameters,_fEditHotKey,
                 _fSelectIP,_fPGPPublicKey, _fRegister, _fOrder, _fQuickConnect,
                 _fNetworkPrinterInDirectModeSelect);
  TResizeMode = (rmDimensionChange,rmFontSizeChange,rmNoChange);
  TLineDNames = (ldLeftTop,ldLeftBottom,ldHorizDivBotom,ldHorizDivTop,ldHorizontal,
                 ldVertical,ldRightTop,ldRightBottom,ldVertDivRight,ldVertDivLeft,ldCross);

  {********************************************************************}
  TdConnection = record
    _Enabled             : Boolean;
    Host                 : String[60];
    Port                 : String[10];
    Caption              : String[60];
    TerminalType         : String[20];
    LocalEcho            : Boolean;
    LineMode             : Boolean;
    CR2CRLF              : Boolean;
    DebugLevel           : Word;
    SSL                  : Word;
    SSLVersion           : String[10];
  End;{-- Connection --------------------------------------------------}
  TdCharSet = record
    _Enabled             : Boolean;
    CharSetEnc           : Boolean;
    HostCP               : String[20];
    LocalCP              : String[20];
    EnabledLD            : Boolean;
    SemigraphicsCP       : String[20];
    KeybCharsetCheckBox  : Boolean;
    KeybCharset          : String[20];
  End;{-- CharSet -----------------------------------------------------}
  TdEnvironment = record
    _Enabled             : Boolean;
    List                 : TStringList;
  End;
  TdSecurityLogging = record
    _Enabled             : Boolean;
    NoLog                : Boolean;
    LogFile              : String;
  End;{-- SecurityLogging ---------------------------------------------}
  TdSecurityOTP = record
    _Enabled             : Boolean;
    SearchOTP            : Boolean;
    DeletePass           : Boolean;
  End;{-- SecurityOTP -------------------------------------------------}
  TdSecuritySSL = record
    _Enabled             : Boolean;
  End;{-- SecuritySSL -------------------------------------------------}
  TdSecurity = record
    _Enabled : Boolean;
    Logging  : TdSecurityLogging;
    OTP      : TdSecurityOTP;
    SSL      : TdSecuritySSL;
  End;{-- Security ----------------------------------------------------}
  TdConsoleFont = record
    _Enabled: Boolean;
    Name    : String;
    Bold    : Boolean;
    Size    : Integer;
  End;{-- ConsoleFont -------------------------------------------------}
  TdConsoleWindow = record
    _Enabled          : Boolean;
    Cols              : Byte;
    Rows              : Byte;
    Top               : Integer;
    Left              : Integer;
    WinResizeWillCause: TResizeMode;
    UnixLikePaste     : Byte;
    CursorMode        : Byte;
    FillInArea        : Boolean;
    AreaColor         : Longint;
  End;{-- ConsoleWindows ----------------------------------------------}
  TdConsoleColors = record
    _Enabled             : Boolean;
    black        : Boolean; blackB      : LongInt; blackF      : LongInt;
    red          : Boolean; redB        : LongInt; redF        : LongInt;
    green        : Boolean; greenB      : LongInt; greenF      : LongInt;
    yellow       : Boolean; yellowB     : LongInt; yellowF     : LongInt;
    blue         : Boolean; blueB       : LongInt; blueF       : LongInt;
    magenta      : Boolean; magentaB    : LongInt; magentaF    : LongInt;
    cyan         : Boolean; cyanB       : LongInt; cyanF       : LongInt;
    white        : Boolean; whiteB      : LongInt; whiteF      : LongInt;
    normal       : Boolean; normalB     : LongInt; normalF     : LongInt;
    bold         : Boolean; boldB       : LongInt; boldF       : LongInt;
    underline    : Boolean; underlineB  : LongInt; underlineF  : LongInt;
    blink        : Boolean; blinkB      : LongInt; blinkF      : LongInt;
    reverse      : Boolean;
    nonvisible   : Boolean; nonvisibleB : LongInt;
    LocalEcho    : Boolean; LocalEchoB  : LongInt; LocalEchoF  : LongInt;
                            Cursor      : LongInt;
  End;{-- ConsoleColors -----------------------------------------------}
  TdConsole = record
    _Enabled : Boolean;
    Font     : TdConsoleFont;
    Window   : TdConsoleWindow;
    Colors   : TdConsoleColors;
  End;{-- Console -----------------------------------------------------}
  TdUserAcounts = record
    _Enabled         : Boolean;
  End;{-- UserAcounts -------------------------------------------------}
  PdConnectionParameters =^TdConnectionParameters;
  TdConnectionParameters = record
    Connection           : TdConnection;
    CharSet              : TdCharSet;
    Environment          : TdEnvironment;
    Security             : TdSecurity;
    Console              : TdConsole;
    UserAcounts          : TdUserAcounts;
  End;{-- ConnectionParameters ----------------------------------------}
  {********************************************************************}
  TdDifferentIP = record
    _Enabled : Boolean;
    Mode     : Byte;
  End;
  TdFileSystem = record
    _Enabled : Boolean;
    HomeDir  : String;
    EnabRO   : Boolean;
    RODirs   : String;
    EnabRW   : Boolean;
    RWDirs   : String;
  End;
  TdFTP = record
    _Enabled    : Boolean;
    DNSResolv   : Boolean;
    DifferentIP : TdDifferentIP;
    FileSystem  : TdFileSystem;
  End;
  PTerminal =^TTerminal;
  TTerminal = record
    Name : String[20];
    FName: String;
  End;
  {********************************************************************}
  PdPrinter =^TdPrinter;
  TdPrinter = record
    _Enabled    : Boolean;
    ProfileName : String;
    PrinterName : String;
    CharsetE    : Boolean;
    HCharset    : String;
    LCharset    : String;
    LineArtE    : Boolean;
    LineArt     : String;
    AccessMode  : Byte;
    LF2CRLF     : Boolean;
    CR2CRLF     : Boolean;
    FontName    : String;
    FontSize    : Integer;
    InitFile    : String;
    DoneFile    : String;
  End;
  TdOTP = record
    _Enabled    : Boolean;
    Minimum     : Integer;
  End;
            
  PConfiguration =^TConfiguration;
  TConfiguration = Record
    MainName              : String;
    LocalName             : String;
    MSGName               : String;
    CPName                : String;
    Windows               : TList;
    Terminals             : TList;
    Connections           : TList;
    CodePageNames         : TStringList;
    CodePage              : TList;
    FTP                   : TdFTP;
    FTPServer             : TxFTPServer;
    Printer               : String;
    PrinterProfiles       : TList;
    ConParPage            : TCFGPages;
    LocalINI              : TINIFile;
    MainINI               : TINIFile;
    MSG                   : TINIFile;
    ConnectionSelect      : Boolean;
    ConnectionName        : String;
    KnownLang             : TStringList;
    Language              : String[3];
    OTP                   : TdOTP;
    UserName              : string;
    DontShowPrnDBP        : Boolean;
    SaveReceivedPRNData   : String;
    SavePrintedPRNData    : String;
  End;
  PCPArray =^TCPArray;
  TCPArray = Array[#0..#255] of char;

Const
  __Version               = '1.0.0';
{$IFDEF METAL_SHIT}
  Version               = __Version+'-mtl';
{$ELSE}
  Version               = __Version;
{$ENDIF}
  DebugNone             : Char = '0';
  DebugNormal           : Char = '1';
  DebugDetailed         : Char = '2';
  ININame               = 'SemTel.ini';
  MSGName               = 'SemTel.lng';
  CPName                = 'SemTel.bnc';
  ctError               : String[20] = 'Chyba';
  ctWarning             : String[20] = 'Upozornění';
  ctQuestion            : String[20] = 'Dotaz';
  ctInformation         : String[20] = 'Informace';
  ctbtnOk               : String[20] = 'O&k';
  ctbtnCancel           : String[20] = '&Storno';
  ctNoMainTermFile      : String     = 'ctNoMainTermFile';
  ctNoIncTermFile       : String     = 'ctNoIncTermFile';
  CFG                   : PConfiguration = nil;

Var
  EXEPath               : String;
  WINPath               : String;
  SuperUser             : Boolean;
  LoadDialogs           : Boolean;
  ConnDef               : PdConnectionParameters;
  IdentCP               : PCPArray;
  fPrinterSetupDialog   : TPrinterSetupDialog;
  fOpenANSI             : TOpenDialog;
  DebugFileName         : String;
  DebugLevel            : Char;


Procedure ConnectionDefault(D:PdConnectionParameters);
Function  ConnectionExists(Name:String):Boolean;
Function  ConnectionFind(Name:String):PdConnectionParameters;
Procedure ConnectionAdd(CData:PdConnectionParameters);
Procedure ConnectionDelete(Name:String);
Procedure ConnectionMakeList(List:TStrings);

Procedure WindowGenerateMenu;
Function  WindowGetNo(P:Pointer):Integer;
Function  WindowGetP(No:Integer):TForm;
Function  WindowGetByHandle(H:HWND):TForm;
Function  WindowGetActive:TForm;
Function  WindowNo2Chr(No:Integer):String;
Function  WindowRandomName:String;
Procedure WindowReadMSG;
Procedure WindowClose;
Procedure WindowSetParameters;
Procedure WindowHideMain;

Function  TerminalFind(Const Name:String):PTerminal;

Function CodePageGetNo(Const Name:String):integer;
Function CodePageFromTo(Const FromCP,ToCP:String):PCPArray;

Procedure PrinterDefault(Printer:PdPrinter);
Procedure PrinterList(List:TStrings);
Function  PrinterGetP(Const ProfileName:String):PdPrinter;

Function EnvGetVariable(Const S:String):String;
Function EnvGetValue(Const S:String):String;
Function EnvGetValueFromOS(Const S:String):String;
Function EnvGetValueFromList(SL:TStringList;Const S:String):String;
Function EnvFindVariable(SL:TStringList;Const S:String):Integer;
Procedure EnvReplaceVariable(SL:TStringList;Const S:String);

{$IFDEF DEBUGMSG}
Procedure WriteToLog(Level:Char; UnitName:TKnownUnits; Const FunctionName, Action:String);
{$ENDIF}
Procedure Init;
Procedure Done;
Function IsMSGFile:Boolean;
Procedure SetLanguage(S:String);
Function LoadList(INI:TINIFile;Section,BaseName:String):TStringList;
Function AllocateDialog(DT:TDialogType):Boolean;
Procedure DeallocateDialog;
Function StringsFindNearest(Strings:TStrings; Const S:String; Numeric:Boolean):Integer;

implementation
Uses
  WinProcs, Controls, 
  OTPCalc,  OneLine,  SelectC,  ConnPar,
  PromtKey, Main,     Menus,    C3216,
  Printers, InVis,    xTerm,    SelectIP,
  pgpPKey,  mime,     MD5,      AboutBox,
  qConn,    SafeMem,  NetworkPrinterInDirectModeSelect;

Const
  Initialized       : Boolean = False;
  ctDefault         = ''; {}
  ctGlobal          = 'Global';
  ctConnection      = 'Connection';
  ctAutomaticLogin  = 'AutomaticLogin';
  ctCharSet         = 'CharSet';
  ctEnvironment     = 'Environment';
  ctSecurity        = 'Security';
  ctLogging         = 'Security.Logging';
  ctOTP             = 'Security.OTP';
  ctSSL             = 'Security.SSL';
  ctConsole         = 'Console';
  ctFont            = 'Console.Font';
  ctWindow          = 'Console.Window';
  ctColors          = 'Console.Colors';
  ctSubstColors     = 'Console.SubstColors';
  ctUserAcounts     = 'UserAcounts';
  ctConnections     = 'NewConnections';
  ctCount           = 'Count';
  ctFTP             = 'FTP';
  ctDifferentIP     = 'FTP.DifferentIP';
  ctFileSystem      = 'FTP.FileSystem';
  ctOTPMinimum      = 'OTP.Minimum';
  ctPrinters        = 'Printers';
  ctPrinter         = 'Printer';

{$IFDEF DEBUGMSG}
Procedure WriteToLog(Level:Char; UnitName:TKnownUnits; Const FunctionName, Action:String);
Var
  DebugFile           : Text;
  Year, Month, Day    : Word;
  Hour, Min, Sec, MSec: Word;
Begin
  If not Initialized Then STConfig.Init;

  If (DebugLevel>=Level)and(DebugFileName<>'') Then Try
    Assign(DebugFile, DebugFileName);
    If FileExists(DebugFileName) Then Append(DebugFile) Else Rewrite(DebugFile);
    DecodeDate(Date, Year, Month, Day);
    DecodeTime(Time, Hour, Min, Sec, MSec);
    WriteLn(DebugFile, Format('%.2d.%.2d.%.4d %.2d:%.2d:%.2d.%.3d: %s: %s(): %s',
      [Day, Month, Year, Hour, Min, Sec, MSec, UnitsNames[UnitName], FunctionName, Action]));
  finally Begin
    Close(DebugFile);
  End End;
End;
{$ENDIF}

{** Connection managment ******************************************************}
Procedure ConnectionDefault(D:PdConnectionParameters);
Begin
  FillChar(D^, SizeOf(TdConnectionParameters), 0);
  D^.Connection._Enabled                            := True;
  D^.Connection.Host                                := '';
  D^.Connection.Port                                := 'telnet';
  D^.Connection.Caption                             := '';
  D^.Connection.TerminalType                        := 'ANSI';
  D^.Connection.LocalEcho                           := False;
  D^.Connection.LineMode                            := False;
  D^.Connection.CR2CRLF                             := False;
  D^.Connection.DebugLevel                          := 0;
  D^.Connection.SSL                                 := 0;
  D^.Connection.SSLVersion                          := 'SSLv3';
  D^.CharSet._Enabled                               := True;
  D^.CharSet.CharSetEnc                             := True;
  D^.CharSet.HostCP                                 := 'ISO-8859-2';
  D^.CharSet.LocalCP                                := 'CP1250';
  D^.CharSet.EnabledLD                              := True;
  D^.CharSet.SemigraphicsCP                         := 'SEMIGRAPHICS';
  D^.CharSet.KeybCharSetCheckBox                    := True;
  D^.CharSet.KeybCharSet                            := 'CP1250';
  D^.Environment._Enabled                           := True;
  If D^.Environment.List<>nil Then D^.Environment.List.Free;
  D^.Environment.List                               := TStringList.Create;
  D^.Environment.List.Duplicates                    := dupIgnore;
  D^.Environment.List.Sorted                        := True;
  (* Removed at 4.6.1999
  D^.Environment.List.Add({$IFDEF Win32}'SYSTEMTYPE=Win32'{$ELSE}'SYSTEMTYPE=Win16'{$ENDIF}); *)
  D^.Security._Enabled                              := True;
  D^.Security.Logging._Enabled                      := True;
  D^.Security.Logging.NoLog                         := True;
  D^.Security.Logging.LogFile                       := 'C:\TEMP\SemTel.log';
  D^.Security.OTP._Enabled                          := True;
  D^.Security.OTP.SearchOTP                         := True;
  D^.Security.OTP.DeletePass                        := True;
  D^.Security.SSL._Enabled                          := False;
  D^.Console._Enabled                               := True;
  D^.Console.Font._Enabled                          := True;
  D^.Console.Font.Name                              := 'Courier New'{}{'Terminal'{};
  D^.Console.Font.Size                              := 11;
  D^.Console.Window._Enabled                        := True;
  D^.Console.Window.Cols                            := 80;
  D^.Console.Window.Rows                            := 25;
  D^.Console.Window.Top                             := 0;
  D^.Console.Window.Left                            := 0;
  D^.Console.Window.WinResizeWillCause              := rmFontSizeChange;
  D^.Console.Window.UnixLikePaste                   := 2;
  D^.Console.Window.CursorMode                      := 0;
  D^.Console.Window.FillInArea                      := False;
  D^.Console.Window.AreaColor                       := clRed;
  D^.Console.Colors._Enabled                        := True;
  D^.Console.Colors.black                           := True;
  D^.Console.Colors.blackB                          := clBlack;
  D^.Console.Colors.blackF                          := clBlack;
  D^.Console.Colors.red                             := True;
  D^.Console.Colors.redB                            := clMaroon;
  D^.Console.Colors.redF                            := clRed;
  D^.Console.Colors.green                           := True;
  D^.Console.Colors.greenB                          := clGreen;
  D^.Console.Colors.greenF                          := clLime;
  D^.Console.Colors.yellow                          := True;
  D^.Console.Colors.yellowB                         := clOlive;
  D^.Console.Colors.yellowF                         := clYellow;
  D^.Console.Colors.blue                            := True;
  D^.Console.Colors.blueB                           := clNavy;
  D^.Console.Colors.blueF                           := clBlue;
  D^.Console.Colors.magenta                         := True;
  D^.Console.Colors.magentaB                        := clPurple;
  D^.Console.Colors.magentaF                        := clFuchsia;
  D^.Console.Colors.cyan                            := True;
  D^.Console.Colors.cyanB                           := clTeal;
  D^.Console.Colors.cyanF                           := clAqua;
  D^.Console.Colors.white                           := True;
  D^.Console.Colors.whiteB                          := clSilver;
  D^.Console.Colors.whiteF                          := clWhite;
  D^.Console.Colors.normal                          := True;
  D^.Console.Colors.normalB                         := clWindow;
  D^.Console.Colors.normalF                         := clWindowText;
  D^.Console.Colors.bold                            := True;
  D^.Console.Colors.boldB                           := clWindow;
  D^.Console.Colors.boldF                           := clWindowText;
  D^.Console.Colors.underline                       := True;
  D^.Console.Colors.underlineB                      := clWindow;
  D^.Console.Colors.underlineF                      := clOlive;
  D^.Console.Colors.blink                           := True;
  D^.Console.Colors.blinkB                          := clWindow;
  D^.Console.Colors.blinkF                          := clMaroon;
  D^.Console.Colors.reverse                         := True;
  D^.Console.Colors.nonvisible                      := True;
  D^.Console.Colors.nonvisibleB                     := clWindow;
  D^.Console.Colors.LocalEcho                       := True;
  D^.Console.Colors.LocalEchoB                      := clBtnFace;
  D^.Console.Colors.LocalEchoF                      := clBtnText;
  D^.Console.Colors.Cursor                          := clRed;                              
  D^.UserAcounts._Enabled                           := False;
End;{-- ConnectionDefault -----------------------------------------------------}
Function ConnectionExists(Name:String):Boolean;
Begin
  Result:=ConnectionFind(Name)<>nil;
End;{-- ConnectionExists ------------------------------------------------------}
Function ConnectionFind(Name:String):PdConnectionParameters;
Var
  I     : Integer;
  PConn : PdConnectionParameters;
Begin
  Result := nil;
  If CFG^.Connections.Count>0 Then Begin
    For I:=0 To CFG^.Connections.Count-1 Do Begin
      PConn:=CFG^.Connections.Items[I];
      If PConn^.Connection.Caption=Name Then Begin
        Result:=PConn;
        Exit;
      End;
    End
  End;
End;{-- ConnectionFind --------------------------------------------------------}
Procedure ConnectionAdd(CData:PdConnectionParameters);
Begin
  CFG^.Connections.Add(CData);
End;{-- ConnectionAdd ---------------------------------------------------------}
Procedure ConnectionDelete(Name:String);
Var
  PConn : PdConnectionParameters;
Begin
  PConn := ConnectionFind(Name);
  If PConn <> nil Then Begin
    CFG^.Connections.Remove(PConn);
  End;
End;{-- ConnecctionDelete -----------------------------------------------------}
Procedure ConnectionMakeList(List:TStrings);
Var
  I     : Integer;
  PConn : PdConnectionParameters;
Begin
  List.Clear;
  If CFG^.Connections.Count>0 Then
    For I:=0 To CFG^.Connections.Count-1 Do Begin
      PConn:=CFG^.Connections.Items[I];
      List.Add(PConn^.Connection.Caption);
    End;
End;{-- ConnectionMakeList ----------------------------------------------------}

{** Connection window managment ***********************************************}
Procedure WindowGenerateMenu;
Var
  I,J       : Integer;
  fMain     : TfMain;
  MenuItem  : TMenuItem;

Begin
  If CFG^.Windows.Count>0 Then Begin
    For I:=0 To CFG^.Windows.Count-1 Do Begin
      fMain := CFG^.Windows.Items[I];
      fMain.SetCaption;
    End;
    For I:=0 To CFG^.Windows.Count-1 Do Begin
      fMain := CFG^.Windows.Items[I];

      While fMain.Menu.Items[3].Count>0 Do Begin
        MenuItem:=fMain.Menu.Items[3].Items[0];
        fMain.Menu.Items[3].Remove(MenuItem);
        MenuItem.Free;
      End;

      For J:=0 To CFG^.Windows.Count-1 Do Begin
        MenuItem := TMenuItem.Create(fMain);
        If (J mod 20 =0)and(J>0) Then Begin
          If J div 20 >0 Then MenuItem.Break:=mbBarBreak
          Else MenuItem.Break:=mbBreak;
        End;
        MenuItem.Caption := '&'+TForm(CFG^.Windows.Items[J]).Caption;
        MenuItem.OnClick := fMain.mnWindowClick;
        MenuItem.Tag     := J shl 1;
        fMain.Menu.Items[3].Insert(fMain.Menu.Items[3].Count,MenuItem);
      End;
    End;
  End;
  WindowHideMain;
End;{-- WindowGenerateMenu ----------------------------------------------------}
Function WindowGetNo(P:Pointer):Integer;
Var
  I : Integer;
Begin
  If CFG^.Windows.Count>0 Then
   For I:=0 To CFG^.Windows.Count-1 Do If CFG^.Windows.Items[I]=P Then Begin
     Result:=I;
     Exit;
   End;
  Result:=-1;
End;{-- WindowGetNo -----------------------------------------------------------}
Function  WindowGetP(No:Integer):TForm;
Begin
  If (CFG^.Windows.Count>0)and(No<CFG^.Windows.Count) Then Result:=CFG^.Windows.Items[No]
  Else Result:=nil;
End;{-- WindowGetP ------------------------------------------------------------}
Function  WindowGetByHandle(H:HWND):TForm;
Var
  I : Integer;
Begin
  Result:=nil;
  If CFG^.Windows.Count>0 Then For I:=0 To CFG^.Windows.Count-1 Do
    If TForm(CFG^.Windows.Items[I]).Handle=H Then Begin
      Result:=TForm(CFG^.Windows.Items[I]);
      Exit;
    End;
End;{-- WindowGetByHandle -----------------------------------------------------}
Function  WindowNo2Chr(No:Integer):String;
Begin
  Case No of
     0..9   : Result := Char(No+48);
     10..35 : Result := Char(No+55);
     Else     Result := IntToStr(No);
  End;
End;{-- WindowNo2Chr ----------------------------------------------------------}
Function  WindowRandomName:String;
Begin
  Result := Format('_%d%d',[Round($FFFFFF*Random),Round($FFFFFF*Random)]);
End;{-- WindowRandomName ------------------------------------------------------}
Procedure WindowClose;
Var
  M : TfMain;
Begin
  While CFG^.Windows.Count>0 Do Begin
     M := CFG^.Windows.Items[0];
     CFG^.Windows.Remove(M);
     M.Free;
  End;
End;{-- WindowClose -----------------------------------------------------------}
Procedure WindowReadMSG;
Var
  I : Integer;
  M : TfMain;
Begin
  If CFG^.Windows.Count>0 Then
   For I:=0 To CFG^.Windows.Count-1 Do Begin
     M := CFG^.Windows.Items[I];
     M.ReadMSG;
   End;
End;{-- WindowReadMSG ---------------------------------------------------------}


{** CodePages managment *******************************************************}
Function  CodePageGetNo(Const Name:String):integer;
Var
  I : Integer;
Begin
  Result:=-1;
  If CFG^.CodePageNames=nil Then Exit;
  For I:=0 To CFG^.CodePageNames.Count-1 Do
   If CFG^.CodePageNames.Strings[I]=Name Then Begin
     Result:=I;
     Exit;
   End;
End;{-- CodePageGetNo ---------------------------------------------------------}
Function CodePageFromTo(Const FromCP,ToCP:String):PCPArray;
Var
  iFrom, iTo : Integer;
  I          : Integer;
Begin
  Result:=IdentCP;
  If (CFG^.CodePageNames=nil)or(CFG^.CodePage=nil) Then Exit;
  iFrom := CodePageGetNo(FromCP);
  iTo   := CodePageGetNo(ToCP);
  If (iTo=-1)or(iFrom=-1) Then Exit;
  If iTo=iFrom Then Exit;
  I:=iFrom*(CFG^.CodePageNames.Count-1)+iTo+1*Byte(iFrom>iTo);
  Result:=CFG^.CodePage.Items[I-1];
End;{-- CodePageFromTo --------------------------------------------------------}

Function GetX(Var S:String;Number:Integer):String;
Begin
  If Pos(';',S)=0 Then
   Begin Result:=S;S:=''End
  Else
   Begin
     Result:=System.Copy(S,1,Pos(';',S)-1);
     System.Delete(S,1,Pos(';',S));
   End;
  If (Number>0)and(Result='') Then Result:='0';
End;

Procedure RWConnection(NotRead,IgnoreEnab:Boolean;INI:TINIFile;Const Section,Prefix:String;Data:PdConnectionParameters);
Function RC(C:LongInt):LongInt;
Begin
  {$IFDEF Win32}
  If C<0 Then
    Result:=abs(C+1)or$80000000
  Else Result:=C;
  {$ELSE}
  Result:=C;
  {$ENDIF}
End;
Function WC(C:LongInt):LongInt;
Begin
  {$IFDEF Win32}
  If C<0 Then
    Result:=-(((C+1)or$80000000)and$7FFFFFFF)
  Else Result:=C;
  {$ELSE}
  Result:=C;
  {$ENDIF}
End;
Const
  MethodName='RWConnection';
Var
  S : String;
  I : Integer;
Begin
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Begin');{$ENDIF}
  With Data^ Do Begin
   With Connection Do If _Enabled or IgnoreEnab or (NotRead) Then Begin {!!! Jméno spojení se musí zapsat VŽDY}
     If NotRead Then Begin
       INI.WriteString(Section,Prefix+ctConnection,Format('%d;%s;%s;%s;%s;%d;%d;%d;%d;%d;%s',
         [Byte(_Enabled),Host,Port,Caption,TerminalType,Byte(LocalEcho),
          Byte(LineMode),Byte(CR2CRLF),DebugLevel,SSL,SSLVersion]));
     End Else Begin
       S:=INI.ReadString(Section,Prefix+ctConnection,ctDefault);
       If S<>'' Then Begin
         _Enabled          := GetX(S,0)='1';
         Host              := GetX(S,0);
         Port              := GetX(S,0);
         Caption           := GetX(S,0);
         TerminalType      := GetX(S,0);
         LocalEcho         := GetX(S,0)='1';
         LineMode          := GetX(S,0)='1';
         CR2CRLF           := GetX(S,0)='1';
         DebugLevel        := StrToInt(GetX(S,1));
         SSL               := StrToInt(GetX(S,1));
         SSLVersion        := GetX(S,0);
       End;
     End;
   End; {-- Connection --}
   With CharSet Do If _Enabled or IgnoreEnab Then Begin
     If NotRead Then Begin
       INI.WriteString(Section,Prefix+ctCharSet,Format('%d;%d;%s;%s;%d;%s;%d;%s',
         [Byte(_Enabled),Byte(CharSetEnc),HostCP,LocalCP,Byte(EnabledLD),
          SemigraphicsCP,Byte(KeybCharSetCheckBox),KeybCharSet]));
     End Else Begin
       S:=INI.ReadString(Section,Prefix+ctCharSet,ctDefault);
       If S<>'' Then Begin
         _Enabled             := GetX(S,0)='1';
         CharSetEnc           := GetX(S,0)='1';
         HostCP               := GetX(S,0);
         LocalCP              := GetX(S,0);
         EnabledLD            := GetX(S,0)='1';
         SemigraphicsCP       := GetX(S,0);
         KeybCharSetCheckBox  := GetX(S,0)='1';
         KeybCharSet          := GetX(S,0);
       End;
     End;
   End; {-- CharSet --}
   With Environment Do If _Enabled or IgnoreEnab Then Begin
     If NotRead Then Begin
       INI.WriteString(Section,Prefix+ctEnvironment,Format('%d;%d',
         [Byte(_Enabled),List.Count]));
       For I:=0 To List.Count-1 Do
         INI.WriteString(Section, Format(Prefix+ctEnvironment+'%d', [I+1]), List.Strings[I]);
     End Else Begin
       S:=INI.ReadString(Section,Prefix+ctEnvironment,ctDefault);
       If S<>'' Then Begin
         _Enabled             := GetX(S,0)='1';
         I                    := StrToInt(GetX(S,0));
         For I:=0 To I-1 Do Begin
           S:=INI.ReadString(Section, Format(Prefix+ctEnvironment+'%d', [I+1]), '');
           If S<>'' Then EnvReplaceVariable(List, S);
         End;
       End;
     End;
   End; {-- Environment --}
   With Security Do If _Enabled or IgnoreEnab Then Begin
     If NotRead Then Begin
       INI.WriteString(Section,Prefix+ctSecurity,Format('%d',
         [Byte(_Enabled)]));
     End Else Begin
       S:=INI.ReadString(Section,Prefix+ctSecurity,ctDefault);
       If S<>'' Then Begin
         _Enabled             := GetX(S,0)='1';
       End;
     End;
     With Logging Do If _Enabled or IgnoreEnab Then Begin
       If NotRead Then Begin
         INI.WriteString(Section,Prefix+ctLogging,Format('%d;%d;%s',
           [Byte(_Enabled),Byte(NoLog),LogFile]));
       End Else Begin
         S:=INI.ReadString(Section,Prefix+ctLogging,ctDefault);
         If S<>'' Then Begin
           _Enabled          := GetX(S,0)='1';
           NoLog             := GetX(S,0)='1';
           LogFile           := GetX(S,0);
         End;
       End;
     End; {-- Security.Logging --}
     With OTP Do If _Enabled or IgnoreEnab Then Begin
       If NotRead Then Begin
         INI.WriteString(Section,Prefix+ctOTP,Format('%d;%d;%d',
           [Byte(_Enabled),Byte(SearchOTP),Byte(DeletePass)]));
       End Else Begin
         S:=INI.ReadString(Section,Prefix+ctOTP,ctDefault);
         If S<>'' Then Begin
           _Enabled          := GetX(S,0)='1';
           SearchOTP         := GetX(S,0)='1';
           DeletePass        := GetX(S,0)='1';
         End;
       End;
     End; {-- Security.OTP --}
     With SSL Do If _Enabled or IgnoreEnab Then Begin
       If NotRead Then Begin
         INI.WriteString(Section,Prefix+ctSSL,Format('%d',
           [Byte(_Enabled)]));
       End Else Begin
         S:=INI.ReadString(Section,Prefix+ctSSL,ctDefault);
         If S<>'' Then Begin
           _Enabled          := GetX(S,0)='1';
         End;
       End;
     End; {-- Security.SSL --}
   End; {-- Security --}
   With Console Do If _Enabled or IgnoreEnab Then Begin
     If NotRead Then Begin
       INI.WriteString(Section,Prefix+ctConsole,Format('%d',
         [Byte(_Enabled)]));
     End Else Begin
       S:=INI.ReadString(Section,Prefix+ctConsole,ctDefault);
       If S<>'' Then Begin
         _Enabled          := GetX(S,0)='1';
       End;
     End;
     With Font Do If _Enabled or IgnoreEnab Then Begin
       If NotRead Then Begin
         INI.WriteString(Section,Prefix+ctFont,Format('%d;%s;%d;%d',
           [Byte(_Enabled),Name,Size,Byte(Bold)]));
       End Else Begin
         S:=INI.ReadString(Section,Prefix+ctFont,ctDefault);
         If S<>'' Then Begin
           {_Enabled           := }GetX(S,0){='1'};
           Name               := GetX(S,0);
           Size               := StrToInt(GetX(S,1));
           Bold               := GetX(S,0)='1';
         End;
       End;
     End; {-- Console.Font --}
     With Window Do If _Enabled or IgnoreEnab Then Begin
       If NotRead Then Begin
         INI.WriteString(Section,Prefix+ctWindow,Format('%d;%d;%d;%d;%d;%d;%d;%d;%d;%.8x',
           [Byte(_Enabled),Cols,Rows,Left,Top,Byte(WinResizeWillCause),
           UnixLikePaste,CursorMode,Byte(FillInArea),WC(AreaColor)]));
       End Else Begin
         S:=INI.ReadString(Section,Prefix+ctWindow,ctDefault);
         If S<>'' Then Begin
           _Enabled          := GetX(S,0)='1';
           Cols              := StrToInt(GetX(S,1));
           Rows              := StrToInt(GetX(S,1));
           Left              := StrToInt(GetX(S,1));
           Top               := StrToInt(GetX(S,1));
           WinResizeWillCause:= TResizeMode(StrToInt(GetX(S,1)));
           UnixLikePaste     := StrToInt(GetX(S,1));
           CursorMode        := StrToInt(GetX(S,1));
           FillInArea        := GetX(S,0)='1';
           AreaColor         := RC(StrToInt('$'+GetX(S,1)));
         End;
       End;
     End; {-- Console.Window --}
     With Colors Do If _Enabled or IgnoreEnab Then Begin
       If NotRead Then Begin
         INI.WriteString(Section,Prefix+ctColors,
           Format('%d;%d;%.8x;%.8x;%d;%.8x;%.8x;%d;%.8x;%.8x;%d;%.8x;%.8x;'+
                  '%d;%.8x;%.8x;%d;%.8x;%.8x;%d;%.8x;%.8x;%d;%.8x;%.8x',
           [Byte(_Enabled),
            Byte(black  ),  WC(blackF  ),  WC(blackB  ),
            Byte(red    ),  WC(redF    ),  WC(redB    ),
            Byte(green  ),  WC(greenF  ),  WC(greenB  ),
            Byte(yellow ),  WC(yellowF ),  WC(yellowB ),
            Byte(blue   ),  WC(blueF   ),  WC(blueB   ),
            Byte(magenta),  WC(magentaF),  WC(magentaB),
            Byte(cyan   ),  WC(cyanF   ),  WC(cyanB   ),
            Byte(white  ),  WC(whiteF  ),  WC(whiteB  )]));
         INI.WriteString(Section,Prefix+ctSubstColors,
           Format('%d;%.8x;%.8x;'+ {normal}
                  '%d;%.8x;%.8x;'+ {bold}
                  '%d;%.8x;%.8x;'+ {underline}
                  '%d;%.8x;%.8x;'+ {blink}
                  '%d;'+           {reverse}
                  '%d;%.8x;'+      {nonvisible}
                  '%d;%.8x;%.8x;'+ {localecho}
                  '%.8x',          {cursor}
           [Byte(normal    ), WC(normalF   ),  WC(normalB    ),
            Byte(bold      ), WC(boldF     ),  WC(boldB      ),
            Byte(underline ), WC(underlineF),  WC(underlineB ),
            Byte(blink     ), WC(blinkF    ),  WC(blinkB     ),
            Byte(reverse   ),
            Byte(nonvisible),                  WC(nonvisibleB),
            Byte(LocalEcho ), WC(LocalEchoF),  WC(LocalEchoB ),
                              WC(Cursor)]));
       End Else Begin
         S:=INI.ReadString(Section,Prefix+ctColors,ctDefault);
         If S<>'' Then Begin
           _Enabled          := GetX(S,0)='1';
           black  := GetX(S,0)='1';  blackF   := RC(StrToInt('$'+GetX(S,1))); blackB   := RC(StrToInt('$'+GetX(S,1)));
           red    := GetX(S,0)='1';  redF     := RC(StrToInt('$'+GetX(S,1))); redB     := RC(StrToInt('$'+GetX(S,1)));
           green  := GetX(S,0)='1';  greenF   := RC(StrToInt('$'+GetX(S,1))); greenB   := RC(StrToInt('$'+GetX(S,1)));
           yellow := GetX(S,0)='1';  yellowF  := RC(StrToInt('$'+GetX(S,1))); yellowB  := RC(StrToInt('$'+GetX(S,1)));
           blue   := GetX(S,0)='1';  blueF    := RC(StrToInt('$'+GetX(S,1))); blueB    := RC(StrToInt('$'+GetX(S,1)));
           magenta:= GetX(S,0)='1';  magentaF := RC(StrToInt('$'+GetX(S,1))); magentaB := RC(StrToInt('$'+GetX(S,1)));
           cyan   := GetX(S,0)='1';  cyanF    := RC(StrToInt('$'+GetX(S,1))); cyanB    := RC(StrToInt('$'+GetX(S,1)));
           white  := GetX(S,0)='1';  whiteF   := RC(StrToInt('$'+GetX(S,1))); whiteB   := RC(StrToInt('$'+GetX(S,1)));
         End;
         S:=INI.ReadString(Section,Prefix+ctSubstColors,ctDefault);
         If S<>'' Then Begin
           normal     := GetX(S,0)='1'; normalF    := RC(StrToInt('$'+GetX(S,1))); normalB    := RC(StrToInt('$'+GetX(S,1)));
           bold       := GetX(S,0)='1'; boldF      := RC(StrToInt('$'+GetX(S,1))); boldB      := RC(StrToInt('$'+GetX(S,1)));
           underline  := GetX(S,0)='1'; underlineF := RC(StrToInt('$'+GetX(S,1))); underlineB := RC(StrToInt('$'+GetX(S,1)));
           blink      := GetX(S,0)='1'; blinkF     := RC(StrToInt('$'+GetX(S,1))); blinkB     := RC(StrToInt('$'+GetX(S,1)));
           reverse    := GetX(S,0)='1';
           nonvisible := GetX(S,0)='1';                                            nonvisibleB:= RC(StrToInt('$'+GetX(S,1)));
           LocalEcho  := GetX(S,0)='1'; LocalEchoF := RC(StrToInt('$'+GetX(S,1))); LocalEchoB := RC(StrToInt('$'+GetX(S,1)));
                                        Cursor     := RC(StrToInt('$'+GetX(S,1)));
         End;
       End;
     End;{-- Console.Colors --}
   End; {-- Console --}
   With UserAcounts Do If _Enabled or IgnoreEnab Then Begin
     If NotRead Then Begin
       INI.WriteString(Section,Prefix+ctUserAcounts,Format('%d',
         [Byte(_Enabled)]));
     End Else Begin
       S:=INI.ReadString(Section,Prefix+ctUserAcounts,ctDefault);
       If S<>'' Then Begin
         _Enabled          := GetX(S,0)='1';
       End;
     End;
   End; {-- UserAcounts --}
  End; {-- Data --}
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'End');{$ENDIF}
End;{-- Procedure --}

Procedure RWGlobal(NotRead,IgnoreEnab:Boolean;INI:TINIFile;Const Section:String);
Var
  S     : String;
Begin
  With CFG^ Do Begin
     With OTP Do If _Enabled or IgnoreEnab Then Begin
       If NotRead Then Begin
         INI.WriteString(Section,ctOTPMinimum,Format('%d;%d',
           [Byte(_Enabled),Minimum]));
       End Else Begin
         S:=INI.ReadString(Section,ctOTPMinimum,ctDefault);
         If S<>'' Then Begin
           _Enabled          := GetX(S,0)='1';
           Minimum           := StrToInt(GetX(S,1));
         End;
       End;
     End;{FTP}
  End;{CFG}
End;

Procedure RWFTP(NotRead,IgnoreEnab:Boolean;INI:TINIFile;Const Section:String);
Var
  S     : String;
Begin
  With CFG^ Do Begin
     With FTP Do If _Enabled or IgnoreEnab Then Begin
       If NotRead Then Begin
         INI.WriteString(Section,ctFTP,Format('%d;%d',
           [Byte(_Enabled),Byte(DNSResolv)]));
       End Else Begin
         S:=INI.ReadString(Section,ctFTP,ctDefault);
         If S<>'' Then Begin
           _Enabled          := GetX(S,0)='1';
           DNSResolv         := GetX(S,0)='1';
         End;
       End;
       With DifferentIP Do If _Enabled or IgnoreEnab Then Begin
         If NotRead Then Begin
           INI.WriteString(Section,ctDifferentIP,Format('%d;%d',
             [Byte(_Enabled),Mode]));
         End Else Begin
           S:=INI.ReadString(Section,ctDifferentIP,ctDefault);
           If S<>'' Then Begin
             _Enabled := GetX(S,0)='1';
             Mode     := StrToInt(GetX(S,1));
           End;
         End;
       End;{DifferentIP}
       With FileSystem Do If _Enabled or IgnoreEnab Then Begin
         If NotRead Then Begin
           INI.WriteString(Section,ctFileSystem,Format('%d;%s;%d;%s;%d;%s',
             [Byte(_Enabled),HomeDir,Byte(EnabRO),RODirs,Byte(EnabRW),RWDirs]));
         End Else Begin
           S:=INI.ReadString(Section,ctFileSystem,ctDefault);
           If S<>'' Then Begin
             _Enabled := GetX(S,0)='1';
             HomeDir  := GetX(S,0);
             EnabRO   := GetX(S,0)='1';
             RODirs   := GetX(S,0);
             EnabRW   := GetX(S,0)='1';
             RWDirs   := GetX(S,0);
           End;
         End;
       End;{FileSystem}
     End;{FTP}
  End;{CFG}
End;

Function  RWPrinter(NotRead,IgnoreEnab:Boolean;INI:TINIFile;Const Section,Ident:String;D:PdPrinter):Boolean;
Var
  S     : String;
Begin
  Result:=True;
  With D^ Do If _Enabled or IgnoreEnab Then Begin
    If NotRead Then Begin
      INI.WriteString(Section,Ident,Format('%d;%s;%s;%d;%s;%s;%d;%s;%d;%d;%s;%d;%d',
        [Byte(_Enabled),ProfileName,PrinterName,Byte(CharsetE),HCharset,LCharset,
         Byte(LineArtE),LineArt,AccessMode,Byte(LF2CRLF),FontName,
         FontSize,Byte(CR2CRLF)]));
      INI.WriteString(Section,Ident+'.Init',Format('%s', [InitFile]));
      INI.WriteString(Section,Ident+'.Done',Format('%s', [DoneFile]));
    End Else Begin
      S:=INI.ReadString(Section,Ident,ctDefault);
      If S<>'' Then Begin
        _Enabled    := GetX(S,0)='1';
        ProfileName := GetX(S,0);
        PrinterName := GetX(S,0);
        CharsetE    := GetX(S,0)='1';
        HCharset    := GetX(S,0);
        LCharset    := GetX(S,0);
        LineArtE    := GetX(S,0)='1';
        LineArt     := GetX(S,0);
        AccessMode  := StrToInt(GetX(S,1));
        LF2CRLF     := GetX(S,0)='1';
        FontName    := GetX(S,0);
        FontSize    := StrToInt(GetX(S,1));
        CR2CRLF     := GetX(S,0)='1';
        InitFile    := INI.ReadString(Section, Ident+'.Init', '');
        DoneFile    := INI.ReadString(Section, Ident+'.Done', '');
      End Else Result:=False;
    End;
  End;{FTP}
End;

Function  TerminalFind(Const Name:String):PTerminal;
Var
  I : Integer;
Begin
  Result:=nil;

  For I:=0 To CFG^.Terminals.Count-1 Do
    If PTerminal(CFG^.Terminals.Items[I])^.Name=Name Then Begin
      Result:=CFG^.Terminals.Items[I];
      Break;
    End;
End;

Function  RWTerminals(NotRead, Local:Boolean;INI:TINIFile;Const Section:String):Boolean;
Var
  S     : String;
  I     : Integer;
  neoi  : Boolean;
  PT    : PTerminal;
Begin
  Result:=True;
  If NotRead Then For I:=0 To CFG^.Terminals.Count-1 Do Begin
    PT:=CFG^.Terminals.Items[I];
    INI.WriteString(Section, Format('Terminal.%d',[I]), Format('1;%s;%s', [PT^.Name, PT^.FName]));
  End Else Begin

    I:=0; neoi:=True;
    While neoi Do Begin
      S:=INI.ReadString(Section, Format('Terminal.%d',[I]), '');
      If S='' Then Begin neoi:=False; Continue End;
      SafeGetMem(PT, SizeOf(PT^));
                     GetX(S,0); {='1'}
      PT^.Name    := GetX(S,0);
      PT^.FName   := GetX(S,0);
      If TerminalFind(PT^.Name)=nil Then CFG^.Terminals.Add(PT) Else SafeFreeMem(PT, SizeOf(PT^));
      Inc(I);
    End;

    If (CFG^.Terminals.Count=0)and Local Then Begin
      SafeGetMem(PT, SizeOf(PT^));
      PT^.Name:='ANSI';
      PT^.FName:='.\trm\ansi.trm';
      CFG^.Terminals.Add(PT);
      SafeGetMem(PT, SizeOf(PT^));
      PT^.Name:='VT100';
      PT^.FName:='.\trm\vt100.trm';
      CFG^.Terminals.Add(PT);
    End;
  End;
End;{-- RWTerminals -----------------------------------------------------------}

Procedure PrintHelp;
begin
  ShowMessage('SemTel version '+Version+', Copyright (C) 1998,99,00 Jan Tomasek'#13+
    'SemTel comes with ABSOLUTELY NO WARRANTY; for details read file COPYING.'#13+
    'This is free software, and you are welcome to redistribute it'#13+
    'under certain conditions; read file COPYING for details.'#13+
    ''#13+
    '--SuperUser, -S aktivuje SemTel v SuperUser režimu'#13#13+
    '--MainINI <FileName>, -M  určuje odkude se má načíst hlavní ini'#13+
    '--LocalINI <FileName>, -L určuje odkude se má načíst lokální ini'#13#13+
    '--MSG <FileName> určuje odkude se má načíst soubor dialogivých textů'#13+
    '--CodePage <FileName>, -CP určuje odkude se má načíst soubor kódových tabulek'#13#13+
    '--LoadDialogs, -D zavede všechna dialogová okna do paměti při startu '+
       'SemTelu, standardně se natahují až na základě žádosti'#13#13+
    '--Connect <ConnectionName>, -C po spuštění se připojí na zadaný server, '+
       'v případě, že neexistuje požadovné spojení zobrazí dialog pro výběr spojení'#13+
    '--ConnectionSelect, -CS zobrazí dialog pro výběr spojení'#13#13+
    '--Debug <FileName> zapne zápis chybových hlášení do souboru'#13+
    '--DebugLevel <0|1|2> možství zapisovaných informací:'#13+
    '         0 ... nic se zapisovat nebude'#13+
    '         1 ... standardní úroveň - zapisují se pouze vyjímky'#13+
    '         2 ... detailní informace - 1 a dále se zapisují informace o '+
                        'zahájení/ukončení některých vybraných procedur'#13);
end;


Procedure ParseArgs;
Var
  I : Integer;
  S : ShortString;
Begin
  EXEPath     := ExtractFilePath(ParamStr(0));
  SetLength(WINPath, 256);
  I           := GetWindowsDirectory(@WINPath[1],$FE);
                 SetLength(WinPath,I); WINPath := WinPath+'\';
  I := 1;
  While I<=ParamCount Do Begin
    if (ParamStr(I)='--help')or(ParamStr(I)='-h')or(ParamStr(I)='/h') then begin
      PrintHelp;
      Halt(0);
    end else begin
      If (ParamStr(I)='--SuperUser')or(ParamStr(I)='-SuperUser')or(ParamStr(I)='-S') Then Begin SuperUser := True;
      End Else Begin
        If (ParamStr(I)='--MainINI')or(ParamStr(I)='-MainINI')or(ParamStr(I)='-M') Then Begin
          Inc(I);
          CFG^.MainName:=ParamStr(I);
        End Else Begin
          If (ParamStr(I)='--LocalINI')or(ParamStr(I)='-LocalINI')or(ParamStr(I)='-L') Then Begin
            Inc(I);
            CFG^.LocalName:=ParamStr(I);
          End Else Begin
            If ParamStr(I)='-MSG' Then Begin
              Inc(I);
              CFG^.MSGName:=ParamStr(I);
            End Else Begin
              If (ParamStr(I)='--LoadDialogs')or(ParamStr(I)='-LoadDialogs')or(ParamStr(I)='-D') Then Begin
                LoadDialogs:=True;
              End Else Begin
                If (ParamStr(I)='--CodePage')or(ParamStr(I)='-CP') Then Begin
                  Inc(I);
                  CFG^.CPName:=ParamStr(I);
                End Else Begin
                  If (ParamStr(I)='--ConnectionSelect')or(ParamStr(I)='-ConnectionSelect')or(ParamStr(I)='-CS') Then Begin
                    CFG^.ConnectionSelect:=True;
                  End Else Begin
                    If (ParamStr(I)='--Connect')or(ParamStr(I)='-Connect')or(ParamStr(I)='-C') Then Begin
                      Inc(I);
                      CFG^.ConnectionName:=ParamStr(I);
                    End Else Begin
                      If (ParamStr(I)='--Debug')or(ParamStr(I)='-Debug') Then Begin
                        Inc(I);
                        DebugFileName:=ParamStr(I);
                        DebugLevel:=DebugNormal;
                      End Else Begin
                        If (ParamStr(I)='--DebugLevel')or(ParamStr(I)='-DebugLevel') Then Begin
                          Inc(I);
                          DebugLevel:=ParamStr(I)[1];
                        End Else Begin
                          if (ParamStr(I)='--UserName')or(ParamStr(I)='-UserName')or(ParamStr(I)='-U') then begin
                            Inc(I);
                            CFG^.UserName:=ParamStr(I);
                          end else begin
                            if (ParamStr(I)='--SaveReceivedPRNData')or(ParamStr(I)='-SaveReceivedPRNData') then begin
                              Inc(I);
                              CFG^.SaveReceivedPRNData:=ParamStr(I);
                            end else begin
                              if (ParamStr(I)='--SavePrintedPRNData')or(ParamStr(I)='-SavePrintedPRNData') then begin
                                Inc(I);
                                CFG^.SavePrintedPRNData:=ParamStr(I);
                              end else begin
                                S := Format('Unknown command line argument "%s".'#0,[ParamStr(I)]);
                                MessageBox(0,@S[1],'Error',MB_OK);
                                PrintHelp;
                              end;{-SavePrintedPRNData}
                            end;{-SaveReceivedPRNData}
                          end;{-UserName}
                        end;{-DebugLevel}
                      end;{-Debug}
                    end;{-Connect}
                  end;{-ConnectionSelect}
                end;{-CP}
              end;{-LoadDialogs}
            end;{-MSG}
          end;{-LocalINI}
        end;{-MainINI}
      end;{-SuperUser}
    end; {--help}
    Inc(I);
  End;
End;

Procedure Init;
Var
  I         : LongInt;
  Count     : Integer;
  CountCP   : Byte;
  S         : ShortString;
  Data      : TdConnectionParameters;
  PData     : PdConnectionParameters;
  CPFile    : File;
  CPArray   : PCPArray;
  C         : Char;
  _PRN      : PdPrinter;
  PPRN      : PdPrinter;
Begin
  Initialized := True;
  {Allocate datamemory --------------------------------------------------------}
  SafeGetMem(CFG,SizeOf(TConfiguration));
  SafeGetMem(ConnDef,SizeOf(TdConnectionParameters));
  ConnectionDefault(ConnDef);
  SafeGetMem(IdentCP,SizeOf(TCPArray));  For C:=#0 To #255 Do IdentCP^[C]:=C;
  CFG^.Connections              := TList.Create;
  CFG^.Terminals                := TList.Create;
  CFG^.Windows                  := TList.Create;
  CFG^.CodePageNames            := TStringList.Create;
  CFG^.CodePageNames.Sorted     := False;
  CFG^.CodePage                 := TList.Create;
  CFG^.MainName                 := '';
  CFG^.LocalName                := '';
  CFG^.MSGName                  := '';
  CFG^.CPName                   := '';
  CFG^.FTP._Enabled             := True;
  CFG^.FTP.DifferentIP._Enabled := True;
  CFG^.FTP.DifferentIP.Mode     := 1;    {Ask user}
  CFG^.FTP.FileSystem._Enabled  := True;
  CFG^.FTP.FileSystem.HomeDir   := '.';
  CFG^.FTP.FileSystem.EnabRO    := False;
  CFG^.FTP.FileSystem.RODirs    := '';
  CFG^.FTP.FileSystem.EnabRW    := False;
  CFG^.FTP.FileSystem.RWDirs    := '';
  CFG^.FTPServer                := nil;
  CFG^.PrinterProfiles          := TList.Create;
  CFG^.LocalINI                 := nil;
  CFG^.Language                 := '.cz';
  CFG^.OTP._Enabled             := True;
  CFG^.OTP.Minimum              := 20;
  SuperUser                     := False;
  LoadDialogs                   := False;
  CFG^.MainINI                  := nil;
  CFG^.MSG                      := nil;
  CFG^.ConnectionSelect         := False;
  CFG^.ConnectionName           := '';
  CFG^.KnownLang                := nil;
  CFG^.UserName                 := '';
  CFG^.DontShowPrnDBP           := False;
  CFG^.SaveReceivedPRNData      := '';
  CFG^.SavePrintedPRNData       := '';
  DebugFileName                 := '';
  DebugLevel                    := DebugNone;

  ParseArgs;

  {-- Debug file --------------------------------------------------------------}
  {$IFDEF DEBUGMSG}WriteToLog(DebugNormal,   kuSemTel_DPR, 'main', 'Begin; -- SemTel '+Version+' started ---');{$ENDIF}
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Begin');{$ENDIF}
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading configuration ...');{$ENDIF}

  {-- MainINI -----------------------------------------------------------------}
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Detecting MainINI name ...');{$ENDIF}
  If CFG^.MainName='' Then CFG^.MainName:=ExePath+ININame;
  If SuperUser Then Begin
    If not CanBeRewriten(CFG^.MainName) Then Begin
      SuperUser:=False;
      CFG^.MainName:='';
    End;
  End;
  If FileExists(CFG^.MainName) Then CFG^.MainINI:=TINIFile.Create(CFG^.MainName);
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', Format('MainINI file is = %s', [CFG^.MainName]));{$ENDIF}
  {-- LocalINI ----------------------------------------------------------------}
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Detecting LocalINI name ...');{$ENDIF}
  If not FileExists(CFG^.LocalName) Then{LocalINI wasn't specified}
    CFG^.LocalName:=WinPath+ININame;
  CFG^.LocalINI:=TINIFile.Create(CFG^.LocalName);
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', Format('LocalINI file is = %s', [CFG^.LocalName]));{$ENDIF}
  {-- MSG ---------------------------------------------------------------------}
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Detecting MSG file name ...');{$ENDIF}
  If not FileExists(CFG^.MSGName) Then CFG^.MSGName:=ExePath+MSGName; {MSG wasn't specified}
  If not FileExists(CFG^.MSGName) Then CFG^.MSGName:=WinPath+MSGName;
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', Format('MSG file is %s ...', [CFG^.MSGName]));{$ENDIF}
  {ShowMessage(CFG^.MSGName);}
  If FileExists(CFG^.MSGName) Then Begin
    CFG^.MSG:=TINIFile.Create(CFG^.MSGName);
    CFG^.KnownLang:=TStringList.Create;
    I:=0; While True Do Begin
      S:=CFG^.MSG.ReadString('LangNames', Format('Language.%d', [I]), ''); Inc(I);
      {ShowMessage(Format('Language.%d="%S"', [I, S]));}
      If S='' Then Break;
      CFG^.KnownLang.Add(S);
    End;
    CFG^.MSG.Free; CFG^.MSG:=nil;
  End Else Begin
    CFG^.MSGName:='';
    CFG^.MSG:=nil;
  End;
  {-- CP ----------------------------------------------------------------------}
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Detecting CP file name ...');{$ENDIF}
  If not FileExists(CFG^.CPName) Then{CP wasn't specified}
    CFG^.CPName:=ExePath+CPName;
  If not FileExists(CFG^.CPName) Then{CP wasn't specified}
    CFG^.CPName:=WinPath+CPName;

  If Assigned(CFG^.MainINI) Then Begin
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading MainINI: Connections ...');{$ENDIF}
    Count:=CFG^.MainINI.ReadInteger(ctConnections,ctCount,0);
    If Count>0 Then For I:=0 To Count-1 Do Begin
      SafeGetMem(PData,SizeOf(TdConnectionParameters));
      ConnectionDefault(PData);
      S:=Format('C%d.',[I+1]);
      RWConnection(False, SuperUser, CFG^.MainINI, ctConnections, S, PData);
      ConnectionAdd(PData);
    End;
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading MainINI: FTP ...');{$ENDIF}
    RWFTP(False, SuperUser, CFG^.MainINI, ctGlobal);
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading MainINI: Global ...');{$ENDIF}
    RWGlobal(False, SuperUser, CFG^.MainINI, ctGlobal);

    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading MainINI: Printers...');{$ENDIF}
    Count:=CFG^.MainINI.ReadInteger(ctPrinters,ctCount,0);
    CFG^.Printer:=CFG^.MainINI.ReadString(ctPrinters,ctPrinter,CFG^.Printer);
    If Count>0 Then For I:=0 To Count-1 Do Begin
      SafeGetMem(PPRN,SizeOf(TdPrinter));
      PrinterDefault(PPRN);
      RWPrinter(False, SuperUser, CFG^.MainINI, ctPrinters, Format('P%d',[I+1]), PPRN);
      CFG^.PrinterProfiles.Add(PPRN);
    End;

    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading MainINI: Terminals ...');{$ENDIF}
    RWTerminals(False, False, CFG^.MainINI, ctGlobal);
  End;{Load main INI}

  {Load global data from LocalINI}
  SetLanguage(CFG^.LocalINI.ReadString(ctGlobal, 'Language', CFG^.Language));
  CFG^.DontShowPrnDBP := CFG^.LocalINI.ReadBool(ctGlobal, 'DontShowPrnDBP', CFG^.DontShowPrnDBP);  
  If not SuperUser Then Begin
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading LocalINI: Connections ...');{$ENDIF}
    Count:=CFG^.LocalINI.ReadInteger(ctConnections,ctCount,0);
    Data.Environment.List:=nil;
    If Count>0 Then For I:=0 To Count-1 Do Begin
      ConnectionDefault(@Data);
      S:=Format('C%d.',[I+1]);
      RWConnection(False, SuperUser, CFG^.LocalINI, ctConnections, S, @Data);
      PData:=ConnectionFind(Data.Connection.Caption);
      If PData=nil Then Begin
        SafeGetMem(PData,SizeOf(TdConnectionParameters));
        PData^:=Data;
        ConnectionAdd(PData);
        Data.Environment.List:=nil;
      End Else Begin
        RWConnection(False, SuperUser, CFG^.LocalINI, ctConnections, S, PData);
      End;
    End;{Connections}
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading LocalINI: FTP ...');{$ENDIF}
    RWFTP(False, SuperUser, CFG^.LocalINI, ctGlobal);
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading LocalINI: Global ...');{$ENDIF}
    RWGlobal(False, SuperUser, CFG^.LocalINI, ctGlobal);
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading LocalINI: Terminals ...');{$ENDIF}
    RWTerminals(False, True, CFG^.LocalINI, ctGlobal);


    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading LocalINI: Printers ...');{$ENDIF}
    Count:=CFG^.LocalINI.ReadInteger(ctPrinters,ctCount,0);
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init',
                                  Format('Reading LocalINI: Printers count = %d', [Count]));{$ENDIF}
    CFG^.Printer:=CFG^.LocalINI.ReadString(ctPrinters,ctPrinter,CFG^.Printer);
    If Count>0 Then For I:=0 To Count-1 Do Begin
      SafeGetMem(_PRN,SizeOf(TdPrinter));
      PrinterDefault(_PRN);
      If not RWPrinter(False, SuperUser, CFG^.LocalINI, ctPrinters, Format('P%d',[I+1]), _PRN) Then Begin
        SafeFreeMem(_PRN,SizeOf(TdPrinter));
        Continue;
      End;
      PPRN:=PrinterGetP(_PRN^.ProfileName);
      {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init',
                                     Format('Reading LocalINI: Printer = %s', [_PRN^.ProfileName]));{$ENDIF}
      If PPRN=nil Then Begin
        CFG^.PrinterProfiles.Add(_PRN);
      End Else Begin
        SafeFreeMem(_PRN,SizeOf(TdPrinter));
        RWPrinter(False, SuperUser, CFG^.LocalINI, ctPrinters, Format('P%d',[I+1]), PPRN);
      End;
    End;

    {LocalINI}
    If CFG^.PrinterProfiles.Count<=0 Then Begin
      SafeGetMem(PPRN,SizeOf(TdPrinter));
      PrinterDefault(PPRN);
      CFG^.PrinterProfiles.Add(PPRN);
      CFG^.Printer:=PPRN^.ProfileName;
    End;
  End;

  {-- Load code pages ---------------------------------------------------------}
  try
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig,   'Init', 'Reading code pages ...');{$ENDIF}
    Assign(CPFile,CFG^.CPName);
    FileMode:=0;
    Reset(CPFile,1);
    BlockRead(CPFile,CountCP,1);
    For I:=1 To CountCP Do Begin {Load names}
      BlockRead(CPFile,S[1],15,Count);
      SetLength(S,strLen(@S[1]));
      CFG^.CodePageNames.Add(S);
    End;
    For I:=1 To CountCP*(CountCP-1) Do Begin {Load tables}
      SafeGetMem(CPArray,SizeOf(TCPArray));
      BlockRead(CPFile,CPArray^,SizeOf(TCPArray),Count);
      CFG^.CodePage.Add(CPArray);
    End;
    Close(CPFile);
  except
    on EInOutError Do Begin
      CFG^.CodePageNames.Free;CFG^.CodePageNames:=nil;
      CFG^.CodePage.Free;     CFG^.CodePage:=nil;
    End;
  end;
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, 'Init', 'End');{$ENDIF}
End;{Init}

Procedure Done;
Const
  MethodName = 'Done';
Var
  I     : Integer;
  S     : String;
  P     : Pointer;
  _INI  :^TINIFile;
Begin
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Begin');{$ENDIF}
  If SuperUser Then _INI:=@CFG^.MainINI Else _INI:=@CFG^.LocalINI;

  {-- Zapis konfigurace na disk -----------------------------------------------}
  if CanBeRewriten(CFG^.LocalINI.FileName) then begin
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Write - language');{$ENDIF}
    CFG^.LocalINI.WriteString('Global', 'Language', CFG^.Language);
    CFG^.LocalINI.WriteBool('Global', 'DontShowPrnDBP', CFG^.DontShowPrnDBP);
  end;

  {-- Connections -------------------------------------------------------------}
  if CanBeRewriten(_INI.FileName) then begin
    {$IFDEF DEBUGMSG}
    WriteToLog(DebugDetailed, kuSTConfig, MethodName, Format('Write - connections (%d)', [CFG^.Connections.Count]));{$ENDIF}
    _INI^.EraseSection(ctConnections);
    _INI^.WriteInteger(ctConnections,ctCount,CFG^.Connections.Count);
    If CFG^.Connections.Count>0 Then For I:=0 To CFG^.Connections.Count-1 Do Begin
      S:=Format('C%d.',[I+1]);
      RWConnection(True, SuperUser, _INI^, ctConnections, S, CFG^.Connections.Items[I]);
    End;

    {-- FTP ---------------------------------------------------------------------}
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Write - ftp');{$ENDIF}
    RWFTP(True, SuperUser, _INI^, ctGlobal);

    {-- G}
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Write - global');{$ENDIF}
    RWGlobal(True, SuperUser, _INI^, ctGlobal);

    {-- Printers ----------------------------------------------------------------}
    {$IFDEF DEBUGMSG}
    WriteToLog(DebugDetailed, kuSTConfig, MethodName, Format('Write - printers (%d)', [CFG^.PrinterProfiles.Count]));{$ENDIF}
    _INI^.EraseSection(ctPrinters);
    _INI^.WriteInteger(ctPrinters,ctCount,CFG^.PrinterProfiles.Count);
    _INI^.WriteString(ctPrinters,ctPrinter,CFG^.Printer);
    If CFG^.PrinterProfiles.Count>0 Then For I:=0 To CFG^.PrinterProfiles.Count-1 Do Begin
      S:=Format('P%d',[I+1]);
      RWPrinter(True, SuperUser, _INI^, ctPrinters, S, CFG^.PrinterProfiles.Items[I]);
    End;

    {-- Terminals ---------------------------------------------------------------}
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Write - terminals');{$ENDIF}
    RWTerminals(True, False, _INI^, ctGlobal);
  end;

  {-- Uvolneni oken telnetu ---------------------------------------------------}
  {$IFDEF DEBUGMSG}
  WriteToLog(DebugDetailed, kuSTConfig, MethodName, Format('Release - terminal windows (%d)', [CFG^.Windows.Count]));{$ENDIF}
  If Assigned(fInvisible) then begin
    For I:=0 To CFG^.Windows.Count-1 Do
      If CFG^.Windows.Items[I]<>fInvisible.MainForm Then TfMain(CFG^.Windows.Items[I]).Free;
    {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Release - main form');{$ENDIF}
    fInvisible.FreeMainForm;
    CFG^.Windows.Clear;
  end;

  {-- Uvolneni pameti ---------------------------------------------------------}
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Release - env. list');{$ENDIF}
  ConnDef^.Environment.List.Free; SafeFreeMem(ConnDef,SizeOf(TdConnectionParameters));

  {$IFDEF DEBUGMSG}
  WriteToLog(DebugDetailed, kuSTConfig, MethodName, Format('Release - connections (%d)', [CFG^.Connections.Count]));{$ENDIF}
  For I:=0 To CFG^.Connections.Count-1 Do Begin
    P:=CFG^.Connections.Items[I];
    PdConnectionParameters(P)^.Environment.List.Free;
    SafeFreeMem(P,SizeOf(TdConnectionParameters));
    CFG^.Connections.Items[I]:=P;
  End; CFG^.Connections.Clear;

  {$IFDEF DEBUGMSG}
  WriteToLog(DebugDetailed, kuSTConfig, MethodName, Format('Release - printers (%d)', [CFG^.PrinterProfiles.Count]));{$ENDIF}
  For I:=0 To CFG^.PrinterProfiles.Count-1 Do Begin
    P:=CFG^.PrinterProfiles.Items[I];
    SafeFreeMem(P, SizeOf(TdPrinter));
    CFG^.PrinterProfiles.Items[I]:=P;
  End;
  CFG^.PrinterProfiles.Clear;

  {$IFDEF DEBUGMSG}
  WriteToLog(DebugDetailed, kuSTConfig, MethodName, Format('Release - terminals (%d)', [CFG^.Terminals.Count]));{$ENDIF}
  For I:=0 To CFG^.Terminals.Count-1 Do Begin
    P:=CFG^.Terminals.Items[I];
    SafeFreeMem(P, SizeOf(TTerminal));
    CFG^.Terminals.Items[I]:=P;
  End;
  CFG^.Terminals.Clear;

  If Assigned(CFG^.CodePage) Then Begin
    {$IFDEF DEBUGMSG}
    WriteToLog(DebugDetailed, kuSTConfig, MethodName, Format('Release - code pages', [CFG^.CodePage.Count]));{$ENDIF}
    For I:=0 To CFG^.CodePage.Count-1 Do Begin
      P:=CFG^.CodePage.Items[I];
      SafeFreeMem(P, SizeOf(TCPArray));
      CFG^.CodePage.Items[I]:=P;
    End;
    CFG^.CodePage.Clear;
  End;

  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Release - other windows');{$ENDIF}
  fOpenANSI.Free; fOpenANSI := nil;
  fOTPCalc.Free; fOTPCalc := nil;
  fOneLineDlg.Free; fOneLineDlg := nil;
  fSelectConnection.Free; fSelectConnection := nil;
  fPrinterSetupDialog.Free; fPrinterSetupDialog := nil;
  fConnectionParameters.Free; fConnectionParameters := nil;
  fEditHotKey.Free; fEditHotKey := nil;
  fSelectIP.Free; fSelectIP := nil;
  fPGPPublicKey.Free; fPGPPublicKey := nil;
  fQuickConnect.Free; fQuickConnect:=nil;
  fInvisible.Free; fInvisible := nil;
  fNetworkPrinterInDirectModeSelect.Free; fNetworkPrinterInDirectModeSelect := nil;

  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Release - CFG');{$ENDIF}
  CFG^.Windows.Free; CFG^.Windows:=nil;
  CFG^.Terminals.Free; CFG^.Terminals:=nil;
  CFG^.Connections.Free; CFG^.Connections:=nil;
  CFG^.CodePageNames.Free; CFG^.CodePageNames:=nil;
  CFG^.CodePage.Free; CFG^.CodePage:=nil;
  CFG^.PrinterProfiles.Free; CFG^.PrinterProfiles:=nil;
  CFG^.LocalINI.Free; CFG^.LocalINI:=nil;
  CFG^.MainINI.Free; CFG^.MainINI:=nil;
  CFG^.MSG.Free; CFG^.MSG:=nil;
  SafeFreeMem(CFG,SizeOf(PConfiguration)); CFG:=nil;

  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'Release - IdentCP');{$ENDIF}
  SafeFreeMem(IdentCP,SizeOf(TCPArray)); IdentCP:=nil;
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, MethodName, 'End');{$ENDIF}
End;{Done}

Function IsMSGFile:Boolean;
Begin
  If CFG<>nil Then Result := CFG^.MSG<>nil Else Result:=False;
End;{IsMSGFile}

Procedure SetLanguage(S:String);
Var
  Name : String;
  Path : ShortString;
Begin
  {ShowMessage(Format('Switching to language %s.', [S]));}
  If CFG^.MSGName='' Then Exit;
  If Assigned(CFG^.MSG) Then CFG^.MSG.Destroy;
  Path := ExtractFileDir(CFG^.MSGName);
  if Path[Length(Path)]<>'\' then Path:=Path+'\';
  Name := Path+'SemTel'+UpperCase(Copy(S, 2, 2))+'.lng';
  {$IFDEF DEBUGMSG}WriteToLog(DebugDetailed, kuSTConfig, 'SetLanguage', Name);{$ENDIF}
  CFG^.MSG := TINIFile.Create(Name);
  CFG^.Language := S;

  ctError         := CFG^.MSG.ReadString('Global','Error',ctError)+#0;
  ctWarning       := CFG^.MSG.ReadString('Global','Warning',ctWarning)+#0;
  ctQuestion      := CFG^.MSG.ReadString('Global','Question',ctQuestion)+#0;
  ctInformation   := CFG^.MSG.ReadString('Global','ctInformation',ctInformation)+#0;
  ctbtnOk         := CFG^.MSG.ReadString('Global','btnOk',ctbtnOk);
  ctbtnCancel     := CFG^.MSG.ReadString('Global','btnCancel',ctbtnCancel);
  ctNoMainTermFile:= CFG^.MSG.ReadString('Global','ctNoMainTermFile',ctNoMainTermFile);
  ctNoIncTermFile := CFG^.MSG.ReadString('Global','ctNoIncTermFile',ctNoIncTermFile);
End;

Function LoadList(INI:TINIFile;Section,BaseName:String):TStringList;
Var
  I,J : Integer;
  S   : String;
Begin
  Result:=nil;
  I:=INI.ReadInteger(Section,BaseName+'_no',0);
  If I<=0 Then Exit;
  Result:=TStringList.Create;
  Result.Sorted:=False;
  For J:=0 To I-1 Do
   Begin
     S := INI.ReadString(Section, BaseName+IntToStr(J), Format('Tab %d',[J]));
     Result.Add(S);
   End;
End;

Function AllocateDialog(DT:TDialogType):Boolean;
Procedure ShowError(Const Caption:String);
Var
  S : ShortString;
Begin
  S := Format('Dialog "%s" is allredy visible.'#0,[Caption]);
  MessageBox(Application.Handle,@S[1],nil,MB_OK);
End;

Var
  OldCursor : TCursor;
Begin
  OldCursor        := Screen.Cursor;
  Screen.Cursor    := crHourGlass;
  Result           := False;
  Case DT of
    _fOpenANSI           : If not Assigned(fOpenANSI) Then Begin
       fOpenANSI            := TOpenDialog.Create(Application);
       fOpenANSI.Name       := 'OpenANSI';
       fOpenANSI.Tag        := 1;
       fOpenANSI.Filter     := 'ANSI soubor|*.ans';
       fOpenANSI.InitialDir := 'ansi';
       fOpenANSI.Options    := [ofHideReadOnly, ofPathMustExist, ofFileMustExist];
       Result               := True;
    End Else Begin
       Result := True; {???}
       If not Result Then ShowError(fOpenANSI.Name);
    End;
    _fOTPCalc : If not Assigned(fOTPCalc) Then Begin
       fOTPCalc := TfOTPCalc.Create(Application);
       fOTPCalc.MSGFile  := @STConfig.CFG^.MSG;
       fOTPCalc.INIFile  := @STConfig.CFG^.LocalINI;
       fOTPCalc.ReadMSG;
       Result := True;
    End Else Begin
       Result := not fOTPCalc.Visible;
       If not Result Then ShowError(fOTPCalc.Caption);
    End;{_fOTPCalc-------------------------------------------------------------}
    _fEnterOneLineDlg : If not Assigned(fOneLineDlg) Then Begin
       fOneLineDlg := TfOneLineDlg.Create(Application);
       fOneLineDlg.MSGFile := @STConfig.CFG^.MSG;
       fOneLineDlg.INIFile := @STConfig.CFG^.LocalINI;
       fOneLineDlg.ReadMSG;
       Result := True;
    End Else Begin
       Result := not fOneLineDlg.Visible;
       If not Result Then ShowError(fOneLineDlg.Caption);
    End;{_fEnterOneLineDlg-----------------------------------------------------}
    _fSelectConnection : If not Assigned(fSelectConnection) Then Begin
       fSelectConnection := TfSelectConnection.Create(nil);
       fSelectConnection.MSGFile := @STConfig.CFG^.MSG;
       fSelectConnection.INIFile := @STConfig.CFG^.LocalINI;
       fSelectConnection.ReadMSG;
       Result :=True;
    End Else Begin
       Result := not fSelectConnection.Visible;
       If not Result Then ShowError(fSelectConnection.Caption);
    End;{_fSelectConnection----------------------------------------------------}
    _fPrinterSetupDialog : If not Assigned(fPrinterSetupDialog) Then Begin
       fPrinterSetupDialog := TPrinterSetupDialog.Create(Application);
       Result := True;
    End Else Begin
       Result := {not fPrinterSetupDialog.Visible}True;
       If not Result Then ShowError('Printer setup dialog');
    End;{_fPrinterSetupDialog--------------------------------------------------}
    _fConnectionParameters : If not Assigned(fConnectionParameters) Then Begin
       fConnectionParameters := TfConnectionParameters.Create(Application);
       fConnectionParameters.SuperUserMode := SuperUser;
       fConnectionParameters.MSGFile := @STConfig.CFG^.MSG;
       fConnectionParameters.INIFile := @STConfig.CFG^.LocalINI;
       fConnectionParameters.ReadMSG;
       Result := True
     End Else Begin
       Result := not fConnectionParameters.Visible;
       If not Result Then ShowError(fConnectionParameters.Caption);
     End;{fConnectionParameters------------------------------------------------}
    _fEditHotKey : If not Assigned(fEditHotKey) Then Begin
       fEditHotKey := TfEditHotKey.Create(Application);
       Result := True;
    End Else Begin
       Result := not fEditHotKey.Visible;
       If not Result Then ShowError(fEditHotKey.Caption);
    End;{_fEditHotKey----------------------------------------------------------}
    _fSelectIP : If not Assigned(fSelectIP) Then Begin
       fSelectIP := TfSelectIP.Create(Application);
       fSelectIP.MSGFile := @STConfig.CFG^.MSG;
       fSelectIP.INIFile := @STConfig.CFG^.LocalINI;
       fSelectIP.ReadMSG;
       Result := True;
    End Else Begin
       Result := not fSelectIP.Visible;
       If not Result Then ShowError(fSelectIP.Caption);
    End;{_fSelectIP------------------------------------------------------------}
    _fPGPPublicKey : If not Assigned(fPGPPublicKey) Then Begin
       fPGPPublicKey := TfPGPPublicKey.Create(Application);
       fPGPPublicKey.MSGFile := @STConfig.CFG^.MSG;
       fPGPPublicKey.INIFile := @STConfig.CFG^.LocalINI;
       fPGPPublicKey.ReadMSG;
       Result := True;
    End Else Begin
       Result := not fPGPPublicKey.Visible;
       If not Result Then ShowError(fPGPPublicKey.Caption);
    End;{_fSelectIP------------------------------------------------------------}
    _fQuickConnect: If not Assigned(fQuickConnect) Then Begin
       fQuickConnect := TfQuickConnect.Create(Application);
       fQuickConnect.MSGFile := @STConfig.CFG^.MSG;
       fQuickConnect.INIFile := @STConfig.CFG^.LocalINI;
       fQuickConnect.ReadMSG;
       Result := True;
    End Else Begin
       Result := not fQuickConnect.Visible;
       If not Result Then ShowError(fQuickConnect.Caption);
    End;{_fSelectIP------------------------------------------------------------}
    _fNetworkPrinterInDirectModeSelect: If not Assigned(fNetworkPrinterInDirectModeSelect) Then Begin
       fNetworkPrinterInDirectModeSelect := TfNetworkPrinterInDirectModeSelect.Create(Application);
       fNetworkPrinterInDirectModeSelect.MSGFile := @STConfig.CFG^.MSG;
       fNetworkPrinterInDirectModeSelect.INIFile := @STConfig.CFG^.LocalINI;
       fNetworkPrinterInDirectModeSelect.ReadMSG;
       Result := True;
    End Else Begin
       Result := not fNetworkPrinterInDirectModeSelect.Visible;
       If not Result Then ShowError(fNetworkPrinterInDirectModeSelect.Caption);
    End;{_fNetworkPrinterInDirectModeSelect -----------------------------------}

  End;
  Screen.Cursor    := OldCursor;
End;{-- AllocDialog -----------------------------------------------------------}

Procedure DeallocateDialog;
Begin
  ShowWindow(Application.Handle, SW_HIDE);
End;

Function  WindowGetActive:TForm;
Var
  I : Integer;
  M : TfMain;
Begin
  Result:=nil;
  If CFG^.Windows.Count>0 Then
   For I:=0 To CFG^.Windows.Count-1 Do Begin
     M := CFG^.Windows.Items[I];
     If M.Active Then Begin Result:=M; Exit End;
   End;
End;

Procedure WindowSetParameters;
Var
  I : Integer;
  M : TfMain;
Begin
  If CFG^.Windows.Count>0 Then
   For I:=0 To CFG^.Windows.Count-1 Do Begin
     M := CFG^.Windows.Items[I];
     M.SetParameters;
   End;
End;

Procedure PrinterDefault(Printer:PdPrinter);
Var
  I : Integer;
  S : String;
Begin
  Printer^._Enabled      := True;
  Printer^.ProfileName   := '(default)';
  If Printers.Printer.Printers.Count>0 Then Begin
    I:=Printers.Printer.PrinterIndex;
    S:=Printers.Printer.Printers[I];
    Printer^.PrinterName := '';
  End Else
    Printer^.PrinterName := '';
  Printer^.CharsetE      := True;
  Printer^.HCharset      := 'ISO-8859-2';
  Printer^.LCharset      := 'ASCII';
  Printer^.LineArtE      := False;
  Printer^.LineArt       := 'ISO-8859-2 => ASCII';
  Printer^.AccessMode    := 1;
  Printer^.CR2CRLF       := True;
  Printer^.LF2CRLF       := True;
  Printer^.FontName      := 'Courier New';
  Printer^.FontSize      := 8;
  Printer^.InitFile      := '';
  Printer^.DoneFile      := '';
End;

Procedure PrinterList(List:TStrings);
Var
  I : Integer;
  P : PdPrinter;
Begin
  List.Clear;
  If CFG^.PrinterProfiles.Count=0 Then Exit;
  For I:=0 To CFG^.PrinterProfiles.Count-1 Do Begin
    P:=CFG^.PrinterProfiles.Items[I];
    List.Add(P^.ProfileName);
  End;
End;

Function  PrinterGetP(Const ProfileName:String):PdPrinter;
Var
  I : Integer;
Begin
  Result:=nil;
  If CFG^.PrinterProfiles.Count=0 Then Exit;
  For I:=0 To CFG^.PrinterProfiles.Count-1 Do Begin
    Result:=CFG^.PrinterProfiles.Items[I];
    If Result^.ProfileName=ProfileName Then Exit;
  End;
  Result:=nil;
End;

Function EnvGetVariable(Const S:String):String;
Begin
  If Pos('=', S)>0 Then
    Result := Copy(S, 1, Pos('=', S)-1)
  Else
    Result := S;
End;

Function EnvGetValue(Const S:String):String;
Begin
  If Pos('=', S)>0 Then
    Result := Copy(S, Pos('=', S)+1, Length(S))
  Else
    Result := '';
End;

Function EnvGetValueFromOS(Const S:String):String;
Var
  P : PChar;
  S1: String;
Begin
  {$IFDEF WIN32} P := GetEnvironmentStrings; {$ELSE} P := GetDOSEnvironment; {$ENDIF}
  Result:='';
  While P^ <> #0 Do Begin
    S1:=StrPas(P);
    If EnvGetVariable(S1)=S Then Result:=EnvGetValue(S1);
    Inc(P, lStrLen(P)+1);
  End;
  {$IFDEF WIN32} FreeEnvironmentStrings(p); {$ENDIF}
End;

Function EnvGetValueFromList(SL:TStringList;Const S:String):String;
Var
  I : Integer;
Begin
  I := EnvFindVariable(SL, S);
  If I>=0 Then Result:=EnvGetValue(SL.Strings[I]) Else Result:='';
End;


Function EnvFindVariable(SL:TStringList;Const S:String):Integer;
Var
  I : Integer;
  S1: String;
Begin
  Result:=-1;
  S1:=EnvGetValue(S);
  S1:=EnvGetVariable(S);
  For I:=0 To SL.Count-1 Do If S1=EnvGetVariable(SL.Strings[I]) Then Begin
    Result:=I;
    Break
  End;
End;

Procedure EnvReplaceVariable(SL:TStringList;Const S:String);
Var
  I : Integer;
  B : Boolean;
Begin
  B:=SL.Sorted;
  SL.Sorted:=False;
  I:=EnvFindVariable(SL, S);
  If I>=0 Then SL.Delete(I);
  SL.Add(S);
  SL.Sorted:=B;
End;

Procedure WindowHideMain;
Begin
  DeallocateDialog;
End;

Function StringsFindNearest(Strings:TStrings; Const S:String; Numeric:Boolean):Integer;
Var
  I, J    : Integer;
Begin
  I := Strings.IndexOf(S);
  If I=-1 Then Begin{.. Najit nejblizsi ..}
    If Strings.Count<=1 Then Result := 0
    Else Begin
      J:=0;
      For I:=0 To Strings.Count-1 Do Begin
        If Numeric Then Begin
          If StrToInt(Strings.Strings[I])>=StrToInt(S) Then Break;
        End Else Begin
          If Strings.Strings[I]>=S Then Break;
        End;
        J:=I;
      End;
      Result:=Strings.IndexOf(Strings.Strings[J]);
    End;
  End Else Begin{.. Existuje v seznamu ..}
    Result := I;
  End;
End;

end.
