{$IFNDEF OS2}
{$O+,F+}
{$ENDIF}
{$I-}

Unit tMainOvr;

{*********************************************************}
{*                    TMAINOVR.PAS                       *}
{*                                                       *}
{*  Copyright (c) Konstantin Klyagin, 1995-98,           *}
{*                exspecially for Tornado BBS System     *}
{*                                                       *}
{*********************************************************}

Interface

Uses
{$IFDEF MSDOS}
  Streams,
  Vector,
  tDebug,
{$ELSE}
  Telnet,
{$ENDIF}
{$IFDEF OS2}
  Os2Base,
  VPUtils,
  tRexx,
{$ENDIF}
{$IFNDEF WIN32}
  aDir,
  UserEd,
  DOS,
  ApSame,
  ApAbsPcl,
  ApCom,
  ApTimer,
  Iface,
  tWin,
  iLine,
{$ELSE}
  Classes,
  Windows,
  SysUtils,
  ooMisc,
  Forms,
  AppExec,
  Console,
  WApro,
{$ENDIF}
  OpCrt,
  MainComm,
  tGlob,
  tMisc,
  tModem,
  Log,
  Resource,
  Areas,
  Parser,
  Parse,
  Users,
  FilesBBS,
  tMenus,
  Protocol,
  MKOpen,
  Shell,
  SaveTag,
  Upgrader,
  torMacro,
  torInOut,
  TimeTask,
  DoReg,
  Objects,
  mFind,
  tMsgLib,
  MainCOVr,
{$IFDEF AUTHOR}
{.$IFNDEF WIN32}
  tHTML,
{.$ENDIF}
{$ENDIF}
  tQWK,
  IEMSI,
  {Protect,}
  {$IFDEF SOUND}
  {$IFDEF MSDOS}
  soundlib,
  {$ENDIF}
  {$ENDIF}
  tScript;

Var
  ReqName   : String [36];
  PrevLang  : String [ 8];
  MenuFile  : Str8;

Procedure InitTMainOvr;

Procedure Login;
Procedure ChangeParam (ParNum: Byte);
Function EnterPass (Msg: String; NewUser: Boolean): String;
Procedure ChooseLang;
Procedure DoMenu (Var FileName: Str8);
Procedure DoBBS;
Procedure ErrorExit;
Procedure Lockout;
Procedure InsDisp (S: PathStr);
Procedure AnalyzeKey (C: Char);
Procedure IncTime;
Procedure DecTime;
Procedure IncKBLD;
Procedure DecKBLD;

{$IFNDEF WIN32}
Procedure ManualSend;
Procedure ViewTagList;
Procedure UEdit;
Procedure Help;
Procedure AccessLevel;
Procedure InsertFile;
{$ELSE}
Procedure ShowUsualBar;
Procedure ShowPasswordBar (S1, S2: String);
{$ENDIF}

{$IFNDEF OS2}
Function tExecRexx (S: PathStr): Boolean;
{$ENDIF}

Implementation

{$IFDEF WIN32}
Uses
  tor32u;
{$ENDIF}

Type
  PLangDesc = ^TLangDesc;
  TLangDesc = Record
    Name     : String [33];
    FileName : PathStr;
  End;

  PLangDescCollection = ^TLangDescCollection;
  TLangDescCollection = Object (TSortedCollection)
                          Function Compare (Key1, Key2: Pointer):
                          {$IFNDEF OS2} Integer; {$ELSE} LongInt; {$ENDIF}
                          Virtual;
                        End;

  PT = Procedure;
  ScrArr = Array [1..65535] Of Char;

  PScreenSave = ^TScreenSave;
  TScreenSave = Record
    SaveX, SaveY,
    Attribute     : Byte;
    svStatusBar   : Boolean;
    P             : ^ScrArr;
  End;

Var
  Err : SysInt;
  KolPass : Byte;
  TimeExeded, VIPinformed, VIPcheck : Boolean;
  TimeLeft : LongInt;
  ScrSave : tScreenSave;
  PScrSave : ^tScreenSave;

{$IFDEF OS2}

Function PreThread (P : Pointer): LongInt;
Begin
  PreThread := 0;
  ThreadLocked := True;

  SetInput (False, Not Local);
  SetOutput (False, Not Local);

  PT (P);

  If Not Local Then ClrScr;
  ThreadLocked := False;

  SetInput (True, Not Local);
  SetOutput (True, Not Local);
End;

{$ELSE}

Function tExecRexx (S: PathStr): Boolean;
Begin
  tExecRexx := False;
End;

{$ENDIF}

{$IFNDEF WIN32}
Procedure ThreadStart (P : PT);
Var
  TID   : LongInt;

Begin
{$IFNDEF OS2}
  P;
{$ELSE}
  BeginThread (Nil, 25600, PreThread, @P, 0, TID);
{$ENDIF}
End;
{$ENDIF}

Procedure ClearReps;
Var
  S     : PathStr;
  i     : LongInt;

Begin
  For i := 0 To Reps^. Count-1 Do
  Begin
    S := GetStr (Reps^. At (i));
    S := Copy (S, Pos (#255, S)+1, 255);
    tDeleteFile (S);
  End;

  Reps^. FreeAll;
  Reps^. DeleteAll;
End;

Procedure VeryImportant;
Var
  i                     : Byte;
  BoxDrawed             : Boolean;

Begin
  If Not VIPinformed Then
  Begin
    BoxDrawed := False;

    If Not Local Then
    If ((R. Name = 'Konstantin Klyagin') And (Crc32Str (R. Name) = -1762682936)) Then
    Begin
      LogWrite ('!', sm (smAuthor));
      BoxDrawed := True;
    {$IFNDEF WIN32}
      CenterDelayTempBox (Cnf. ColorScheme [caFrame], Cnf. ColorScheme
        [caText], 1, CenterCh (sm (smAuthor), ' ', 30), ZoomSpeed, '');
    {$ENDIF}
    End;

    If InList (Cnf. VIPList, R. Name) and (Not BoxDrawed) Then
    Begin
      LogWrite ('!', sm (smVIP));
      BoxDrawed := True;
    {$IFNDEF WIN32}
      CenterDelayTempBox (Cnf. ColorScheme [caFrame], Cnf. ColorScheme [caText], 1,
                          CenterCh (sm (smVIP), ' ', 30), ZoomSpeed, '');
    {$ENDIF}
    End;

    If BoxDrawed Then
    Begin
      If Cnf. Sound Then Begin
      {$IFDEF WIN32}
        MainForm. PlayerWave1. Stop;
        MainForm. PlayerWave1. WaveName := Cnf. Path + 'vip.wav';
        MainForm. PlayerWave1. Loop := False;
        MainForm. PlayerWave1. Async := True;
        MainForm. PlayerWave1. Play;
      {$ELSE}
        {$IFDEF SOUND}
        {$IFDEF MSDOS}
        If UseWav Then initblaster else blaster. available := False;
        if blaster. available then
          if opensound (0, Cnf. Path + 'vip.wav') then begin{Open parameter 1 file as file 0}
            startplay(0);                       {start playback of file 0}
            repeat
            until (play.stopped); {Until file reached its end}
            closesound(0);                        {close file 0}
          end else
            blaster. available := false
        else
        {$ENDIF}
        {$ENDIF}
        Begin
          SoundOf ('4 3500 0 50 1 3000 0 50 1 4000 0 5 1');
          For i := 1 To 6 Do
          Begin
            If KeyPressed Then Break;
            If Cnf. Sound Then
            Begin
              Pause (500);
              SoundOf ('1 500 0 2 1');
            End;
          End;
        End;
      {$ENDIF}
      End;

    {$IFNDEF WIN32}
      DoneTempBox;
    {$ENDIF}
    End;

    VIPinformed := True;
  End;
End;

Procedure SetXLAT (FName: PathStr);
Var
  i : LongInt;

Begin
  ScreenOut^. XLATenabled := False;

  With XLATs^ Do
  For i := 0 To Count-1 Do
  If UpString (PXLATrec (At (i))^. FileName) = UpString (FName) Then
  Begin
    ScreenOut^. XLAT := PXLATrec (At (i))^. Table;
    ScreenOut^. XLATenabled := True;
    Break;
  End;
End;

Procedure SetLanguage;
Var
  DirInfo       : {$IFNDEF WIN32} SearchRec {$ELSE} TSearchRec {$ENDIF};
  Found         : Boolean;

Begin
  Found := False;
{$IFDEF WIN32}
  DOSerror :=
{$ENDIF}
  FindFirst (Cnf. LngPath + '*.lng', AnyFile-Directory, DirInfo);
  While DosError = 0 Do
  Begin
    Found := Found Or (UpString (JustName (DirInfo. Name)) = UpString (R. Lang));

  {$IFDEF WIN32}
    DOSerror :=
  {$ENDIF}
    FindNext (DirInfo);
  End;

{$IFDEF OS2}
  FindClose (DirInfo);
{$ENDIF}

  If Not Found Then ChooseLang;
  ReadLanguage (Language, Cnf. LngPath + LoString (R. Lang) + '.lng');
  If R. XLAT <> '' Then SetXLAt (R. XLAT);
End;

Procedure oDispFile (S: String);
Begin
  EmuDispFile (S);
End;

Procedure oExecScript (S: String);
Begin
  ExecScript (S);
  ScreenOut^. UseMacroTable1 := True;
  ScreenOut^. UseMacroTable2 := True;
  ScreenOut^. UseMacroTable3 := True;
End;

Procedure DoBBS;
Var
  X : tArr255;

Begin
  LastClock := MidSec;
  HiddenCursor;
  SetTitle ('logging in');

  R. Emu := teTty;
  R. More := False;
  R. Lang := '';
  R. LastDate := 0;
  R. LastTime := 0;
  R. FirstDate := 0;
  R. BirthDate := 0;
  HotKeysStr := '';
  Language := New (PBigCollection, Init (217, 1));
  ReadHistory := New (PBigCollection, Init (5, 2));
  R. Lang := UpString (JustName (Cnf. DefLangFile));

  ScreenOut :=
    New (PTorInOut, Init (oPort, oScreen, soPort, soScreen, EmuColor,
         oDispFile, oExecScript, 4096, X, False, NewMacroTable (
         NewMacro ('SYSO', Cnf. SysOp,
         NewMacro ('BBSN', Cnf. BBSname,
         NewMacro ('DATE', ReFormatDate (StrDate, 'DD-MM-YYYY', Cnf. DateMask),
         NewMacro ('TIME', StrTime,
         NewMacro ('FRAM', lang (laNo),
         NewMacro ('BAUD', Long2Str (GetConnectSpeed),
         NewMacro ('LANG', lang (laName),
         NewMacro ('PROD', NameVer,
         NewMacro ('USRS', Long2Str (uNum),
         NewMacro ('NODE', Long2Str (BbsLine),
    Nil)))))))))))));

  SetLanguage;
  ScreenOut^. UseMacroTable2 := False;
  ScreenOut^. StopBuffering;

  If Not Local Then
  Begin
    SetInput (True, True);
    SetOutput (True, True);
  {$IFNDEF WIN32}
    SetAbortFunc (P, KbdAbort);
  {$ENDIF}
  End Else
  Begin
    SetInput (True, False);
    SetOutput (True, False);
  End;

  If (Not Local) and (Cnf. DetectEmu = ynAuto) Then
{$IFNDEF WIN32}
  AddMsg (Copy (StrTime, 1, 5) + sm (smTestEmu), False, Cnf. ColorScheme [cmUsers]);
{$ENDIF}

  If Not Local Then
  Begin
    If Cnf. DetectEmu = ynAuto Then
    Begin
      If RemoteAnsiDetected Then R. Emu := teAnsi Else R. Emu := teTty;
    End Else
    If Cnf. DetectEmu = ynYes Then R. Emu := teAnsi Else
    If Cnf. DetectEmu = ynNo Then R. Emu  := teTty;
  End Else
    R. Emu := teAnsi;

  SetEmulation;
  If Not Local Then
{$IFNDEF WIN32}
  AddMsg (' [' + EmuName [R. Emu] + ']', False, Cnf. ColorScheme [cmUsers])
{$ENDIF};

  StatusBar := Cnf. StatusBar;
  StatusBarEnable := True;
  EnterTime := MidSec;
  enTime := MidSec;
  TextAttr := $07;
  SetCrtColor;
  ClrScr;

{$IFNDEF WIN32}
  If Cnf. StatusBar Then Window (1, 1, 80, ScrY - 1);
{$ENDIF}

  ShowStatusBar;
  NormalCursor;

  If (Not Local) And (GetConnectSpeed < Cnf. MinSpeed) Then
  Begin
    EmuDispFile ('~tooslow');
    LogWrite ('!', sm (smlTooSlow));
    ExecScript ('onexit');
    If Not Local Then Pause (2000);
    NormExit;
  End;

  Login;

{$IFDEF WIN32}
  If Application. Terminated Then Exit;
{$ENDIF}

  Ent := DateL;
  EntT := Time2Word(StrTime);

  If (RunScript <> '') Or (RunRexx <> '') Then
  Begin
    If RunScript <> '' Then ExecScript (RunScript);
    If RunRexx <> '' Then ExecRexx (RunRexx);
    NormExit;
  End Else
  Begin
    If Not R. Guest Then Upgrade;
    UpdateUserMacro;

    If RestoreTagList Then
    Begin
      UpdateUserMacro;
      DownLoad;
    End;

    MenuFile := LoString (Cnf. MainMenu);
    Menus := New (PNotSortedCollection, Init (10, 1));

    If Not (Local And Cnf. FastLogon) Or Not Local Then
    Begin
      If ToEventTime <> 0 Then
      Begin
        SmartLine;
        Message (lang (laToEventLeft) + Long2Str (ToEventTime) + ' ' + lang (laMinutes));
      End;

      EmuDispFile ('~welcome');
      ComWriteLn ('', 0);
      ExecScript ('welcome');
      ExecRexx ('welcome');

      If Not EMSI. Session Then
      Begin
        If Cnf. ScanPrivMail = atAsk Then
        If Query (lang (laSearchPrivateMsg), True, ofFramed) Then SearchPrivate;
     {$IFDEF WIN32}
        If Application. Terminated Then Exit;
     {$ENDIF}
        If Cnf. ScanPrivMail = atYes Then SearchPrivate;
      End Else
        If EMSI. CheckMail Then SearchPrivate;

      If Not EMSI. Session And (R. NoCalls > 1) Then
      Begin
        If Cnf. ScanNewFiles <> atNo Then GlobalSearch ('*.*', True, Cnf. ScanNewFiles, '1');
      {$IFDEF WIN32}
        If Application. Terminated Then Exit;
      {$ENDIF}
      End Else
        If EMSI. CheckNewFiles Then GlobalSearch ('*.*', True, atYes, '');

      If Cnf. ShowNews <> tnNo Then News (R. NoCalls <> 1);
    End;

    EmuDispFile ('~start');
    ExecScript ('start');
    ExecRexx ('start');

    mL_SendMsg (0, trcSysMsgPrefix + '** ' + R. Name + lang (laTRCline) +
    Long2Str (BbsLine) + lang (laTRCentered), mtConference);

    While {$IFNDEF WIN32} True {$ELSE} Not Application. Terminated {$ENDIF} Do
    Begin
      ComWrite (EmuColor (3), 0);
      DoMenu (MenuFile);
    End;
  End;
End;

Function EnterPass (Msg: String; NewUser: Boolean): String;
Var
  S     : String [40];
  C     : Char;
  oStat : Boolean;
{$IFDEF WIN32}
  S1    : String;
{$ENDIF}

Label
  Loop;

Begin
  oStat := StatusBar;
  StatusBarEnable := False;
  Inc (KolPass);

  If KolPass = Cnf. PassTryes + 1 Then
  Begin
    If (Not R. Frames) or (EmuGoToXY (1, 1) = '') Then ComWriteLn ('', 0);
    If Query (lang (laOutOfTryes), True, ofFramed) Then Msg2SysOp ('Password error.');
    ExecScript ('onexit');
    NormExit;
    Exit;
  End;

  EnteringPass := True;

  Loop:
  Clock2;

{$IFNDEF WIN32}
  If StatusBar Then
    FastWrite (sm (smEntering) + Replicate (' ', 80 -
      Length (sm (smEntering))), ScrY, 1, Cnf.
      ColorScheme [cmStatusLine]);

  If Trim (R. Password) <> '' Then
  Begin
    If StatusBar Then
       FastWrite (sm (smPassMustBe) + R. Password +
                  Replicate (' ', 80 - Length (R.Password + sm (smPassMustBe))),
                  ScrY + 1, 1, Cnf. ColorScheme [cmStatusLine]);
  End
  Else If StatusBar Then
          FastWrite (Replicate (' ', ScrX + 1), ScrY + 1, 1, Cnf. ColorScheme
                     [cmStatusLine]);
{$ELSE}
  If Trim (R. Password) <> '' Then
    S1 := TrimLead (sm (smPassMustBe)) + R. Password
  Else
    S1 := '';

  ShowPasswordBar (TrimLead (sm (smEntering)), S1);
{$ENDIF}

  Frame;
  ComWrite (Msg, eoMacro + eoCodes);

  If VIPcheck Then VeryImportant;

  S := '';
  Repeat
    C := ComReadKey;
  {$IFDEF WIN32}
    If Application. Terminated Then Exit;
  {$ENDIF}

    {C := LoCase (C);}
    If C > #31 Then
    Begin

      If Length (S) < Cnf. PassMaxLength Then
      Begin
        S := S + C;
        ComWrite ('þ', 0);
      {$IFNDEF WIN32}
        If StatusBar Then
          FastWrite (S + Replicate (' ', 40 - Length (S)), ScrY,
          Length (sm (smEntering)) + 1, Cnf.
          ColorScheme [cmStatusLine]);
      {$ELSE}
        MainForm. Label1. Caption := TrimLead (sm (smEntering)) + S;
      {$ENDIF}
      End;
    End Else
    Begin
      If C = #8 Then
      Begin
        If Length (S) > 0 Then
        Begin
          S := Copy (S, 1, Length (S) - 1);
          ComWrite (#8#32#8, 0);
        {$IFNDEF WIN32}
          If StatusBar Then
            FastWrite (S + Replicate (' ', 40 - Length (S)), ScrY,
            Length (sm (smEntering)) + 1, Cnf. ColorScheme [cmStatusLine]);
        {$ELSE}
          MainForm. Label1. Caption := TrimLead (sm (smEntering)) + S;
        {$ENDIF}
        End;
      End;
      If C = #0 Then Continue;
      If C = #24 Then
      Begin
        ComWrite (Replicate (#8, Length (S)) + EmuClrEoL, 0);
        S := '';
      {$IFNDEF WIN32}
        If StatusBar Then
          FastWrite (Replicate (' ', 40), ScrY,
          Length (sm (smEntering)) + 1,
          Cnf. ColorScheme [cmStatusLine]);
      {$ELSE}
        MainForm. Label1. Caption := TrimLead (sm (smEntering)) + S;
      {$ENDIF}
      End;
    End;
  Until C = #13;

  If (Length (S) < Cnf. PassLength) and NewUser Then
  Begin
    ComWriteLn ('|' + lang (laPassTooShort1) + Long2Str (Cnf. PassLength) +
                lang (laPassTooShort2), eoMacro + eoCodes);
    GoTo Loop;
  End;

  EnterPass := S;

{$IFNDEF WIN32}
  If StatusBar Then
  Begin
    FastWrite (Replicate (' ', ScrX + 1), ScrY, 1, $07);
    FastWrite (Replicate (' ', ScrX + 1), ScrY + 1, 1, $07);
  End;
{$ENDIF}

  StatusBarEnable := True;

  StatusBar := Not oStat;
{$IFNDEF WIN32}
  SwitchStatusBar;
{$ENDIF}
  Clock2;
  EnteringPass := False;
  ComWriteLn ('', 0);

{$IFDEF WIN32}
  ShowUsualBar;
{$ENDIF}
End;

Function TLangDescCollection. Compare (Key1, Key2: Pointer):
         {$IFNDEF OS2} Integer; {$ELSE} LongInt; {$ENDIF}
Var
  I : ShortInt;

Begin
  I := 0;
  If PLangDesc (Key1)^. Name < PLangDesc (Key2)^. Name Then i := -1;
  If PLangDesc (Key1)^. Name > PLangDesc (Key2)^. Name Then i :=  1;
  Compare := I;
End;

Function NewLangDesc (LD: TLangDesc): PLangDesc;
Var
  P: PLangDesc;

Begin
  GetMem (P, SizeOf (TLangDesc));
  P^ := LD;
  NewLangDesc := P;
End;

Procedure DisposeLangDesc (P: PLangDesc);
Begin
  If P <> nil Then FreeMem (P, SizeOf (TLangDesc))
End;

Procedure ChooseLang;
Var
  LangColl : PLangDescCollection;
  MenuLang : PNotSortedCollection;
  NumLang  : Byte;
  DirInfo  : {$IFNDEF WIN32} SearchRec {$ELSE}TSearchRec {$ENDIF};
  S1, S2   : String;
  LangDesc : TLangDesc;
  i        : Integer;
  CC       : tConfigParser;

Label
  ProcDone,
  CodePage;

Begin
  LangColl := New (PLangDescCollection, Init (10, 1));
  MenuLang := New (PNotSortedCollection, Init (10, 1));

{$IFDEF WIN32}
  DOSerror :=
{$ENDIF}
  FindFirst (Cnf. LngPath + '*.lng', AnyFile, DirInfo);

  While DosError = 0 Do
  Begin
    If Not ParserOpen (CC, Cnf. LngPath + DirInfo. Name, tpoWriteLog) Then Continue;

    While Not ParserEnd (CC) Do
    Begin
      S1 := ParserRead (CC, S2);
      If (S2 = 'MAIN') And (S1 = 'LANGUAGE') Then
      Begin
        ParserGetParam (CC, tptString, '', S1);
        Break;
      End;
    End;

    ParserClose (CC);
    LangDesc. Name := S1;
    LangDesc. FileName := DirInfo. Name;

    LangColl^. Insert (NewLangDesc (LangDesc));
  {$IFDEF WIN32}
    DOSerror :=
  {$ENDIF}
    FindNext (DirInfo);
  End;

{$IFDEF OS2}
  FindClose (DirInfo);
{$ENDIF}

  If LangColl^. Count <= 0 Then
  Begin
    LogWrite ('!', sm (smNoOneLngFile));
    Halt (202);
  End;

  If LangColl^. Count = 1 Then
  Begin
    R. Lang := JustName (PLangDesc (LangColl^. At (0))^. FileName);
    Goto Codepage;
  End;

  For i := 0 To LangColl^. Count-1 Do
  MenuLang ^. Insert (NewStr (PLangDesc (LangColl^. At (i))^. Name));

  S1 := ComMenu (Cnf. ChoiceLanguageStr1, Cnf. ChoiceLanguageStr2, MenuLang);
  Val (S1, NumLang, Err);

  If ((NumLang <= 0) or (Err <> 0) or (NumLang > LangColl^. Count)) Then GoTo ProcDone;
  If (R. Lang = JustName (PLangDesc (LangColl^. At (NumLang-1))^. FileName)) And (lang (laAskXLAT) = 'NO') Then GoTo ProcDone;
  R. Lang := JustName (PLangDesc (LangColl^. At (NumLang-1))^. FileName);

  CodePage:
  R. XLAT := '';
  ReadLanguage (Language, Cnf. LngPath + LoString (R. Lang) + '.lng');

  If lang (laAskXLAT) = 'YES' Then
  Begin
    MenuLang^. FreeAll;
    MenuLang^. DeleteAll;
    MenuLang^. Insert (NewStr (lang (laRawXLAT)));

    For i := 0 To XLATs^. Count-1 Do
    Begin
      S1 := PXLATrec (XLATs^. At (i))^. Name;
      MenuLang^. Insert (NewStr (S1));
    End;

    If MenuLang^. Count > 1 Then
    Begin
      S1 := ComMenu ('|'+lang (laXLATs), lang (laChooseXLAT), MenuLang);
      Val (S1, i, Err);
      If (i > 0) And (Err = 0) And (i <= XLATs^. Count+1) Then
      If i = 1 Then R. XLAT := '' Else R. XLAT := PXLATrec (XLATs^. At (i-2))^. FileName;
    End Else
      R. XLAT := '';
  End;

  SetXLAT (R. XLAT);

  ProcDone:
  For i := 0 To LangColl^. Count-1 Do
  DisposeLangDesc (LangColl^. At (i));

  LangColl^. DeleteAll;
  Dispose (LangColl, Done);
  Dispose (MenuLang, Done);
End;

Procedure ChangeParam (ParNum: Byte);
Var
  TmpStr, TmpStr1,
  TmpStr2, Was, Now  : String;
  Password, Pas1     : String [15];
  Yes                : Boolean;
  Options, i, Key, j : Byte;

Const
  Emul                  : Array [teAnsi..teAvatar] Of String [6] =
                                ('ANSI', 'TTY', 'AVATAR');

Label
  1,
  EoP,
  Sovsem_End,
  ReAlias,
  ReReadKey;

Begin
  Options := 0;
  TmpStr := '';

  Yes := (ParNum in [pLocation, pOrganization, pAddress, pPassword,
  pBPhone, pHPhone, pHotKeys, pBirthDate, pLines, pLang, pProtocol,
  pEmu, pMore, pFrames, pAlias, pFSEditor]);

  Case ParNum Of
    pLocation    : Begin
                     If Registering and ((EMSI. Session And
                       (R. Location <> '')) Or Not Cnf. AskLocation)
                     Then GoTo Sovsem_End;

                     Was := R. Location;
                     Now := Was;

                     Repeat
                       TmpStr := Trim (GetAnswer (lang (laLocation), 50, Options, R. Location));
                     Until
                       (Pos ('$EXEC', UpString (TmpStr)) = 0) And
                       (Pos ('$FILE', UpString (TmpStr)) = 0);

                     If TmpStr <> '' Then R. Location := TmpStr;
                     Now := R. Location;
                   End;

    pOrganization: Begin
                     If Registering and (Not Cnf. Organization) Then GoTo Sovsem_End;
                     Was := R. Organization;
                     Now := Was;

                     Repeat
                       TmpStr := Trim (GetAnswer (lang (laOrganization), 50, Options, R. Organization));
                     Until (Pos ('$EXEC', UpString (TmpStr)) = 0) And (Pos ('$FILE', UpString (TmpStr)) = 0);

                     If TmpStr <> '' Then R. Organization := TmpStr;
                     Now := R. Organization;
                   End;

    pAddress     : Begin
                     If Registering And Not Cnf. Address Then GoTo Sovsem_End;
                     SmartLine; ComWrite (lang (laFIDOAddress), eoMacro + eoCodes);
                     TmpStr  := '';
                     TmpStr1 := '';
                     TmpStr2 := '';
                     Was := R. Address1 + ', ' + R. Address2 + ', ' + R. Address3;
                     Now := Was;

                     Repeat
                       TmpStr := R. Address1;
                       ComWrite (lang (laAddress1), eoMacro + eoCodes);
                       ComReadLn (TmpStr, 50, ofAllowEmpty);
                     {$IFDEF WIN32}
                       If Application. Terminated Then Exit;
                     {$ENDIF}
                     Until (Pos ('$EXEC', UpString (TmpStr)) = 0) And (Pos ('$FILE', UpString (TmpStr)) = 0);

                     If (Registering And (TmpStr <> '')) Or Not Registering Then
                     Begin
                       Repeat
                         TmpStr1 := R. Address2;
                         ComWrite (lang (laAddress2), eoMacro + eoCodes);
                         ComReadLn (TmpStr1, 50, ofAllowEmpty);
                       {$IFDEF WIN32}
                         If Application. Terminated Then Exit;
                       {$ENDIF}
                       Until (Pos ('$EXEC', UpString (TmpStr1)) = 0) And (Pos ('$FILE', UpString (TmpStr1)) = 0);

                       If (Registering And (TmpStr1 <> '')) Or Not Registering Then
                       Begin
                         Repeat
                           TmpStr2 := R. Address3;
                           ComWrite (lang (laAddress3), eoMacro + eoCodes);
                           ComReadLn (TmpStr2, 50, ofAllowEmpty);
                         {$IFDEF WIN32}
                           If Application. Terminated Then Exit;
                         {$ENDIF}
                         Until (Pos ('$EXEC', UpString (TmpStr2)) = 0) And (Pos ('$FILE', UpString (TmpStr2)) = 0);

                       End;
                     End;

                     R. Address1 := TmpStr;
                     R. Address2 := TmpStr1;
                     R. Address3 := TmpStr2;
                     Now := R. Address1 + ', ' +
                            R. Address2 + ', ' +
                            R. Address3;
                   End;

    pPassword    : Begin
                     If Registering and (EMSI. Session Or (R. Password <> '')) Then GoTo Sovsem_End;
                     Was := R. Password;
                     Now := Was;

                     If (R. Password <> '') And Not InList (Cnf. BadPasswordsList, R. Password) Then
                     If EnterPass (lang (laPassword), False) <> R. Password Then
                     Begin
                       Message (lang (laPasswordNotValid));
                       KolPass := 0;
                       Goto EoP;
                     End;
                   {$IFDEF WIN32}
                     If Application. Terminated Then Exit;
                   {$ENDIF}

                     1: KolPass := 0;
                     R. Password := '';
                     Password := EnterPass (lang (laChoosePassword), Registering);
                   {$IFDEF WIN32}
                     If Application. Terminated Then Exit;
                   {$ENDIF}

                     If InList (Cnf. BadPasswordsList, Password) Then
                     Begin
                       ComWriteLn ('|' + lang (laForbiddenPassword) + '|', eoMacro + eoCodes);
                       GoTo 1;
                     End;

                     Pas1 := EnterPass (lang (laRepeatPassword), Registering);
                   {$IFDEF WIN32}
                     If Application. Terminated Then Exit;
                   {$ENDIF}
                     KolPass := 0;
                     If Password <> Pas1 Then
                     Begin
                       ComWriteLn ('', 0);
                       Message (lang (laPasswordsNotSame));
                       KolPass := 0;
                       Goto 1;
                     End;
                     R. Password := Password;
                     Now := R. Password;
                   End;

    pBPhone      : Begin
                     If Registering and ((EMSI. Session And
                       (R. BPhone <> '')) Or Not Cnf. DataPhone)
                     Then GoTo Sovsem_End;

                     Was := R. BPhone;
                     Now := Was;
                     While Not PhoneValid (TmpStr) Do
                     Begin
                       TmpStr := Trim (GetAnswer (lang (laDataPhone), 15, Options, R. BPhone));
                     {$IFDEF WIN32}
                       If Application. Terminated Then Exit;
                     {$ENDIF}
                       If TmpStr = '' Then Break;
                     End;

                     If TmpStr <> '' Then R. BPhone := TmpStr;
                     Now := R. BPhone;
                   End;

    pHPhone      : Begin
                     If Registering And ((EMSI. Session And
                       (R. HPhone <> '')) Or Not Cnf. VoicePhone)
                     Then GoTo Sovsem_End;

                     Was := R. HPhone;
                     Now := Was;
                     While Not PhoneValid (TmpStr) Do
                     Begin
                       TmpStr := Trim (GetAnswer (lang (laHomePhone), 15, Options, R. HPhone));
                     {$IFDEF WIN32}
                       If Application. Terminated Then Exit;
                     {$ENDIF}
                       If TmpStr = '' Then Break;
                     End;

                     If TmpStr <> '' Then R. HPhone := TmpStr;
                     Now := R. HPhone;
                   End;

    pHotKeys     : Begin
                     If Registering and EMSI. Session Then GoTo Sovsem_End;
                     If Registering and (Cnf. HotKeys in [atYes, atNo]) Then
                     Begin
                       R. HotKeys := YNA2Bool (Cnf. HotKeys);
                       GoTo Sovsem_End;
                     End;

                     Was := BoolMsg [R. HotKeys];
                     Now := Was;
                     R. HotKeys := Query (lang (laUseHotKeys), True, ofFramed);
                   {$IFDEF WIN32}
                     If Application. Terminated Then Exit;
                   {$ENDIF}
                     If R. HotKeys Then
                     Begin
                       KeyBuffer := '';
                       HotKeysStr := '';
                     End;
                     Now := BoolMsg [R. HotKeys];
                   End;

    pBirthDate   : Begin
                     If Registering and ((EMSI. Session And
                       (R. BirthDate <> 0)) Or Not Cnf. Birthdate)
                     Then GoTo Sovsem_End;

                     Was := ReFormatDate (Long2Date (R. BirthDate), DefaultDateMask, Cnf. DateMask);
                     Now := Was;

                     While Not DateMaskMatch (TmpStr, Cnf. DateMask) Do
                     Begin
                       If R. BirthDate = 0 Then TmpStr := '' Else
                       TmpStr := ReFormatDate (Long2Date (R. BirthDate),
                         DefaultDateMask, Cnf. DateMask);

                       TmpStr := Trim (GetAnswer (lang (laBirthDate) + '(' +
                         Cnf. DateMask + '): ', Length (Cnf. DateMask),
                         Options, TmpStr));

                     {$IFDEF WIN32}
                       If Application. Terminated Then Exit;
                     {$ENDIF}
                       If TmpStr = '' Then Break;
                     End;

                     If TmpStr <> '' Then
                     R. BirthDate := Date2Long (ReFormatDate (TmpStr, Cnf. DateMask, DefaultDateMask));
                     Now := ReFormatDate (Long2Date (R. BirthDate), DefaultDateMask, Cnf. DateMask);
                   End;

    pLines       : Begin
                     If Registering and EMSI. Session Then GoTo Sovsem_End;
                     If Registering and Not Cnf. DispAsk Then
                     Begin
                       R. Lines := Cnf. DisplayLines;
                       GoTo Sovsem_End;
                     End;

                     Was := Long2Str (R. Lines);
                     Now := Was;
                     Pas1 := GetAnswer (lang (laDispLines) + ' ', 3,
                     ofAllowEmpty, Long2Str (R. Lines));

                   {$IFDEF WIN32}
                     If Application. Terminated Then Exit;
                   {$ENDIF}
                     If Trim (Pas1) = '' Then Err := 1 Else Val (Pas1, R. Lines, Err);
                     If Err <> 0 Then R. Lines := Cnf. DisplayLines;
                     Now := Long2Str (R. Lines);
                   End;

    pLang        : Begin
                     Was := R. Lang;
                     Now := Was;
                     ChooseLang;
                     Now := R. Lang;
                   End;

    pProtocol    : Begin
                     Was := ProtocolDef. Name;
                     Now := Was;
                     SetProtocol (#0);
                     Now := ProtocolDef. Name;
                   End;

    pEmu         : Begin
                     If Registering and EMSI. Session Then GoTo Sovsem_End;

                     If Registering Then
                     If Cnf. ANSI = atYes Then
                     Begin
                       R. Emu := teAnsi;
                       GoTo Sovsem_End;
                     End Else
                     If Cnf. ANSI = atNo Then
                     Begin
                       R. Emu := teTty;
                       GoTo Sovsem_End;
                     End;

                     i := 0;
                     Was := EmuName [R. Emu];
                     Now := Was;
                     If Cnf. eaAnsi Then Inc (i);
                     If Cnf. eaAvatar Then Inc (i);
                     If Cnf. eaTty Then Inc (i);

                     If i = 0 Then
                     Begin
                       Cnf. eaTty := True;
                       i := 1;
                     End;

                     If i = 1 Then
                     Begin
                       If Cnf. eaAnsi Then R. Emu := teAnsi Else
                       If Cnf. eaAvatar Then R. Emu := teAvatar Else
                       If Cnf. eaTty Then R. Emu := teTty;
                       Exit;
                     End;

                     i := 1;
                     ComWriteLn ('', 0);

                     If Cnf. eaAnsi Then
                     Begin
                       ComWriteLn ('\15' + Long2Str (i) + '\11) \02ANSI \03(\02color\03)', eoCodes);
                       Inc (i);
                     End; If Cnf. eaAvatar Then
                     Begin
                       ComWriteLn ('\15' + Long2Str (i) + '\11) \02Avatar \03(\02color\03)', eoCodes);
                       Inc (i);
                     End; If Cnf. eaTty Then
                     Begin
                       ComWriteLn ('\15' + Long2Str (i) + '\11) \02TTY \03(\02no color\03)', eoCodes);
                       Inc (i);
                     End;

                     ComWriteLn ('', 0);
                     ComWrite (lang (laChooseEmulation), eoMacro + eoCodes);

                     ReReadKey:
                     ProcessChoices;
                   {$IFDEF WIN32}
                     Application. ProcessMessages;
                   {$ENDIF}
                     Key := Str2Long (ComReadKey);
                   {$IFDEF WIN32}
                     If Application. Terminated Then Exit;
                   {$ENDIF}
                     If (Key < 1) Or (Key > i) Then GoTo ReReadKey;

                     j := 0;
                     If Cnf. eaAnsi Then
                     Begin
                       Inc (j);
                       If Key = j Then R. Emu := teAnsi;
                     End; If Cnf. eaAvatar Then
                     Begin
                       Inc (j);
                       If Key = j Then R. Emu := teAvatar;
                     End; If Cnf. eaTty Then
                     Begin
                       Inc (j);
                       If Key = j Then R. Emu := teTty;
                     End;

                     If R. Emu = teTTY Then
                     Begin
                       TextAttr := 3;
                       SetCrtColor;
                     End;

                     ComWriteLn (Emul [R. Emu], 0);
                     Now := EmuName [R. Emu];

                     If (R. Emu = teTty) and R. FSEditor Then
                     Begin
                       ComWriteLn ('|'+lang (lafsANSIreq), eoCodes+eoMacro);
                       R. FSEditor := Query (lang (laUseFSEditor), False, ofFramed);
                     {$IFDEF WIN32}
                       If Application. Terminated Then Exit;
                     {$ENDIF}
                     End;
                   End;

    pMore      : Begin
                     If Registering and EMSI. Session Then GoTo Sovsem_End;
                     If Registering and (Cnf. More in [atYes, atNo]) Then
                     Begin
                       R. More := YNA2Bool (Cnf. More);
                       GoTo Sovsem_End;
                     End;

                     Was := BoolMsg [R. More];
                     Now := Was;
                     R. More := Query (lang (laPausing), True, ofFramed);
                     Now := BoolMsg [R. More];
                   End;

    pFrames    : Begin
                   If Registering and (Cnf. Frames in [atYes, atNo]) Then
                   Begin
                     R. Frames := YNA2Bool (Cnf. Frames);
                     GoTo Sovsem_End;
                   End;

                   Was := BoolMsg [R. Frames];
                   Now := Was;
                   R. Frames := Query (lang (laUseFrames), False, ofFramed);
                   Now := BoolMsg [R. Frames];
                  End;

    pAlias     : Begin
                   If Registering and (Not Cnf. AskAlias) Then GoTo Sovsem_End;
                   ReAlias:
                   Was := R. Alias;
                   Now := Was;

                   Repeat
                     TmpStr := Trim (GetAnswer (lang (laAlias), 15, ofAllowEmpty, R. Alias));
                   Until (Pos ('$EXEC', UpString (TmpStr)) = 0) And (Pos ('$FILE', UpString (TmpStr)) = 0);

                   If UpString (TmpStr) = UpString (R. Alias) Then GoTo EoP;
                   If (Not Is_User (TmpStr, True)) Or (TmpStr = '') Then
                     R. Alias := TmpStr
                   Else Begin
                     ComWriteLn (lang (laAliasExist), eoMacro+eoCodes);
                     GoTo ReAlias;
                   End;

                   Now := R. Alias;
                   If Not Registering Then SaveUser (R);
                 End;

    pFSEditor  : Begin
                   If Registering and (Cnf. FSEditor in [atYes, atNo]) Then
                   Begin
                     R. FSEditor := YNA2Bool (Cnf. FSEditor);
                     GoTo Sovsem_End;
                   End;

                   Was := BoolMsg [R. FSEditor];
                   Now := Was;
                   R. FSEditor := Query (lang (laUseFSEditor), True, ofFramed);
                   Now := BoolMsg [R. FSEditor];
                 End;
  End;

  EoP:
{$IFDEF WIN32}
  If Application. Terminated Then Exit;
  ShowUsualBar;
{$ENDIF}
  If Registering Then
  If Not (ParNum in [pMore, pHotKeys, pFrames, pFSEditor]) Then
  If Not R. Frames Then ComWriteLn ('', 0);

  If Yes And Not Registering And (Was <> Now) Then
  Begin
    LogWrite ('+', sm (smParam) + GetStr (ParamNames^. At (ParNum-1)) + Sm (smParamChanged));
    LogWrite ('@', PlaceSubStr (PlaceSubStr (sm (smParamChangeInfo), '%1', Was), '%2', Now));
  End;

  Sovsem_End:
  UpdateUserMacro;
  SetEmulation;
End;

Procedure Register;
Const
  Registration: String [21] = 'KPMHONLABCEFGD';

Var
  i, StartLet : Byte;
  LogStr      : String [100];

Label
  Reg;

Begin
  If Cnf. Private Then
  Begin
    If Query (lang (laPrivate), True, ofFramed) Then
    Begin
      LogWrite ('!', sm (smRejectNew));
      Msg2SysOp ('New user.');
    End;
    ExecScript ('onexit');
    NormExit;
    Exit;
  End;

  EmuDispFile ('~newuser');
  ExecScript ('newuser');
  ExecRexx ('newuser');

  If GetDoReg (R) Then
  Begin
    SetLanguage;
    ComWriteLn (#13#10 + lang (laRegResume) + #13#10, eoMacro + eoCodes);
    GoTo Reg;
  End;

  LogWrite ('~', sm (smNewReg));
  SetTitle ('registering as a new user');
  Registering := True;
  RegLet := 1;

  Reg:
  If RegLet < 255 Then
  Begin
    StartLet := RegLet;

    For i := StartLet To Length (Registration) Do
    Begin
      RegLet := i;

      LogWrite ('&', 'Asking registration question about ' +
      GetStr (ParamNames^. At (Letters [Registration [RegLet]]-1)));

      If Registration [RegLet] = 'D' Then
      If EMSI. Session Then
      Begin
        R. Password := EMSI. Password;
        Continue;
      End;

      ChangeParam (Letters [Registration [RegLet]]);
    {$IFDEF WIN32}
      If Application. Terminated Then Exit;
    {$ENDIF}
    End;
  End;

  RegLet := 255;

  If Cnf. AcceptReg Then
  If Not Query (lang (laIsRegCorrect), True, ofFramed) And
     Not EMSI. Session Then
  Begin
  {$IFDEF WIN32}
    If Application. Terminated Then Exit;
  {$ENDIF}
    RegLet := 1;
    R. Password := '';
    Goto Reg;
  End;

  If InList (Cnf. GoodUsersList, R. Name) Then
  Begin
    R. Security := Cnf. GoodSecurity;
    R. Flags := Cnf. GoodFlags;
  End Else
  Begin
    R. Security := Cnf. Security;
    R. Flags := Cnf. Flags;
  End;

  R. TimeUsedToday := 0;
  R. LastDate := DateL;
  R. LastTime := Time2Word (StrTime);
  R. FirstDate := 1;

  R. MsgGroup := 0;
  R. MsgArea := 1;

  R. FileGroup := 0;
  R. FileArea := 1;

  R. LastRead := NextLastRead;
  R. Protocol := #0;

  SetGroups;
  SetAreas;

  If Not ReadLimit (Lim, R. Security) Then
  Begin
    LogStr := PlaceSubStr (sm (smNoSec), '%level%', Long2Str (R. Security));
    LogStr := PlaceSubStr (LogStr, '%limfile%', Cnf. LimitsFile);
    LogWrite ('!', LogStr);
    Halt (203);
  End;

  R. TotalTime := Lim. Time * 60;
  R. DailySize := Lim. KBLimit;

  TimeCount := True;
  EnterTime := MidSec;
  R. ReReadLimit := False;
  SaveUser (R);

  LogWrite ('@', 'ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ');
  If R. Alias <> '' Then
    LogWrite ('@', PadCh (Sm (smueAlias), ' ', 16) + ': ' + R. Alias);
  If R. Birthdate <> 0 Then
    LogWrite ('@', PadCh (Sm (smueBirthdate), ' ', 16) + ': ' +
    ReFormatDate (Long2Date (R. BirthDate),
    DefaultDateMask, Cnf. DateMask));
  If R. Location <> '' Then
    LogWrite ('@', PadCh (Sm (smueLocation), ' ', 16) + ': ' + R. Location);
  If R. Organization <> '' Then
    LogWrite ('@', PadCh (Sm (smueOrganization), ' ', 16) + ': ' + R. Organization);
  If R. Address1 <> '' Then
    LogWrite ('@', PadCh (Sm (smue1stAddress), ' ', 16) + ': ' + R. Address1);
  If R. Address2 <> '' Then
    LogWrite ('@', PadCh (Sm (smue2ndAddress), ' ', 16) + ': ' + R. Address2);
  If R. Address3 <> '' Then
    LogWrite ('@', PadCh (Sm (smue3rdAddress), ' ', 16) + ': ' + R. Address3);
  If R. HPhone <> '' Then
    LogWrite ('@', PadCh (Sm (smueHomePhone), ' ', 16) + ': ' + R. HPhone);
  If R. BPhone <> '' Then
    LogWrite ('@', PadCh (Sm (smueDataPhone), ' ', 16) + ': ' + R. BPhone);

  LogWrite ('@', PadCh (Sm (smueLines), ' ', 16) + ': ' + Long2Str (R. Lines));
  LogWrite ('@', PadCh (Sm (smueLanguage), ' ', 16) + ': ' + R. Lang);
  LogWrite ('@', PadCh (Sm (smueEmulation), ' ', 16) + ': ' + EmuName [R. Emu]);
  LogWrite ('@', PadCh (Sm (smuePausing), ' ', 16) + ': ' + BoolMsg [R. More]);
  LogWrite ('@', PadCh (Sm (smueHotKeys), ' ', 16) + ': ' + BoolMsg [R. HotKeys]);
  LogWrite ('@', PadCh (Sm (smueFSeditor), ' ', 16) + ': ' + BoolMsg [R. FSeditor]);
  LogWrite ('@', 'ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ');

  Registering := False;
End;

Procedure Login;
Var
  LogStr, S : String;
  NowD : LongInt;
  NowT : LongInt;
  LastD : LongInt;
  LastT : LongInt;

Procedure EnableButtons;
Begin
{$IFDEF WIN32}
  MainForm. Console1. Paint;
  MainForm. miUserInfo := True;
  MainForm. miTagList := True;
  MainForm. miEditUser := True;
  MainForm. miSecurity := True;
{$ENDIF}
End;

Label
  3,
  4,
  5,
  NOWN,
  PassEnd,
  ReLogOn;

Begin
{$IFDEF OS2}
  InitRexx;
{$ENDIF}

  With Cnf Do
  Begin
    If eaTty Then R. Emu := teTty;
    If eaAvatar Then R. Emu := teAvatar;
    If eaAnsi Then R. Emu := teAnsi;
  End;

  R. HotKeys := (Cnf. HotKeys in [atYes, atAsk]);

  Cls;

{$IFDEF WIN32}
  MainForm. miUserInfo := False;
  MainForm. miTagList := False;
  MainForm. miEditUser := False;
  MainForm. miSecurity := False;
{$ENDIF}

  SetInputCap (NoCaps, AllChars);
  InConference := False;
  VIPcheck := False;
  ExecScript ('logo');
  ExecRexx ('logo');
  EmuDispFile (Cnf. Logo);

  ComWriteLn ('', 0);

{$IFDEF WIN32}
  Application. Restore;
{$ENDIF}

  If EMSI. Allowed Then
  Begin
    ComWrite ('**EMSI_IRQ8E08', 0);
    ComWrite (#13, 0);
    If R. Emu = teTty
     Then Begin ComWrite (Replicate (' ', 14), 0); ComWrite (#13, 0); End
     Else ComWrite (EmuClrEol, 0);
  End;

  If Cnf. ShowTorVer Then ComWriteLn (EmuColor ($07) + NameVer, 0);

  ReLogOn:
  Registering := True;
  R. Name := '';
  R. Lines := Cnf. DisplayLines;
  R. Frames := (Cnf. Frames = atYes);
  TimeCount := False;

  ComWrite (Cnf. LoginString, eoMacro + eoCodes);
  ReqName := DelSpaces (ReqName);

  If ReqName = '' Then
  Begin
    If Cnf. CapitalizeNames
    Then SetInputCap (Proper, LettersOnly)
    Else SetInputCap (NoCaps, LettersOnly);

    EMSI. Allowed := True;
    S := '';
    ComReadLn (S, 36, 0);
    R. Name := DelSpaces (S);
  {$IFDEF WIN32}
    If Application. Terminated Then Exit;
  {$ENDIF}
    EMSI. Allowed := False;
    R. Name := Trim (R. Name);
    If R. Name = '' Then Goto ReLogOn;
  End Else
  Begin
    ComWriteLn (PadCh (ReqName, ' ', 36), 0);
    R. Name := ReqName;
    ReqName := '';
  End;

  LogWrite ('~', R. Name + sm (smOnLine));
  SetInputCap (NoCaps, AllChars);

  If InList (Cnf. BadUsersList, R. Name) Then
  Begin
    EmuDispFile ('~baduser');
    ExecScript ('baduser');
    ExecRexx ('baduser');

    LogWrite ('!', sm (smlBadUser));
    If Not Local Then Pause (2000);
    ExecScript ('onexit');
    NormExit;
  End;

  If InList (Cnf. GoodUsersList, R. Name) Then
  Begin
    LogWrite ('!', sm (smlGoodUser));
    EmuDispFile ('~gooduser');
    ExecScript ('gooduser');
    ExecRexx ('gooduser');
  End;

  Suxx := InList (Cnf. SuxxUsersList, R. Name);
  If Suxx Then LogWrite ('!', sm (smlSuxxUser));

  If ((Not Cnf. OneWordNames) And (WordCount (R. Name, [' ']) <= 1) And
     Cnf. Aliases And (Not Is_User (R. Name, Cnf. Aliases))) Or
     ((Not Cnf. Aliases) And (Not Cnf. OneWordNames) And (WordCount (R. Name, [' ']) <= 1))
  Then
    GoTo NOWN
  Else
    GoTo 3;

  If Not Cnf. OneWordNames And (WordCount (R. Name, [' ']) <= 1) Then
  Begin
    NOWN:
    ComWriteLn (Cnf. NoOneWordNames, eoMacro + eoCodes);
    Goto ReLogOn;
  End;

  3:
  If Not Is_User (R. Name, Cnf. Aliases) Then
  If Not EMSI. Session Then
  Begin
    If DoRegExist Then
    Begin
      Register;
      GoTo PassEnd;
    End;

    ChooseLang;
  {$IFDEF WIN32}
    If Application. Terminated Then Exit;
  {$ENDIF}

    ComWriteLn ('|' + lang (laYourNameNotFound), eoMacro + eoCodes);
    ComWriteLn (lang (laNameEntered) + R. Name, eoMacro + eoCodes);
    If R. Frames and (EmuGoToXY (1, 1) <> '') Then ComWriteLn (#10#10#13, 0);
    If Query (lang (laWantToReg), False, ofFramed) Then
    Begin
      Register;
      mL_Init (BbsLine);
      GoTo PassEnd;
    End Else
    Begin
    {$IFDEF WIN32}
      If Application. Terminated Then Exit;
    {$ENDIF}
      SmartLine;
      GoTo ReLogOn;
    End;
  End Else
    Register;

  PrevLang := R. Lang;
  GetUser (R. Name, R, Cnf. Aliases);

  If R. Emu = teTTY Then
  Begin
    TextAttr := 3;
    SetCrtColor;
  End;

  If InList (Cnf. SuxxUsersList, R. Name) And Not Suxx Then
  Begin
    LogWrite ('!', sm (smlSuxxUser));
    Suxx := True;
  End;

  SetEmulation;

  If BbsLine <> 0 Then
  If Not mL_Init (BbsLine) Then
  Begin
    LogWrite ('!', sm (smOnAnotherLine));
    ComWriteLn (#13#10 + lang (laOnAnotherLine), eoCodes+eoMacro);
    If Not Local Then Pause (2000);
    ExecScript ('onexit');
    NormExit;
  End;

  If R. LastRead = 0 Then R. LastRead := NextLastRead;

  If R. Password = '' Then
  Begin
    If Not R. Guest Then ChangeParam (pPassword);
    GoTo PassEnd;
  End;

  KolPass := 0;
  VIPinformed := False;

  4:
  If Cnf. FastLogon And Local Then GoTo PassEnd;

  VIPcheck := True;

  If (Not EMSI. Session) or (EMSI. Session and (KolPass > 0)) Then
    EMSI. Password := EnterPass (lang (laPassword), False)
  Else
    VeryImportant;

{$IFDEF WIN32}
  If Application. Terminated Then Exit;
{$ENDIF}

  VIPcheck := False;

  If UpString (EMSI. Password) <> UpString (R. Password) Then
  Begin
    SmartLine;
    ComWriteLn (lang (laPasswordNotValid), eoMacro + eoCodes);
    LogStr := sm (smInvalidPass);
    LogStr := PlaceSubStr (LogStr, '%pass1%', EMSI. Password);
    LogStr := PlaceSubStr (LogStr, '%pass2%', R. Password);
    LogWrite ('!', LogStr);
    If KolPass = 0 Then Inc (KolPass);
    Goto 4;
  End;

  PassEnd:
{$IFDEF WIN32}
  If Application. Terminated Then Exit;
{$ENDIF}

  If InList (Cnf. BadPasswordsList, R. Password) Then
  Begin
    ComWriteLn ('|' + lang (laForbiddenPassword), eoMacro + eoCodes);
    ChangeParam (pPassword);
  End;

  Registering := False;
  KolPass := 0;

  If (UpString (R. Lang) <> UpString (PrevLang)) Or (XLATs^. Count <> 0)
  Then SetLanguage;

  If (Not (R. Emu in [teAnsi..teAvatar])) Or
     (Not Cnf. eaAnsi And (R. Emu = teAnsi)) Or
     (Not Cnf. eaAvatar And (R. Emu = teAvatar)) Or
     (Not Cnf. eaTty And (R. Emu = teTty))
  Then ChangeParam (pEmu);

  If R. Security <= 0 Then
  Begin
    LogWrite ('!', sm (smLockOut));
    EmuDispFile ('~lockout');
    If Not Local Then Pause (2000);
    ExecScript ('onexit');
    NormExit;
    Exit;
  End;

  If Not ReadLimit (Lim, R. Security) Then
  Begin
    LogStr := PlaceSubStr (sm (smSecNotFound), '%level%', Long2Str (R. Security));
    LogStr := PlaceSubStr (LogStr, '%limfile%', Trim (NiceFileName (Cnf. LimitsFile, 30)));
    LogWrite ('!', LogStr);
    ErrorExit;
  End;

  Ent := DateL;
  EntT := Time2Word(StrTime);

  If R. ReReadLimit Then
  Begin
    SetSecurity;
    R. ReReadLimit := False;
  End;

  TimeCount := True;
  EnterTime := MidSec;
  If Not IsToday (R. LastDate, Time2Long(Word2Time(R. LastTime))) Then
  Begin
    R. TotalTime := Lim. Time * 60;
    R. DailySize := Lim. KBLimit;
    R. TimeUsedToday := 0;
    R. TodayK := 0;
    LogWrite ('&', 'User''s limit updated');
  End;

  If (R. FirstDate = 1) Or R. Guest Then
  Begin
    R. TotalTime := Lim. Time * 60;
    If Not R. Guest Then R. FirstDate := DateL Else
    Begin
      R. DailySize := Lim. KBLimit;
      R. TimeUsedToday := 0;
      R. TodayK := 0;
    End;
  End;

  If (R. TotalTime <= 0) And Not R. Guest Then
  Begin
    ComWriteLn (lang (laTimeLimit), eoMacro + eoCodes);
    LogWrite ('+', sm (smTimeLimit));
    R. TotalTime := 0;
    TimeExeded := True;
    If Not Local Then Pause (1000);
    ExecScript ('onexit');
    NormExit;
  End;

  If (Not Local) And (GetConnectSpeed < Lim. MinSpeed) Then
  Begin
    EmuDispFile ('~tooslow');
    LogWrite ('!', sm (smlTooSlow));
    ExecScript ('onexit');
    NormExit;
  End;

  If Not MatchTimeArray (Lim. LoginTime) Then
  Begin
    EmuDispFile ('~nlogtime');
    ComWriteLn (#13#10#10 + lang (laLoginNAllow), eoMacro + eoCodes);
    LogWrite ('+', sm (smLoginNAllow));
    ExecScript ('onexit');
    NormExit;
  End;

  SaveUser (R);

{$IFDEF WIN32}
  If Application. Terminated Then Exit;
  ShowUsualBar;
{$ENDIF}

  SetGroups;
  SetAreas;

  FillChar (ProtocolDef, SizeOf (ProtocolDef), #0);
  If R. Protocol <> #0 Then SetProtocol (R. Protocol) Else ProtocolDef. Name := 'None';

  If (R. NoCalls = 0) And (Not R. Guest) Then
  Begin
    ExecScript ('regend');
    ExecRexx ('regend');
    EmuDispFile ('~regend');
  End;

  Inc (R. NoCalls);
  mL_EnableMsg;

  5:
  Inc (Sys. TotalCalls);
  UpdateUserMacro;
  qwkReadList;

  EnableButtons;
End;

Procedure fNews (Logon: Boolean);
Var
  F                      : Text;
  S, T, Last             : String;
  New, Cont, Skipped,
  SomeShowed             : Boolean;

Begin
  If Trim (lang (laNews)) = '' Then Exit;
  SetTitle ('reading news');

  Cls;
  New := True;
  Skipped := False;
  SomeShowed := False;
  Cont := True;
  Last := ReFormatDate (Long2Date (R. LastDate), DefaultDateMask, 'DD-MM-YY') + ' ' +
          Word2Time (R. LastTime);

  Assign (F, lang (laNews));
  ReSet (F);
  DOSerror := IOResult;

  If DOSerror <> 0 Then
  Begin
    LogWrite ('!', sm (smFile) + lang (laNews) + sm (smNotFound));
    LogWrite ('&', 'IOResult: ' + Long2Str (DOSerror));
    Exit;
  End;

  SetDebugFile (lang (laNews));

  While Not EoF (F) Do
  Begin
    ReadLn (F, S);
    S := PlaceSubStr (S, #8, '    ');
    T := Trim (S);

    If T <> '' Then
    If T [1] = ';' Then Continue;

    If T = '/***/' Then
    Begin
      New := True;
      Skipped := False;
      Continue;
    End;

    If DrawAborted Then Break;

    If New Then
    Begin
      S := Trim (S);

      If Logon And ((Cnf. ShowNews = tnLast) And (CompareDates (Last,
         ReFormatDate (ExtractWord (1, S, [' ']),
         Cnf. DateMask, 'DD-MM-YY') + ' ' +
         ExtractWord (2, S, [' '])) <> 2)) Then
      Begin
        New := False;
        Skipped := True;
        Continue;
      End;

      If Not Skipped Then
      If SomeShowed Then
      Begin
        ComWrite (EmuColor (Cnf. ColorScheme [nwFrames]) + Replicate ('Ä', 79) + #13#10, 0);

        If Cnf. NewsPauseAsk
        Then Cont := fQuery (lang (laNextBulletin), True, 0) Else
        Begin
          Cont := True;
          ComWrite (lang (laEnterForCont), eoMacro + eoCodes);
          While (ComReadKey <> #13) {$IFDEF WIN32} And Not Application. Terminated {$ENDIF} Do;
        {$IFDEF WIN32}
          If Application. Terminated Then Exit;
        {$ENDIF}
        End;
      End;

      If Not Cont Then
      Begin
        Close (F);
        Exit;
      End;

      Cls;
      SomeShowed := True;
      S := Copy (S, 1, Length (Cnf. DateMask));

      If Length (S) < Length (Cnf. DateMask) Then
        S := S + Replicate (' ', Length (Cnf. DateMask)-Length (S));

      ComWriteLn (EmuColor (Cnf. ColorScheme [nwFrames]) + '     Ú' +
      Replicate ('Ä', Length (Cnf. DateMask)+2) + '¿', 0);

      ComWriteLn (EmuColor (Cnf. ColorScheme [nwFrames]) + 'ÄÄÄÄÄ´ ' +
      EmuColor (Cnf. ColorScheme [nwDate]) + S + EmuColor (Cnf. ColorScheme
      [nwFrames]) + ' Ã' + Replicate ('Ä', 70-Length (Cnf. DateMask)), 0);

      ComWriteLn ('     À' + Replicate ('Ä', Length (Cnf. DateMask)+2) + 'Ù' +
      EmuColor ($03), 0);

      InitMore (WhereY-1);
      New := False;
    End Else
      If Not Skipped Then ComWriteLn (S, eoMacro + eoCodes);

    If Not Skipped Then
    If Not More Then
    Begin
      Skipped := True;
    End;
  End;

  If SomeShowed Then
  Begin
    ComWrite (EmuColor (Cnf. ColorScheme [nwFrames]) +
    Replicate ('Ä', 79), 0);
    Message ('');
  End;

  Close (F);
End;

Procedure Information;
Begin
  Cls;
  ComWriteLn ('|\15$BBSN running on ' + NameVer, eoMacro+eoCodes);
  If BbsLine <> 0 Then
  ComWriteLn ('Line Number ' + Long2Str (BbsLine) + '|', eoCodes);
  ComWrite ('|\10Operating system: ' + MTaskerz [Task. OS], eoCodes);

{$IFDEF MSDOS}
  If Task. OS <> 0 Then
  ComWrite (' ' + Long2Str (Hi (Task. Version)) + '.' + Long2Str (Lo (Task. Version)), 0);
{$ENDIF}
  ComWriteLn ('', 0);

  Message ('');
End;

Procedure TodaysCallers;
Var
  LC    : tLastCaller;
  HList : PNotSortedCollection;

Label
  EoP, ExitP;

Begin
  Cls;
  ComWriteLn (lang (laTodaysHead), eoMacro + eoCodes);
  ComWriteLn (EmuColor (Cnf. ColorScheme [umSeparator]) +
    'ÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄ ÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄ', eoMacro + eoCodes);
  InitMore (WhereY);

  If Not ReadLastCaller (LC, trlcOpen4All) Then Goto ExitP;

{  Begin
    Message ('');
    Exit;
  End;}

  HList := New (PNotSortedCollection, Init (10, 1));
  ReadList (Cnf. HideUsersList, HList);

  While ReadLastCaller (LC, trlcRead) Do
  Begin
    If (LC. Name = '') Or (HList^. Contains (LC. Name) And (R. Name <> Cnf. SysOp)) Then Continue;
    If DrawAborted Then GoTo EoP;

    ComWriteLn (
      EmuColor (Cnf. ColorScheme [tdLine]) + PadCh (Long2Str (LC. Line), ' ', 6) +
      EmuColor (Cnf. ColorScheme [tdName]) + PadCh (LC. Name, ' ', 37) +
      EmuColor (Cnf. ColorScheme [tdEnterTime]) + LC. LoginTime + ' ' +
      EmuColor (Cnf. ColorScheme [tdOnLine]) + LeftPadCh (Long2Str (LC. TimeOnLine), ' ', 5) + ' ' +
      EmuColor (Cnf. ColorScheme [tdTransfers]) + LeftPadCh (Long2Str (
      LC. DLkb), ' ', 4) + ':' + PadCh (Long2Str (LC. ULkb), ' ', 4),
    0);

    If Not More Then Break;
 {$IFDEF WIN32}
    If Application. Terminated Then Exit;
 {$ENDIF}
  End;

  EoP:
  ReadLastCaller (LC, trlcClose);
  Dispose (HList, Done);
  ExitP:
  Message ('');
End;

Var
  j     : Word;

Procedure QuickChangeMArea (i : ShortInt);
Begin
  If Not OpenMsgAreas Then Exit;
  j := R. MsgArea+i;

  If ReadMsgArea (tMA, j) Then
  While (tMA. Name = '') Or (Not FlagsValid (R. Flags, tMA. ShowFlags)) Or
        (tMA. ShowSec > R. Security) Or
        ((Not WordInString (MsgGroup. Tag, tMA. Group)) And
        (MsgGroup. Tag <> '') And (tMA. Group <> '')) Do
  Begin
    Inc (j, Trunc (i/Abs (i)));

    If Not ReadMsgArea (tMA, j) Then
    If (tMA. Name = '') Or (Not FlagsValid (R. Flags, tMA. ShowFlags)) Or
       (tMA. ShowSec > R. Security) Or
       ((Not WordInString (MsgGroup. Tag, tMA. Group)) And
       (MsgGroup. Tag <> '') And (tMA. Group <> '')) Then
    Begin
      CloseMsgAreas;
      Exit;
    End Else
      Break;

  End Else
  Begin
    CloseMsgAreas;
    Exit;
  End;

  CloseMsgAreas;
  R. MsgArea := j;
  MsgArea := tMA;

  UpdateUserMacro;
End;

Procedure QuickChangeFArea (i : ShortInt);
Begin
  If Not OpenFileAreas Then Exit;
  j := R. FileArea+i;

  If ReadFileArea (tFA, j) Then
  While (tFA. Name = '') Or (Not FlagsValid (R. Flags, tFA. ShowFlags)) Or
        (tFA. ShowSec > R. Security) Or ((Not WordInString
        (FileGroup. Tag, tFA. Group)) And (tFA. Group <> '') And
        (FileGroup. Tag <> '')) Do
  Begin
    Inc (j, Trunc (i/Abs (i)));

    If Not ReadFileArea (tFA, j) Then
    If (tFA. Name = '') Or (Not FlagsValid (R. Flags, tFA. ShowFlags)) Or
       (tFA. ShowSec > R. Security) Or ((Not WordInString
       (FileGroup. Tag, tFA. Group)) And (tFA. Group <> '') And
       (FileGroup. Tag <> '')) Then
    Begin
      CloseFileAreas;
      Exit;
    End Else
      Break;

  End Else
  Begin
    CloseFileAreas;
    Exit;
  End;

  CloseFileAreas;

  R. FileArea := j;
  FileArea := tFA;

  UpdateUserMacro;
End;

Procedure QuickChangeMGroup (i : ShortInt);
Begin
  If Not OpenMsgGroups Then Exit;
  j := R. MsgGroup+i;

  If ReadMsgGroup (tMG, j) Then
  While (tMG. ShowSec > R. Security) Or
        (Not FlagsValid (R. Flags, tMG. ShowFlags)) Do
  Begin
    Inc (j, Trunc (i/Abs (i)));

    If Not ReadMsgGroup (tMG, j) Then
    If (tMG. ShowSec > R. Security) Or
       (Not FlagsValid (R. Flags, tMG. ShowFlags)) Then
    Begin
      CloseMsgGroups;
      Exit;
    End Else
      Break;

  End Else
  Begin
    CloseMsgGroups;
    Exit;
  End;

  CloseMsgGroups;

  R. MsgGroup := j;
  MsgGroup := tMG;

  SetRelativeMsgArea;
  UpdateUserMacro;
End;

Procedure QuickChangeFGroup (i : ShortInt);
Begin
  If Not OpenFileGroups Then Exit;
  j := R. FileGroup+i;

  If ReadFileGroup (tFG, j) Then
  While (tFG. ShowSec > R. Security) Or
        (Not FlagsValid (R. Flags, tFG. ShowFlags)) Do
  Begin
    Inc (j, Trunc (i/Abs (i)));

    If Not ReadFileGroup (tFG, j) Then
    If (tFG. ShowSec > R. Security) Or
       (Not FlagsValid (R. Flags, tFG. ShowFlags)) Then
    Begin
      CloseFileGroups;
      Exit;
    End Else
      Break;

  End Else
  Begin
    CloseFileGroups;
    Exit;
  End;

  CloseFileGroups;

  R. FileGroup := j;
  FileGroup := tFG;

  SetRelativeFileArea;
  UpdateUserMacro;
End;

Procedure DoFinger (Q: String);
Begin
  If Q = '' Then
  Begin
    ComWrite ('\11Finger query: ', eoCodes+eoMacro);
    Q := '';
    ComReadLn (Q, 50, ofAllowEmpty);
    Q := Trim (Q);
  {$IFDEF WIN32}
    MainForm. Console1. ShowCursor;
    MainForm. Console1. Paint;
  {$ENDIF}
  End;
(*
{$IFDEF WIN32}
  If Q <> '' Then
  Begin
    DnsFinished := False;
    MainForm. Finger. Query := Q;
    MainForm. Finger. StartQuery;

    Repeat
      Application. ProcessMessages;
      Application. HandleMessage;

      If DrawAborted Then
      Begin
        MainForm. Finger. Abort;
        Break;
      End;

    Until DnsFinished;
  End;
{$ENDIF}
*)
End;

Procedure fGoTelnet (Host: String);
Var
  C : Char;

Begin
  {If Not Protect. Registered Then
  Begin
    Message ('\12You can''t use internal Telnet client feature in \14UNREGISTERED \12version');
  End Else}
  Begin
  {$IFNDEF MSDOS}
    If Host = '' Then
    Begin
      ComWrite ('\11Hostname: ', eoCodes+eoMacro);
      Host := '';
      ComReadLn (Host, 50, ofAllowEmpty);
      Host := Trim (Host);
    End;

    If Host <> '' Then
    Begin
      Cls;
      TelnetOpen (Host);
    {$IFDEF WIN32}
      MainForm. Console1. Paint;
      MainForm. Console1. ShowCursor;
    {$ENDIF}

      If Not TelnFinish Then
      Begin
        ComWrite (EmuColor ($03), 0);

        Repeat
          If TelnetDataAvail Then
          Begin
            TelnetProcess;
          {$IFDEF WIN32}
            MainForm. Console1. ShowCursor;
          {$ENDIF}
          End;

          If Incoming Then
          Begin
            C := ComReadKey;
            TelnFinish := TelnFinish Or (C = #29);
            If Not TelnFinish Then TelnetSend (C);
          End Else
          Begin
            Clock2;
            TimeSlice;
          {$IFDEF WIN32}
            Application. ProcessMessages;
          {$ENDIF}
          End;

        Until TelnFinish;

        TelnetClose;
      End;
    End;
  {$ENDIF}
  End;
End;

Procedure DoMenu;
Var
  MU, MU1                              : tMenuItem;
  HotKeys, CurDir                      : String [100];
  MenuKey                              : Char;
  CLine                                : Byte;
  Breaked, tB, wFin, Secured           : Boolean;
  FileRec                              : TTagFileRec;
  nFileArea                            : tFileArea;
  nMsgArea                             : tMsgArea;
  nFileGroup                           : tFileGroup;
  nMsgGroup                            : tMsgGroup;
  mc, ic                               : Word;
  LastDraw                             : LongInt;

Const
  InGosub        : Boolean = False;
  LightedArrItem : LongInt = 0;

Function ExecMenuAction (Action: Byte; Param: String): Boolean;
Var
  DirInfo       : {$IFNDEF WIN32} SearchRec {$ELSE} TSearchRec {$ENDIF};
  FL            : PathStr;
  Want          : Boolean;

Begin
  CurrentDebugFile := '';
  SetTitle ('');
  ExecMenuAction := False;
  InLightBarMenu := True;

  FL := Actions [Action];
  If Param <> '' Then FL := FL + ' (' + Param + ')';
  LogWrite ('&', FL);

  If (BbsLine = 0) And (Action in [cSend_Msg, cSet_Msg_Off, cSet_Msg_On, cLine_List, cConference]) Then
  Begin
    ExecMenuAction := True;
    wFin := True;
    Exit;
  End;

  If Not R. Frames Then ComWriteLn ('', 0);
  ExecMenuAction := True;
(*
  If Random (6) = 2 Then
  Begin
    CheckReg;
  {$IFDEF WIN32}
    If Application. Terminated Then Exit;
  {$ENDIF}
  End;
*)
  Case Action Of
    cGosub : Begin
               Menus^. Insert (NewStr (UpString (FileName)));
               FileName := Param;
               ExecMenuAction := True;
               InGosub := True;
               LightedArrItem := 0;
             End;

    cGoTo : Begin
              Menus^. DeleteAll;
              FileName := Param;
              LightedArrItem := 0;
            End;

    cDownLoad : If Param = '' Then DownLoad Else
                If FileExists (Param) Then
                Begin
                {$IFDEF WIN32}
                  DOSerror :=
                {$ENDIF}
                  FindFirst (Param, AnyFile{$IFNDEF OS2}-VolumeID{$ENDIF}-Directory, DirInfo);

                  While DOSerror = 0 Do
                  Begin
                    FL := AddBackSlash (JustPathName (Param)) + DirInfo. Name;

                    If (R. TodayK + Trunc (gFileSize (FL)/1024) + Trunc (SizeOfAll/1024) < R. DailySize)
                      Or (Cnf. DontUseDLLimitWhenTagging) Then
                    Begin
                      If (R. TodayK + Trunc (gFileSize (FL)/1024 + SizeOfAll/1024) <
                          Round ((GetConnectSpeed/10 * (R. TotalTime - MidSec +
                          EnterTime))/1024)) or Local Or (Cnf. DontUseTimeLimitWhenTagging) Then
                      Begin
                        FileRec. PathName := FL;
                        FileRec. AreaNum  := 0;
                        FileRec. Size     := gFileSize (FL);
                        FileRec. Free     := False;
                        FileRec. FromName := '';

                        If Not InTagList (FileRec. PathName) Then
                        Begin
                          F2Transfer^. Insert (NewTagFile (FileRec));
                          Inc (SizeOfAll, gFileSize (FL));
                        End;
                      End Else Message (lang (laDLTimeLimit));
                    End Else Message (lang (laDLLimitExceed));

                  {$IFDEF WIN32}
                    DOSerror :=
                  {$ENDIF}
                    FindNext (DirInfo);
                  End;
                  {$IFDEF OS2} FindClose (DirInfo); {$ENDIF}

                  DownLoad;
                End Else
                  Message (lang (laFileName) + Param + lang (laNotFound));

    cUpLoad : Begin
                UpLoadToUser := '';
                FL := FileArea. ULPath;
                If Param <> '' Then FileArea. ULPath := AddBackSlash (Param);
                Transfer (Param, Receive, tsNormal);
                If Param <> '' Then FileArea. ULPath := FL;
              End;

cUpLoadPriv : Begin
                UpLoadToUser := Param;
                Transfer (Param, Receive, tsPrivate);
              End;

    cReturn : Begin
                If Menus^. Count = 0 Then
                Begin
                  ExecScript ('onexit');
                  NormExit;
                End;
                FileName := GetStr (Menus^. At (Menus^. Count-1));
                Menus^. AtFree (Menus^. Count-1);
                ExecMenuAction := True;
                LightedArrItem := 0;
              End;

    cLogOff : Begin
                If Not R. HotKeys Then ComWriteLn ('', 0);

                If Cnf. LogoffAsk
                Then Want := Query (lang (laLogOff), True, ofFramed)
                Else Want := True;

                If Want Then
                Begin

                  If Cnf. LogoffMail Then
                  If Query (lang (laLogoffMessage), False, ofFramed)
                  Then Msg2SysOp ('Feedback');

                  {$IFDEF OS2}
                  NeedThreadClose := True;
                  Repeat Until Not ThreadLocked;
                  {$ENDIF}

                  LogWrite ('+', sm (smlHangUp));

                  EmuDispFile ('~logoff');
                  ExecScript ('logoff');
                  ExecRexx ('logoff');

                  LogWrite ('#', 'Waiting while OutBuffUsed');
                  If Not Local Then
                  Begin
                    NewTimerSecs (Timer, 10);
                    While OutBuffUsed (P) > 0 Do
                    If TimerExpired (Timer) Then Break;
                  End;

                  LogWrite ('#', 'NormExit NOW!');
                  ExecScript ('onexit');
                  If Not Local Then Pause (2000);
                  NormExit;
                End;
              End;

    cChangeFileArea : Begin
                        If Param = '' Then SelectFArea Else
                        Begin
                          OpenFileAreas;
                          ReadFileArea (nFileArea, Str2Long (param));
                          CloseFileAreas;
                          If nFileArea. Name <> '' Then FileArea := nFileArea;
                        End;
                      End;

   cChangeFileGroup : Begin
                        If Param = '' Then SelectFGroup Else
                        Begin
                          OpenFileGroups;
                          ReadFileGroup (nFileGroup, Str2Long (Param));
                          CloseFileGroups;
                          If nFileGroup. Name <> '' Then FileGroup := nFileGroup;
                        End;
                      End;

    cUserInfo : If (Param = '') And (R. Security >= Cnf. UserInfoMinSec) And FlagsValid (R. Flags, Cnf. UserInfoMinFlags) Then
                Begin
                  If Cnf. CapitalizeNames
                    Then SetInputCap (Proper, LettersOnly)
                    Else SetInputCap (NoCaps, LettersOnly);

                  UserInfo (GetAnswer (lang (laUserName), 36, ofAllowEmpty, ''));
                  SetInputCap (NoCaps, AllChars);
                End Else
                Begin
                  UserInfo (Param);
                  SetInputCap (NoCaps, AllChars);
                End;

    cPostMsg : PrePostMsg (Param);

    cFileList : Begin
                  If param <> '' Then
                  Begin
                    nFileArea := FileArea;
                    OpenFileAreas;
                    ReadFileArea (FileArea, Str2Long (param));
                    CloseFileAreas;
                  End;

                  If (FileArea. List_Security > R. Security) or
                     (Not FlagsValid (R. Flags, FileArea. List_Flags)) Then
                  Begin
                    If R. HotKeys Then ComWriteLn ('', 0);
                    Message (lang (laSecurityLow));
                    wFin := True;
                  End Else
                  Begin
                    SetTitle ('browsing file area contents');
                    LogWrite ('+', sm (smlBrowsingFArea) + ZeroMsg (FileArea. Name, True));
                    InitMore (0);
                    DispFilesBBS ('*.*', '', False, False, tB);
                  End;
                {$IFDEF WIN32}
                  If Application. Terminated Then Exit;
                {$ENDIF}
                  If param <> '' Then FileArea := nFileArea;
                End;

  cShowRawDir : Begin
                  If (FileArea. List_Security > R. Security) or
                     (Not FlagsValid (R. Flags, FileArea. List_Flags)) Then
                  Begin
                    If R. HotKeys Then ComWriteLn ('', 0);
                    Message (lang (laSecurityLow));
                    wFin := True;
                  End;

                  SetTitle ('browsing file area as a raw dir');
                  LogWrite ('+', sm (smlBrowsingFArea) + ZeroMsg (FileArea. Name, True));
                  InitMore (0);
                  DispFilesBBS ('*.*', '', False, True, tB);
                End;

    cArcView :  Begin
                  If Trim (Param) = '' Then
                  Param := JustFileName (GetAnswer (lang (laQueryArcName), 12, ofAllowEmpty, ''));

                  If (Not IsDevice (Param)) And
                     InFilesBBS (Param) And
                     (mFileExist (FileArea. DLPath, Param) <> '') Then
                  Begin
                    Cls;
                    OnlineArcView (mFileExist (FileArea. DLPath, Param));
                  End Else
                  If Trim (Param) <> '' Then
                  Begin
                    ComWrite ('|\12' + lang (laFileName), eoCodes+eoMacro);
                    ComWrite (Param, 0);
                    ComWrite (lang (laNotFound), eoCodes+eoMacro);
                    Message ('');
                  End;
                End;

    cDisplayFile : Begin
                     LogWrite ('+', sm (smlShowFile) + Trim (NiceFileName
                              (DefaultName (Param, EmuExt [R. Emu],
                              lang (laTxtFiles)), 50)));
                     EmuDispFile (Param);
                   End;

    cPageSysOp : PageSysOp (Param);

    cShell : Begin
               LogWrite ('+', sm (smlEnterDW));
               GetDir (0, CurDir);
               CommandProcessor;
             {$IFDEF WIN32}
               If Not Application. Terminated Then
             {$ENDIF}
               LogWrite ('+', sm (smExitDW));
               SmartChDir (CurDir);
             End;

    cChangeMsgArea : If Param = '' Then SelectMArea Else
                     Begin
                       OpenMsgAreas;
                       ReadMsgArea (nMsgArea, Str2Long (Param));
                       CloseMsgAreas;
                       If nMsgArea. Name <> '' Then MsgArea := nMsgArea;
                     End;

   cChangeMsgGroup : If Param = '' Then SelectMGroup Else
                     Begin
                       OpenMsgGroups;
                       ReadMsgGroup (nMsgGroup, Str2Long (Param));
                       CloseMsgGroups;
                       If nMsgGroup. Name <> '' Then MsgGroup := nMsgGroup;
                     End;

    cReadMsgs : Begin
                  SetTitle ('reading messages');
                  LogWrite ('+', sm (smlReadingMsg) + ZeroMsg (MsgArea. Name, True));
                  ReadMsgs (0);
                End;

    cListMsgs : Begin
                  SetTitle ('browsing messages list');
                  LogWrite ('+', sm (smlListingMsg) + ZeroMsg (MsgArea. Name, True));
                  ListMsgs;
                End;

    cVerInfo : Information;

   cExecRexx : Begin
               {$IFDEF OS2}
                 LogWrite ('+', 'Executing REXX program ' + Trim (NiceFileName (Param, 50)));
                 If Not ExecRexx (Param) Then LogWrite ('!', 'Unable to execute REXX program');
               {$ENDIF}
               End;

    cExec    : Begin
                 Param := TranslateExecParams (Param);
                 SetTitle ('executing external program');
                 LogWrite (':', sm (smlExec) + param);
                 DosShell (Param, exCommand, True);
               End;

    cExecScript : If Param <> '' Then
                  If FileExists (DefaultName (ExtractWord (1, Param, [' ']), 'trs', lang (laTrsFiles))) Then
                  Begin
                    SetTitle ('executing script ' + DefaultName (Param, 'trs', ''));
                    LogWrite ('%', sm (smlExecScript) + Trim (NiceFileName
                             (DefaultName (Param, 'trs', lang (laTrsFiles)), 50)));
                    ExecScript (Param);
                  End Else
                    LogWrite ('!', sm (smFile) + Trim (NiceFileName
                             (Param, 50)) + sm (smNotFound));

    cScan_NewFiles : GlobalSearch ('*.*', True, atAsk, '');

    cScan_PrivMail : SearchPrivate;

    cSet_Msg_On    : Begin
                       LogWrite ('+', sm (smlEnabelingFrom));
                       mL_EnableMsg;
                       Message ('|'+lang (laMsgsEnabeled));
                     End;

    cSet_Msg_Off   : Begin
                       LogWrite ('+', sm (smlDisabelingFrom));
                       mL_DisableMsg;
                       Message ('|'+lang (laMsgsDisabeled));
                     End;

    cSend_Msg      : Begin
                       cLine := mL_ChooseLine;
                       If cLine = BbsLine Then wFin := True;
                       If cLine = 0 Then wFin := True
                                    Else
                       Begin
                         If Not mL_GetMesgStat (cLine) Then
                         Begin
                           Message ('|'+lang (laLineDisabeled));
                           wFin := True;
                           Exit;
                         End;
                         mL_SendMsg (CLine, GetAnswer (lang (laSendMessage),
                           55, ofAllowEmpty, ''), mtUserMsg);
                         LogWrite ('+', sm (smlSendingMsg) + Long2Str (CLine));
                       End;
                     End;

    cLine_List : Begin
                   LogWrite ('+', sm (smlOnLineList));
                   mL_WhoDo (lmAll);
                   Message ('');
                 End;

    cChangeParam : ChangeParam (Letters [Param [1]]);

    cReLogin : Begin
                 If TimeCount Then
                 Begin
                   R. TotalTime := R. TotalTime - (MidSec - EnterTime);
                   R. TimeUsedToday := (MidSec - EnterTime) + R. TimeUsedToday;
                 End;

                 R. LastDate := Ent;
                 R. LastTime := EntT;
                 SaveUser (R);

                 FillChar (R, SizeOf (R), #0);
                 ReadLanguage (Language, Cnf. DefLangFile);
                 R. Lang := UpString (JustName (Cnf. DefLangFile));
                 Registering := True;
                 TimeCount := False;
                 ClearReps;
                 mL_Done;
                 EnterTime := MidSec;
                 enTime := MidSec;
                 Login;
               End;

    cTodaysCallers : TodaysCallers;

    cNews : fNews (False);

    cTypeFile : Begin
                  If Param = '' Then
                  Param := JustFileName (GetAnswer (lang (laAskFileName), 12, ofAllowEmpty, ''));

                  If Trim (Param) <> '' Then
                  Begin
                    If (Not IsDevice (Param)) And
                       InFilesBBS (Param) And
                       (mFileExist (FileArea. DLPath, Param) <> '') Then
                    Begin
                      ComWriteLn ('', 0);
                      TypeFile (mFileExist (FileArea. DLPath, Param));
                      Message ('');
                    End Else
                    Begin
                      ComWrite ('|\12' + lang (laFileName), eoCodes+eoMacro);
                      ComWrite (Param, 0);
                      ComWrite (lang (laNotFound), eoCodes+eoMacro);
                      Message ('');
                    End;
                  End;

                End;

    cGlobalSearch : Begin
                      If Param = '' Then
                      Param := GetAnswer (lang (laSearchMask), 12, ofAllowEmpty, '');
                      If Trim (Param) <> '' Then GlobalSearch (Param, False, atNo, '');
                    End;

    cConference : mL_RealTimeConference;

     cNextMsgArea : QuickChangeMArea (1);

     cPrevMsgArea : QuickChangeMArea (-1);

    cNextFileArea : QuickChangeFArea (1);

    cPrevFileArea : QuickChangeFArea (-1);

    cNextMsgGroup : QuickChangeMGroup (1);

    cPrevMsgGroup : QuickChangeMGroup (-1);

   cNextFileGroup : QuickChangeFGroup (1);

   cPrevFileGroup : QuickChangeFGroup (-1);

   cHTML :
{$IFDEF AUTHOR}
{.$IFNDEF WIN32}
           BrowseHTML (Param)
{.$ENDIF}
{$ENDIF};

   cTelnet        : fGoTelnet (Param);
   cFinger        : DoFinger (Param);

   cDownLoadQWK   : qwkDownLoad;
   cUpLoadQWK     : qwkUpLoad;
   cSelectQWK     : qwkSelect;

  End;
End;

Procedure ArrowedMenu;
Var
  i, CurItem, oItem,
  Amount, TailItems         : LongInt;
  MaxLength, Hor,
  Ver, mL, InitX            : Byte;
  C                         : Char;
  Selected, Found,
  NoCycles, nL              : Boolean;
  S                         : String;

Function GetXCoord (Item: LongInt): Byte;
Var
  X : Byte;

Begin
  X := Trunc (Item/mHeader. ArrowVer)*MaxLength+mHeader. StartX;
  If X > mHeader. StartX Then Inc (X, Trunc (Item/mHeader. ArrowVer));
  GetXCoord := X;
End;

Function GetYCoord (Item: LongInt): Byte;
Begin
  GetYCoord := Item-Trunc (Item/mHeader. ArrowVer)*mHeader. ArrowVer+mHeader. StartY;
End;

Function Secured (M: tMenuItem): Boolean;
Begin
  Secured := (R. Security < M. Security) Or Not FlagsValid (R. Flags, M. Flags);
End;

Procedure FoundNext (Direction: Char);
Begin
  Found := False;
  oItem := CurItem;

  While (CurItem <= Amount-1) And (CurItem >= 0) Do
  Begin
    Case Direction Of
      kbUp    : Dec (CurItem);
      kbDown  : Inc (CurItem);
      kbRight : Inc (CurItem, mHeader. ArrowVer);
      kbLeft  : Dec (CurItem, mHeader. ArrowVer);
      kbHome  : Begin
                  CurItem := -1;
                  Direction := kbLeft;
                End;
      kbEnd   : Begin
                  CurItem := Amount;
                  Direction := kbRight;
                End;
    End;

    If (CurItem > Amount-1) Or (CurItem < 0) Then
    Begin
      If Direction in [kbRight, kbLeft] Then
      Begin
        Case Direction Of
          kbRight : CurItem := Amount-1;
          kbLeft : CurItem := 0;
        End;

        MU1 := PMenuItem (MenuItems^. At (CurItem))^;

        While Secured (MU1) Or (MU1. Action = cDisplayOnly) Do
        Begin
          Case Direction Of
            kbRight : Dec (CurItem);
            kbLeft : Inc (CurItem);
          End;

          If CurItem > Amount-1 Then
          Begin
            CurItem := Amount-1;
            Break;
          End;

          If CurItem < 0 Then
          Begin
            CurItem := 0;
            Break;
          End;

          MU1 := PMenuItem (MenuItems^. At (CurItem))^;
        End;

        Found := True;
      End;

      Break;
    End;

    MU1 := PMenuItem (MenuItems^. At (CurItem))^;

    If (Not Secured (MU1) Or (Cnf. ShowSecured <> ssHidden)) And
       (MU1. Action <> cDisplayOnly) Then
    Begin
      Found := True;
      Break;
    End;
  End;

  If Not Found Then CurItem := oItem;
End;

Function ExecAction: Boolean;
Begin
  If Secured (MU) Then
  Begin
    ComWrite (#7, 0);
    ExecAction := False;
  End Else
  Begin
    ComWrite (EmuColor ($07), 0);
    If Not (MU. Action in [cExecScript, cReturn, cGosub, cGoTo]) Then Cls;
    LightedArrItem := CurItem;
    ExecAction := ExecMenuAction (MU. Action, MU. OptData);
  End;
End;

Function GetItemsCount: LongInt;
Begin
  GetItemsCount := MenuItems^. Count-TailItems-1;
End;

Procedure NextLine (Ver: Byte);
Begin
  If R. Emu = teTTY Then
     If Ver<mHeader. ArrowVer Then ComWrite (#10#13+Replicate(' ',GetXCoord (Ver)-1), 0)
     Else ComWriteLn('',0)
  Else
  Begin
    CurItem := Ver + 1;
    ComWrite (EmuGoToXY (GetXCoord (CurItem-1),
    GetYCoord (CurItem-1)), 0);
  End;
End;

Begin {ArrowedMenu}
  mL := 0;
  CurItem := 0;
  TailItems := 0;
  i := -1;

  While True Do
  Begin
    Inc (i);
    If i > GetItemsCount Then Break;
    MU := PMenuItem (MenuItems^. At (i))^;

    If MU. AutoExec And Not Secured (MU) Then
    Begin
      ExecMenuAction (MU. Action, MU. OptData);
      DisposeMenuItem (MenuItems^. At (i));
      MenuItems^. AtDelete (i);
    End Else
    If Secured (MU) And (MU. AutoExec Or (Cnf. ShowSecured = ssHide)) Then
    Begin
      DisposeMenuItem (MenuItems^. At (i));
      MenuItems^. AtDelete (i);
      Dec (i);
    End Else
    If (MU. Display = '') And (MU. Action <> cDisplayOnly) Then
    Begin
      DisposeMenuItem (MenuItems^. At (i));
      MenuItems^. AtDelete (i);
      MenuItems^. Insert (NewMenuItem (MU));
      Inc (TailItems);
      Dec (i);
    End;
  End;

  Amount := MenuItems^. Count-TailItems;
  If Amount > mHeader. ArrowVer*mHeader. ArrowHor Then
     Amount := mHeader. ArrowVer*mHeader. ArrowHor;

  If Amount = 0 Then
  While True Do ComReadKey;

  For i := 0 To MenuItems^. Count-1 Do
  Begin
    MU := PMenuItem (MenuItems^. At (i))^;
    If Length (ZeroMsg (MU. Display, True)) > mL Then
      mL := Length (ZeroMsg (MU. Display, True));
  End;

  MaxLength := mL;
  mL := Trunc ((80-mHeader. ArrowHor-mHeader. StartX)/mHeader. ArrowHor);
  If MaxLength  > mL Then MaxLength := mL;

  If R. Emu <> teTTY Then ComWrite (EmuGoToXY (GetXCoord (0), GetYCoord (0)), 0)
  else ComWrite (Replicate(' ',GetXCoord (0)-1),0);
  nL := False;

  For Ver := 1 To mHeader. ArrowVer Do
  For Hor := 1 To mHeader. ArrowHor Do
  Begin
    CurItem := (Hor-1) * mHeader. ArrowVer + Ver;

    If CurItem <= MenuItems^. Count Then
    Begin
      If nL Then NextLine (Ver-1);
      nL := False;

      PMenuItem (MenuItems^. At (CurItem-1))^. Display :=
      PlaceSubStr (PMenuItem (MenuItems^. At (CurItem-1))^.
      Display, '|', '');

      MU := PMenuItem (MenuItems^. At (CurItem-1))^;

      If Secured (MU) Then
      If Cnf. ShowSecured = ssHidden Then
      If R. Emu = teTty Then MU. Display := '' Else
      Begin
        ComWrite (EmuColor (Cnf. ColorScheme [mnHidden]), 0);
        MU. Display := ZeroMsg (MU. Display, True);
      End;

      mWriteLen (MU. Display, MaxLength, pmPadRight);

      If Hor = mHeader. ArrowHor
      Then NextLine (Ver)
      Else ComWrite (' ', 0);

    End Else
      nL := True;
  End;

  If LightedArrItem < GetItemsCount+1 Then CurItem := LightedArrItem Else CurItem := 0;
  Selected := False;
  Found := False;
  NoCycles := True;

  MU := PMenuItem (MenuItems^. At (CurItem))^;
  While (CurItem < MenuItems^. Count-1) And
        (CurItem >= 0) And Secured (MU) Or
        (MU. Action = cDisplayOnly) Do
  Begin
    Inc (CurItem);
    NoCycles := False;
    MU := PMenuItem (MenuItems^. At (CurItem))^;
    If Not Secured (MU) And (MU. Action <> cDisplayOnly) Then
    Begin
      Found := True;
      Break;
    End;
  End;

  InLightBarMenu := True;
  If Not Found And Not NoCycles Then
  While {$IFDEF WIN32} Not Application. Terminated
        {$ELSE} True
        {$ENDIF} Do ComReadKey;

  Repeat
    If R. Emu = teTTY Then
    Begin
      C := UpCase (ComReadKey);
    {$IFDEF WIN32}
      If Application. Terminated Then Exit;
    {$ENDIF}

      For i := 0 To MenuItems^. Count-1 Do
      Begin
        MU1 := PMenuItem (MenuItems^. At (i))^;
        If (MU1. HotKey = C) and Not Secured(MU1) Then
        Begin
          Selected := True;
          If MU1. Action <> cExecScript Then Cls;
          If ExecMenuAction (MU1. Action, MU1. OptData) Then Exit;
        End
        Else If (i = MenuItems^. Count-1) And Cnf. CRInMenu
             Then If (MidSec-LastDraw > 1) Or (MidSec-LastDraw < 0) Then Exit
                  Else  LastDraw := MidSec;
      End;
    End Else
    Begin
      MU := PMenuItem (MenuItems^. At (CurItem))^;
      ComWrite (EmuGoToXY (GetXCoord (CurItem), GetYCoord (CurItem)) + EmuColor (mHeader. SelectedColor), 0);
      S := ZeroBackGround (MU. Display);
      mWriteLen (S, MaxLength, pmNone);
      ComWrite (EmuGoToXY (GetXCoord (CurItem),
      GetYCoord (CurItem)) + EmuColor ($07), 0);

      Repeat
        C := UpCase (ComReadKey);
      {$IFDEF WIN32}
        If Application. Terminated Then Exit;
      {$ENDIF}
        oItem := CurItem;

        If C in [kbUp..kbEnd] Then FoundNext (C) Else
        If C = #13 Then
        Begin
          If ExecAction Then Exit;
        End Else
        For i := 0 To MenuItems^. Count-1 Do
        Begin
          MU1 := PMenuItem (MenuItems^. At (i))^;
          If MU1. HotKey = C Then
          Begin
            If (Cnf. ShowSecured = ssHidden) And Secured (MU1) Then
            Begin
              ComWrite (#7, 0);
              Break;
            End;

            CurItem := i;

            If R. HotKeys Or (MU1. Display = '') Then
            Begin
              MU := MU1;
              If ExecAction Then Exit;
            End;

            Break;
          End
          Else If (i = MenuItems^. Count-1) And Cnf. CRInMenu
               Then If (MidSec-LastDraw > 1) Or (MidSec-LastDraw < 0) Then Exit
                    Else  LastDraw := MidSec;
        End;

      Until oItem <> CurItem;

      If Not Selected Then mWriteLen (MU. Display, MaxLength, pmNone);
    End;
  Until Selected;
End;

Var
  dFile, oFN : PathStr;

Label
  Loop2,
  Loop3,
  NoChat;

Begin {DoMenu}
{$IFDEF WIN32}
  Application. ProcessMessages;
  If Application. Terminated Then Exit;
{$ENDIF}

  If Not UseMenu (FileName) Then
  Begin
    FileName := GetStr (Menus^. At (Menus^. Count-1));
    Menus^. AtFree (Menus^. Count-1);
    Exit;
  End;

  dFile := mHeader. DisplayFile;

  Loop2:
  UpdateUserMacro;
  mL_LineMsg;
  LastDraw := MidSec;

  { Ž¡à ¡®âª  HEADER'     }

  mHeader. DisplayFile := dFile;
  If IsOpen And InGosub Then InGosub := False;
  mHeader. DisplayFile := Trim (mHeader. DisplayFile);
  If mHeader. DisplayFile = #255 Then mHeader. DisplayFile := '';

  { ‚ë¢®¤ ANSI-ä ©«  ¬¥­î }

  If (mHeader. DisplayFile <> '')
  Then DispFile (DefaultName (mHeader. DisplayFile,
       EmuExt [R. Emu], lang (laTxtFiles)))
  Else If mHeader. ArrowHor = 0 Then Cls;

  HotKeys := '';
  MU. Action := 1;
  Breaked := False;
  SetDebugFile (lang (laMenus) + FileName + '.mnu');
  SetTitle ('browsing menu ' + FileName + '.mnu');

  If (HotKeysStr <> '') or (KeyBuffer <> '') Then
  Begin
    Breaked := True;
    mHeader. DisplayFile := #255;
  End;

  If (mHeader. ArrowHor <> 0) And (mHeader. ArrowVer <> 0) Then
  Begin
    ArrowedMenu;
    Exit;
  End;

  ic := 0;

  While True Do
  Begin
    If R. HotKeys Then
    If InComing Then
    Begin
      InAction := True;
      MenuKey := UpCase (ComReadKey);
    {$IFDEF WIN32}
      If Application. Terminated Then Exit;
    {$ENDIF}
      InAction := False;

      If Not FuncKey Then
      Begin
        HotKeys := '';

        If MenuItems^. Count > 0 Then
        For mc := 0 To MenuItems ^. Count-1 Do
        Begin
          MU := PMenuItem (MenuItems^. At (mc))^;
          If MU. Action = 0 Then Break;
          If MU. Action = 17 Then MU. HotKey := ' ';
          If MU. HotKey <> ' ' Then HotKeys := HotKeys + MU. HotKey;
        End;

        KeyBufAdd (MenuKey);
        ClearBuffer;

        mHeader. DisplayFile := #255;
        Breaked := True;
      End;
    End;

    Inc (ic);
    If ic > MenuItems^. Count Then Break;
    MU := PMenuItem (MenuItems^. At (ic-1))^;

    If MU. Action = ActionsNum + 1 Then Continue;
    If MU. Action = 17 Then MU. HotKey := ' ';

    Secured := (R. Security < MU. Security) Or Not FlagsValid (R. Flags, MU. Flags);

    If MU. AutoExec and not Secured Then
    Begin
      oFN := FileName;
      ExecMenuAction (MU. Action, MU. OptData);
      If (oFN <> FileName) Or (MU. Action = cReturn) Then Exit;
    End;

    If (Secured And (Cnf. ShowSecured <> ssHidden)) Or Not Secured Then
    If MU. HotKey <> ' ' Then HotKeys := HotKeys + MU. HotKey;

    If mHeader. DisplayFile = '' Then
    If Secured Then
    Begin
      If Cnf. ShowSecured = ssShow Then ComWrite (MU. Display, eoMacro + eoCodes) Else
      If Cnf. ShowSecured = ssHidden Then
        ComWrite (EmuColor (Cnf. ColorScheme [mnHidden]) +
        ZeroMsg (MU. Display, False), eoMacro + eoCodes)
      Else ComWrite (Replicate ('|', SymbolCount (MU. Display, '|')), eoCodes);
    End Else
       ComWrite (MU. Display, eoMacro + eoCodes);

  End;

  If Not Breaked Then
  Begin
    If mHeader. WriteHotKeys Then
    Begin
      ComWriteLn ('', 0);
      ComWriteLn ('[' + HotKeys + ']', 0);
    End;

    Frame;
    If (Not R. Frames) or (EmuGoToXY (1, 1) = '') Then ComWriteLn ('', 0);
    ComWrite (mHeader. Prompt, eoMacro + eoCodes);
  End;

  Loop3:
  ProcessChoices;
  MenuKey := UpCase (ComReadKey);
{$IFDEF WIN32}
  If Application. Terminated Then Exit;
{$ENDIF}

  If Pos (MenuKey, HotKeys) = 0 Then
  Begin
    If Cnf. CRinMenu Then
    Begin
      If (MidSec-LastDraw > 1) Or (MidSec-LastDraw < 0) Then GoTo Loop2
      Else Begin
        LastDraw := MidSec;
        GoTo Loop3;
      End;
    End Else
      GoTo Loop3;
  End;

  If R. HotKeys Then
  Begin
    If Not (MenuKey in [#1..#31]) Then ComWrite (MenuKey, 0);
  End Else
    If HotKeysStr = '' Then ComWriteLn ('', 0);

  If ((KeyBuffer = '') and (HotKeysStr = '')) Or (R. HotKeys and
     (EmuGoToXY (1, 1) = '')) Then ComWriteLn ('', 0);

  mL_LineMsg;

  {€­ «¨§ ­ ¦ â®© ª« ¢¨è¨}
  MU. Action := 1;
  wFin := False;
  mc := 0;

  While Not wFin Do
  Begin
    Inc (mc);
    If mc > MenuItems^. Count Then Break;
    MU := PMenuItem (MenuItems^. At (mc-1))^;

    If MenuKey = MU. HotKey Then
    Begin
      If (R. Security < MU. Security) or
         (Not FlagsValid (R. Flags, MU. Flags)) Then
      Begin
        If R. HotKeys Then ComWriteLn ('', 0);
        If (Cnf. ShowSecured <> ssHide) Then Message (lang (laSecurityLow));
        Break;
      End;

      SmartLine;

      If ExecMenuAction (MU. Action, MU. OptData) Then
      Begin
      {$IFDEF WIN32}
        If Application. Terminated Then Exit;
      {$ENDIF}
        If mHeader. DisplayFile = #255 Then mHeader. DisplayFile := '';
        Exit;
      End;

    End;

  End;
  GoTo Loop2;
End;

Procedure fUserInfo (Name: String);
Var
  TmpUser          : tUser;
  i, Num, {SysOpNum,} k, ListNum,
  CurNum, j        : LongInt;
  S                : String;
  HList            : PNotSortedCollection;

Label
  NotFound,
  Loop,
  MN,
  Loop1;

Begin
{$IFDEF WIN32}
  If Application. Terminated Then Exit;
{$ENDIF}
  InputAccept := NumbersOnly;
  Name := Trim (Name);
  Loop1:
  S := '';
  HList := New (PNotSortedCollection, Init (1, 1));
  ReadList (Cnf. HideUsersList, HList);

  If Name = '' Then
  Begin
    Cls;
    Num := UsersNum;
    ComWriteLn (lang (laUsersHead), eoMacro + eoCodes);
    ComWriteLn (EmuColor (Cnf. ColorScheme [umSeparator]) +
      'ÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄÄ', eoMacro + eoCodes);

    InitMore (WhereY);

    CurNum := 0;
    For j := 1 To Num Do
    Begin
      If DrawAborted Then Begin Dispose (HList, Done); Exit; End;
      GetUserByNum (j, TmpUser);

      If (HList^. Contains (TmpUser. Name) and
         (R. Name <> Cnf. SysOp)) Then
      Begin
        Continue;
      End;
      Inc (CurNum);

      ComWriteLn (EmuColor (Cnf. ColorScheme [ulNumbers]) + LeftPadCh
                 (Long2Str (CurNum), ' ', 4) + ' ' + EmuColor (Cnf. ColorScheme
                 [ulName]) + PadCh (TmpUser. Name, ' ', 36) + ' ' + EmuColor
                 (Cnf. ColorScheme [ulLocation]) + PadCh (Copy
                 (TmpUser. Location, 1, 15), ' ', 15) + ' ' + EmuColor
                 (Cnf. ColorScheme [ulBirthDate]) + PadCh (ReFormatDate
                 (Long2Date (TmpUser. BirthDate), DefaultDateMask, Cnf. DateMask), ' ',
                  10) + ' ' + EmuColor (Cnf. ColorScheme [ulLastDate]) +
                  ReFormatDate (Long2Date (TmpUser. LastDate), DefaultDateMask, Cnf.
                  DateMask), 0);

      MN:

      If (R. Security < Cnf. UserInfoMinSec) Or Not FlagsValid (R. Flags, Cnf. UserInfoMinFlags) Then
      Begin
        If Not More Then Begin Dispose (HList, Done); Exit; End;
      End Else
        If Not MoreNums (S, lang (laEnterUsrNums) )Then Begin Dispose (HList, Done); Exit; End;

    {$IFDEF WIN32}
      If Application. Terminated Then Exit;
    {$ENDIF}

      InputAccept := NumbersOnly;

      If S <> '' Then
      Begin
        i := Str2Long (S);
{        If (i < 1) Or (i > j) Then}
        If (i < 1) Or (i > CurNum) Then
        Begin
          MoreLines := R. Lines;
          S := '';
          GoTo MN;
        End;

        ListNum := 0;
        For k := 1 To j Do
        Begin
          GetUserByNum (k, TmpUser);
          If (HList^. Contains (TmpUser. Name) and
             (R. Name <> Cnf. SysOp)) Then
          Begin
            Continue;
          End;

          Inc (ListNum);

          If i = ListNum Then
          Begin
            i := k;
            Break;
          End;
        End;

        Name := GetUserName (i);
        Break;
      End;
    End;

  End;

  If Trim (Name) = '' Then
  If (R. Security >= Cnf. UserInfoMinSec) And FlagsValid (R. Flags, Cnf. UserInfoMinFlags) Then
  Begin
    ComWriteLn ('', 0);
    ComWrite (lang (laEnterUsrNums), eoCodes + eoMacro);
    S := '';
    ComReadLn (S, 4, ofAllowEmpty);
  {$IFDEF WIN32}
    If Application. Terminated Then Exit;
  {$ENDIF}

    i := Str2Long (S);
    If (i < 1) Or (i > CurNum) Then Begin Dispose (HList, Done); Exit; End;

    ListNum := 0;
    For k := 1 To j Do
    Begin
      GetUserByNum (k, TmpUser);
      If (HList^. Contains (TmpUser. Name) and
         (R. Name <> Cnf. SysOp)) Then
      Begin
        Continue;
      End;
        Inc (ListNum);
        If i = ListNum Then
      Begin
        i := k;
        Break;
      End;
    End;

    Name := GetUserName (i);
    ComWriteLn ('', 0);
  End Else
  Begin
    Message ('');
    Exit;
  End Else
    ComWriteLn ('', 0);

  If Not Is_User (Name, Cnf. Aliases) Then
  Begin
    NotFound:
    Dispose (HList, Done);
    Message (lang (laUser) + Name + lang (laUserNotFound));
    Exit;
  End;

  If Name <> R. Name Then
    GetUser (Name, TmpUser, Cnf. Aliases)
  Else
    TmpUser := R;

  If HList^. Contains (TmpUser. Name) and
     (R. Name <> Cnf. SysOp)
  Then GoTo NotFound;

  SmartLine;
  With TmpUser Do
  Begin
    Cls;
    ComWrite ('|' + tGlob. lang (laInfoName) + Name, eoMacro + eoCodes);
    If Alias <> '' Then ComWrite (' (' + Alias + ')', 0);
    ComWriteLn ('', 0);

    ComWrite (tGlob. lang (laInfoLoc), eoMacro + eoCodes); ComWriteLn (Location, 0);
    ComWrite (tGlob. lang (laInfoOrg), eoMacro + eoCodes); ComWriteLn (Organization, 0);
    ComWrite (tGlob. lang (laInfoAddress1), eoMacro + eoCodes); ComWriteLn (Address1, 0);
    ComWrite (tGlob. lang (laInfoAddress2), eoMacro + eoCodes); ComWriteLn (Address2, 0);
    ComWrite (tGlob. lang (laInfoAddress3), eoMacro + eoCodes); ComWriteLn (Address3, 0);
    ComWrite (tGlob. lang (laInfoHPhone), eoMacro + eoCodes); ComWriteLn (HPhone, 0);
    ComWrite (tGlob. lang (laInfoBPhone), eoMacro + eoCodes); ComWriteLn (BPhone, 0);

    ComWrite (tGlob. lang (laInfoFirstCall), eoMacro + eoCodes);
    ComWriteLn (ReFormatDate (Long2Date (FirstDate), DefaultDateMask, Cnf. DateMask), 0);

    ComWrite (tGlob. lang (laInfoLastCall), eoMacro + eoCodes);
    ComWriteLn (ReFormatDate (Long2Date (LastDate), DefaultDateMask, Cnf. DateMask), 0);

    ComWrite (tGlob. lang (laInfoBirthDate), eoMacro + eoCodes);
    ComWriteLn (ReFormatDate (Long2Date (BirthDate), DefaultDateMask, Cnf. DateMask), 0);

    ComWrite (tGlob. lang (laInfoSecurity), eoMacro + eoCodes); ComWriteLn (Long2Str (Security), 0);
    ComWrite (tGlob. lang (laInfoCallNum), eoMacro + eoCodes); ComWriteLn (Long2Str (NoCalls), 0);
  End;

  Message ('');

  If S <> '' Then
  Begin
    Name := '';
    GoTo Loop1;
  End;
  Dispose (HList, Done);
End;

Procedure fNormExit;
Var
  AddTime, i : LongInt;
  AddSize    : LongInt;

Const
  Gone : Boolean = False;

Begin
  LogWrite ('#', 'fNormExit begin...');
  {$IFDEF SOUND}
  {$IFDEF MSDOS}
  If UseWav Then closesound(0);                        {close file 0}
  {$ENDIF}
  {$ENDIF}
  If Gone Then Exit;
  Gone := True;
  LogWrite ('#', 'NormExit now...');
(*  ExecScript ('onexit');*)
(*
{$IFDEF OS2}
{  LogWrite ('#', 'ExecRexx now');}
{$ENDIF}
{  ExecRexx ('onexit');}
{$IFDEF OS2}
{  LogWrite ('#', 'ExecRexx done');}
{$ENDIF}
*)
  ExitProc := Nil;

{$IFDEF OS2}
  NeedThreadClose := True;
  Repeat Until Not ThreadLocked;
{$ENDIF}

  If Language <> Nil Then
    mL_SendMsg (0, trcSysMsgPrefix + '** ' + R. Name + lang (laTRCline) +
    Long2Str (BbsLine) + lang (laTRCleftBBS), mtConference);

  If TransferTime > 0 Then
  Begin
    AddTime := Round (TransferTime/60)*Cnf. UploadTimePlus;
    If AddTime > 0 Then Inc (R. TotalTime, AddTime * 60);
  End;
  If TransferSize > 0 Then
  Begin
    AddSize := TransferSize * Cnf. UploadSizePlus;
    If AddSize > 0 Then Inc (R. DailySize, AddSize);
  End;

  ClearCL;
{  LogWrite ('#', 'ClearCL done');}

  HiddenCursor;
{$IFNDEF WIN32}
  DoneTornadoScreen;
  CenterDelayTempBox (Cnf. ColorScheme [cdFrame], Cnf. ColorScheme [cdText],
  1, CenterCh (sm (smNormalExit) + '..', ' ', 30), ZoomSpeed, '');
{$ENDIF}
{  LogWrite ('#', 'Screen done');}

  qwkWriteList;
{  LogWrite ('#', 'QWK done');}
  If Kill_Line_Flag Then EraseFlag (RunFlag);
  SaveTime;
{  LogWrite ('#', 'SaveTime done');}
  SaveTagList;
{  LogWrite ('#', 'SaveTag done');}
  SaveDoReg;
{  LogWrite ('#', 'SaveDoReg done');}
  ClearReps;
{  LogWrite ('#', 'ClearReps done');}
  mL_Done;

  If Is_User (R. Name, Cnf. Aliases) Then
  LogWrite ('~', R. Name + sm (smUsrFinished) +
   Long2Str (Round ((MidSec - enTime)/60)) + sm (smMin) +
   Long2Str (SessionDL) + '/' + Long2Str (SessionUL));

  If InChat Then
  Begin
    If R. Emu <> teTTY Then
    Begin
      If SysOpText<>nil Then
      Begin
        (*
        WriteLn (ChatLog, '*** [ ' + Cnf. SysOp + ' ]');
        With SysOpText^ Do For i := 0 To Count-1 Do WriteLn (ChatLog, GetStr (At (i)));
        WriteLn (ChatLog);
        *)
        Dispose (SysOpText, Done);
      End;
      If UserText<>nil Then
      Begin
        (*
        WriteLn (ChatLog, '*** [ ' + R. Name + ' ]');
        With UserText^ Do For i := 0 To Count-1 Do WriteLn (ChatLog, GetStr (At (i)));
        *)
        Dispose (UserText, Done);
      End;
    End;

    WriteLn (ChatLog);
    WriteLn (ChatLog, sm (smChatLogClosed));
    Close (ChatLog);
    Inc (R. TotalTime, MidSec-ChatStartTime);
  End;

  If (Not Local And Not InitError) Or LocalOffHook
     {$IFDEF WIN32} And P. Open {$ENDIF} Then
  Begin
{    LogWrite ('#', 'HangUp now');}
    HangUp;
{    LogWrite ('#', 'DonePort now');}
  {$IFDEF MSDOS}
    ptOptionsOn (P, ptRestoreOnClose);
    ptOptionsOn (P, ptDropModemOnClose);
  {$ENDIF}
  {$IFNDEF WIN32}
    DonePort (P);
  {$ELSE}
    If Prot. InProgress Then Prot. CancelProtocol;
  {$ENDIF}
  End;

  If Not Exeption Then LogWrite (':', sm (smEnd));
  WriteSystemStatus (Sys, Cnf. Path + 'system.tor');

{$IFDEF MSDOS}
  OvrDisposeStreams;
{  LogWrite ('#', 'Overlay disposed');}
{$ENDIF}

{$IFNDEF WIN32}

{$IFNDEF OS2}
  { LogWrite ('&', 'Disposing Language'); } If Language <> Nil Then Dispose (Language, Done);
  { LogWrite ('&', 'Disposing ReadHistory'); } If ReadHistory <> Nil Then Dispose (ReadHistory, Done);
  { LogWrite ('&', 'Disposing Reps'); } If Reps <> Nil Then Dispose (Reps, Done);
  { LogWrite ('&', 'Disposing Menus'); } If Menus <> Nil Then Dispose (Menus, Done);
  { LogWrite ('&', 'Disposing UpFiles'); } If UpFiles <> Nil Then Dispose (UpFiles, Done);
  { LogWrite ('&', 'Disposing ParamNames'); } If ParamNames <> Nil Then Dispose (ParamNames, Done);
  { LogWrite ('&', 'Disposing MsgText'); } If MsgText <> Nil Then Dispose (MsgText, Done);
{$ENDIF}

  DoneTempBox;
  LogClose;

  NormalCursor;
  Window (1, 1, 80, ScrY + 1);
  GotoXY (WXG, WYG);
  TextAttr := 3;

{$IFDEF MSDOS}
{$IFDEF DEBUG}

  WriteLn ('þ XMS memory free: ' + Long2Str (XMS_MemAvail));
  WriteLn ('þ EMS memory free: ' + Long2Str (EMS_MemAvail));

{$ENDIF}
{$ENDIF}

  WriteLn ('þ ' + sm (smNormalExit) + '..');
{$IFNDEF OS2}
  If SysMes <> Nil Then Dispose (SysMes, Done);
{$ENDIF}
  TextAttr := 7; WriteLn;
  RestBlink;
{$ENDIF}

{$IFDEF MSDOS}
  SetCBreak (CtrlCState);
  RestoreVecs;
{$ENDIF}

{$IFNDEF WIN32}
  SetTitle (SaveTitle);
  SmartChDir (oDir);
  Halt (ExitCode);
{$ELSE}

  If AfterCommand <> '' Then
  With MainForm. Executer Do
  Begin
    Clear;
    Wait := False;
    ChangeDir := False;
    ExeParams. Add (AfterCommand);
    Try Execute; Except End;
  End;

  Application. Terminate;
  Application. ProcessMessages;
{$ENDIF}
End;

Procedure ErrorExit;
Begin
{$IFDEF OS2}
  NeedThreadClose := True;
  Repeat Until Not ThreadLocked;
{$ENDIF}

{$IFNDEF WIN32}
  ExitProc := Nil;

  If ExitCode in [208, 209] Then
  Begin
    DoneTornadoScreen;
    Window (1, 1, ScrX + 1, ScrY + 1);
    GotoXY (WXG, WYG);
    WriteLn ('! ' + sm (smOvrError));
    Halt (209);
  End;
  If ExitCode = 203 Then
  Begin
    DoneTornadoScreen;
    Window (1, 1, ScrX + 1, ScrY + 1);
    GotoXY (WXG, WYG);
    WriteLn ('! Heap error at ' + HexL(LongInt(ErrorAddr)));
    WriteLn ('! Free stack: ' + Long2Str(SPtr));
    WriteLn ('! Free mem: ' + Long2Str(MaxAvail));
    LogWrite ('!', 'Heap error at ' + HexL(LongInt(ErrorAddr)));
    LogWrite ('!', 'Free stack: ' + Long2Str(SPtr));
    LogWrite ('!', 'Free mem: ' + Long2Str(MaxAvail));
    Halt (211);
  End;

  HiddenCursor;
  DoneTornadoScreen;
  CenterDelayTempBox (Cnf. ColorScheme [caFrame], Cnf. ColorScheme [caText], 1,
                      CenterCh (sm (smErrorExit) + '..', ' ', 30),
                      ZoomSpeed, '');
{$ENDIF}

  If Cnf. Sound Then Begin
    {$IFDEF WIN32}
    MainForm. PlayerWave1. Stop;
    MainForm. PlayerWave1. WaveName := Cnf. Path + 'theend.wav';
    MainForm. PlayerWave1. Loop := False;
    MainForm. PlayerWave1. Async := True;
    MainForm. PlayerWave1. Play;
    {$ELSE}
    {$IFDEF SOUND}
    {$IFDEF MSDOS}
    If UseWav Then initblaster Else blaster.available := False;
    if blaster.available then
      if opensound (0, Cnf. Path + 'theend.wav') then begin{Open parameter 1 file as file 0}
        startplay(0);                       {start playback of file 0}
        repeat
        until (play.stopped); {Until file reached its end}
      end else
        blaster. available := false
    else
    {$ENDIF}
    {$ENDIF}
      SoundOf ('1 200 1 2 800 1000 -1 2 800');
    {$ENDIF}
  End;
  {$IFDEF SOUND}
  {$IFDEF MSDOS}
  If UseWav Then closesound(0);                        {close file 0}
  {$ENDIF}
  {$ENDIF}
  EraseFlag (RunFlag);

  If ErrorAddr <> Nil Then
  Begin
    LogWrite ('!', sm (smRunTime) + Long2Str (ExitCode));
    ErrorAddr := Nil;
    ExitCode := 211;
  End Else
    LogWrite ('!', sm (smErrorExit));

{  LogClose;}

  SaveTime;
  mL_Done;

  If ((Not Local) and (Not InitError)) or LocalOffHook Then
  Begin
  {$IFDEF MSDOS}
    ptOptionsOn (P, ptRestoreOnClose);
    ptOptionsOn (P, ptDropModemOnClose);
  {$ENDIF}
  {$IFNDEF WIN32}
    DonePort (P);
  {$ELSE}
    P. Open := False;
  {$ENDIF}
  End;

{  LogWrite ('#', 'Port closed');}

{$IFDEF MSDOS}
  OvrDisposeStreams;
{  LogWrite ('#', 'Overlay disposed');}
{$ENDIF}

  LogClose;

{$IFNDEF WIN32}
  DoneTempBox;

  NormalCursor;
  Window (1, 1, ScrX + 1, ScrY + 1);
  GotoXY (WXG, WYG);
  TextAttr := 12;
  WriteLn ('! ' + sm (smErrorExit) + '..'#13#10);
  TextAttr := 7; WriteLn;
  RestBlink;
{$ENDIF}

{$IFDEF MSDOS}
  SetCBreak (CtrlCState);
  RestoreVecs;
{$ENDIF}

  SetTitle (SaveTitle);
  SmartChDir (oDir);
  Halt (ExitCode);
End;

{$IFNDEF WIN32}

Var
  oF2Transfer           : PTagFilesCollection;
  MarkedFiles           : PNotSortedCollection;

Procedure ManualSend;
Var
  CurName, CurDir,
  CurDir1         : PathStr;
  PathBox         : PBoxRec;
  oX, oY, iState  : Byte;
  Changed         : Boolean;
  FileRec         : TTagFileRec;
  oSizeOfAll, i   : LongInt;

Const
  Path   : PathStr = '';

Label
  Loop;

Begin
  ThreadLocked := False;
  GetDir (0, CurDir);

  {
  oX := WhereX;
  oY := WhereY;
  InitWindow (PathBox, 5, 9, 73, 11, 4, Cnf. ColorScheme [cdFrame],
              sm (smInputPath), Cnf. ColorScheme [cdTitle],
              ZoomSpeed, True);

  HiddenCursor;
  DrawWindow (PathBox);
  NormalCursor;

  Loop:
  Path := iLine. Input (9, PathBox^. Y1 + 1, Path, ' ', '', 61, 0, [#32..#175],
          True, iState, Cnf. ColorScheme [cdInput], Changed);

  If iState In [72, 80, 73, 81] Then GoTo Loop Else
  If iState = 27 Then
  Begin
    CloseWindow (PathBox);
    GoToXY (oX, oY);
    Exit;
  End;

  If Trim (Path) = '' Then Path := Copy (CurDir, 1, 3);

  CloseWindow (PathBox);
  GoToXY (oX, oY);
  }
  HiddenCursor;

  MarkedFiles := New (PNotSortedCollection, Init (10, 1));
  If Pane_Process (20, Round (tWin. ScrY/2)-6, pmMultiHalf, ivOnlyName, Path, 'DD-MM-YY',
                  Cnf. Blinking, MarkedFiles) <> pnOk Then
  Begin
    GetDir (0, CurDir1);
    If CurDir <> CurDir1 Then SmartChDir (CurDir);
    NormalCursor;
    Dispose (MarkedFiles, Done);
    Exit;
  End;

  NormalCursor;
  SmartChDir (CurDir);
  If MarkedFiles^. Count = 0 Then
  Begin
    Dispose (MarkedFiles, Done);
    Exit;
  End;

  oF2Transfer := New (PTagFilesCollection, Init (F2Transfer^. Count, 1));

  If F2Transfer^. Count > 0 Then
  For i := 0 To F2Transfer^. Count-1 Do
    oF2Transfer^. Insert (NewTagFile (PTagFileRec (F2Transfer^. At (i))^));

  F2Transfer^. DeleteAll;
  oSizeOfAll := SizeOfAll;
  SizeOfAll := 0;

  While MarkedFiles^. Count > 0 Do
  Begin
    CurName := GetStr (MarkedFiles^. At (0));

    FileRec. PathName := CurName;
    FileRec. AreaNum := 0;
    FileRec. Size := gFileSize (CurName);
    FileRec. FromName := '';
    Inc (SizeOfAll, FileRec. Size);

    F2Transfer^. Insert (NewTagFile (FileRec));

    DisposeStr (MarkedFiles^. At (0));
    MarkedFiles^. AtDelete (0);
  End;

  Dispose (MarkedFiles, Done);
  AutoDL := True;
  Transfer ('', Transmit, tsNormal);
  AutoDL := False;

  F2Transfer^. DeleteAll;
  SizeOfAll := oSizeOfAll;

  While oF2Transfer^. Count > 0 Do
  Begin
    F2Transfer^. Insert (NewTagFile (PTagFileRec (oF2Transfer^. At (0))^));
    DisposeTagFile (oF2Transfer^. At (0));
    oF2Transfer^. AtDelete (0);
  End;
  Dispose (oF2Transfer, Done);

  SmartChDir (CurDir);
End;

Procedure ViewTagList;
Var
  ScrollList            : PNotSortedCollection;
  TagBox                : PBoxRec;
  oX, oY, oAttr         : Byte;
  Size, i               : LongInt;

Begin
  If F2Transfer^. Count <= 0 Then
  Begin
    HiddenCursor;
    CenterTempBox (Cnf. ColorScheme [cdFrame], Cnf. ColorScheme [cdButton],
                   1, sm (smNoTagFiles),
                   ZoomSpeed, sm (smWarningWinTitle));
    NormalCursor;
    Exit;
  End;

  HiddenCursor;
  oX := WhereX;
  oY := WhereY;

  oAttr := TextAttr;

  InitWindow (TagBox, 12, 5, 68, 19, 4, Cnf. ColorScheme [cdFrame],
              '¹  ' + sm (smTagListTitle) + '  Ì',
              Cnf. ColorScheme [cdTitle], ZoomSpeed, True);

  DrawWindow (TagBox);
  ScrollList := New (PNotSortedCollection, Init (10, 1));
  Size := 0;

  For i := 0 To F2Transfer^. Count-1 Do
  Begin

    ScrollList ^. Insert (NewStr (Trim (NiceFileName (PTagFileRec
                         (F2Transfer^. At (i))^. PathName, 55)) + ' ' +
                         NiceFileSize (PTagFileRec (F2Transfer^. At (i))^.
                         Size)));

    Size := Size + PTagFileRec (F2Transfer^. At (i))^. Size;
  End;

  FastWrite ('Æ' + Replicate ('Í', 55) + 'µ', TagBox^. Y1 + 11, 12, Cnf. ColorScheme [cdFrame]);

  FastWrite (sm (smTotalFiles), TagBox^. Y1 + 12, 14, Cnf. ColorScheme [cdText]);
  FastWrite (Long2Str (F2Transfer^. Count), TagBox^. Y1 + 12, 31, Cnf. ColorScheme [cdInput]);

  FastWrite (sm (smTotalSize), TagBox^. Y1 + 13, 14, Cnf. ColorScheme [cdText]);
  FastWrite (NiceFileSize (Size), TagBox^. Y1 + 13, 31, Cnf. ColorScheme [cdInput]);

  FastWrite (sm (smibSpeed), TagBox^. Y1 + 12, 39, Cnf. ColorScheme [cdText]);
  FastWrite (Long2Str (GetConnectSpeed) + ' bps', TagBox^. Y1 + 12, 58, Cnf. ColorScheme [cdInput]);

  FastWrite (sm (smEstTime), TagBox^. Y1 + 13, 39, Cnf. ColorScheme [cdText]);

  FastWrite (Long2Str (Round (EstimatedTransferTime
            (SizeOfAll, R. AvgCPS, GetConnectSpeed)/60)) + ' min.',
            TagBox^. Y1 + 13, 58, Cnf. ColorScheme
            [cdInput]);

  ScrollTextWindow (13, TagBox^. Y1 + 1, 68, TagBox^. Y1 + 11, Lo4 (Cnf. ColorScheme [cdFrame]),
                    Hi4 (Cnf. ColorScheme [cdFrame]), Lo4 (Cnf. ColorScheme
                    [cdScroller]), Hi4 (Cnf. ColorScheme [cdScroller]),
                    Hi4 (Cnf. ColorScheme [cdScroller]), Lo4 (Cnf. ColorScheme
                    [cdScroller]), ScrollList);

  CloseWindow (TagBox);

  Dispose (ScrollList, Done);
  GotoXY (oX, oY);
  NormalCursor;
  TextAttr := oAttr;
End;

Procedure UEdit;
Var
  TmpUser       : tUser;

Begin
  If NoInfo Then Exit;
  TmpUser := R;
  If EditUser (TmpUser) Then
  Begin
    R := TmpUser;
    SaveUser (R);
    UpdateUserMacro;
  End;
  SetEmulation;
End;

Procedure Help;
Var
  HelpBox        : PBoxRec;
  oX, oY, oAttr  : Byte;
  Help           : PNotSortedCollection;

Begin
  Help := New (PNotSortedCollection, Init (10, 1));

  If Not ReadCollection (MsgFileName, PBigCollection (Help), 'Help', NameVer, True) Then
  Begin
    Dispose (Help, Done);
    Exit;
  End;

  HiddenCursor;
  oX := WhereX;
  oY := WhereY;
  oAttr := TextAttr;

  InitWindow (HelpBox, 5, 5, 75, 19, 4, Cnf. ColorScheme [cdFrame],
              ' ' + sm (smHelpWinTitle) + ' ', Cnf. ColorScheme [cdTitle],
              ZoomSpeed, True);
  {CopyScr;}

  DrawWindow (HelpBox);

  {Restrict. X1 := HelpBox^. X1;
  Restrict. Y1 := HelpBox^. Y1;
  Restrict. X2 := HelpBox^. X2;
  Restrict. Y2 := HelpBox^. Y2;}

  ScrollTextWindow (6, HelpBox^. Y1 + 1, 75, HelpBox^. Y1 + 14, Lo4
                   (Cnf. ColorScheme [cdFrame]), Hi4 (Cnf. ColorScheme
                   [cdFrame]), Lo4 (Cnf. ColorScheme [cdScroller]), Hi4
                   (Cnf. ColorScheme [cdScroller]), Hi4 (Cnf. ColorScheme
                   [cdScroller]), Lo4 (Cnf. ColorScheme [cdScroller]),
                   Help);

  Dispose (Help, Done);
  CloseWindow (HelpBox);
  {FillChar (Restrict, 4, #0);}
  GotoXY (oX, oY);
  NormalCursor;
  TextAttr := oAttr;
End;

Procedure AccessLevel;
Var
  SecBox              : PBoxRec;
  oX, oY, iState      : Byte;
  TmpSec              : LongInt;
  Changed             : Boolean;

Label
  Loop, ExitProc;

Begin
  If NoInfo Then Exit;
  OX := WhereX;
  OY := WhereY;
  InitWindow (SecBox, 24, 9, 52, 11, 4, Cnf. ColorScheme [cdFrame],
              sm (smSecLevel), Cnf. ColorScheme [cdTitle],
              ZoomSpeed, True);

  DrawWindow (SecBox);
  TmpSec := R. Security;

  Loop:
  TmpSec := Str2Long (Input (37, SecBox^. Y1 + 1, Long2Str (TmpSec), ' ', '', 6, 0,
            [#32..#175], True, iState, Cnf. ColorScheme [cdInput], Changed));

  If iState = 27 Then Goto ExitProc;
  If iState In [72, 80, 73, 81] Then Goto Loop;

  If (TmpSec > 65535) Or (TmpSec < 1) Then
  Begin
    HiddenCursor;
    CenterTempBox (Cnf. ColorScheme [cdFrame], Cnf. ColorScheme [cdButton],
                   1, sm (smSecOutRange),
                   ZoomSpeed, sm (smWarningWinTitle));
    NormalCursor;
    GoTo Loop;
  End;

  R. Security := TmpSec;
  SetSecurity;

  ExitProc:
  CloseWindow (SecBox);
  GotoXY (OX, OY);
End;
{$ENDIF}

Procedure Lockout;
Begin
  If (R. Name <> '') And Not Registering Then
  Begin
    LogWrite ('!', sm (smLockOut));
    EmuDispFile ('~lockout');
    R. Security := 0;
    NormExit;
  End;
End;

Procedure fGluck;
Var
  i, j  : Integer;
  S     : Char;

Begin
  Randomize;
  j := Random (100);
  For i := 1 To j Do
  Begin
    S := Chr (Random (254));
    If (S = #1) or (S = #12) Then Continue;
    ComWrite (S, 0);
  End;
End;

{$IFNDEF WIN32}
Var
  DispBox            : PBoxRec;
{$ENDIF}

Procedure MessageToUser;
{$IFNDEF WIN32}
Var
  Changed            : Boolean;
  Msg2Disp           : String;
  iState, oX, oY     : Byte;

Label
  Loop, EoP;

Begin
  oX := WhereX;
  oY := WhereY;
  HiddenCursor;
  InitWindow (DispBox, 5, 9, 73, 11, 4, Cnf. ColorScheme [cdFrame],
              sm (smSendMsgText), Cnf. ColorScheme [cdTitle],
              ZoomSpeed, True);

  DrawWindow (DispBox);
  NormalCursor;

  Loop:
  Msg2Disp := Input (9, DispBox^. Y1 + 1, '', ' ', '', 61, 0, [#32..#255], True, iState,
              Cnf. ColorScheme [cdInput], Changed);

  If iState In [72, 80, 73, 81] Then Goto Loop Else
  If (iState = 27) Or (Trim (Msg2Disp) = '') Then
  Begin
    CloseWindow (DispBox);
    GoToXY (oX, oY);
    Exit;
  End;

  CloseWindow (DispBox);
  GoToXY (oX, oY);

  ComWriteLn (#13#10, 0);
  ComWriteLn (lang (laMsgFromSysOp), eoCodes+eoMacro);
  ComWriteLn (Msg2Disp, eoCodes+eoMacro);
  GoToXY(oX,oY);
{$ELSE}
Begin
{$ENDIF}
End;

Procedure InsDisp (S: PathStr);
Begin
  LogWrite ('+', sm (smlShowFile) + Trim (NiceFileName (S, 50)));
  EmuDispFile (S);
End;

Procedure InsertFile;
{$IFNDEF WIN32}
Var
  Changed            : Boolean;
  CurDir, CurDir1    : PathStr;
  iState, oX, oY     : Byte;

Const
  Path : PathStr = '';
  File2Disp : PathStr = '';

Label
  Loop, EoP;

Begin
  oX := WhereX;
  oY := WhereY;
  ComSaveScreen;
  HiddenCursor;
  InitWindow (DispBox, 5, 9, 73, 11, 4, Cnf. ColorScheme [cdFrame],
  sm (smFile2Disp), Cnf. ColorScheme [cdTitle], ZoomSpeed, True);

  DrawWindow (DispBox);
  NormalCursor;

  Loop:
  File2Disp := Trim (Input (9, DispBox^. Y1 + 1, File2Disp, ' ', '', 61, 0, [#32..#175],
  True, iState, Cnf. ColorScheme [cdInput], Changed));

  If iState In [72, 80, 73, 81] Then Goto Loop Else
  If iState = 27 Then
  Begin
    CloseWindow (DispBox);
    GoToXY (oX, oY);
    Exit;
  End;

  CloseWindow (DispBox);
  GoToXY (oX, oY);

  If File2Disp = '' Then
  Begin
    MarkedFiles := New (PNotSortedCollection, Init (10, 1));

    HiddenCursor;
    GetDir (0, CurDir);

    If Pane_Process (20, Round (tWin. ScrY/2)-6, pmMultiHalf, ivOnlyName,
       Path, 'DD-MM-YY', Cnf. Blinking, MarkedFiles) <> pnOk Then
    Begin
      GetDir (0, CurDir1);
      If CurDir <> CurDir1 Then SmartChDir (CurDir);
      NormalCursor;
      Dispose (MarkedFiles, Done);
      Exit;
    End;

    NormalCursor;
    SmartChDir (CurDir);
    If MarkedFiles^. Count = 0 Then
    Begin
      Dispose (MarkedFiles, Done);
      Exit;
    End;

    While MarkedFiles^. Count > 0 Do
    Begin
      InsDisp (GetStr (MarkedFiles^. At (0)));
      DisposeStr (MarkedFiles^. At (0));
      MarkedFiles^. AtDelete (0);
    End;

    Dispose (MarkedFiles, Done);
    SmartChDir (CurDir);
    Exit;
  End;

  InsDisp (File2Disp);
  ComRestoreScreen (InLightBarMenu);
{$ELSE}
Begin
{$ENDIF}
End;

Procedure PageSwitch;
{$IFNDEF WIN32}
Var
  OnOff         : Array [Boolean] Of String [5];
  PageStatus    : Boolean;
  Res           : Byte;
  S             : String [5];

Begin
  PageStatus := Not ChkFlag (PageFlag);
  OnOff [True] := sm (smPageOn);
  OnOff [False] := sm (smPageOff);
  S := OnOff [False];
  If Not PageStatus Then S := '~' + OnOff [False];
  HiddenCursor;

  Res := SelectBox (OnOff [True] + '|' + S, Cnf. ColorScheme
         [cdFrame], Cnf. ColorScheme [cdButton], Cnf. ColorScheme [cdTitle],
         ZoomSpeed, sm (smPageIs) + OnOff [PageStatus]);

  Case Res Of
    1 : EraseFlag (PageFlag);
    2 : MakeFlag (PageFlag);
  End;

  NormalCursor;
{$ELSE}
Begin
{$ENDIF}
End;
{
Procedure SwitchConsole;
Const
  Cons : Boolean = True;

Begin
  Cons := Not Cons;
  InAllow. ConOut := Cons;
  InAllow. ConIn := Cons;

  If Cons Then
  Begin
    NormalCursor;
  End Else
  Begin
    ClearWindow (0, 0, ScrX+1, ScrY+1, #0, 0);
    HiddenCursor;
  End;
End;
}

Procedure IncTime;
Begin
  If TimeCount Then
  Begin
    Inc (R. TotalTime, 60);
    If StatusBar and Not EnteringPass Then ShowTimeLeft;
  End;
End;

Procedure DecTime;
Begin
  If TimeCount Then
  Begin
    If R. TotalTime >= 60 Then Dec (R. TotalTime, 60) Else R. TotalTime := 0;
    If StatusBar and (Not EnteringPass) Then ShowTimeLeft;
  End;
End;

Procedure AnalyzeKey (C: Char);
Begin
  Case C Of
  {$IFNDEF WIN32}
    #50: MessageToUser;              { .Alt-M. }
    #25: PageSwitch;                 { .Alt-P. }
    #34: Gluck;                      { .Alt-G. }
    #20: ThreadStart (ViewTagList);  { .Alt-T. }
    #31: ThreadStart (AccessLevel);  { .Alt-S. }
    #38: LockOut;                    { .Alt-L. }
    #18: ThreadStart (UEdit);        { .Alt-E. }
    #23: InsertFile;                 { .Alt-I. }
    #35: Begin
           ExecScript ('onexit');
           NormExit;                 { .Alt-H. }
         End;
    #46: If Not InChat Then          { .Alt-C. }
         Begin
           ManualChat := True;
           Chat;
           ManualChat := False;
         End;

    #36: Begin                       { .Alt-J. }
           LogWrite (':', sm (smDOSShell));
           ComWrite ('|\10SysOp is going to DOS shell. Wait please...',eoCodes);
           DosShell ('', exCommand, False);
           ComWriteln (' \15Thanks!',eoCodes);
         End;

    #59: ThreadStart (Help);         { .F1. }
    #60: ThreadStart (UserParams);   {. F2 .}
    #61: DecTime;                    {. F3 .}
    #62: IncTime;                    {. F4 .}
    #63: DecKBLD;                    {. F5 .}
    #64: IncKBLD;                    {. F6 .}
    #68: SwitchStatusBar;            {. F10 .}
  {$ENDIF}

  {$IFDEF MSDOS}
    #32: DebugInfo;                  { .Alt-D. }
  {$ENDIF}

    #73: {$IFNDEF WIN32} ManualSend; {. PgUp .}
         {$ELSE} MainForm. SendFileButtonClick (nil);
         {$ENDIF}

  End;
End;

{$IFDEF WIN32}
Procedure ShowUsualBar;
Var
  S : String;

Begin
  S := Trim (R. Name);
  If R. Location <> '' Then S := S + sm (smStatusFrom) + R. Location;
  S := S + sm (smStatusAtBPS) + Long2Str (GetConnectSpeed) + sm (smBaud);
  MainForm. Label1. Caption := S;
  MainForm. Label2. Caption := '';
End;

Procedure ShowPasswordBar (S1, S2: String);
Begin
  MainForm. Label1. Caption := S1;
  MainForm. Label2. Caption := S2;
End;
{$ENDIF}

Procedure fComSaveScreen;
Begin
  With ScrSave Do
  Begin
    SaveWindow (1, 1, ScrX+1, ScrY+1, True, Pointer (P));
    SaveX := WhereX;
    SaveY := WhereY;
    Attribute := TextAttr;
    svStatusBar := StatusBar;
  End;

  GetMem (PScrSave, SizeOf (tScreenSave));
  PScrSave^ := ScrSave;
  Screens^. Insert (PScrSave);
End;

Procedure fComRestoreScreen (WaitForKey: Boolean);
Var
  PrevAttr : Char;
  X, Y     : Word;
  S        : String;

Begin
  If WaitForKey Then
  Begin
    PrevAttr := ComReadKey;
    KeyBufAdd (PrevAttr);
  End;

  S := '';
  Cls;
  ScrSave := PScreenSave (Screens^. At (Screens^. Count-1))^;

  With ScrSave Do
  Begin
    PrevAttr := P^ [2];

    For Y := 1 To ScrY Do
    Begin
    {$IFNDEF WIN32}
      If svStatusBar and (WhereY >= ScrY) Then Break;
    {$ENDIF}

      For X := 1 To ScrX Do
      Begin
        If ((Y = 1) and Cnf. Clock and (X > ScrX-8))
      {$IFNDEF WIN32}
        Or (svStatusBar and (Y >= ScrY))
      {$ENDIF}
        Then Break;

        If PrevAttr = P^ [((Y-1)*(ScrX+1)+X)*2] Then
          S := S + P^ [((Y-1)*(ScrX+1)+X-1)*2+1] Else
        Begin
          ComWrite (EmuColor (Byte (PrevAttr)) + S, 0);
          PrevAttr := P^ [((Y-1)*(ScrX+1)+X)*2];
          S := P^ [((Y-1)*(ScrX+1)+X-1)*2+1];
        End;
      End;

      If {$IFNDEF WIN32} Not (svStatusBar And (WhereY < ScrY-1)) Or {$ENDIF} (R. Emu = teTTY) Then S := TrimTrail (S);
      If Trim (S) <> '' Then ComWrite (EmuColor (Byte (PrevAttr)) + S, 0) Else ComWrite (Trim (S), 0);

      If (R. Emu = teTTY) And (WhereY >= SaveY) Then
      Begin
        ComWrite (Replicate (' ', SaveX-WhereX), 0);
        Break;
      End;

      If
    {$IFNDEF WIN32}
      ((svStatusBar And (WhereY < ScrY-1)) Or Not svStatusBar) And
    {$ENDIF}
      Not ((R. Emu = teTTY) And (WhereY >= SaveY)) Then ComWriteLn ('', 0);

      S := '';
      PrevAttr := #0;
      If
    {$IFNDEF WIN32}
      (svStatusBar And (WhereY >= ScrY-1) And (WhereX > 1)) Or
    {$ENDIF}
      ((R. Emu = teTTY) And (WhereY >= SaveY) And (WhereX >= SaveX)) Then Break;
    End;

    ComWrite (EmuGoToXY (SaveX, SaveY), 0);
    ComWrite (EmuColor (Attribute), 0);
  End;

  FreeMem (ScrSave. P, (Succ (ScrX)*Succ (ScrY)) shl 1);
  FreeMem (Screens^. At (Screens^. Count-1), SizeOf (tScreenSave));
  Screens^. AtDelete (Screens^. Count-1);
End;

Procedure fSuspendTime;
Begin
  If Not TimeSusp Then
  Begin
    TimeSusp := True {Not TimeSusp};
    TimeCount := False;
    TimeLeft := R. TotalTime - MidSec + EnterTime;
  End;
End;

Procedure fUnSuspendTime;
Begin
  If TimeSusp Then
  Begin
    TimeSusp := False {Not TimeSusp};

    If Not Registering Then
    Begin
      R. TotalTime := TimeLeft + MidSec - EnterTime;
      UsedMinus := UsedMinus + (MidSec - ChatStartTime);
      TimeCount := True;
    End Else
      EnterTime := MidSec;
  End;
End;

Procedure InitTMainOvr;
Begin
  NormExit := fNormExit;
  UserInfo := fUserInfo;
  ComSaveScreen := fComSaveScreen;
  ComRestoreScreen := fComRestoreScreen;
  News := fNews;
  Gluck := fGluck;
  SuspendTime := fSuspendTime;
  UnSuspendTime := fUnSuspendTime;
  GoTelnet := fGoTelnet;
End;

Procedure DecKBLD;
Begin
  If R. DailySize > 50 Then Dec (R. DailySize, 50);
End;

Procedure IncKBLD;
Begin
  Inc (R. DailySize, 50);
End;

End.
