
   skMHL

    ⥪  㯠  MSG, Squish, Jam
    Borland Pascal-ᮢ⨬ p

                                                         WARNING!
           䠩 ⠬ ᮤp 楫 p⨢ ᨪ!
                 p㭠, ᪨ ⠡   ⥭
                              ⮣ 䠩 p p⨢!

   NB! p⠩   p p⥭ ᥣ ⠫쭮
       plz!

 . INTRO.
~~~~~ ~~~~~~~ ~~~~~~
0.0.    ⠪?
~~~~ ~~~ ~~~ ~~~~~~ ~~~~~~
   , skMHL 砫쭮 뢠  ꥪ⭮-pp,
   p⠡쭠 ⥪    㭨pᠫ쭮 㯠
    䨤 .

   뫨 p p p: MSG, Squish  Jam, p ᠬ p
   p. ⠫ Hudson  ᮢᥬ ᯮ㥬 p - 
    襥 p  p ( 䨣?).

0.1.   ᮡp?
~~~~ ~~~ ~~~ ~~~~~~~~~~~
   ,  ᮡp ᥬ ᪠ p 稨 p
   p,   p 㯮p⢠.

   skMHL pp ᮡp  p⠥ ( ) ᫥騬
   p   ᫥騥 p:
     Borland Pascal 7.0: real mode, protected mode (᪠  dll)
     Virtual Pascal 2.0: Win32 target, OS/2 target (᪠  dll)
     Delphi 5.0: Win32 target (᪠, dll  p)

    pᮬ 䠪 ᡮp  p:
     Borland Pascal 7.0: Win16 target, OS/2 target
     Virtual Pascal 2.0: DOS target, Linux target
     Free Pascal Compiler

0.2.  㦭   p  skMHL?
~~~~ ~~~ ~~~~~ ~~~~~ ~~~ ~~~~~~ ~ ~~~~~~
   뫮  ᭮, ᫨   㬥 ᮧ p ꥪ⮢,
   ,  ⠪ p, PChar',    쭮
   p⠢  ⠭p FTN.

   , ᢮  ⥪ -  p,   p,
   , p㪨   室 ⥪: ⠥  . ᫨ ,
   筮.   p p  짮.  .. ;)

0.3.   far calls etc..?
~~~~ ~~~ ~~~~~~ ~~~ ~~~~~ ~~~~~~
    ᠥ 権 p:   $F+  $X+ ﭭ.
   p⭮,  -   . H    㦭.
    stack/range/io/overflow 祪 ⥫쭮 ⪫
   ( 类 砥 p 樥 p ᢮ ⨭, 
    祭 p p묨 call @_StkChk  p. :)



 . skMHL.
~~~~~ ~~~~~~~ ~~~~~~
1.0.   skMHL?
~~~~ ~~~~~~ ~~~~~~~~~ ~~~~~~

    skMHL   :  (   ᮮ饭)
    ᠬ ᮮ饭.

    p ꥪ  p   pᬠp p
     ᮮ饭    p.

   TMessageBase   ᯮ .   p⥭, 
   p ⥬⨧p   ,  ᠬ 䠪᪨ 
   祣 .   p묨  ⢫
   TFidoMessageBase, TJamMessageBase, TSquishMessageBase  
   skMHLmsg, skMHLjam, skMHLsq ᮮ⢥⢥.

    襯p᫥ ꥪ ᫥  TMessageBase.

   ⠪, , .. ꥪ .

    :

    PMessageBase = ^TMessageBase;
    TMessageBase = object
     constructor Init;
     destructor Done; virtual;

     function Open(const Path: String): Boolean; virtual;
     function Create(const Path: String): Boolean; virtual;
     function Exist(const Path: String): Boolean; virtual;
     procedure Close; virtual;
     function Exists(Message: Longint): Boolean; virtual;
     function Current: Longint; virtual;
     procedure Seek(Message: Longint); virtual;
     procedure SeekNext; virtual;
     procedure SeekPrev; virtual;
     function SeekFound: Boolean; virtual;
     function GetLocation: Longint; virtual;
     procedure SetLocation(Location: Longint); virtual;
     function OpenMessage: Boolean; virtual;
     function OpenMessageHeader: Boolean; virtual;
     function CloseMessage: Boolean; virtual;
     function GetHighest: Longint; virtual;
     function GetCount: Longint; virtual;
     function GetFrom: String; virtual;
     function GetTo: String; virtual;
     function GetSubject: String; virtual;
     procedure GetFromAddress(var Address: TAddress); virtual;
     procedure GetToAddress(var Address: TAddress); virtual;
     procedure GetFromAndToAddress(var FromAddress, ToAddress: TAddress); virtual;
     procedure SetFrom(const S: String); virtual;
     procedure SetTo(const S: String); virtual;
     procedure SetSubject(const S: String); virtual;
     procedure SetFromAddress(var Address: TAddress; const FreshMSGID: Boolean); virtual;
     procedure SetToAddress(var Address: TAddress); virtual;
     procedure SetFromAndToAddress(var FromAddress, ToAddress: TAddress; const FreshMSGID: Boolean); virtual;
     procedure GetStringPChar(Line: PChar; MaxLen: Integer); virtual;
     procedure GetString(var Line: String); virtual;
     procedure PutStringPChar(Line: PChar); virtual;
     procedure PutString(const Line: String); virtual;
     function EndOfMessage: Boolean; virtual;
     procedure SetTextPos(Position: Longint); virtual;
     function GetTextPos: Longint; virtual;
     function GetTextSize: Longint; virtual;
     procedure TruncateText; virtual;
     procedure ReadText(var Buf; Count: Word); virtual;
     procedure WriteText(var Buf; Count: Word); virtual;
     function GetAttribute(Attribute: Longint): Boolean; virtual;
     procedure SetAttribute(Attribute: Longint; Enable: Boolean); virtual;
     procedure GetWrittenDateTime(var DateTime: TMessageBaseDateTime); virtual;
     procedure GetArrivedDateTime(var DateTime: TMessageBaseDateTime); virtual;
     procedure SetWrittenDateTime(var DateTime: TMessageBaseDateTime); virtual;
     procedure SetArrivedDateTime(var DateTime: TMessageBaseDateTime); virtual;
     function WriteMessage: Boolean; virtual;
     function WriteMessageHeader: Boolean; virtual;
     function GetKludgePChar(const Name, Destination: PChar; const MaxLen: Integer): Boolean; virtual;
     function GetKludge(const Name: String; var Destination: String): Boolean; virtual;
     procedure SetKludgePChar(const Name, Value: PChar); virtual;
     procedure SetKludge(const Name, Value: String); virtual;
     procedure DeleteKludgePChar(const Name: PChar); virtual;
     procedure DeleteKludge(const Name: String); virtual;
     procedure AddKludgePChar(const Value: PChar); virtual;
     procedure AddKludge(const Value: String); virtual;
     function GetMessageTextStream: PMessageBaseStream; virtual;
     procedure SetFlag(const Flag: Longint; const Enable: Boolean); virtual;
     function GetFlag(const Flag: Longint): Boolean; virtual;
     procedure CheckFromAddress(const S: String; var Address: TAddress); virtual;
     procedure CheckToAddress(const S: String; var Address: TAddress); virtual;
     function CreateNewMessage: Boolean; virtual;
     function KillMessage: Boolean; virtual;
     function GetLastRead(const UserNumber: Longint): Longint; virtual;
     procedure SetLastRead(const UserNumber: Longint; const Value: Longint); virtual;
     procedure ResetDateTime;
     procedure SetBaseType(const BaseType: TBaseType); virtual;
     procedure PutOrigin(Address: TAddress; const Text: String); virtual;
     function AfterLastKludge: Longint; virtual;
     procedure SetMessageTextStream(const AMessageText: PMessageBaseStream); virtual;
     procedure SetStatus(const AStatus: Longint); virtual;
     function GetStatus: Longint; virtual;
     procedure SetOpened(const AOpened: Boolean); virtual;
     function GetOpened: Boolean; virtual;
     procedure SetCurrent(const ACurrentMessage: Longint); virtual;
     procedure SetBasePath(const ABasePath: String); virtual;
     function GetBasePath: String; virtual;
     function GetRead: Boolean; virtual;
     procedure SetRead(const Value: Boolean); virtual;
    end;

    ? 㤥   ⮤ 宭..

1.1. TMessageBase: pp/pp
~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~

   constructor Init;
   destructor Done;

       ꥪ, 饣 p㠫묨 ⮤
   ( TMessageBase  )   pp, p
   vmt p :). pp  TMB (TMessageBase) .
    ⠢ p p  ,
    魮, 祣  .

   pp    ᮫⭮ 祣.

   讥 㯫:
      p  TMessageBase   ⮬ 룫廊
     ᫥騬 p ( ᫮  p, ⮬
       ᮪ , ⮡  ⭥ 뫮):

     var
      B: PFidoMessageBase;
     begin
      B:=New(PMessageBase, Init);

      B^.Open('F:\Fido\Netmail');

      ...

      B^.Close;

      Dispose(B, Done);
     end

      p樯,   娬 ⮭ ᯮ짮 pp
      ⮤ ⨯ Open (p  p뢠) p,
      p⨩/p⨩__ᮧ/p⨩  
     ᯥ樠  skOpen  ᮮ⢥騥 ⮤  .

1.2. TMessageBase: p⨥/ᮧ/pp ⢮/p⨥ 
~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ ~~~~

   NB!   뫮 ⠭ ( Path  skMHL 뢠 p ;), ,
         Path -    . HH. 
       直 p⮢.  ᪢/ - :\\  pp,
         -   襬   (   ).

   function Open(const Path: String): Boolean;
   function Create(const Path: String): Boolean;
   function Exist(const Path: String): Boolean;
   procedure Close;

   Open, ᮮ⢥⢥, p뢠 . ᫨   p -
   p頥 False  ⢥ p  p稭, p 
   㧭, ᯮ짮 ⮤ GetStatus.

   Create ᮧ . ᫨   - ᮧ .
    砥 訡  ᥡ ⠪,   Open.

   Exist p pp ⢮ ,  p뢠   
   pp pp⭮ p /.  ⢮
   p頥  p (True/False).

   Close p뢠 .   믮 ᥣ p 㭨⮦
   ꥪ!  ⮬,     砥 믮,  
    - p , grunged headers, 騥 p
    ;)

1.3. TMessageBase:  ᮮ饭
~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~
    p㯯 ⮤ ⢫,  ᭮,  ᮮ饭.
       ,   㬠 p p,  
   ᮮ饭  㪠 p, p饭  ᫥饬
   ᮮ饭  . H , 筮, p樮 ⮤.

   function Exists(Message: Longint): Boolean; virtual;

   , pp, Exists. H 祬  p樮 ⮤?
     p樮 =) p頥 True, ᫨ ᮮ饭
    㪠 p   .
   (, ᬮp    㬥p権 ᮮ饭  )

   function Current: Longint; virtual;

   p頥 p "⥪饣 ᮮ饭". 騬 ᮮ饭
    ᮮ饭,  p 㤥 p  㦥  p
   (p⨥//).

   function GetHighest: Longint; virtual;

   p頥 _ᨬ_ p ᮮ饭   (_H_ ᮢ
    GetCount,  H ).

   function GetCount: Longint; virtual;

   p頥 饥 ⢮ ᮮ饭    ⥪騩 .

   procedure Seek(Message: Longint); virtual;

   ⠭ ⥪騬 ᮮ饭  㪠 p. ᫨
   ᮮ饭  㪠 p  ,  
   ᮮ饭  p  訬,  ⥪騬 ⠭
   . ⮡  訡, p Current  p Seek'
   Message.    ..    㡨 ᮮ饭 
    p,  ᮮ饭- 㤠 㪠, pp,
    ⮡  㡨 ᫥饥  .. ;)

   procedure SeekNext; virtual;
   procedure SeekPrev; virtual;

    ⥪騬 ᮮ⢥⢥ ᫥饥  p饥 ᮮ饭.

   function SeekFound: Boolean; virtual;

   p頥 True, ᫨ ⥪饥 ᮮ饭    pp.
   H稭 p False p p室  p  (pp,
   SeekPrev,  ⥪騬  p ᮮ饭  SeekNext
    ᫥)    . ᯮ pp ⠪:

   ...

   Base^.Seek(1); { seek'  ᠬ ᮮ饭  p  }
                  { ᫨ ⠪  , seek p ᫥饥 }

   while Base^.SeekFound do
    begin
     ...

     Base^.SeekNext;
    end;

   NB! ᫥ 맮 KillMessage 易⥫쭮 㦭  seek  -
        ᮮ饭.

       pp:

       Base^.Seek(1);

       while Base^.SeekFound do
        begin
         ...

         if NeedToBeKilled then
          Base^.KillMessage;

         ...

         Base^.SeekNext;
        end;

   function GetLocation: Longint; virtual;
   procedure SetLocation(Location: Longint); virtual;

   GetLocation  SetLocation ᯮ  p  pp,
   p 室  p - ᮮ饭 
   ⮬ ⠭ 㪠⥫  .

   祭, p頥 GetLocation  p SetLocation
    ⫨  ᮫⭮ p ᮮ饭!

   ᫥ 맮 SetLocation  뫮  pp, ⠭
      ᮮ饭. ?   筮: SeekFound ;)


   ! p  -  ᠬ ᫠. p/p
    p祣 p ⥫쭮 p⢥ ᮮ饭.

   NB! Open/CreateNew/KillMessage  뢠 ⮫쪮 ⮣, 
        p㣮 ᮮ饭     p, 
        㯠,   #  ..

   function OpenMessage: Boolean; virtual;

   OpenMessage ⠥ p ⥪饥 ᮮ饭. ᫨   
   砥,   p頥 True. ᫨  砥 - False
     訡  GetStatus. ᫨ ᮮ饭 뫮 p ᯥ譮,
     ⮬ H  p (CloseMessage),  leaks.. ;)

   function CreateNewMessage: Boolean; virtual;

   CreateNewMessage ᮧ   ᮮ饭.

   HINT:   㦭  SetWrittenDateTime ᫥ CreateNewMessage,
         ⮡ ⠭ ⥪ /p,    ᤥ
         ⮤ ResetDateTime, p .CreateNewMessage 뢠
         ⮬᪨.

   btw, p ⥬,  뢠  ⮤  p 㬠:
   筮  㦭 ᮧ ᮮ饭?
    ᫥ 맮   . H맮 WriteMessage  CloseMessage
     p  leak'e - p,   ᯮp祭  - .

   function WriteMessage: Boolean; virtual;

   WriteMessage  p p⮥  ᮧ ᮮ饭  .
   p True, ᫨   㤠.

   function CloseMessage: Boolean; virtual;

   CloseMessage p ᮮ饭, 祣  p. p ⤠
   ⥬ , p 뫠 ( )   .

   NB! CloseMessage 㦭 H 뢠 p Close.

   function KillMessage: Boolean; virtual;

   KillMessage 直 p - 㡨 ⥪饥 ᮮ饭. H pp⭮
    , ⮫쪮 ᫨ ⥪饥 ᮮ饭 p.

   NB! Seek[Next|Prev]  ᫥ KillMessage   㦭!  
       .. ;)

       btw  TJamMessageBase Current ᫥ 맮 KillMessage 㤥
       ᪠ (㤥 Current-1) -  室  pp⭮
       p SeekNext ᫥ KillMessage.

   function OpenMessageHeader: Boolean; virtual;
   function WriteMessageHeader: Boolean; virtual;

     㭪樨  p㬠,  ᠫ p . p
   p   p pp 娤p  -  
   . 쪮 .  ᮮ饭  p稥 p䠪 
   뫨  㦭 (  ᥩ  㦭..?).

   p⭥  ⨬ ⮤.   ᯮ짮 
   OpenMessage/WriteMessage.

   NB! ᯮ짮 OpenMessage  WriteMessageHeader 
       OpenMessageHeader  WriteMessage  p  祭 砫
       ᫥⢨!

   pp:

   if Base^.Exists(666) then WriteLn('Devil was here!');

   Base^.Seek(1);

   while Base^.SeekFound do
    begin
     if Base^.OpenMessage then
      begin
       GonnaKill:=(Base^.GetFrom = 'another damned user') or
                  (Base^.GetFrom = 'Moderator');

       ...

       Base^.CloseMessage;

       if GonnaKill then
        Base^.KillMessage;
      end;

     Base^.SeekNext;
    end;

1.3. TMessageBase:  ᮮ饭
~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~ ~~~~~~~~~

    ⮤  뢠 ⮫쪮 ᫥ p/ᮧ ᮮ饭.
   맮   p㣮 p  p  ⪮ GPF'.

   function GetFrom: String; virtual;
   function GetTo: String; virtual;
   function GetSubject: String; virtual;

   p ᮮ⢥⢥ From ( ᥭp), To ( pᨢp) 
   Subject (⥬ ᮮ饭).

   procedure SetFrom(const S: String); virtual;
   procedure SetTo(const S: String); virtual;
   procedure SetSubject(const S: String); virtual;

   ⠭ ᮮ⢥⢥  ᥭp/pᨢp  ᠡ.

   procedure GetFromAddress(var Address: TAddress); virtual;
   procedure GetToAddress(var Address: TAddress); virtual;
   procedure GetFromAndToAddress(var FromAddress, ToAddress: TAddress); virtual;

   HINT: " ⠪ TAddress     p" -  ⮬  ,
         - p 易  skCommon.

   Get?Address ⮫쪮   ,  p p ⮣   ?.
    ⢥ ?  䨣pp ᫥騥 p: From, To 
   FromAndTo.

   祬 ᫥?  ⥬,  祭 p pᮢ ᫥
   ⢫  横,    (᫨ ᯮ짮  ⤥쭮
   getfromaddress/gettoaddress). Speeeeeed... ;)

   procedure SetFromAddress(var Address: TAddress; const FreshMSGID: Boolean); virtual;
   procedure SetToAddress(var Address: TAddress); virtual;
   procedure SetFromAndToAddress(var FromAddress, ToAddress: TAddress; const FreshMSGID: Boolean); virtual;

   Set?Address -  ,   Get?Address, ⮫쪮 ⠭,  
   p p.

    頥 pp FreshMSGID? : ᫨  True, 
   SetFrom(AndTo)Address   㤦 @MSGID  ⮫쪮 p
   ᥭp,   magic-number, p, ᮡ⢥,  뢠 MSGID:
   MessageIdentifier.

   NB! Get/Set*Address p ⥪   ⥪!
        ᤥ ⠪, ⮡   ᠫ p ⥪  p
       㤦, ⠩  ᫥饩 .

1.4. TMessageBase:  ᮮ饭
~~~~ ~~~~~~~~~~~~~ ~~~~~ ~~~~~~~~~

     ⥪⮬,   p   ⠪ 
   p ⮫쪮 ⮣,  ᮮ饭 p (ᮧ).

    p  ⥪⮬ ᮮ饭  skMHL 宦   p
    ⥪⮢ 䠩  ᪢: p筮 ⥭/,
   p  reset'/rewrite'/append'  -     ⥫ ;)

   ⠪..

   procedure SetTextPos(Position: Longint); virtual;

   SetTextPos ⠭ ⥪   ⥪.

    p  ,   堫:   ,  p .
    TStream^.Seek,  㦥 ⭮? ;)

   p⥫ 祭 SetTextPos' p ᫥,
   筮. ⥫ -  GetTextSize.   
   p  . Hpp,  ⮣, ⮡ ⮬ ᤥ
   TruncateText  ⥬ ᠬ p ⮢ p  p
    pp ᠣ. ? ;)

   function GetTextPos: Longint; virtual;

   p頥 ⥪ .

   function GetTextSize: Longint; virtual;

   p頥 騩 pp ⥪.

   function EndOfMessage: Boolean; virtual;

   p頥 True, ᫨ ⨣  ⥪:

   Hpp:
             Base^.SetTextPos(0);

             while not Base^.EndOfMessage do
              begin
               Base^.GetString(S);

               WriteLn(S);
              end;

   procedure GetStringPChar(Line: PChar; MaxLen: Integer); virtual;
   procedure GetString(var Line: String); virtual;

    ᫠ p窠 ,  p樯,   ⮦: ⠥
   p  ⥪. p祬 p p楤p ⠥  PChar, p - 
   p.  砥  PChar'    p 騩 pp,
   뤥  PChar,   襬 - 㤠-  㯠
    GPF'. Hp 㤥.

    p, p  MaxLen  砥  PChar' 
   255 ᨬ  砥  p p. 騩 GetString*
   p頥 H  ,  _᫥_ p.

   procedure PutStringPChar(Line: PChar); virtual;
   procedure PutString(const Line: String); virtual;

    ᫠ p窠 ᮮ⢥⢥  PChar  String 
   ⥪.   ⥪ , 㢥稢  ᫥  
    ᠭ   #13 (p p  FTN).

   procedure TruncateText; virtual;

   p ⥪  ⥪ .

   procedure ReadText(var Buf; Count: Word); virtual;
   procedure WriteText(var Buf; Count: Word); virtual;

    ᮡ p饭楢 pᬮp  BlockRead/Write.

   procedure PutOrigin(Address: TAddress; const Text: String); virtual;

    p쭠 窠.   _⥪_  (   
   ⥪) p  㪠 pᮬ  ⥪⮬. p祬 ⥪
   p, ᫨ p蠥 p pp.  饬, 
   pp -  ᢥ ;)

   HINT: " p쭮 ⠭  㤦   p쭮  ⥪
           ᢥp祭 ᮮ饭?"

          筮  ᭠砫 㤦,  ⮬ ⥪.

         㤦 , ⢥,  p窠,    p
         ⠬ SetKludge  Set*Address.

         ⮬  SetTextPos(GetTextSize),   PID:
         PutString(#1'PID: another suxx v1.0');

          p   ⥪ ᮮ饭.

         ⮬ - ᮣ᭮ ⨪ -  p.

           ⢥ ᯥ権  ⠣.

         p - ᥣ:
         PutString('--- another suxx v1.0');

           p:
         PutOrigin(StrToAddressR('2:6033/27.0')^, 'tm team * salvator * under the bridge');

           . WriteMessage  CloseMessage. ᥠ 祭.

   Q: "Set*Address  ⥪ ,   ⥪  !
        ?!!!"

        砫 p, 믨 ,  ᫥ ᤥ
       SetTextPos(GetTextSize);   ⥪  ⮩ ᮢ.

   pp:

   uses
        skMHL,
        skOpen,
        skCommon;

   var
    Base: PMessageBase;
    Sender, Receiver: TAddress;
   begin
    if not OpenOrCreateMessageBase(Base, 'FF:\Fido\Netmail') then
     begin
      WriteLn('Failed to open netmail: ', ExplainStatus(OpenStatus));

      Halt(255);
     end;

    Base^.SetBaseType(btNetmail);

    if Base^.CreateNewMessage then
     begin
      StrToAddress('2:6033/27.0', Sender);
      StrToAddress('2:6033/28.0', Receiver);

      Base^.SetFromAndToAddress(Sender, Receiver, True);

      Base^.SetFrom('sergey korowkin');
      Base^.SetTo('tatyana medvedeva');

      Base^.SetSubject('J.I.L.Y. my dear ;-)');

      Base^.SetTextPos(Base^.GetTextSize);

      Base^.PutString(#1'PID: tanyushka''s letter generator');

      Base^.PutString('');
      Base^.PutString('ᥣ     ⥡.');
      Base^.PutString('ok?');
      Base^.PutString('');

      Base^.PutString('--- tiny sk');

      Base^.PutOrigin(Sender, 'avariya * salvator * summer is crazy');

      Base^.SetAttribute(maSent, False);
      Base^.SetAttribute(maLocal, True);
      Base^.SetAttribute(maPrivate, True);

      if not Base^.WriteMessage then
       WriteLn('Failed to write message: ', ExplainStatus(Base^.GetStatus));

      Base^.CloseMessage;
     end
    else
     WriteLn('Failed to create new message: ', ExplainStatus(Base^.GetStatus));

    CloseMessageBase(Base);
   end.

1.4. TMessageBase: p/ ᮮ饭
~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~~ ~~~~~~~~~

   H  㦥 﫨,  p   祭/ᠭ
   ⮦   ᪫⥫쭮 ⮣,  ᮮ饭 p..?

   function GetAttribute(Attribute: Longint): Boolean; virtual;
   procedure SetAttribute(Attribute: Longint; Enable: Boolean); virtual;

   p 뢠 p, ,  ᭮, ⠪:

    maPrivate,    maCrash,
    maReceived,   maSent,
    maAttach,     maTransit,
    maOrphan,     maKill,
    maLocal,      maHold,
    maFRq,        maRRq,
    maRRc,        maARq,
    maURq,        maScanned

   祭 ᨫ쭮    祭.  ⮫쪮,
    GetAttribute/SetAttribute   祭 ma* 
    p ( ᫥ p SetAttribute(maPrivate or
   maLocal or maSent, True)  p p ).

   ᭮ p樨  p⠬  ᮧ ᮮ饭:

   ᫨  netmail:
     SetAttribute(maLocal, True);
     SetAttribute(maSent, False);
     SetAttribute(maPrivate, True); {    }

   ᫨  echomail:
     SetAttribute(maLocal, True);

   procedure GetWrittenDateTime(var DateTime: TMessageBaseDateTime); virtual;
   procedure SetWrittenDateTime(var DateTime: TMessageBaseDateTime); virtual;

   砥/⠭  ᠭ 쬠.

   HINT: p p楤p  p  TMessageBaseDateTime 
          㫥 skCommon, p ᠭ .

   procedure GetArrivedDateTime(var DateTime: TMessageBaseDateTime); virtual;
   procedure SetArrivedDateTime(var DateTime: TMessageBaseDateTime); virtual;

     䨣,   Get/SetWrittenDateTime, ⮫쪮
   p頥/⠭ /p 祭 쬠.

   procedure ResetDateTime;

   ⠭ /p ᠭ  祭  ⥪饥 p.

1.5. TMessageBase:   㤦
~~~~ ~~~~~~~~~~~~~ ~~~~~~ ~ ~~~~~~~~

     ᫠ p  ⮬,   ⮤  뢠
   ⮫쪮  ᮮ饭 p (ᮧ).

   function GetKludgePChar(const Name, Destination: PChar; const MaxLen: Integer): Boolean; virtual;
   function GetKludge(const Name: String; var Destination: String): Boolean; virtual;

   ᫨ GetKludge*   ⥪ ᮮ饭 p, 稭 
   Name (pp, #1'MSGID:'), , -p p True  p
      p (pp, #1'MSGID: 2:6033/27 f1d39a3a')
    Destination.    PChar' 室 㪠 MaxLen,
     뢠 GPF 譨 p. ᫨ GetKludge* 祣  ,
    p False    殬 ;)

   Hpp:

      var
        P: PChar;

      GetMem(P, 2048);

      if Base^.GetKludgePChar(#1'MSGID:', P, 2048) then
       WriteLn(P)
      else
       WriteLn('no msgid in this message!');

      FreeMem(P, 2048);

   procedure SetKludgePChar(const Name, Value: PChar); virtual;
   procedure SetKludge(const Name, Value: String); virtual;

   SetKludge* ⠭ 㤦 Name  祭 Value. p祬
   ᫨ 㤦 Name 㦥 ,   p 㤥  
   祭 Value.

   Hpp:
      SetKludge(#1'PID', #1'PID: PornoTosser v6.66.HELL');
      SetKludge(#1'PID', #1'TID: JT');

      ( ⮣ PID, ᫨    ᮮ饭, p  p
          殢 pp  #1'TID: JT' :)

   procedure DeleteKludgePChar(const Name: PChar); virtual;
   procedure DeleteKludge(const Name: String); virtual;

    p, 稭  Name (btw,   易⥫쭮 㤦 ;):

   DeleteKludge(#1'MSGID');

   procedure AddKludgePChar(const Value: PChar); virtual;
   procedure AddKludge(const Value: String); virtual;

   __ 㤦 ᫥  㤦  砫 ᮮ饭.  
     㭪樥 AfterLastKludge. ᫥㤦
   ⥪, ᫨  ,  p,   p  .

   NB!  襯p᫥  ⮬ p p楤p/㭪樨 H
       ⥪  (GetTextPos p).     
        㤠  ;)

   function AfterLastKludge: Longint; virtual;

    㦥 뫮 ᪠ ,   ᫥ p  ᫥
   㤦  #13  砫 ᮮ饭 (p ⥪⮬).

1.6. TMessageBase: 䫠 
~~~~ ~~~~~~~~~~~~~ ~~~~~ ~~~~

     ⠭  㣮,  p ᯥ
   䫠 室 ⠭ p p⨥/ᮧ ᮮ饭.

   ,  ,  䫠 ?  p樯, ﬨ: 
   TView.Options - p p   .

   procedure SetFlag(const Flag: Longint; const Enable: Boolean); virtual;
   function GetFlag(const Flag: Longint): Boolean; virtual;

     p楤p ⠭   祭 ᮮ⢥
   䫠.

      ᥣ p,   p - ᪫騥 (..
     ⠭ -   ):

     afNetmail
     afEchomail
     afLocal

    p 䫠 ⠭ ⨯ : netmail, echomail  local
   ᮮ⢥⢥. 筮   p筮,   p p 㭪権
       䫠.   pp⭮ p  
   䫠 易⥫쭮  ⠭..     
   p祭 ᠣ ;)

   procedure SetBaseType(const BaseType: TBaseType); virtual;

   p-p ⠭ ⨯  (⮡ p窠 Get/SetFlag
     -  ).  室 ,  㬠   ⭮:

     SetFlag(afNetmail, BaseType = btNetmail);
     SetFlag(afEchomail, BaseType = btEchomail);
     SetFlag(afLocal, BaseType = btLocal);

   SetBaseType' p btNetmail, btEchomail  btLocal.

1.7. TMessageBase: ⮪ (stream) ⥪ ᮮ饭
~~~~ ~~~~~~~~~~~~~ ~~~~~ ~~~~~~~~ ~~~~~~ ~~~~~~~~~

   function GetMessageTextStream: PMessageBaseStream; virtual;

    뢠 㦭   ⥪ ᠣ -
   让 䠩,  ⮣ p  ,  p 
   ⮪, p "p" ⥪ ᮮ饭: GetMessageTextStream
   p頥  㪠⥫  p ꥪ ⮪
   (⮤ TMessageBaseStream  ⮤ objects'᪮ TStream).

   procedure SetMessageTextStream(const AMessageText: PMessageBaseStream); virtual;

     p楤p  ⥪騩 ⮪   (p p ⮬
   destroy', ..  ⮨  Dispose(GetMessageTextStream, Done) ;).

   ᫥ p楤p  p쭮 ᯮ짮,   - ᥣ
   640 (realmode),    10mb ⥪, pp:
   ⮣ ᮧ 䠩p (⮫쪮  ᪨,  skCommon'᪨,
   CreateMessageBaseFileStream), 
   Base^.SetMessageTextStream(_䠩_p)  Base^.WriteMessage.

   ⮢,  ;)

1.8. TMessageBase: 䨣
~~~~ ~~~~~~~~~~~~~ ~~~~~

   饭  易⥫쭮   p.

   procedure CheckFromAddress(const S: String; var Address: TAddress); virtual;
   procedure CheckToAddress(const S: String; var Address: TAddress); virtual;

   Check*Address ᯮ p  Get*Address:  p
   p,  Check*Address   㤦 (᫨ p p -
     㦭 㤦)  ᮤp Address.

1.9. TMessageBase: p  - 
~~~~ ~~~~~~~~~~~~~ ~~~~~~~~ ~ ~~~~~~~ ~~~

   饭   p/ᮧ.

   function GetLastRead(const UserNumber: Longint): Longint; virtual;
   procedure SetLastRead(const UserNumber: Longint; const Value: Longint); virtual;

   砥/⠭ p  ᮮ⢥饣 p.

    ,  ᫨ SQ  MSG p p浪 p p
   (0 - p, 1 - p  ⠪ ),  JAM'  ⢥ UserNumber
   p CRC32   짮⥫:

              lr:=GetLastRead(StringCRC32('sergey korowkin', -1));

   function GetRead: Boolean; virtual;
   procedure SetRead(const Value: Boolean); virtual;

   GetRead p頥 True ᫨ ᮮ饭 p⠭. SetRead ⠭,
   p⠭  ᮮ饭.

1.10. TMessageBase: internal stuff
~~~~~ ~~~~~~~~~~~~~ ~~~~~~~~ ~~~~~

   procedure SetCurrent(const ACurrentMessage: Longint); virtual;

   ⠭ 祭 private p ꥪ CurrentMessage.
   ᯮ  ⮬ ᪫⥫쭮 internally.  ᯮ짮
    p  p ;)

1.11. TMessageBase: 
~~~~~ ~~~~~~~~~~~~~ ~~~~~~

   procedure SetStatus(const AStatus: Longint); virtual;
   function GetStatus: Longint; virtual;

   SetStatus  ᯮ짮 p狼 p -  p SetCurrent
    p諮 p,   GetStatus    祭 pᥭ.
     -  p.   堭p -   p GetStatus,
   ⮡  ᪠   訡. ᮡ   p
   뢠 ExplainStatus  skCommon, ⮡  ᠭ 訡
   p.

   p.s. GetStatus' , p ᮮ饭   =)
           맢       p
         GPF' ( p  PMessageBase(nil)^.GetStatus ;)

1.12. TMessageBase: p⨢ stuff
~~~~~ ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ ~~~~~

   procedure SetOpened(const AOpened: Boolean); virtual;
   procedure SetBasePath(const ABasePath: String); virtual;

   function GetOpened: Boolean; virtual;
   function GetBasePath: String; virtual;

   SetOpened,   SetBasePath ᯮ  p 楫.

   GetOpened p頥, p   ᥩ  .
   GetBasePath p頥   .



 . .
~~~~~ ~~~~~~~ ~~~~~~~~~~
2.0. 祭 pᨨ skMHL
~~~~ ~~~~~~~~~~~~~~~~~~~~~~

   function skMHLversion: String;

   p p  '0.1bXX',  XX - p .

   function skMHLtitle: String;

   p p  'skMHL 0.1bXX'.

   function skMHLfulltitle: String;

   p p  'skMHL 0.1bXX (q) by sk // [rAN], 1998-2000'

2.1. 祭 p p⮢ ⥪饣 ᮮ饭
~~~~ ~~~~~~~~~ ~~~~~~ ~~~~~~~~~~ ~~~~~~~~ ~~~~~~~~~

   procedure GetAttributesLine(B: PMessageBase; var S: String);

    B  ᮮ饭   p.  S 㤥 ᠭ
   p p⮢ ⥪饣 ᮮ饭  'Pvt K/s Loc etc'

2.2. 祭 p /p
~~~~ ~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~

   procedure GetDateTimeLine(var DT: TMessageBaseDateTime; var S: String);

    S 㤥 ᠭ 祭 - '2000/05/10 01:26:50.77'



 . LOW-LEVEL 
~~~~~ ~~~~~~~~~~ ~~~~~~~~~ ~~~~~~
3.0. Low-level p  --
~~~~ ~~~~~~~~~ ~~~~~~ ~ ~~~~~~~~~~~

   skMHL.pas, skMHLmsg, skMHLjam  skMHLsq ,  ,
   ᮪p묨 ﬨ skMHL (high-level), p ⢫
   p  ,    ,  p 䠩, ᤥ
   findfirst  .. -  pp 祭 .

    p   skCommon   p.

    skCommon' ᮤp   ⨯, 㭪権 ⨯
   DirectoryExists  p祣 p. p᪨   skCommon'
   ᠭ  p BP-like ⨫  p  SysUtils/Windows
    Delphi, Dos/Strings  BP  Dos/Strings/vpSysLow  VP.

    skCommon'   p ꥪ TMessageBaseStream - ⮪,
   p ᯮ  㯠  䠩,  p p ,
   ⮪-- (MemoryStream), p p ⥪ ᮮ饭.. etc

   p⢥ low-level p p  䠩, ⮪  
    file finder' p  mhl*.inc, p  
   skCommon ⮬᪨.

3.1.   skCommon
~~~~ ~~~~~~~~~~ ~ ~~~~~~~~

    TSquish*, TFido*  TJam* ⨯ p諮   ᢮
   㫥 ᪫⥫쭮 - VskMHL,    - .

    p㯯 ⠭ ma*  af*    , ᫨ ⠥
     砫,   ⨫ p PgDn.

   ⠭ MaxLineSize  MaxMessageSize ᪮p  p,
   祬 㠫 - ᫥ ⠭ p᪨   ᯮ,
    p ᯮ   -  GetMem',  p  PChar'
   롨.

   fmb*, jmb*, smb* -  訡  Fido (MSG), Jam'  ᪢
   ᮮ⢥⢥. omb* - 祭, p  p p
   OpenStatus  skOpen (p  - ).   ⠭
   p 뫨 pᥭ  ᢮ ,  ⥯p ᮡp ,
    skCommon ⮫쪮   p稭 - ExplainStatus. ExplainStatus
     訡 p   ᠭ. p p...

   ⠭ sm* -  p᪨. p ᥬ  - smCreate,
   smOpen*, smDeny*  p ᮧ 䠩p - 㪠뢠
    p p/ᮧ 䠩  p. p  ⮫쪮
    p, pp⥫쭮  OR ( ᫮):  ⠭
    p ⢥p  (樮쭮) ⠭  p ⢥p.
   .. smCreate or smDenyAll,   smOpenRead or smDenyNone or smDenyAll.

   smOk ᯮ ᪫⥫쭮  if',  pp p쭮
   ﭨ p. ⨯ if Stream^.Status = smOk then ...

   fa* - p  TMessageBaseFileFind.   p  祣 ,
     ᠬ  ,   ⠪.

   DefaultZone - p, p 㤥 ᯮ짮 (⠢
       p),  ⨭  p  㤠.

   堫, p  ⨯:

   TAddress - p Integer'. , , , .

   TMessageBaseDateTime -  ⠪ ⨯ p   p 祣-.

    - TMessageBaseStream, p p   㦥  p᪠ ;)

   TMessageBaseFind:  ᫮
    StartSearch      == FindFirst
    NextSearch       == FindNext
    StopSearch       == FindClose

    ᫨ 㤥 ᯮ짮 TMBFF,  ᫥ StartSearch 뢠
    StopSearch H.   砥.   .

     p  直 p, p 
   p  ,  ᫨  - pp ᠬ.

   ⮬ - p  䮫 p.

   :  ⠭ - RegisterFileOpen  RegisterFileClose.
   ⮬᪨ 뢠 ⠬   TMBS'.  
   ᢮ p  RFO  RFC  ᬮp,  䠩 skMHL
   p뢠/p뢠.  p㬠   JT,  ⠬  p
   䠩   뫮   ..

3.2. p楤p  㭪樨 skCommon
~~~~ ~~~~~~~~~ ~ ~~~~~~~ ~~~~~~~~

    ᫥騬 㭪ﬨ/p楤p,  㬠,  ᭮:

   function DirectoryExists(const Pathname: String): Boolean;
   function FileExists(const Filename: String): Boolean;
   function KillFile(const Filename: String): Boolean;
   function RenameFile(const OldFilename, NewFilename: String): Boolean;
   function LongToStr(const Number: Longint): String;
   procedure StrToInteger(const S: String; var I: System.Integer);
   procedure StrToWord(const S: String; var I: Word);
   function StrToNumber(const S: String): Boolean;
   function ExtractWord(N: Byte; const S: String; WordDelims: TCharSet): String;

     p室  ᮮ⢥騥 㭪樨  p:

   procedure ToASCIIZ(const Source: String; const Destination: Pointer);
   function FromASCIIZ(const Source: Pointer): String;
   procedure ConcatASCIIZ(const Destination, Source: Pointer);
   function LenASCIIZ(const Source: Pointer): Integer;
   function PosASCIIZ(const SubString, Source: Pointer): Pointer;
   function CompLASCIIZ(const Str1, Str2: Pointer; MaxLen: Word): Integer;

   騥 㭪樨/p楤p -   pᠬ.

   function AddressToStr(var Address: TAddress): String;

   p p  p, p  (2, 6033, 27, 28), p頥:
   '2:6033/27.28'

   function AddressToStrPointless(var Address: TAddress): String;

   p p  p,    p頥 p   
   p p. 2:6033/27.28 -> '2:6033/27'

   function AddressToStrEx(var Address: TAddress): String;

    p p㬠: ᫨ Address.Point <> 0,   塞
     襬 p ,  襬 pointless p.

   .. 2:6033/27.28 -> '2:6033/27.28', 
        2:6033/27.0  -> '2:6033/27'

   function StrToAddress(Source: String; var Address: TAddress): Boolean;

   pp p p p '/27', '.222', '5012/22', '2:33/2'
    TAddress. Address p p⪮  頥 -  ⮣
   ᯮ ClearAddress. ᫨ ᬮ  - pᯠp
    p, p True,  ᬮ - p False.

   function StrToAddressR(const Source: String): PAddress;

    ,   StrToAddress,  p頥 p    ᪨
   TAddress' (ᯮ ﬨ p   㤮
   p樨 p  p):

   Base^.SetFromAddress(StrToAddressR('2:6033/27')^, True);

    p  p  '^'  p㬠 - ⮣,  BP 
   㬥 p record  p 㭪樨.

   procedure ClearAddress(var Address: TAddress);

     .

   function IsCleanAddress(var Address: TAddress): Boolean;

   p True, ᫨   p .

   function AddressCompare(const First, Second: TAddress): Longint;

   p  p  p頥:
      -1    ᫨ First "" Second
      0     ᫨ First == Second
      1     ᫨ First "" Second

   procedure PatchAddress(const Flags: Longint; const Valid: TAddress; var Partial: TAddress);

   ᯮ p栬  "p騢"   pᮢ
   ⨯ '2:6033/27'  '.9'. Flags - p pa*, p p, 
   p騢. p  ⮣ . 室 PatchAddress ;)


   /p.

   function IsRealMessageBaseDateTime(var DateTime: TMessageBaseDateTime): Boolean;

   p頥 True, ᫨ Year >= 1980 (..   )

   function IsValidMessageBaseDateTime(var DateTime: TMessageBaseDateTime): Boolean;

   p頥 True, ᫨ Year >= 1980   ⠫  㪫뢠
    ⢥  p (⨯ Month - 1..12, etc)

   procedure GetCurrentMessageBaseDateTime(var DateTime: TMessageBaseDateTime);

     DateTime ⥪   p.

   function MessageBaseDateTimeCompare(const First, Second: TMessageBaseDateTime): Integer;

   p  , p p -   AddressCompare (. )

   procedure MessageBaseDateTimeToDosDateTime(var DateTime: TMessageBaseDateTime; var DosDateTime: Longint);
   procedure DosDateTimeToMessageBaseDateTime(var DosDateTime: Longint; var DateTime: TMessageBaseDateTime);

   pp TMBDT  DosDateTime  p⭮.

   function GregorianToJulian(DateTime: TMessageBaseDateTime): LongInt;
   procedure JulianToGregorian(JulianDN: LongInt; var Year, Month, Day: Integer);

    ᪨ p  p⭮

   procedure UnixDateTimeToMessageBaseDateTime(SecsPast: LongInt; var DateTime: TMessageBaseDateTime);
   procedure MessageBaseDateTimeToUnixDateTime(var DateTime: TMessageBaseDateTime; var SecsPast: Longint);

    ⠩  p⭮.

   procedure MessageBaseDateTimeToMSGDateTime(const DT: TMessageBaseDateTime; var L: Longint);
   procedure MSGDateTimeToMessageBaseDateTime(const A: Longint; var DT: TMessageBaseDateTime);

    msgdatetime  p⭮ (p   娤p .msg)


   procedure MonthStringToMonthNumber(S: String; var Month: Word);
   function MonthNumberToMonthString(const Month: Word): String;

   'Jan' etc -> 1..  p.


   function GenerateMSGID: String;

   p MSGID.


   function UpdateCRC32(Octet: Byte; Crc: Longint): Longint;

    crc32    (crc p p p樥 
    ⠭  $FFFFFFFF)

   function StringCRC32(const S: String; Crc: Longint): Longint;
   function PCharCRC32(S: PChar; Crc: Longint): Longint;

   p頥 crc32  p   PChar' ᮮ⢥⢥.

   function CreateDirectory(Directory: String): Boolean;

   ᮧ ⠫  ⥯ 


   function Y2ToDouble(const Year: Longint): Longint;
   function DoubleToY2(const Year: Longint): Longint;

   ⨯ 2000 -> 0, 2010 -> 10  p.


   function ExplainStatus(const Status: Longint): String;

   p頥 ᠭ 訡   .  ExplainStatus 뫮
   ᪠ .



 .   (skOpen)
~~~~~ ~~~~~~ ~~~~~~~~ ~~~ ~~~~~~~~
4.0.  ?
~~~~ ~ ~~~~~~

    . ⮡ 㤮 뫮 p뢠  p p⮢.
    p楤p.    p -   p,
    짮⥫ - .

    p  ⢥  p  p "",
    "" 㪠뢠 p .

   "F", "M", "*" - MSG
   "S"           - Squish
   "J"           - Jam

   H   - ,  ᠭ  p NB  1.2.

4.1. p᪨ ⮤
~~~~ ~~~~~~~~~~~~~~~ ~~~~~~

      ⭥ SplitID,  Init/DoneMessageBase:

   procedure SplitID(const ID: String; var Format: TMessageBaseFormat; var Path: String);
   function InitMessageBase(var Base: PMessageBase; const ID: String): Boolean;
   function DoneMessageBase(var Base: PMessageBase): Boolean;

   SplitID pp p 짮⥫ ID  ⥬  p 
     ⠢: p  (TMessageBaseFormat) - mbfJam, mbfMSG,
   mbfSquish , ᫨ -  ⠪, mbfUnknown;  p⢥
     , p  㤥 p p楤p Open ᮮ⢥饣
   ⨯  ꥪ.

   InitMessageBase ᮧ  p TFido/Jam/SquishMessageBase,
    ᨬ  ID,   p뢠   㤥. ⠢
      ᮢ ;)

   DoneMessageBase p  ᯮ ,  Base ᤥ p nil.

   H  p ⮤ p ᯮ. 筮 ᯮ , 
   ᠭ ⪠ .

4.2. Hp᪨ ⮤
~~~~ ~~~~~~~~~~~~~~~~~ ~~~~~~

   function OpenMessageBase(var Base: PMessageBase; const ID: String): Boolean;
   function OpenOrCreateMessageBase(var Base: PMessageBase; const ID: String): Boolean;

     ⮤ 祭 宦,  p ᫥ ⫨砥  p.
   : ᫨   㤠 p,  ⠥  ᮧ.
   쪮  ᫨   ᮢᥬ 祣  , p False 
   p稭  p OpenStatus.

   function CloseMessageBase(var Base: PMessageBase): Boolean;

    ⮤ (,  ⮤?     ꥪ! p楤p.  
   p  ) p . p  ᥬ p, ⤠  
   etc.

   function ExistMessageBase(const ID: String): Boolean;

   p True ᫨   ⠪ ID  (   p).

    pp:

      uses
           skCommon,
           skMHL,
           skOpen;

      var
       Base: PMessageBase;
      begin
       if not OpenOrCreateMessageBase(Base, 'Jc:\testjam') then
        WriteLn('failed to open/create: ', ExplainStatus(OpenStatus))
       else
        begin
         WriteLn('Opened, here ', Base^.GetCount, ' message(s).');

         ...

         CloseMessageBase(Base);
        end;
      end;

4.3. ᥬ Hp᪨ ⮤
~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~ ~~~~~~

   function OpenMessageBaseEx(var Base: PMessageBase; const ID: String;
    const Process: TMessageBaseOpenProcess; Attempts: Longint): Boolean;

   p뢠 ( p뢠/ᮧ) , p祬 ⠥ p 
   Attempts p  p AttemptDelay (⠭   skOpen).

   祬  ⫨砥  Open(OrCreate)MessageBase, ⮫쪮  㪠
   ⮪ p.

   , btw, ⪨  p   p,   ⢮
     節,  Open(OrCreate)MessageBase p True, 
   p False  -, ⫨筮  ombLocked  GetStatus.

   pp:

   if not OpenMessageBaseEx(Base, 'Jc:\testjam', OpenOrCreateMessageBase, 10) then
    ...;
   if not OpenMessageBaseEx(Base2, 'Sc:\testsq', OpenMessageBase, 10) then
    ...;



 . HH  T*MessageBase
~~~~~ ~~~~~~~ ~~~~~~~~~~~ ~~~~~~~~ ~~~~~~~~~~~~~
5.0. ᮡ ꥪ⮢ T*MessageBase
~~~~ ~~~~~~~~~~~ ~~~~~~~~ ~~~~~~~~~~~~~

    뭪 TMessageBase  ᢮ ᮡ⢥ ⮤, p
   p - ᯥ  p⭮ .
     p ᯮ, ⠪  ᫨   ⠪ ᨫ쭮
   pp,  pp ᠬ.   㤥 ⭮ - p
    .



 . H  H (TVirtualMessageBase, skMHLvmb)
~~~~~ ~~~~~~~~ ~~~~~~~~~~~ ~~~~ ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~
6.0. p㠫 ᥩ p
~~~~ ~~~~~~~~~~~~~ ~~~~ ~~~~~~

    祬  p㠫쭮  ᮮ饭?   ⠪ p 뢠,
     ᠬ    騭.

   pp:  skMHL  쭮 宩 pp PChar'
   (p,  >255 ᨬ  p (  ⥭) ).

    뢠 㦭 pp p PChar'  p 
   ⥪⮢,   ᢮ ᮡ⢥ p楤p  p  PChar'
   ⥪⮬  p뢠  skMHL .

      pp ⠪ 䨣,  㬠,  㤥 訬
   p饭 pp pp  skMHL,  p뢠   ⠢ 
   p.   ᮢᥬ ᫮..

     祬  ?

     ⮬,   p뢠 - 䠩   ⮪
    ,  p 室 - ⥪  묨 p.
      ⥪  p.

     ⠪:

   uses
        skMHL,
        skMHLvmb,
        Objects,
        __祣;

   var
    Stream: PStream;
    Ch: array[0..4095] of Char;
    vmb: PMessageBase;
   begin
    Stream:=New(PBufStream, Init('c:\bootlog.txt', stOpenRead, 2048));

    vmb:=New(PVirtualMessageBase, Init(Stream));

    { ?    ᮧ p䥩  p  ⥯p 
      p     ⥪⮢ 䠩,  p p 
      ⮤ skMHL :) }

    vmb^.SetTextPos(0);

    while not vmb^.EndOfMessage do
     begin
      vmb^.GetStringPChar(Ch, SizeOf(Ch));

      WriteLn(Ch);
     end;

    Dispose(vmb, Done);

    Dispose(Stream, Done);
   end.

    vmb  㦭   OpenMessage, p  㦭  p:
   p p  ⥪⮬/㤦  .

   vmb  ᯮ p  p, ⠪   ⮬  p
    ᠬ.

     pp  TV p (,    ⨫? ;),
       ꥪ vmb - TVirtualMessageBaseMHL,  ⮦ 
   p p⠥,  ⮫쪮  MHL'᪨,  ⥬ ᠬ
   TMessageBaseStream'  skCommon'.

   , ,  ,   ᪠ p vmb.



 . skMHL  DLL. skMHL API.
~~~~~ ~~~~~~~~ ~~~~~ ~ ~~~~ ~~~~~ ~~~~
7.0. skMHL  DLL
~~~~ ~~~~~ ~ ~~~

    DLL-p skMHL,   ⮤ p⠢ ᯮpp㥬묨
   p楤p/㭪ﬨ. skmhldll ᮡp  p p:
    skmhlapi.dll - dos(dpmi)
    skmhlw32.dll - win32
    skmhlos2.dll - os/2

    p, 祬  p  dll?

     ⢥,    㤮  筥, p筥 
   筥. ⨬,     , p p
    skMHL/dll.

     p: ᪮쪮   ,   p 
             skMHL (  ⠪  pp  ,   ⮬ 
             pp      p㬥⮬.. ;)

     p: p p㦥     p p
              p  AFTNFAST  ⠫,    p
             pᮡp  㥢  p⮢,  skmhl.
              㦭 㤥 ᥣ  ᮡp dll  p
             skmhl,   䠩,   -   
             dll   p  筮. 㤮⢮..?

   -, ⮣ 筮, ⮡ ᪠ "" skmhldll :)

7.1. skMHL API
~~~~ ~~~~~ ~~~

    , ᫨  - p ppp,  㦥 뢠:
   ᫨ p skmhl 뫠 ᪮     뫮 p
     ꥪ⠬,   ⥯p ..? dll   㬥 ᯮpp
   ꥪ! ⮫쪮 p楤p  㭪樨.

   ,  ᫮ p, p  p襭   p⢠,
   ᠭ  ᫥饩  (VskMHL).    DLL 
     ꥪ⠬. ..  ⠥,   p, 
    砥 p⢮   dll.

     ,  pure skMHL API ⠢  ⭨
   entrypoint',  p ᮧ⥫ 筮  p
    ᠤ娧,  -  ᯮ짮
   pure skMHL api ;)


 . The Virtual skMHL
~~~~~ ~~~~~~~~ ~~~ ~~~~~~~ ~~~~~
8.0. ⥫  p稥 H
~~~~ ~~~~~~~ ~ ~~~~~~ ~~~

    ⠫ V\ p⨢ pᯮ  㫥 skMHL:
    skmhl.pas skmhlapi.pas skmhljam.pas skmhlmsg.pas
    skmhlsq.pas skmhlvmb.pas skopen.pas

      ᠬ skMHL, ⮫쪮   p.   VskMHL
    ᯮ , 室騩  dll.  ,   
   p p, p p ⥫, p⠢   p䥩,
     skMHL,  ᯮ dll ;)

   p ⥫   dll. H訥 p室窨  ꥪ.

     p ⥫   skMHL,  p ⠨
     p⪨ ..

    p᪨ ⮤   "⮤ 㯫᭮ ⥫".

8.1. 祬 㯫᭠?
~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~

   H ᠬ-     㬠,    ⠥ ᥫ..
    p᪠,  祬 .

    饬,  dll  .exe.  (dll & exe)   , p,
   ⢥,    ᪨.  ⮬ ᪮ 㫥
    ꥪ. pᨨ ᪮  -    . Exe ᮧ
   p ⮣ ꥪ, 樠p   p 㪠⥫ 
   dll.  dll ⠥ 맢 - ⮤ ⮣ ꥪ,
   ᮧ  .exe, p室 GPF.

    类 砥, ⠪ 䨣 뫠 (   )  BP.

   ,    TMessageBase,  ᤥ p室,  p⠥.
   p쥧 p⠥. H  뫨  p  : p. p
   ᮧ  ⥪ skmhlapi.dll.. 筮    㦭, 
    p  p  p室!      ⥬ p
   -  ⢮p.   p 砥 㪠⥫ 
    p. ⠥  ᯮ짮  砥 GPF.

   p:     ?

   p, ⥬    p  㦥 p訫.

   襭 室  㫥 GStream, p    VskMHL.
   襭 砥  ᯮ짮 p-p室. p
   p㠫 p, ⠪  p,   VskMHL :) p p
    , ⮤ p  뢠,  -  ᠬ  ᯮ
   ᮢᥬ  p㣮  ,  p,  .

    饬,   p⭮ pp:
   : p , p⮥ ᮮ饭. H 㦭 ⥪ ᮮ饭
     䠩. H GetString',  樢쭮, p p ;)

     ⠪:

     1. AlienStreamMHL:=Base^.GetMessageTextStream;
         AlienStreamMHL - 㪠⥫  PMessageBaseStream, ᮧ 
        .dll.

         p ᯮ짮 .

     2. ᮧ thunk (p室) - "" p, p
        p "" (⠪   p楤p, p ⨬ )
        뢠  dll  㫨p alien-p  ⥪ dll:

        LocalStreamMHL:=New(PMessageBaseStreamThunk, Init(
               AlienStream,             { "p᪨" p :) }
               @skmhlapiGatewayMHL,     {  MHL, p ᯥ  }
                                        { p  ⨬ p }
               False));                 { False  㪠 thunk'
                                           ᯮ "p᪨" p
                                          p 맮 pp thunk' }

     3. ⥯p p⠥  LocalStreamMHL:

        LocalStreamMHL^.Seek(0);

        FileStreamMHL^.Seek(0);

        FileStreamMHL^.CopyFrom(LocalStreamMHL^, LocalStreamMHL^.GetSize);

        p⠥  p,  맮 ⮬᪨ p᫨p p
          dll  p⭮   砥 ,  ⥫  譥
        pp.

      p GStreams p㦨 (   䥪
    :) -  ᮧ TV-Thunk (.. ꥪ, p騩 
   objects.TStream), p 㤥 p᫨p  MHL-Stream:

   var
    LocalStreamTV: PStream;

   LocalStreamTV:=New(PStreamThunk, Init(AlienStream, @skmhlapiGatewayMHL, False));

   ? ;)

8.2. GStreams
~~~~ ~~~~~~~~

    ﭥ  GStreams  ᬮp,   ⠬ 堭-..

   gfn* - ⠭, p ᯮ ⠬.  p 
          p  p ᠬ.

   TStreamGateway - 㭪, p   "⮬":
   function(const Stream: Pointer; const fn: Integer; const Data: Pointer; var l: Longint): Longint;

   TStreamThunk  TMessageBaseStreamThunk - ꥪ-p室.

   DefaultGateway - "p" Gateway, p ᯥ稢 ᮧ
    ᢮ ⥪ p室  p    祣 .
    易 뢠  ⠫ p室  ⥪
   (  ),  ᯥ pp⭮ ᮧ "㤠 p室".

   DefaultGatewayTV -   ⥪饣 ⥪  TV-p.
   (btw,  㦥 ,  룫廊  skmhlapiGatewayTV? ;)
    :
    function skmhlapiGatewayTV(const Stream: Pointer; const fn: Integer; const Data: Pointer; var l: Longint): Longint; export;
     begin
      skmhlapiGatewayTV:=DefaultGatewayTV(Stream, fn, Data, l);
     end;

   DefaultGatewayMHL -   *TV,   MHL-p .

     .. 孮 "㤠 p室" 
    p "㯫᭮" ⥫..

    . " , ⥫!" () ...

8.3.  p室 (remote thunks)
~~~~ ~~~~~~~~~ ~~~~~~~~~~~ ~~~~~~~ ~~~~~~~

   "Hp  p", p ?

   H  ⢥,   業p..

   p p,  :  p p⮣ ᮮ饭  ᢮.
      ,  p,  ᮮ饭,  p.
        p p ⠢ ᢮. , ⭮,
   p室  dll.   p , p  p蠫 p ᯮ짮
   vmb  dll.

     ⮬,  p ( p-p室,   skMHL p? ;)
     ᮧ  ⥪ skmhlapi.dll,  p p 맮
   襣 p쭮 p skmhlapi p孥  GPF.

   : 㦭  skmhlapi.dll  p室, p 㤥
   p᫨p  ⮤  H p, p ᮧ  H,  .exe,
      skmhlapi.dll.

     ⢨?

   H, p㥬 - p㬠.

   ⠪,  p.   㤥 TV'.  p쭥.
      VskMHL.  p, ᮮ饭 ⮦,  
   ᥣ-  p  ᢮  (⨯) p  ᮮ饭
   :

   var
    Stream: PStream;
    Base: PMessageBase;
    MessageStream: PMessageBaseStream;

   Stream:=New(PBufStream, Init('c:\pagefile.sys', stOpen, 2048));

   CreateRemoteMessageBaseStreamThunk ᮧ MHL-p-p室
    ⥪ p㣮 dll (exe).

   MessageStream:=CreateRemoteMessageBaseStreamThunk(
    { p pp p 㤠  } @skmhlapiGatewayMHL,
    {  p樯,  p,    }
    { 㪠뢠 - TV  MHL. 祬? . DefaultGateway  }
    { ,    p p ;) }

    { p pp   - p.  p }  Stream,

    {  p쨬 -  , p 㤥 p뢠 }
    { p  襬 p. }
    {     TV- }                 @DefaultGatewayTV,

    {  㪠 thunk',   p  }
    {   pp (  p;) } True);

     맮 CRMBST ⠪ pﬨ p⨫,  , p,
    p  ? H  p  p:

   MessageStream:=CreateRemoteMessageBaseStreamThunk(@skmhlapiGatewayMHL,
     Stream, @DefaultGatewayTV, True);

   H . p ⠢  MessageStream  p    窮.
   쪮  㬠 뢠  ᮧ p⭮ p -
   ⮤ =)  p   #  .

   Base^.SetMessageTextStream(MessageStream);

    p p   ᯮ - SMTS   ᠬ.


    ⮬ 砥   p 㡨 p p,   ᫨
      pᯨ - :  DestroyRemote*StreamThunk:

   DestroyRemoteMessageBaseStreamThunk(@skmhlapiGatewayMHL, MessageStream);

   p pp  㪠뢠 㤠 , p  㤥
   p 㡨. p - 㪠⥫  ᬥp⭨.

   , ,  ,  ᠥ GStream', "# p室"
    p "  ꥪ⮢"...

   .

 .     --.
~~~~~ ~~~~~~~~ ~~~ ~~~~~~~~ ~~~~~~ ~ ~~~~~~~~~~~~
9.0.   ⥫
~~~~ ~ ~~ ~~~~~~~~

     ⥫   ,     , ᮡ
   ⠪  - ᠭ ⥪. p⭮,  㤥 ᫮
      ⮭ skMHL, VskMHL, p p  .. p,
       p;)

   㬠,         p p -  뫮 ᫨誮
   筮  p,    - 砫 ᯮ짮  
   .

   Hp  p ,     ,  p,
   p -   ⨬  ᯮp,   - ⠪  .   ,
    祬 㬠,   㬠 p, 祬  - p᪠ p
   ᫨, p,  ,  祢묨  ..

   H,   砥,  ᥣ   뫮     p,
    ⭮ -  p ᭨.

   H p㣠       ᫥ p ᫮p,
    p p  樮쭮 -   ;(

    饬,  ,  ᢥ⨫  ⮩   ⥬, p 뫨
    p. ᫨  p -  ᠫ, ᠫ  
   ᠫ  ⠪ - p  뫮,  p. ok? ;)

   truly yours, sk.

9.1.   ?
~~~~ ~~~ ~~~~ ~~~~~~

   ᫨   ,    sergey korowkin.

    p:

                   http://sk.elk.ru, sk@fido.irk.ru
                   2:6033/27@fidonet

    ᥣ    ᫥ :

                   RU.FASTUUE
                   RU.FASTUUE.TALK

                   ⠬   㤨 - p
                    skMHL.

9.2. That's all folks!
~~~~ ~~~~~~ ~~~ ~~~~~~

   H ⮬ p  .
   ᨡ,  ⠫  ⮣ .

   truly yours, sk ;)
