{MKMsgAbs - Abstract Msg Object
Copyright 1993 by Mark May (1:110/290;maym@dmapub.dma.org)
Changes (c) by Andre Grueneberg
Changes (c) 1998-2000 by Bernhard R. Link (2:2476/841.64;brl@gmx.de)
Changes (c) 2001 by Oliver Kopp (2:2471/1464;olly98@users.sourceforge.net)
****************************************************************************
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
****************************************************************************}
(* $Id: mkmsgabs.pas,v 1.15 2001/04/16 23:51:22 olly98 Exp $ *)

Unit MKMsgAbs;
{$I platform.inc}
{$I mkglobal.inc}

Interface
{Some Compilers allow abstract methods:}
{$IFDEF PPC_FPC}{$DEFINE UA}{$ENDIF}
{$IFDEF PPC_DELPHI}{$DEFINE UA}{$ENDIF}
(*
  {$IFDEF PPC_VIRTUAL}{$DEFINE UA}{$ENDIF}
  In Virtual Pascal it isn't possible for a function/procedure to be virtual AND abstract
*)

Uses {$IFDEF PPC_VIRTUAL}Use32,{$ENDIF}
     aTypes,aString,uDate,FTNAddr;

Type MsgMailType=TMailType;

(* Data for Yours*-Methods *)
(* not implemented as pointer to data, because it can't be assured that
   the constructor of TMKAbstract is always called *)
tYoursSeekData = record
    UpperName,
    UpperHandle: OpenString;
end;

Type TMKAbstract = Object
  LastSoft: Boolean;
  SubjectOfs: word;

(* object-routines *)
  Constructor Init; {Initialize}
  Destructor Done; Virtual; {Done cleanup and dispose}

(* handling with the whole messagebase *)
  Function  OpenMsgBase: Word; virtual{$IFDEF UA};abstract{$ENDIF}; {Open message base}
  Function  CloseMsgBase: Word; virtual{$IFDEF UA};abstract{$ENDIF}; {Close message base}
  Function  CreateMsgBase(MaxMsg: Word; MaxDays: Word): Word; virtual{$IFDEF UA};abstract{$ENDIF};

  Procedure SetMsgBasePath(const FN: OpenString); virtual{$IFDEF UA};abstract{$ENDIF}; {Set filepath and name - no extension}
  Procedure SetMsgBaseType(MT: TMailType); virtual{$IFDEF UA};abstract{$ENDIF}; {set messagebase type}
  Procedure SetMsgBaseDefaultZone(DZ: Word); Virtual; {Set default zone to use, currently only needed at mkmsgfid}

  Function  MsgBaseExists: Boolean; virtual{$IFDEF UA};abstract{$ENDIF};

  Function  LockMsgBase: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Lock msg base}
  Function  UnLockMsgBase: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Unlock msg base}

  Function  NumberOfMsgs: LongInt; virtual{$IFDEF UA};abstract{$ENDIF}; {Number of messages}

  (* don't know, for what these are used *)
  Function  GetSubArea: Word; virtual; {Get sub area number}

(* handling with msgs *)
  (*  Function  GetHighActiveMsgNum: LongInt; virtual{$IFDEF UA};abstract{$ENDIF}; {Get highest active msg num}*)
  Function  GetHighMsgNum: LongInt; virtual{$IFDEF UA};abstract{$ENDIF}; {Get highest msg number}
  (* perhaps this would be also useful:   Function  GetLowMsgNum: LongInt; Virtual; {Get lowest msg number}, taken from mkmsghud *)

  Function KillMsg(MsgNum: LongInt):Integer; virtual{$IFDEF UA};abstract{$ENDIF}; {Kill msg msgnum}

  (* lastread *)
  Function  GetLastRead(UNum: LongInt):Longint; virtual{$IFDEF UA};abstract{$ENDIF}; {Get last read for user num}
  Procedure SetLastRead(UNum: LongInt; LR: LongInt); virtual{$IFDEF UA};abstract{$ENDIF}; {Set last read}

(* seeking *)
  Function SeekFirst(MsgNum: LongInt;Reload:Boolean):Boolean; virtual{$IFDEF UA};abstract{$ENDIF};
  {Seeks to 1st msg >= MsgNum, true if msg=MsgNum or ( msgNum=0 and any msg found)}

  Function SeekFirstAfter(MsgNum: LongInt;Reload:Boolean):Boolean; virtual;
  {Seeks to 1st msg > MsgNum, true if any msg found}

  Function SeekPrior:Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Prior msg}
  Function SeekNext:Boolean; virtual{$IFDEF UA};abstract{$ENDIF};

  (*
    Desc:
      Seek your unreceived mail
      Name or Handle may match.
      Search is done case-insenstive
  *)
  function YoursFirst(const Name,Handle: OpenString):Boolean; virtual;

  (*
    Desc:
      Seek your next unreceived mail
      Uses Name and Handle from YoursFirst
  *)
  function YoursNext:Boolean; virtual;


(* handling of a specific msg *)

  Function  GetMsgDisplayNum: LongInt; virtual; {Get msg number to display - currently equals to GetMsgNum}
  Function  GetMsgNum: LongInt; virtual{$IFDEF UA};abstract{$ENDIF}; {Get Number of current message - possibly in MkMsgSqu: Count of Msgs}

(* should work at reading and writing *)
  Function  GetTxtPos: LongInt; Virtual{$IFDEF UA};abstract{$ENDIF}; {Get indicator of msg text position}
  Procedure SetTxtPos(TP: LongInt); virtual{$IFDEF UA};abstract{$ENDIF}; {Set text position}

(* reading the content of a msg *)
  Function MsgStartUp:Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Set up message}
  Function MsgTxtStartUp:Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Set up for msg text}

  (* reading the text *)
  Function  GetChar: Char; virtual{$IFDEF UA};abstract{$ENDIF}; {Get msg text character}
  Function  GetNoKludgeStr(MaxLen: Word): TString; virtual; {Get ww str no ^A lines}
  Function  GetString(MaxLen: Word): TString; virtual;
  Function  EOM: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {No more msg text}
  Function  WasWrap: Boolean; virtual;

  (* sender, receipient, subject *)
  Function  GetSubj: TString; virtual{$IFDEF UA};abstract{$ENDIF}; {Get message subject}
  Function  GetFromName: TString; virtual{$IFDEF UA};abstract{$ENDIF}; {Get message from}
  Function  GetFromAddr: TFtnAddr; virtual{$IFDEF UA};abstract{$ENDIF};
  Function  GetToName: TString; virtual{$IFDEF UA};abstract{$ENDIF}; {Get message to}
  Function  GetToAddr: TFTNAddr; virtual{$IFDEF UA};abstract{$ENDIF};

  (* date and time *)
  Function  GetDateTime:TDateTimeStr; virtual{$IFDEF UA};abstract{$ENDIF}; {'dd mmm yyyy  hh:mm:ss'}
  Function  GetRDateTime:TDateTimeStr; virtual; {Received Date, if not supported GetDateTime is returned}

  (* links to other messages *)
  Function  GetSeeAlso: LongInt; virtual; {Get see also of current msg}
  Function  GetNextSeeAlso: LongInt; virtual;
  Function  GetRefer: LongInt; virtual{$IFDEF UA};abstract{$ENDIF}; {Get reply to of current msg}

  Function  GetCost: Word; Virtual; {Get cost of current msg; std=0}

  (* f/a *)
  Function  GetFAttach: String; Virtual;
  Function  GetFRequest: String; Virtual;
  Function  IsFAttach: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg file attach}
  Function  IsFileReq: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg a file request}

  (* other attributes *)
  Function  IsCrash: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg crash}
  Function  IsDeleted: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg deleted}
  Function  IsEchoed: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg unmoved echomail msg}
  Function  IsLocal: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg local}
  Function  IsFwd: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg in transit}
  Function  IsHold: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg ist on hold}
  Function  IsKillSent: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg kill sent}
  Function  IsPriv: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg priviledged/private}
  Function  IsRcvd: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg received}
  Function  IsReqAud: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg request audit}
  Function  IsReqRct: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg request receipt}
  Function  IsRetRct: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg a return receipt}
  Function  IsSent: Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Is current msg sent}

(* writing a message *)
  Function  StartNewMsg:Boolean; virtual{$IFDEF UA};abstract{$ENDIF}; {Initialize msg header}
  Function  WriteMsg: Word; virtual{$IFDEF UA};abstract{$ENDIF}; {Write msg to msg base}
  Function  ReWriteHdr: Word; virtual{$IFDEF UA};abstract{$ENDIF}; {Rewrite msg header after changes}

  (* writing the text *)
  Procedure DoChar(Ch: Char); virtual{$IFDEF UA};abstract{$ENDIF}; {Add character to message text}
  Procedure DoKludgeLn(const Str:OpenString);virtual;
  Procedure DoString(const Str: OpenString); virtual; {Add String to message text}
  Procedure DoStringLn(const Str: OpenString); virtual; {Add string and newline to msg text}

  (* sender, receipient, subject *)
  Procedure SetSubj(const Str: OpenString); virtual{$IFDEF UA};abstract{$ENDIF}; {Set message subject}
  Procedure SetFromName(const name: OpenString); virtual{$IFDEF UA};abstract{$ENDIF}; {Set message from}
  Procedure SetFromAddr(const Addr: TFTNAddr); virtual{$IFDEF UA};abstract{$ENDIF};
  Procedure SetToName(const name: OpenString); virtual{$IFDEF UA};abstract{$ENDIF}; {Set message to}
  Procedure SetToAddr(const Addr: TFTNAddr); virtual{$IFDEF UA};abstract{$ENDIF};

  (* date and time *)
  Procedure SetDateTime(const s:TDateTimeStr);virtual{$IFDEF UA};abstract{$ENDIF};
  (* SetRDateTime doesn't exist *)

  (* links to other messages *)
  Procedure SetSeeAlso(dummy: LongInt); virtual; {Set message see also}
  Procedure SetNextSeeAlso(dummy: LongInt); virtual;
  Procedure SetRefer(Num: LongInt); virtual{$IFDEF UA};abstract{$ENDIF}; {Set reply to of current msg}

  Procedure SetCost(dummy: Word); virtual; {Set message cost}

  (* f/a *)
  Procedure AddFAttach(const s: String); Virtual;
  Procedure AddFRequest(const s: String); Virtual;
  Procedure SetFAttach(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set file attach status}
  Procedure SetFileReq(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set file request status}

  (* other attributes *)
  Procedure SetCrash(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set crash netmail status}
  (* setdeleted doesn't exist *)
  Procedure SetEcho(ES: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set echo status}
  Procedure SetLocal(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set local status}
  Procedure SetFwd(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set in transit status}
  Procedure SetHold(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set file hold status}
  Procedure SetKillSent(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set kill/sent netmail status}
  Procedure SetPriv(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set priveledge vs public status}
  Procedure SetRcvd(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set received status}
  Procedure SetReqAud(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set request audit status}
  Procedure SetReqRct(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set request receipt status}
  Procedure SetRetRct(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set return receipt status}
  Procedure SetSent(St: Boolean); virtual{$IFDEF UA};abstract{$ENDIF}; {Set sent netmail status}

  private
    YoursSeekData: tYoursSeekData; {used when seeking for personal Mail}

    (*
      Desc:
        Checks if current msg is a personal mail
      Returns:
        True  - if yes
        False - otherwise
    *)
    function YoursSeek_CurrMsgMatches: Boolean;

  End;

Type AbsMsgObj = TMKAbstract;
     AbsMsgPtr = ^AbsMsgObj;
     PMKMsgAbs=^TMKAbstract;

Implementation

uses
  ustring {$IFDEF UseObjects},Objects{$ENDIF}; {don't know, where UseObjects is definied, found it nowhere :-\}

{$IFNDEF UA}
Procedure abstract;
begin
RunError(210);
end;
{$ENDIF}

Constructor TMKAbstract.Init;
begin
end;

Destructor TMKAbstract.Done;
Begin
End;

Procedure TMKAbstract.DoString(const Str: openString);
  Var
    i: Word;

  Begin
  For i := 1 to Length(Str) Do
    DoChar(Str[i]);
  End;
Procedure TMKAbstract.DoStringLn(const Str: OpenString);
  Begin
  DoString(Str+#13);
  End;

Procedure TMKAbstract.DoKludgeLn(const Str: OpenString);
  Begin {Str hat mit #1 zu beginnen, sonst geht es nichts!}
     If Str[1]<>#1
        then DoStringLn(#1+Str)
        else DoStringLn(Str);
  End;


Function TMKAbstract.WasWrap: Boolean;
  Begin
  WasWrap := LastSoft and not EOM; {implementation of GetString is buggy, it doesn't set LastSoft correctly!}
  End;


Function TMKAbstract.GetSubArea: Word;
  Begin
  GetSubArea := 0;
  End;

Function TMKAbstract.GetMsgDisplayNum: LongInt;
  Begin
  GetMsgDisplayNum := GetMsgNum;
  End;


{$IFNDEF UA}

Procedure TMKAbstract.SetMsgBasePath(const FN: OpenString);
Begin abstract End;
Function TMKAbstract.OpenMsgBase: Word;
Begin abstract End;
Function TMKAbstract.CloseMsgBase: Word;
Begin abstract End;
Function TMKAbstract.LockMsgBase: Boolean;
Begin abstract End;
Function TMKAbstract.UnLockMsgBase: Boolean;
Begin abstract; End;
Procedure TMKAbstract.SetToAddr(const Addr: TFTNAddr);
Begin abstract; End;
Procedure TMKAbstract.SetFromAddr(const Addr: TFTNAddr);
Begin abstract; End;
Procedure TMKAbstract.SetFromName(const Name: OpenString);
Begin abstract;End;
Procedure TMKAbstract.SetToName(const Name: OpenString);
Begin abstract;End;
Procedure TMKAbstract.SetSubj(const Str: OpenString);
Begin abstract;End;
Procedure TMKAbstract.SetRefer(num: LongInt);
Begin abstract;End;
Procedure TMKAbstract.SetLocal(St: Boolean);
Begin abstract;End;
Procedure TMKAbstract.SetRcvd(St: Boolean);
Begin abstract;End;
Procedure TMKAbstract.SetFwd(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetHold(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetPriv(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetCrash(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetKillSent(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetSent(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetFAttach(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetReqRct(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetReqAud(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetRetRct(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.SetFileReq(St: Boolean);
Begin abstract; End;
Procedure TMKAbstract.DoChar(Ch: Char);
Begin abstract; End;
Function TMKAbstract.WriteMsg: Word;
Begin abstract;End;
Function TMKAbstract.GetChar: Char;
Begin abstract;End;
Function TMKAbstract.EOM: Boolean;
Begin abstract; End;
Function TMKAbstract.SeekFirst(MsgNum: LongInt;reload:Boolean):Boolean;
Begin abstract; End;
Function TMKAbstract.SeekNext:Boolean;
Begin abstract;  End;
Function TMKAbstract.GetFromName: tString;
Begin abstract;  End;
Function TMKAbstract.GetToName: tString;
Begin abstract;  End;
Function TMKAbstract.GetSubj: tString;
Begin abstract;  End;
Function TMKAbstract.GetRefer: LongInt;
Begin abstract;  End;
Function TMKAbstract.GetMsgNum: LongInt;
Begin abstract; End;
Function TMKAbstract.GetFromAddr: TFTNAddr;
Begin abstract; End;
Function TMKAbstract.GetToAddr: TFTNAddr;
Begin abstract; End;
Function TMKAbstract.IsLocal: Boolean;
Begin abstract; End;
Function TMKAbstract.IsCrash: Boolean;
Begin abstract; End;
Function TMKAbstract.IsKillSent: Boolean;
Begin abstract; End;
Function TMKAbstract.IsSent: Boolean;
Begin abstract; End;
Function TMKAbstract.IsFAttach: Boolean;
Begin abstract; End;
Function TMKAbstract.IsReqRct: Boolean;
Begin abstract; End;
Function TMKAbstract.IsReqAud: Boolean;
Begin abstract; End;
Function TMKAbstract.IsFwd: Boolean;
Begin abstract; End;
Function TMKAbstract.IsHold: Boolean;
Begin abstract; End;
Function TMKAbstract.IsRetRct: Boolean;
Begin abstract; End;
Function TMKAbstract.IsFileReq: Boolean;
Begin abstract; End;
Function TMKAbstract.IsRcvd: Boolean;
Begin abstract; End;
Function TMKAbstract.IsPriv: Boolean;
Begin abstract; End;
Function TMKAbstract.IsDeleted: Boolean;
Begin abstract; End;
Function TMKAbstract.IsEchoed: Boolean;
Begin abstract; End;
Function TMKAbstract.MsgStartUp:Boolean;
Begin abstract; End;
Function TMKAbstract.KillMsg(MsgNum: LongInt):Integer; {Kill msg msgnum}
begin abstract; end;
Function TMKAbstract.MsgTxtStartUp:Boolean;
Begin abstract; End;
Function TMKAbstract.CreateMsgBase(MaxMsg: Word; MaxDays: Word): Word;
Begin abstract; End;
Function TMKAbstract.MsgBaseExists: Boolean;
Begin abstract; End;
Function TMKAbstract.StartNewMsg:Boolean;
Begin abstract; End;
Function TMKAbstract.GetHighMsgNum: LongInt;
Begin abstract; End;
Procedure TMKAbstract.SetMsgBaseType(MT: TMailType);
Begin abstract; End;
Function TMKAbstract.ReWriteHdr: Word;
Begin abstract; End;
Procedure TMKAbstract.SetEcho(ES: Boolean);
Begin abstract;End;
function TMKAbstract.SeekPrior:boolean;
Begin abstract;End;
Function TMKAbstract.NumberOfMsgs: LongInt;
Begin abstract;End;
Function TMKAbstract.GetLastRead(UNum: LongInt): LongInt;
Begin abstract;End;
Procedure TMKAbstract.SetLastRead(UNum: LongInt; LR: LongInt);
Begin abstract;End;
Function  TMKAbstract.GetDateTime:TDateTimeStr;
begin abstract;end;
Procedure TMKAbstract.SetDateTime(const s:TDateTimeStr);
begin abstract;end;
Function  TMKAbstract.GetTxtPos: LongInt;
begin abstract;end;
Procedure TMKAbstract.SetTxtPos(TP: LongInt);
begin abstract;end;
{$ENDIF UA}

Function  TMKAbstract.GetRDateTime:TDateTimeStr;
begin
  GetRDateTime:=GetDateTime;
end;

Function TMKAbstract.SeekFirstAfter(MsgNum: LongInt;reload:Boolean):Boolean;
Begin
  if SeekFirst(MsgNum, reload) then begin
     SeekFirstAfter:=SeekNext;
  end else begin
     SeekFirstAfter:=false;
  end;
End;

procedure TMKAbstract.SetMsgBaseDefaultZone(DZ: Word);
begin
  {not every unit has to implement this code}
end;

Function TMKAbstract.GetNextSeeAlso: LongInt;
Begin
GetNextSeeAlso:=-1;
End;

Function TMKAbstract.GetCost: Word;
Begin
getCost:=0;
End;

Function TMKAbstract.GetSeeAlso: LongInt;
Begin
getSeeAlso:=-1;
End;

function TMKAbstract.YoursFirst(const Name,Handle: openString):Boolean;
begin
  YoursSeekData.UpperName:=UpString(Name);
  YoursSeekData.UpperHandle:=UpString(Handle);
  if SeekFirst(0, false) then begin
    (* if there are any messages
       search should start at first avail message *)

    (* extra check is necessary, because otherwise first message wouldn't be checked *)
    if YoursSeek_CurrMsgMatches then begin
      YoursFirst:=True;
    end else begin
      YoursFirst:=YoursNext;
    end;

  end else begin
    YoursFirst:=False;
  end;
end;

function TMKAbstract.YoursNext:Boolean;
var
  SeekFound,               (* if anything was found *)
  FoundMatching : Boolean; (* if a personal mail was found *)
  HighestNum    : LongInt; (* upper bound of search *)

begin
  FoundMatching:=false;
  HighestNum:=GetHighMsgNum;
  SeekFound:=SeekFirst(GetMsgNum+1, false);
  while (SeekFound) and (GetMsgNum <= HighestNum) and (not FoundMatching) do begin
    FoundMatching:=YoursSeek_CurrMsgMatches;
    if not FoundMatching then begin
      SeekFound:=SeekNext;
    end;
  end;
  YoursNext:=SeekFound;
end;

function TMKAbstract.YoursSeek_CurrMsgMatches: Boolean;
var
  UpperGetTo: TString;
begin
  MsgStartup;
  UpperGetTo:=UpString(GetToName);
  YoursSeek_CurrMsgMatches:=
    ((UpperGetTo = YoursSeekData.UpperName) or  //     Name matches
     (UpperGetTo = YoursSeekData.UpperHandle))  //  or Handle matches
    and not isRcvd;                             // AND Mail is not received
end;

Function TMKAbstract.GetFAttach: String;
  Begin
  If IsFAttach and (SubjectOfs < WordCount(GetSubj)) Then
    Begin
    Inc(SubjectOfs);
    GetFAttach:=ExtractWord(GetSubj, SubjectOfs);
    End
  Else
    GetFAttach := '';
  End;


Function TMKAbstract.GetFRequest: String;
  Var
    S: String;

  Begin
  If IsFileReq and (SubjectOfs < WordCount(GetSubj)) Then
    Begin
    Inc(SubjectOfs);
    If SubjectOfs < WordCount(GetSubj) Then
      S := ExtractWord(GetSubj, Succ(SubjectOfs));
    If S[1]='!' Then
      Begin
      S:=ExtractWord(GetSubj, SubjectOfs) + ' ' + S;
      Inc(SubjectOfs);
      End
    Else
      S:=ExtractWord(GetSubj, SubjectOfs);
    GetFRequest:=S;
    End
  Else
    GetFRequest := '';
  End;


Procedure TMKAbstract.AddFAttach(const s: String);
  Begin
  If IsFAttach Then
    SetSubj(GetSubj + ' ' + s);
  End;


Procedure TMKAbstract.AddFRequest(const s: String);
  Begin
  If IsFileReq Then
    SetSubj(GetSubj + ' ' + s);
  End;

Function TMKAbstract.GetString(MaxLen: Word): TString;
  Var
    WPos: LongInt;
    WLen: Byte;
    StrDone: Boolean;
    StartSoft: Boolean;
    CurrLen: Word;
    TmpCh: Char;
    OldPos: LongInt;

  Begin
  If EOM Then
    GetString := ''
  Else
    Begin
    StrDone := False;
    CurrLen := 0;
    WPos := GetTxtPos;
    WLen := 0;
    StartSoft := LastSoft;
    LastSoft := True;
    OldPos := GetTxtPos;
    TmpCh := GetChar;
    While ((Not StrDone) And (CurrLen < MaxLen) And (Not EOM)) Do
      Begin
      Case TmpCh of
        #$00:;
        #$0d: Begin
              StrDone := True;
              LastSoft := False;
              End;
        #$8d:;
        #$0a:;
        #$20: Begin
              If ((CurrLen <> 0) or (Not StartSoft)) Then
                Begin
                Inc(CurrLen);
                WLen := CurrLen;
                GetString[CurrLen] := TmpCh;
                WPos := GetTxtPos;
                End
              Else
                StartSoft := False;
              End;
        Else
          Begin
          Inc(CurrLen);
          GetString[CurrLen] := TmpCh;
          End;
        End;
      If Not StrDone Then
        Begin
        OldPos := GetTxtPos;
        TmpCh := GetChar;
        End;
      End;
    If StrDone Then
      Begin
      GetString[0] := Chr(CurrLen);
      End
    Else
      If EOM Then
        Begin
        GetString[0] := Chr(CurrLen);
        End
      Else
        Begin
        If WLen = 0 Then
          Begin
          GetString[0] := Chr(CurrLen);
          SetTxtPos(OldPos);
          End
        Else
          Begin
          GetString[0] := Chr(WLen);
          SetTxtPos(WPos);
          End;
        End;
    End;
  End;

Function TMKAbstract.GetNoKludgeStr(MaxLen: Word): tString;
{From a suggestion by Johan Corstjens 2:281/610}
  Var
    TmpStr: tString;

  Begin
  TmpStr := GetString(MaxLen);
  While ((Length(TmpStr) > 0) and (TmpStr[1] = #1) and (Not EOM)) Do
    TmpStr := GetString(MaxLen);
  GetNoKludgeStr := TmpStr;
  End;

Procedure TMKAbstract.SetSeeAlso(dummy: LongInt);
Begin
End;

Procedure TMKAbstract.SetCost(dummy: Word);
Begin
End;

Procedure TMKAbstract.SetNextSeeAlso(dummy: LongInt);
Begin
End;


End.

