Unit TKitLog;
InterFace
Uses CTime, Objects, FTN;
type
  PLogDay = ^TLogDay;
  PLogSes = ^TLogSes;
  PLog    = ^TLog;

  TLog    = object
    MyAddr     : TFTNA;
    LogName    : FNameStr;
    AllLog     : PLogDay;
    Days       : PCollection;
    DayNum     : word;
    SesNum     : longint;
    CurDay     : PLogDay;
    CurNum     : word;
    TZ         : ShortInt;

    Constructor Init(aLogName:FNameStr;aTZ:ShortInt);
    Function    GetDaySes(day:tm):PLogSes;
    Function    GetDay(day:tm):PLogDay;
    Function    GetSesNum:longint;
    Function    GetDayNum:Word;
    Procedure   SetCurDay;
    Procedure   ChangeCurDay(delta:integer);
    Procedure   Load;
    Destructor  Done;
  end;

  TLogSes = object
    Owner  :  PLogDay;
    Who    :  TFTNA;
    TS     :  Tm;
    TE     :  Tm;
    SB     :  LongInt;
    RB     :  LongInt;
    ST     :  LongInt;
    RT     :  LongInt;
    OL     :  LongInt;
    OE     :  LongInt;
    Flags  :  LongInt;
    SF     :  LongInt;
    RF     :  LongInt;
    Next   :  PLogSes;
    Destructor  Done;
    Constructor Init(aOwn:PLogDay);
    Procedure   Get(S:PDosStream);
    Function    GetProt:string;
    Function    GetFlag:string;
    Function    LogLine:string;
  end;

  TLogDay = object
    Owner    : PLog;
    Date     : tm;
    LogSes   : PLogSes;
    Next     : PLogDay;
    Constructor Init(aOwn:PLOg);
    Procedure   Get(S:PDosStream);
    Function    GetSesNum:word;
    destructor  Done;
  end;

Implementation
Constructor TLogDay.Init;
begin
  Owner:=aOwn;
end;

Destructor  TLog.Done;
begin
  if (Days<>nil) Then
   begin
    Days^.DeleteAll;
    Dispose(Days);
   end;
  if (AllLog<>nil) then DisPose(AllLog,Done);
end;

Destructor  TLogSes.Done;
begin
  if (Next<>nil) then DisPose(Next,Done);
end;

Destructor  TLogDay.Done;
begin
  if (LogSes<>nil) then Dispose(LogSes,Done);
  if (Next<>nil) then DisPose(Next,Done);
end;

Procedure   TLOG.SetCurDay;
var
 cur:plogday;
begin
  if (Days=nil) then
   begin
     New(days,Init(10,5));
     cur:=AllLog;
     DayNum:=0;
     while(cur<>nil) do
      begin
        Days^.Insert(Cur);
        cur:=cur^.next;
        inc(DayNum);
      end;
     CurNum:=DayNum-1;
     CurDay:=Days^.At(CurNum);
   end;
end;

Function TLogSes.GetProt:String;
const
  Zds:array[0..3] of string[6] = ('zmodem','zedzap','undf  ','dirzap');
  Hyd:array[6..7] of string[6] = ('hydra ','hydRH1');
  FTS:string[6] = 'xmodem';
  KMP:string[6] = 'KMP   ';
begin
   if (((Flags shr 8) and $F) and $C) = 0 then
      GetProt:=Zds[(Flags shr 8) and $F]
   else if (((Flags shr 8) and $F) and 8) = 0 then
      GetProt:=Hyd[(Flags shr 8) and $F]
   else if ((Flags shr 8) and $F) = 8 then
      GetProt:=FTS
   else
      GetProt:=KMP;
end;

Function TLogSes.GetFlag:String;
const
  FLS:string[7] = 'IPCAFEK';
begin
  if (Flags and 1)=0 then FLS[1]:='O';
  if (Flags and 2)=0 then FLS[2]:='!';
  if (Flags and 4)=0 then FLS[3]:=' ';
  if (Flags and 8)=0 then FLS[4]:=' ';
  if (Flags and 16)=0 then FLS[5]:=' ';
  if (Flags and 32)=0 then FLS[6]:='d';
  if (Flags and 4096)=0 then FLS[7]:=' ';
  GetFlag:=Fls;
end;
{------------------------------------------}
Procedure TLog.Load;
var
  Log:PDosStream;
  sig,ver:longint;
begin
  New(Log,Init(LogName,stOpenRead));
  if Log^.Status=stOk then
   begin
     Log^.Read(Sig,4);
     Log^.Read(Ver,4);
       if (Sig=$D51AFF04) and (Ver=1) then
         begin
           New(AllLog,Init(@Self));
           AllLog^.Get(Log);
         end;
   end;
  Dispose(Log,Done);
end;

Procedure TLogDay.Get(S:PDosStream);
var
 gg:LongInt;
begin
 S^.Read(GG,4);
 S^.Read(GG,4);
 S^.Read(GG,4);
 unixtodos(GG,Date,Owner^.TZ);
 S^.Seek(S^.GetPos-12);
 if (S^.Status=stOk) then
 begin
   New(LogSes,Init(@Self));
   LogSes^.Get(S);
   if (S^.Status=stOk) then
   begin
     New(Next,Init(Owner));
     Next^.Get(S);
   end
     else Next:=nil;
 end
end;

Procedure TLogSes.Get;
var g:longint;nxt:tm;
begin
  S^.Read(Who,8);
  S^.Read(G,4);
  UnixToDos(G,TS,Owner^.Owner^.TZ);
  S^.Read(G,4);
  UnixToDos(G,TE,Owner^.Owner^.TZ);
  S^.Read(SB,4);
  S^.Read(RB,4);
  S^.Read(ST,4);
  S^.Read(RT,4);
  S^.Read(OL,4);
  S^.Read(OE,4);
  S^.Read(Flags,4);
  S^.Read(G,4);
  S^.Read(SF,4);
  S^.Read(RF,4);
  S^.Read(G,4);
  S^.Read(G,4);
  if (S^.Status=stOk) then
   begin
    S^.Read(G,4);
    S^.Read(G,4);
    S^.Read(G,4);
    UnixToDos(G,NXT,Owner^.Owner^.TZ);
    S^.Seek(S^.GetPos-12);
    if (NXT.TM_MDAY=Owner^.Date.TM_MDay) and
       (NXT.TM_MON=Owner^.Date.TM_MON)   and
       (NXT.TM_YEAR=Owner^.Date.TM_YEAR) then
       begin
         New(Next,INit(Owner));
         Next^.Get(S);
       end
    else
      Next:=nil;
   end;
end;

Constructor TLogSes.Init(aOwn:PLogDay);
begin
  Owner:=aOwn;
end;

Constructor  TLog.Init;
begin
 LogName:=aLogName;
 Days:=nil;
 TZ:=ATZ;
end;

Function  TLog.GetDayNum:Word;
var ret:word;
    Cur : PLogDay;
begin
   ret:=0;
   cur:=AllLog;
   while(cur<>nil) do
    begin
      inc(ret);
      cur:=cur^.next;
    end;
   GetDayNum:=ret;
   DayNum:=ret;
end;

Function  TLog.GetDaySes(day:tm):PLogSes;
var
  Cur : PLogDay;
begin
  Cur:=AllLog;
  while (cur^.Next<>nil) and (not
        (cur^.Date.tm_mday=day.tm_mday) and
        (cur^.Date.tm_mon=day.tm_mon) and
        (cur^.Date.tm_year=day.tm_year)) do Cur:=Cur^.Next;

  if    (cur^.Date.tm_mday=day.tm_mday) and
        (cur^.Date.tm_mon=day.tm_mon) and
        (cur^.Date.tm_year=day.tm_year) then GetDaySes:=Cur^.LogSes
  else
    GetDaySes:=nil;
end;

Function  TLog.GetDay(day:tm):PLogDay;
var
  Cur : PLogDay;
begin
  Cur:=AllLog;
  while (cur^.Next<>nil) and
        (not ((cur^.Date.tm_mday=day.tm_mday) and
        (cur^.Date.tm_mon=day.tm_mon) and
        (cur^.Date.tm_year=day.tm_year))) do Cur:=Cur^.Next;

  if    (cur^.Date.tm_mday=day.tm_mday) and
        (cur^.Date.tm_mon=day.tm_mon) and
        (cur^.Date.tm_year=day.tm_year) then GetDay:=Cur
  else
    GetDay:=nil;
end;

Function TLog.GetSesNum:longint;
var ret:word;
    Cur : PLogDay;
begin
  ret:=0;
  cur:=AllLog;
  while Cur<>nil do
    begin
      ret:=ret+Cur^.GetSesNum;
      Cur:=cur^.next;
    end;
  GetSesNum:=ret;
  SesNum:=ret;
end;

Function  TLogDay.GetSesNum:Word;
var
    Cur2 : PLogSes;
    ret2 : word;
begin
   ret2:=0;
   cur2:=LogSes;
   while(cur2<>nil) do
    begin
      inc(ret2);
      cur2:=cur2^.next;
    end;
   GetSesNum:=ret2;
end;

Function TLogSes.LogLine;
begin
  LogLine:=AdrToStr(Who);
end;

Procedure   TLog.ChangeCurDay(delta:integer);
begin
  if (DAys<>nil) then
   begin
  if (CurNum+Delta) in [0..DayNum-1] then
    begin
      CurNum:=CurNum+Delta;
      CurDay:=Days^.At(CurNum);
    end;
   end;
end;
END.